mirror of https://github.com/hak5/openwrt.git
mvebu: backport mainline patches from kernel 3.13
This is a backport of the patches accepted to the Linux mainline related to mvebu SoC (Armada XP and Armada 370) between Linux v3.12, and Linux v3.13. This work mainly covers: * Finishes work for sharing the pxa nand driver(drivers/mtd/nand/pxa3xx_nand.c) between the PXA family, and the Armada family. * timer initialization update, and access function for the Armada family. * Generic IRQ handling backporting. * Some bug fixes. Signed-off-by: Seif Mazareeb <seif.mazareeb@gmail.com> CC: Luka Perkov <luka@openwrt.org> SVN-Revision: 39566lede-17.01
parent
3af779eb17
commit
c9ae111a20
|
@ -0,0 +1,25 @@
|
|||
From 38a6d3f3330da6586695746a0a85a96143171211 Mon Sep 17 00:00:00 2001
|
||||
From: Sachin Kamat <sachin.kamat@linaro.org>
|
||||
Date: Mon, 30 Sep 2013 15:10:24 +0530
|
||||
Subject: [PATCH 128/203] mtd: nand: pxa3xx_nand: Remove redundant of_match_ptr
|
||||
|
||||
The data structure of_match_ptr() protects is always compiled in.
|
||||
Hence of_match_ptr() is not needed.
|
||||
|
||||
Signed-off-by: Sachin Kamat <sachin.kamat@linaro.org>
|
||||
Signed-off-by: Brian Norris <computersforpeace@gmail.com>
|
||||
---
|
||||
drivers/mtd/nand/pxa3xx_nand.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/mtd/nand/pxa3xx_nand.c
|
||||
+++ b/drivers/mtd/nand/pxa3xx_nand.c
|
||||
@@ -1412,7 +1412,7 @@ static int pxa3xx_nand_resume(struct pla
|
||||
static struct platform_driver pxa3xx_nand_driver = {
|
||||
.driver = {
|
||||
.name = "pxa3xx-nand",
|
||||
- .of_match_table = of_match_ptr(pxa3xx_nand_dt_ids),
|
||||
+ .of_match_table = pxa3xx_nand_dt_ids,
|
||||
},
|
||||
.probe = pxa3xx_nand_probe,
|
||||
.remove = pxa3xx_nand_remove,
|
|
@ -0,0 +1,40 @@
|
|||
From 18166290599760e8ff1b6c0389834beafd09a517 Mon Sep 17 00:00:00 2001
|
||||
From: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
Date: Fri, 4 Oct 2013 15:30:37 -0300
|
||||
Subject: [PATCH 129/203] mtd: nand: pxa3xx: Move DMA I/O enabling
|
||||
|
||||
Instead of setting info->dma each time a command is prepared,
|
||||
we can move it after the DMA buffers are allocated.
|
||||
|
||||
This is more clear and it's the proper place to enable this, given
|
||||
DMA cannot be turned on and off during runtime.
|
||||
|
||||
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
Tested-by: Daniel Mack <zonque@gmail.com>
|
||||
Signed-off-by: Brian Norris <computersforpeace@gmail.com>
|
||||
---
|
||||
drivers/mtd/nand/pxa3xx_nand.c | 6 +++++-
|
||||
1 file changed, 5 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/mtd/nand/pxa3xx_nand.c
|
||||
+++ b/drivers/mtd/nand/pxa3xx_nand.c
|
||||
@@ -540,7 +540,6 @@ static int prepare_command_pool(struct p
|
||||
info->oob_size = 0;
|
||||
info->use_ecc = 0;
|
||||
info->use_spare = 1;
|
||||
- info->use_dma = (use_dma) ? 1 : 0;
|
||||
info->is_ready = 0;
|
||||
info->retcode = ERR_NONE;
|
||||
if (info->cs != 0)
|
||||
@@ -950,6 +949,11 @@ static int pxa3xx_nand_init_buff(struct
|
||||
return info->data_dma_ch;
|
||||
}
|
||||
|
||||
+ /*
|
||||
+ * Now that DMA buffers are allocated we turn on
|
||||
+ * DMA proper for I/O operations.
|
||||
+ */
|
||||
+ info->use_dma = 1;
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,143 @@
|
|||
From 71d6267980d7590e38059a784785ca158e361f87 Mon Sep 17 00:00:00 2001
|
||||
From: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
Date: Fri, 4 Oct 2013 15:30:38 -0300
|
||||
Subject: [PATCH 130/203] mtd: nand: pxa3xx: Allocate data buffer on detected
|
||||
flash size
|
||||
|
||||
This commit replaces the currently hardcoded buffer size, by a
|
||||
dynamic detection scheme. First a small 256 bytes buffer is allocated
|
||||
so the device can be detected (using READID and friends commands).
|
||||
|
||||
After detection, this buffer is released and a new buffer is allocated
|
||||
to acommodate the page size plus out-of-band size.
|
||||
|
||||
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
Tested-by: Daniel Mack <zonque@gmail.com>
|
||||
Signed-off-by: Brian Norris <computersforpeace@gmail.com>
|
||||
---
|
||||
drivers/mtd/nand/pxa3xx_nand.c | 45 ++++++++++++++++++++++++++++--------------
|
||||
1 file changed, 30 insertions(+), 15 deletions(-)
|
||||
|
||||
--- a/drivers/mtd/nand/pxa3xx_nand.c
|
||||
+++ b/drivers/mtd/nand/pxa3xx_nand.c
|
||||
@@ -39,6 +39,13 @@
|
||||
#define NAND_STOP_DELAY (2 * HZ/50)
|
||||
#define PAGE_CHUNK_SIZE (2048)
|
||||
|
||||
+/*
|
||||
+ * Define a buffer size for the initial command that detects the flash device:
|
||||
+ * STATUS, READID and PARAM. The largest of these is the PARAM command,
|
||||
+ * needing 256 bytes.
|
||||
+ */
|
||||
+#define INIT_BUFFER_SIZE 256
|
||||
+
|
||||
/* registers and bit definitions */
|
||||
#define NDCR (0x00) /* Control register */
|
||||
#define NDTR0CS0 (0x04) /* Timing Parameter 0 for CS0 */
|
||||
@@ -164,6 +171,7 @@ struct pxa3xx_nand_info {
|
||||
|
||||
unsigned int buf_start;
|
||||
unsigned int buf_count;
|
||||
+ unsigned int buf_size;
|
||||
|
||||
/* DMA information */
|
||||
int drcmr_dat;
|
||||
@@ -911,26 +919,20 @@ static int pxa3xx_nand_detect_config(str
|
||||
return 0;
|
||||
}
|
||||
|
||||
-/* the maximum possible buffer size for large page with OOB data
|
||||
- * is: 2048 + 64 = 2112 bytes, allocate a page here for both the
|
||||
- * data buffer and the DMA descriptor
|
||||
- */
|
||||
-#define MAX_BUFF_SIZE PAGE_SIZE
|
||||
-
|
||||
#ifdef ARCH_HAS_DMA
|
||||
static int pxa3xx_nand_init_buff(struct pxa3xx_nand_info *info)
|
||||
{
|
||||
struct platform_device *pdev = info->pdev;
|
||||
- int data_desc_offset = MAX_BUFF_SIZE - sizeof(struct pxa_dma_desc);
|
||||
+ int data_desc_offset = info->buf_size - sizeof(struct pxa_dma_desc);
|
||||
|
||||
if (use_dma == 0) {
|
||||
- info->data_buff = kmalloc(MAX_BUFF_SIZE, GFP_KERNEL);
|
||||
+ info->data_buff = kmalloc(info->buf_size, GFP_KERNEL);
|
||||
if (info->data_buff == NULL)
|
||||
return -ENOMEM;
|
||||
return 0;
|
||||
}
|
||||
|
||||
- info->data_buff = dma_alloc_coherent(&pdev->dev, MAX_BUFF_SIZE,
|
||||
+ info->data_buff = dma_alloc_coherent(&pdev->dev, info->buf_size,
|
||||
&info->data_buff_phys, GFP_KERNEL);
|
||||
if (info->data_buff == NULL) {
|
||||
dev_err(&pdev->dev, "failed to allocate dma buffer\n");
|
||||
@@ -944,7 +946,7 @@ static int pxa3xx_nand_init_buff(struct
|
||||
pxa3xx_nand_data_dma_irq, info);
|
||||
if (info->data_dma_ch < 0) {
|
||||
dev_err(&pdev->dev, "failed to request data dma\n");
|
||||
- dma_free_coherent(&pdev->dev, MAX_BUFF_SIZE,
|
||||
+ dma_free_coherent(&pdev->dev, info->buf_size,
|
||||
info->data_buff, info->data_buff_phys);
|
||||
return info->data_dma_ch;
|
||||
}
|
||||
@@ -962,7 +964,7 @@ static void pxa3xx_nand_free_buff(struct
|
||||
struct platform_device *pdev = info->pdev;
|
||||
if (use_dma) {
|
||||
pxa_free_dma(info->data_dma_ch);
|
||||
- dma_free_coherent(&pdev->dev, MAX_BUFF_SIZE,
|
||||
+ dma_free_coherent(&pdev->dev, info->buf_size,
|
||||
info->data_buff, info->data_buff_phys);
|
||||
} else {
|
||||
kfree(info->data_buff);
|
||||
@@ -971,7 +973,7 @@ static void pxa3xx_nand_free_buff(struct
|
||||
#else
|
||||
static int pxa3xx_nand_init_buff(struct pxa3xx_nand_info *info)
|
||||
{
|
||||
- info->data_buff = kmalloc(MAX_BUFF_SIZE, GFP_KERNEL);
|
||||
+ info->data_buff = kmalloc(info->buf_size, GFP_KERNEL);
|
||||
if (info->data_buff == NULL)
|
||||
return -ENOMEM;
|
||||
return 0;
|
||||
@@ -1085,7 +1087,16 @@ KEEP_CONFIG:
|
||||
else
|
||||
host->col_addr_cycles = 1;
|
||||
|
||||
+ /* release the initial buffer */
|
||||
+ kfree(info->data_buff);
|
||||
+
|
||||
+ /* allocate the real data + oob buffer */
|
||||
+ info->buf_size = mtd->writesize + mtd->oobsize;
|
||||
+ ret = pxa3xx_nand_init_buff(info);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
info->oob_buff = info->data_buff + mtd->writesize;
|
||||
+
|
||||
if ((mtd->size >> chip->page_shift) > 65536)
|
||||
host->row_addr_cycles = 3;
|
||||
else
|
||||
@@ -1191,9 +1202,13 @@ static int alloc_nand_resource(struct pl
|
||||
}
|
||||
info->mmio_phys = r->start;
|
||||
|
||||
- ret = pxa3xx_nand_init_buff(info);
|
||||
- if (ret)
|
||||
+ /* Allocate a buffer to allow flash detection */
|
||||
+ info->buf_size = INIT_BUFFER_SIZE;
|
||||
+ info->data_buff = kmalloc(info->buf_size, GFP_KERNEL);
|
||||
+ if (info->data_buff == NULL) {
|
||||
+ ret = -ENOMEM;
|
||||
goto fail_disable_clk;
|
||||
+ }
|
||||
|
||||
/* initialize all interrupts to be disabled */
|
||||
disable_int(info, NDSR_MASK);
|
||||
@@ -1211,7 +1226,7 @@ static int alloc_nand_resource(struct pl
|
||||
|
||||
fail_free_buf:
|
||||
free_irq(irq, info);
|
||||
- pxa3xx_nand_free_buff(info);
|
||||
+ kfree(info->data_buff);
|
||||
fail_disable_clk:
|
||||
clk_disable_unprepare(info->clk);
|
||||
return ret;
|
|
@ -0,0 +1,27 @@
|
|||
From e3779fc4a84e1c51c061e3e13b1abf1c9a56a2cd Mon Sep 17 00:00:00 2001
|
||||
From: Michael Opdenacker <michael.opdenacker@free-electrons.com>
|
||||
Date: Sun, 13 Oct 2013 08:21:32 +0200
|
||||
Subject: [PATCH 131/203] mtd: nand: remove deprecated IRQF_DISABLED
|
||||
|
||||
This patch proposes to remove the use of the IRQF_DISABLED flag
|
||||
|
||||
It's a NOOP since 2.6.35 and it will be removed one day.
|
||||
|
||||
Signed-off-by: Michael Opdenacker <michael.opdenacker@free-electrons.com>
|
||||
Signed-off-by: Brian Norris <computersforpeace@gmail.com>
|
||||
---
|
||||
drivers/mtd/nand/pxa3xx_nand.c | 3 +--
|
||||
1 file changed, 1 insertion(+), 2 deletions(-)
|
||||
|
||||
--- a/drivers/mtd/nand/pxa3xx_nand.c
|
||||
+++ b/drivers/mtd/nand/pxa3xx_nand.c
|
||||
@@ -1213,8 +1213,7 @@ static int alloc_nand_resource(struct pl
|
||||
/* initialize all interrupts to be disabled */
|
||||
disable_int(info, NDSR_MASK);
|
||||
|
||||
- ret = request_irq(irq, pxa3xx_nand_irq, IRQF_DISABLED,
|
||||
- pdev->name, info);
|
||||
+ ret = request_irq(irq, pxa3xx_nand_irq, 0, pdev->name, info);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "failed to request IRQ\n");
|
||||
goto fail_free_buf;
|
|
@ -0,0 +1,28 @@
|
|||
From 54c1163b143e4ed911b8dddc0829c87f93b3debd Mon Sep 17 00:00:00 2001
|
||||
From: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
Date: Thu, 7 Nov 2013 12:17:10 -0300
|
||||
Subject: [PATCH 132/203] mtd: nand: pxa3xx: Add documentation about the
|
||||
controller
|
||||
|
||||
Given there's no public specification to this date, and in order
|
||||
to capture some important details and singularities about the
|
||||
controller let's document them once and for good.
|
||||
|
||||
Cc: linux-doc@vger.kernel.org
|
||||
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
Signed-off-by: Brian Norris <computersforpeace@gmail.com>
|
||||
---
|
||||
drivers/mtd/nand/pxa3xx_nand.c | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
--- a/drivers/mtd/nand/pxa3xx_nand.c
|
||||
+++ b/drivers/mtd/nand/pxa3xx_nand.c
|
||||
@@ -7,6 +7,8 @@
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
+ *
|
||||
+ * See Documentation/mtd/nand/pxa3xx-nand.txt for more details.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
|
@ -0,0 +1,25 @@
|
|||
From ec1977c2873dc7f0e6cec3edb8c30d92882f65d1 Mon Sep 17 00:00:00 2001
|
||||
From: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
Date: Thu, 7 Nov 2013 12:17:12 -0300
|
||||
Subject: [PATCH 133/203] mtd: nand: pxa3xx: Prevent sub-page writes
|
||||
|
||||
The current driver doesn't support sub-page writing, so report
|
||||
that to the NAND core.
|
||||
|
||||
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
Tested-by: Daniel Mack <zonque@gmail.com>
|
||||
Signed-off-by: Brian Norris <computersforpeace@gmail.com>
|
||||
---
|
||||
drivers/mtd/nand/pxa3xx_nand.c | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
--- a/drivers/mtd/nand/pxa3xx_nand.c
|
||||
+++ b/drivers/mtd/nand/pxa3xx_nand.c
|
||||
@@ -1145,6 +1145,7 @@ static int alloc_nand_resource(struct pl
|
||||
chip->read_byte = pxa3xx_nand_read_byte;
|
||||
chip->read_buf = pxa3xx_nand_read_buf;
|
||||
chip->write_buf = pxa3xx_nand_write_buf;
|
||||
+ chip->options |= NAND_NO_SUBPAGE_WRITE;
|
||||
}
|
||||
|
||||
spin_lock_init(&chip->controller->lock);
|
|
@ -0,0 +1,42 @@
|
|||
From 97598678602aaea473303523ce37a45d258206ca Mon Sep 17 00:00:00 2001
|
||||
From: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
Date: Thu, 7 Nov 2013 12:17:13 -0300
|
||||
Subject: [PATCH 134/203] mtd: nand: pxa3xx: read_page() returns max_bitflips
|
||||
|
||||
As per the ecc.read_page() prototype, we must return the maximum number
|
||||
of bitflips that were corrected on any one region covering an ecc step.
|
||||
|
||||
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
Tested-by: Daniel Mack <zonque@gmail.com>
|
||||
Signed-off-by: Brian Norris <computersforpeace@gmail.com>
|
||||
---
|
||||
drivers/mtd/nand/pxa3xx_nand.c | 4 +++-
|
||||
1 file changed, 3 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/mtd/nand/pxa3xx_nand.c
|
||||
+++ b/drivers/mtd/nand/pxa3xx_nand.c
|
||||
@@ -751,6 +751,7 @@ static int pxa3xx_nand_read_page_hwecc(s
|
||||
{
|
||||
struct pxa3xx_nand_host *host = mtd->priv;
|
||||
struct pxa3xx_nand_info *info = host->info_data;
|
||||
+ int max_bitflips = 0;
|
||||
|
||||
chip->read_buf(mtd, buf, mtd->writesize);
|
||||
chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
|
||||
@@ -758,6 +759,7 @@ static int pxa3xx_nand_read_page_hwecc(s
|
||||
if (info->retcode == ERR_SBERR) {
|
||||
switch (info->use_ecc) {
|
||||
case 1:
|
||||
+ max_bitflips = 1;
|
||||
mtd->ecc_stats.corrected++;
|
||||
break;
|
||||
case 0:
|
||||
@@ -776,7 +778,7 @@ static int pxa3xx_nand_read_page_hwecc(s
|
||||
mtd->ecc_stats.failed++;
|
||||
}
|
||||
|
||||
- return 0;
|
||||
+ return max_bitflips;
|
||||
}
|
||||
|
||||
static uint8_t pxa3xx_nand_read_byte(struct mtd_info *mtd)
|
|
@ -0,0 +1,97 @@
|
|||
From dc333ddda677d416a6726509e144c6dfb93e7e89 Mon Sep 17 00:00:00 2001
|
||||
From: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
Date: Thu, 7 Nov 2013 12:17:14 -0300
|
||||
Subject: [PATCH 135/203] mtd: nand: pxa3xx: Early variant detection
|
||||
|
||||
In order to customize early settings depending on the detected SoC variant,
|
||||
move the detection to be before the nand_chip struct filling.
|
||||
|
||||
In a follow-up patch, this change is needed to detect the variant *before*
|
||||
the call to alloc_nand_resource(), which allows to set a different cmdfunc()
|
||||
for each variant.
|
||||
|
||||
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
Tested-by: Daniel Mack <zonque@gmail.com>
|
||||
Signed-off-by: Brian Norris <computersforpeace@gmail.com>
|
||||
---
|
||||
drivers/mtd/nand/pxa3xx_nand.c | 48 +++++++++++++++++++++---------------------
|
||||
1 file changed, 24 insertions(+), 24 deletions(-)
|
||||
|
||||
--- a/drivers/mtd/nand/pxa3xx_nand.c
|
||||
+++ b/drivers/mtd/nand/pxa3xx_nand.c
|
||||
@@ -258,6 +258,29 @@ static struct pxa3xx_nand_flash builtin_
|
||||
/* convert nano-seconds to nand flash controller clock cycles */
|
||||
#define ns2cycle(ns, clk) (int)((ns) * (clk / 1000000) / 1000)
|
||||
|
||||
+static struct of_device_id pxa3xx_nand_dt_ids[] = {
|
||||
+ {
|
||||
+ .compatible = "marvell,pxa3xx-nand",
|
||||
+ .data = (void *)PXA3XX_NAND_VARIANT_PXA,
|
||||
+ },
|
||||
+ {
|
||||
+ .compatible = "marvell,armada370-nand",
|
||||
+ .data = (void *)PXA3XX_NAND_VARIANT_ARMADA370,
|
||||
+ },
|
||||
+ {}
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, pxa3xx_nand_dt_ids);
|
||||
+
|
||||
+static enum pxa3xx_nand_variant
|
||||
+pxa3xx_nand_get_variant(struct platform_device *pdev)
|
||||
+{
|
||||
+ const struct of_device_id *of_id =
|
||||
+ of_match_device(pxa3xx_nand_dt_ids, &pdev->dev);
|
||||
+ if (!of_id)
|
||||
+ return PXA3XX_NAND_VARIANT_PXA;
|
||||
+ return (enum pxa3xx_nand_variant)of_id->data;
|
||||
+}
|
||||
+
|
||||
static void pxa3xx_nand_set_timing(struct pxa3xx_nand_host *host,
|
||||
const struct pxa3xx_nand_timing *t)
|
||||
{
|
||||
@@ -1125,6 +1148,7 @@ static int alloc_nand_resource(struct pl
|
||||
return -ENOMEM;
|
||||
|
||||
info->pdev = pdev;
|
||||
+ info->variant = pxa3xx_nand_get_variant(pdev);
|
||||
for (cs = 0; cs < pdata->num_cs; cs++) {
|
||||
mtd = (struct mtd_info *)((unsigned int)&info[1] +
|
||||
(sizeof(*mtd) + sizeof(*host)) * cs);
|
||||
@@ -1259,29 +1283,6 @@ static int pxa3xx_nand_remove(struct pla
|
||||
return 0;
|
||||
}
|
||||
|
||||
-static struct of_device_id pxa3xx_nand_dt_ids[] = {
|
||||
- {
|
||||
- .compatible = "marvell,pxa3xx-nand",
|
||||
- .data = (void *)PXA3XX_NAND_VARIANT_PXA,
|
||||
- },
|
||||
- {
|
||||
- .compatible = "marvell,armada370-nand",
|
||||
- .data = (void *)PXA3XX_NAND_VARIANT_ARMADA370,
|
||||
- },
|
||||
- {}
|
||||
-};
|
||||
-MODULE_DEVICE_TABLE(of, pxa3xx_nand_dt_ids);
|
||||
-
|
||||
-static enum pxa3xx_nand_variant
|
||||
-pxa3xx_nand_get_variant(struct platform_device *pdev)
|
||||
-{
|
||||
- const struct of_device_id *of_id =
|
||||
- of_match_device(pxa3xx_nand_dt_ids, &pdev->dev);
|
||||
- if (!of_id)
|
||||
- return PXA3XX_NAND_VARIANT_PXA;
|
||||
- return (enum pxa3xx_nand_variant)of_id->data;
|
||||
-}
|
||||
-
|
||||
static int pxa3xx_nand_probe_dt(struct platform_device *pdev)
|
||||
{
|
||||
struct pxa3xx_nand_platform_data *pdata;
|
||||
@@ -1338,7 +1339,6 @@ static int pxa3xx_nand_probe(struct plat
|
||||
}
|
||||
|
||||
info = platform_get_drvdata(pdev);
|
||||
- info->variant = pxa3xx_nand_get_variant(pdev);
|
||||
probe_success = 0;
|
||||
for (cs = 0; cs < pdata->num_cs; cs++) {
|
||||
struct mtd_info *mtd = info->host[cs]->mtd;
|
|
@ -0,0 +1,41 @@
|
|||
From 67ab922e1e292494732a10f367d3de47338639ac Mon Sep 17 00:00:00 2001
|
||||
From: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
Date: Thu, 7 Nov 2013 12:17:15 -0300
|
||||
Subject: [PATCH 136/203] mtd: nand: pxa3xx: Use chip->cmdfunc instead of the
|
||||
internal
|
||||
|
||||
Whenever possible, it's always better to use the generic chip->cmdfunc
|
||||
instead of the internal pxa3xx_nand_cmdfunc().
|
||||
In this particular case, this will allow to have multiple cmdfunc()
|
||||
implementations for different SoC variants.
|
||||
|
||||
Reviewed-by: Huang Shijie <shijie8@gmail.com>
|
||||
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
Tested-by: Daniel Mack <zonque@gmail.com>
|
||||
Signed-off-by: Brian Norris <computersforpeace@gmail.com>
|
||||
---
|
||||
drivers/mtd/nand/pxa3xx_nand.c | 6 +++++-
|
||||
1 file changed, 5 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/mtd/nand/pxa3xx_nand.c
|
||||
+++ b/drivers/mtd/nand/pxa3xx_nand.c
|
||||
@@ -1015,14 +1015,18 @@ static void pxa3xx_nand_free_buff(struct
|
||||
static int pxa3xx_nand_sensing(struct pxa3xx_nand_info *info)
|
||||
{
|
||||
struct mtd_info *mtd;
|
||||
+ struct nand_chip *chip;
|
||||
int ret;
|
||||
+
|
||||
mtd = info->host[info->cs]->mtd;
|
||||
+ chip = mtd->priv;
|
||||
+
|
||||
/* use the common timing to make a try */
|
||||
ret = pxa3xx_nand_config_flash(info, &builtin_flash_types[0]);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
- pxa3xx_nand_cmdfunc(mtd, NAND_CMD_RESET, 0, 0);
|
||||
+ chip->cmdfunc(mtd, NAND_CMD_RESET, 0, 0);
|
||||
if (info->is_ready)
|
||||
return 0;
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
From 496f307424d3958ef43ad06ae6a0be98ede2a92c Mon Sep 17 00:00:00 2001
|
||||
From: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
Date: Thu, 7 Nov 2013 12:17:16 -0300
|
||||
Subject: [PATCH 137/203] mtd: nand: pxa3xx: Split FIFO size from to-be-read
|
||||
FIFO count
|
||||
|
||||
Introduce a fifo_size field to represent the size of the controller's
|
||||
FIFO buffer, and use it to distinguish that size from the amount
|
||||
of data bytes to be read from the FIFO.
|
||||
|
||||
This is important to support devices with pages larger than the
|
||||
controller's internal FIFO, that need to read the pages in FIFO-sized
|
||||
chunks.
|
||||
|
||||
In particular, the current code is at least confusing, for it mixes
|
||||
all the different sizes involved: FIFO size, page size and data size.
|
||||
|
||||
This commit starts the cleaning by removing the info->page_size field
|
||||
that is not currently used. The host->page_size field should also
|
||||
be removed and use always mtd->writesize instead. Follow up commits
|
||||
will clean this up.
|
||||
|
||||
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
Tested-by: Daniel Mack <zonque@gmail.com>
|
||||
Signed-off-by: Brian Norris <computersforpeace@gmail.com>
|
||||
---
|
||||
drivers/mtd/nand/pxa3xx_nand.c | 12 +++++++-----
|
||||
1 file changed, 7 insertions(+), 5 deletions(-)
|
||||
|
||||
--- a/drivers/mtd/nand/pxa3xx_nand.c
|
||||
+++ b/drivers/mtd/nand/pxa3xx_nand.c
|
||||
@@ -201,8 +201,8 @@ struct pxa3xx_nand_info {
|
||||
int use_spare; /* use spare ? */
|
||||
int is_ready;
|
||||
|
||||
- unsigned int page_size; /* page size of attached chip */
|
||||
- unsigned int data_size; /* data size in FIFO */
|
||||
+ unsigned int fifo_size; /* max. data size in the FIFO */
|
||||
+ unsigned int data_size; /* data to be read from FIFO */
|
||||
unsigned int oob_size;
|
||||
int retcode;
|
||||
|
||||
@@ -307,16 +307,15 @@ static void pxa3xx_nand_set_timing(struc
|
||||
|
||||
static void pxa3xx_set_datasize(struct pxa3xx_nand_info *info)
|
||||
{
|
||||
- struct pxa3xx_nand_host *host = info->host[info->cs];
|
||||
int oob_enable = info->reg_ndcr & NDCR_SPARE_EN;
|
||||
|
||||
- info->data_size = host->page_size;
|
||||
+ info->data_size = info->fifo_size;
|
||||
if (!oob_enable) {
|
||||
info->oob_size = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
- switch (host->page_size) {
|
||||
+ switch (info->fifo_size) {
|
||||
case 2048:
|
||||
info->oob_size = (info->use_ecc) ? 40 : 64;
|
||||
break;
|
||||
@@ -933,9 +932,12 @@ static int pxa3xx_nand_detect_config(str
|
||||
uint32_t ndcr = nand_readl(info, NDCR);
|
||||
|
||||
if (ndcr & NDCR_PAGE_SZ) {
|
||||
+ /* Controller's FIFO size */
|
||||
+ info->fifo_size = 2048;
|
||||
host->page_size = 2048;
|
||||
host->read_id_bytes = 4;
|
||||
} else {
|
||||
+ info->fifo_size = 512;
|
||||
host->page_size = 512;
|
||||
host->read_id_bytes = 2;
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
From ad40a597cbfeb2374c799ba6dad3a69f131511c8 Mon Sep 17 00:00:00 2001
|
||||
From: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
Date: Thu, 7 Nov 2013 12:17:17 -0300
|
||||
Subject: [PATCH 138/203] mtd: nand: pxa3xx: Replace host->page_size by
|
||||
mtd->writesize
|
||||
|
||||
There's no need to privately store the device page size as it's
|
||||
available in mtd structure field mtd->writesize.
|
||||
Also, this removes the hardcoded page size value, leaving the
|
||||
auto-detected value only.
|
||||
|
||||
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
Tested-by: Daniel Mack <zonque@gmail.com>
|
||||
Signed-off-by: Brian Norris <computersforpeace@gmail.com>
|
||||
---
|
||||
drivers/mtd/nand/pxa3xx_nand.c | 10 +++-------
|
||||
1 file changed, 3 insertions(+), 7 deletions(-)
|
||||
|
||||
--- a/drivers/mtd/nand/pxa3xx_nand.c
|
||||
+++ b/drivers/mtd/nand/pxa3xx_nand.c
|
||||
@@ -151,7 +151,6 @@ struct pxa3xx_nand_host {
|
||||
void *info_data;
|
||||
|
||||
/* page size of attached chip */
|
||||
- unsigned int page_size;
|
||||
int use_ecc;
|
||||
int cs;
|
||||
|
||||
@@ -614,12 +613,12 @@ static int prepare_command_pool(struct p
|
||||
info->buf_start += mtd->writesize;
|
||||
|
||||
/* Second command setting for large pages */
|
||||
- if (host->page_size >= PAGE_CHUNK_SIZE)
|
||||
+ if (mtd->writesize >= PAGE_CHUNK_SIZE)
|
||||
info->ndcb0 |= NDCB0_DBC | (NAND_CMD_READSTART << 8);
|
||||
|
||||
case NAND_CMD_SEQIN:
|
||||
/* small page addr setting */
|
||||
- if (unlikely(host->page_size < PAGE_CHUNK_SIZE)) {
|
||||
+ if (unlikely(mtd->writesize < PAGE_CHUNK_SIZE)) {
|
||||
info->ndcb1 = ((page_addr & 0xFFFFFF) << 8)
|
||||
| (column & 0xFF);
|
||||
|
||||
@@ -895,7 +894,6 @@ static int pxa3xx_nand_config_flash(stru
|
||||
}
|
||||
|
||||
/* calculate flash information */
|
||||
- host->page_size = f->page_size;
|
||||
host->read_id_bytes = (f->page_size == 2048) ? 4 : 2;
|
||||
|
||||
/* calculate addressing information */
|
||||
@@ -934,11 +932,9 @@ static int pxa3xx_nand_detect_config(str
|
||||
if (ndcr & NDCR_PAGE_SZ) {
|
||||
/* Controller's FIFO size */
|
||||
info->fifo_size = 2048;
|
||||
- host->page_size = 2048;
|
||||
host->read_id_bytes = 4;
|
||||
} else {
|
||||
info->fifo_size = 512;
|
||||
- host->page_size = 512;
|
||||
host->read_id_bytes = 2;
|
||||
}
|
||||
|
||||
@@ -1106,7 +1102,7 @@ static int pxa3xx_nand_scan(struct mtd_i
|
||||
def = pxa3xx_flash_ids;
|
||||
KEEP_CONFIG:
|
||||
chip->ecc.mode = NAND_ECC_HW;
|
||||
- chip->ecc.size = host->page_size;
|
||||
+ chip->ecc.size = info->fifo_size;
|
||||
chip->ecc.strength = 1;
|
||||
|
||||
if (info->reg_ndcr & NDCR_DWIDTH_M)
|
|
@ -0,0 +1,30 @@
|
|||
From 8bce53e42f78e009fbfbd4a98ea98f66e6cd5b4c Mon Sep 17 00:00:00 2001
|
||||
From: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
Date: Thu, 7 Nov 2013 12:17:18 -0300
|
||||
Subject: [PATCH 139/203] mtd: nand: pxa3xx: Add a nice comment to
|
||||
pxa3xx_set_datasize()
|
||||
|
||||
Add a comment clarifying the use of pxa3xx_set_datasize() which is only
|
||||
applicable on data read/write commands (i.e. commands with a data cycle,
|
||||
such as READID, READ0, STATUS, etc.)
|
||||
|
||||
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
Signed-off-by: Brian Norris <computersforpeace@gmail.com>
|
||||
---
|
||||
drivers/mtd/nand/pxa3xx_nand.c | 5 +++++
|
||||
1 file changed, 5 insertions(+)
|
||||
|
||||
--- a/drivers/mtd/nand/pxa3xx_nand.c
|
||||
+++ b/drivers/mtd/nand/pxa3xx_nand.c
|
||||
@@ -304,6 +304,11 @@ static void pxa3xx_nand_set_timing(struc
|
||||
nand_writel(info, NDTR1CS0, ndtr1);
|
||||
}
|
||||
|
||||
+/*
|
||||
+ * Set the data and OOB size, depending on the selected
|
||||
+ * spare and ECC configuration.
|
||||
+ * Only applicable to READ0, READOOB and PAGEPROG commands.
|
||||
+ */
|
||||
static void pxa3xx_set_datasize(struct pxa3xx_nand_info *info)
|
||||
{
|
||||
int oob_enable = info->reg_ndcr & NDCR_SPARE_EN;
|
|
@ -0,0 +1,138 @@
|
|||
From b5289e9cb18e6c254e13826e6bcfbfe95b819d77 Mon Sep 17 00:00:00 2001
|
||||
From: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
Date: Thu, 14 Nov 2013 18:25:26 -0300
|
||||
Subject: [PATCH 140/203] mtd: nand: pxa3xx: Use a completion to signal device
|
||||
ready
|
||||
|
||||
The expected behavior of the waitfunc() NAND chip call is to wait
|
||||
for the device to be READY (this is a standard chip line).
|
||||
However, the current implementation does almost nothing, which opens
|
||||
the possibility of issuing a command to a non-ready device.
|
||||
|
||||
Fix this by adding a new completion to wait for the ready event to arrive.
|
||||
|
||||
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
Tested-by: Daniel Mack <zonque@gmail.com>
|
||||
Signed-off-by: Brian Norris <computersforpeace@gmail.com>
|
||||
---
|
||||
drivers/mtd/nand/pxa3xx_nand.c | 38 ++++++++++++++++++++++++--------------
|
||||
1 file changed, 24 insertions(+), 14 deletions(-)
|
||||
|
||||
--- a/drivers/mtd/nand/pxa3xx_nand.c
|
||||
+++ b/drivers/mtd/nand/pxa3xx_nand.c
|
||||
@@ -37,6 +37,7 @@
|
||||
|
||||
#include <linux/platform_data/mtd-nand-pxa3xx.h>
|
||||
|
||||
+#define NAND_DEV_READY_TIMEOUT 50
|
||||
#define CHIP_DELAY_TIMEOUT (2 * HZ/10)
|
||||
#define NAND_STOP_DELAY (2 * HZ/50)
|
||||
#define PAGE_CHUNK_SIZE (2048)
|
||||
@@ -168,7 +169,7 @@ struct pxa3xx_nand_info {
|
||||
struct clk *clk;
|
||||
void __iomem *mmio_base;
|
||||
unsigned long mmio_phys;
|
||||
- struct completion cmd_complete;
|
||||
+ struct completion cmd_complete, dev_ready;
|
||||
|
||||
unsigned int buf_start;
|
||||
unsigned int buf_count;
|
||||
@@ -198,7 +199,7 @@ struct pxa3xx_nand_info {
|
||||
int use_ecc; /* use HW ECC ? */
|
||||
int use_dma; /* use DMA ? */
|
||||
int use_spare; /* use spare ? */
|
||||
- int is_ready;
|
||||
+ int need_wait;
|
||||
|
||||
unsigned int fifo_size; /* max. data size in the FIFO */
|
||||
unsigned int data_size; /* data to be read from FIFO */
|
||||
@@ -480,7 +481,7 @@ static void start_data_dma(struct pxa3xx
|
||||
static irqreturn_t pxa3xx_nand_irq(int irq, void *devid)
|
||||
{
|
||||
struct pxa3xx_nand_info *info = devid;
|
||||
- unsigned int status, is_completed = 0;
|
||||
+ unsigned int status, is_completed = 0, is_ready = 0;
|
||||
unsigned int ready, cmd_done;
|
||||
|
||||
if (info->cs == 0) {
|
||||
@@ -516,8 +517,8 @@ static irqreturn_t pxa3xx_nand_irq(int i
|
||||
is_completed = 1;
|
||||
}
|
||||
if (status & ready) {
|
||||
- info->is_ready = 1;
|
||||
info->state = STATE_READY;
|
||||
+ is_ready = 1;
|
||||
}
|
||||
|
||||
if (status & NDSR_WRCMDREQ) {
|
||||
@@ -546,6 +547,8 @@ static irqreturn_t pxa3xx_nand_irq(int i
|
||||
nand_writel(info, NDSR, status);
|
||||
if (is_completed)
|
||||
complete(&info->cmd_complete);
|
||||
+ if (is_ready)
|
||||
+ complete(&info->dev_ready);
|
||||
NORMAL_IRQ_EXIT:
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
@@ -576,7 +579,6 @@ static int prepare_command_pool(struct p
|
||||
info->oob_size = 0;
|
||||
info->use_ecc = 0;
|
||||
info->use_spare = 1;
|
||||
- info->is_ready = 0;
|
||||
info->retcode = ERR_NONE;
|
||||
if (info->cs != 0)
|
||||
info->ndcb0 = NDCB0_CSEL;
|
||||
@@ -749,6 +751,8 @@ static void pxa3xx_nand_cmdfunc(struct m
|
||||
exec_cmd = prepare_command_pool(info, command, column, page_addr);
|
||||
if (exec_cmd) {
|
||||
init_completion(&info->cmd_complete);
|
||||
+ init_completion(&info->dev_ready);
|
||||
+ info->need_wait = 1;
|
||||
pxa3xx_nand_start(info);
|
||||
|
||||
ret = wait_for_completion_timeout(&info->cmd_complete,
|
||||
@@ -863,21 +867,27 @@ static int pxa3xx_nand_waitfunc(struct m
|
||||
{
|
||||
struct pxa3xx_nand_host *host = mtd->priv;
|
||||
struct pxa3xx_nand_info *info = host->info_data;
|
||||
+ int ret;
|
||||
+
|
||||
+ if (info->need_wait) {
|
||||
+ ret = wait_for_completion_timeout(&info->dev_ready,
|
||||
+ CHIP_DELAY_TIMEOUT);
|
||||
+ info->need_wait = 0;
|
||||
+ if (!ret) {
|
||||
+ dev_err(&info->pdev->dev, "Ready time out!!!\n");
|
||||
+ return NAND_STATUS_FAIL;
|
||||
+ }
|
||||
+ }
|
||||
|
||||
/* pxa3xx_nand_send_command has waited for command complete */
|
||||
if (this->state == FL_WRITING || this->state == FL_ERASING) {
|
||||
if (info->retcode == ERR_NONE)
|
||||
return 0;
|
||||
- else {
|
||||
- /*
|
||||
- * any error make it return 0x01 which will tell
|
||||
- * the caller the erase and write fail
|
||||
- */
|
||||
- return 0x01;
|
||||
- }
|
||||
+ else
|
||||
+ return NAND_STATUS_FAIL;
|
||||
}
|
||||
|
||||
- return 0;
|
||||
+ return NAND_STATUS_READY;
|
||||
}
|
||||
|
||||
static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info,
|
||||
@@ -1030,7 +1040,7 @@ static int pxa3xx_nand_sensing(struct px
|
||||
return ret;
|
||||
|
||||
chip->cmdfunc(mtd, NAND_CMD_RESET, 0, 0);
|
||||
- if (info->is_ready)
|
||||
+ if (!info->need_wait)
|
||||
return 0;
|
||||
|
||||
return -ENODEV;
|
|
@ -0,0 +1,34 @@
|
|||
From 2a1254f505ca4d376eae81768e4d5d890b578d13 Mon Sep 17 00:00:00 2001
|
||||
From: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
Date: Thu, 14 Nov 2013 18:25:27 -0300
|
||||
Subject: [PATCH 141/203] mtd: nand: pxa3xx: Use waitfunc() to wait for the
|
||||
device to be ready
|
||||
|
||||
In pxa3xx_nand_sensing() instead of simply using info->is_ready
|
||||
after issuing a command, the correct way of checking is to wait
|
||||
for the device to be ready through the chip's waitfunc().
|
||||
|
||||
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
Tested-by: Daniel Mack <zonque@gmail.com>
|
||||
Signed-off-by: Brian Norris <computersforpeace@gmail.com>
|
||||
---
|
||||
drivers/mtd/nand/pxa3xx_nand.c | 7 ++++---
|
||||
1 file changed, 4 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/drivers/mtd/nand/pxa3xx_nand.c
|
||||
+++ b/drivers/mtd/nand/pxa3xx_nand.c
|
||||
@@ -1040,10 +1040,11 @@ static int pxa3xx_nand_sensing(struct px
|
||||
return ret;
|
||||
|
||||
chip->cmdfunc(mtd, NAND_CMD_RESET, 0, 0);
|
||||
- if (!info->need_wait)
|
||||
- return 0;
|
||||
+ ret = chip->waitfunc(mtd, chip);
|
||||
+ if (ret & NAND_STATUS_FAIL)
|
||||
+ return -ENODEV;
|
||||
|
||||
- return -ENODEV;
|
||||
+ return 0;
|
||||
}
|
||||
|
||||
static int pxa3xx_nand_scan(struct mtd_info *mtd)
|
|
@ -0,0 +1,108 @@
|
|||
From bd428b9b18c2dffb8c9d737e99adfd145822e502 Mon Sep 17 00:00:00 2001
|
||||
From: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
Date: Thu, 14 Nov 2013 18:25:28 -0300
|
||||
Subject: [PATCH 142/203] mtd: nand: pxa3xx: Add bad block handling
|
||||
|
||||
Add support for flash-based bad block table using Marvell's
|
||||
custom in-flash bad block table layout. The support is enabled
|
||||
a 'flash_bbt' platform data or device tree parameter.
|
||||
|
||||
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
Tested-by: Daniel Mack <zonque@gmail.com>
|
||||
Signed-off-by: Brian Norris <computersforpeace@gmail.com>
|
||||
---
|
||||
.../devicetree/bindings/mtd/pxa3xx-nand.txt | 2 ++
|
||||
drivers/mtd/nand/pxa3xx_nand.c | 37 ++++++++++++++++++++++
|
||||
include/linux/platform_data/mtd-nand-pxa3xx.h | 3 ++
|
||||
3 files changed, 42 insertions(+)
|
||||
|
||||
--- a/Documentation/devicetree/bindings/mtd/pxa3xx-nand.txt
|
||||
+++ b/Documentation/devicetree/bindings/mtd/pxa3xx-nand.txt
|
||||
@@ -13,6 +13,8 @@ Optional properties:
|
||||
- marvell,nand-keep-config: Set to keep the NAND controller config as set
|
||||
by the bootloader
|
||||
- num-cs: Number of chipselect lines to usw
|
||||
+ - nand-on-flash-bbt: boolean to enable on flash bbt option if
|
||||
+ not present false
|
||||
|
||||
Example:
|
||||
|
||||
--- a/drivers/mtd/nand/pxa3xx_nand.c
|
||||
+++ b/drivers/mtd/nand/pxa3xx_nand.c
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
+#include <linux/of_mtd.h>
|
||||
|
||||
#if defined(CONFIG_ARCH_PXA) || defined(CONFIG_ARCH_MMP)
|
||||
#define ARCH_HAS_DMA
|
||||
@@ -241,6 +242,29 @@ static struct pxa3xx_nand_flash builtin_
|
||||
{ "256MiB 16-bit", 0xba20, 64, 2048, 16, 16, 2048, &timing[3] },
|
||||
};
|
||||
|
||||
+static u8 bbt_pattern[] = {'M', 'V', 'B', 'b', 't', '0' };
|
||||
+static u8 bbt_mirror_pattern[] = {'1', 't', 'b', 'B', 'V', 'M' };
|
||||
+
|
||||
+static struct nand_bbt_descr bbt_main_descr = {
|
||||
+ .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
|
||||
+ | NAND_BBT_2BIT | NAND_BBT_VERSION,
|
||||
+ .offs = 8,
|
||||
+ .len = 6,
|
||||
+ .veroffs = 14,
|
||||
+ .maxblocks = 8, /* Last 8 blocks in each chip */
|
||||
+ .pattern = bbt_pattern
|
||||
+};
|
||||
+
|
||||
+static struct nand_bbt_descr bbt_mirror_descr = {
|
||||
+ .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
|
||||
+ | NAND_BBT_2BIT | NAND_BBT_VERSION,
|
||||
+ .offs = 8,
|
||||
+ .len = 6,
|
||||
+ .veroffs = 14,
|
||||
+ .maxblocks = 8, /* Last 8 blocks in each chip */
|
||||
+ .pattern = bbt_mirror_pattern
|
||||
+};
|
||||
+
|
||||
/* Define a default flash type setting serve as flash detecting only */
|
||||
#define DEFAULT_FLASH_TYPE (&builtin_flash_types[0])
|
||||
|
||||
@@ -1126,6 +1150,18 @@ KEEP_CONFIG:
|
||||
|
||||
if (nand_scan_ident(mtd, 1, def))
|
||||
return -ENODEV;
|
||||
+
|
||||
+ if (pdata->flash_bbt) {
|
||||
+ /*
|
||||
+ * We'll use a bad block table stored in-flash and don't
|
||||
+ * allow writing the bad block marker to the flash.
|
||||
+ */
|
||||
+ chip->bbt_options |= NAND_BBT_USE_FLASH |
|
||||
+ NAND_BBT_NO_OOB_BBM;
|
||||
+ chip->bbt_td = &bbt_main_descr;
|
||||
+ chip->bbt_md = &bbt_mirror_descr;
|
||||
+ }
|
||||
+
|
||||
/* calculate addressing information */
|
||||
if (mtd->writesize >= 2048)
|
||||
host->col_addr_cycles = 2;
|
||||
@@ -1320,6 +1356,7 @@ static int pxa3xx_nand_probe_dt(struct p
|
||||
if (of_get_property(np, "marvell,nand-keep-config", NULL))
|
||||
pdata->keep_config = 1;
|
||||
of_property_read_u32(np, "num-cs", &pdata->num_cs);
|
||||
+ pdata->flash_bbt = of_get_nand_on_flash_bbt(np);
|
||||
|
||||
pdev->dev.platform_data = pdata;
|
||||
|
||||
--- a/include/linux/platform_data/mtd-nand-pxa3xx.h
|
||||
+++ b/include/linux/platform_data/mtd-nand-pxa3xx.h
|
||||
@@ -55,6 +55,9 @@ struct pxa3xx_nand_platform_data {
|
||||
/* indicate how many chip selects will be used */
|
||||
int num_cs;
|
||||
|
||||
+ /* use an flash-based bad block table */
|
||||
+ bool flash_bbt;
|
||||
+
|
||||
const struct mtd_partition *parts[NUM_CHIP_SELECT];
|
||||
unsigned int nr_parts[NUM_CHIP_SELECT];
|
||||
|
|
@ -0,0 +1,172 @@
|
|||
From 3677d22ed7e3a631f35e2addc4e2181f6215e4b0 Mon Sep 17 00:00:00 2001
|
||||
From: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
Date: Thu, 14 Nov 2013 18:25:29 -0300
|
||||
Subject: [PATCH 143/203] mtd: nand: pxa3xx: Add driver-specific ECC BCH
|
||||
support
|
||||
|
||||
This commit adds the BCH ECC support available in NFCv2 controller.
|
||||
Depending on the detected required strength the respective ECC layout
|
||||
is selected.
|
||||
|
||||
This commit adds an empty ECC layout, since support to access large
|
||||
pages is first required. Once that support is added, a proper ECC
|
||||
layout will be added as well.
|
||||
|
||||
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
Tested-by: Daniel Mack <zonque@gmail.com>
|
||||
Signed-off-by: Brian Norris <computersforpeace@gmail.com>
|
||||
---
|
||||
drivers/mtd/nand/pxa3xx_nand.c | 86 +++++++++++++++++++++++++++++++++---------
|
||||
1 file changed, 69 insertions(+), 17 deletions(-)
|
||||
|
||||
--- a/drivers/mtd/nand/pxa3xx_nand.c
|
||||
+++ b/drivers/mtd/nand/pxa3xx_nand.c
|
||||
@@ -58,6 +58,7 @@
|
||||
#define NDPCR (0x18) /* Page Count Register */
|
||||
#define NDBDR0 (0x1C) /* Bad Block Register 0 */
|
||||
#define NDBDR1 (0x20) /* Bad Block Register 1 */
|
||||
+#define NDECCCTRL (0x28) /* ECC control */
|
||||
#define NDDB (0x40) /* Data Buffer */
|
||||
#define NDCB0 (0x48) /* Command Buffer0 */
|
||||
#define NDCB1 (0x4C) /* Command Buffer1 */
|
||||
@@ -198,6 +199,7 @@ struct pxa3xx_nand_info {
|
||||
|
||||
int cs;
|
||||
int use_ecc; /* use HW ECC ? */
|
||||
+ int ecc_bch; /* using BCH ECC? */
|
||||
int use_dma; /* use DMA ? */
|
||||
int use_spare; /* use spare ? */
|
||||
int need_wait;
|
||||
@@ -205,6 +207,8 @@ struct pxa3xx_nand_info {
|
||||
unsigned int fifo_size; /* max. data size in the FIFO */
|
||||
unsigned int data_size; /* data to be read from FIFO */
|
||||
unsigned int oob_size;
|
||||
+ unsigned int spare_size;
|
||||
+ unsigned int ecc_size;
|
||||
int retcode;
|
||||
|
||||
/* cached register value */
|
||||
@@ -339,19 +343,12 @@ static void pxa3xx_set_datasize(struct p
|
||||
int oob_enable = info->reg_ndcr & NDCR_SPARE_EN;
|
||||
|
||||
info->data_size = info->fifo_size;
|
||||
- if (!oob_enable) {
|
||||
- info->oob_size = 0;
|
||||
+ if (!oob_enable)
|
||||
return;
|
||||
- }
|
||||
|
||||
- switch (info->fifo_size) {
|
||||
- case 2048:
|
||||
- info->oob_size = (info->use_ecc) ? 40 : 64;
|
||||
- break;
|
||||
- case 512:
|
||||
- info->oob_size = (info->use_ecc) ? 8 : 16;
|
||||
- break;
|
||||
- }
|
||||
+ info->oob_size = info->spare_size;
|
||||
+ if (!info->use_ecc)
|
||||
+ info->oob_size += info->ecc_size;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -366,10 +363,15 @@ static void pxa3xx_nand_start(struct pxa
|
||||
|
||||
ndcr = info->reg_ndcr;
|
||||
|
||||
- if (info->use_ecc)
|
||||
+ if (info->use_ecc) {
|
||||
ndcr |= NDCR_ECC_EN;
|
||||
- else
|
||||
+ if (info->ecc_bch)
|
||||
+ nand_writel(info, NDECCCTRL, 0x1);
|
||||
+ } else {
|
||||
ndcr &= ~NDCR_ECC_EN;
|
||||
+ if (info->ecc_bch)
|
||||
+ nand_writel(info, NDECCCTRL, 0x0);
|
||||
+ }
|
||||
|
||||
if (info->use_dma)
|
||||
ndcr |= NDCR_DMA_EN;
|
||||
@@ -1071,6 +1073,41 @@ static int pxa3xx_nand_sensing(struct px
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static int pxa_ecc_init(struct pxa3xx_nand_info *info,
|
||||
+ struct nand_ecc_ctrl *ecc,
|
||||
+ int strength, int page_size)
|
||||
+{
|
||||
+ /*
|
||||
+ * We don't use strength here as the PXA variant
|
||||
+ * is used with non-ONFI compliant devices.
|
||||
+ */
|
||||
+ if (page_size == 2048) {
|
||||
+ info->spare_size = 40;
|
||||
+ info->ecc_size = 24;
|
||||
+ ecc->mode = NAND_ECC_HW;
|
||||
+ ecc->size = 512;
|
||||
+ ecc->strength = 1;
|
||||
+ return 1;
|
||||
+
|
||||
+ } else if (page_size == 512) {
|
||||
+ info->spare_size = 8;
|
||||
+ info->ecc_size = 8;
|
||||
+ ecc->mode = NAND_ECC_HW;
|
||||
+ ecc->size = 512;
|
||||
+ ecc->strength = 1;
|
||||
+ return 1;
|
||||
+ }
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int armada370_ecc_init(struct pxa3xx_nand_info *info,
|
||||
+ struct nand_ecc_ctrl *ecc,
|
||||
+ int strength, int page_size)
|
||||
+{
|
||||
+ /* Unimplemented yet */
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
static int pxa3xx_nand_scan(struct mtd_info *mtd)
|
||||
{
|
||||
struct pxa3xx_nand_host *host = mtd->priv;
|
||||
@@ -1141,13 +1178,13 @@ static int pxa3xx_nand_scan(struct mtd_i
|
||||
pxa3xx_flash_ids[1].name = NULL;
|
||||
def = pxa3xx_flash_ids;
|
||||
KEEP_CONFIG:
|
||||
- chip->ecc.mode = NAND_ECC_HW;
|
||||
- chip->ecc.size = info->fifo_size;
|
||||
- chip->ecc.strength = 1;
|
||||
-
|
||||
if (info->reg_ndcr & NDCR_DWIDTH_M)
|
||||
chip->options |= NAND_BUSWIDTH_16;
|
||||
|
||||
+ /* Device detection must be done with ECC disabled */
|
||||
+ if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370)
|
||||
+ nand_writel(info, NDECCCTRL, 0x0);
|
||||
+
|
||||
if (nand_scan_ident(mtd, 1, def))
|
||||
return -ENODEV;
|
||||
|
||||
@@ -1162,6 +1199,21 @@ KEEP_CONFIG:
|
||||
chip->bbt_md = &bbt_mirror_descr;
|
||||
}
|
||||
|
||||
+ if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370)
|
||||
+ ret = armada370_ecc_init(info, &chip->ecc,
|
||||
+ chip->ecc_strength_ds,
|
||||
+ mtd->writesize);
|
||||
+ else
|
||||
+ ret = pxa_ecc_init(info, &chip->ecc,
|
||||
+ chip->ecc_strength_ds,
|
||||
+ mtd->writesize);
|
||||
+ if (!ret) {
|
||||
+ dev_err(&info->pdev->dev,
|
||||
+ "ECC strength %d at page size %d is not supported\n",
|
||||
+ chip->ecc_strength_ds, mtd->writesize);
|
||||
+ return -ENODEV;
|
||||
+ }
|
||||
+
|
||||
/* calculate addressing information */
|
||||
if (mtd->writesize >= 2048)
|
||||
host->col_addr_cycles = 2;
|
|
@ -0,0 +1,34 @@
|
|||
From cb574fecefd9552e5c6c5105adab7b37b0feb712 Mon Sep 17 00:00:00 2001
|
||||
From: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
Date: Thu, 14 Nov 2013 18:25:30 -0300
|
||||
Subject: [PATCH 144/203] mtd: nand: pxa3xx: Clear cmd buffer #3 (NDCB3) on
|
||||
command start
|
||||
|
||||
Command buffer #3 is not properly cleared and it keeps the last
|
||||
set value. Fix this by clearing when a command is setup.
|
||||
|
||||
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
Tested-by: Daniel Mack <zonque@gmail.com>
|
||||
Signed-off-by: Brian Norris <computersforpeace@gmail.com>
|
||||
---
|
||||
drivers/mtd/nand/pxa3xx_nand.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/mtd/nand/pxa3xx_nand.c
|
||||
+++ b/drivers/mtd/nand/pxa3xx_nand.c
|
||||
@@ -606,6 +606,7 @@ static int prepare_command_pool(struct p
|
||||
info->use_ecc = 0;
|
||||
info->use_spare = 1;
|
||||
info->retcode = ERR_NONE;
|
||||
+ info->ndcb3 = 0;
|
||||
if (info->cs != 0)
|
||||
info->ndcb0 = NDCB0_CSEL;
|
||||
else
|
||||
@@ -627,7 +628,6 @@ static int prepare_command_pool(struct p
|
||||
default:
|
||||
info->ndcb1 = 0;
|
||||
info->ndcb2 = 0;
|
||||
- info->ndcb3 = 0;
|
||||
break;
|
||||
}
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
From 09a84f8e89c3715160423701b0606ef99e2a05bf Mon Sep 17 00:00:00 2001
|
||||
From: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
Date: Thu, 14 Nov 2013 18:25:31 -0300
|
||||
Subject: [PATCH 145/203] mtd: nand: pxa3xx: Add helper function to set page
|
||||
address
|
||||
|
||||
Let's simplify the code by first introducing a helper function
|
||||
to set the page address, as done by the READ0, READOOB and SEQIN
|
||||
commands.
|
||||
|
||||
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
Tested-by: Daniel Mack <zonque@gmail.com>
|
||||
Signed-off-by: Brian Norris <computersforpeace@gmail.com>
|
||||
---
|
||||
drivers/mtd/nand/pxa3xx_nand.c | 36 +++++++++++++++++++++---------------
|
||||
1 file changed, 21 insertions(+), 15 deletions(-)
|
||||
|
||||
--- a/drivers/mtd/nand/pxa3xx_nand.c
|
||||
+++ b/drivers/mtd/nand/pxa3xx_nand.c
|
||||
@@ -587,6 +587,26 @@ static inline int is_buf_blank(uint8_t *
|
||||
return 1;
|
||||
}
|
||||
|
||||
+static void set_command_address(struct pxa3xx_nand_info *info,
|
||||
+ unsigned int page_size, uint16_t column, int page_addr)
|
||||
+{
|
||||
+ /* small page addr setting */
|
||||
+ if (page_size < PAGE_CHUNK_SIZE) {
|
||||
+ info->ndcb1 = ((page_addr & 0xFFFFFF) << 8)
|
||||
+ | (column & 0xFF);
|
||||
+
|
||||
+ info->ndcb2 = 0;
|
||||
+ } else {
|
||||
+ info->ndcb1 = ((page_addr & 0xFFFF) << 16)
|
||||
+ | (column & 0xFFFF);
|
||||
+
|
||||
+ if (page_addr & 0xFF0000)
|
||||
+ info->ndcb2 = (page_addr & 0xFF0000) >> 16;
|
||||
+ else
|
||||
+ info->ndcb2 = 0;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
static int prepare_command_pool(struct pxa3xx_nand_info *info, int command,
|
||||
uint16_t column, int page_addr)
|
||||
{
|
||||
@@ -650,22 +670,8 @@ static int prepare_command_pool(struct p
|
||||
info->ndcb0 |= NDCB0_DBC | (NAND_CMD_READSTART << 8);
|
||||
|
||||
case NAND_CMD_SEQIN:
|
||||
- /* small page addr setting */
|
||||
- if (unlikely(mtd->writesize < PAGE_CHUNK_SIZE)) {
|
||||
- info->ndcb1 = ((page_addr & 0xFFFFFF) << 8)
|
||||
- | (column & 0xFF);
|
||||
-
|
||||
- info->ndcb2 = 0;
|
||||
- } else {
|
||||
- info->ndcb1 = ((page_addr & 0xFFFF) << 16)
|
||||
- | (column & 0xFFFF);
|
||||
-
|
||||
- if (page_addr & 0xFF0000)
|
||||
- info->ndcb2 = (page_addr & 0xFF0000) >> 16;
|
||||
- else
|
||||
- info->ndcb2 = 0;
|
||||
- }
|
||||
|
||||
+ set_command_address(info, mtd->writesize, column, page_addr);
|
||||
info->buf_count = mtd->writesize + mtd->oobsize;
|
||||
memset(info->data_buff, 0xFF, info->buf_count);
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
From 11532c10a29e4faef29b5f3b354391d1e2f90213 Mon Sep 17 00:00:00 2001
|
||||
From: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
Date: Thu, 14 Nov 2013 18:25:32 -0300
|
||||
Subject: [PATCH 146/203] mtd: nand: pxa3xx: Remove READ0 switch/case
|
||||
falltrough
|
||||
|
||||
READ0 and READOOB command preparation has a falltrough to SEQIN
|
||||
case, where the command address is specified.
|
||||
This is certainly confusing and makes the code less readable with
|
||||
no added value. Let's remove it.
|
||||
|
||||
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
Tested-by: Daniel Mack <zonque@gmail.com>
|
||||
Signed-off-by: Brian Norris <computersforpeace@gmail.com>
|
||||
---
|
||||
drivers/mtd/nand/pxa3xx_nand.c | 5 +++++
|
||||
1 file changed, 5 insertions(+)
|
||||
|
||||
--- a/drivers/mtd/nand/pxa3xx_nand.c
|
||||
+++ b/drivers/mtd/nand/pxa3xx_nand.c
|
||||
@@ -669,6 +669,11 @@ static int prepare_command_pool(struct p
|
||||
if (mtd->writesize >= PAGE_CHUNK_SIZE)
|
||||
info->ndcb0 |= NDCB0_DBC | (NAND_CMD_READSTART << 8);
|
||||
|
||||
+ set_command_address(info, mtd->writesize, column, page_addr);
|
||||
+ info->buf_count = mtd->writesize + mtd->oobsize;
|
||||
+ memset(info->data_buff, 0xFF, info->buf_count);
|
||||
+ break;
|
||||
+
|
||||
case NAND_CMD_SEQIN:
|
||||
|
||||
set_command_address(info, mtd->writesize, column, page_addr);
|
|
@ -0,0 +1,101 @@
|
|||
From 78c8c8dc7e27c4502504cb4daa07bc9762f54de9 Mon Sep 17 00:00:00 2001
|
||||
From: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
Date: Thu, 14 Nov 2013 18:25:33 -0300
|
||||
Subject: [PATCH 147/203] mtd: nand: pxa3xx: Split prepare_command_pool() in
|
||||
two stages
|
||||
|
||||
This commit splits the prepare_command_pool() function into two
|
||||
stages: prepare_start_command() / prepare_set_command().
|
||||
|
||||
This is a preparation patch without any functionality changes,
|
||||
and is meant to allow support for multiple page reading/writing
|
||||
operations.
|
||||
|
||||
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
Tested-by: Daniel Mack <zonque@gmail.com>
|
||||
Signed-off-by: Brian Norris <computersforpeace@gmail.com>
|
||||
---
|
||||
drivers/mtd/nand/pxa3xx_nand.c | 44 ++++++++++++++++++++++++------------------
|
||||
1 file changed, 25 insertions(+), 19 deletions(-)
|
||||
|
||||
--- a/drivers/mtd/nand/pxa3xx_nand.c
|
||||
+++ b/drivers/mtd/nand/pxa3xx_nand.c
|
||||
@@ -607,18 +607,8 @@ static void set_command_address(struct p
|
||||
}
|
||||
}
|
||||
|
||||
-static int prepare_command_pool(struct pxa3xx_nand_info *info, int command,
|
||||
- uint16_t column, int page_addr)
|
||||
+static void prepare_start_command(struct pxa3xx_nand_info *info, int command)
|
||||
{
|
||||
- int addr_cycle, exec_cmd;
|
||||
- struct pxa3xx_nand_host *host;
|
||||
- struct mtd_info *mtd;
|
||||
-
|
||||
- host = info->host[info->cs];
|
||||
- mtd = host->mtd;
|
||||
- addr_cycle = 0;
|
||||
- exec_cmd = 1;
|
||||
-
|
||||
/* reset data and oob column point to handle data */
|
||||
info->buf_start = 0;
|
||||
info->buf_count = 0;
|
||||
@@ -627,10 +617,6 @@ static int prepare_command_pool(struct p
|
||||
info->use_spare = 1;
|
||||
info->retcode = ERR_NONE;
|
||||
info->ndcb3 = 0;
|
||||
- if (info->cs != 0)
|
||||
- info->ndcb0 = NDCB0_CSEL;
|
||||
- else
|
||||
- info->ndcb0 = 0;
|
||||
|
||||
switch (command) {
|
||||
case NAND_CMD_READ0:
|
||||
@@ -642,14 +628,32 @@ static int prepare_command_pool(struct p
|
||||
case NAND_CMD_PARAM:
|
||||
info->use_spare = 0;
|
||||
break;
|
||||
- case NAND_CMD_SEQIN:
|
||||
- exec_cmd = 0;
|
||||
- break;
|
||||
default:
|
||||
info->ndcb1 = 0;
|
||||
info->ndcb2 = 0;
|
||||
break;
|
||||
}
|
||||
+}
|
||||
+
|
||||
+static int prepare_set_command(struct pxa3xx_nand_info *info, int command,
|
||||
+ uint16_t column, int page_addr)
|
||||
+{
|
||||
+ int addr_cycle, exec_cmd;
|
||||
+ struct pxa3xx_nand_host *host;
|
||||
+ struct mtd_info *mtd;
|
||||
+
|
||||
+ host = info->host[info->cs];
|
||||
+ mtd = host->mtd;
|
||||
+ addr_cycle = 0;
|
||||
+ exec_cmd = 1;
|
||||
+
|
||||
+ if (info->cs != 0)
|
||||
+ info->ndcb0 = NDCB0_CSEL;
|
||||
+ else
|
||||
+ info->ndcb0 = 0;
|
||||
+
|
||||
+ if (command == NAND_CMD_SEQIN)
|
||||
+ exec_cmd = 0;
|
||||
|
||||
addr_cycle = NDCB0_ADDR_CYC(host->row_addr_cycles
|
||||
+ host->col_addr_cycles);
|
||||
@@ -784,8 +788,10 @@ static void pxa3xx_nand_cmdfunc(struct m
|
||||
nand_writel(info, NDTR1CS0, info->ndtr1cs0);
|
||||
}
|
||||
|
||||
+ prepare_start_command(info, command);
|
||||
+
|
||||
info->state = STATE_PREPARED;
|
||||
- exec_cmd = prepare_command_pool(info, command, column, page_addr);
|
||||
+ exec_cmd = prepare_set_command(info, command, column, page_addr);
|
||||
if (exec_cmd) {
|
||||
init_completion(&info->cmd_complete);
|
||||
init_completion(&info->dev_ready);
|
|
@ -0,0 +1,69 @@
|
|||
From 1c0aed9b4cfb7bb891aab07a429436d017ac4d7c Mon Sep 17 00:00:00 2001
|
||||
From: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
Date: Thu, 14 Nov 2013 18:25:34 -0300
|
||||
Subject: [PATCH 148/203] mtd: nand: pxa3xx: Move the data buffer clean to
|
||||
prepare_start_command()
|
||||
|
||||
To allow future support of multiple page reading/writing, move the data
|
||||
buffer clean out of prepare_set_command().
|
||||
|
||||
This is done to prevent the data buffer from being cleaned on every command
|
||||
preparation, when a multiple command sequence is implemented to read/write
|
||||
pages larger than the FIFO size (2 KiB).
|
||||
|
||||
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
Tested-by: Daniel Mack <zonque@gmail.com>
|
||||
Signed-off-by: Brian Norris <computersforpeace@gmail.com>
|
||||
---
|
||||
drivers/mtd/nand/pxa3xx_nand.c | 21 ++++++++++++++++-----
|
||||
1 file changed, 16 insertions(+), 5 deletions(-)
|
||||
|
||||
--- a/drivers/mtd/nand/pxa3xx_nand.c
|
||||
+++ b/drivers/mtd/nand/pxa3xx_nand.c
|
||||
@@ -609,6 +609,9 @@ static void set_command_address(struct p
|
||||
|
||||
static void prepare_start_command(struct pxa3xx_nand_info *info, int command)
|
||||
{
|
||||
+ struct pxa3xx_nand_host *host = info->host[info->cs];
|
||||
+ struct mtd_info *mtd = host->mtd;
|
||||
+
|
||||
/* reset data and oob column point to handle data */
|
||||
info->buf_start = 0;
|
||||
info->buf_count = 0;
|
||||
@@ -633,6 +636,19 @@ static void prepare_start_command(struct
|
||||
info->ndcb2 = 0;
|
||||
break;
|
||||
}
|
||||
+
|
||||
+ /*
|
||||
+ * If we are about to issue a read command, or about to set
|
||||
+ * the write address, then clean the data buffer.
|
||||
+ */
|
||||
+ if (command == NAND_CMD_READ0 ||
|
||||
+ command == NAND_CMD_READOOB ||
|
||||
+ command == NAND_CMD_SEQIN) {
|
||||
+
|
||||
+ info->buf_count = mtd->writesize + mtd->oobsize;
|
||||
+ memset(info->data_buff, 0xFF, info->buf_count);
|
||||
+ }
|
||||
+
|
||||
}
|
||||
|
||||
static int prepare_set_command(struct pxa3xx_nand_info *info, int command,
|
||||
@@ -674,16 +690,11 @@ static int prepare_set_command(struct px
|
||||
info->ndcb0 |= NDCB0_DBC | (NAND_CMD_READSTART << 8);
|
||||
|
||||
set_command_address(info, mtd->writesize, column, page_addr);
|
||||
- info->buf_count = mtd->writesize + mtd->oobsize;
|
||||
- memset(info->data_buff, 0xFF, info->buf_count);
|
||||
break;
|
||||
|
||||
case NAND_CMD_SEQIN:
|
||||
|
||||
set_command_address(info, mtd->writesize, column, page_addr);
|
||||
- info->buf_count = mtd->writesize + mtd->oobsize;
|
||||
- memset(info->data_buff, 0xFF, info->buf_count);
|
||||
-
|
||||
break;
|
||||
|
||||
case NAND_CMD_PAGEPROG:
|
|
@ -0,0 +1,32 @@
|
|||
From d5c9b013c71a570737353270f94b9a52639fcea1 Mon Sep 17 00:00:00 2001
|
||||
From: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
Date: Thu, 14 Nov 2013 18:25:35 -0300
|
||||
Subject: [PATCH 149/203] mtd: nand: pxa3xx: Fix SEQIN column address set
|
||||
|
||||
This commit adds support page programming with a non-zero "column"
|
||||
address setting. This is important to support OOB writing, through
|
||||
command sequences such as:
|
||||
|
||||
cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize, ofs);
|
||||
write_buf(mtd, oob_buf, 6);
|
||||
cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
|
||||
|
||||
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
Tested-by: Daniel Mack <zonque@gmail.com>
|
||||
Signed-off-by: Brian Norris <computersforpeace@gmail.com>
|
||||
---
|
||||
drivers/mtd/nand/pxa3xx_nand.c | 3 ++-
|
||||
1 file changed, 2 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/mtd/nand/pxa3xx_nand.c
|
||||
+++ b/drivers/mtd/nand/pxa3xx_nand.c
|
||||
@@ -694,7 +694,8 @@ static int prepare_set_command(struct px
|
||||
|
||||
case NAND_CMD_SEQIN:
|
||||
|
||||
- set_command_address(info, mtd->writesize, column, page_addr);
|
||||
+ info->buf_start = column;
|
||||
+ set_command_address(info, mtd->writesize, 0, page_addr);
|
||||
break;
|
||||
|
||||
case NAND_CMD_PAGEPROG:
|
|
@ -0,0 +1,111 @@
|
|||
From 6e3022aeb5d221af838ad43a2163374aecacf929 Mon Sep 17 00:00:00 2001
|
||||
From: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
Date: Thu, 14 Nov 2013 18:25:36 -0300
|
||||
Subject: [PATCH 150/203] mtd: nand: pxa3xx: Add a read/write buffers markers
|
||||
|
||||
In preparation to support multiple (aka chunked, aka splitted)
|
||||
page I/O, this commit adds 'data_buff_pos' and 'oob_buff_pos' fields
|
||||
to keep track of where the next read (or write) should be done.
|
||||
|
||||
This will allow multiple calls to handle_data_pio() to continue
|
||||
the read (or write) operation.
|
||||
|
||||
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
Tested-by: Daniel Mack <zonque@gmail.com>
|
||||
Signed-off-by: Brian Norris <computersforpeace@gmail.com>
|
||||
---
|
||||
drivers/mtd/nand/pxa3xx_nand.c | 40 +++++++++++++++++++++++++++++-----------
|
||||
1 file changed, 29 insertions(+), 11 deletions(-)
|
||||
|
||||
--- a/drivers/mtd/nand/pxa3xx_nand.c
|
||||
+++ b/drivers/mtd/nand/pxa3xx_nand.c
|
||||
@@ -176,6 +176,8 @@ struct pxa3xx_nand_info {
|
||||
unsigned int buf_start;
|
||||
unsigned int buf_count;
|
||||
unsigned int buf_size;
|
||||
+ unsigned int data_buff_pos;
|
||||
+ unsigned int oob_buff_pos;
|
||||
|
||||
/* DMA information */
|
||||
int drcmr_dat;
|
||||
@@ -338,11 +340,12 @@ static void pxa3xx_nand_set_timing(struc
|
||||
* spare and ECC configuration.
|
||||
* Only applicable to READ0, READOOB and PAGEPROG commands.
|
||||
*/
|
||||
-static void pxa3xx_set_datasize(struct pxa3xx_nand_info *info)
|
||||
+static void pxa3xx_set_datasize(struct pxa3xx_nand_info *info,
|
||||
+ struct mtd_info *mtd)
|
||||
{
|
||||
int oob_enable = info->reg_ndcr & NDCR_SPARE_EN;
|
||||
|
||||
- info->data_size = info->fifo_size;
|
||||
+ info->data_size = mtd->writesize;
|
||||
if (!oob_enable)
|
||||
return;
|
||||
|
||||
@@ -430,26 +433,39 @@ static void disable_int(struct pxa3xx_na
|
||||
|
||||
static void handle_data_pio(struct pxa3xx_nand_info *info)
|
||||
{
|
||||
+ unsigned int do_bytes = min(info->data_size, info->fifo_size);
|
||||
+
|
||||
switch (info->state) {
|
||||
case STATE_PIO_WRITING:
|
||||
- __raw_writesl(info->mmio_base + NDDB, info->data_buff,
|
||||
- DIV_ROUND_UP(info->data_size, 4));
|
||||
+ __raw_writesl(info->mmio_base + NDDB,
|
||||
+ info->data_buff + info->data_buff_pos,
|
||||
+ DIV_ROUND_UP(do_bytes, 4));
|
||||
+
|
||||
if (info->oob_size > 0)
|
||||
- __raw_writesl(info->mmio_base + NDDB, info->oob_buff,
|
||||
- DIV_ROUND_UP(info->oob_size, 4));
|
||||
+ __raw_writesl(info->mmio_base + NDDB,
|
||||
+ info->oob_buff + info->oob_buff_pos,
|
||||
+ DIV_ROUND_UP(info->oob_size, 4));
|
||||
break;
|
||||
case STATE_PIO_READING:
|
||||
- __raw_readsl(info->mmio_base + NDDB, info->data_buff,
|
||||
- DIV_ROUND_UP(info->data_size, 4));
|
||||
+ __raw_readsl(info->mmio_base + NDDB,
|
||||
+ info->data_buff + info->data_buff_pos,
|
||||
+ DIV_ROUND_UP(do_bytes, 4));
|
||||
+
|
||||
if (info->oob_size > 0)
|
||||
- __raw_readsl(info->mmio_base + NDDB, info->oob_buff,
|
||||
- DIV_ROUND_UP(info->oob_size, 4));
|
||||
+ __raw_readsl(info->mmio_base + NDDB,
|
||||
+ info->oob_buff + info->oob_buff_pos,
|
||||
+ DIV_ROUND_UP(info->oob_size, 4));
|
||||
break;
|
||||
default:
|
||||
dev_err(&info->pdev->dev, "%s: invalid state %d\n", __func__,
|
||||
info->state);
|
||||
BUG();
|
||||
}
|
||||
+
|
||||
+ /* Update buffer pointers for multi-page read/write */
|
||||
+ info->data_buff_pos += do_bytes;
|
||||
+ info->oob_buff_pos += info->oob_size;
|
||||
+ info->data_size -= do_bytes;
|
||||
}
|
||||
|
||||
#ifdef ARCH_HAS_DMA
|
||||
@@ -616,6 +632,8 @@ static void prepare_start_command(struct
|
||||
info->buf_start = 0;
|
||||
info->buf_count = 0;
|
||||
info->oob_size = 0;
|
||||
+ info->data_buff_pos = 0;
|
||||
+ info->oob_buff_pos = 0;
|
||||
info->use_ecc = 0;
|
||||
info->use_spare = 1;
|
||||
info->retcode = ERR_NONE;
|
||||
@@ -626,7 +644,7 @@ static void prepare_start_command(struct
|
||||
case NAND_CMD_PAGEPROG:
|
||||
info->use_ecc = 1;
|
||||
case NAND_CMD_READOOB:
|
||||
- pxa3xx_set_datasize(info);
|
||||
+ pxa3xx_set_datasize(info, mtd);
|
||||
break;
|
||||
case NAND_CMD_PARAM:
|
||||
info->use_spare = 0;
|
|
@ -0,0 +1,325 @@
|
|||
From cfd1799f9ec5c9820f371e1fcf2f3c458bd24ebb Mon Sep 17 00:00:00 2001
|
||||
From: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
Date: Thu, 14 Nov 2013 18:25:37 -0300
|
||||
Subject: [PATCH 151/203] mtd: nand: pxa3xx: Introduce multiple page I/O
|
||||
support
|
||||
|
||||
As preparation work to fully support large pages, this commit adds
|
||||
the initial infrastructure to support splitted (aka chunked) I/O
|
||||
operation. This commit adds support for read, and follow-up patches
|
||||
will add write support.
|
||||
|
||||
When a read (aka READ0) command is issued, the driver loops issuing
|
||||
the same command until all the requested data is transfered, changing
|
||||
the 'extended' command field as needed.
|
||||
|
||||
For instance, if the driver is required to read a 4 KiB page, using a
|
||||
chunk size of 2 KiB, the transaction is splitted in:
|
||||
1. Monolithic read, first 2 KiB page chunk is read
|
||||
2. Last naked read, second and last 2KiB page chunk is read
|
||||
|
||||
If ECC is enabled it is calculated on each chunk transfered and added
|
||||
at a controller-fixed location after the data chunk that must be
|
||||
spare area.
|
||||
|
||||
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
Tested-by: Daniel Mack <zonque@gmail.com>
|
||||
Signed-off-by: Brian Norris <computersforpeace@gmail.com>
|
||||
---
|
||||
drivers/mtd/nand/pxa3xx_nand.c | 182 ++++++++++++++++++++++++++++++++++++++---
|
||||
1 file changed, 172 insertions(+), 10 deletions(-)
|
||||
|
||||
--- a/drivers/mtd/nand/pxa3xx_nand.c
|
||||
+++ b/drivers/mtd/nand/pxa3xx_nand.c
|
||||
@@ -103,6 +103,8 @@
|
||||
#define NDCB0_ST_ROW_EN (0x1 << 26)
|
||||
#define NDCB0_AUTO_RS (0x1 << 25)
|
||||
#define NDCB0_CSEL (0x1 << 24)
|
||||
+#define NDCB0_EXT_CMD_TYPE_MASK (0x7 << 29)
|
||||
+#define NDCB0_EXT_CMD_TYPE(x) (((x) << 29) & NDCB0_EXT_CMD_TYPE_MASK)
|
||||
#define NDCB0_CMD_TYPE_MASK (0x7 << 21)
|
||||
#define NDCB0_CMD_TYPE(x) (((x) << 21) & NDCB0_CMD_TYPE_MASK)
|
||||
#define NDCB0_NC (0x1 << 20)
|
||||
@@ -113,6 +115,14 @@
|
||||
#define NDCB0_CMD1_MASK (0xff)
|
||||
#define NDCB0_ADDR_CYC_SHIFT (16)
|
||||
|
||||
+#define EXT_CMD_TYPE_DISPATCH 6 /* Command dispatch */
|
||||
+#define EXT_CMD_TYPE_NAKED_RW 5 /* Naked read or Naked write */
|
||||
+#define EXT_CMD_TYPE_READ 4 /* Read */
|
||||
+#define EXT_CMD_TYPE_DISP_WR 4 /* Command dispatch with write */
|
||||
+#define EXT_CMD_TYPE_FINAL 3 /* Final command */
|
||||
+#define EXT_CMD_TYPE_LAST_RW 1 /* Last naked read/write */
|
||||
+#define EXT_CMD_TYPE_MONO 0 /* Monolithic read/write */
|
||||
+
|
||||
/* macros for registers read/write */
|
||||
#define nand_writel(info, off, val) \
|
||||
__raw_writel((val), (info)->mmio_base + (off))
|
||||
@@ -206,8 +216,8 @@ struct pxa3xx_nand_info {
|
||||
int use_spare; /* use spare ? */
|
||||
int need_wait;
|
||||
|
||||
- unsigned int fifo_size; /* max. data size in the FIFO */
|
||||
unsigned int data_size; /* data to be read from FIFO */
|
||||
+ unsigned int chunk_size; /* split commands chunk size */
|
||||
unsigned int oob_size;
|
||||
unsigned int spare_size;
|
||||
unsigned int ecc_size;
|
||||
@@ -271,6 +281,31 @@ static struct nand_bbt_descr bbt_mirror_
|
||||
.pattern = bbt_mirror_pattern
|
||||
};
|
||||
|
||||
+static struct nand_ecclayout ecc_layout_4KB_bch4bit = {
|
||||
+ .eccbytes = 64,
|
||||
+ .eccpos = {
|
||||
+ 32, 33, 34, 35, 36, 37, 38, 39,
|
||||
+ 40, 41, 42, 43, 44, 45, 46, 47,
|
||||
+ 48, 49, 50, 51, 52, 53, 54, 55,
|
||||
+ 56, 57, 58, 59, 60, 61, 62, 63,
|
||||
+ 96, 97, 98, 99, 100, 101, 102, 103,
|
||||
+ 104, 105, 106, 107, 108, 109, 110, 111,
|
||||
+ 112, 113, 114, 115, 116, 117, 118, 119,
|
||||
+ 120, 121, 122, 123, 124, 125, 126, 127},
|
||||
+ /* Bootrom looks in bytes 0 & 5 for bad blocks */
|
||||
+ .oobfree = { {6, 26}, { 64, 32} }
|
||||
+};
|
||||
+
|
||||
+static struct nand_ecclayout ecc_layout_4KB_bch8bit = {
|
||||
+ .eccbytes = 128,
|
||||
+ .eccpos = {
|
||||
+ 32, 33, 34, 35, 36, 37, 38, 39,
|
||||
+ 40, 41, 42, 43, 44, 45, 46, 47,
|
||||
+ 48, 49, 50, 51, 52, 53, 54, 55,
|
||||
+ 56, 57, 58, 59, 60, 61, 62, 63},
|
||||
+ .oobfree = { }
|
||||
+};
|
||||
+
|
||||
/* Define a default flash type setting serve as flash detecting only */
|
||||
#define DEFAULT_FLASH_TYPE (&builtin_flash_types[0])
|
||||
|
||||
@@ -433,7 +468,7 @@ static void disable_int(struct pxa3xx_na
|
||||
|
||||
static void handle_data_pio(struct pxa3xx_nand_info *info)
|
||||
{
|
||||
- unsigned int do_bytes = min(info->data_size, info->fifo_size);
|
||||
+ unsigned int do_bytes = min(info->data_size, info->chunk_size);
|
||||
|
||||
switch (info->state) {
|
||||
case STATE_PIO_WRITING:
|
||||
@@ -670,7 +705,7 @@ static void prepare_start_command(struct
|
||||
}
|
||||
|
||||
static int prepare_set_command(struct pxa3xx_nand_info *info, int command,
|
||||
- uint16_t column, int page_addr)
|
||||
+ int ext_cmd_type, uint16_t column, int page_addr)
|
||||
{
|
||||
int addr_cycle, exec_cmd;
|
||||
struct pxa3xx_nand_host *host;
|
||||
@@ -703,9 +738,20 @@ static int prepare_set_command(struct px
|
||||
if (command == NAND_CMD_READOOB)
|
||||
info->buf_start += mtd->writesize;
|
||||
|
||||
- /* Second command setting for large pages */
|
||||
- if (mtd->writesize >= PAGE_CHUNK_SIZE)
|
||||
+ /*
|
||||
+ * Multiple page read needs an 'extended command type' field,
|
||||
+ * which is either naked-read or last-read according to the
|
||||
+ * state.
|
||||
+ */
|
||||
+ if (mtd->writesize == PAGE_CHUNK_SIZE) {
|
||||
info->ndcb0 |= NDCB0_DBC | (NAND_CMD_READSTART << 8);
|
||||
+ } else if (mtd->writesize > PAGE_CHUNK_SIZE) {
|
||||
+ info->ndcb0 |= NDCB0_DBC | (NAND_CMD_READSTART << 8)
|
||||
+ | NDCB0_LEN_OVRD
|
||||
+ | NDCB0_EXT_CMD_TYPE(ext_cmd_type);
|
||||
+ info->ndcb3 = info->chunk_size +
|
||||
+ info->oob_size;
|
||||
+ }
|
||||
|
||||
set_command_address(info, mtd->writesize, column, page_addr);
|
||||
break;
|
||||
@@ -821,7 +867,8 @@ static void pxa3xx_nand_cmdfunc(struct m
|
||||
prepare_start_command(info, command);
|
||||
|
||||
info->state = STATE_PREPARED;
|
||||
- exec_cmd = prepare_set_command(info, command, column, page_addr);
|
||||
+ exec_cmd = prepare_set_command(info, command, 0, column, page_addr);
|
||||
+
|
||||
if (exec_cmd) {
|
||||
init_completion(&info->cmd_complete);
|
||||
init_completion(&info->dev_ready);
|
||||
@@ -839,6 +886,93 @@ static void pxa3xx_nand_cmdfunc(struct m
|
||||
info->state = STATE_IDLE;
|
||||
}
|
||||
|
||||
+static void armada370_nand_cmdfunc(struct mtd_info *mtd,
|
||||
+ const unsigned command,
|
||||
+ int column, int page_addr)
|
||||
+{
|
||||
+ struct pxa3xx_nand_host *host = mtd->priv;
|
||||
+ struct pxa3xx_nand_info *info = host->info_data;
|
||||
+ int ret, exec_cmd, ext_cmd_type;
|
||||
+
|
||||
+ /*
|
||||
+ * if this is a x16 device then convert the input
|
||||
+ * "byte" address into a "word" address appropriate
|
||||
+ * for indexing a word-oriented device
|
||||
+ */
|
||||
+ if (info->reg_ndcr & NDCR_DWIDTH_M)
|
||||
+ column /= 2;
|
||||
+
|
||||
+ /*
|
||||
+ * There may be different NAND chip hooked to
|
||||
+ * different chip select, so check whether
|
||||
+ * chip select has been changed, if yes, reset the timing
|
||||
+ */
|
||||
+ if (info->cs != host->cs) {
|
||||
+ info->cs = host->cs;
|
||||
+ nand_writel(info, NDTR0CS0, info->ndtr0cs0);
|
||||
+ nand_writel(info, NDTR1CS0, info->ndtr1cs0);
|
||||
+ }
|
||||
+
|
||||
+ /* Select the extended command for the first command */
|
||||
+ switch (command) {
|
||||
+ case NAND_CMD_READ0:
|
||||
+ case NAND_CMD_READOOB:
|
||||
+ ext_cmd_type = EXT_CMD_TYPE_MONO;
|
||||
+ break;
|
||||
+ default:
|
||||
+ ext_cmd_type = 0;
|
||||
+ }
|
||||
+
|
||||
+ prepare_start_command(info, command);
|
||||
+
|
||||
+ /*
|
||||
+ * Prepare the "is ready" completion before starting a command
|
||||
+ * transaction sequence. If the command is not executed the
|
||||
+ * completion will be completed, see below.
|
||||
+ *
|
||||
+ * We can do that inside the loop because the command variable
|
||||
+ * is invariant and thus so is the exec_cmd.
|
||||
+ */
|
||||
+ info->need_wait = 1;
|
||||
+ init_completion(&info->dev_ready);
|
||||
+ do {
|
||||
+ info->state = STATE_PREPARED;
|
||||
+ exec_cmd = prepare_set_command(info, command, ext_cmd_type,
|
||||
+ column, page_addr);
|
||||
+ if (!exec_cmd) {
|
||||
+ info->need_wait = 0;
|
||||
+ complete(&info->dev_ready);
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ init_completion(&info->cmd_complete);
|
||||
+ pxa3xx_nand_start(info);
|
||||
+
|
||||
+ ret = wait_for_completion_timeout(&info->cmd_complete,
|
||||
+ CHIP_DELAY_TIMEOUT);
|
||||
+ if (!ret) {
|
||||
+ dev_err(&info->pdev->dev, "Wait time out!!!\n");
|
||||
+ /* Stop State Machine for next command cycle */
|
||||
+ pxa3xx_nand_stop(info);
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ /* Check if the sequence is complete */
|
||||
+ if (info->data_size == 0)
|
||||
+ break;
|
||||
+
|
||||
+ if (command == NAND_CMD_READ0 || command == NAND_CMD_READOOB) {
|
||||
+ /* Last read: issue a 'last naked read' */
|
||||
+ if (info->data_size == info->chunk_size)
|
||||
+ ext_cmd_type = EXT_CMD_TYPE_LAST_RW;
|
||||
+ else
|
||||
+ ext_cmd_type = EXT_CMD_TYPE_NAKED_RW;
|
||||
+ }
|
||||
+ } while (1);
|
||||
+
|
||||
+ info->state = STATE_IDLE;
|
||||
+}
|
||||
+
|
||||
static int pxa3xx_nand_write_page_hwecc(struct mtd_info *mtd,
|
||||
struct nand_chip *chip, const uint8_t *buf, int oob_required)
|
||||
{
|
||||
@@ -1019,13 +1153,14 @@ static int pxa3xx_nand_detect_config(str
|
||||
|
||||
if (ndcr & NDCR_PAGE_SZ) {
|
||||
/* Controller's FIFO size */
|
||||
- info->fifo_size = 2048;
|
||||
+ info->chunk_size = 2048;
|
||||
host->read_id_bytes = 4;
|
||||
} else {
|
||||
- info->fifo_size = 512;
|
||||
+ info->chunk_size = 512;
|
||||
host->read_id_bytes = 2;
|
||||
}
|
||||
|
||||
+ /* Set an initial chunk size */
|
||||
info->reg_ndcr = ndcr & ~NDCR_INT_MASK;
|
||||
info->ndtr0cs0 = nand_readl(info, NDTR0CS0);
|
||||
info->ndtr1cs0 = nand_readl(info, NDTR1CS0);
|
||||
@@ -1129,6 +1264,7 @@ static int pxa_ecc_init(struct pxa3xx_na
|
||||
* is used with non-ONFI compliant devices.
|
||||
*/
|
||||
if (page_size == 2048) {
|
||||
+ info->chunk_size = 2048;
|
||||
info->spare_size = 40;
|
||||
info->ecc_size = 24;
|
||||
ecc->mode = NAND_ECC_HW;
|
||||
@@ -1137,6 +1273,7 @@ static int pxa_ecc_init(struct pxa3xx_na
|
||||
return 1;
|
||||
|
||||
} else if (page_size == 512) {
|
||||
+ info->chunk_size = 512;
|
||||
info->spare_size = 8;
|
||||
info->ecc_size = 8;
|
||||
ecc->mode = NAND_ECC_HW;
|
||||
@@ -1151,7 +1288,28 @@ static int armada370_ecc_init(struct pxa
|
||||
struct nand_ecc_ctrl *ecc,
|
||||
int strength, int page_size)
|
||||
{
|
||||
- /* Unimplemented yet */
|
||||
+ if (strength == 4 && page_size == 4096) {
|
||||
+ info->ecc_bch = 1;
|
||||
+ info->chunk_size = 2048;
|
||||
+ info->spare_size = 32;
|
||||
+ info->ecc_size = 32;
|
||||
+ ecc->mode = NAND_ECC_HW;
|
||||
+ ecc->size = info->chunk_size;
|
||||
+ ecc->layout = &ecc_layout_4KB_bch4bit;
|
||||
+ ecc->strength = 16;
|
||||
+ return 1;
|
||||
+
|
||||
+ } else if (strength == 8 && page_size == 4096) {
|
||||
+ info->ecc_bch = 1;
|
||||
+ info->chunk_size = 1024;
|
||||
+ info->spare_size = 0;
|
||||
+ info->ecc_size = 32;
|
||||
+ ecc->mode = NAND_ECC_HW;
|
||||
+ ecc->size = info->chunk_size;
|
||||
+ ecc->layout = &ecc_layout_4KB_bch8bit;
|
||||
+ ecc->strength = 16;
|
||||
+ return 1;
|
||||
+ }
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1319,12 +1477,16 @@ static int alloc_nand_resource(struct pl
|
||||
chip->controller = &info->controller;
|
||||
chip->waitfunc = pxa3xx_nand_waitfunc;
|
||||
chip->select_chip = pxa3xx_nand_select_chip;
|
||||
- chip->cmdfunc = pxa3xx_nand_cmdfunc;
|
||||
chip->read_word = pxa3xx_nand_read_word;
|
||||
chip->read_byte = pxa3xx_nand_read_byte;
|
||||
chip->read_buf = pxa3xx_nand_read_buf;
|
||||
chip->write_buf = pxa3xx_nand_write_buf;
|
||||
chip->options |= NAND_NO_SUBPAGE_WRITE;
|
||||
+
|
||||
+ if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370)
|
||||
+ chip->cmdfunc = armada370_nand_cmdfunc;
|
||||
+ else
|
||||
+ chip->cmdfunc = pxa3xx_nand_cmdfunc;
|
||||
}
|
||||
|
||||
spin_lock_init(&chip->controller->lock);
|
|
@ -0,0 +1,146 @@
|
|||
From db95c66cebb6297595a5a32b369d1033b08775ce Mon Sep 17 00:00:00 2001
|
||||
From: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
Date: Thu, 14 Nov 2013 18:25:38 -0300
|
||||
Subject: [PATCH 152/203] mtd: nand: pxa3xx: Add multiple chunk write support
|
||||
|
||||
This commit adds write support for large pages (4 KiB, 8 KiB).
|
||||
Such support is implemented by issuing a multiple command sequence,
|
||||
transfering a set of 2 KiB chunks per transaction.
|
||||
|
||||
The splitted command sequence requires to send the SEQIN command
|
||||
independently of the PAGEPROG command and therefore it's set as
|
||||
an execution command.
|
||||
|
||||
Since PAGEPROG enables ECC, each 2 KiB chunk of data is written
|
||||
together with ECC code at a controller-fixed location within
|
||||
the flash page.
|
||||
|
||||
Currently, only devices with a 4 KiB page size has been tested.
|
||||
|
||||
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
Tested-by: Daniel Mack <zonque@gmail.com>
|
||||
Signed-off-by: Brian Norris <computersforpeace@gmail.com>
|
||||
---
|
||||
drivers/mtd/nand/pxa3xx_nand.c | 81 +++++++++++++++++++++++++++++++++++++-----
|
||||
1 file changed, 73 insertions(+), 8 deletions(-)
|
||||
|
||||
--- a/drivers/mtd/nand/pxa3xx_nand.c
|
||||
+++ b/drivers/mtd/nand/pxa3xx_nand.c
|
||||
@@ -760,6 +760,20 @@ static int prepare_set_command(struct px
|
||||
|
||||
info->buf_start = column;
|
||||
set_command_address(info, mtd->writesize, 0, page_addr);
|
||||
+
|
||||
+ /*
|
||||
+ * Multiple page programming needs to execute the initial
|
||||
+ * SEQIN command that sets the page address.
|
||||
+ */
|
||||
+ if (mtd->writesize > PAGE_CHUNK_SIZE) {
|
||||
+ info->ndcb0 |= NDCB0_CMD_TYPE(0x1)
|
||||
+ | NDCB0_EXT_CMD_TYPE(ext_cmd_type)
|
||||
+ | addr_cycle
|
||||
+ | command;
|
||||
+ /* No data transfer in this case */
|
||||
+ info->data_size = 0;
|
||||
+ exec_cmd = 1;
|
||||
+ }
|
||||
break;
|
||||
|
||||
case NAND_CMD_PAGEPROG:
|
||||
@@ -769,13 +783,40 @@ static int prepare_set_command(struct px
|
||||
break;
|
||||
}
|
||||
|
||||
- info->ndcb0 |= NDCB0_CMD_TYPE(0x1)
|
||||
- | NDCB0_AUTO_RS
|
||||
- | NDCB0_ST_ROW_EN
|
||||
- | NDCB0_DBC
|
||||
- | (NAND_CMD_PAGEPROG << 8)
|
||||
- | NAND_CMD_SEQIN
|
||||
- | addr_cycle;
|
||||
+ /* Second command setting for large pages */
|
||||
+ if (mtd->writesize > PAGE_CHUNK_SIZE) {
|
||||
+ /*
|
||||
+ * Multiple page write uses the 'extended command'
|
||||
+ * field. This can be used to issue a command dispatch
|
||||
+ * or a naked-write depending on the current stage.
|
||||
+ */
|
||||
+ info->ndcb0 |= NDCB0_CMD_TYPE(0x1)
|
||||
+ | NDCB0_LEN_OVRD
|
||||
+ | NDCB0_EXT_CMD_TYPE(ext_cmd_type);
|
||||
+ info->ndcb3 = info->chunk_size +
|
||||
+ info->oob_size;
|
||||
+
|
||||
+ /*
|
||||
+ * This is the command dispatch that completes a chunked
|
||||
+ * page program operation.
|
||||
+ */
|
||||
+ if (info->data_size == 0) {
|
||||
+ info->ndcb0 = NDCB0_CMD_TYPE(0x1)
|
||||
+ | NDCB0_EXT_CMD_TYPE(ext_cmd_type)
|
||||
+ | command;
|
||||
+ info->ndcb1 = 0;
|
||||
+ info->ndcb2 = 0;
|
||||
+ info->ndcb3 = 0;
|
||||
+ }
|
||||
+ } else {
|
||||
+ info->ndcb0 |= NDCB0_CMD_TYPE(0x1)
|
||||
+ | NDCB0_AUTO_RS
|
||||
+ | NDCB0_ST_ROW_EN
|
||||
+ | NDCB0_DBC
|
||||
+ | (NAND_CMD_PAGEPROG << 8)
|
||||
+ | NAND_CMD_SEQIN
|
||||
+ | addr_cycle;
|
||||
+ }
|
||||
break;
|
||||
|
||||
case NAND_CMD_PARAM:
|
||||
@@ -919,8 +960,15 @@ static void armada370_nand_cmdfunc(struc
|
||||
case NAND_CMD_READOOB:
|
||||
ext_cmd_type = EXT_CMD_TYPE_MONO;
|
||||
break;
|
||||
+ case NAND_CMD_SEQIN:
|
||||
+ ext_cmd_type = EXT_CMD_TYPE_DISPATCH;
|
||||
+ break;
|
||||
+ case NAND_CMD_PAGEPROG:
|
||||
+ ext_cmd_type = EXT_CMD_TYPE_NAKED_RW;
|
||||
+ break;
|
||||
default:
|
||||
ext_cmd_type = 0;
|
||||
+ break;
|
||||
}
|
||||
|
||||
prepare_start_command(info, command);
|
||||
@@ -958,7 +1006,16 @@ static void armada370_nand_cmdfunc(struc
|
||||
}
|
||||
|
||||
/* Check if the sequence is complete */
|
||||
- if (info->data_size == 0)
|
||||
+ if (info->data_size == 0 && command != NAND_CMD_PAGEPROG)
|
||||
+ break;
|
||||
+
|
||||
+ /*
|
||||
+ * After a splitted program command sequence has issued
|
||||
+ * the command dispatch, the command sequence is complete.
|
||||
+ */
|
||||
+ if (info->data_size == 0 &&
|
||||
+ command == NAND_CMD_PAGEPROG &&
|
||||
+ ext_cmd_type == EXT_CMD_TYPE_DISPATCH)
|
||||
break;
|
||||
|
||||
if (command == NAND_CMD_READ0 || command == NAND_CMD_READOOB) {
|
||||
@@ -967,6 +1024,14 @@ static void armada370_nand_cmdfunc(struc
|
||||
ext_cmd_type = EXT_CMD_TYPE_LAST_RW;
|
||||
else
|
||||
ext_cmd_type = EXT_CMD_TYPE_NAKED_RW;
|
||||
+
|
||||
+ /*
|
||||
+ * If a splitted program command has no more data to transfer,
|
||||
+ * the command dispatch must be issued to complete.
|
||||
+ */
|
||||
+ } else if (command == NAND_CMD_PAGEPROG &&
|
||||
+ info->data_size == 0) {
|
||||
+ ext_cmd_type = EXT_CMD_TYPE_DISPATCH;
|
||||
}
|
||||
} while (1);
|
||||
|
|
@ -0,0 +1,144 @@
|
|||
From 26d82e0081aa6f0c7db5e4bb5b154b7c528cb8d6 Mon Sep 17 00:00:00 2001
|
||||
From: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
Date: Thu, 14 Nov 2013 18:25:39 -0300
|
||||
Subject: [PATCH 153/203] mtd: nand: pxa3xx: Add ECC BCH correctable errors
|
||||
detection
|
||||
|
||||
This commit extends the ECC correctable error detection to include
|
||||
ECC BCH errors. The number of BCH correctable errors can be any up to 16,
|
||||
and the actual value is exposed in the NDSR register.
|
||||
|
||||
Therefore, we change some symbol names to refer to correctable or
|
||||
uncorrectable (instead of single-bit or double-bit as it was in the
|
||||
Hamming case) and while at it, cleanup the detection code slightly.
|
||||
|
||||
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
Tested-by: Daniel Mack <zonque@gmail.com>
|
||||
Signed-off-by: Brian Norris <computersforpeace@gmail.com>
|
||||
---
|
||||
drivers/mtd/nand/pxa3xx_nand.c | 57 ++++++++++++++++++++++++++----------------
|
||||
1 file changed, 35 insertions(+), 22 deletions(-)
|
||||
|
||||
--- a/drivers/mtd/nand/pxa3xx_nand.c
|
||||
+++ b/drivers/mtd/nand/pxa3xx_nand.c
|
||||
@@ -85,6 +85,9 @@
|
||||
#define NDCR_INT_MASK (0xFFF)
|
||||
|
||||
#define NDSR_MASK (0xfff)
|
||||
+#define NDSR_ERR_CNT_OFF (16)
|
||||
+#define NDSR_ERR_CNT_MASK (0x1f)
|
||||
+#define NDSR_ERR_CNT(sr) ((sr >> NDSR_ERR_CNT_OFF) & NDSR_ERR_CNT_MASK)
|
||||
#define NDSR_RDY (0x1 << 12)
|
||||
#define NDSR_FLASH_RDY (0x1 << 11)
|
||||
#define NDSR_CS0_PAGED (0x1 << 10)
|
||||
@@ -93,8 +96,8 @@
|
||||
#define NDSR_CS1_CMDD (0x1 << 7)
|
||||
#define NDSR_CS0_BBD (0x1 << 6)
|
||||
#define NDSR_CS1_BBD (0x1 << 5)
|
||||
-#define NDSR_DBERR (0x1 << 4)
|
||||
-#define NDSR_SBERR (0x1 << 3)
|
||||
+#define NDSR_UNCORERR (0x1 << 4)
|
||||
+#define NDSR_CORERR (0x1 << 3)
|
||||
#define NDSR_WRDREQ (0x1 << 2)
|
||||
#define NDSR_RDDREQ (0x1 << 1)
|
||||
#define NDSR_WRCMDREQ (0x1)
|
||||
@@ -135,9 +138,9 @@ enum {
|
||||
ERR_NONE = 0,
|
||||
ERR_DMABUSERR = -1,
|
||||
ERR_SENDCMD = -2,
|
||||
- ERR_DBERR = -3,
|
||||
+ ERR_UNCORERR = -3,
|
||||
ERR_BBERR = -4,
|
||||
- ERR_SBERR = -5,
|
||||
+ ERR_CORERR = -5,
|
||||
};
|
||||
|
||||
enum {
|
||||
@@ -221,6 +224,8 @@ struct pxa3xx_nand_info {
|
||||
unsigned int oob_size;
|
||||
unsigned int spare_size;
|
||||
unsigned int ecc_size;
|
||||
+ unsigned int ecc_err_cnt;
|
||||
+ unsigned int max_bitflips;
|
||||
int retcode;
|
||||
|
||||
/* cached register value */
|
||||
@@ -571,10 +576,25 @@ static irqreturn_t pxa3xx_nand_irq(int i
|
||||
|
||||
status = nand_readl(info, NDSR);
|
||||
|
||||
- if (status & NDSR_DBERR)
|
||||
- info->retcode = ERR_DBERR;
|
||||
- if (status & NDSR_SBERR)
|
||||
- info->retcode = ERR_SBERR;
|
||||
+ if (status & NDSR_UNCORERR)
|
||||
+ info->retcode = ERR_UNCORERR;
|
||||
+ if (status & NDSR_CORERR) {
|
||||
+ info->retcode = ERR_CORERR;
|
||||
+ if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370 &&
|
||||
+ info->ecc_bch)
|
||||
+ info->ecc_err_cnt = NDSR_ERR_CNT(status);
|
||||
+ else
|
||||
+ info->ecc_err_cnt = 1;
|
||||
+
|
||||
+ /*
|
||||
+ * Each chunk composing a page is corrected independently,
|
||||
+ * and we need to store maximum number of corrected bitflips
|
||||
+ * to return it to the MTD layer in ecc.read_page().
|
||||
+ */
|
||||
+ info->max_bitflips = max_t(unsigned int,
|
||||
+ info->max_bitflips,
|
||||
+ info->ecc_err_cnt);
|
||||
+ }
|
||||
if (status & (NDSR_RDDREQ | NDSR_WRDREQ)) {
|
||||
/* whether use dma to transfer data */
|
||||
if (info->use_dma) {
|
||||
@@ -672,6 +692,7 @@ static void prepare_start_command(struct
|
||||
info->use_ecc = 0;
|
||||
info->use_spare = 1;
|
||||
info->retcode = ERR_NONE;
|
||||
+ info->ecc_err_cnt = 0;
|
||||
info->ndcb3 = 0;
|
||||
|
||||
switch (command) {
|
||||
@@ -1053,26 +1074,18 @@ static int pxa3xx_nand_read_page_hwecc(s
|
||||
{
|
||||
struct pxa3xx_nand_host *host = mtd->priv;
|
||||
struct pxa3xx_nand_info *info = host->info_data;
|
||||
- int max_bitflips = 0;
|
||||
|
||||
chip->read_buf(mtd, buf, mtd->writesize);
|
||||
chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
|
||||
|
||||
- if (info->retcode == ERR_SBERR) {
|
||||
- switch (info->use_ecc) {
|
||||
- case 1:
|
||||
- max_bitflips = 1;
|
||||
- mtd->ecc_stats.corrected++;
|
||||
- break;
|
||||
- case 0:
|
||||
- default:
|
||||
- break;
|
||||
- }
|
||||
- } else if (info->retcode == ERR_DBERR) {
|
||||
+ if (info->retcode == ERR_CORERR && info->use_ecc) {
|
||||
+ mtd->ecc_stats.corrected += info->ecc_err_cnt;
|
||||
+
|
||||
+ } else if (info->retcode == ERR_UNCORERR) {
|
||||
/*
|
||||
* for blank page (all 0xff), HW will calculate its ECC as
|
||||
* 0, which is different from the ECC information within
|
||||
- * OOB, ignore such double bit errors
|
||||
+ * OOB, ignore such uncorrectable errors
|
||||
*/
|
||||
if (is_buf_blank(buf, mtd->writesize))
|
||||
info->retcode = ERR_NONE;
|
||||
@@ -1080,7 +1093,7 @@ static int pxa3xx_nand_read_page_hwecc(s
|
||||
mtd->ecc_stats.failed++;
|
||||
}
|
||||
|
||||
- return max_bitflips;
|
||||
+ return info->max_bitflips;
|
||||
}
|
||||
|
||||
static uint8_t pxa3xx_nand_read_byte(struct mtd_info *mtd)
|
|
@ -0,0 +1,67 @@
|
|||
From c312e183e96bed3b727888673d4b6b54b8e6283e Mon Sep 17 00:00:00 2001
|
||||
From: Brian Norris <computersforpeace@gmail.com>
|
||||
Date: Thu, 14 Nov 2013 14:41:32 -0800
|
||||
Subject: [PATCH 154/203] mtd: nand: pxa3xx: make ECC configuration checks more
|
||||
explicit
|
||||
|
||||
The Armada BCH configuration in this driver uses one of the two
|
||||
following ECC schemes:
|
||||
|
||||
16-bit correction per 2048 bytes
|
||||
16-bit correction per 1024 bytes
|
||||
|
||||
These are sufficient for mapping to the 4-bit per 512-bytes and 8-bit
|
||||
per 512-bytes (respectively) minimum correctability requirements of many
|
||||
common NAND.
|
||||
|
||||
The current code only checks for the required strength (4-bit or 8-bit)
|
||||
without checking the ECC step size that is associated with that strength
|
||||
(and simply assumes it is 512). While that is often a safe assumption to
|
||||
make, let's make it explicit, since we have that information.
|
||||
|
||||
Signed-off-by: Brian Norris <computersforpeace@gmail.com>
|
||||
Acked-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
Tested-by: Daniel Mack <zonque@gmail.com>
|
||||
---
|
||||
drivers/mtd/nand/pxa3xx_nand.c | 15 ++++++++++++---
|
||||
1 file changed, 12 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/drivers/mtd/nand/pxa3xx_nand.c
|
||||
+++ b/drivers/mtd/nand/pxa3xx_nand.c
|
||||
@@ -1364,9 +1364,13 @@ static int pxa_ecc_init(struct pxa3xx_na
|
||||
|
||||
static int armada370_ecc_init(struct pxa3xx_nand_info *info,
|
||||
struct nand_ecc_ctrl *ecc,
|
||||
- int strength, int page_size)
|
||||
+ int strength, int ecc_stepsize, int page_size)
|
||||
{
|
||||
- if (strength == 4 && page_size == 4096) {
|
||||
+ /*
|
||||
+ * Required ECC: 4-bit correction per 512 bytes
|
||||
+ * Select: 16-bit correction per 2048 bytes
|
||||
+ */
|
||||
+ if (strength == 4 && ecc_stepsize == 512 && page_size == 4096) {
|
||||
info->ecc_bch = 1;
|
||||
info->chunk_size = 2048;
|
||||
info->spare_size = 32;
|
||||
@@ -1377,7 +1381,11 @@ static int armada370_ecc_init(struct pxa
|
||||
ecc->strength = 16;
|
||||
return 1;
|
||||
|
||||
- } else if (strength == 8 && page_size == 4096) {
|
||||
+ /*
|
||||
+ * Required ECC: 8-bit correction per 512 bytes
|
||||
+ * Select: 16-bit correction per 1024 bytes
|
||||
+ */
|
||||
+ } else if (strength == 8 && ecc_stepsize == 512 && page_size == 4096) {
|
||||
info->ecc_bch = 1;
|
||||
info->chunk_size = 1024;
|
||||
info->spare_size = 0;
|
||||
@@ -1485,6 +1493,7 @@ KEEP_CONFIG:
|
||||
if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370)
|
||||
ret = armada370_ecc_init(info, &chip->ecc,
|
||||
chip->ecc_strength_ds,
|
||||
+ chip->ecc_step_ds,
|
||||
mtd->writesize);
|
||||
else
|
||||
ret = pxa_ecc_init(info, &chip->ecc,
|
|
@ -0,0 +1,29 @@
|
|||
From 4c6bade4cf80d77decc5ea89fbaadff8b008f5e9 Mon Sep 17 00:00:00 2001
|
||||
From: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
Date: Mon, 25 Nov 2013 12:35:28 -0300
|
||||
Subject: [PATCH 155/203] mtd: nand: pxa3xx: Use info->use_dma to release DMA
|
||||
resources
|
||||
|
||||
After the driver allocates all DMA resources, it sets "info->use_dma".
|
||||
Therefore, we need to check that variable to decide which resources
|
||||
needs to be freed, instead of the global use_dma variable.
|
||||
|
||||
Without this change, when the device probe fails, the driver will try
|
||||
to release unallocated DMA resources, with nasty results.
|
||||
|
||||
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
---
|
||||
drivers/mtd/nand/pxa3xx_nand.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/mtd/nand/pxa3xx_nand.c
|
||||
+++ b/drivers/mtd/nand/pxa3xx_nand.c
|
||||
@@ -1288,7 +1288,7 @@ static int pxa3xx_nand_init_buff(struct
|
||||
static void pxa3xx_nand_free_buff(struct pxa3xx_nand_info *info)
|
||||
{
|
||||
struct platform_device *pdev = info->pdev;
|
||||
- if (use_dma) {
|
||||
+ if (info->use_dma) {
|
||||
pxa_free_dma(info->data_dma_ch);
|
||||
dma_free_coherent(&pdev->dev, info->buf_size,
|
||||
info->data_buff, info->data_buff_phys);
|
|
@ -0,0 +1,89 @@
|
|||
From a701d8e1c4c1e31a208dae616ed9067ba4e90191 Mon Sep 17 00:00:00 2001
|
||||
From: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
Date: Mon, 25 Nov 2013 11:02:51 -0300
|
||||
Subject: [PATCH 156/203] mtd: nand: pxa3xx: Use extended cmdfunc() only if
|
||||
needed
|
||||
|
||||
Currently, we have two different cmdfunc's implementations:
|
||||
one for PXA3xx SoC variant and one for Armada 370/XP SoC variant.
|
||||
|
||||
The former is the legacy one, typically constrained to devices
|
||||
with page sizes smaller or equal to the controller's FIFO buffer.
|
||||
On the other side, the latter _only_ supports the so-called extended
|
||||
command semantics, which allow to handle devices with larger
|
||||
page sizes (4 KiB, 8 KiB, ...).
|
||||
|
||||
This means we currently don't support devices with smaller pages on the
|
||||
A370/XP SoC. Fix it by first renaming the cmdfuncs variants, and then
|
||||
make the choice based on device page size (and SoC variant), rather than
|
||||
SoC variant alone.
|
||||
|
||||
While at it, add a check for page size, to make sure we don't allow larger
|
||||
pages sizes on the PXA3xx variant.
|
||||
|
||||
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
---
|
||||
drivers/mtd/nand/pxa3xx_nand.c | 31 +++++++++++++++++++++----------
|
||||
1 file changed, 21 insertions(+), 10 deletions(-)
|
||||
|
||||
--- a/drivers/mtd/nand/pxa3xx_nand.c
|
||||
+++ b/drivers/mtd/nand/pxa3xx_nand.c
|
||||
@@ -900,8 +900,8 @@ static int prepare_set_command(struct px
|
||||
return exec_cmd;
|
||||
}
|
||||
|
||||
-static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command,
|
||||
- int column, int page_addr)
|
||||
+static void nand_cmdfunc(struct mtd_info *mtd, unsigned command,
|
||||
+ int column, int page_addr)
|
||||
{
|
||||
struct pxa3xx_nand_host *host = mtd->priv;
|
||||
struct pxa3xx_nand_info *info = host->info_data;
|
||||
@@ -948,9 +948,9 @@ static void pxa3xx_nand_cmdfunc(struct m
|
||||
info->state = STATE_IDLE;
|
||||
}
|
||||
|
||||
-static void armada370_nand_cmdfunc(struct mtd_info *mtd,
|
||||
- const unsigned command,
|
||||
- int column, int page_addr)
|
||||
+static void nand_cmdfunc_extended(struct mtd_info *mtd,
|
||||
+ const unsigned command,
|
||||
+ int column, int page_addr)
|
||||
{
|
||||
struct pxa3xx_nand_host *host = mtd->priv;
|
||||
struct pxa3xx_nand_info *info = host->info_data;
|
||||
@@ -1490,6 +1490,21 @@ KEEP_CONFIG:
|
||||
chip->bbt_md = &bbt_mirror_descr;
|
||||
}
|
||||
|
||||
+ /*
|
||||
+ * If the page size is bigger than the FIFO size, let's check
|
||||
+ * we are given the right variant and then switch to the extended
|
||||
+ * (aka splitted) command handling,
|
||||
+ */
|
||||
+ if (mtd->writesize > PAGE_CHUNK_SIZE) {
|
||||
+ if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370) {
|
||||
+ chip->cmdfunc = nand_cmdfunc_extended;
|
||||
+ } else {
|
||||
+ dev_err(&info->pdev->dev,
|
||||
+ "unsupported page size on this variant\n");
|
||||
+ return -ENODEV;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370)
|
||||
ret = armada370_ecc_init(info, &chip->ecc,
|
||||
chip->ecc_strength_ds,
|
||||
@@ -1569,11 +1584,7 @@ static int alloc_nand_resource(struct pl
|
||||
chip->read_buf = pxa3xx_nand_read_buf;
|
||||
chip->write_buf = pxa3xx_nand_write_buf;
|
||||
chip->options |= NAND_NO_SUBPAGE_WRITE;
|
||||
-
|
||||
- if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370)
|
||||
- chip->cmdfunc = armada370_nand_cmdfunc;
|
||||
- else
|
||||
- chip->cmdfunc = pxa3xx_nand_cmdfunc;
|
||||
+ chip->cmdfunc = nand_cmdfunc;
|
||||
}
|
||||
|
||||
spin_lock_init(&chip->controller->lock);
|
|
@ -0,0 +1,100 @@
|
|||
From 70c36de37f357f38b5a56292534133d75e7d8870 Mon Sep 17 00:00:00 2001
|
||||
From: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
Date: Mon, 25 Nov 2013 12:36:18 -0300
|
||||
Subject: [PATCH 157/203] mtd: nand: pxa3xx: Consolidate ECC initialization
|
||||
|
||||
In order to avoid code duplication, let's consolidate the ECC setting
|
||||
for all SoC variants. Such decision is based on page size and ECC
|
||||
strength requirements.
|
||||
|
||||
Also, provide a default value for the case where such ECC information
|
||||
is not provided (non-ONFI devices).
|
||||
|
||||
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
---
|
||||
drivers/mtd/nand/pxa3xx_nand.c | 40 ++++++++++++++++------------------------
|
||||
1 file changed, 16 insertions(+), 24 deletions(-)
|
||||
|
||||
--- a/drivers/mtd/nand/pxa3xx_nand.c
|
||||
+++ b/drivers/mtd/nand/pxa3xx_nand.c
|
||||
@@ -1335,13 +1335,9 @@ static int pxa3xx_nand_sensing(struct px
|
||||
|
||||
static int pxa_ecc_init(struct pxa3xx_nand_info *info,
|
||||
struct nand_ecc_ctrl *ecc,
|
||||
- int strength, int page_size)
|
||||
+ int strength, int ecc_stepsize, int page_size)
|
||||
{
|
||||
- /*
|
||||
- * We don't use strength here as the PXA variant
|
||||
- * is used with non-ONFI compliant devices.
|
||||
- */
|
||||
- if (page_size == 2048) {
|
||||
+ if (strength == 1 && ecc_stepsize == 512 && page_size == 2048) {
|
||||
info->chunk_size = 2048;
|
||||
info->spare_size = 40;
|
||||
info->ecc_size = 24;
|
||||
@@ -1350,7 +1346,7 @@ static int pxa_ecc_init(struct pxa3xx_na
|
||||
ecc->strength = 1;
|
||||
return 1;
|
||||
|
||||
- } else if (page_size == 512) {
|
||||
+ } else if (strength == 1 && ecc_stepsize == 512 && page_size == 512) {
|
||||
info->chunk_size = 512;
|
||||
info->spare_size = 8;
|
||||
info->ecc_size = 8;
|
||||
@@ -1358,19 +1354,12 @@ static int pxa_ecc_init(struct pxa3xx_na
|
||||
ecc->size = 512;
|
||||
ecc->strength = 1;
|
||||
return 1;
|
||||
- }
|
||||
- return 0;
|
||||
-}
|
||||
|
||||
-static int armada370_ecc_init(struct pxa3xx_nand_info *info,
|
||||
- struct nand_ecc_ctrl *ecc,
|
||||
- int strength, int ecc_stepsize, int page_size)
|
||||
-{
|
||||
/*
|
||||
* Required ECC: 4-bit correction per 512 bytes
|
||||
* Select: 16-bit correction per 2048 bytes
|
||||
*/
|
||||
- if (strength == 4 && ecc_stepsize == 512 && page_size == 4096) {
|
||||
+ } else if (strength == 4 && ecc_stepsize == 512 && page_size == 4096) {
|
||||
info->ecc_bch = 1;
|
||||
info->chunk_size = 2048;
|
||||
info->spare_size = 32;
|
||||
@@ -1411,6 +1400,7 @@ static int pxa3xx_nand_scan(struct mtd_i
|
||||
uint32_t id = -1;
|
||||
uint64_t chipsize;
|
||||
int i, ret, num;
|
||||
+ uint16_t ecc_strength, ecc_step;
|
||||
|
||||
if (pdata->keep_config && !pxa3xx_nand_detect_config(info))
|
||||
goto KEEP_CONFIG;
|
||||
@@ -1505,15 +1495,17 @@ KEEP_CONFIG:
|
||||
}
|
||||
}
|
||||
|
||||
- if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370)
|
||||
- ret = armada370_ecc_init(info, &chip->ecc,
|
||||
- chip->ecc_strength_ds,
|
||||
- chip->ecc_step_ds,
|
||||
- mtd->writesize);
|
||||
- else
|
||||
- ret = pxa_ecc_init(info, &chip->ecc,
|
||||
- chip->ecc_strength_ds,
|
||||
- mtd->writesize);
|
||||
+ ecc_strength = chip->ecc_strength_ds;
|
||||
+ ecc_step = chip->ecc_step_ds;
|
||||
+
|
||||
+ /* Set default ECC strength requirements on non-ONFI devices */
|
||||
+ if (ecc_strength < 1 && ecc_step < 1) {
|
||||
+ ecc_strength = 1;
|
||||
+ ecc_step = 512;
|
||||
+ }
|
||||
+
|
||||
+ ret = pxa_ecc_init(info, &chip->ecc, ecc_strength,
|
||||
+ ecc_step, mtd->writesize);
|
||||
if (!ret) {
|
||||
dev_err(&info->pdev->dev,
|
||||
"ECC strength %d at page size %d is not supported\n",
|
|
@ -0,0 +1,29 @@
|
|||
From 933f5de151614aee0f7b1f664f86b04f3773a075 Mon Sep 17 00:00:00 2001
|
||||
From: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
Date: Mon, 12 Aug 2013 14:14:59 -0300
|
||||
Subject: [PATCH 158/203] mtd: nand: Allow to build pxa3xx_nand on Orion
|
||||
platforms
|
||||
|
||||
The Armada 370 and Armada XP SoC families, selected by PLAT_ORION,
|
||||
have a Nand Flash Controller (NFC) IP very similar to the one present
|
||||
in PXA platforms. Therefore, we want to build this driver on PLAT_ORION.
|
||||
|
||||
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
Tested-by: Daniel Mack <zonque@gmail.com>
|
||||
Signed-off-by: Brian Norris <computersforpeace@gmail.com>
|
||||
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
|
||||
---
|
||||
drivers/mtd/nand/Kconfig | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/mtd/nand/Kconfig
|
||||
+++ b/drivers/mtd/nand/Kconfig
|
||||
@@ -354,7 +354,7 @@ config MTD_NAND_ATMEL
|
||||
|
||||
config MTD_NAND_PXA3xx
|
||||
tristate "Support for NAND flash devices on PXA3xx"
|
||||
- depends on PXA3xx || ARCH_MMP
|
||||
+ depends on PXA3xx || ARCH_MMP || PLAT_ORION
|
||||
help
|
||||
This enables the driver for the NAND flash device found on
|
||||
PXA3xx processors
|
|
@ -0,0 +1,31 @@
|
|||
From b1abf1e5c6a7531a1a93a0ab6c75607dcb0e9947 Mon Sep 17 00:00:00 2001
|
||||
From: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
Date: Thu, 7 Nov 2013 12:17:11 -0300
|
||||
Subject: [PATCH 159/203] mtd: nand: pxa3xx: Make config menu show supported
|
||||
platforms
|
||||
|
||||
Since we have now support for the NFCv2 controller found on
|
||||
Armada 370/XP platforms.
|
||||
|
||||
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
Signed-off-by: Brian Norris <computersforpeace@gmail.com>
|
||||
---
|
||||
drivers/mtd/nand/Kconfig | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/drivers/mtd/nand/Kconfig
|
||||
+++ b/drivers/mtd/nand/Kconfig
|
||||
@@ -353,11 +353,11 @@ config MTD_NAND_ATMEL
|
||||
on Atmel AT91 and AVR32 processors.
|
||||
|
||||
config MTD_NAND_PXA3xx
|
||||
- tristate "Support for NAND flash devices on PXA3xx"
|
||||
+ tristate "NAND support on PXA3xx and Armada 370/XP"
|
||||
depends on PXA3xx || ARCH_MMP || PLAT_ORION
|
||||
help
|
||||
This enables the driver for the NAND flash device found on
|
||||
- PXA3xx processors
|
||||
+ PXA3xx processors (NFCv1) and also on Armada 370/XP (NFCv2).
|
||||
|
||||
config MTD_NAND_SLC_LPC32XX
|
||||
tristate "NXP LPC32xx SLC Controller"
|
|
@ -0,0 +1,24 @@
|
|||
From a18945a7fd26b83c765b60bcffe306421f7efe80 Mon Sep 17 00:00:00 2001
|
||||
From: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
Date: Mon, 2 Dec 2013 18:44:40 -0300
|
||||
Subject: [PATCH 160/203] ARM: mvebu: config: Add NAND support
|
||||
|
||||
Enable the pxa3xx-nand driver, which now supports the NAND controller
|
||||
in Armada 370/XP SoC.
|
||||
|
||||
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
---
|
||||
arch/arm/configs/mvebu_defconfig | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
--- a/arch/arm/configs/mvebu_defconfig
|
||||
+++ b/arch/arm/configs/mvebu_defconfig
|
||||
@@ -53,6 +53,8 @@ CONFIG_MTD_CFI_INTELEXT=y
|
||||
CONFIG_MTD_CFI_AMDSTD=y
|
||||
CONFIG_MTD_CFI_STAA=y
|
||||
CONFIG_MTD_PHYSMAP_OF=y
|
||||
+CONFIG_MTD_NAND=y
|
||||
+CONFIG_MTD_NAND_PXA3xx=y
|
||||
CONFIG_SERIAL_8250_DW=y
|
||||
CONFIG_GPIOLIB=y
|
||||
CONFIG_GPIO_SYSFS=y
|
|
@ -0,0 +1,69 @@
|
|||
From f834da3962eaee5d72f152e9a066c06ec0d9c2c4 Mon Sep 17 00:00:00 2001
|
||||
From: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
Date: Thu, 5 Dec 2013 13:35:37 -0300
|
||||
Subject: [PATCH 161/203] net: mvneta: Fix incorrect DMA unmapping size
|
||||
|
||||
The current code unmaps the DMA mapping created for rx skb_buff's by
|
||||
using the data_size as the the mapping size. This is wrong since the
|
||||
correct size to specify should match the size used to create the mapping.
|
||||
|
||||
This commit removes the following DMA_API_DEBUG warning:
|
||||
|
||||
------------[ cut here ]------------
|
||||
WARNING: at lib/dma-debug.c:887 check_unmap+0x3a8/0x860()
|
||||
mvneta d0070000.ethernet: DMA-API: device driver frees DMA memory with different size [device address=0x000000002eb80000] [map size=1600 bytes] [unmap size=66 bytes]
|
||||
CPU: 0 PID: 0 Comm: swapper/0 Not tainted 3.10.21-01444-ga88ae13-dirty #92
|
||||
[<c0013600>] (unwind_backtrace+0x0/0xf8) from [<c0010fb8>] (show_stack+0x10/0x14)
|
||||
[<c0010fb8>] (show_stack+0x10/0x14) from [<c001afa0>] (warn_slowpath_common+0x48/0x68)
|
||||
[<c001afa0>] (warn_slowpath_common+0x48/0x68) from [<c001b01c>] (warn_slowpath_fmt+0x30/0x40)
|
||||
[<c001b01c>] (warn_slowpath_fmt+0x30/0x40) from [<c018d0fc>] (check_unmap+0x3a8/0x860)
|
||||
[<c018d0fc>] (check_unmap+0x3a8/0x860) from [<c018d734>] (debug_dma_unmap_page+0x64/0x70)
|
||||
[<c018d734>] (debug_dma_unmap_page+0x64/0x70) from [<c0233f78>] (mvneta_rx+0xec/0x468)
|
||||
[<c0233f78>] (mvneta_rx+0xec/0x468) from [<c023436c>] (mvneta_poll+0x78/0x16c)
|
||||
[<c023436c>] (mvneta_poll+0x78/0x16c) from [<c02db468>] (net_rx_action+0x94/0x160)
|
||||
[<c02db468>] (net_rx_action+0x94/0x160) from [<c0021e68>] (__do_softirq+0xe8/0x1d0)
|
||||
[<c0021e68>] (__do_softirq+0xe8/0x1d0) from [<c0021ff8>] (do_softirq+0x4c/0x58)
|
||||
[<c0021ff8>] (do_softirq+0x4c/0x58) from [<c0022228>] (irq_exit+0x58/0x90)
|
||||
[<c0022228>] (irq_exit+0x58/0x90) from [<c000e7c8>] (handle_IRQ+0x3c/0x94)
|
||||
[<c000e7c8>] (handle_IRQ+0x3c/0x94) from [<c0008548>] (armada_370_xp_handle_irq+0x4c/0xb4)
|
||||
[<c0008548>] (armada_370_xp_handle_irq+0x4c/0xb4) from [<c000dc20>] (__irq_svc+0x40/0x50)
|
||||
Exception stack(0xc04f1f70 to 0xc04f1fb8)
|
||||
1f60: c1fe46f8 00000000 00001d92 00001d92
|
||||
1f80: c04f0000 c04f0000 c04f84a4 c03e081c c05220e7 00000001 c05220e7 c04f0000
|
||||
1fa0: 00000000 c04f1fb8 c000eaf8 c004c048 60000113 ffffffff
|
||||
[<c000dc20>] (__irq_svc+0x40/0x50) from [<c004c048>] (cpu_startup_entry+0x54/0x128)
|
||||
[<c004c048>] (cpu_startup_entry+0x54/0x128) from [<c04c1a14>] (start_kernel+0x29c/0x2f0)
|
||||
[<c04c1a14>] (start_kernel+0x29c/0x2f0) from [<00008074>] (0x8074)
|
||||
---[ end trace d4955f6acd178110 ]---
|
||||
Mapped at:
|
||||
[<c018d600>] debug_dma_map_page+0x4c/0x11c
|
||||
[<c0235d6c>] mvneta_setup_rxqs+0x398/0x598
|
||||
[<c0236084>] mvneta_open+0x40/0x17c
|
||||
[<c02dbbd4>] __dev_open+0x9c/0x100
|
||||
[<c02dbe58>] __dev_change_flags+0x7c/0x134
|
||||
|
||||
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
---
|
||||
drivers/net/ethernet/marvell/mvneta.c | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/drivers/net/ethernet/marvell/mvneta.c
|
||||
+++ b/drivers/net/ethernet/marvell/mvneta.c
|
||||
@@ -1341,7 +1341,7 @@ static void mvneta_rxq_drop_pkts(struct
|
||||
|
||||
dev_kfree_skb_any(skb);
|
||||
dma_unmap_single(pp->dev->dev.parent, rx_desc->buf_phys_addr,
|
||||
- rx_desc->data_size, DMA_FROM_DEVICE);
|
||||
+ MVNETA_RX_BUF_SIZE(pp->pkt_size), DMA_FROM_DEVICE);
|
||||
}
|
||||
|
||||
if (rx_done)
|
||||
@@ -1387,7 +1387,7 @@ static int mvneta_rx(struct mvneta_port
|
||||
}
|
||||
|
||||
dma_unmap_single(pp->dev->dev.parent, rx_desc->buf_phys_addr,
|
||||
- rx_desc->data_size, DMA_FROM_DEVICE);
|
||||
+ MVNETA_RX_BUF_SIZE(pp->pkt_size), DMA_FROM_DEVICE);
|
||||
|
||||
rx_bytes = rx_desc->data_size -
|
||||
(ETH_FCS_LEN + MVNETA_MH_SIZE);
|
|
@ -0,0 +1,50 @@
|
|||
From 7efaa8677ffd07d54d0122b5e92f29b74a36ad39 Mon Sep 17 00:00:00 2001
|
||||
From: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
Date: Thu, 19 Dec 2013 06:08:03 -0300
|
||||
Subject: [PATCH 162/203] mtd: nand: pxa3xx: Clear need_wait flag when starting
|
||||
a command
|
||||
|
||||
Currently the driver assumes all commands will eventually trigger a RnB
|
||||
transition, and thus a "device is ready" IRQ.
|
||||
|
||||
This assumption means that on every issued command, the dev_ready completion
|
||||
handler is init'ed and the need_wait flag is set.
|
||||
|
||||
However this is incorrect: some commands (such as NAND_CMD_STATUS) don't
|
||||
make the device 'busy' and thus a RnB transition never occurs.
|
||||
Given, the NAND core never calls waitfunc() after such commands, this
|
||||
is not a problem.
|
||||
|
||||
Therefore, it's possible to only clear the need_wait flag on every command
|
||||
that is started.
|
||||
|
||||
This fixes a current bug that can be reproduced on PXA boards by writing
|
||||
blank (all 0xff'ed) to a page:
|
||||
|
||||
1. The kernel issues NAND_CMD_STATUS and sets need_wait=1. The flag
|
||||
won't be cleared for this command since no RnB transition is
|
||||
involved.
|
||||
|
||||
2. NAND_CMD_PAGEPROG is issued but since the data is blank, the driver
|
||||
decides not to execute the command (and no IRQ activity is
|
||||
involved).
|
||||
|
||||
3. The NAND core calls waitfunc() and waits for the dev_ready
|
||||
completion, which will never end since the device _is_ already ready.
|
||||
|
||||
Tested-by: Arnaud Ebalard <arno@natisbad.org>
|
||||
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
---
|
||||
drivers/mtd/nand/pxa3xx_nand.c | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
--- a/drivers/mtd/nand/pxa3xx_nand.c
|
||||
+++ b/drivers/mtd/nand/pxa3xx_nand.c
|
||||
@@ -694,6 +694,7 @@ static void prepare_start_command(struct
|
||||
info->retcode = ERR_NONE;
|
||||
info->ecc_err_cnt = 0;
|
||||
info->ndcb3 = 0;
|
||||
+ info->need_wait = 0;
|
||||
|
||||
switch (command) {
|
||||
case NAND_CMD_READ0:
|
|
@ -0,0 +1,39 @@
|
|||
From b340059540cbc90412f3e7159dc57a178e0effd6 Mon Sep 17 00:00:00 2001
|
||||
From: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
|
||||
Date: Wed, 4 Dec 2013 14:28:59 +0100
|
||||
Subject: [PATCH 163/203] ARM: mvebu: move ARMADA_XP_MAX_CPUS to
|
||||
armada-370-xp.h
|
||||
|
||||
The ARMADA_XP_MAX_CPUS definition was in common.h, which as its name
|
||||
says, is common to all mvebu SoCs. It is more logical to have this XP
|
||||
specific definition in the already existing armada-370-xp.h header
|
||||
file.
|
||||
|
||||
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
|
||||
---
|
||||
arch/arm/mach-mvebu/armada-370-xp.h | 2 ++
|
||||
arch/arm/mach-mvebu/common.h | 2 --
|
||||
2 files changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/arch/arm/mach-mvebu/armada-370-xp.h
|
||||
+++ b/arch/arm/mach-mvebu/armada-370-xp.h
|
||||
@@ -18,6 +18,8 @@
|
||||
#ifdef CONFIG_SMP
|
||||
#include <linux/cpumask.h>
|
||||
|
||||
+#define ARMADA_XP_MAX_CPUS 4
|
||||
+
|
||||
void armada_mpic_send_doorbell(const struct cpumask *mask, unsigned int irq);
|
||||
void armada_xp_mpic_smp_cpu_init(void);
|
||||
#endif
|
||||
--- a/arch/arm/mach-mvebu/common.h
|
||||
+++ b/arch/arm/mach-mvebu/common.h
|
||||
@@ -15,8 +15,6 @@
|
||||
#ifndef __ARCH_MVEBU_COMMON_H
|
||||
#define __ARCH_MVEBU_COMMON_H
|
||||
|
||||
-#define ARMADA_XP_MAX_CPUS 4
|
||||
-
|
||||
void mvebu_restart(char mode, const char *cmd);
|
||||
|
||||
void armada_370_xp_init_irq(void);
|
|
@ -0,0 +1,34 @@
|
|||
From 10208caf7f0ebfb3d6b546aa2ae66e42462551e0 Mon Sep 17 00:00:00 2001
|
||||
From: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
|
||||
Date: Wed, 4 Dec 2013 14:37:52 +0100
|
||||
Subject: [PATCH 164/203] ARM: mvebu: fix register length for Armada XP PMSU
|
||||
|
||||
The per-CPU PMSU registers documented in the datasheet start at
|
||||
0x22100 and the last register for CPU3 is at 0x22428. However, the DT
|
||||
informations use <0x22100 0x430>, which makes the region end at
|
||||
0x22530 and not 0x22430.
|
||||
|
||||
Moreover, looking at the datasheet, we can see that the registers for
|
||||
CPU0 start at 0x22100, for CPU1 at 0x22200, for CPU2 at 0x22300 and
|
||||
for CPU3 at 0x22400. It seems clear that 0x100 bytes of registers have
|
||||
been used per CPU.
|
||||
|
||||
Therefore, this commit reduces the length of the PMSU per-CPU register
|
||||
area from the incorrect 0x430 bytes to a more logical 0x400 bytes.
|
||||
|
||||
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
|
||||
---
|
||||
arch/arm/boot/dts/armada-xp.dtsi | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
--- a/arch/arm/boot/dts/armada-xp.dtsi
|
||||
+++ b/arch/arm/boot/dts/armada-xp.dtsi
|
||||
@@ -48,7 +48,7 @@
|
||||
|
||||
armada-370-xp-pmsu@22000 {
|
||||
compatible = "marvell,armada-370-xp-pmsu";
|
||||
- reg = <0x22100 0x430>, <0x20800 0x20>;
|
||||
+ reg = <0x22100 0x400>, <0x20800 0x20>;
|
||||
};
|
||||
|
||||
serial@12200 {
|
|
@ -0,0 +1,36 @@
|
|||
From 167c442fb9adf4c2e02663a0291c6cfae31bad72 Mon Sep 17 00:00:00 2001
|
||||
From: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
|
||||
Date: Thu, 5 Dec 2013 10:02:25 +0100
|
||||
Subject: [PATCH 165/203] ARM: mvebu: make armada_370_xp_pmsu_init() static
|
||||
|
||||
The armada_370_xp_pmsu_init() function is called as an
|
||||
early_initcall(). Therefore, there is no need to export this function,
|
||||
and we can make it static.
|
||||
|
||||
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
|
||||
---
|
||||
arch/arm/mach-mvebu/common.h | 1 -
|
||||
arch/arm/mach-mvebu/pmsu.c | 2 +-
|
||||
2 files changed, 1 insertion(+), 2 deletions(-)
|
||||
|
||||
--- a/arch/arm/mach-mvebu/common.h
|
||||
+++ b/arch/arm/mach-mvebu/common.h
|
||||
@@ -22,7 +22,6 @@ void armada_370_xp_handle_irq(struct pt_
|
||||
|
||||
void armada_xp_cpu_die(unsigned int cpu);
|
||||
int armada_370_xp_coherency_init(void);
|
||||
-int armada_370_xp_pmsu_init(void);
|
||||
void armada_xp_secondary_startup(void);
|
||||
extern struct smp_operations armada_xp_smp_ops;
|
||||
#endif
|
||||
--- a/arch/arm/mach-mvebu/pmsu.c
|
||||
+++ b/arch/arm/mach-mvebu/pmsu.c
|
||||
@@ -58,7 +58,7 @@ int armada_xp_boot_cpu(unsigned int cpu_
|
||||
}
|
||||
#endif
|
||||
|
||||
-int __init armada_370_xp_pmsu_init(void)
|
||||
+static int __init armada_370_xp_pmsu_init(void)
|
||||
{
|
||||
struct device_node *np;
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
From ea331be867c791bca8200e6d707499845d8dfa87 Mon Sep 17 00:00:00 2001
|
||||
From: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
Date: Tue, 13 Aug 2013 11:43:10 -0300
|
||||
Subject: [PATCH 166/203] clocksource: armada-370-xp: Use BIT()
|
||||
|
||||
This is a purely cosmetic commit: we replace hardcoded values that
|
||||
representing bits by BIT(), which is slightly more readable.
|
||||
|
||||
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
|
||||
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
|
||||
---
|
||||
drivers/clocksource/time-armada-370-xp.c | 12 ++++++------
|
||||
1 file changed, 6 insertions(+), 6 deletions(-)
|
||||
|
||||
--- a/drivers/clocksource/time-armada-370-xp.c
|
||||
+++ b/drivers/clocksource/time-armada-370-xp.c
|
||||
@@ -35,13 +35,13 @@
|
||||
* Timer block registers.
|
||||
*/
|
||||
#define TIMER_CTRL_OFF 0x0000
|
||||
-#define TIMER0_EN 0x0001
|
||||
-#define TIMER0_RELOAD_EN 0x0002
|
||||
-#define TIMER0_25MHZ 0x0800
|
||||
+#define TIMER0_EN BIT(0)
|
||||
+#define TIMER0_RELOAD_EN BIT(1)
|
||||
+#define TIMER0_25MHZ BIT(11)
|
||||
#define TIMER0_DIV(div) ((div) << 19)
|
||||
-#define TIMER1_EN 0x0004
|
||||
-#define TIMER1_RELOAD_EN 0x0008
|
||||
-#define TIMER1_25MHZ 0x1000
|
||||
+#define TIMER1_EN BIT(2)
|
||||
+#define TIMER1_RELOAD_EN BIT(3)
|
||||
+#define TIMER1_25MHZ BIT(12)
|
||||
#define TIMER1_DIV(div) ((div) << 22)
|
||||
#define TIMER_EVENTS_STATUS 0x0004
|
||||
#define TIMER0_CLR_MASK (~0x1)
|
|
@ -0,0 +1,174 @@
|
|||
From 7a5e03909417ccecc85819837d10cbb6ffe1d759 Mon Sep 17 00:00:00 2001
|
||||
From: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
Date: Tue, 13 Aug 2013 11:43:11 -0300
|
||||
Subject: [PATCH 167/203] clocksource: armada-370-xp: Simplify TIMER_CTRL
|
||||
register access
|
||||
|
||||
This commit creates two functions to access the TIMER_CTRL register:
|
||||
one for global one for the per-cpu. This makes the code much more
|
||||
readable. In addition, since the TIMER_CTRL register is also used for
|
||||
watchdog, this is preparation work for future thread-safe improvements.
|
||||
|
||||
Acked-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
|
||||
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
|
||||
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
|
||||
---
|
||||
drivers/clocksource/time-armada-370-xp.c | 69 ++++++++++++++------------------
|
||||
1 file changed, 30 insertions(+), 39 deletions(-)
|
||||
|
||||
--- a/drivers/clocksource/time-armada-370-xp.c
|
||||
+++ b/drivers/clocksource/time-armada-370-xp.c
|
||||
@@ -71,6 +71,18 @@ static u32 ticks_per_jiffy;
|
||||
|
||||
static struct clock_event_device __percpu **percpu_armada_370_xp_evt;
|
||||
|
||||
+static void timer_ctrl_clrset(u32 clr, u32 set)
|
||||
+{
|
||||
+ writel((readl(timer_base + TIMER_CTRL_OFF) & ~clr) | set,
|
||||
+ timer_base + TIMER_CTRL_OFF);
|
||||
+}
|
||||
+
|
||||
+static void local_timer_ctrl_clrset(u32 clr, u32 set)
|
||||
+{
|
||||
+ writel((readl(local_base + TIMER_CTRL_OFF) & ~clr) | set,
|
||||
+ local_base + TIMER_CTRL_OFF);
|
||||
+}
|
||||
+
|
||||
static u32 notrace armada_370_xp_read_sched_clock(void)
|
||||
{
|
||||
return ~readl(timer_base + TIMER0_VAL_OFF);
|
||||
@@ -83,7 +95,6 @@ static int
|
||||
armada_370_xp_clkevt_next_event(unsigned long delta,
|
||||
struct clock_event_device *dev)
|
||||
{
|
||||
- u32 u;
|
||||
/*
|
||||
* Clear clockevent timer interrupt.
|
||||
*/
|
||||
@@ -97,11 +108,8 @@ armada_370_xp_clkevt_next_event(unsigned
|
||||
/*
|
||||
* Enable the timer.
|
||||
*/
|
||||
- u = readl(local_base + TIMER_CTRL_OFF);
|
||||
- u = ((u & ~TIMER0_RELOAD_EN) | TIMER0_EN |
|
||||
- TIMER0_DIV(TIMER_DIVIDER_SHIFT));
|
||||
- writel(u, local_base + TIMER_CTRL_OFF);
|
||||
-
|
||||
+ local_timer_ctrl_clrset(TIMER0_RELOAD_EN,
|
||||
+ TIMER0_EN | TIMER0_DIV(TIMER_DIVIDER_SHIFT));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -109,8 +117,6 @@ static void
|
||||
armada_370_xp_clkevt_mode(enum clock_event_mode mode,
|
||||
struct clock_event_device *dev)
|
||||
{
|
||||
- u32 u;
|
||||
-
|
||||
if (mode == CLOCK_EVT_MODE_PERIODIC) {
|
||||
|
||||
/*
|
||||
@@ -122,18 +128,14 @@ armada_370_xp_clkevt_mode(enum clock_eve
|
||||
/*
|
||||
* Enable timer.
|
||||
*/
|
||||
-
|
||||
- u = readl(local_base + TIMER_CTRL_OFF);
|
||||
-
|
||||
- writel((u | TIMER0_EN | TIMER0_RELOAD_EN |
|
||||
- TIMER0_DIV(TIMER_DIVIDER_SHIFT)),
|
||||
- local_base + TIMER_CTRL_OFF);
|
||||
+ local_timer_ctrl_clrset(0, TIMER0_RELOAD_EN |
|
||||
+ TIMER0_EN |
|
||||
+ TIMER0_DIV(TIMER_DIVIDER_SHIFT));
|
||||
} else {
|
||||
/*
|
||||
* Disable timer.
|
||||
*/
|
||||
- u = readl(local_base + TIMER_CTRL_OFF);
|
||||
- writel(u & ~TIMER0_EN, local_base + TIMER_CTRL_OFF);
|
||||
+ local_timer_ctrl_clrset(TIMER0_EN, 0);
|
||||
|
||||
/*
|
||||
* ACK pending timer interrupt.
|
||||
@@ -169,18 +171,18 @@ static irqreturn_t armada_370_xp_timer_i
|
||||
*/
|
||||
static int __cpuinit armada_370_xp_timer_setup(struct clock_event_device *evt)
|
||||
{
|
||||
- u32 u;
|
||||
+ u32 clr = 0, set = 0;
|
||||
int cpu = smp_processor_id();
|
||||
|
||||
/* Use existing clock_event for cpu 0 */
|
||||
if (!smp_processor_id())
|
||||
return 0;
|
||||
|
||||
- u = readl(local_base + TIMER_CTRL_OFF);
|
||||
if (timer25Mhz)
|
||||
- writel(u | TIMER0_25MHZ, local_base + TIMER_CTRL_OFF);
|
||||
+ set = TIMER0_25MHZ;
|
||||
else
|
||||
- writel(u & ~TIMER0_25MHZ, local_base + TIMER_CTRL_OFF);
|
||||
+ clr = TIMER0_25MHZ;
|
||||
+ local_timer_ctrl_clrset(clr, set);
|
||||
|
||||
evt->name = armada_370_xp_clkevt.name;
|
||||
evt->irq = armada_370_xp_clkevt.irq;
|
||||
@@ -212,7 +214,7 @@ static struct local_timer_ops armada_370
|
||||
|
||||
static void __init armada_370_xp_timer_init(struct device_node *np)
|
||||
{
|
||||
- u32 u;
|
||||
+ u32 clr = 0, set = 0;
|
||||
int res;
|
||||
|
||||
timer_base = of_iomap(np, 0);
|
||||
@@ -221,29 +223,20 @@ static void __init armada_370_xp_timer_i
|
||||
|
||||
if (of_find_property(np, "marvell,timer-25Mhz", NULL)) {
|
||||
/* The fixed 25MHz timer is available so let's use it */
|
||||
- u = readl(local_base + TIMER_CTRL_OFF);
|
||||
- writel(u | TIMER0_25MHZ,
|
||||
- local_base + TIMER_CTRL_OFF);
|
||||
- u = readl(timer_base + TIMER_CTRL_OFF);
|
||||
- writel(u | TIMER0_25MHZ,
|
||||
- timer_base + TIMER_CTRL_OFF);
|
||||
+ set = TIMER0_25MHZ;
|
||||
timer_clk = 25000000;
|
||||
} else {
|
||||
unsigned long rate = 0;
|
||||
struct clk *clk = of_clk_get(np, 0);
|
||||
WARN_ON(IS_ERR(clk));
|
||||
rate = clk_get_rate(clk);
|
||||
- u = readl(local_base + TIMER_CTRL_OFF);
|
||||
- writel(u & ~(TIMER0_25MHZ),
|
||||
- local_base + TIMER_CTRL_OFF);
|
||||
-
|
||||
- u = readl(timer_base + TIMER_CTRL_OFF);
|
||||
- writel(u & ~(TIMER0_25MHZ),
|
||||
- timer_base + TIMER_CTRL_OFF);
|
||||
-
|
||||
timer_clk = rate / TIMER_DIVIDER;
|
||||
+
|
||||
+ clr = TIMER0_25MHZ;
|
||||
timer25Mhz = false;
|
||||
}
|
||||
+ timer_ctrl_clrset(clr, set);
|
||||
+ local_timer_ctrl_clrset(clr, set);
|
||||
|
||||
/*
|
||||
* We use timer 0 as clocksource, and private(local) timer 0
|
||||
@@ -265,10 +258,8 @@ static void __init armada_370_xp_timer_i
|
||||
writel(0xffffffff, timer_base + TIMER0_VAL_OFF);
|
||||
writel(0xffffffff, timer_base + TIMER0_RELOAD_OFF);
|
||||
|
||||
- u = readl(timer_base + TIMER_CTRL_OFF);
|
||||
-
|
||||
- writel((u | TIMER0_EN | TIMER0_RELOAD_EN |
|
||||
- TIMER0_DIV(TIMER_DIVIDER_SHIFT)), timer_base + TIMER_CTRL_OFF);
|
||||
+ timer_ctrl_clrset(0, TIMER0_EN | TIMER0_RELOAD_EN |
|
||||
+ TIMER0_DIV(TIMER_DIVIDER_SHIFT));
|
||||
|
||||
clocksource_mmio_init(timer_base + TIMER0_VAL_OFF,
|
||||
"armada_370_xp_clocksource",
|
|
@ -0,0 +1,101 @@
|
|||
From 9cb47bf175645d15f97e6d964dd4a4f089275ef5 Mon Sep 17 00:00:00 2001
|
||||
From: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
Date: Tue, 13 Aug 2013 11:43:13 -0300
|
||||
Subject: [PATCH 168/203] clocksource: armada-370-xp: Introduce new compatibles
|
||||
|
||||
The Armada XP SoC clocksource driver cannot work without the 25 MHz
|
||||
fixed timer. Therefore it's appropriate to introduce a new compatible
|
||||
string and use it to set the 25 MHz fixed timer.
|
||||
|
||||
The 'marvell,timer-25MHz' property will be marked as deprecated.
|
||||
|
||||
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
|
||||
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
|
||||
---
|
||||
drivers/clocksource/time-armada-370-xp.c | 54 +++++++++++++++++++++++---------
|
||||
1 file changed, 39 insertions(+), 15 deletions(-)
|
||||
|
||||
--- a/drivers/clocksource/time-armada-370-xp.c
|
||||
+++ b/drivers/clocksource/time-armada-370-xp.c
|
||||
@@ -13,6 +13,19 @@
|
||||
*
|
||||
* Timer 0 is used as free-running clocksource, while timer 1 is
|
||||
* used as clock_event_device.
|
||||
+ *
|
||||
+ * ---
|
||||
+ * Clocksource driver for Armada 370 and Armada XP SoC.
|
||||
+ * This driver implements one compatible string for each SoC, given
|
||||
+ * each has its own characteristics:
|
||||
+ *
|
||||
+ * * Armada 370 has no 25 MHz fixed timer.
|
||||
+ *
|
||||
+ * * Armada XP cannot work properly without such 25 MHz fixed timer as
|
||||
+ * doing otherwise leads to using a clocksource whose frequency varies
|
||||
+ * when doing cpufreq frequency changes.
|
||||
+ *
|
||||
+ * See Documentation/devicetree/bindings/timer/marvell,armada-370-xp-timer.txt
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
@@ -212,7 +225,7 @@ static struct local_timer_ops armada_370
|
||||
.stop = armada_370_xp_timer_stop,
|
||||
};
|
||||
|
||||
-static void __init armada_370_xp_timer_init(struct device_node *np)
|
||||
+static void __init armada_370_xp_timer_common_init(struct device_node *np)
|
||||
{
|
||||
u32 clr = 0, set = 0;
|
||||
int res;
|
||||
@@ -221,20 +234,10 @@ static void __init armada_370_xp_timer_i
|
||||
WARN_ON(!timer_base);
|
||||
local_base = of_iomap(np, 1);
|
||||
|
||||
- if (of_find_property(np, "marvell,timer-25Mhz", NULL)) {
|
||||
- /* The fixed 25MHz timer is available so let's use it */
|
||||
+ if (timer25Mhz)
|
||||
set = TIMER0_25MHZ;
|
||||
- timer_clk = 25000000;
|
||||
- } else {
|
||||
- unsigned long rate = 0;
|
||||
- struct clk *clk = of_clk_get(np, 0);
|
||||
- WARN_ON(IS_ERR(clk));
|
||||
- rate = clk_get_rate(clk);
|
||||
- timer_clk = rate / TIMER_DIVIDER;
|
||||
-
|
||||
+ else
|
||||
clr = TIMER0_25MHZ;
|
||||
- timer25Mhz = false;
|
||||
- }
|
||||
timer_ctrl_clrset(clr, set);
|
||||
local_timer_ctrl_clrset(clr, set);
|
||||
|
||||
@@ -288,5 +291,26 @@ static void __init armada_370_xp_timer_i
|
||||
#endif
|
||||
}
|
||||
}
|
||||
-CLOCKSOURCE_OF_DECLARE(armada_370_xp, "marvell,armada-370-xp-timer",
|
||||
- armada_370_xp_timer_init);
|
||||
+
|
||||
+static void __init armada_xp_timer_init(struct device_node *np)
|
||||
+{
|
||||
+ /* The fixed 25MHz timer is required, timer25Mhz is true by default */
|
||||
+ timer_clk = 25000000;
|
||||
+
|
||||
+ armada_370_xp_timer_common_init(np);
|
||||
+}
|
||||
+CLOCKSOURCE_OF_DECLARE(armada_xp, "marvell,armada-xp-timer",
|
||||
+ armada_xp_timer_init);
|
||||
+
|
||||
+static void __init armada_370_timer_init(struct device_node *np)
|
||||
+{
|
||||
+ struct clk *clk = of_clk_get(np, 0);
|
||||
+
|
||||
+ WARN_ON(IS_ERR(clk));
|
||||
+ timer_clk = clk_get_rate(clk) / TIMER_DIVIDER;
|
||||
+ timer25Mhz = false;
|
||||
+
|
||||
+ armada_370_xp_timer_common_init(np);
|
||||
+}
|
||||
+CLOCKSOURCE_OF_DECLARE(armada_370, "marvell,armada-370-timer",
|
||||
+ armada_370_timer_init);
|
|
@ -0,0 +1,29 @@
|
|||
From bcaac3d9265d751f7d20df6ed0ac24241308dff7 Mon Sep 17 00:00:00 2001
|
||||
From: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
Date: Tue, 20 Aug 2013 12:45:52 -0300
|
||||
Subject: [PATCH 169/203] clocksource: armada-370-xp: Replace WARN_ON with
|
||||
BUG_ON
|
||||
|
||||
If the clock fails to be obtained and the timer fails to be properly
|
||||
registered, the kernel will freeze real soon. Instead, let's BUG()
|
||||
where the actual problem is located.
|
||||
|
||||
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
|
||||
Acked-by: Jason Cooper <jason@lakedaemon.net>
|
||||
Acked-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
|
||||
---
|
||||
drivers/clocksource/time-armada-370-xp.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/clocksource/time-armada-370-xp.c
|
||||
+++ b/drivers/clocksource/time-armada-370-xp.c
|
||||
@@ -306,7 +306,7 @@ static void __init armada_370_timer_init
|
||||
{
|
||||
struct clk *clk = of_clk_get(np, 0);
|
||||
|
||||
- WARN_ON(IS_ERR(clk));
|
||||
+ BUG_ON(IS_ERR(clk));
|
||||
timer_clk = clk_get_rate(clk) / TIMER_DIVIDER;
|
||||
timer25Mhz = false;
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
From 7d7214129f7bde5bb55c0691968407b48f08efb5 Mon Sep 17 00:00:00 2001
|
||||
From: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
Date: Tue, 20 Aug 2013 12:45:53 -0300
|
||||
Subject: [PATCH 170/203] clocksource: armada-370-xp: Get reference fixed-clock
|
||||
by name
|
||||
|
||||
The Armada XP timer has two mandatory clock inputs: nbclk and refclk,
|
||||
as specified by the device-tree binding.
|
||||
|
||||
This commit fixes the clock selection. Instead of hard-coding the clock
|
||||
rate for the 25 MHz reference fixed-clock, obtain the clock by its name.
|
||||
|
||||
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
|
||||
Acked-by: Jason Cooper <jason@lakedaemon.net>
|
||||
Acked-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
|
||||
---
|
||||
drivers/clocksource/time-armada-370-xp.c | 7 +++++--
|
||||
1 file changed, 5 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/drivers/clocksource/time-armada-370-xp.c
|
||||
+++ b/drivers/clocksource/time-armada-370-xp.c
|
||||
@@ -294,8 +294,11 @@ static void __init armada_370_xp_timer_c
|
||||
|
||||
static void __init armada_xp_timer_init(struct device_node *np)
|
||||
{
|
||||
- /* The fixed 25MHz timer is required, timer25Mhz is true by default */
|
||||
- timer_clk = 25000000;
|
||||
+ struct clk *clk = of_clk_get_by_name(np, "fixed");
|
||||
+
|
||||
+ /* The 25Mhz fixed clock is mandatory, and must always be available */
|
||||
+ BUG_ON(IS_ERR(clk));
|
||||
+ timer_clk = clk_get_rate(clk);
|
||||
|
||||
armada_370_xp_timer_common_init(np);
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
From 3d7976bb4a0f34203456cc0e9054b4a6401c9fdb Mon Sep 17 00:00:00 2001
|
||||
From: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
Date: Tue, 26 Nov 2013 18:20:14 -0300
|
||||
Subject: [PATCH 171/203] clocksource: armada-370-xp: Register sched_clock
|
||||
after the counter reset
|
||||
|
||||
This commit registers the sched_clock _after_ the counter reset
|
||||
(instead of before). This removes the timestamp 'jump' in kernel
|
||||
log messages.
|
||||
|
||||
Before this change:
|
||||
|
||||
[ 0.000000] sched_clock: 32 bits at 25MHz, resolution 40ns, wraps every 171798691800ns
|
||||
[ 0.000000] Initializing Coherency fabric
|
||||
[ 0.000000] Aurora cache controller enabled
|
||||
[ 0.000000] l2x0: 16 ways, CACHE_ID 0x00000100, AUX_CTRL 0x1a696b12, Cache size: 1024 kB
|
||||
[ 163.507447] Calibrating delay loop... 1325.05 BogoMIPS (lpj=662528)
|
||||
[ 163.521419] pid_max: default: 32768 minimum: 301
|
||||
[ 163.526185] Mount-cache hash table entries: 512
|
||||
[ 163.531095] CPU: Testing write buffer coherency: ok
|
||||
|
||||
After this change:
|
||||
|
||||
[ 0.000000] sched_clock: 32 bits at 25MHz, resolution 40ns, wraps every 171798691800ns
|
||||
[ 0.000000] Initializing Coherency fabric
|
||||
[ 0.000000] Aurora cache controller enabled
|
||||
[ 0.000000] l2x0: 16 ways, CACHE_ID 0x00000100, AUX_CTRL 0x1a696b12, Cache size: 1024 kB
|
||||
[ 0.016849] Calibrating delay loop... 1325.05 BogoMIPS (lpj=662528)
|
||||
[ 0.030820] pid_max: default: 32768 minimum: 301
|
||||
[ 0.035588] Mount-cache hash table entries: 512
|
||||
[ 0.040500] CPU: Testing write buffer coherency: ok
|
||||
|
||||
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
|
||||
Acked-by: Jason Cooper <jason@lakedaemon.net>
|
||||
---
|
||||
drivers/clocksource/time-armada-370-xp.c | 10 +++++-----
|
||||
1 file changed, 5 insertions(+), 5 deletions(-)
|
||||
|
||||
--- a/drivers/clocksource/time-armada-370-xp.c
|
||||
+++ b/drivers/clocksource/time-armada-370-xp.c
|
||||
@@ -250,11 +250,6 @@ static void __init armada_370_xp_timer_c
|
||||
ticks_per_jiffy = (timer_clk + HZ / 2) / HZ;
|
||||
|
||||
/*
|
||||
- * Set scale and timer for sched_clock.
|
||||
- */
|
||||
- setup_sched_clock(armada_370_xp_read_sched_clock, 32, timer_clk);
|
||||
-
|
||||
- /*
|
||||
* Setup free-running clocksource timer (interrupts
|
||||
* disabled).
|
||||
*/
|
||||
@@ -264,6 +259,11 @@ static void __init armada_370_xp_timer_c
|
||||
timer_ctrl_clrset(0, TIMER0_EN | TIMER0_RELOAD_EN |
|
||||
TIMER0_DIV(TIMER_DIVIDER_SHIFT));
|
||||
|
||||
+ /*
|
||||
+ * Set scale and timer for sched_clock.
|
||||
+ */
|
||||
+ setup_sched_clock(armada_370_xp_read_sched_clock, 32, timer_clk);
|
||||
+
|
||||
clocksource_mmio_init(timer_base + TIMER0_VAL_OFF,
|
||||
"armada_370_xp_clocksource",
|
||||
timer_clk, 300, 32, clocksource_mmio_readl_down);
|
|
@ -0,0 +1,62 @@
|
|||
From e33103d8d4cfc513467eb30bc4faee5c91c8e6c2 Mon Sep 17 00:00:00 2001
|
||||
From: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
Date: Tue, 13 Aug 2013 11:43:15 -0300
|
||||
Subject: [PATCH 172/203] ARM: mvebu: Fix the Armada 370/XP timer compatible
|
||||
strings
|
||||
|
||||
The "marvell,armada-370-xp-timer" compatible string, together with
|
||||
the "marvell,timer-25Mhz" property are deprecated and should be
|
||||
removed from current DT.
|
||||
|
||||
Instead, the timer DT nodes are now required to have an appropriate
|
||||
compatible string, which should be either "marvell,armada-370-timer"
|
||||
or "marvell,armada-xp-timer", depending on SoC.
|
||||
|
||||
The clock property is now required only for Armada 370 so move it accordingly.
|
||||
|
||||
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
Signed-off-by: Jason Cooper <jason@lakedaemon.net>
|
||||
---
|
||||
arch/arm/boot/dts/armada-370-xp.dtsi | 2 --
|
||||
arch/arm/boot/dts/armada-370.dtsi | 5 +++++
|
||||
arch/arm/boot/dts/armada-xp.dtsi | 2 +-
|
||||
3 files changed, 6 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/arch/arm/boot/dts/armada-370-xp.dtsi
|
||||
+++ b/arch/arm/boot/dts/armada-370-xp.dtsi
|
||||
@@ -143,10 +143,8 @@
|
||||
};
|
||||
|
||||
timer@20300 {
|
||||
- compatible = "marvell,armada-370-xp-timer";
|
||||
reg = <0x20300 0x30>, <0x21040 0x30>;
|
||||
interrupts = <37>, <38>, <39>, <40>, <5>, <6>;
|
||||
- clocks = <&coreclk 2>;
|
||||
};
|
||||
|
||||
sata@a0000 {
|
||||
--- a/arch/arm/boot/dts/armada-370.dtsi
|
||||
+++ b/arch/arm/boot/dts/armada-370.dtsi
|
||||
@@ -163,6 +163,11 @@
|
||||
interrupts = <91>;
|
||||
};
|
||||
|
||||
+ timer@20300 {
|
||||
+ compatible = "marvell,armada-370-timer";
|
||||
+ clocks = <&coreclk 2>;
|
||||
+ };
|
||||
+
|
||||
coreclk: mvebu-sar@18230 {
|
||||
compatible = "marvell,armada-370-core-clock";
|
||||
reg = <0x18230 0x08>;
|
||||
--- a/arch/arm/boot/dts/armada-xp.dtsi
|
||||
+++ b/arch/arm/boot/dts/armada-xp.dtsi
|
||||
@@ -69,7 +69,7 @@
|
||||
};
|
||||
|
||||
timer@20300 {
|
||||
- marvell,timer-25Mhz;
|
||||
+ compatible = "marvell,armada-xp-timer";
|
||||
};
|
||||
|
||||
coreclk: mvebu-sar@18230 {
|
|
@ -0,0 +1,34 @@
|
|||
From e4011be91332bacc5cf166e1ce92c3678fc7c646 Mon Sep 17 00:00:00 2001
|
||||
From: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
Date: Tue, 20 Aug 2013 12:45:50 -0300
|
||||
Subject: [PATCH 173/203] ARM: mvebu: Add the reference 25 MHz fixed-clock to
|
||||
Armada XP
|
||||
|
||||
The Armada XP SoC has a reference 25 MHz fixed-clock that is used in
|
||||
some controllers such as the timer and the watchdog. This commit adds
|
||||
a DT representation of this clock through a fixed-clock compatible node.
|
||||
|
||||
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
Reviewed-by: Mike Turquette <mturquette@linaro.org>
|
||||
Acked-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
|
||||
Signed-off-by: Jason Cooper <jason@lakedaemon.net>
|
||||
---
|
||||
arch/arm/boot/dts/armada-xp.dtsi | 9 +++++++++
|
||||
1 file changed, 9 insertions(+)
|
||||
|
||||
--- a/arch/arm/boot/dts/armada-xp.dtsi
|
||||
+++ b/arch/arm/boot/dts/armada-xp.dtsi
|
||||
@@ -169,4 +169,13 @@
|
||||
};
|
||||
};
|
||||
};
|
||||
+
|
||||
+ clocks {
|
||||
+ /* 25 MHz reference crystal */
|
||||
+ refclk: oscillator {
|
||||
+ compatible = "fixed-clock";
|
||||
+ #clock-cells = <0>;
|
||||
+ clock-frequency = <25000000>;
|
||||
+ };
|
||||
+ };
|
||||
};
|
|
@ -0,0 +1,30 @@
|
|||
From 200b303fc6c2709340996b02ae0c9a7130de7ec3 Mon Sep 17 00:00:00 2001
|
||||
From: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
Date: Tue, 20 Aug 2013 12:45:51 -0300
|
||||
Subject: [PATCH 174/203] ARM: mvebu: Add clock properties to Armada XP timer
|
||||
node
|
||||
|
||||
With the addition of the Armada XP reference clock, we can now model
|
||||
accurately the available clock inputs for the timer: namely, nbclk
|
||||
and refclk. For each of this clock inputs we assign a name, for the
|
||||
driver to select as appropriate.
|
||||
|
||||
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
Reviewed-by: Mike Turquette <mturquette@linaro.org>
|
||||
Acked-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
|
||||
Signed-off-by: Jason Cooper <jason@lakedaemon.net>
|
||||
---
|
||||
arch/arm/boot/dts/armada-xp.dtsi | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
--- a/arch/arm/boot/dts/armada-xp.dtsi
|
||||
+++ b/arch/arm/boot/dts/armada-xp.dtsi
|
||||
@@ -70,6 +70,8 @@
|
||||
|
||||
timer@20300 {
|
||||
compatible = "marvell,armada-xp-timer";
|
||||
+ clocks = <&coreclk 2>, <&refclk>;
|
||||
+ clock-names = "nbclk", "fixed";
|
||||
};
|
||||
|
||||
coreclk: mvebu-sar@18230 {
|
|
@ -0,0 +1,62 @@
|
|||
From 079d1ecae4bd4166a0f89bcb8e0c96bec1b39622 Mon Sep 17 00:00:00 2001
|
||||
From: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
Date: Thu, 8 Aug 2013 18:03:09 -0300
|
||||
Subject: [PATCH 175/203] ARM: mvebu: Relocate PCIe node in Armada 370 RD board
|
||||
|
||||
The pcie-controller node needs to be relocated according the MBus
|
||||
DT binding, since it's now a child of the mbus-compatible node.
|
||||
|
||||
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
Signed-off-by: Jason Cooper <jason@lakedaemon.net>
|
||||
---
|
||||
arch/arm/boot/dts/armada-370-rd.dts | 32 ++++++++++++++++----------------
|
||||
1 file changed, 16 insertions(+), 16 deletions(-)
|
||||
|
||||
--- a/arch/arm/boot/dts/armada-370-rd.dts
|
||||
+++ b/arch/arm/boot/dts/armada-370-rd.dts
|
||||
@@ -31,6 +31,22 @@
|
||||
ranges = <MBUS_ID(0xf0, 0x01) 0 0xd0000000 0x100000
|
||||
MBUS_ID(0x01, 0xe0) 0 0xfff00000 0x100000>;
|
||||
|
||||
+ pcie-controller {
|
||||
+ status = "okay";
|
||||
+
|
||||
+ /* Internal mini-PCIe connector */
|
||||
+ pcie@1,0 {
|
||||
+ /* Port 0, Lane 0 */
|
||||
+ status = "okay";
|
||||
+ };
|
||||
+
|
||||
+ /* Internal mini-PCIe connector */
|
||||
+ pcie@2,0 {
|
||||
+ /* Port 1, Lane 0 */
|
||||
+ status = "okay";
|
||||
+ };
|
||||
+ };
|
||||
+
|
||||
internal-regs {
|
||||
serial@12000 {
|
||||
clock-frequency = <200000000>;
|
||||
@@ -88,22 +104,6 @@
|
||||
gpios = <&gpio0 6 1>;
|
||||
};
|
||||
};
|
||||
-
|
||||
- pcie-controller {
|
||||
- status = "okay";
|
||||
-
|
||||
- /* Internal mini-PCIe connector */
|
||||
- pcie@1,0 {
|
||||
- /* Port 0, Lane 0 */
|
||||
- status = "okay";
|
||||
- };
|
||||
-
|
||||
- /* Internal mini-PCIe connector */
|
||||
- pcie@2,0 {
|
||||
- /* Port 1, Lane 0 */
|
||||
- status = "okay";
|
||||
- };
|
||||
- };
|
||||
};
|
||||
};
|
||||
};
|
|
@ -0,0 +1,104 @@
|
|||
From 6dc29d94d92ccc558b946bd57cd8d7cb19d8def1 Mon Sep 17 00:00:00 2001
|
||||
From: Grant Likely <grant.likely@linaro.org>
|
||||
Date: Thu, 19 Dec 2013 09:30:47 -0300
|
||||
Subject: [PATCH 176/203] of/irq: create interrupts-extended property
|
||||
|
||||
The standard interrupts property in device tree can only handle
|
||||
interrupts coming from a single interrupt parent. If a device is wired
|
||||
to multiple interrupt controllers, then it needs to be attached to a
|
||||
node with an interrupt-map property to demux the interrupt specifiers
|
||||
which is confusing. It would be a lot easier if there was a form of the
|
||||
interrupts property that allows for a separate interrupt phandle for
|
||||
each interrupt specifier.
|
||||
|
||||
This patch does exactly that by creating a new interrupts-extended
|
||||
property which reuses the phandle+arguments pattern used by GPIOs and
|
||||
other core bindings.
|
||||
|
||||
Signed-off-by: Grant Likely <grant.likely@linaro.org>
|
||||
Acked-by: Tony Lindgren <tony@atomide.com>
|
||||
Acked-by: Kumar Gala <galak@codeaurora.org>
|
||||
[grant.likely: removed versatile platform hunks into separate patch]
|
||||
Cc: Rob Herring <rob.herring@calxeda.com>
|
||||
|
||||
Conflicts:
|
||||
arch/arm/boot/dts/testcases/tests-interrupts.dtsi
|
||||
drivers/of/selftest.c
|
||||
---
|
||||
.../bindings/interrupt-controller/interrupts.txt | 29 +++++++++++++++++-----
|
||||
drivers/of/irq.c | 16 ++++++++----
|
||||
2 files changed, 34 insertions(+), 11 deletions(-)
|
||||
|
||||
--- a/Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
|
||||
+++ b/Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
|
||||
@@ -4,16 +4,33 @@ Specifying interrupt information for dev
|
||||
1) Interrupt client nodes
|
||||
-------------------------
|
||||
|
||||
-Nodes that describe devices which generate interrupts must contain an
|
||||
-"interrupts" property. This property must contain a list of interrupt
|
||||
-specifiers, one per output interrupt. The format of the interrupt specifier is
|
||||
-determined by the interrupt controller to which the interrupts are routed; see
|
||||
-section 2 below for details.
|
||||
+Nodes that describe devices which generate interrupts must contain an either an
|
||||
+"interrupts" property or an "interrupts-extended" property. These properties
|
||||
+contain a list of interrupt specifiers, one per output interrupt. The format of
|
||||
+the interrupt specifier is determined by the interrupt controller to which the
|
||||
+interrupts are routed; see section 2 below for details.
|
||||
+
|
||||
+ Example:
|
||||
+ interrupt-parent = <&intc1>;
|
||||
+ interrupts = <5 0>, <6 0>;
|
||||
|
||||
The "interrupt-parent" property is used to specify the controller to which
|
||||
interrupts are routed and contains a single phandle referring to the interrupt
|
||||
controller node. This property is inherited, so it may be specified in an
|
||||
-interrupt client node or in any of its parent nodes.
|
||||
+interrupt client node or in any of its parent nodes. Interrupts listed in the
|
||||
+"interrupts" property are always in reference to the node's interrupt parent.
|
||||
+
|
||||
+The "interrupts-extended" property is a special form for use when a node needs
|
||||
+to reference multiple interrupt parents. Each entry in this property contains
|
||||
+both the parent phandle and the interrupt specifier. "interrupts-extended"
|
||||
+should only be used when a device has multiple interrupt parents.
|
||||
+
|
||||
+ Example:
|
||||
+ interrupts-extended = <&intc1 5 1>, <&intc2 1 0>;
|
||||
+
|
||||
+A device node may contain either "interrupts" or "interrupts-extended", but not
|
||||
+both. If both properties are present, then the operating system should log an
|
||||
+error and use only the data in "interrupts".
|
||||
|
||||
2) Interrupt controller nodes
|
||||
-----------------------------
|
||||
--- a/drivers/of/irq.c
|
||||
+++ b/drivers/of/irq.c
|
||||
@@ -293,17 +293,23 @@ int of_irq_map_one(struct device_node *d
|
||||
if (of_irq_workarounds & OF_IMAP_OLDWORLD_MAC)
|
||||
return of_irq_map_oldworld(device, index, out_irq);
|
||||
|
||||
+ /* Get the reg property (if any) */
|
||||
+ addr = of_get_property(device, "reg", NULL);
|
||||
+
|
||||
/* Get the interrupts property */
|
||||
intspec = of_get_property(device, "interrupts", &intlen);
|
||||
- if (intspec == NULL)
|
||||
- return -EINVAL;
|
||||
+ if (intspec == NULL) {
|
||||
+ /* Try the new-style interrupts-extended */
|
||||
+ res = of_parse_phandle_with_args(device, "interrupts-extended",
|
||||
+ "#interrupt-cells", index, out_irq);
|
||||
+ if (res)
|
||||
+ return -EINVAL;
|
||||
+ return of_irq_parse_raw(addr, out_irq);
|
||||
+ }
|
||||
intlen /= sizeof(*intspec);
|
||||
|
||||
pr_debug(" intspec=%d intlen=%d\n", be32_to_cpup(intspec), intlen);
|
||||
|
||||
- /* Get the reg property (if any) */
|
||||
- addr = of_get_property(device, "reg", NULL);
|
||||
-
|
||||
/* Look for the interrupt parent. */
|
||||
p = of_irq_find_parent(device);
|
||||
if (p == NULL)
|
|
@ -0,0 +1,30 @@
|
|||
From f159ea8ab3bce09a098d0d56c9e8909f385b87aa Mon Sep 17 00:00:00 2001
|
||||
From: Axel Lin <axel.lin@ingics.com>
|
||||
Date: Thu, 19 Dec 2013 09:30:48 -0300
|
||||
Subject: [PATCH 177/203] of/irq: Avoid calling list_first_entry() for empty
|
||||
list
|
||||
|
||||
list_first_entry() expects the list is not empty, we need to check if list is
|
||||
empty before calling list_first_entry(). Thus use list_first_entry_or_null()
|
||||
instead of list_first_entry().
|
||||
|
||||
Signed-off-by: Axel Lin <axel.lin@ingics.com>
|
||||
Signed-off-by: Grant Likely <grant.likely@linaro.org>
|
||||
---
|
||||
drivers/of/irq.c | 5 +++--
|
||||
1 file changed, 3 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/drivers/of/irq.c
|
||||
+++ b/drivers/of/irq.c
|
||||
@@ -488,8 +488,9 @@ void __init of_irq_init(const struct of_
|
||||
}
|
||||
|
||||
/* Get the next pending parent that might have children */
|
||||
- desc = list_first_entry(&intc_parent_list, typeof(*desc), list);
|
||||
- if (list_empty(&intc_parent_list) || !desc) {
|
||||
+ desc = list_first_entry_or_null(&intc_parent_list,
|
||||
+ typeof(*desc), list);
|
||||
+ if (!desc) {
|
||||
pr_err("of_irq_init: children remain, but no parents\n");
|
||||
break;
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
From 704f3796c741df558d624078c5094439c0b65d09 Mon Sep 17 00:00:00 2001
|
||||
From: Rob Herring <rob.herring@calxeda.com>
|
||||
Date: Thu, 19 Dec 2013 09:30:49 -0300
|
||||
Subject: [PATCH 178/203] of: clean-up ifdefs in of_irq.h
|
||||
|
||||
Much of of_irq.h is needlessly ifdef'ed. Clean this up and minimize the
|
||||
amount ifdef'ed code. This fixes some build warnings when CONFIG_OF
|
||||
is not enabled (seen on i386 and x86_64):
|
||||
|
||||
include/linux/of_irq.h:82:7: warning: 'struct device_node' declared inside parameter list [enabled by default]
|
||||
include/linux/of_irq.h:82:7: warning: its scope is only this definition or declaration, which is probably not what you want [enabled by default]
|
||||
include/linux/of_irq.h:87:47: warning: 'struct device_node' declared inside parameter list [enabled by default]
|
||||
|
||||
Compile tested on i386, sparc and arm.
|
||||
|
||||
Reported-by: Randy Dunlap <rdunlap@infradead.org>
|
||||
Cc: Grant Likely <grant.likely@linaro.org>
|
||||
Signed-off-by: Rob Herring <rob.herring@calxeda.com>
|
||||
---
|
||||
include/linux/of_irq.h | 20 ++++++++------------
|
||||
1 file changed, 8 insertions(+), 12 deletions(-)
|
||||
|
||||
--- a/include/linux/of_irq.h
|
||||
+++ b/include/linux/of_irq.h
|
||||
@@ -1,8 +1,6 @@
|
||||
#ifndef __OF_IRQ_H
|
||||
#define __OF_IRQ_H
|
||||
|
||||
-#if defined(CONFIG_OF)
|
||||
-struct of_irq;
|
||||
#include <linux/types.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/irq.h>
|
||||
@@ -10,14 +8,6 @@ struct of_irq;
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
-/*
|
||||
- * irq_of_parse_and_map() is used by all OF enabled platforms; but SPARC
|
||||
- * implements it differently. However, the prototype is the same for all,
|
||||
- * so declare it here regardless of the CONFIG_OF_IRQ setting.
|
||||
- */
|
||||
-extern unsigned int irq_of_parse_and_map(struct device_node *node, int index);
|
||||
-
|
||||
-#if defined(CONFIG_OF_IRQ)
|
||||
/**
|
||||
* of_irq - container for device_node/irq_specifier pair for an irq controller
|
||||
* @controller: pointer to interrupt controller device tree node
|
||||
@@ -71,11 +61,17 @@ extern int of_irq_to_resource(struct dev
|
||||
extern int of_irq_count(struct device_node *dev);
|
||||
extern int of_irq_to_resource_table(struct device_node *dev,
|
||||
struct resource *res, int nr_irqs);
|
||||
-extern struct device_node *of_irq_find_parent(struct device_node *child);
|
||||
|
||||
extern void of_irq_init(const struct of_device_id *matches);
|
||||
|
||||
-#endif /* CONFIG_OF_IRQ */
|
||||
+#if defined(CONFIG_OF)
|
||||
+/*
|
||||
+ * irq_of_parse_and_map() is used by all OF enabled platforms; but SPARC
|
||||
+ * implements it differently. However, the prototype is the same for all,
|
||||
+ * so declare it here regardless of the CONFIG_OF_IRQ setting.
|
||||
+ */
|
||||
+extern unsigned int irq_of_parse_and_map(struct device_node *node, int index);
|
||||
+extern struct device_node *of_irq_find_parent(struct device_node *child);
|
||||
|
||||
#else /* !CONFIG_OF */
|
||||
static inline unsigned int irq_of_parse_and_map(struct device_node *dev,
|
|
@ -0,0 +1,27 @@
|
|||
From 15a2884ede54118137708ccc72f246fe986f8a57 Mon Sep 17 00:00:00 2001
|
||||
From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
|
||||
Date: Thu, 19 Dec 2013 09:30:50 -0300
|
||||
Subject: [PATCH 179/203] of/irq: init struct resource to 0 in
|
||||
of_irq_to_resource()
|
||||
|
||||
It almost does not matter because most users use only the ->start member
|
||||
of the struct. However if this struct is passed to a platform device
|
||||
which is then added via platform_device_add() then the ->parent member is
|
||||
also used.
|
||||
|
||||
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
|
||||
Signed-off-by: Grant Likely <grant.likely@linaro.org>
|
||||
---
|
||||
drivers/of/irq.c | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
--- a/drivers/of/irq.c
|
||||
+++ b/drivers/of/irq.c
|
||||
@@ -351,6 +351,7 @@ int of_irq_to_resource(struct device_nod
|
||||
if (r && irq) {
|
||||
const char *name = NULL;
|
||||
|
||||
+ memset(r, 0, sizeof(*r));
|
||||
/*
|
||||
* Get optional "interrupts-names" property to add a name
|
||||
* to the resource.
|
|
@ -0,0 +1,24 @@
|
|||
From 3d73f7a8db8a7506630174d0e8609138d97c8326 Mon Sep 17 00:00:00 2001
|
||||
From: Yijing Wang <wangyijing@huawei.com>
|
||||
Date: Thu, 19 Dec 2013 09:30:51 -0300
|
||||
Subject: [PATCH 180/203] irq/of: Fix comment typo for irq_of_parse_and_map
|
||||
|
||||
Fix trivial comment typo for irq_of_parse_and_map().
|
||||
|
||||
Signed-off-by: Yijing Wang <wangyijing@huawei.com>
|
||||
Signed-off-by: Grant Likely <grant.likely@linaro.org>
|
||||
---
|
||||
drivers/of/irq.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/of/irq.c
|
||||
+++ b/drivers/of/irq.c
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
/**
|
||||
* irq_of_parse_and_map - Parse and map an interrupt into linux virq space
|
||||
- * @device: Device node of the device whose interrupt is to be mapped
|
||||
+ * @dev: Device node of the device whose interrupt is to be mapped
|
||||
* @index: Index of the interrupt to map
|
||||
*
|
||||
* This function is a wrapper that chains of_irq_map_one() and
|
|
@ -0,0 +1,82 @@
|
|||
From 02abb20a226a5a1e5c6dfaaf765dd71a90200cf9 Mon Sep 17 00:00:00 2001
|
||||
From: Grant Likely <grant.likely@linaro.org>
|
||||
Date: Thu, 19 Dec 2013 09:30:52 -0300
|
||||
Subject: [PATCH 181/203] of: Fix dereferencing node name in debug output to be
|
||||
safe
|
||||
|
||||
Several locations in the of_address and of_irq code dereference the
|
||||
full_name parameter from a device_node pointer without checking if the
|
||||
pointer is valid. This patch switches to use of_node_full_name() which
|
||||
always checks the pointer.
|
||||
|
||||
Signed-off-by: Grant Likely <grant.likely@linaro.org>
|
||||
---
|
||||
drivers/of/address.c | 6 +++---
|
||||
drivers/of/irq.c | 8 ++++----
|
||||
2 files changed, 7 insertions(+), 7 deletions(-)
|
||||
|
||||
--- a/drivers/of/address.c
|
||||
+++ b/drivers/of/address.c
|
||||
@@ -481,7 +481,7 @@ static u64 __of_translate_address(struct
|
||||
int na, ns, pna, pns;
|
||||
u64 result = OF_BAD_ADDR;
|
||||
|
||||
- pr_debug("OF: ** translation for device %s **\n", dev->full_name);
|
||||
+ pr_debug("OF: ** translation for device %s **\n", of_node_full_name(dev));
|
||||
|
||||
/* Increase refcount at current level */
|
||||
of_node_get(dev);
|
||||
@@ -496,13 +496,13 @@ static u64 __of_translate_address(struct
|
||||
bus->count_cells(dev, &na, &ns);
|
||||
if (!OF_CHECK_COUNTS(na, ns)) {
|
||||
printk(KERN_ERR "prom_parse: Bad cell count for %s\n",
|
||||
- dev->full_name);
|
||||
+ of_node_full_name(dev));
|
||||
goto bail;
|
||||
}
|
||||
memcpy(addr, in_addr, na * 4);
|
||||
|
||||
pr_debug("OF: bus is %s (na=%d, ns=%d) on %s\n",
|
||||
- bus->name, na, ns, parent->full_name);
|
||||
+ bus->name, na, ns, of_node_full_name(parent));
|
||||
of_dump_addr("OF: translating address:", addr, na);
|
||||
|
||||
/* Translate */
|
||||
--- a/drivers/of/irq.c
|
||||
+++ b/drivers/of/irq.c
|
||||
@@ -102,7 +102,7 @@ int of_irq_map_raw(struct device_node *p
|
||||
int imaplen, match, i;
|
||||
|
||||
pr_debug("of_irq_map_raw: par=%s,intspec=[0x%08x 0x%08x...],ointsize=%d\n",
|
||||
- parent->full_name, be32_to_cpup(intspec),
|
||||
+ of_node_full_name(parent), be32_to_cpup(intspec),
|
||||
be32_to_cpup(intspec + 1), ointsize);
|
||||
|
||||
ipar = of_node_get(parent);
|
||||
@@ -126,7 +126,7 @@ int of_irq_map_raw(struct device_node *p
|
||||
goto fail;
|
||||
}
|
||||
|
||||
- pr_debug("of_irq_map_raw: ipar=%s, size=%d\n", ipar->full_name, intsize);
|
||||
+ pr_debug("of_irq_map_raw: ipar=%s, size=%d\n", of_node_full_name(ipar), intsize);
|
||||
|
||||
if (ointsize != intsize)
|
||||
return -EINVAL;
|
||||
@@ -287,7 +287,7 @@ int of_irq_map_one(struct device_node *d
|
||||
u32 intsize, intlen;
|
||||
int res = -EINVAL;
|
||||
|
||||
- pr_debug("of_irq_map_one: dev=%s, index=%d\n", device->full_name, index);
|
||||
+ pr_debug("of_irq_map_one: dev=%s, index=%d\n", of_node_full_name(device), index);
|
||||
|
||||
/* OldWorld mac stuff is "special", handle out of line */
|
||||
if (of_irq_workarounds & OF_IMAP_OLDWORLD_MAC)
|
||||
@@ -361,7 +361,7 @@ int of_irq_to_resource(struct device_nod
|
||||
|
||||
r->start = r->end = irq;
|
||||
r->flags = IORESOURCE_IRQ;
|
||||
- r->name = name ? name : dev->full_name;
|
||||
+ r->name = name ? name : of_node_full_name(dev);
|
||||
}
|
||||
|
||||
return irq;
|
|
@ -0,0 +1,34 @@
|
|||
From 4bd60065fb935a5d390c9a442be3a18d2ea18eee Mon Sep 17 00:00:00 2001
|
||||
From: Tomasz Figa <tomasz.figa@gmail.com>
|
||||
Date: Thu, 19 Dec 2013 09:30:53 -0300
|
||||
Subject: [PATCH 182/203] of/irq: Pass trigger type in IRQ resource flags
|
||||
|
||||
Some drivers might rely on availability of trigger flags in IRQ
|
||||
resource, for example to configure the hardware for particular interrupt
|
||||
type. However current code creating IRQ resources from data in device
|
||||
tree does not configure trigger flags in resulting resources.
|
||||
|
||||
This patch tries to solve the problem, based on the fact that
|
||||
irq_of_parse_and_map() configures the trigger based on DT interrupt
|
||||
specifier and IRQD_TRIGGER_* flags are consistent with IORESOURCE_IRQ_*,
|
||||
and we can get correct trigger flags by calling irqd_get_trigger_type()
|
||||
after mapping the interrupt.
|
||||
|
||||
Signed-off-by: Tomasz Figa <tomasz.figa@gmail.com>
|
||||
[grant.likely: Merged the two assignments to r->flags]
|
||||
Signed-off-by: Grant Likely <grant.likely@linaro.org>
|
||||
---
|
||||
drivers/of/irq.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/of/irq.c
|
||||
+++ b/drivers/of/irq.c
|
||||
@@ -360,7 +360,7 @@ int of_irq_to_resource(struct device_nod
|
||||
&name);
|
||||
|
||||
r->start = r->end = irq;
|
||||
- r->flags = IORESOURCE_IRQ;
|
||||
+ r->flags = IORESOURCE_IRQ | irqd_get_trigger_type(irq_get_irq_data(irq));
|
||||
r->name = name ? name : of_node_full_name(dev);
|
||||
}
|
||||
|
|
@ -0,0 +1,682 @@
|
|||
From fd33285b3dab183df0cea06de9f618886dc0f1c0 Mon Sep 17 00:00:00 2001
|
||||
From: Grant Likely <grant.likely@linaro.org>
|
||||
Date: Thu, 19 Dec 2013 09:30:54 -0300
|
||||
Subject: [PATCH 183/203] of/irq: Rename of_irq_map_* functions to
|
||||
of_irq_parse_*
|
||||
|
||||
The OF irq handling code has been overloading the term 'map' to refer to
|
||||
both parsing the data in the device tree and mapping it to the internal
|
||||
linux irq system. This is probably because the device tree does have the
|
||||
concept of an 'interrupt-map' function for translating interrupt
|
||||
references from one node to another, but 'map' is still confusing when
|
||||
the primary purpose of some of the functions are to parse the DT data.
|
||||
|
||||
This patch renames all the of_irq_map_* functions to of_irq_parse_*
|
||||
which makes it clear that there is a difference between the parsing
|
||||
phase and the mapping phase. Kernel code can make use of just the
|
||||
parsing or just the mapping support as needed by the subsystem.
|
||||
|
||||
The patch was generated mechanically with a handful of sed commands.
|
||||
|
||||
Signed-off-by: Grant Likely <grant.likely@linaro.org>
|
||||
Acked-by: Michal Simek <monstr@monstr.eu>
|
||||
Acked-by: Tony Lindgren <tony@atomide.com>
|
||||
Cc: Ralf Baechle <ralf@linux-mips.org>
|
||||
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
|
||||
|
||||
Conflicts:
|
||||
arch/arm/mach-integrator/pci_v3.c
|
||||
arch/mips/pci/pci-rt3883.c
|
||||
---
|
||||
arch/arm/mach-integrator/pci_v3.c | 279 +++++++++++++++++++++++++
|
||||
arch/microblaze/pci/pci-common.c | 2 +-
|
||||
arch/mips/pci/fixup-lantiq.c | 2 +-
|
||||
arch/powerpc/kernel/pci-common.c | 2 +-
|
||||
arch/powerpc/platforms/cell/celleb_scc_pciex.c | 2 +-
|
||||
arch/powerpc/platforms/cell/celleb_scc_sio.c | 2 +-
|
||||
arch/powerpc/platforms/cell/spider-pic.c | 2 +-
|
||||
arch/powerpc/platforms/cell/spu_manage.c | 2 +-
|
||||
arch/powerpc/platforms/fsl_uli1575.c | 2 +-
|
||||
arch/powerpc/platforms/powermac/pic.c | 2 +-
|
||||
arch/powerpc/platforms/pseries/event_sources.c | 2 +-
|
||||
arch/powerpc/sysdev/mpic_msi.c | 2 +-
|
||||
arch/x86/kernel/devicetree.c | 2 +-
|
||||
drivers/of/address.c | 4 +-
|
||||
drivers/of/irq.c | 28 +--
|
||||
drivers/of/of_pci_irq.c | 10 +-
|
||||
drivers/pci/host/pci-mvebu.c | 2 +-
|
||||
include/linux/of_irq.h | 8 +-
|
||||
include/linux/of_pci.h | 2 +-
|
||||
19 files changed, 318 insertions(+), 39 deletions(-)
|
||||
|
||||
--- a/arch/arm/mach-integrator/pci_v3.c
|
||||
+++ b/arch/arm/mach-integrator/pci_v3.c
|
||||
@@ -610,3 +610,282 @@ void __init pci_v3_postinit(void)
|
||||
|
||||
register_isa_ports(PHYS_PCI_MEM_BASE, PHYS_PCI_IO_BASE, 0);
|
||||
}
|
||||
+
|
||||
+/*
|
||||
+ * A small note about bridges and interrupts. The DECchip 21050 (and
|
||||
+ * later) adheres to the PCI-PCI bridge specification. This says that
|
||||
+ * the interrupts on the other side of a bridge are swizzled in the
|
||||
+ * following manner:
|
||||
+ *
|
||||
+ * Dev Interrupt Interrupt
|
||||
+ * Pin on Pin on
|
||||
+ * Device Connector
|
||||
+ *
|
||||
+ * 4 A A
|
||||
+ * B B
|
||||
+ * C C
|
||||
+ * D D
|
||||
+ *
|
||||
+ * 5 A B
|
||||
+ * B C
|
||||
+ * C D
|
||||
+ * D A
|
||||
+ *
|
||||
+ * 6 A C
|
||||
+ * B D
|
||||
+ * C A
|
||||
+ * D B
|
||||
+ *
|
||||
+ * 7 A D
|
||||
+ * B A
|
||||
+ * C B
|
||||
+ * D C
|
||||
+ *
|
||||
+ * Where A = pin 1, B = pin 2 and so on and pin=0 = default = A.
|
||||
+ * Thus, each swizzle is ((pin-1) + (device#-4)) % 4
|
||||
+ */
|
||||
+
|
||||
+/*
|
||||
+ * This routine handles multiple bridges.
|
||||
+ */
|
||||
+static u8 __init pci_v3_swizzle(struct pci_dev *dev, u8 *pinp)
|
||||
+{
|
||||
+ if (*pinp == 0)
|
||||
+ *pinp = 1;
|
||||
+
|
||||
+ return pci_common_swizzle(dev, pinp);
|
||||
+}
|
||||
+
|
||||
+static int irq_tab[4] __initdata = {
|
||||
+ IRQ_AP_PCIINT0, IRQ_AP_PCIINT1, IRQ_AP_PCIINT2, IRQ_AP_PCIINT3
|
||||
+};
|
||||
+
|
||||
+/*
|
||||
+ * map the specified device/slot/pin to an IRQ. This works out such
|
||||
+ * that slot 9 pin 1 is INT0, pin 2 is INT1, and slot 10 pin 1 is INT1.
|
||||
+ */
|
||||
+static int __init pci_v3_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
|
||||
+{
|
||||
+ int intnr = ((slot - 9) + (pin - 1)) & 3;
|
||||
+
|
||||
+ return irq_tab[intnr];
|
||||
+}
|
||||
+
|
||||
+static struct hw_pci pci_v3 __initdata = {
|
||||
+ .swizzle = pci_v3_swizzle,
|
||||
+ .setup = pci_v3_setup,
|
||||
+ .nr_controllers = 1,
|
||||
+ .ops = &pci_v3_ops,
|
||||
+ .preinit = pci_v3_preinit,
|
||||
+ .postinit = pci_v3_postinit,
|
||||
+};
|
||||
+
|
||||
+#ifdef CONFIG_OF
|
||||
+
|
||||
+static int __init pci_v3_map_irq_dt(const struct pci_dev *dev, u8 slot, u8 pin)
|
||||
+{
|
||||
+ struct of_irq oirq;
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = of_irq_parse_pci(dev, &oirq);
|
||||
+ if (ret) {
|
||||
+ dev_err(&dev->dev, "of_irq_parse_pci() %d\n", ret);
|
||||
+ /* Proper return code 0 == NO_IRQ */
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ return irq_create_of_mapping(oirq.controller, oirq.specifier,
|
||||
+ oirq.size);
|
||||
+}
|
||||
+
|
||||
+static int __init pci_v3_dtprobe(struct platform_device *pdev,
|
||||
+ struct device_node *np)
|
||||
+{
|
||||
+ struct of_pci_range_parser parser;
|
||||
+ struct of_pci_range range;
|
||||
+ struct resource *res;
|
||||
+ int irq, ret;
|
||||
+
|
||||
+ if (of_pci_range_parser_init(&parser, np))
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ /* Get base for bridge registers */
|
||||
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
+ if (!res) {
|
||||
+ dev_err(&pdev->dev, "unable to obtain PCIv3 base\n");
|
||||
+ return -ENODEV;
|
||||
+ }
|
||||
+ pci_v3_base = devm_ioremap(&pdev->dev, res->start,
|
||||
+ resource_size(res));
|
||||
+ if (!pci_v3_base) {
|
||||
+ dev_err(&pdev->dev, "unable to remap PCIv3 base\n");
|
||||
+ return -ENODEV;
|
||||
+ }
|
||||
+
|
||||
+ /* Get and request error IRQ resource */
|
||||
+ irq = platform_get_irq(pdev, 0);
|
||||
+ if (irq <= 0) {
|
||||
+ dev_err(&pdev->dev, "unable to obtain PCIv3 error IRQ\n");
|
||||
+ return -ENODEV;
|
||||
+ }
|
||||
+ ret = devm_request_irq(&pdev->dev, irq, v3_irq, 0,
|
||||
+ "PCIv3 error", NULL);
|
||||
+ if (ret < 0) {
|
||||
+ dev_err(&pdev->dev, "unable to request PCIv3 error IRQ %d (%d)\n", irq, ret);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ for_each_of_pci_range(&parser, &range) {
|
||||
+ if (!range.flags) {
|
||||
+ of_pci_range_to_resource(&range, np, &conf_mem);
|
||||
+ conf_mem.name = "PCIv3 config";
|
||||
+ }
|
||||
+ if (range.flags & IORESOURCE_IO) {
|
||||
+ of_pci_range_to_resource(&range, np, &io_mem);
|
||||
+ io_mem.name = "PCIv3 I/O";
|
||||
+ }
|
||||
+ if ((range.flags & IORESOURCE_MEM) &&
|
||||
+ !(range.flags & IORESOURCE_PREFETCH)) {
|
||||
+ non_mem_pci = range.pci_addr;
|
||||
+ non_mem_pci_sz = range.size;
|
||||
+ of_pci_range_to_resource(&range, np, &non_mem);
|
||||
+ non_mem.name = "PCIv3 non-prefetched mem";
|
||||
+ }
|
||||
+ if ((range.flags & IORESOURCE_MEM) &&
|
||||
+ (range.flags & IORESOURCE_PREFETCH)) {
|
||||
+ pre_mem_pci = range.pci_addr;
|
||||
+ pre_mem_pci_sz = range.size;
|
||||
+ of_pci_range_to_resource(&range, np, &pre_mem);
|
||||
+ pre_mem.name = "PCIv3 prefetched mem";
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (!conf_mem.start || !io_mem.start ||
|
||||
+ !non_mem.start || !pre_mem.start) {
|
||||
+ dev_err(&pdev->dev, "missing ranges in device node\n");
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ pci_v3.map_irq = pci_v3_map_irq_dt;
|
||||
+ pci_common_init_dev(&pdev->dev, &pci_v3);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+#else
|
||||
+
|
||||
+static inline int pci_v3_dtprobe(struct platform_device *pdev,
|
||||
+ struct device_node *np)
|
||||
+{
|
||||
+ return -EINVAL;
|
||||
+}
|
||||
+
|
||||
+#endif
|
||||
+
|
||||
+static int __init pci_v3_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct device_node *np = pdev->dev.of_node;
|
||||
+ int ret;
|
||||
+
|
||||
+ /* Remap the Integrator system controller */
|
||||
+ ap_syscon_base = ioremap(INTEGRATOR_SC_BASE, 0x100);
|
||||
+ if (!ap_syscon_base) {
|
||||
+ dev_err(&pdev->dev, "unable to remap the AP syscon for PCIv3\n");
|
||||
+ return -ENODEV;
|
||||
+ }
|
||||
+
|
||||
+ /* Device tree probe path */
|
||||
+ if (np)
|
||||
+ return pci_v3_dtprobe(pdev, np);
|
||||
+
|
||||
+ pci_v3_base = devm_ioremap(&pdev->dev, PHYS_PCI_V3_BASE, SZ_64K);
|
||||
+ if (!pci_v3_base) {
|
||||
+ dev_err(&pdev->dev, "unable to remap PCIv3 base\n");
|
||||
+ return -ENODEV;
|
||||
+ }
|
||||
+
|
||||
+ ret = devm_request_irq(&pdev->dev, IRQ_AP_V3INT, v3_irq, 0, "V3", NULL);
|
||||
+ if (ret) {
|
||||
+ dev_err(&pdev->dev, "unable to grab PCI error interrupt: %d\n",
|
||||
+ ret);
|
||||
+ return -ENODEV;
|
||||
+ }
|
||||
+
|
||||
+ conf_mem.name = "PCIv3 config";
|
||||
+ conf_mem.start = PHYS_PCI_CONFIG_BASE;
|
||||
+ conf_mem.end = PHYS_PCI_CONFIG_BASE + SZ_16M - 1;
|
||||
+ conf_mem.flags = IORESOURCE_MEM;
|
||||
+
|
||||
+ io_mem.name = "PCIv3 I/O";
|
||||
+ io_mem.start = PHYS_PCI_IO_BASE;
|
||||
+ io_mem.end = PHYS_PCI_IO_BASE + SZ_16M - 1;
|
||||
+ io_mem.flags = IORESOURCE_MEM;
|
||||
+
|
||||
+ non_mem_pci = 0x00000000;
|
||||
+ non_mem_pci_sz = SZ_256M;
|
||||
+ non_mem.name = "PCIv3 non-prefetched mem";
|
||||
+ non_mem.start = PHYS_PCI_MEM_BASE;
|
||||
+ non_mem.end = PHYS_PCI_MEM_BASE + SZ_256M - 1;
|
||||
+ non_mem.flags = IORESOURCE_MEM;
|
||||
+
|
||||
+ pre_mem_pci = 0x10000000;
|
||||
+ pre_mem_pci_sz = SZ_256M;
|
||||
+ pre_mem.name = "PCIv3 prefetched mem";
|
||||
+ pre_mem.start = PHYS_PCI_PRE_BASE + SZ_256M;
|
||||
+ pre_mem.end = PHYS_PCI_PRE_BASE + SZ_256M - 1;
|
||||
+ pre_mem.flags = IORESOURCE_MEM | IORESOURCE_PREFETCH;
|
||||
+
|
||||
+ pci_v3.map_irq = pci_v3_map_irq;
|
||||
+
|
||||
+ pci_common_init_dev(&pdev->dev, &pci_v3);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static const struct of_device_id pci_ids[] = {
|
||||
+ { .compatible = "v3,v360epc-pci", },
|
||||
+ {},
|
||||
+};
|
||||
+
|
||||
+static struct platform_driver pci_v3_driver = {
|
||||
+ .driver = {
|
||||
+ .name = "pci-v3",
|
||||
+ .of_match_table = pci_ids,
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
+static int __init pci_v3_init(void)
|
||||
+{
|
||||
+ return platform_driver_probe(&pci_v3_driver, pci_v3_probe);
|
||||
+}
|
||||
+
|
||||
+subsys_initcall(pci_v3_init);
|
||||
+
|
||||
+/*
|
||||
+ * Static mappings for the PCIv3 bridge
|
||||
+ *
|
||||
+ * e8000000 40000000 PCI memory PHYS_PCI_MEM_BASE (max 512M)
|
||||
+ * ec000000 61000000 PCI config space PHYS_PCI_CONFIG_BASE (max 16M)
|
||||
+ * fee00000 60000000 PCI IO PHYS_PCI_IO_BASE (max 16M)
|
||||
+ */
|
||||
+static struct map_desc pci_v3_io_desc[] __initdata __maybe_unused = {
|
||||
+ {
|
||||
+ .virtual = (unsigned long)PCI_MEMORY_VADDR,
|
||||
+ .pfn = __phys_to_pfn(PHYS_PCI_MEM_BASE),
|
||||
+ .length = SZ_16M,
|
||||
+ .type = MT_DEVICE
|
||||
+ }, {
|
||||
+ .virtual = (unsigned long)PCI_CONFIG_VADDR,
|
||||
+ .pfn = __phys_to_pfn(PHYS_PCI_CONFIG_BASE),
|
||||
+ .length = SZ_16M,
|
||||
+ .type = MT_DEVICE
|
||||
+ }
|
||||
+};
|
||||
+
|
||||
+int __init pci_v3_early_init(void)
|
||||
+{
|
||||
+ iotable_init(pci_v3_io_desc, ARRAY_SIZE(pci_v3_io_desc));
|
||||
+ vga_base = (unsigned long)PCI_MEMORY_VADDR;
|
||||
+ pci_map_io_early(__phys_to_pfn(PHYS_PCI_IO_BASE));
|
||||
+ return 0;
|
||||
+}
|
||||
--- a/arch/microblaze/pci/pci-common.c
|
||||
+++ b/arch/microblaze/pci/pci-common.c
|
||||
@@ -217,7 +217,7 @@ int pci_read_irq_line(struct pci_dev *pc
|
||||
memset(&oirq, 0xff, sizeof(oirq));
|
||||
#endif
|
||||
/* Try to get a mapping from the device-tree */
|
||||
- if (of_irq_map_pci(pci_dev, &oirq)) {
|
||||
+ if (of_irq_parse_pci(pci_dev, &oirq)) {
|
||||
u8 line, pin;
|
||||
|
||||
/* If that fails, lets fallback to what is in the config
|
||||
--- a/arch/mips/pci/fixup-lantiq.c
|
||||
+++ b/arch/mips/pci/fixup-lantiq.c
|
||||
@@ -28,7 +28,7 @@ int __init pcibios_map_irq(const struct
|
||||
struct of_irq dev_irq;
|
||||
int irq;
|
||||
|
||||
- if (of_irq_map_pci(dev, &dev_irq)) {
|
||||
+ if (of_irq_parse_pci(dev, &dev_irq)) {
|
||||
dev_err(&dev->dev, "trying to map irq for unknown slot:%d pin:%d\n",
|
||||
slot, pin);
|
||||
return 0;
|
||||
--- a/arch/powerpc/kernel/pci-common.c
|
||||
+++ b/arch/powerpc/kernel/pci-common.c
|
||||
@@ -237,7 +237,7 @@ static int pci_read_irq_line(struct pci_
|
||||
memset(&oirq, 0xff, sizeof(oirq));
|
||||
#endif
|
||||
/* Try to get a mapping from the device-tree */
|
||||
- if (of_irq_map_pci(pci_dev, &oirq)) {
|
||||
+ if (of_irq_parse_pci(pci_dev, &oirq)) {
|
||||
u8 line, pin;
|
||||
|
||||
/* If that fails, lets fallback to what is in the config
|
||||
--- a/arch/powerpc/platforms/cell/celleb_scc_pciex.c
|
||||
+++ b/arch/powerpc/platforms/cell/celleb_scc_pciex.c
|
||||
@@ -507,7 +507,7 @@ static __init int celleb_setup_pciex(str
|
||||
phb->ops = &scc_pciex_pci_ops;
|
||||
|
||||
/* internal interrupt handler */
|
||||
- if (of_irq_map_one(node, 1, &oirq)) {
|
||||
+ if (of_irq_parse_one(node, 1, &oirq)) {
|
||||
pr_err("PCIEXC:Failed to map irq\n");
|
||||
goto error;
|
||||
}
|
||||
--- a/arch/powerpc/platforms/cell/celleb_scc_sio.c
|
||||
+++ b/arch/powerpc/platforms/cell/celleb_scc_sio.c
|
||||
@@ -53,7 +53,7 @@ static int __init txx9_serial_init(void)
|
||||
if (!(txx9_serial_bitmap & (1<<i)))
|
||||
continue;
|
||||
|
||||
- if (of_irq_map_one(node, i, &irq))
|
||||
+ if (of_irq_parse_one(node, i, &irq))
|
||||
continue;
|
||||
if (of_address_to_resource(node,
|
||||
txx9_scc_tab[i].index, &res))
|
||||
--- a/arch/powerpc/platforms/cell/spider-pic.c
|
||||
+++ b/arch/powerpc/platforms/cell/spider-pic.c
|
||||
@@ -236,7 +236,7 @@ static unsigned int __init spider_find_c
|
||||
* tree in case the device-tree is ever fixed
|
||||
*/
|
||||
struct of_irq oirq;
|
||||
- if (of_irq_map_one(pic->host->of_node, 0, &oirq) == 0) {
|
||||
+ if (of_irq_parse_one(pic->host->of_node, 0, &oirq) == 0) {
|
||||
virq = irq_create_of_mapping(oirq.controller, oirq.specifier,
|
||||
oirq.size);
|
||||
return virq;
|
||||
--- a/arch/powerpc/platforms/cell/spu_manage.c
|
||||
+++ b/arch/powerpc/platforms/cell/spu_manage.c
|
||||
@@ -182,7 +182,7 @@ static int __init spu_map_interrupts(str
|
||||
int i;
|
||||
|
||||
for (i=0; i < 3; i++) {
|
||||
- ret = of_irq_map_one(np, i, &oirq);
|
||||
+ ret = of_irq_parse_one(np, i, &oirq);
|
||||
if (ret) {
|
||||
pr_debug("spu_new: failed to get irq %d\n", i);
|
||||
goto err;
|
||||
--- a/arch/powerpc/platforms/fsl_uli1575.c
|
||||
+++ b/arch/powerpc/platforms/fsl_uli1575.c
|
||||
@@ -333,7 +333,7 @@ static void hpcd_final_uli5288(struct pc
|
||||
|
||||
laddr[0] = (hose->first_busno << 16) | (PCI_DEVFN(31, 0) << 8);
|
||||
laddr[1] = laddr[2] = 0;
|
||||
- of_irq_map_raw(hosenode, &pin, 1, laddr, &oirq);
|
||||
+ of_irq_parse_raw(hosenode, &pin, 1, laddr, &oirq);
|
||||
virq = irq_create_of_mapping(oirq.controller, oirq.specifier,
|
||||
oirq.size);
|
||||
dev->irq = virq;
|
||||
--- a/arch/powerpc/platforms/powermac/pic.c
|
||||
+++ b/arch/powerpc/platforms/powermac/pic.c
|
||||
@@ -393,7 +393,7 @@ static void __init pmac_pic_probe_oldsty
|
||||
#endif
|
||||
}
|
||||
|
||||
-int of_irq_map_oldworld(struct device_node *device, int index,
|
||||
+int of_irq_parse_oldworld(struct device_node *device, int index,
|
||||
struct of_irq *out_irq)
|
||||
{
|
||||
const u32 *ints = NULL;
|
||||
--- a/arch/powerpc/platforms/pseries/event_sources.c
|
||||
+++ b/arch/powerpc/platforms/pseries/event_sources.c
|
||||
@@ -55,7 +55,7 @@ void request_event_sources_irqs(struct d
|
||||
/* Else use normal interrupt tree parsing */
|
||||
else {
|
||||
/* First try to do a proper OF tree parsing */
|
||||
- for (index = 0; of_irq_map_one(np, index, &oirq) == 0;
|
||||
+ for (index = 0; of_irq_parse_one(np, index, &oirq) == 0;
|
||||
index++) {
|
||||
if (count > 15)
|
||||
break;
|
||||
--- a/arch/powerpc/sysdev/mpic_msi.c
|
||||
+++ b/arch/powerpc/sysdev/mpic_msi.c
|
||||
@@ -63,7 +63,7 @@ static int mpic_msi_reserve_u3_hwirqs(st
|
||||
pr_debug("mpic: mapping hwirqs for %s\n", np->full_name);
|
||||
|
||||
index = 0;
|
||||
- while (of_irq_map_one(np, index++, &oirq) == 0) {
|
||||
+ while (of_irq_parse_one(np, index++, &oirq) == 0) {
|
||||
ops->xlate(mpic->irqhost, NULL, oirq.specifier,
|
||||
oirq.size, &hwirq, &flags);
|
||||
msi_bitmap_reserve_hwirq(&mpic->msi_bitmap, hwirq);
|
||||
--- a/arch/x86/kernel/devicetree.c
|
||||
+++ b/arch/x86/kernel/devicetree.c
|
||||
@@ -117,7 +117,7 @@ static int x86_of_pci_irq_enable(struct
|
||||
if (!pin)
|
||||
return 0;
|
||||
|
||||
- ret = of_irq_map_pci(dev, &oirq);
|
||||
+ ret = of_irq_parse_pci(dev, &oirq);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
--- a/drivers/of/address.c
|
||||
+++ b/drivers/of/address.c
|
||||
@@ -524,12 +524,12 @@ static u64 __of_translate_address(struct
|
||||
pbus->count_cells(dev, &pna, &pns);
|
||||
if (!OF_CHECK_COUNTS(pna, pns)) {
|
||||
printk(KERN_ERR "prom_parse: Bad cell count for %s\n",
|
||||
- dev->full_name);
|
||||
+ of_node_full_name(dev));
|
||||
break;
|
||||
}
|
||||
|
||||
pr_debug("OF: parent bus is %s (na=%d, ns=%d) on %s\n",
|
||||
- pbus->name, pna, pns, parent->full_name);
|
||||
+ pbus->name, pna, pns, of_node_full_name(parent));
|
||||
|
||||
/* Apply bus translation */
|
||||
if (of_translate_one(dev, bus, pbus, addr, na, ns, pna, rprop))
|
||||
--- a/drivers/of/irq.c
|
||||
+++ b/drivers/of/irq.c
|
||||
@@ -31,14 +31,14 @@
|
||||
* @dev: Device node of the device whose interrupt is to be mapped
|
||||
* @index: Index of the interrupt to map
|
||||
*
|
||||
- * This function is a wrapper that chains of_irq_map_one() and
|
||||
+ * This function is a wrapper that chains of_irq_parse_one() and
|
||||
* irq_create_of_mapping() to make things easier to callers
|
||||
*/
|
||||
unsigned int irq_of_parse_and_map(struct device_node *dev, int index)
|
||||
{
|
||||
struct of_irq oirq;
|
||||
|
||||
- if (of_irq_map_one(dev, index, &oirq))
|
||||
+ if (of_irq_parse_one(dev, index, &oirq))
|
||||
return 0;
|
||||
|
||||
return irq_create_of_mapping(oirq.controller, oirq.specifier,
|
||||
@@ -79,7 +79,7 @@ struct device_node *of_irq_find_parent(s
|
||||
}
|
||||
|
||||
/**
|
||||
- * of_irq_map_raw - Low level interrupt tree parsing
|
||||
+ * of_irq_parse_raw - Low level interrupt tree parsing
|
||||
* @parent: the device interrupt parent
|
||||
* @intspec: interrupt specifier ("interrupts" property of the device)
|
||||
* @ointsize: size of the passed in interrupt specifier
|
||||
@@ -93,7 +93,7 @@ struct device_node *of_irq_find_parent(s
|
||||
* properties, for example when resolving PCI interrupts when no device
|
||||
* node exist for the parent.
|
||||
*/
|
||||
-int of_irq_map_raw(struct device_node *parent, const __be32 *intspec,
|
||||
+int of_irq_parse_raw(struct device_node *parent, const __be32 *intspec,
|
||||
u32 ointsize, const __be32 *addr, struct of_irq *out_irq)
|
||||
{
|
||||
struct device_node *ipar, *tnode, *old = NULL, *newpar = NULL;
|
||||
@@ -101,7 +101,7 @@ int of_irq_map_raw(struct device_node *p
|
||||
u32 intsize = 1, addrsize, newintsize = 0, newaddrsize = 0;
|
||||
int imaplen, match, i;
|
||||
|
||||
- pr_debug("of_irq_map_raw: par=%s,intspec=[0x%08x 0x%08x...],ointsize=%d\n",
|
||||
+ pr_debug("of_irq_parse_raw: par=%s,intspec=[0x%08x 0x%08x...],ointsize=%d\n",
|
||||
of_node_full_name(parent), be32_to_cpup(intspec),
|
||||
be32_to_cpup(intspec + 1), ointsize);
|
||||
|
||||
@@ -126,7 +126,7 @@ int of_irq_map_raw(struct device_node *p
|
||||
goto fail;
|
||||
}
|
||||
|
||||
- pr_debug("of_irq_map_raw: ipar=%s, size=%d\n", of_node_full_name(ipar), intsize);
|
||||
+ pr_debug("of_irq_parse_raw: ipar=%s, size=%d\n", of_node_full_name(ipar), intsize);
|
||||
|
||||
if (ointsize != intsize)
|
||||
return -EINVAL;
|
||||
@@ -269,29 +269,29 @@ int of_irq_map_raw(struct device_node *p
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
-EXPORT_SYMBOL_GPL(of_irq_map_raw);
|
||||
+EXPORT_SYMBOL_GPL(of_irq_parse_raw);
|
||||
|
||||
/**
|
||||
- * of_irq_map_one - Resolve an interrupt for a device
|
||||
+ * of_irq_parse_one - Resolve an interrupt for a device
|
||||
* @device: the device whose interrupt is to be resolved
|
||||
* @index: index of the interrupt to resolve
|
||||
* @out_irq: structure of_irq filled by this function
|
||||
*
|
||||
* This function resolves an interrupt, walking the tree, for a given
|
||||
- * device-tree node. It's the high level pendant to of_irq_map_raw().
|
||||
+ * device-tree node. It's the high level pendant to of_irq_parse_raw().
|
||||
*/
|
||||
-int of_irq_map_one(struct device_node *device, int index, struct of_irq *out_irq)
|
||||
+int of_irq_parse_one(struct device_node *device, int index, struct of_irq *out_irq)
|
||||
{
|
||||
struct device_node *p;
|
||||
const __be32 *intspec, *tmp, *addr;
|
||||
u32 intsize, intlen;
|
||||
int res = -EINVAL;
|
||||
|
||||
- pr_debug("of_irq_map_one: dev=%s, index=%d\n", of_node_full_name(device), index);
|
||||
+ pr_debug("of_irq_parse_one: dev=%s, index=%d\n", of_node_full_name(device), index);
|
||||
|
||||
/* OldWorld mac stuff is "special", handle out of line */
|
||||
if (of_irq_workarounds & OF_IMAP_OLDWORLD_MAC)
|
||||
- return of_irq_map_oldworld(device, index, out_irq);
|
||||
+ return of_irq_parse_oldworld(device, index, out_irq);
|
||||
|
||||
/* Get the reg property (if any) */
|
||||
addr = of_get_property(device, "reg", NULL);
|
||||
@@ -328,13 +328,13 @@ int of_irq_map_one(struct device_node *d
|
||||
goto out;
|
||||
|
||||
/* Get new specifier and map it */
|
||||
- res = of_irq_map_raw(p, intspec + index * intsize, intsize,
|
||||
+ res = of_irq_parse_raw(p, intspec + index * intsize, intsize,
|
||||
addr, out_irq);
|
||||
out:
|
||||
of_node_put(p);
|
||||
return res;
|
||||
}
|
||||
-EXPORT_SYMBOL_GPL(of_irq_map_one);
|
||||
+EXPORT_SYMBOL_GPL(of_irq_parse_one);
|
||||
|
||||
/**
|
||||
* of_irq_to_resource - Decode a node's IRQ and return it as a resource
|
||||
--- a/drivers/of/of_pci_irq.c
|
||||
+++ b/drivers/of/of_pci_irq.c
|
||||
@@ -5,7 +5,7 @@
|
||||
#include <asm/prom.h>
|
||||
|
||||
/**
|
||||
- * of_irq_map_pci - Resolve the interrupt for a PCI device
|
||||
+ * of_irq_parse_pci - Resolve the interrupt for a PCI device
|
||||
* @pdev: the device whose interrupt is to be resolved
|
||||
* @out_irq: structure of_irq filled by this function
|
||||
*
|
||||
@@ -15,7 +15,7 @@
|
||||
* PCI tree until an device-node is found, at which point it will finish
|
||||
* resolving using the OF tree walking.
|
||||
*/
|
||||
-int of_irq_map_pci(const struct pci_dev *pdev, struct of_irq *out_irq)
|
||||
+int of_irq_parse_pci(const struct pci_dev *pdev, struct of_irq *out_irq)
|
||||
{
|
||||
struct device_node *dn, *ppnode;
|
||||
struct pci_dev *ppdev;
|
||||
@@ -30,7 +30,7 @@ int of_irq_map_pci(const struct pci_dev
|
||||
*/
|
||||
dn = pci_device_to_OF_node(pdev);
|
||||
if (dn) {
|
||||
- rc = of_irq_map_one(dn, 0, out_irq);
|
||||
+ rc = of_irq_parse_one(dn, 0, out_irq);
|
||||
if (!rc)
|
||||
return rc;
|
||||
}
|
||||
@@ -88,6 +88,6 @@ int of_irq_map_pci(const struct pci_dev
|
||||
lspec_be = cpu_to_be32(lspec);
|
||||
laddr[0] = cpu_to_be32((pdev->bus->number << 16) | (pdev->devfn << 8));
|
||||
laddr[1] = laddr[2] = cpu_to_be32(0);
|
||||
- return of_irq_map_raw(ppnode, &lspec_be, 1, laddr, out_irq);
|
||||
+ return of_irq_parse_raw(ppnode, &lspec_be, 1, laddr, out_irq);
|
||||
}
|
||||
-EXPORT_SYMBOL_GPL(of_irq_map_pci);
|
||||
+EXPORT_SYMBOL_GPL(of_irq_parse_pci);
|
||||
--- a/drivers/pci/host/pci-mvebu.c
|
||||
+++ b/drivers/pci/host/pci-mvebu.c
|
||||
@@ -652,7 +652,7 @@ static int __init mvebu_pcie_map_irq(con
|
||||
struct of_irq oirq;
|
||||
int ret;
|
||||
|
||||
- ret = of_irq_map_pci(dev, &oirq);
|
||||
+ ret = of_irq_parse_pci(dev, &oirq);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
--- a/include/linux/of_irq.h
|
||||
+++ b/include/linux/of_irq.h
|
||||
@@ -35,12 +35,12 @@ typedef int (*of_irq_init_cb_t)(struct d
|
||||
#if defined(CONFIG_PPC32) && defined(CONFIG_PPC_PMAC)
|
||||
extern unsigned int of_irq_workarounds;
|
||||
extern struct device_node *of_irq_dflt_pic;
|
||||
-extern int of_irq_map_oldworld(struct device_node *device, int index,
|
||||
+extern int of_irq_parse_oldworld(struct device_node *device, int index,
|
||||
struct of_irq *out_irq);
|
||||
#else /* CONFIG_PPC32 && CONFIG_PPC_PMAC */
|
||||
#define of_irq_workarounds (0)
|
||||
#define of_irq_dflt_pic (NULL)
|
||||
-static inline int of_irq_map_oldworld(struct device_node *device, int index,
|
||||
+static inline int of_irq_parse_oldworld(struct device_node *device, int index,
|
||||
struct of_irq *out_irq)
|
||||
{
|
||||
return -EINVAL;
|
||||
@@ -48,10 +48,10 @@ static inline int of_irq_map_oldworld(st
|
||||
#endif /* CONFIG_PPC32 && CONFIG_PPC_PMAC */
|
||||
|
||||
|
||||
-extern int of_irq_map_raw(struct device_node *parent, const __be32 *intspec,
|
||||
+extern int of_irq_parse_raw(struct device_node *parent, const __be32 *intspec,
|
||||
u32 ointsize, const __be32 *addr,
|
||||
struct of_irq *out_irq);
|
||||
-extern int of_irq_map_one(struct device_node *device, int index,
|
||||
+extern int of_irq_parse_one(struct device_node *device, int index,
|
||||
struct of_irq *out_irq);
|
||||
extern unsigned int irq_create_of_mapping(struct device_node *controller,
|
||||
const u32 *intspec,
|
||||
--- a/include/linux/of_pci.h
|
||||
+++ b/include/linux/of_pci.h
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
struct pci_dev;
|
||||
struct of_irq;
|
||||
-int of_irq_map_pci(const struct pci_dev *pdev, struct of_irq *out_irq);
|
||||
+int of_irq_parse_pci(const struct pci_dev *pdev, struct of_irq *out_irq);
|
||||
|
||||
struct device_node;
|
||||
struct device_node *of_pci_find_child_device(struct device_node *parent,
|
|
@ -0,0 +1,486 @@
|
|||
From 1baf727ee1d863a0eacd249cff6afc99022593c2 Mon Sep 17 00:00:00 2001
|
||||
From: Grant Likely <grant.likely@linaro.org>
|
||||
Date: Thu, 19 Dec 2013 09:30:55 -0300
|
||||
Subject: [PATCH 184/203] of/irq: Replace of_irq with of_phandle_args
|
||||
|
||||
struct of_irq and struct of_phandle_args are exactly the same structure.
|
||||
This patch makes the kernel use of_phandle_args everywhere. This in
|
||||
itself isn't a big deal, but it makes some follow-on patches simpler.
|
||||
|
||||
Signed-off-by: Grant Likely <grant.likely@linaro.org>
|
||||
Acked-by: Michal Simek <monstr@monstr.eu>
|
||||
Acked-by: Tony Lindgren <tony@atomide.com>
|
||||
Cc: Russell King <linux@arm.linux.org.uk>
|
||||
Cc: Ralf Baechle <ralf@linux-mips.org>
|
||||
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
|
||||
|
||||
Conflicts:
|
||||
arch/mips/pci/pci-rt3883.c
|
||||
---
|
||||
arch/arm/mach-integrator/pci_v3.c | 5 ++---
|
||||
arch/microblaze/pci/pci-common.c | 9 ++++-----
|
||||
arch/mips/pci/fixup-lantiq.c | 5 ++---
|
||||
arch/powerpc/kernel/pci-common.c | 9 ++++-----
|
||||
arch/powerpc/platforms/cell/celleb_scc_pciex.c | 5 ++---
|
||||
arch/powerpc/platforms/cell/celleb_scc_sio.c | 5 ++---
|
||||
arch/powerpc/platforms/cell/spider-pic.c | 6 +++---
|
||||
arch/powerpc/platforms/cell/spu_manage.c | 12 ++++++------
|
||||
arch/powerpc/platforms/fsl_uli1575.c | 8 +++-----
|
||||
arch/powerpc/platforms/powermac/pic.c | 8 ++++----
|
||||
arch/powerpc/platforms/pseries/event_sources.c | 7 +++----
|
||||
arch/powerpc/sysdev/mpic_msi.c | 6 +++---
|
||||
arch/x86/kernel/devicetree.c | 5 ++---
|
||||
drivers/of/irq.c | 15 +++++++--------
|
||||
drivers/of/of_pci_irq.c | 2 +-
|
||||
drivers/pci/host/pci-mvebu.c | 5 ++---
|
||||
include/linux/of_irq.h | 24 ++++--------------------
|
||||
include/linux/of_pci.h | 4 ++--
|
||||
18 files changed, 56 insertions(+), 84 deletions(-)
|
||||
|
||||
--- a/arch/arm/mach-integrator/pci_v3.c
|
||||
+++ b/arch/arm/mach-integrator/pci_v3.c
|
||||
@@ -684,7 +684,7 @@ static struct hw_pci pci_v3 __initdata =
|
||||
|
||||
static int __init pci_v3_map_irq_dt(const struct pci_dev *dev, u8 slot, u8 pin)
|
||||
{
|
||||
- struct of_irq oirq;
|
||||
+ struct of_phandle_args oirq;
|
||||
int ret;
|
||||
|
||||
ret = of_irq_parse_pci(dev, &oirq);
|
||||
@@ -694,8 +694,7 @@ static int __init pci_v3_map_irq_dt(cons
|
||||
return 0;
|
||||
}
|
||||
|
||||
- return irq_create_of_mapping(oirq.controller, oirq.specifier,
|
||||
- oirq.size);
|
||||
+ return irq_create_of_mapping(oirq.np, oirq.args, oirq.args_count);
|
||||
}
|
||||
|
||||
static int __init pci_v3_dtprobe(struct platform_device *pdev,
|
||||
--- a/arch/microblaze/pci/pci-common.c
|
||||
+++ b/arch/microblaze/pci/pci-common.c
|
||||
@@ -199,7 +199,7 @@ void pcibios_set_master(struct pci_dev *
|
||||
*/
|
||||
int pci_read_irq_line(struct pci_dev *pci_dev)
|
||||
{
|
||||
- struct of_irq oirq;
|
||||
+ struct of_phandle_args oirq;
|
||||
unsigned int virq;
|
||||
|
||||
/* The current device-tree that iSeries generates from the HV
|
||||
@@ -243,11 +243,10 @@ int pci_read_irq_line(struct pci_dev *pc
|
||||
irq_set_irq_type(virq, IRQ_TYPE_LEVEL_LOW);
|
||||
} else {
|
||||
pr_debug(" Got one, spec %d cells (0x%08x 0x%08x...) on %s\n",
|
||||
- oirq.size, oirq.specifier[0], oirq.specifier[1],
|
||||
- of_node_full_name(oirq.controller));
|
||||
+ oirq.args_count, oirq.args[0], oirq.args[1],
|
||||
+ of_node_full_name(oirq.np));
|
||||
|
||||
- virq = irq_create_of_mapping(oirq.controller, oirq.specifier,
|
||||
- oirq.size);
|
||||
+ virq = irq_create_of_mapping(oirq.np, oirq.args, oirq.args_count);
|
||||
}
|
||||
if (!virq) {
|
||||
pr_debug(" Failed to map !\n");
|
||||
--- a/arch/mips/pci/fixup-lantiq.c
|
||||
+++ b/arch/mips/pci/fixup-lantiq.c
|
||||
@@ -25,7 +25,7 @@ int pcibios_plat_dev_init(struct pci_dev
|
||||
|
||||
int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
|
||||
{
|
||||
- struct of_irq dev_irq;
|
||||
+ struct of_phandle_args dev_irq;
|
||||
int irq;
|
||||
|
||||
if (of_irq_parse_pci(dev, &dev_irq)) {
|
||||
@@ -33,8 +33,7 @@ int __init pcibios_map_irq(const struct
|
||||
slot, pin);
|
||||
return 0;
|
||||
}
|
||||
- irq = irq_create_of_mapping(dev_irq.controller, dev_irq.specifier,
|
||||
- dev_irq.size);
|
||||
+ irq = irq_create_of_mapping(dev_irq.np, dev_irq.args, dev_irq.args_count);
|
||||
dev_info(&dev->dev, "SLOT:%d PIN:%d IRQ:%d\n", slot, pin, irq);
|
||||
return irq;
|
||||
}
|
||||
--- a/arch/powerpc/kernel/pci-common.c
|
||||
+++ b/arch/powerpc/kernel/pci-common.c
|
||||
@@ -228,7 +228,7 @@ int pcibios_add_platform_entries(struct
|
||||
*/
|
||||
static int pci_read_irq_line(struct pci_dev *pci_dev)
|
||||
{
|
||||
- struct of_irq oirq;
|
||||
+ struct of_phandle_args oirq;
|
||||
unsigned int virq;
|
||||
|
||||
pr_debug("PCI: Try to map irq for %s...\n", pci_name(pci_dev));
|
||||
@@ -263,11 +263,10 @@ static int pci_read_irq_line(struct pci_
|
||||
irq_set_irq_type(virq, IRQ_TYPE_LEVEL_LOW);
|
||||
} else {
|
||||
pr_debug(" Got one, spec %d cells (0x%08x 0x%08x...) on %s\n",
|
||||
- oirq.size, oirq.specifier[0], oirq.specifier[1],
|
||||
- of_node_full_name(oirq.controller));
|
||||
+ oirq.args_count, oirq.args[0], oirq.args[1],
|
||||
+ of_node_full_name(oirq.np));
|
||||
|
||||
- virq = irq_create_of_mapping(oirq.controller, oirq.specifier,
|
||||
- oirq.size);
|
||||
+ virq = irq_create_of_mapping(oirq.np, oirq.args, oirq.args_count);
|
||||
}
|
||||
if(virq == NO_IRQ) {
|
||||
pr_debug(" Failed to map !\n");
|
||||
--- a/arch/powerpc/platforms/cell/celleb_scc_pciex.c
|
||||
+++ b/arch/powerpc/platforms/cell/celleb_scc_pciex.c
|
||||
@@ -486,7 +486,7 @@ static __init int celleb_setup_pciex(str
|
||||
struct pci_controller *phb)
|
||||
{
|
||||
struct resource r;
|
||||
- struct of_irq oirq;
|
||||
+ struct of_phandle_args oirq;
|
||||
int virq;
|
||||
|
||||
/* SMMIO registers; used inside this file */
|
||||
@@ -511,8 +511,7 @@ static __init int celleb_setup_pciex(str
|
||||
pr_err("PCIEXC:Failed to map irq\n");
|
||||
goto error;
|
||||
}
|
||||
- virq = irq_create_of_mapping(oirq.controller, oirq.specifier,
|
||||
- oirq.size);
|
||||
+ virq = irq_create_of_mapping(oirq.np, oirq.args, oirq.args_count);
|
||||
if (request_irq(virq, pciex_handle_internal_irq,
|
||||
0, "pciex", (void *)phb)) {
|
||||
pr_err("PCIEXC:Failed to request irq\n");
|
||||
--- a/arch/powerpc/platforms/cell/celleb_scc_sio.c
|
||||
+++ b/arch/powerpc/platforms/cell/celleb_scc_sio.c
|
||||
@@ -45,7 +45,7 @@ static int __init txx9_serial_init(void)
|
||||
struct device_node *node;
|
||||
int i;
|
||||
struct uart_port req;
|
||||
- struct of_irq irq;
|
||||
+ struct of_phandle_args irq;
|
||||
struct resource res;
|
||||
|
||||
for_each_compatible_node(node, "serial", "toshiba,sio-scc") {
|
||||
@@ -66,8 +66,7 @@ static int __init txx9_serial_init(void)
|
||||
#ifdef CONFIG_SERIAL_TXX9_CONSOLE
|
||||
req.membase = ioremap(req.mapbase, 0x24);
|
||||
#endif
|
||||
- req.irq = irq_create_of_mapping(irq.controller,
|
||||
- irq.specifier, irq.size);
|
||||
+ req.irq = irq_create_of_mapping(irq.np, irq.args, irq.args_count);
|
||||
req.flags |= UPF_IOREMAP | UPF_BUGGY_UART
|
||||
/*HAVE_CTS_LINE*/;
|
||||
req.uartclk = 83300000;
|
||||
--- a/arch/powerpc/platforms/cell/spider-pic.c
|
||||
+++ b/arch/powerpc/platforms/cell/spider-pic.c
|
||||
@@ -235,10 +235,10 @@ static unsigned int __init spider_find_c
|
||||
/* First, we check whether we have a real "interrupts" in the device
|
||||
* tree in case the device-tree is ever fixed
|
||||
*/
|
||||
- struct of_irq oirq;
|
||||
+ struct of_phandle_args oirq;
|
||||
if (of_irq_parse_one(pic->host->of_node, 0, &oirq) == 0) {
|
||||
- virq = irq_create_of_mapping(oirq.controller, oirq.specifier,
|
||||
- oirq.size);
|
||||
+ virq = irq_create_of_mapping(oirq.np, oirq.args,
|
||||
+ oirq.args_count);
|
||||
return virq;
|
||||
}
|
||||
|
||||
--- a/arch/powerpc/platforms/cell/spu_manage.c
|
||||
+++ b/arch/powerpc/platforms/cell/spu_manage.c
|
||||
@@ -177,7 +177,7 @@ out:
|
||||
|
||||
static int __init spu_map_interrupts(struct spu *spu, struct device_node *np)
|
||||
{
|
||||
- struct of_irq oirq;
|
||||
+ struct of_phandle_args oirq;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
@@ -188,10 +188,10 @@ static int __init spu_map_interrupts(str
|
||||
goto err;
|
||||
}
|
||||
ret = -EINVAL;
|
||||
- pr_debug(" irq %d no 0x%x on %s\n", i, oirq.specifier[0],
|
||||
- oirq.controller->full_name);
|
||||
- spu->irqs[i] = irq_create_of_mapping(oirq.controller,
|
||||
- oirq.specifier, oirq.size);
|
||||
+ pr_debug(" irq %d no 0x%x on %s\n", i, oirq.args[0],
|
||||
+ oirq.np->full_name);
|
||||
+ spu->irqs[i] = irq_create_of_mapping(oirq.np,
|
||||
+ oirq.args, oirq.args_count);
|
||||
if (spu->irqs[i] == NO_IRQ) {
|
||||
pr_debug("spu_new: failed to map it !\n");
|
||||
goto err;
|
||||
@@ -200,7 +200,7 @@ static int __init spu_map_interrupts(str
|
||||
return 0;
|
||||
|
||||
err:
|
||||
- pr_debug("failed to map irq %x for spu %s\n", *oirq.specifier,
|
||||
+ pr_debug("failed to map irq %x for spu %s\n", *oirq.args,
|
||||
spu->name);
|
||||
for (; i >= 0; i--) {
|
||||
if (spu->irqs[i] != NO_IRQ)
|
||||
--- a/arch/powerpc/platforms/fsl_uli1575.c
|
||||
+++ b/arch/powerpc/platforms/fsl_uli1575.c
|
||||
@@ -321,8 +321,8 @@ static void hpcd_final_uli5288(struct pc
|
||||
{
|
||||
struct pci_controller *hose = pci_bus_to_host(dev->bus);
|
||||
struct device_node *hosenode = hose ? hose->dn : NULL;
|
||||
- struct of_irq oirq;
|
||||
- int virq, pin = 2;
|
||||
+ struct of_phandle_args oirq;
|
||||
+ int pin = 2;
|
||||
u32 laddr[3];
|
||||
|
||||
if (!machine_is(mpc86xx_hpcd))
|
||||
@@ -334,9 +334,7 @@ static void hpcd_final_uli5288(struct pc
|
||||
laddr[0] = (hose->first_busno << 16) | (PCI_DEVFN(31, 0) << 8);
|
||||
laddr[1] = laddr[2] = 0;
|
||||
of_irq_parse_raw(hosenode, &pin, 1, laddr, &oirq);
|
||||
- virq = irq_create_of_mapping(oirq.controller, oirq.specifier,
|
||||
- oirq.size);
|
||||
- dev->irq = virq;
|
||||
+ dev->irq = irq_create_of_mapping(oirq.np, oirq.args, oirq.args_count);
|
||||
}
|
||||
|
||||
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AL, 0x1575, hpcd_quirk_uli1575);
|
||||
--- a/arch/powerpc/platforms/powermac/pic.c
|
||||
+++ b/arch/powerpc/platforms/powermac/pic.c
|
||||
@@ -394,7 +394,7 @@ static void __init pmac_pic_probe_oldsty
|
||||
}
|
||||
|
||||
int of_irq_parse_oldworld(struct device_node *device, int index,
|
||||
- struct of_irq *out_irq)
|
||||
+ struct of_phandle_args *out_irq)
|
||||
{
|
||||
const u32 *ints = NULL;
|
||||
int intlen;
|
||||
@@ -422,9 +422,9 @@ int of_irq_parse_oldworld(struct device_
|
||||
if (index >= intlen)
|
||||
return -EINVAL;
|
||||
|
||||
- out_irq->controller = NULL;
|
||||
- out_irq->specifier[0] = ints[index];
|
||||
- out_irq->size = 1;
|
||||
+ out_irq->np = NULL;
|
||||
+ out_irq->args[0] = ints[index];
|
||||
+ out_irq->args_count = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
--- a/arch/powerpc/platforms/pseries/event_sources.c
|
||||
+++ b/arch/powerpc/platforms/pseries/event_sources.c
|
||||
@@ -25,7 +25,7 @@ void request_event_sources_irqs(struct d
|
||||
const char *name)
|
||||
{
|
||||
int i, index, count = 0;
|
||||
- struct of_irq oirq;
|
||||
+ struct of_phandle_args oirq;
|
||||
const u32 *opicprop;
|
||||
unsigned int opicplen;
|
||||
unsigned int virqs[16];
|
||||
@@ -59,9 +59,8 @@ void request_event_sources_irqs(struct d
|
||||
index++) {
|
||||
if (count > 15)
|
||||
break;
|
||||
- virqs[count] = irq_create_of_mapping(oirq.controller,
|
||||
- oirq.specifier,
|
||||
- oirq.size);
|
||||
+ virqs[count] = irq_create_of_mapping(oirq.np, oirq.args,
|
||||
+ oirq.args_count);
|
||||
if (virqs[count] == NO_IRQ) {
|
||||
pr_err("event-sources: Unable to allocate "
|
||||
"interrupt number for %s\n",
|
||||
--- a/arch/powerpc/sysdev/mpic_msi.c
|
||||
+++ b/arch/powerpc/sysdev/mpic_msi.c
|
||||
@@ -35,7 +35,7 @@ static int mpic_msi_reserve_u3_hwirqs(st
|
||||
const struct irq_domain_ops *ops = mpic->irqhost->ops;
|
||||
struct device_node *np;
|
||||
int flags, index, i;
|
||||
- struct of_irq oirq;
|
||||
+ struct of_phandle_args oirq;
|
||||
|
||||
pr_debug("mpic: found U3, guessing msi allocator setup\n");
|
||||
|
||||
@@ -64,8 +64,8 @@ static int mpic_msi_reserve_u3_hwirqs(st
|
||||
|
||||
index = 0;
|
||||
while (of_irq_parse_one(np, index++, &oirq) == 0) {
|
||||
- ops->xlate(mpic->irqhost, NULL, oirq.specifier,
|
||||
- oirq.size, &hwirq, &flags);
|
||||
+ ops->xlate(mpic->irqhost, NULL, oirq.args,
|
||||
+ oirq.args_count, &hwirq, &flags);
|
||||
msi_bitmap_reserve_hwirq(&mpic->msi_bitmap, hwirq);
|
||||
}
|
||||
}
|
||||
--- a/arch/x86/kernel/devicetree.c
|
||||
+++ b/arch/x86/kernel/devicetree.c
|
||||
@@ -106,7 +106,7 @@ struct device_node *pcibios_get_phb_of_n
|
||||
|
||||
static int x86_of_pci_irq_enable(struct pci_dev *dev)
|
||||
{
|
||||
- struct of_irq oirq;
|
||||
+ struct of_phandle_args oirq;
|
||||
u32 virq;
|
||||
int ret;
|
||||
u8 pin;
|
||||
@@ -121,8 +121,7 @@ static int x86_of_pci_irq_enable(struct
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
- virq = irq_create_of_mapping(oirq.controller, oirq.specifier,
|
||||
- oirq.size);
|
||||
+ virq = irq_create_of_mapping(oirq.np, oirq.args, oirq.args_count);
|
||||
if (virq == 0)
|
||||
return -EINVAL;
|
||||
dev->irq = virq;
|
||||
--- a/drivers/of/irq.c
|
||||
+++ b/drivers/of/irq.c
|
||||
@@ -36,13 +36,12 @@
|
||||
*/
|
||||
unsigned int irq_of_parse_and_map(struct device_node *dev, int index)
|
||||
{
|
||||
- struct of_irq oirq;
|
||||
+ struct of_phandle_args oirq;
|
||||
|
||||
if (of_irq_parse_one(dev, index, &oirq))
|
||||
return 0;
|
||||
|
||||
- return irq_create_of_mapping(oirq.controller, oirq.specifier,
|
||||
- oirq.size);
|
||||
+ return irq_create_of_mapping(oirq.np, oirq.args, oirq.args_count);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(irq_of_parse_and_map);
|
||||
|
||||
@@ -94,7 +93,7 @@ struct device_node *of_irq_find_parent(s
|
||||
* node exist for the parent.
|
||||
*/
|
||||
int of_irq_parse_raw(struct device_node *parent, const __be32 *intspec,
|
||||
- u32 ointsize, const __be32 *addr, struct of_irq *out_irq)
|
||||
+ u32 ointsize, const __be32 *addr, struct of_phandle_args *out_irq)
|
||||
{
|
||||
struct device_node *ipar, *tnode, *old = NULL, *newpar = NULL;
|
||||
const __be32 *tmp, *imap, *imask;
|
||||
@@ -156,10 +155,10 @@ int of_irq_parse_raw(struct device_node
|
||||
NULL) {
|
||||
pr_debug(" -> got it !\n");
|
||||
for (i = 0; i < intsize; i++)
|
||||
- out_irq->specifier[i] =
|
||||
+ out_irq->args[i] =
|
||||
of_read_number(intspec +i, 1);
|
||||
- out_irq->size = intsize;
|
||||
- out_irq->controller = ipar;
|
||||
+ out_irq->args_count = intsize;
|
||||
+ out_irq->np = ipar;
|
||||
of_node_put(old);
|
||||
return 0;
|
||||
}
|
||||
@@ -280,7 +279,7 @@ EXPORT_SYMBOL_GPL(of_irq_parse_raw);
|
||||
* This function resolves an interrupt, walking the tree, for a given
|
||||
* device-tree node. It's the high level pendant to of_irq_parse_raw().
|
||||
*/
|
||||
-int of_irq_parse_one(struct device_node *device, int index, struct of_irq *out_irq)
|
||||
+int of_irq_parse_one(struct device_node *device, int index, struct of_phandle_args *out_irq)
|
||||
{
|
||||
struct device_node *p;
|
||||
const __be32 *intspec, *tmp, *addr;
|
||||
--- a/drivers/of/of_pci_irq.c
|
||||
+++ b/drivers/of/of_pci_irq.c
|
||||
@@ -15,7 +15,7 @@
|
||||
* PCI tree until an device-node is found, at which point it will finish
|
||||
* resolving using the OF tree walking.
|
||||
*/
|
||||
-int of_irq_parse_pci(const struct pci_dev *pdev, struct of_irq *out_irq)
|
||||
+int of_irq_parse_pci(const struct pci_dev *pdev, struct of_phandle_args *out_irq)
|
||||
{
|
||||
struct device_node *dn, *ppnode;
|
||||
struct pci_dev *ppdev;
|
||||
--- a/drivers/pci/host/pci-mvebu.c
|
||||
+++ b/drivers/pci/host/pci-mvebu.c
|
||||
@@ -649,15 +649,14 @@ static int __init mvebu_pcie_setup(int n
|
||||
|
||||
static int __init mvebu_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
|
||||
{
|
||||
- struct of_irq oirq;
|
||||
+ struct of_phandle_args oirq;
|
||||
int ret;
|
||||
|
||||
ret = of_irq_parse_pci(dev, &oirq);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
- return irq_create_of_mapping(oirq.controller, oirq.specifier,
|
||||
- oirq.size);
|
||||
+ return irq_create_of_mapping(oirq.np, oirq.args, oirq.args_count);
|
||||
}
|
||||
|
||||
static struct pci_bus *mvebu_pcie_scan_bus(int nr, struct pci_sys_data *sys)
|
||||
--- a/include/linux/of_irq.h
|
||||
+++ b/include/linux/of_irq.h
|
||||
@@ -8,22 +8,6 @@
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
-/**
|
||||
- * of_irq - container for device_node/irq_specifier pair for an irq controller
|
||||
- * @controller: pointer to interrupt controller device tree node
|
||||
- * @size: size of interrupt specifier
|
||||
- * @specifier: array of cells @size long specifing the specific interrupt
|
||||
- *
|
||||
- * This structure is returned when an interrupt is mapped. The controller
|
||||
- * field needs to be put() after use
|
||||
- */
|
||||
-#define OF_MAX_IRQ_SPEC 4 /* We handle specifiers of at most 4 cells */
|
||||
-struct of_irq {
|
||||
- struct device_node *controller; /* Interrupt controller node */
|
||||
- u32 size; /* Specifier size */
|
||||
- u32 specifier[OF_MAX_IRQ_SPEC]; /* Specifier copy */
|
||||
-};
|
||||
-
|
||||
typedef int (*of_irq_init_cb_t)(struct device_node *, struct device_node *);
|
||||
|
||||
/*
|
||||
@@ -36,12 +20,12 @@ typedef int (*of_irq_init_cb_t)(struct d
|
||||
extern unsigned int of_irq_workarounds;
|
||||
extern struct device_node *of_irq_dflt_pic;
|
||||
extern int of_irq_parse_oldworld(struct device_node *device, int index,
|
||||
- struct of_irq *out_irq);
|
||||
+ struct of_phandle_args *out_irq);
|
||||
#else /* CONFIG_PPC32 && CONFIG_PPC_PMAC */
|
||||
#define of_irq_workarounds (0)
|
||||
#define of_irq_dflt_pic (NULL)
|
||||
static inline int of_irq_parse_oldworld(struct device_node *device, int index,
|
||||
- struct of_irq *out_irq)
|
||||
+ struct of_phandle_args *out_irq)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -50,9 +34,9 @@ static inline int of_irq_parse_oldworld(
|
||||
|
||||
extern int of_irq_parse_raw(struct device_node *parent, const __be32 *intspec,
|
||||
u32 ointsize, const __be32 *addr,
|
||||
- struct of_irq *out_irq);
|
||||
+ struct of_phandle_args *out_irq);
|
||||
extern int of_irq_parse_one(struct device_node *device, int index,
|
||||
- struct of_irq *out_irq);
|
||||
+ struct of_phandle_args *out_irq);
|
||||
extern unsigned int irq_create_of_mapping(struct device_node *controller,
|
||||
const u32 *intspec,
|
||||
unsigned int intsize);
|
||||
--- a/include/linux/of_pci.h
|
||||
+++ b/include/linux/of_pci.h
|
||||
@@ -5,8 +5,8 @@
|
||||
#include <linux/msi.h>
|
||||
|
||||
struct pci_dev;
|
||||
-struct of_irq;
|
||||
-int of_irq_parse_pci(const struct pci_dev *pdev, struct of_irq *out_irq);
|
||||
+struct of_phandle_args;
|
||||
+int of_irq_parse_pci(const struct pci_dev *pdev, struct of_phandle_args *out_irq);
|
||||
|
||||
struct device_node;
|
||||
struct device_node *of_pci_find_child_device(struct device_node *parent,
|
|
@ -0,0 +1,245 @@
|
|||
From 5e69ff59f7e51ddfde0b31587beb9e40ea1c85bc Mon Sep 17 00:00:00 2001
|
||||
From: Grant Likely <grant.likely@linaro.org>
|
||||
Date: Thu, 19 Dec 2013 09:30:56 -0300
|
||||
Subject: [PATCH 185/203] of/irq: simplify args to irq_create_of_mapping
|
||||
|
||||
All the callers of irq_create_of_mapping() pass the contents of a struct
|
||||
of_phandle_args structure to the function. Since all the callers already
|
||||
have an of_phandle_args pointer, why not pass it directly to
|
||||
irq_create_of_mapping()?
|
||||
|
||||
Signed-off-by: Grant Likely <grant.likely@linaro.org>
|
||||
Acked-by: Michal Simek <monstr@monstr.eu>
|
||||
Acked-by: Tony Lindgren <tony@atomide.com>
|
||||
Cc: Thomas Gleixner <tglx@linutronix.de>
|
||||
Cc: Russell King <linux@arm.linux.org.uk>
|
||||
Cc: Ralf Baechle <ralf@linux-mips.org>
|
||||
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
|
||||
|
||||
Conflicts:
|
||||
arch/mips/pci/pci-rt3883.c
|
||||
kernel/irq/irqdomain.c
|
||||
---
|
||||
arch/arm/mach-integrator/pci_v3.c | 2 +-
|
||||
arch/microblaze/pci/pci-common.c | 2 +-
|
||||
arch/mips/pci/fixup-lantiq.c | 2 +-
|
||||
arch/powerpc/kernel/pci-common.c | 2 +-
|
||||
arch/powerpc/platforms/cell/celleb_scc_pciex.c | 2 +-
|
||||
arch/powerpc/platforms/cell/celleb_scc_sio.c | 2 +-
|
||||
arch/powerpc/platforms/cell/spider-pic.c | 7 ++-----
|
||||
arch/powerpc/platforms/cell/spu_manage.c | 3 +--
|
||||
arch/powerpc/platforms/fsl_uli1575.c | 2 +-
|
||||
arch/powerpc/platforms/pseries/event_sources.c | 3 +--
|
||||
arch/x86/kernel/devicetree.c | 2 +-
|
||||
drivers/of/irq.c | 2 +-
|
||||
drivers/pci/host/pci-mvebu.c | 2 +-
|
||||
include/linux/of_irq.h | 4 +---
|
||||
kernel/irq/irqdomain.c | 15 +++++++--------
|
||||
15 files changed, 22 insertions(+), 30 deletions(-)
|
||||
|
||||
--- a/arch/arm/mach-integrator/pci_v3.c
|
||||
+++ b/arch/arm/mach-integrator/pci_v3.c
|
||||
@@ -694,7 +694,7 @@ static int __init pci_v3_map_irq_dt(cons
|
||||
return 0;
|
||||
}
|
||||
|
||||
- return irq_create_of_mapping(oirq.np, oirq.args, oirq.args_count);
|
||||
+ return irq_create_of_mapping(&oirq);
|
||||
}
|
||||
|
||||
static int __init pci_v3_dtprobe(struct platform_device *pdev,
|
||||
--- a/arch/microblaze/pci/pci-common.c
|
||||
+++ b/arch/microblaze/pci/pci-common.c
|
||||
@@ -246,7 +246,7 @@ int pci_read_irq_line(struct pci_dev *pc
|
||||
oirq.args_count, oirq.args[0], oirq.args[1],
|
||||
of_node_full_name(oirq.np));
|
||||
|
||||
- virq = irq_create_of_mapping(oirq.np, oirq.args, oirq.args_count);
|
||||
+ virq = irq_create_of_mapping(&oirq);
|
||||
}
|
||||
if (!virq) {
|
||||
pr_debug(" Failed to map !\n");
|
||||
--- a/arch/mips/pci/fixup-lantiq.c
|
||||
+++ b/arch/mips/pci/fixup-lantiq.c
|
||||
@@ -33,7 +33,7 @@ int __init pcibios_map_irq(const struct
|
||||
slot, pin);
|
||||
return 0;
|
||||
}
|
||||
- irq = irq_create_of_mapping(dev_irq.np, dev_irq.args, dev_irq.args_count);
|
||||
+ irq = irq_create_of_mapping(&dev_irq);
|
||||
dev_info(&dev->dev, "SLOT:%d PIN:%d IRQ:%d\n", slot, pin, irq);
|
||||
return irq;
|
||||
}
|
||||
--- a/arch/powerpc/kernel/pci-common.c
|
||||
+++ b/arch/powerpc/kernel/pci-common.c
|
||||
@@ -266,7 +266,7 @@ static int pci_read_irq_line(struct pci_
|
||||
oirq.args_count, oirq.args[0], oirq.args[1],
|
||||
of_node_full_name(oirq.np));
|
||||
|
||||
- virq = irq_create_of_mapping(oirq.np, oirq.args, oirq.args_count);
|
||||
+ virq = irq_create_of_mapping(&oirq);
|
||||
}
|
||||
if(virq == NO_IRQ) {
|
||||
pr_debug(" Failed to map !\n");
|
||||
--- a/arch/powerpc/platforms/cell/celleb_scc_pciex.c
|
||||
+++ b/arch/powerpc/platforms/cell/celleb_scc_pciex.c
|
||||
@@ -511,7 +511,7 @@ static __init int celleb_setup_pciex(str
|
||||
pr_err("PCIEXC:Failed to map irq\n");
|
||||
goto error;
|
||||
}
|
||||
- virq = irq_create_of_mapping(oirq.np, oirq.args, oirq.args_count);
|
||||
+ virq = irq_create_of_mapping(&oirq);
|
||||
if (request_irq(virq, pciex_handle_internal_irq,
|
||||
0, "pciex", (void *)phb)) {
|
||||
pr_err("PCIEXC:Failed to request irq\n");
|
||||
--- a/arch/powerpc/platforms/cell/celleb_scc_sio.c
|
||||
+++ b/arch/powerpc/platforms/cell/celleb_scc_sio.c
|
||||
@@ -66,7 +66,7 @@ static int __init txx9_serial_init(void)
|
||||
#ifdef CONFIG_SERIAL_TXX9_CONSOLE
|
||||
req.membase = ioremap(req.mapbase, 0x24);
|
||||
#endif
|
||||
- req.irq = irq_create_of_mapping(irq.np, irq.args, irq.args_count);
|
||||
+ req.irq = irq_create_of_mapping(&irq);
|
||||
req.flags |= UPF_IOREMAP | UPF_BUGGY_UART
|
||||
/*HAVE_CTS_LINE*/;
|
||||
req.uartclk = 83300000;
|
||||
--- a/arch/powerpc/platforms/cell/spider-pic.c
|
||||
+++ b/arch/powerpc/platforms/cell/spider-pic.c
|
||||
@@ -236,11 +236,8 @@ static unsigned int __init spider_find_c
|
||||
* tree in case the device-tree is ever fixed
|
||||
*/
|
||||
struct of_phandle_args oirq;
|
||||
- if (of_irq_parse_one(pic->host->of_node, 0, &oirq) == 0) {
|
||||
- virq = irq_create_of_mapping(oirq.np, oirq.args,
|
||||
- oirq.args_count);
|
||||
- return virq;
|
||||
- }
|
||||
+ if (of_irq_parse_one(pic->host->of_node, 0, &oirq) == 0)
|
||||
+ return irq_create_of_mapping(&oirq);
|
||||
|
||||
/* Now do the horrible hacks */
|
||||
tmp = of_get_property(pic->host->of_node, "#interrupt-cells", NULL);
|
||||
--- a/arch/powerpc/platforms/cell/spu_manage.c
|
||||
+++ b/arch/powerpc/platforms/cell/spu_manage.c
|
||||
@@ -190,8 +190,7 @@ static int __init spu_map_interrupts(str
|
||||
ret = -EINVAL;
|
||||
pr_debug(" irq %d no 0x%x on %s\n", i, oirq.args[0],
|
||||
oirq.np->full_name);
|
||||
- spu->irqs[i] = irq_create_of_mapping(oirq.np,
|
||||
- oirq.args, oirq.args_count);
|
||||
+ spu->irqs[i] = irq_create_of_mapping(&oirq);
|
||||
if (spu->irqs[i] == NO_IRQ) {
|
||||
pr_debug("spu_new: failed to map it !\n");
|
||||
goto err;
|
||||
--- a/arch/powerpc/platforms/fsl_uli1575.c
|
||||
+++ b/arch/powerpc/platforms/fsl_uli1575.c
|
||||
@@ -334,7 +334,7 @@ static void hpcd_final_uli5288(struct pc
|
||||
laddr[0] = (hose->first_busno << 16) | (PCI_DEVFN(31, 0) << 8);
|
||||
laddr[1] = laddr[2] = 0;
|
||||
of_irq_parse_raw(hosenode, &pin, 1, laddr, &oirq);
|
||||
- dev->irq = irq_create_of_mapping(oirq.np, oirq.args, oirq.args_count);
|
||||
+ dev->irq = irq_create_of_mapping(&oirq);
|
||||
}
|
||||
|
||||
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AL, 0x1575, hpcd_quirk_uli1575);
|
||||
--- a/arch/powerpc/platforms/pseries/event_sources.c
|
||||
+++ b/arch/powerpc/platforms/pseries/event_sources.c
|
||||
@@ -59,8 +59,7 @@ void request_event_sources_irqs(struct d
|
||||
index++) {
|
||||
if (count > 15)
|
||||
break;
|
||||
- virqs[count] = irq_create_of_mapping(oirq.np, oirq.args,
|
||||
- oirq.args_count);
|
||||
+ virqs[count] = irq_create_of_mapping(&oirq);
|
||||
if (virqs[count] == NO_IRQ) {
|
||||
pr_err("event-sources: Unable to allocate "
|
||||
"interrupt number for %s\n",
|
||||
--- a/arch/x86/kernel/devicetree.c
|
||||
+++ b/arch/x86/kernel/devicetree.c
|
||||
@@ -121,7 +121,7 @@ static int x86_of_pci_irq_enable(struct
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
- virq = irq_create_of_mapping(oirq.np, oirq.args, oirq.args_count);
|
||||
+ virq = irq_create_of_mapping(&oirq);
|
||||
if (virq == 0)
|
||||
return -EINVAL;
|
||||
dev->irq = virq;
|
||||
--- a/drivers/of/irq.c
|
||||
+++ b/drivers/of/irq.c
|
||||
@@ -41,7 +41,7 @@ unsigned int irq_of_parse_and_map(struct
|
||||
if (of_irq_parse_one(dev, index, &oirq))
|
||||
return 0;
|
||||
|
||||
- return irq_create_of_mapping(oirq.np, oirq.args, oirq.args_count);
|
||||
+ return irq_create_of_mapping(&oirq);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(irq_of_parse_and_map);
|
||||
|
||||
--- a/drivers/pci/host/pci-mvebu.c
|
||||
+++ b/drivers/pci/host/pci-mvebu.c
|
||||
@@ -656,7 +656,7 @@ static int __init mvebu_pcie_map_irq(con
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
- return irq_create_of_mapping(oirq.np, oirq.args, oirq.args_count);
|
||||
+ return irq_create_of_mapping(&oirq);
|
||||
}
|
||||
|
||||
static struct pci_bus *mvebu_pcie_scan_bus(int nr, struct pci_sys_data *sys)
|
||||
--- a/include/linux/of_irq.h
|
||||
+++ b/include/linux/of_irq.h
|
||||
@@ -37,9 +37,7 @@ extern int of_irq_parse_raw(struct devic
|
||||
struct of_phandle_args *out_irq);
|
||||
extern int of_irq_parse_one(struct device_node *device, int index,
|
||||
struct of_phandle_args *out_irq);
|
||||
-extern unsigned int irq_create_of_mapping(struct device_node *controller,
|
||||
- const u32 *intspec,
|
||||
- unsigned int intsize);
|
||||
+extern unsigned int irq_create_of_mapping(struct of_phandle_args *irq_data);
|
||||
extern int of_irq_to_resource(struct device_node *dev, int index,
|
||||
struct resource *r);
|
||||
extern int of_irq_count(struct device_node *dev);
|
||||
--- a/kernel/irq/irqdomain.c
|
||||
+++ b/kernel/irq/irqdomain.c
|
||||
@@ -655,15 +655,14 @@ int irq_create_strict_mappings(struct ir
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(irq_create_strict_mappings);
|
||||
|
||||
-unsigned int irq_create_of_mapping(struct device_node *controller,
|
||||
- const u32 *intspec, unsigned int intsize)
|
||||
+unsigned int irq_create_of_mapping(struct of_phandle_args *irq_data)
|
||||
{
|
||||
struct irq_domain *domain;
|
||||
irq_hw_number_t hwirq;
|
||||
unsigned int type = IRQ_TYPE_NONE;
|
||||
unsigned int virq;
|
||||
|
||||
- domain = controller ? irq_find_host(controller) : irq_default_domain;
|
||||
+ domain = irq_data->np ? irq_find_host(irq_data->np) : irq_default_domain;
|
||||
if (!domain) {
|
||||
#ifdef CONFIG_MIPS
|
||||
/*
|
||||
@@ -677,17 +676,17 @@ unsigned int irq_create_of_mapping(struc
|
||||
if (intsize > 0)
|
||||
return intspec[0];
|
||||
#endif
|
||||
- pr_warning("no irq domain found for %s !\n",
|
||||
- of_node_full_name(controller));
|
||||
+ pr_warn("no irq domain found for %s !\n",
|
||||
+ of_node_full_name(irq_data->np));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If domain has no translation, then we assume interrupt line */
|
||||
if (domain->ops->xlate == NULL)
|
||||
- hwirq = intspec[0];
|
||||
+ hwirq = irq_data->args[0];
|
||||
else {
|
||||
- if (domain->ops->xlate(domain, controller, intspec, intsize,
|
||||
- &hwirq, &type))
|
||||
+ if (domain->ops->xlate(domain, irq_data->np, irq_data->args,
|
||||
+ irq_data->args_count, &hwirq, &type))
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,287 @@
|
|||
From 44ad702902e9e274f57edce8944e46540b978f9a Mon Sep 17 00:00:00 2001
|
||||
From: Grant Likely <grant.likely@linaro.org>
|
||||
Date: Thu, 19 Dec 2013 09:30:57 -0300
|
||||
Subject: [PATCH 186/203] of/irq: Refactor interrupt-map parsing
|
||||
|
||||
All the users of of_irq_parse_raw pass in a raw interrupt specifier from
|
||||
the device tree and expect it to be returned (possibly modified) in an
|
||||
of_phandle_args structure. However, the primary function of
|
||||
of_irq_parse_raw() is to check for translations due to the presence of
|
||||
one or more interrupt-map properties. The actual placing of the data
|
||||
into an of_phandle_args structure is trivial. If it is refactored to
|
||||
accept an of_phandle_args structure directly, then it becomes possible
|
||||
to consume of_phandle_args from other sources. This is important for an
|
||||
upcoming patch that allows a device to be connected to more than one
|
||||
interrupt parent. It also simplifies the code a bit.
|
||||
|
||||
The biggest complication with this patch is that the old version works
|
||||
on the interrupt specifiers in __be32 form, but the of_phandle_args
|
||||
structure is intended to carry it in the cpu-native version. A bit of
|
||||
churn was required to make this work. In the end it results in tighter
|
||||
code, so the churn is worth it.
|
||||
|
||||
Signed-off-by: Grant Likely <grant.likely@linaro.org>
|
||||
Acked-by: Tony Lindgren <tony@atomide.com>
|
||||
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
|
||||
---
|
||||
arch/powerpc/platforms/fsl_uli1575.c | 6 +-
|
||||
drivers/of/irq.c | 108 ++++++++++++++++++-----------------
|
||||
drivers/of/of_pci_irq.c | 7 ++-
|
||||
include/linux/of_irq.h | 5 +-
|
||||
4 files changed, 67 insertions(+), 59 deletions(-)
|
||||
|
||||
--- a/arch/powerpc/platforms/fsl_uli1575.c
|
||||
+++ b/arch/powerpc/platforms/fsl_uli1575.c
|
||||
@@ -322,7 +322,6 @@ static void hpcd_final_uli5288(struct pc
|
||||
struct pci_controller *hose = pci_bus_to_host(dev->bus);
|
||||
struct device_node *hosenode = hose ? hose->dn : NULL;
|
||||
struct of_phandle_args oirq;
|
||||
- int pin = 2;
|
||||
u32 laddr[3];
|
||||
|
||||
if (!machine_is(mpc86xx_hpcd))
|
||||
@@ -331,9 +330,12 @@ static void hpcd_final_uli5288(struct pc
|
||||
if (!hosenode)
|
||||
return;
|
||||
|
||||
+ oirq.np = hosenode;
|
||||
+ oirq.args[0] = 2;
|
||||
+ oirq.args_count = 1;
|
||||
laddr[0] = (hose->first_busno << 16) | (PCI_DEVFN(31, 0) << 8);
|
||||
laddr[1] = laddr[2] = 0;
|
||||
- of_irq_parse_raw(hosenode, &pin, 1, laddr, &oirq);
|
||||
+ of_irq_parse_raw(laddr, &oirq);
|
||||
dev->irq = irq_create_of_mapping(&oirq);
|
||||
}
|
||||
|
||||
--- a/drivers/of/irq.c
|
||||
+++ b/drivers/of/irq.c
|
||||
@@ -80,31 +80,32 @@ struct device_node *of_irq_find_parent(s
|
||||
/**
|
||||
* of_irq_parse_raw - Low level interrupt tree parsing
|
||||
* @parent: the device interrupt parent
|
||||
- * @intspec: interrupt specifier ("interrupts" property of the device)
|
||||
- * @ointsize: size of the passed in interrupt specifier
|
||||
- * @addr: address specifier (start of "reg" property of the device)
|
||||
- * @out_irq: structure of_irq filled by this function
|
||||
+ * @addr: address specifier (start of "reg" property of the device) in be32 format
|
||||
+ * @out_irq: structure of_irq updated by this function
|
||||
*
|
||||
* Returns 0 on success and a negative number on error
|
||||
*
|
||||
* This function is a low-level interrupt tree walking function. It
|
||||
* can be used to do a partial walk with synthetized reg and interrupts
|
||||
* properties, for example when resolving PCI interrupts when no device
|
||||
- * node exist for the parent.
|
||||
+ * node exist for the parent. It takes an interrupt specifier structure as
|
||||
+ * input, walks the tree looking for any interrupt-map properties, translates
|
||||
+ * the specifier for each map, and then returns the translated map.
|
||||
*/
|
||||
-int of_irq_parse_raw(struct device_node *parent, const __be32 *intspec,
|
||||
- u32 ointsize, const __be32 *addr, struct of_phandle_args *out_irq)
|
||||
+int of_irq_parse_raw(const __be32 *addr, struct of_phandle_args *out_irq)
|
||||
{
|
||||
struct device_node *ipar, *tnode, *old = NULL, *newpar = NULL;
|
||||
- const __be32 *tmp, *imap, *imask;
|
||||
+ __be32 initial_match_array[8];
|
||||
+ const __be32 *match_array = initial_match_array;
|
||||
+ const __be32 *tmp, *imap, *imask, dummy_imask[] = { ~0, ~0, ~0, ~0, ~0 };
|
||||
u32 intsize = 1, addrsize, newintsize = 0, newaddrsize = 0;
|
||||
int imaplen, match, i;
|
||||
|
||||
pr_debug("of_irq_parse_raw: par=%s,intspec=[0x%08x 0x%08x...],ointsize=%d\n",
|
||||
- of_node_full_name(parent), be32_to_cpup(intspec),
|
||||
- be32_to_cpup(intspec + 1), ointsize);
|
||||
+ of_node_full_name(out_irq->np), out_irq->args[0], out_irq->args[1],
|
||||
+ out_irq->args_count);
|
||||
|
||||
- ipar = of_node_get(parent);
|
||||
+ ipar = of_node_get(out_irq->np);
|
||||
|
||||
/* First get the #interrupt-cells property of the current cursor
|
||||
* that tells us how to interpret the passed-in intspec. If there
|
||||
@@ -127,7 +128,7 @@ int of_irq_parse_raw(struct device_node
|
||||
|
||||
pr_debug("of_irq_parse_raw: ipar=%s, size=%d\n", of_node_full_name(ipar), intsize);
|
||||
|
||||
- if (ointsize != intsize)
|
||||
+ if (out_irq->args_count != intsize)
|
||||
return -EINVAL;
|
||||
|
||||
/* Look for this #address-cells. We have to implement the old linux
|
||||
@@ -146,6 +147,21 @@ int of_irq_parse_raw(struct device_node
|
||||
|
||||
pr_debug(" -> addrsize=%d\n", addrsize);
|
||||
|
||||
+ /* If we were passed no "reg" property and we attempt to parse
|
||||
+ * an interrupt-map, then #address-cells must be 0.
|
||||
+ * Fail if it's not.
|
||||
+ */
|
||||
+ if (addr == NULL && addrsize != 0) {
|
||||
+ pr_debug(" -> no reg passed in when needed !\n");
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ /* Precalculate the match array - this simplifies match loop */
|
||||
+ for (i = 0; i < addrsize; i++)
|
||||
+ initial_match_array[i] = addr[i];
|
||||
+ for (i = 0; i < intsize; i++)
|
||||
+ initial_match_array[addrsize + i] = cpu_to_be32(out_irq->args[i]);
|
||||
+
|
||||
/* Now start the actual "proper" walk of the interrupt tree */
|
||||
while (ipar != NULL) {
|
||||
/* Now check if cursor is an interrupt-controller and if it is
|
||||
@@ -154,11 +170,6 @@ int of_irq_parse_raw(struct device_node
|
||||
if (of_get_property(ipar, "interrupt-controller", NULL) !=
|
||||
NULL) {
|
||||
pr_debug(" -> got it !\n");
|
||||
- for (i = 0; i < intsize; i++)
|
||||
- out_irq->args[i] =
|
||||
- of_read_number(intspec +i, 1);
|
||||
- out_irq->args_count = intsize;
|
||||
- out_irq->np = ipar;
|
||||
of_node_put(old);
|
||||
return 0;
|
||||
}
|
||||
@@ -175,34 +186,16 @@ int of_irq_parse_raw(struct device_node
|
||||
|
||||
/* Look for a mask */
|
||||
imask = of_get_property(ipar, "interrupt-map-mask", NULL);
|
||||
-
|
||||
- /* If we were passed no "reg" property and we attempt to parse
|
||||
- * an interrupt-map, then #address-cells must be 0.
|
||||
- * Fail if it's not.
|
||||
- */
|
||||
- if (addr == NULL && addrsize != 0) {
|
||||
- pr_debug(" -> no reg passed in when needed !\n");
|
||||
- goto fail;
|
||||
- }
|
||||
+ if (!imask)
|
||||
+ imask = dummy_imask;
|
||||
|
||||
/* Parse interrupt-map */
|
||||
match = 0;
|
||||
while (imaplen > (addrsize + intsize + 1) && !match) {
|
||||
/* Compare specifiers */
|
||||
match = 1;
|
||||
- for (i = 0; i < addrsize && match; ++i) {
|
||||
- __be32 mask = imask ? imask[i]
|
||||
- : cpu_to_be32(0xffffffffu);
|
||||
- match = ((addr[i] ^ imap[i]) & mask) == 0;
|
||||
- }
|
||||
- for (; i < (addrsize + intsize) && match; ++i) {
|
||||
- __be32 mask = imask ? imask[i]
|
||||
- : cpu_to_be32(0xffffffffu);
|
||||
- match =
|
||||
- ((intspec[i-addrsize] ^ imap[i]) & mask) == 0;
|
||||
- }
|
||||
- imap += addrsize + intsize;
|
||||
- imaplen -= addrsize + intsize;
|
||||
+ for (i = 0; i < (addrsize + intsize); i++, imaplen--)
|
||||
+ match = !((match_array[i] ^ *imap++) & imask[i]);
|
||||
|
||||
pr_debug(" -> match=%d (imaplen=%d)\n", match, imaplen);
|
||||
|
||||
@@ -247,12 +240,18 @@ int of_irq_parse_raw(struct device_node
|
||||
if (!match)
|
||||
goto fail;
|
||||
|
||||
- of_node_put(old);
|
||||
- old = of_node_get(newpar);
|
||||
+ /*
|
||||
+ * Successfully parsed an interrrupt-map translation; copy new
|
||||
+ * interrupt specifier into the out_irq structure
|
||||
+ */
|
||||
+ of_node_put(out_irq->np);
|
||||
+ out_irq->np = of_node_get(newpar);
|
||||
+
|
||||
+ match_array = imap - newaddrsize - newintsize;
|
||||
+ for (i = 0; i < newintsize; i++)
|
||||
+ out_irq->args[i] = be32_to_cpup(imap - newintsize + i);
|
||||
+ out_irq->args_count = intsize = newintsize;
|
||||
addrsize = newaddrsize;
|
||||
- intsize = newintsize;
|
||||
- intspec = imap - intsize;
|
||||
- addr = intspec - addrsize;
|
||||
|
||||
skiplevel:
|
||||
/* Iterate again with new parent */
|
||||
@@ -263,7 +262,7 @@ int of_irq_parse_raw(struct device_node
|
||||
}
|
||||
fail:
|
||||
of_node_put(ipar);
|
||||
- of_node_put(old);
|
||||
+ of_node_put(out_irq->np);
|
||||
of_node_put(newpar);
|
||||
|
||||
return -EINVAL;
|
||||
@@ -276,15 +275,16 @@ EXPORT_SYMBOL_GPL(of_irq_parse_raw);
|
||||
* @index: index of the interrupt to resolve
|
||||
* @out_irq: structure of_irq filled by this function
|
||||
*
|
||||
- * This function resolves an interrupt, walking the tree, for a given
|
||||
- * device-tree node. It's the high level pendant to of_irq_parse_raw().
|
||||
+ * This function resolves an interrupt for a node by walking the interrupt tree,
|
||||
+ * finding which interrupt controller node it is attached to, and returning the
|
||||
+ * interrupt specifier that can be used to retrieve a Linux IRQ number.
|
||||
*/
|
||||
int of_irq_parse_one(struct device_node *device, int index, struct of_phandle_args *out_irq)
|
||||
{
|
||||
struct device_node *p;
|
||||
const __be32 *intspec, *tmp, *addr;
|
||||
u32 intsize, intlen;
|
||||
- int res = -EINVAL;
|
||||
+ int i, res = -EINVAL;
|
||||
|
||||
pr_debug("of_irq_parse_one: dev=%s, index=%d\n", of_node_full_name(device), index);
|
||||
|
||||
@@ -326,9 +326,15 @@ int of_irq_parse_one(struct device_node
|
||||
if ((index + 1) * intsize > intlen)
|
||||
goto out;
|
||||
|
||||
- /* Get new specifier and map it */
|
||||
- res = of_irq_parse_raw(p, intspec + index * intsize, intsize,
|
||||
- addr, out_irq);
|
||||
+ /* Copy intspec into irq structure */
|
||||
+ intspec += index * intsize;
|
||||
+ out_irq->np = p;
|
||||
+ out_irq->args_count = intsize;
|
||||
+ for (i = 0; i < intsize; i++)
|
||||
+ out_irq->args[i] = be32_to_cpup(intspec++);
|
||||
+
|
||||
+ /* Check if there are any interrupt-map translations to process */
|
||||
+ res = of_irq_parse_raw(addr, out_irq);
|
||||
out:
|
||||
of_node_put(p);
|
||||
return res;
|
||||
--- a/drivers/of/of_pci_irq.c
|
||||
+++ b/drivers/of/of_pci_irq.c
|
||||
@@ -85,9 +85,12 @@ int of_irq_parse_pci(const struct pci_de
|
||||
pdev = ppdev;
|
||||
}
|
||||
|
||||
+ out_irq->np = ppnode;
|
||||
+ out_irq->args_count = 1;
|
||||
+ out_irq->args[0] = lspec;
|
||||
lspec_be = cpu_to_be32(lspec);
|
||||
laddr[0] = cpu_to_be32((pdev->bus->number << 16) | (pdev->devfn << 8));
|
||||
- laddr[1] = laddr[2] = cpu_to_be32(0);
|
||||
- return of_irq_parse_raw(ppnode, &lspec_be, 1, laddr, out_irq);
|
||||
+ laddr[1] = laddr[2] = cpu_to_be32(0);
|
||||
+ return of_irq_parse_raw(laddr, out_irq);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_irq_parse_pci);
|
||||
--- a/include/linux/of_irq.h
|
||||
+++ b/include/linux/of_irq.h
|
||||
@@ -31,10 +31,7 @@ static inline int of_irq_parse_oldworld(
|
||||
}
|
||||
#endif /* CONFIG_PPC32 && CONFIG_PPC_PMAC */
|
||||
|
||||
-
|
||||
-extern int of_irq_parse_raw(struct device_node *parent, const __be32 *intspec,
|
||||
- u32 ointsize, const __be32 *addr,
|
||||
- struct of_phandle_args *out_irq);
|
||||
+extern int of_irq_parse_raw(const __be32 *addr, struct of_phandle_args *out_irq);
|
||||
extern int of_irq_parse_one(struct device_node *device, int index,
|
||||
struct of_phandle_args *out_irq);
|
||||
extern unsigned int irq_create_of_mapping(struct of_phandle_args *irq_data);
|
|
@ -0,0 +1,62 @@
|
|||
From 061855025b6842debdf6ea2e8bfd86f50700e263 Mon Sep 17 00:00:00 2001
|
||||
From: Grant Likely <grant.likely@linaro.org>
|
||||
Date: Thu, 19 Dec 2013 09:30:58 -0300
|
||||
Subject: [PATCH 187/203] of: Add helper for printing an of_phandle_args
|
||||
structure
|
||||
|
||||
It is sometimes useful for debug to get the contents of an
|
||||
of_phandle_args structure out into the kernel log.
|
||||
|
||||
Signed-off-by: Grant Likely <grant.likely@linaro.org>
|
||||
|
||||
Conflicts:
|
||||
drivers/of/base.c
|
||||
---
|
||||
drivers/of/base.c | 9 +++++++++
|
||||
drivers/of/irq.c | 6 +++---
|
||||
include/linux/of.h | 1 +
|
||||
3 files changed, 13 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/drivers/of/base.c
|
||||
+++ b/drivers/of/base.c
|
||||
@@ -1136,6 +1136,15 @@ EXPORT_SYMBOL(of_parse_phandle);
|
||||
* To get a device_node of the `node2' node you may call this:
|
||||
* of_parse_phandle_with_args(node3, "list", "#list-cells", 1, &args);
|
||||
*/
|
||||
+void of_print_phandle_args(const char *msg, const struct of_phandle_args *args)
|
||||
+{
|
||||
+ int i;
|
||||
+ printk("%s %s", msg, of_node_full_name(args->np));
|
||||
+ for (i = 0; i < args->args_count; i++)
|
||||
+ printk(i ? ",%08x" : ":%08x", args->args[i]);
|
||||
+ printk("\n");
|
||||
+}
|
||||
+
|
||||
static int __of_parse_phandle_with_args(const struct device_node *np,
|
||||
const char *list_name,
|
||||
const char *cells_name, int index,
|
||||
--- a/drivers/of/irq.c
|
||||
+++ b/drivers/of/irq.c
|
||||
@@ -101,9 +101,9 @@ int of_irq_parse_raw(const __be32 *addr,
|
||||
u32 intsize = 1, addrsize, newintsize = 0, newaddrsize = 0;
|
||||
int imaplen, match, i;
|
||||
|
||||
- pr_debug("of_irq_parse_raw: par=%s,intspec=[0x%08x 0x%08x...],ointsize=%d\n",
|
||||
- of_node_full_name(out_irq->np), out_irq->args[0], out_irq->args[1],
|
||||
- out_irq->args_count);
|
||||
+#ifdef DEBUG
|
||||
+ of_print_phandle_args("of_irq_parse_raw: ", out_irq);
|
||||
+#endif
|
||||
|
||||
ipar = of_node_get(out_irq->np);
|
||||
|
||||
--- a/include/linux/of.h
|
||||
+++ b/include/linux/of.h
|
||||
@@ -274,6 +274,7 @@ extern int of_n_size_cells(struct device
|
||||
extern const struct of_device_id *of_match_node(
|
||||
const struct of_device_id *matches, const struct device_node *node);
|
||||
extern int of_modalias_node(struct device_node *node, char *modalias, int len);
|
||||
+extern void of_print_phandle_args(const char *msg, const struct of_phandle_args *args);
|
||||
extern struct device_node *of_parse_phandle(const struct device_node *np,
|
||||
const char *phandle_name,
|
||||
int index);
|
|
@ -0,0 +1,36 @@
|
|||
From 3665853921092bb68aa0929efb3a94ecdfc96782 Mon Sep 17 00:00:00 2001
|
||||
From: Thierry Reding <thierry.reding@gmail.com>
|
||||
Date: Thu, 19 Dec 2013 09:30:59 -0300
|
||||
Subject: [PATCH 188/203] of/irq: Rework of_irq_count()
|
||||
|
||||
The of_irq_to_resource() helper that is used to implement of_irq_count()
|
||||
tries to resolve interrupts and in fact creates a mapping for resolved
|
||||
interrupts. That's pretty heavy lifting for something that claims to
|
||||
just return the number of interrupts requested by a given device node.
|
||||
|
||||
Instead, use the more lightweight of_irq_map_one(), which, despite the
|
||||
name, doesn't create an actual mapping. Perhaps a better name would be
|
||||
of_irq_translate_one().
|
||||
|
||||
Signed-off-by: Thierry Reding <treding@nvidia.com>
|
||||
Acked-by: Rob Herring <rob.herring@calxeda.com>
|
||||
[grant.likely: fixup s/of_irq_map_one/of_irq_parse_one/]
|
||||
Signed-off-by: Grant Likely <grant.likely@linaro.org>
|
||||
---
|
||||
drivers/of/irq.c | 3 ++-
|
||||
1 file changed, 2 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/of/irq.c
|
||||
+++ b/drivers/of/irq.c
|
||||
@@ -379,9 +379,10 @@ EXPORT_SYMBOL_GPL(of_irq_to_resource);
|
||||
*/
|
||||
int of_irq_count(struct device_node *dev)
|
||||
{
|
||||
+ struct of_phandle_args irq;
|
||||
int nr = 0;
|
||||
|
||||
- while (of_irq_to_resource(dev, nr, NULL))
|
||||
+ while (of_irq_parse_one(dev, nr, &irq) == 0)
|
||||
nr++;
|
||||
|
||||
return nr;
|
|
@ -0,0 +1,192 @@
|
|||
From efd4032754a57bc258eafe30fde684ec47dc36e1 Mon Sep 17 00:00:00 2001
|
||||
From: Grant Likely <grant.likely@linaro.org>
|
||||
Date: Thu, 19 Dec 2013 09:31:00 -0300
|
||||
Subject: [PATCH 189/203] of/irq: create interrupts-extended property
|
||||
|
||||
The standard interrupts property in device tree can only handle
|
||||
interrupts coming from a single interrupt parent. If a device is wired
|
||||
to multiple interrupt controllers, then it needs to be attached to a
|
||||
node with an interrupt-map property to demux the interrupt specifiers
|
||||
which is confusing. It would be a lot easier if there was a form of the
|
||||
interrupts property that allows for a separate interrupt phandle for
|
||||
each interrupt specifier.
|
||||
|
||||
This patch does exactly that by creating a new interrupts-extended
|
||||
property which reuses the phandle+arguments pattern used by GPIOs and
|
||||
other core bindings.
|
||||
|
||||
Signed-off-by: Grant Likely <grant.likely@linaro.org>
|
||||
Acked-by: Tony Lindgren <tony@atomide.com>
|
||||
Acked-by: Kumar Gala <galak@codeaurora.org>
|
||||
[grant.likely: removed versatile platform hunks into separate patch]
|
||||
Cc: Rob Herring <rob.herring@calxeda.com>
|
||||
|
||||
Conflicts:
|
||||
arch/arm/boot/dts/testcases/tests-interrupts.dtsi
|
||||
drivers/of/selftest.c
|
||||
---
|
||||
drivers/of/selftest.c | 146 +++++++++++++++++++++++++++++++++++++++++++++++++-
|
||||
1 file changed, 145 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/of/selftest.c
|
||||
+++ b/drivers/of/selftest.c
|
||||
@@ -154,6 +154,147 @@ static void __init of_selftest_property_
|
||||
selftest(rc == -EILSEQ, "unterminated string; rc=%i", rc);
|
||||
}
|
||||
|
||||
+static void __init of_selftest_parse_interrupts(void)
|
||||
+{
|
||||
+ struct device_node *np;
|
||||
+ struct of_phandle_args args;
|
||||
+ int i, rc;
|
||||
+
|
||||
+ np = of_find_node_by_path("/testcase-data/interrupts/interrupts0");
|
||||
+ if (!np) {
|
||||
+ pr_err("missing testcase data\n");
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ for (i = 0; i < 4; i++) {
|
||||
+ bool passed = true;
|
||||
+ args.args_count = 0;
|
||||
+ rc = of_irq_parse_one(np, i, &args);
|
||||
+
|
||||
+ passed &= !rc;
|
||||
+ passed &= (args.args_count == 1);
|
||||
+ passed &= (args.args[0] == (i + 1));
|
||||
+
|
||||
+ selftest(passed, "index %i - data error on node %s rc=%i\n",
|
||||
+ i, args.np->full_name, rc);
|
||||
+ }
|
||||
+ of_node_put(np);
|
||||
+
|
||||
+ np = of_find_node_by_path("/testcase-data/interrupts/interrupts1");
|
||||
+ if (!np) {
|
||||
+ pr_err("missing testcase data\n");
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ for (i = 0; i < 4; i++) {
|
||||
+ bool passed = true;
|
||||
+ args.args_count = 0;
|
||||
+ rc = of_irq_parse_one(np, i, &args);
|
||||
+
|
||||
+ /* Test the values from tests-phandle.dtsi */
|
||||
+ switch (i) {
|
||||
+ case 0:
|
||||
+ passed &= !rc;
|
||||
+ passed &= (args.args_count == 1);
|
||||
+ passed &= (args.args[0] == 9);
|
||||
+ break;
|
||||
+ case 1:
|
||||
+ passed &= !rc;
|
||||
+ passed &= (args.args_count == 3);
|
||||
+ passed &= (args.args[0] == 10);
|
||||
+ passed &= (args.args[1] == 11);
|
||||
+ passed &= (args.args[2] == 12);
|
||||
+ break;
|
||||
+ case 2:
|
||||
+ passed &= !rc;
|
||||
+ passed &= (args.args_count == 2);
|
||||
+ passed &= (args.args[0] == 13);
|
||||
+ passed &= (args.args[1] == 14);
|
||||
+ break;
|
||||
+ case 3:
|
||||
+ passed &= !rc;
|
||||
+ passed &= (args.args_count == 2);
|
||||
+ passed &= (args.args[0] == 15);
|
||||
+ passed &= (args.args[1] == 16);
|
||||
+ break;
|
||||
+ default:
|
||||
+ passed = false;
|
||||
+ }
|
||||
+ selftest(passed, "index %i - data error on node %s rc=%i\n",
|
||||
+ i, args.np->full_name, rc);
|
||||
+ }
|
||||
+ of_node_put(np);
|
||||
+}
|
||||
+
|
||||
+static void __init of_selftest_parse_interrupts_extended(void)
|
||||
+{
|
||||
+ struct device_node *np;
|
||||
+ struct of_phandle_args args;
|
||||
+ int i, rc;
|
||||
+
|
||||
+ np = of_find_node_by_path("/testcase-data/interrupts/interrupts-extended0");
|
||||
+ if (!np) {
|
||||
+ pr_err("missing testcase data\n");
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ for (i = 0; i < 7; i++) {
|
||||
+ bool passed = true;
|
||||
+ rc = of_irq_parse_one(np, i, &args);
|
||||
+
|
||||
+ /* Test the values from tests-phandle.dtsi */
|
||||
+ switch (i) {
|
||||
+ case 0:
|
||||
+ passed &= !rc;
|
||||
+ passed &= (args.args_count == 1);
|
||||
+ passed &= (args.args[0] == 1);
|
||||
+ break;
|
||||
+ case 1:
|
||||
+ passed &= !rc;
|
||||
+ passed &= (args.args_count == 3);
|
||||
+ passed &= (args.args[0] == 2);
|
||||
+ passed &= (args.args[1] == 3);
|
||||
+ passed &= (args.args[2] == 4);
|
||||
+ break;
|
||||
+ case 2:
|
||||
+ passed &= !rc;
|
||||
+ passed &= (args.args_count == 2);
|
||||
+ passed &= (args.args[0] == 5);
|
||||
+ passed &= (args.args[1] == 6);
|
||||
+ break;
|
||||
+ case 3:
|
||||
+ passed &= !rc;
|
||||
+ passed &= (args.args_count == 1);
|
||||
+ passed &= (args.args[0] == 9);
|
||||
+ break;
|
||||
+ case 4:
|
||||
+ passed &= !rc;
|
||||
+ passed &= (args.args_count == 3);
|
||||
+ passed &= (args.args[0] == 10);
|
||||
+ passed &= (args.args[1] == 11);
|
||||
+ passed &= (args.args[2] == 12);
|
||||
+ break;
|
||||
+ case 5:
|
||||
+ passed &= !rc;
|
||||
+ passed &= (args.args_count == 2);
|
||||
+ passed &= (args.args[0] == 13);
|
||||
+ passed &= (args.args[1] == 14);
|
||||
+ break;
|
||||
+ case 6:
|
||||
+ passed &= !rc;
|
||||
+ passed &= (args.args_count == 1);
|
||||
+ passed &= (args.args[0] == 15);
|
||||
+ break;
|
||||
+ default:
|
||||
+ passed = false;
|
||||
+ }
|
||||
+
|
||||
+ selftest(passed, "index %i - data error on node %s rc=%i\n",
|
||||
+ i, args.np->full_name, rc);
|
||||
+ }
|
||||
+ of_node_put(np);
|
||||
+}
|
||||
+
|
||||
static int __init of_selftest(void)
|
||||
{
|
||||
struct device_node *np;
|
||||
@@ -168,7 +309,10 @@ static int __init of_selftest(void)
|
||||
pr_info("start of selftest - you will see error messages\n");
|
||||
of_selftest_parse_phandle_with_args();
|
||||
of_selftest_property_match_string();
|
||||
- pr_info("end of selftest - %s\n", selftest_passed ? "PASS" : "FAIL");
|
||||
+ of_selftest_parse_interrupts();
|
||||
+ of_selftest_parse_interrupts_extended();
|
||||
+ pr_info("end of selftest - %i passed, %i failed\n",
|
||||
+ selftest_results.passed, selftest_results.failed);
|
||||
return 0;
|
||||
}
|
||||
late_initcall(of_selftest);
|
|
@ -0,0 +1,60 @@
|
|||
From 1c67d6e7cc30a856e79664e0be3a1f705bad56e4 Mon Sep 17 00:00:00 2001
|
||||
From: Grant Likely <grant.likely@linaro.org>
|
||||
Date: Thu, 19 Dec 2013 09:31:01 -0300
|
||||
Subject: [PATCH 190/203] of/irq: Fix bug in interrupt parsing refactor.
|
||||
|
||||
Commit 2361613206e6, "of/irq: Refactor interrupt-map parsing" introduced
|
||||
a bug. The irq parsing will fail for some nodes that don't have a reg
|
||||
property. It is fixed by deferring the check for reg until it is
|
||||
actually needed. Also adjust the testcase data to catch the bug.
|
||||
|
||||
Signed-off-by: Grant Likely <grant.likely@linaro.org>
|
||||
Tested-by: Stephen Warren <swarren@nvidia.com>
|
||||
Tested-by: Ming Lei <tom.leiming@gmail.com>
|
||||
Tested-by: Stephen Warren <swarren@nvidia.com>
|
||||
Cc: Rob Herring <rob.herring@calxeda.com>
|
||||
|
||||
Conflicts:
|
||||
arch/arm/boot/dts/testcases/tests-interrupts.dtsi
|
||||
---
|
||||
drivers/of/irq.c | 20 ++++++++++----------
|
||||
1 file changed, 10 insertions(+), 10 deletions(-)
|
||||
|
||||
--- a/drivers/of/irq.c
|
||||
+++ b/drivers/of/irq.c
|
||||
@@ -147,18 +147,9 @@ int of_irq_parse_raw(const __be32 *addr,
|
||||
|
||||
pr_debug(" -> addrsize=%d\n", addrsize);
|
||||
|
||||
- /* If we were passed no "reg" property and we attempt to parse
|
||||
- * an interrupt-map, then #address-cells must be 0.
|
||||
- * Fail if it's not.
|
||||
- */
|
||||
- if (addr == NULL && addrsize != 0) {
|
||||
- pr_debug(" -> no reg passed in when needed !\n");
|
||||
- return -EINVAL;
|
||||
- }
|
||||
-
|
||||
/* Precalculate the match array - this simplifies match loop */
|
||||
for (i = 0; i < addrsize; i++)
|
||||
- initial_match_array[i] = addr[i];
|
||||
+ initial_match_array[i] = addr ? addr[i] : 0;
|
||||
for (i = 0; i < intsize; i++)
|
||||
initial_match_array[addrsize + i] = cpu_to_be32(out_irq->args[i]);
|
||||
|
||||
@@ -174,6 +165,15 @@ int of_irq_parse_raw(const __be32 *addr,
|
||||
return 0;
|
||||
}
|
||||
|
||||
+ /*
|
||||
+ * interrupt-map parsing does not work without a reg
|
||||
+ * property when #address-cells != 0
|
||||
+ */
|
||||
+ if (addrsize && !addr) {
|
||||
+ pr_debug(" -> no reg passed in when needed !\n");
|
||||
+ goto fail;
|
||||
+ }
|
||||
+
|
||||
/* Now look for an interrupt-map */
|
||||
imap = of_get_property(ipar, "interrupt-map", &imaplen);
|
||||
/* No interrupt map, check for an interrupt parent */
|
|
@ -0,0 +1,52 @@
|
|||
From 5a1bd82f089e19ba049a871a0d5538ed9eb5e5cd Mon Sep 17 00:00:00 2001
|
||||
From: Grant Likely <grant.likely@linaro.org>
|
||||
Date: Thu, 19 Dec 2013 09:31:02 -0300
|
||||
Subject: [PATCH 191/203] of/irq: Fix potential buffer overflow
|
||||
|
||||
Commit 2361613206e6, "of/irq: Refactor interrupt-map parsing" introduced
|
||||
a potential buffer overflow bug because it doesn't do sufficient range
|
||||
checking on the input data. This patch adds the appropriate checking and
|
||||
buffer size adjustments. If the bounds are out of range then warn
|
||||
loudly. MAX_PHANDLE_ARGS should be sufficient. If it is not then the
|
||||
value can be increased.
|
||||
|
||||
Signed-off-by: Grant Likely <grant.likely@linaro.org>
|
||||
Cc: Rob Herring <rob.herring@calxeda.com>
|
||||
---
|
||||
drivers/of/irq.c | 10 ++++++++--
|
||||
1 file changed, 8 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/drivers/of/irq.c
|
||||
+++ b/drivers/of/irq.c
|
||||
@@ -95,9 +95,9 @@ struct device_node *of_irq_find_parent(s
|
||||
int of_irq_parse_raw(const __be32 *addr, struct of_phandle_args *out_irq)
|
||||
{
|
||||
struct device_node *ipar, *tnode, *old = NULL, *newpar = NULL;
|
||||
- __be32 initial_match_array[8];
|
||||
+ __be32 initial_match_array[MAX_PHANDLE_ARGS];
|
||||
const __be32 *match_array = initial_match_array;
|
||||
- const __be32 *tmp, *imap, *imask, dummy_imask[] = { ~0, ~0, ~0, ~0, ~0 };
|
||||
+ const __be32 *tmp, *imap, *imask, dummy_imask[] = { [0 ... MAX_PHANDLE_ARGS] = ~0 };
|
||||
u32 intsize = 1, addrsize, newintsize = 0, newaddrsize = 0;
|
||||
int imaplen, match, i;
|
||||
|
||||
@@ -147,6 +147,10 @@ int of_irq_parse_raw(const __be32 *addr,
|
||||
|
||||
pr_debug(" -> addrsize=%d\n", addrsize);
|
||||
|
||||
+ /* Range check so that the temporary buffer doesn't overflow */
|
||||
+ if (WARN_ON(addrsize + intsize > MAX_PHANDLE_ARGS))
|
||||
+ goto fail;
|
||||
+
|
||||
/* Precalculate the match array - this simplifies match loop */
|
||||
for (i = 0; i < addrsize; i++)
|
||||
initial_match_array[i] = addr ? addr[i] : 0;
|
||||
@@ -229,6 +233,8 @@ int of_irq_parse_raw(const __be32 *addr,
|
||||
newintsize, newaddrsize);
|
||||
|
||||
/* Check for malformed properties */
|
||||
+ if (WARN_ON(newaddrsize + newintsize > MAX_PHANDLE_ARGS))
|
||||
+ goto fail;
|
||||
if (imaplen < (newaddrsize + newintsize))
|
||||
goto fail;
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
From 8413f9010508998c62969827850a7434a1d5716c Mon Sep 17 00:00:00 2001
|
||||
From: Tomasz Figa <t.figa@samsung.com>
|
||||
Date: Thu, 19 Dec 2013 09:31:03 -0300
|
||||
Subject: [PATCH 192/203] of: irq: Fix interrupt-map entry matching
|
||||
|
||||
This patch fixes interrupt-map entry matching code to properly match all
|
||||
specifier cells with interrupt map entries.
|
||||
|
||||
Signed-off-by: Tomasz Figa <t.figa@samsung.com>
|
||||
Tested-by: Sachin Kamat <sachin.kamat@linaro.org>
|
||||
Signed-off-by: Rob Herring <rob.herring@calxeda.com>
|
||||
---
|
||||
drivers/of/irq.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/of/irq.c
|
||||
+++ b/drivers/of/irq.c
|
||||
@@ -199,7 +199,7 @@ int of_irq_parse_raw(const __be32 *addr,
|
||||
/* Compare specifiers */
|
||||
match = 1;
|
||||
for (i = 0; i < (addrsize + intsize); i++, imaplen--)
|
||||
- match = !((match_array[i] ^ *imap++) & imask[i]);
|
||||
+ match &= !((match_array[i] ^ *imap++) & imask[i]);
|
||||
|
||||
pr_debug(" -> match=%d (imaplen=%d)\n", match, imaplen);
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
From ba47ab198541f6ed822b3c9691b392d83edba8b4 Mon Sep 17 00:00:00 2001
|
||||
From: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
Date: Tue, 13 Aug 2013 11:43:14 -0300
|
||||
Subject: [PATCH 193/203] clocksource: armada-370-xp: Fix device-tree binding
|
||||
|
||||
This commit fixes the DT binding for the Armada 370/XP SoC timer.
|
||||
The previous "marvell,armada-370-xp-timer" compatible is removed and
|
||||
two new compatible strings are introduced: "marvell,armada-xp-timer"
|
||||
and "marvell,armada-370-timer".
|
||||
|
||||
The rationale behind this change is that the Armada 370 SoC and the
|
||||
Armada XP SoC timers are not really compatible:
|
||||
|
||||
* Armada 370 has no 25 MHz fixed timer.
|
||||
|
||||
* Armada XP cannot work properly without such 25 MHz fixed timer
|
||||
as doing otherwise leads to using a clocksource whose frequency
|
||||
varies when doing cpufreq frequency changes.
|
||||
|
||||
This commit also removes the "marvell,timer-25Mhz" property, given
|
||||
it's now meaningless.
|
||||
|
||||
Cc: devicetree@vger.kernel.org
|
||||
Acked-by: Jason Cooper <jason@lakedaemon.net>
|
||||
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
|
||||
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
|
||||
---
|
||||
.../bindings/timer/marvell,armada-370-xp-timer.txt | 27 ++++++++++++++++++----
|
||||
1 file changed, 22 insertions(+), 5 deletions(-)
|
||||
|
||||
--- a/Documentation/devicetree/bindings/timer/marvell,armada-370-xp-timer.txt
|
||||
+++ b/Documentation/devicetree/bindings/timer/marvell,armada-370-xp-timer.txt
|
||||
@@ -2,14 +2,31 @@ Marvell Armada 370 and Armada XP Timers
|
||||
---------------------------------------
|
||||
|
||||
Required properties:
|
||||
-- compatible: Should be "marvell,armada-370-xp-timer"
|
||||
+- compatible: Should be either "marvell,armada-370-timer" or
|
||||
+ "marvell,armada-xp-timer" as appropriate.
|
||||
- interrupts: Should contain the list of Global Timer interrupts and
|
||||
then local timer interrupts
|
||||
- reg: Should contain location and length for timers register. First
|
||||
pair for the Global Timer registers, second pair for the
|
||||
local/private timers.
|
||||
-- clocks: clock driving the timer hardware
|
||||
+- clocks: clock driving the timer hardware, only required for
|
||||
+ "marvell,armada-370-timer";
|
||||
|
||||
-Optional properties:
|
||||
-- marvell,timer-25Mhz: Tells whether the Global timer supports the 25
|
||||
- Mhz fixed mode (available on Armada XP and not on Armada 370)
|
||||
+Examples:
|
||||
+
|
||||
+- Armada 370:
|
||||
+
|
||||
+ timer {
|
||||
+ compatible = "marvell,armada-370-timer";
|
||||
+ reg = <0x20300 0x30>, <0x21040 0x30>;
|
||||
+ interrupts = <37>, <38>, <39>, <40>, <5>, <6>;
|
||||
+ clocks = <&coreclk 2>;
|
||||
+ };
|
||||
+
|
||||
+- Armada XP:
|
||||
+
|
||||
+ timer {
|
||||
+ compatible = "marvell,armada-xp-timer";
|
||||
+ reg = <0x20300 0x30>, <0x21040 0x30>;
|
||||
+ interrupts = <37>, <38>, <39>, <40>, <5>, <6>;
|
||||
+ };
|
|
@ -0,0 +1,47 @@
|
|||
From d569707433b26bb70f6b595a480bcfb3043a614c Mon Sep 17 00:00:00 2001
|
||||
From: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
Date: Tue, 20 Aug 2013 12:45:54 -0300
|
||||
Subject: [PATCH 194/203] clocksource: armada-370-xp: Add detailed clock
|
||||
requirements in devicetree binding
|
||||
|
||||
Specifies the required clock inputs for each supported compatible.
|
||||
Armada 370 requires a single clock phandle, and Armada XP requires
|
||||
two clock phandles with clock-names "nbclk" and "fixed".
|
||||
|
||||
Cc: devicetree@vger.kernel.org
|
||||
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
|
||||
Acked-by: Jason Cooper <jason@lakedaemon.net>
|
||||
Acked-by: Stephen Warren <swarren@nvidia.com>
|
||||
Acked-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
|
||||
---
|
||||
.../bindings/timer/marvell,armada-370-xp-timer.txt | 13 +++++++++++--
|
||||
1 file changed, 11 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/Documentation/devicetree/bindings/timer/marvell,armada-370-xp-timer.txt
|
||||
+++ b/Documentation/devicetree/bindings/timer/marvell,armada-370-xp-timer.txt
|
||||
@@ -9,8 +9,15 @@ Required properties:
|
||||
- reg: Should contain location and length for timers register. First
|
||||
pair for the Global Timer registers, second pair for the
|
||||
local/private timers.
|
||||
-- clocks: clock driving the timer hardware, only required for
|
||||
- "marvell,armada-370-timer";
|
||||
+
|
||||
+Clocks required for compatible = "marvell,armada-370-timer":
|
||||
+- clocks : Must contain a single entry describing the clock input
|
||||
+
|
||||
+Clocks required for compatible = "marvell,armada-xp-timer":
|
||||
+- clocks : Must contain an entry for each entry in clock-names.
|
||||
+- clock-names : Must include the following entries:
|
||||
+ "nbclk" (L2/coherency fabric clock),
|
||||
+ "fixed" (Reference 25 MHz fixed-clock).
|
||||
|
||||
Examples:
|
||||
|
||||
@@ -29,4 +36,6 @@ Examples:
|
||||
compatible = "marvell,armada-xp-timer";
|
||||
reg = <0x20300 0x30>, <0x21040 0x30>;
|
||||
interrupts = <37>, <38>, <39>, <40>, <5>, <6>;
|
||||
+ clocks = <&coreclk 2>, <&refclk>;
|
||||
+ clock-names = "nbclk", "fixed";
|
||||
};
|
|
@ -0,0 +1,68 @@
|
|||
From 956b857c1fc80164859adbe1147704b1f352e153 Mon Sep 17 00:00:00 2001
|
||||
From: Al Cooper <alcooperx@gmail.com>
|
||||
Date: Fri, 6 Dec 2013 00:18:25 +0100
|
||||
Subject: [PATCH 195/203] usb: Add Device Tree support to XHCI Platform driver
|
||||
|
||||
Add Device Tree match table to xhci-plat.c. Add DT bindings document.
|
||||
|
||||
Signed-off-by: Al Cooper <alcooperx@gmail.com>
|
||||
Cc: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com>
|
||||
Cc: Felipe Balbi <balbi@ti.com>
|
||||
Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
|
||||
|
||||
Conflicts:
|
||||
drivers/usb/host/xhci-plat.c
|
||||
---
|
||||
Documentation/devicetree/bindings/usb/usb-xhci.txt | 14 ++++++++++++++
|
||||
drivers/usb/host/xhci-plat.c | 10 ++++++++++
|
||||
2 files changed, 24 insertions(+)
|
||||
create mode 100644 Documentation/devicetree/bindings/usb/usb-xhci.txt
|
||||
|
||||
--- /dev/null
|
||||
+++ b/Documentation/devicetree/bindings/usb/usb-xhci.txt
|
||||
@@ -0,0 +1,14 @@
|
||||
+USB xHCI controllers
|
||||
+
|
||||
+Required properties:
|
||||
+ - compatible: should be "xhci-platform".
|
||||
+ - reg: should contain address and length of the standard XHCI
|
||||
+ register set for the device.
|
||||
+ - interrupts: one XHCI interrupt should be described here.
|
||||
+
|
||||
+Example:
|
||||
+ usb@f0931000 {
|
||||
+ compatible = "xhci-platform";
|
||||
+ reg = <0xf0931000 0x8c8>;
|
||||
+ interrupts = <0x0 0x4e 0x0>;
|
||||
+ };
|
||||
--- a/drivers/usb/host/xhci-plat.c
|
||||
+++ b/drivers/usb/host/xhci-plat.c
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
+#include <linux/of.h>
|
||||
|
||||
#include "xhci.h"
|
||||
|
||||
@@ -186,11 +187,20 @@ static int xhci_plat_remove(struct platf
|
||||
return 0;
|
||||
}
|
||||
|
||||
+#ifdef CONFIG_OF
|
||||
+static const struct of_device_id usb_xhci_of_match[] = {
|
||||
+ { .compatible = "xhci-platform" },
|
||||
+ { },
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, usb_xhci_of_match);
|
||||
+#endif
|
||||
+
|
||||
static struct platform_driver usb_xhci_driver = {
|
||||
.probe = xhci_plat_probe,
|
||||
.remove = xhci_plat_remove,
|
||||
.driver = {
|
||||
.name = "xhci-hcd",
|
||||
+ .of_match_table = of_match_ptr(usb_xhci_of_match),
|
||||
},
|
||||
};
|
||||
MODULE_ALIAS("platform:xhci-hcd");
|
|
@ -0,0 +1,58 @@
|
|||
From d587c866f34aa8e59ddc3628969113e725e36eab Mon Sep 17 00:00:00 2001
|
||||
From: Lior Amsalem <alior@marvell.com>
|
||||
Date: Mon, 23 Dec 2013 13:07:35 +0100
|
||||
Subject: [PATCH 196/203] ata: sata_mv: setting PHY speed according to SControl
|
||||
speed
|
||||
|
||||
This patch fixes a SATA hotplug issue on the Armada 370 and Armada XP
|
||||
SoCs. Without it, if a disk is unplugged from a SATA port, then further
|
||||
hotplug notification are now longer received on this port.
|
||||
|
||||
This should be applied to every -stable kernel supporting Armada SoCs.
|
||||
|
||||
Signed-off-by: Lior Amsalem <alior@marvell.com>
|
||||
Signed-off-by: Nadav Haklai <nadavh@marvell.com>
|
||||
Signed-off-by: Simon Guinot <simon.guinot@sequanux.org>
|
||||
Cc: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
|
||||
Cc: Jason Cooper <jason@lakedaemon.net>
|
||||
Cc: Andrew Lunn <andrew@lunn.ch>
|
||||
Cc: Gregory Clement <gregory.clement@free-electrons.com>
|
||||
Cc: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
|
||||
Cc: stable@vger.kernel.org
|
||||
---
|
||||
drivers/ata/sata_mv.c | 10 ++++++++++
|
||||
1 file changed, 10 insertions(+)
|
||||
|
||||
--- a/drivers/ata/sata_mv.c
|
||||
+++ b/drivers/ata/sata_mv.c
|
||||
@@ -304,6 +304,7 @@ enum {
|
||||
MV5_LTMODE = 0x30,
|
||||
MV5_PHY_CTL = 0x0C,
|
||||
SATA_IFCFG = 0x050,
|
||||
+ LP_PHY_CTL = 0x058,
|
||||
|
||||
MV_M2_PREAMP_MASK = 0x7e0,
|
||||
|
||||
@@ -1353,6 +1354,7 @@ static int mv_scr_write(struct ata_link
|
||||
|
||||
if (ofs != 0xffffffffU) {
|
||||
void __iomem *addr = mv_ap_base(link->ap) + ofs;
|
||||
+ void __iomem *lp_phy_addr = mv_ap_base(link->ap) + LP_PHY_CTL;
|
||||
if (sc_reg_in == SCR_CONTROL) {
|
||||
/*
|
||||
* Workaround for 88SX60x1 FEr SATA#26:
|
||||
@@ -1369,6 +1371,14 @@ static int mv_scr_write(struct ata_link
|
||||
*/
|
||||
if ((val & 0xf) == 1 || (readl(addr) & 0xf) == 1)
|
||||
val |= 0xf000;
|
||||
+
|
||||
+ /*
|
||||
+ * Setting PHY speed according to SControl speed
|
||||
+ */
|
||||
+ if ((val & 0xf0) == 0x10)
|
||||
+ writelfl(0x7, lp_phy_addr);
|
||||
+ else
|
||||
+ writelfl(0x227, lp_phy_addr);
|
||||
}
|
||||
writelfl(val, addr);
|
||||
return 0;
|
|
@ -0,0 +1,124 @@
|
|||
From 5cb802766e9cdc9a56e8ce8e4686692ebbcfb5cc Mon Sep 17 00:00:00 2001
|
||||
From: Xenia Ragiadakou <burzalodowa@gmail.com>
|
||||
Date: Mon, 23 Dec 2013 16:59:02 +0100
|
||||
Subject: [PATCH 197/203] xhci: fix dma mask setup in xhci.c
|
||||
|
||||
The function dma_set_mask() tests internally whether the dma_mask pointer
|
||||
for the device is initialized and fails if the dma_mask pointer is NULL.
|
||||
On pci platforms, the device dma_mask pointer is initialized, when pci
|
||||
devices are enumerated, to point to the pci_dev->dma_mask which is 0xffffffff.
|
||||
However, for non-pci platforms, the dma_mask pointer may not be initialized
|
||||
and in that case dma_set_mask() will fail.
|
||||
|
||||
This patch initializes the dma_mask and the coherent_dma_mask to 32bits
|
||||
in xhci_plat_probe(), before the call to usb_create_hcd() that sets the
|
||||
"uses_dma" flag for the usb bus and the call to usb_add_hcd() that creates
|
||||
coherent dma pools for the usb hcd.
|
||||
|
||||
Moreover, a call to dma_set_mask() does not set the device coherent_dma_mask.
|
||||
Since the xhci-hcd driver calls dma_alloc_coherent() and dma_pool_alloc()
|
||||
to allocate consistent DMA memory blocks, the coherent DMA address mask
|
||||
has to be set explicitly.
|
||||
|
||||
This patch sets the coherent_dma_mask to 64bits in xhci_gen_setup() when
|
||||
the xHC is capable for 64-bit DMA addressing.
|
||||
|
||||
If dma_set_mask() succeeds, for a given bitmask, it is guaranteed that
|
||||
the given bitmask is also supported for consistent DMA mappings.
|
||||
|
||||
Other changes introduced in this patch are:
|
||||
|
||||
- The return value of dma_set_mask() is checked to ensure that the required
|
||||
dma bitmask conforms with the host system's addressing capabilities.
|
||||
|
||||
- The dma_mask setup code for the non-primary hcd was removed since both
|
||||
primary and non-primary hcd refer to the same generic device whose
|
||||
dma_mask and coherent_dma_mask are already set during the setup of
|
||||
the primary hcd.
|
||||
|
||||
- The code for reading the HCCPARAMS register to find out the addressing
|
||||
capabilities of xHC was removed since its value is already cached in
|
||||
xhci->hccparams.
|
||||
|
||||
- hcd->self.controller was replaced with the dev variable since it is
|
||||
already available.
|
||||
|
||||
Signed-off-by: Xenia Ragiadakou <burzalodowa@gmail.com>
|
||||
Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
|
||||
|
||||
Conflicts:
|
||||
drivers/usb/host/xhci-plat.c
|
||||
---
|
||||
drivers/usb/host/xhci-plat.c | 10 ++++++++++
|
||||
drivers/usb/host/xhci.c | 19 +++++--------------
|
||||
2 files changed, 15 insertions(+), 14 deletions(-)
|
||||
|
||||
--- a/drivers/usb/host/xhci-plat.c
|
||||
+++ b/drivers/usb/host/xhci-plat.c
|
||||
@@ -15,6 +15,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/of.h>
|
||||
+#include <linux/dma-mapping.h>
|
||||
|
||||
#include "xhci.h"
|
||||
|
||||
@@ -105,6 +106,15 @@ static int xhci_plat_probe(struct platfo
|
||||
if (!res)
|
||||
return -ENODEV;
|
||||
|
||||
+ /* Initialize dma_mask and coherent_dma_mask to 32-bits */
|
||||
+ ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+ if (!pdev->dev.dma_mask)
|
||||
+ pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;
|
||||
+ else
|
||||
+ dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
|
||||
+
|
||||
hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev));
|
||||
if (!hcd)
|
||||
return -ENOMEM;
|
||||
--- a/drivers/usb/host/xhci.c
|
||||
+++ b/drivers/usb/host/xhci.c
|
||||
@@ -4654,7 +4654,6 @@ int xhci_gen_setup(struct usb_hcd *hcd,
|
||||
struct xhci_hcd *xhci;
|
||||
struct device *dev = hcd->self.controller;
|
||||
int retval;
|
||||
- u32 temp;
|
||||
|
||||
/* Accept arbitrarily long scatter-gather lists */
|
||||
hcd->self.sg_tablesize = ~0;
|
||||
@@ -4682,14 +4681,6 @@ int xhci_gen_setup(struct usb_hcd *hcd,
|
||||
/* xHCI private pointer was set in xhci_pci_probe for the second
|
||||
* registered roothub.
|
||||
*/
|
||||
- xhci = hcd_to_xhci(hcd);
|
||||
- temp = xhci_readl(xhci, &xhci->cap_regs->hcc_params);
|
||||
- if (HCC_64BIT_ADDR(temp)) {
|
||||
- xhci_dbg(xhci, "Enabling 64-bit DMA addresses.\n");
|
||||
- dma_set_mask(hcd->self.controller, DMA_BIT_MASK(64));
|
||||
- } else {
|
||||
- dma_set_mask(hcd->self.controller, DMA_BIT_MASK(32));
|
||||
- }
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -4728,12 +4719,12 @@ int xhci_gen_setup(struct usb_hcd *hcd,
|
||||
goto error;
|
||||
xhci_dbg(xhci, "Reset complete\n");
|
||||
|
||||
- temp = xhci_readl(xhci, &xhci->cap_regs->hcc_params);
|
||||
- if (HCC_64BIT_ADDR(temp)) {
|
||||
+ /* Set dma_mask and coherent_dma_mask to 64-bits,
|
||||
+ * if xHC supports 64-bit addressing */
|
||||
+ if (HCC_64BIT_ADDR(xhci->hcc_params) &&
|
||||
+ !dma_set_mask(dev, DMA_BIT_MASK(64))) {
|
||||
xhci_dbg(xhci, "Enabling 64-bit DMA addresses.\n");
|
||||
- dma_set_mask(hcd->self.controller, DMA_BIT_MASK(64));
|
||||
- } else {
|
||||
- dma_set_mask(hcd->self.controller, DMA_BIT_MASK(32));
|
||||
+ dma_set_coherent_mask(dev, DMA_BIT_MASK(64));
|
||||
}
|
||||
|
||||
xhci_dbg(xhci, "Calling HCD init\n");
|
|
@ -0,0 +1,104 @@
|
|||
From 39623dc5cb8814223e9580e22e78dfab10d91783 Mon Sep 17 00:00:00 2001
|
||||
From: Grant Likely <grant.likely@linaro.org>
|
||||
Date: Tue, 24 Dec 2013 11:36:02 +0100
|
||||
Subject: [PATCH 198/203] of: Add testcases for interrupt parsing
|
||||
|
||||
This patch extends the DT selftest code with some test cases for the
|
||||
interrupt parsing functions.
|
||||
|
||||
Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
|
||||
---
|
||||
arch/arm/boot/dts/testcases/tests-interrupts.dtsi | 41 +++++++++++++++++++++++
|
||||
arch/arm/boot/dts/testcases/tests.dtsi | 1 +
|
||||
drivers/of/selftest.c | 15 ++++++---
|
||||
3 files changed, 52 insertions(+), 5 deletions(-)
|
||||
create mode 100644 arch/arm/boot/dts/testcases/tests-interrupts.dtsi
|
||||
|
||||
--- /dev/null
|
||||
+++ b/arch/arm/boot/dts/testcases/tests-interrupts.dtsi
|
||||
@@ -0,0 +1,41 @@
|
||||
+
|
||||
+/ {
|
||||
+ testcase-data {
|
||||
+ interrupts {
|
||||
+ #address-cells = <0>;
|
||||
+ test_intc0: intc0 {
|
||||
+ interrupt-controller;
|
||||
+ #interrupt-cells = <1>;
|
||||
+ };
|
||||
+
|
||||
+ test_intc1: intc1 {
|
||||
+ interrupt-controller;
|
||||
+ #interrupt-cells = <3>;
|
||||
+ };
|
||||
+
|
||||
+ test_intc2: intc2 {
|
||||
+ interrupt-controller;
|
||||
+ #interrupt-cells = <2>;
|
||||
+ };
|
||||
+
|
||||
+ test_intmap0: intmap0 {
|
||||
+ #interrupt-cells = <1>;
|
||||
+ #address-cells = <0>;
|
||||
+ interrupt-map = <1 &test_intc0 9>,
|
||||
+ <2 &test_intc1 10 11 12>,
|
||||
+ <3 &test_intc2 13 14>,
|
||||
+ <4 &test_intc2 15 16>;
|
||||
+ };
|
||||
+
|
||||
+ interrupts0 {
|
||||
+ interrupt-parent = <&test_intc0>;
|
||||
+ interrupts = <1>, <2>, <3>, <4>;
|
||||
+ };
|
||||
+
|
||||
+ interrupts1 {
|
||||
+ interrupt-parent = <&test_intmap0>;
|
||||
+ interrupts = <1>, <2>, <3>, <4>;
|
||||
+ };
|
||||
+ };
|
||||
+ };
|
||||
+};
|
||||
--- a/arch/arm/boot/dts/testcases/tests.dtsi
|
||||
+++ b/arch/arm/boot/dts/testcases/tests.dtsi
|
||||
@@ -1 +1,2 @@
|
||||
/include/ "tests-phandle.dtsi"
|
||||
+/include/ "tests-interrupts.dtsi"
|
||||
--- a/drivers/of/selftest.c
|
||||
+++ b/drivers/of/selftest.c
|
||||
@@ -9,18 +9,24 @@
|
||||
#include <linux/errno.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
+#include <linux/of_irq.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/device.h>
|
||||
|
||||
-static bool selftest_passed = true;
|
||||
+static struct selftest_results {
|
||||
+ int passed;
|
||||
+ int failed;
|
||||
+} selftest_results;
|
||||
+
|
||||
#define selftest(result, fmt, ...) { \
|
||||
if (!(result)) { \
|
||||
- pr_err("FAIL %s:%i " fmt, __FILE__, __LINE__, ##__VA_ARGS__); \
|
||||
- selftest_passed = false; \
|
||||
+ selftest_results.failed++; \
|
||||
+ pr_err("FAIL %s():%i " fmt, __func__, __LINE__, ##__VA_ARGS__); \
|
||||
} else { \
|
||||
- pr_info("pass %s:%i\n", __FILE__, __LINE__); \
|
||||
+ selftest_results.passed++; \
|
||||
+ pr_debug("pass %s():%i\n", __func__, __LINE__); \
|
||||
} \
|
||||
}
|
||||
|
||||
@@ -131,7 +137,6 @@ static void __init of_selftest_property_
|
||||
struct device_node *np;
|
||||
int rc;
|
||||
|
||||
- pr_info("start\n");
|
||||
np = of_find_node_by_path("/testcase-data/phandle-tests/consumer-a");
|
||||
if (!np) {
|
||||
pr_err("No testcase data in device tree\n");
|
|
@ -0,0 +1,44 @@
|
|||
From 508e3a33ebe14ae4444a45b3f65dff5d5e6a4c73 Mon Sep 17 00:00:00 2001
|
||||
From: Tushar Behera <tushar.behera@linaro.org>
|
||||
Date: Mon, 17 Jun 2013 14:46:13 +0530
|
||||
Subject: [PATCH 199/203] PCI: mvebu: Convert to use devm_ioremap_resource
|
||||
|
||||
Commit 75096579c3ac ("lib: devres: Introduce devm_ioremap_resource()")
|
||||
introduced devm_ioremap_resource() and deprecated the use of
|
||||
devm_request_and_ioremap().
|
||||
|
||||
While at it, modify mvebu_pcie_map_registers() to propagate error code.
|
||||
|
||||
Signed-off-by: Tushar Behera <tushar.behera@linaro.org>
|
||||
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
|
||||
Acked-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||||
---
|
||||
drivers/pci/host/pci-mvebu.c | 7 ++++---
|
||||
1 file changed, 4 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/drivers/pci/host/pci-mvebu.c
|
||||
+++ b/drivers/pci/host/pci-mvebu.c
|
||||
@@ -736,9 +736,9 @@ mvebu_pcie_map_registers(struct platform
|
||||
|
||||
ret = of_address_to_resource(np, 0, ®s);
|
||||
if (ret)
|
||||
- return NULL;
|
||||
+ return ERR_PTR(ret);
|
||||
|
||||
- return devm_request_and_ioremap(&pdev->dev, ®s);
|
||||
+ return devm_ioremap_resource(&pdev->dev, ®s);
|
||||
}
|
||||
|
||||
static void __init mvebu_pcie_msi_enable(struct mvebu_pcie *pcie)
|
||||
@@ -897,9 +897,10 @@ static int __init mvebu_pcie_probe(struc
|
||||
}
|
||||
|
||||
port->base = mvebu_pcie_map_registers(pdev, child, port);
|
||||
- if (!port->base) {
|
||||
+ if (IS_ERR(port->base)) {
|
||||
dev_err(&pdev->dev, "PCIe%d.%d: cannot map registers\n",
|
||||
port->port, port->lane);
|
||||
+ port->base = NULL;
|
||||
continue;
|
||||
}
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
From c524c5790d413b37702013e7e83a845fd3f007ac Mon Sep 17 00:00:00 2001
|
||||
From: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
|
||||
Date: Tue, 13 Aug 2013 14:25:20 +0200
|
||||
Subject: [PATCH 200/203] PCI: mvebu: move clock enable before register access
|
||||
|
||||
The clock passed to PCI controller found on MVEBU SoCs may come from a
|
||||
clock gate. This requires the clock to be enabled before any registers
|
||||
are accessed. Therefore, move the clock enable before register iomap to
|
||||
ensure it is enabled.
|
||||
|
||||
Signed-off-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
|
||||
Signed-off-by: Jason Cooper <jason@lakedaemon.net>
|
||||
---
|
||||
drivers/pci/host/pci-mvebu.c | 25 ++++++++++++-------------
|
||||
1 file changed, 12 insertions(+), 13 deletions(-)
|
||||
|
||||
--- a/drivers/pci/host/pci-mvebu.c
|
||||
+++ b/drivers/pci/host/pci-mvebu.c
|
||||
@@ -896,11 +896,23 @@ static int __init mvebu_pcie_probe(struc
|
||||
continue;
|
||||
}
|
||||
|
||||
+ port->clk = of_clk_get_by_name(child, NULL);
|
||||
+ if (IS_ERR(port->clk)) {
|
||||
+ dev_err(&pdev->dev, "PCIe%d.%d: cannot get clock\n",
|
||||
+ port->port, port->lane);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ ret = clk_prepare_enable(port->clk);
|
||||
+ if (ret)
|
||||
+ continue;
|
||||
+
|
||||
port->base = mvebu_pcie_map_registers(pdev, child, port);
|
||||
if (IS_ERR(port->base)) {
|
||||
dev_err(&pdev->dev, "PCIe%d.%d: cannot map registers\n",
|
||||
port->port, port->lane);
|
||||
port->base = NULL;
|
||||
+ clk_disable_unprepare(port->clk);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -916,22 +928,9 @@ static int __init mvebu_pcie_probe(struc
|
||||
port->port, port->lane);
|
||||
}
|
||||
|
||||
- port->clk = of_clk_get_by_name(child, NULL);
|
||||
- if (!port->clk) {
|
||||
- dev_err(&pdev->dev, "PCIe%d.%d: cannot get clock\n",
|
||||
- port->port, port->lane);
|
||||
- iounmap(port->base);
|
||||
- port->haslink = 0;
|
||||
- continue;
|
||||
- }
|
||||
-
|
||||
port->dn = child;
|
||||
-
|
||||
- clk_prepare_enable(port->clk);
|
||||
spin_lock_init(&port->conf_lock);
|
||||
-
|
||||
mvebu_sw_pci_bridge_init(port);
|
||||
-
|
||||
i++;
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
From e619fe9eb65d8064739f16eca2015145ac920f13 Mon Sep 17 00:00:00 2001
|
||||
From: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
|
||||
Date: Tue, 13 Aug 2013 14:25:21 +0200
|
||||
Subject: [PATCH 201/203] PCI: mvebu: increment nports only for registered
|
||||
ports
|
||||
|
||||
The number of ports is probed by counting the number of available child nodes.
|
||||
Later on, the registration of a port can fail and cause a mismatch between
|
||||
the ->nports counter and registered ports. This patch modifies the counting
|
||||
strategy, to make ->nports represent the number of registered ports instead
|
||||
of the number of available childs.
|
||||
|
||||
Signed-off-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
|
||||
Signed-off-by: Jason Cooper <jason@lakedaemon.net>
|
||||
---
|
||||
drivers/pci/host/pci-mvebu.c | 7 ++++---
|
||||
1 file changed, 4 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/drivers/pci/host/pci-mvebu.c
|
||||
+++ b/drivers/pci/host/pci-mvebu.c
|
||||
@@ -841,13 +841,14 @@ static int __init mvebu_pcie_probe(struc
|
||||
return ret;
|
||||
}
|
||||
|
||||
+ i = 0;
|
||||
for_each_child_of_node(pdev->dev.of_node, child) {
|
||||
if (!of_device_is_available(child))
|
||||
continue;
|
||||
- pcie->nports++;
|
||||
+ i++;
|
||||
}
|
||||
|
||||
- pcie->ports = devm_kzalloc(&pdev->dev, pcie->nports *
|
||||
+ pcie->ports = devm_kzalloc(&pdev->dev, i *
|
||||
sizeof(struct mvebu_pcie_port),
|
||||
GFP_KERNEL);
|
||||
if (!pcie->ports)
|
||||
@@ -934,8 +935,8 @@ static int __init mvebu_pcie_probe(struc
|
||||
i++;
|
||||
}
|
||||
|
||||
+ pcie->nports = i;
|
||||
mvebu_pcie_msi_enable(pcie);
|
||||
-
|
||||
mvebu_pcie_enable(pcie);
|
||||
|
||||
return 0;
|
|
@ -0,0 +1,85 @@
|
|||
From b2ea44bd7bca49fe5696857327a1d1514edd1196 Mon Sep 17 00:00:00 2001
|
||||
From: Arnaud Ebalard <arno@natisbad.org>
|
||||
Date: Tue, 5 Nov 2013 21:45:48 +0100
|
||||
Subject: [PATCH 202/203] ARM: mvebu: second PCIe unit of Armada XP mv78230 is
|
||||
only x1 capable
|
||||
|
||||
Various Marvell datasheets advertise second PCIe unit of mv78230
|
||||
flavour of Armada XP as x4/quad x1 capable. This second unit is in
|
||||
fact only x1 capable. This patch fixes current mv78230 .dtsi to
|
||||
reflect that, i.e. makes 1.0 the second interface (instead of 2.0
|
||||
at the moment). This was successfully tested on a mv78230-based
|
||||
ReadyNAS 2120 platform with a x1 device (FL1009 XHCI controller)
|
||||
connected to this second interface.
|
||||
|
||||
Signed-off-by: Arnaud Ebalard <arno@natisbad.org>
|
||||
Acked-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
|
||||
Cc: <stable@vger.kernel.org> # v3.10.x
|
||||
Signed-off-by: Jason Cooper <jason@lakedaemon.net>
|
||||
---
|
||||
arch/arm/boot/dts/armada-xp-mv78230.dtsi | 24 ++++++++++++------------
|
||||
1 file changed, 12 insertions(+), 12 deletions(-)
|
||||
|
||||
--- a/arch/arm/boot/dts/armada-xp-mv78230.dtsi
|
||||
+++ b/arch/arm/boot/dts/armada-xp-mv78230.dtsi
|
||||
@@ -47,7 +47,7 @@
|
||||
/*
|
||||
* MV78230 has 2 PCIe units Gen2.0: One unit can be
|
||||
* configured as x4 or quad x1 lanes. One unit is
|
||||
- * x4/x1.
|
||||
+ * x1 only.
|
||||
*/
|
||||
pcie-controller {
|
||||
compatible = "marvell,armada-xp-pcie";
|
||||
@@ -62,10 +62,10 @@
|
||||
|
||||
ranges =
|
||||
<0x82000000 0 0x40000 MBUS_ID(0xf0, 0x01) 0x40000 0 0x00002000 /* Port 0.0 registers */
|
||||
- 0x82000000 0 0x42000 MBUS_ID(0xf0, 0x01) 0x42000 0 0x00002000 /* Port 2.0 registers */
|
||||
0x82000000 0 0x44000 MBUS_ID(0xf0, 0x01) 0x44000 0 0x00002000 /* Port 0.1 registers */
|
||||
0x82000000 0 0x48000 MBUS_ID(0xf0, 0x01) 0x48000 0 0x00002000 /* Port 0.2 registers */
|
||||
0x82000000 0 0x4c000 MBUS_ID(0xf0, 0x01) 0x4c000 0 0x00002000 /* Port 0.3 registers */
|
||||
+ 0x82000000 0 0x80000 MBUS_ID(0xf0, 0x01) 0x80000 0 0x00002000 /* Port 1.0 registers */
|
||||
0x82000000 0x1 0 MBUS_ID(0x04, 0xe8) 0 1 0 /* Port 0.0 MEM */
|
||||
0x81000000 0x1 0 MBUS_ID(0x04, 0xe0) 0 1 0 /* Port 0.0 IO */
|
||||
0x82000000 0x2 0 MBUS_ID(0x04, 0xd8) 0 1 0 /* Port 0.1 MEM */
|
||||
@@ -74,8 +74,8 @@
|
||||
0x81000000 0x3 0 MBUS_ID(0x04, 0xb0) 0 1 0 /* Port 0.2 IO */
|
||||
0x82000000 0x4 0 MBUS_ID(0x04, 0x78) 0 1 0 /* Port 0.3 MEM */
|
||||
0x81000000 0x4 0 MBUS_ID(0x04, 0x70) 0 1 0 /* Port 0.3 IO */
|
||||
- 0x82000000 0x9 0 MBUS_ID(0x04, 0xf8) 0 1 0 /* Port 2.0 MEM */
|
||||
- 0x81000000 0x9 0 MBUS_ID(0x04, 0xf0) 0 1 0 /* Port 2.0 IO */>;
|
||||
+ 0x82000000 0x5 0 MBUS_ID(0x08, 0xe8) 0 1 0 /* Port 1.0 MEM */
|
||||
+ 0x81000000 0x5 0 MBUS_ID(0x08, 0xe0) 0 1 0 /* Port 1.0 IO */>;
|
||||
|
||||
pcie@1,0 {
|
||||
device_type = "pci";
|
||||
@@ -145,20 +145,20 @@
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
- pcie@9,0 {
|
||||
+ pcie@5,0 {
|
||||
device_type = "pci";
|
||||
- assigned-addresses = <0x82000800 0 0x42000 0 0x2000>;
|
||||
- reg = <0x4800 0 0 0 0>;
|
||||
+ assigned-addresses = <0x82000800 0 0x80000 0 0x2000>;
|
||||
+ reg = <0x2800 0 0 0 0>;
|
||||
#address-cells = <3>;
|
||||
#size-cells = <2>;
|
||||
#interrupt-cells = <1>;
|
||||
- ranges = <0x82000000 0 0 0x82000000 0x9 0 1 0
|
||||
- 0x81000000 0 0 0x81000000 0x9 0 1 0>;
|
||||
+ ranges = <0x82000000 0 0 0x82000000 0x5 0 1 0
|
||||
+ 0x81000000 0 0 0x81000000 0x5 0 1 0>;
|
||||
interrupt-map-mask = <0 0 0 0>;
|
||||
- interrupt-map = <0 0 0 0 &mpic 99>;
|
||||
- marvell,pcie-port = <2>;
|
||||
+ interrupt-map = <0 0 0 0 &mpic 62>;
|
||||
+ marvell,pcie-port = <1>;
|
||||
marvell,pcie-lane = <0>;
|
||||
- clocks = <&gateclk 26>;
|
||||
+ clocks = <&gateclk 9>;
|
||||
status = "disabled";
|
||||
};
|
||||
};
|
|
@ -0,0 +1,180 @@
|
|||
From 9c2caf4d2d60780182d7754896c41496192b99c2 Mon Sep 17 00:00:00 2001
|
||||
From: Arnaud Ebalard <arno@natisbad.org>
|
||||
Date: Tue, 5 Nov 2013 21:46:02 +0100
|
||||
Subject: [PATCH 203/203] ARM: mvebu: fix second and third PCIe unit of Armada
|
||||
XP mv78260
|
||||
|
||||
mv78260 flavour of Marvell Armada XP SoC has 3 PCIe units. The
|
||||
two first units are both x4 and quad x1 capable. The third unit
|
||||
is only x4 capable. This patch fixes mv78260 .dtsi to reflect
|
||||
those capabilities.
|
||||
|
||||
Signed-off-by: Arnaud Ebalard <arno@natisbad.org>
|
||||
Acked-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
|
||||
Cc: <stable@vger.kernel.org> # v3.10.x
|
||||
Signed-off-by: Jason Cooper <jason@lakedaemon.net>
|
||||
---
|
||||
arch/arm/boot/dts/armada-xp-mv78260.dtsi | 109 ++++++++++++++++++++++++-------
|
||||
1 file changed, 85 insertions(+), 24 deletions(-)
|
||||
|
||||
--- a/arch/arm/boot/dts/armada-xp-mv78260.dtsi
|
||||
+++ b/arch/arm/boot/dts/armada-xp-mv78260.dtsi
|
||||
@@ -48,7 +48,7 @@
|
||||
/*
|
||||
* MV78260 has 3 PCIe units Gen2.0: Two units can be
|
||||
* configured as x4 or quad x1 lanes. One unit is
|
||||
- * x4/x1.
|
||||
+ * x4 only.
|
||||
*/
|
||||
pcie-controller {
|
||||
compatible = "marvell,armada-xp-pcie";
|
||||
@@ -68,7 +68,9 @@
|
||||
0x82000000 0 0x48000 MBUS_ID(0xf0, 0x01) 0x48000 0 0x00002000 /* Port 0.2 registers */
|
||||
0x82000000 0 0x4c000 MBUS_ID(0xf0, 0x01) 0x4c000 0 0x00002000 /* Port 0.3 registers */
|
||||
0x82000000 0 0x80000 MBUS_ID(0xf0, 0x01) 0x80000 0 0x00002000 /* Port 1.0 registers */
|
||||
- 0x82000000 0 0x82000 MBUS_ID(0xf0, 0x01) 0x82000 0 0x00002000 /* Port 3.0 registers */
|
||||
+ 0x82000000 0 0x84000 MBUS_ID(0xf0, 0x01) 0x84000 0 0x00002000 /* Port 1.1 registers */
|
||||
+ 0x82000000 0 0x88000 MBUS_ID(0xf0, 0x01) 0x88000 0 0x00002000 /* Port 1.2 registers */
|
||||
+ 0x82000000 0 0x8c000 MBUS_ID(0xf0, 0x01) 0x8c000 0 0x00002000 /* Port 1.3 registers */
|
||||
0x82000000 0x1 0 MBUS_ID(0x04, 0xe8) 0 1 0 /* Port 0.0 MEM */
|
||||
0x81000000 0x1 0 MBUS_ID(0x04, 0xe0) 0 1 0 /* Port 0.0 IO */
|
||||
0x82000000 0x2 0 MBUS_ID(0x04, 0xd8) 0 1 0 /* Port 0.1 MEM */
|
||||
@@ -77,10 +79,18 @@
|
||||
0x81000000 0x3 0 MBUS_ID(0x04, 0xb0) 0 1 0 /* Port 0.2 IO */
|
||||
0x82000000 0x4 0 MBUS_ID(0x04, 0x78) 0 1 0 /* Port 0.3 MEM */
|
||||
0x81000000 0x4 0 MBUS_ID(0x04, 0x70) 0 1 0 /* Port 0.3 IO */
|
||||
- 0x82000000 0x9 0 MBUS_ID(0x08, 0xe8) 0 1 0 /* Port 1.0 MEM */
|
||||
- 0x81000000 0x9 0 MBUS_ID(0x08, 0xe0) 0 1 0 /* Port 1.0 IO */
|
||||
- 0x82000000 0xa 0 MBUS_ID(0x08, 0xf8) 0 1 0 /* Port 3.0 MEM */
|
||||
- 0x81000000 0xa 0 MBUS_ID(0x08, 0xf0) 0 1 0 /* Port 3.0 IO */>;
|
||||
+
|
||||
+ 0x82000000 0x5 0 MBUS_ID(0x08, 0xe8) 0 1 0 /* Port 1.0 MEM */
|
||||
+ 0x81000000 0x5 0 MBUS_ID(0x08, 0xe0) 0 1 0 /* Port 1.0 IO */
|
||||
+ 0x82000000 0x6 0 MBUS_ID(0x08, 0xd8) 0 1 0 /* Port 1.1 MEM */
|
||||
+ 0x81000000 0x6 0 MBUS_ID(0x08, 0xd0) 0 1 0 /* Port 1.1 IO */
|
||||
+ 0x82000000 0x7 0 MBUS_ID(0x08, 0xb8) 0 1 0 /* Port 1.2 MEM */
|
||||
+ 0x81000000 0x7 0 MBUS_ID(0x08, 0xb0) 0 1 0 /* Port 1.2 IO */
|
||||
+ 0x82000000 0x8 0 MBUS_ID(0x08, 0x78) 0 1 0 /* Port 1.3 MEM */
|
||||
+ 0x81000000 0x8 0 MBUS_ID(0x08, 0x70) 0 1 0 /* Port 1.3 IO */
|
||||
+
|
||||
+ 0x82000000 0x9 0 MBUS_ID(0x04, 0xf8) 0 1 0 /* Port 2.0 MEM */
|
||||
+ 0x81000000 0x9 0 MBUS_ID(0x04, 0xf0) 0 1 0 /* Port 2.0 IO */>;
|
||||
|
||||
pcie@1,0 {
|
||||
device_type = "pci";
|
||||
@@ -106,8 +116,8 @@
|
||||
#address-cells = <3>;
|
||||
#size-cells = <2>;
|
||||
#interrupt-cells = <1>;
|
||||
- ranges = <0x82000000 0 0 0x82000000 0x2 0 1 0
|
||||
- 0x81000000 0 0 0x81000000 0x2 0 1 0>;
|
||||
+ ranges = <0x82000000 0 0 0x82000000 0x2 0 1 0
|
||||
+ 0x81000000 0 0 0x81000000 0x2 0 1 0>;
|
||||
interrupt-map-mask = <0 0 0 0>;
|
||||
interrupt-map = <0 0 0 0 &mpic 59>;
|
||||
marvell,pcie-port = <0>;
|
||||
@@ -150,37 +160,88 @@
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
- pcie@9,0 {
|
||||
+ pcie@5,0 {
|
||||
device_type = "pci";
|
||||
- assigned-addresses = <0x82000800 0 0x42000 0 0x2000>;
|
||||
- reg = <0x4800 0 0 0 0>;
|
||||
+ assigned-addresses = <0x82000800 0 0x80000 0 0x2000>;
|
||||
+ reg = <0x2800 0 0 0 0>;
|
||||
#address-cells = <3>;
|
||||
#size-cells = <2>;
|
||||
#interrupt-cells = <1>;
|
||||
- ranges = <0x82000000 0 0 0x82000000 0x9 0 1 0
|
||||
- 0x81000000 0 0 0x81000000 0x9 0 1 0>;
|
||||
+ ranges = <0x82000000 0 0 0x82000000 0x5 0 1 0
|
||||
+ 0x81000000 0 0 0x81000000 0x5 0 1 0>;
|
||||
interrupt-map-mask = <0 0 0 0>;
|
||||
- interrupt-map = <0 0 0 0 &mpic 99>;
|
||||
- marvell,pcie-port = <2>;
|
||||
+ interrupt-map = <0 0 0 0 &mpic 62>;
|
||||
+ marvell,pcie-port = <1>;
|
||||
marvell,pcie-lane = <0>;
|
||||
- clocks = <&gateclk 26>;
|
||||
+ clocks = <&gateclk 9>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
- pcie@10,0 {
|
||||
+ pcie@6,0 {
|
||||
device_type = "pci";
|
||||
- assigned-addresses = <0x82000800 0 0x82000 0 0x2000>;
|
||||
- reg = <0x5000 0 0 0 0>;
|
||||
+ assigned-addresses = <0x82000800 0 0x84000 0 0x2000>;
|
||||
+ reg = <0x3000 0 0 0 0>;
|
||||
#address-cells = <3>;
|
||||
#size-cells = <2>;
|
||||
#interrupt-cells = <1>;
|
||||
- ranges = <0x82000000 0 0 0x82000000 0xa 0 1 0
|
||||
- 0x81000000 0 0 0x81000000 0xa 0 1 0>;
|
||||
+ ranges = <0x82000000 0 0 0x82000000 0x6 0 1 0
|
||||
+ 0x81000000 0 0 0x81000000 0x6 0 1 0>;
|
||||
interrupt-map-mask = <0 0 0 0>;
|
||||
- interrupt-map = <0 0 0 0 &mpic 103>;
|
||||
- marvell,pcie-port = <3>;
|
||||
+ interrupt-map = <0 0 0 0 &mpic 63>;
|
||||
+ marvell,pcie-port = <1>;
|
||||
+ marvell,pcie-lane = <1>;
|
||||
+ clocks = <&gateclk 10>;
|
||||
+ status = "disabled";
|
||||
+ };
|
||||
+
|
||||
+ pcie@7,0 {
|
||||
+ device_type = "pci";
|
||||
+ assigned-addresses = <0x82000800 0 0x88000 0 0x2000>;
|
||||
+ reg = <0x3800 0 0 0 0>;
|
||||
+ #address-cells = <3>;
|
||||
+ #size-cells = <2>;
|
||||
+ #interrupt-cells = <1>;
|
||||
+ ranges = <0x82000000 0 0 0x82000000 0x7 0 1 0
|
||||
+ 0x81000000 0 0 0x81000000 0x7 0 1 0>;
|
||||
+ interrupt-map-mask = <0 0 0 0>;
|
||||
+ interrupt-map = <0 0 0 0 &mpic 64>;
|
||||
+ marvell,pcie-port = <1>;
|
||||
+ marvell,pcie-lane = <2>;
|
||||
+ clocks = <&gateclk 11>;
|
||||
+ status = "disabled";
|
||||
+ };
|
||||
+
|
||||
+ pcie@8,0 {
|
||||
+ device_type = "pci";
|
||||
+ assigned-addresses = <0x82000800 0 0x8c000 0 0x2000>;
|
||||
+ reg = <0x4000 0 0 0 0>;
|
||||
+ #address-cells = <3>;
|
||||
+ #size-cells = <2>;
|
||||
+ #interrupt-cells = <1>;
|
||||
+ ranges = <0x82000000 0 0 0x82000000 0x8 0 1 0
|
||||
+ 0x81000000 0 0 0x81000000 0x8 0 1 0>;
|
||||
+ interrupt-map-mask = <0 0 0 0>;
|
||||
+ interrupt-map = <0 0 0 0 &mpic 65>;
|
||||
+ marvell,pcie-port = <1>;
|
||||
+ marvell,pcie-lane = <3>;
|
||||
+ clocks = <&gateclk 12>;
|
||||
+ status = "disabled";
|
||||
+ };
|
||||
+
|
||||
+ pcie@9,0 {
|
||||
+ device_type = "pci";
|
||||
+ assigned-addresses = <0x82000800 0 0x42000 0 0x2000>;
|
||||
+ reg = <0x4800 0 0 0 0>;
|
||||
+ #address-cells = <3>;
|
||||
+ #size-cells = <2>;
|
||||
+ #interrupt-cells = <1>;
|
||||
+ ranges = <0x82000000 0 0 0x82000000 0x9 0 1 0
|
||||
+ 0x81000000 0 0 0x81000000 0x9 0 1 0>;
|
||||
+ interrupt-map-mask = <0 0 0 0>;
|
||||
+ interrupt-map = <0 0 0 0 &mpic 99>;
|
||||
+ marvell,pcie-port = <2>;
|
||||
marvell,pcie-lane = <0>;
|
||||
- clocks = <&gateclk 27>;
|
||||
+ clocks = <&gateclk 26>;
|
||||
status = "disabled";
|
||||
};
|
||||
};
|
Loading…
Reference in New Issue