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: 39566
lede-17.01
Luka Perkov 2014-02-11 02:07:44 +00:00
parent 3af779eb17
commit c9ae111a20
76 changed files with 6776 additions and 0 deletions

View File

@ -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,

View File

@ -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;
}

View File

@ -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;

View File

@ -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;

View File

@ -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>

View File

@ -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);

View File

@ -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)

View File

@ -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;

View File

@ -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;

View File

@ -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;
}

View File

@ -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)

View File

@ -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;

View File

@ -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;

View File

@ -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)

View File

@ -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];

View File

@ -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;

View File

@ -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;
}

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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:

View File

@ -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:

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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)

View File

@ -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,

View File

@ -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);

View File

@ -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);

View File

@ -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",

View File

@ -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

View File

@ -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"

View File

@ -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

View File

@ -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);

View File

@ -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:

View File

@ -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);

View File

@ -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 {

View File

@ -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;

View File

@ -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)

View File

@ -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",

View File

@ -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);

View File

@ -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;

View File

@ -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);
}

View File

@ -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);

View File

@ -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 {

View File

@ -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>;
+ };
+ };
};

View File

@ -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 {

View File

@ -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";
- };
- };
};
};
};

View File

@ -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)

View File

@ -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;
}

View File

@ -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,

View File

@ -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.

View File

@ -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

View File

@ -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;

View File

@ -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);
}

View File

@ -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,

View File

@ -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,

View File

@ -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;
}

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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 */

View File

@ -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;

View File

@ -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);

View File

@ -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>;
+ };

View File

@ -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";
};

View File

@ -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");

View File

@ -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;

View File

@ -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");

View File

@ -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");

View File

@ -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, &regs);
if (ret)
- return NULL;
+ return ERR_PTR(ret);
- return devm_request_and_ioremap(&pdev->dev, &regs);
+ return devm_ioremap_resource(&pdev->dev, &regs);
}
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;
}

View File

@ -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++;
}

View File

@ -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;

View File

@ -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";
};
};

View File

@ -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";
};
};