From: Luka Perkov Date: Tue, 11 Feb 2014 02:07:44 +0000 (+0000) Subject: mvebu: backport mainline patches from kernel 3.13 X-Git-Url: http://git.lede-project.org./?a=commitdiff_plain;h=c9ae111a20be4c9555128cced8edded660d133df;p=openwrt%2Fstaging%2Fadrian.git mvebu: backport mainline patches from kernel 3.13 This is a backport of the patches accepted to the Linux mainline related to mvebu SoC (Armada XP and Armada 370) between Linux v3.12, and Linux v3.13. This work mainly covers: * Finishes work for sharing the pxa nand driver(drivers/mtd/nand/pxa3xx_nand.c) between the PXA family, and the Armada family. * timer initialization update, and access function for the Armada family. * Generic IRQ handling backporting. * Some bug fixes. Signed-off-by: Seif Mazareeb CC: Luka Perkov SVN-Revision: 39566 --- diff --git a/target/linux/mvebu/patches-3.10/0128-mtd-nand-pxa3xx_nand-Remove-redundant-of_match_ptr.patch b/target/linux/mvebu/patches-3.10/0128-mtd-nand-pxa3xx_nand-Remove-redundant-of_match_ptr.patch new file mode 100644 index 0000000000..a0c4e6995f --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0128-mtd-nand-pxa3xx_nand-Remove-redundant-of_match_ptr.patch @@ -0,0 +1,25 @@ +From 38a6d3f3330da6586695746a0a85a96143171211 Mon Sep 17 00:00:00 2001 +From: Sachin Kamat +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 +Signed-off-by: Brian Norris +--- + 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, diff --git a/target/linux/mvebu/patches-3.10/0129-mtd-nand-pxa3xx-Move-DMA-I-O-enabling.patch b/target/linux/mvebu/patches-3.10/0129-mtd-nand-pxa3xx-Move-DMA-I-O-enabling.patch new file mode 100644 index 0000000000..0c95a61b97 --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0129-mtd-nand-pxa3xx-Move-DMA-I-O-enabling.patch @@ -0,0 +1,40 @@ +From 18166290599760e8ff1b6c0389834beafd09a517 Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +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 +Tested-by: Daniel Mack +Signed-off-by: Brian Norris +--- + 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; + } + diff --git a/target/linux/mvebu/patches-3.10/0130-mtd-nand-pxa3xx-Allocate-data-buffer-on-detected-fla.patch b/target/linux/mvebu/patches-3.10/0130-mtd-nand-pxa3xx-Allocate-data-buffer-on-detected-fla.patch new file mode 100644 index 0000000000..09f022b967 --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0130-mtd-nand-pxa3xx-Allocate-data-buffer-on-detected-fla.patch @@ -0,0 +1,143 @@ +From 71d6267980d7590e38059a784785ca158e361f87 Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +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 +Tested-by: Daniel Mack +Signed-off-by: Brian Norris +--- + 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; diff --git a/target/linux/mvebu/patches-3.10/0131-mtd-nand-remove-deprecated-IRQF_DISABLED.patch b/target/linux/mvebu/patches-3.10/0131-mtd-nand-remove-deprecated-IRQF_DISABLED.patch new file mode 100644 index 0000000000..6cecbf2c88 --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0131-mtd-nand-remove-deprecated-IRQF_DISABLED.patch @@ -0,0 +1,27 @@ +From e3779fc4a84e1c51c061e3e13b1abf1c9a56a2cd Mon Sep 17 00:00:00 2001 +From: Michael Opdenacker +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 +Signed-off-by: Brian Norris +--- + 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; diff --git a/target/linux/mvebu/patches-3.10/0132-mtd-nand-pxa3xx-Add-documentation-about-the-controll.patch b/target/linux/mvebu/patches-3.10/0132-mtd-nand-pxa3xx-Add-documentation-about-the-controll.patch new file mode 100644 index 0000000000..561c7d7d74 --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0132-mtd-nand-pxa3xx-Add-documentation-about-the-controll.patch @@ -0,0 +1,28 @@ +From 54c1163b143e4ed911b8dddc0829c87f93b3debd Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +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 +Signed-off-by: Brian Norris +--- + 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 diff --git a/target/linux/mvebu/patches-3.10/0133-mtd-nand-pxa3xx-Prevent-sub-page-writes.patch b/target/linux/mvebu/patches-3.10/0133-mtd-nand-pxa3xx-Prevent-sub-page-writes.patch new file mode 100644 index 0000000000..1af6da297f --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0133-mtd-nand-pxa3xx-Prevent-sub-page-writes.patch @@ -0,0 +1,25 @@ +From ec1977c2873dc7f0e6cec3edb8c30d92882f65d1 Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +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 +Tested-by: Daniel Mack +Signed-off-by: Brian Norris +--- + 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); diff --git a/target/linux/mvebu/patches-3.10/0134-mtd-nand-pxa3xx-read_page-returns-max_bitflips.patch b/target/linux/mvebu/patches-3.10/0134-mtd-nand-pxa3xx-read_page-returns-max_bitflips.patch new file mode 100644 index 0000000000..afb81720c0 --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0134-mtd-nand-pxa3xx-read_page-returns-max_bitflips.patch @@ -0,0 +1,42 @@ +From 97598678602aaea473303523ce37a45d258206ca Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +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 +Tested-by: Daniel Mack +Signed-off-by: Brian Norris +--- + 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) diff --git a/target/linux/mvebu/patches-3.10/0135-mtd-nand-pxa3xx-Early-variant-detection.patch b/target/linux/mvebu/patches-3.10/0135-mtd-nand-pxa3xx-Early-variant-detection.patch new file mode 100644 index 0000000000..328a2ab900 --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0135-mtd-nand-pxa3xx-Early-variant-detection.patch @@ -0,0 +1,97 @@ +From dc333ddda677d416a6726509e144c6dfb93e7e89 Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +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 +Tested-by: Daniel Mack +Signed-off-by: Brian Norris +--- + 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; diff --git a/target/linux/mvebu/patches-3.10/0136-mtd-nand-pxa3xx-Use-chip-cmdfunc-instead-of-the-inte.patch b/target/linux/mvebu/patches-3.10/0136-mtd-nand-pxa3xx-Use-chip-cmdfunc-instead-of-the-inte.patch new file mode 100644 index 0000000000..de79b8d28d --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0136-mtd-nand-pxa3xx-Use-chip-cmdfunc-instead-of-the-inte.patch @@ -0,0 +1,41 @@ +From 67ab922e1e292494732a10f367d3de47338639ac Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +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 +Signed-off-by: Ezequiel Garcia +Tested-by: Daniel Mack +Signed-off-by: Brian Norris +--- + 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; + diff --git a/target/linux/mvebu/patches-3.10/0137-mtd-nand-pxa3xx-Split-FIFO-size-from-to-be-read-FIFO.patch b/target/linux/mvebu/patches-3.10/0137-mtd-nand-pxa3xx-Split-FIFO-size-from-to-be-read-FIFO.patch new file mode 100644 index 0000000000..e00921d40f --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0137-mtd-nand-pxa3xx-Split-FIFO-size-from-to-be-read-FIFO.patch @@ -0,0 +1,74 @@ +From 496f307424d3958ef43ad06ae6a0be98ede2a92c Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +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 +Tested-by: Daniel Mack +Signed-off-by: Brian Norris +--- + 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; + } diff --git a/target/linux/mvebu/patches-3.10/0138-mtd-nand-pxa3xx-Replace-host-page_size-by-mtd-writes.patch b/target/linux/mvebu/patches-3.10/0138-mtd-nand-pxa3xx-Replace-host-page_size-by-mtd-writes.patch new file mode 100644 index 0000000000..259f6a0a39 --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0138-mtd-nand-pxa3xx-Replace-host-page_size-by-mtd-writes.patch @@ -0,0 +1,72 @@ +From ad40a597cbfeb2374c799ba6dad3a69f131511c8 Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +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 +Tested-by: Daniel Mack +Signed-off-by: Brian Norris +--- + 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) diff --git a/target/linux/mvebu/patches-3.10/0139-mtd-nand-pxa3xx-Add-a-nice-comment-to-pxa3xx_set_dat.patch b/target/linux/mvebu/patches-3.10/0139-mtd-nand-pxa3xx-Add-a-nice-comment-to-pxa3xx_set_dat.patch new file mode 100644 index 0000000000..aeecae6218 --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0139-mtd-nand-pxa3xx-Add-a-nice-comment-to-pxa3xx_set_dat.patch @@ -0,0 +1,30 @@ +From 8bce53e42f78e009fbfbd4a98ea98f66e6cd5b4c Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +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 +Signed-off-by: Brian Norris +--- + 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; diff --git a/target/linux/mvebu/patches-3.10/0140-mtd-nand-pxa3xx-Use-a-completion-to-signal-device-re.patch b/target/linux/mvebu/patches-3.10/0140-mtd-nand-pxa3xx-Use-a-completion-to-signal-device-re.patch new file mode 100644 index 0000000000..7f5108fd2f --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0140-mtd-nand-pxa3xx-Use-a-completion-to-signal-device-re.patch @@ -0,0 +1,138 @@ +From b5289e9cb18e6c254e13826e6bcfbfe95b819d77 Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +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 +Tested-by: Daniel Mack +Signed-off-by: Brian Norris +--- + 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 + ++#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; diff --git a/target/linux/mvebu/patches-3.10/0141-mtd-nand-pxa3xx-Use-waitfunc-to-wait-for-the-device-.patch b/target/linux/mvebu/patches-3.10/0141-mtd-nand-pxa3xx-Use-waitfunc-to-wait-for-the-device-.patch new file mode 100644 index 0000000000..13fdffe532 --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0141-mtd-nand-pxa3xx-Use-waitfunc-to-wait-for-the-device-.patch @@ -0,0 +1,34 @@ +From 2a1254f505ca4d376eae81768e4d5d890b578d13 Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +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 +Tested-by: Daniel Mack +Signed-off-by: Brian Norris +--- + 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) diff --git a/target/linux/mvebu/patches-3.10/0142-mtd-nand-pxa3xx-Add-bad-block-handling.patch b/target/linux/mvebu/patches-3.10/0142-mtd-nand-pxa3xx-Add-bad-block-handling.patch new file mode 100644 index 0000000000..0d04bf4d82 --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0142-mtd-nand-pxa3xx-Add-bad-block-handling.patch @@ -0,0 +1,108 @@ +From bd428b9b18c2dffb8c9d737e99adfd145822e502 Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +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 +Tested-by: Daniel Mack +Signed-off-by: Brian Norris +--- + .../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 + #include + #include ++#include + + #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]; + diff --git a/target/linux/mvebu/patches-3.10/0143-mtd-nand-pxa3xx-Add-driver-specific-ECC-BCH-support.patch b/target/linux/mvebu/patches-3.10/0143-mtd-nand-pxa3xx-Add-driver-specific-ECC-BCH-support.patch new file mode 100644 index 0000000000..c310effadf --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0143-mtd-nand-pxa3xx-Add-driver-specific-ECC-BCH-support.patch @@ -0,0 +1,172 @@ +From 3677d22ed7e3a631f35e2addc4e2181f6215e4b0 Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +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 +Tested-by: Daniel Mack +Signed-off-by: Brian Norris +--- + 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; diff --git a/target/linux/mvebu/patches-3.10/0144-mtd-nand-pxa3xx-Clear-cmd-buffer-3-NDCB3-on-command-.patch b/target/linux/mvebu/patches-3.10/0144-mtd-nand-pxa3xx-Clear-cmd-buffer-3-NDCB3-on-command-.patch new file mode 100644 index 0000000000..567cc8e1b1 --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0144-mtd-nand-pxa3xx-Clear-cmd-buffer-3-NDCB3-on-command-.patch @@ -0,0 +1,34 @@ +From cb574fecefd9552e5c6c5105adab7b37b0feb712 Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +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 +Tested-by: Daniel Mack +Signed-off-by: Brian Norris +--- + 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; + } + diff --git a/target/linux/mvebu/patches-3.10/0145-mtd-nand-pxa3xx-Add-helper-function-to-set-page-addr.patch b/target/linux/mvebu/patches-3.10/0145-mtd-nand-pxa3xx-Add-helper-function-to-set-page-addr.patch new file mode 100644 index 0000000000..a0a909e09d --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0145-mtd-nand-pxa3xx-Add-helper-function-to-set-page-addr.patch @@ -0,0 +1,70 @@ +From 09a84f8e89c3715160423701b0606ef99e2a05bf Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +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 +Tested-by: Daniel Mack +Signed-off-by: Brian Norris +--- + 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); + diff --git a/target/linux/mvebu/patches-3.10/0146-mtd-nand-pxa3xx-Remove-READ0-switch-case-falltrough.patch b/target/linux/mvebu/patches-3.10/0146-mtd-nand-pxa3xx-Remove-READ0-switch-case-falltrough.patch new file mode 100644 index 0000000000..0631b926b1 --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0146-mtd-nand-pxa3xx-Remove-READ0-switch-case-falltrough.patch @@ -0,0 +1,32 @@ +From 11532c10a29e4faef29b5f3b354391d1e2f90213 Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +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 +Tested-by: Daniel Mack +Signed-off-by: Brian Norris +--- + 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); diff --git a/target/linux/mvebu/patches-3.10/0147-mtd-nand-pxa3xx-Split-prepare_command_pool-in-two-st.patch b/target/linux/mvebu/patches-3.10/0147-mtd-nand-pxa3xx-Split-prepare_command_pool-in-two-st.patch new file mode 100644 index 0000000000..aa25c07bb4 --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0147-mtd-nand-pxa3xx-Split-prepare_command_pool-in-two-st.patch @@ -0,0 +1,101 @@ +From 78c8c8dc7e27c4502504cb4daa07bc9762f54de9 Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +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 +Tested-by: Daniel Mack +Signed-off-by: Brian Norris +--- + 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); diff --git a/target/linux/mvebu/patches-3.10/0148-mtd-nand-pxa3xx-Move-the-data-buffer-clean-to-prepar.patch b/target/linux/mvebu/patches-3.10/0148-mtd-nand-pxa3xx-Move-the-data-buffer-clean-to-prepar.patch new file mode 100644 index 0000000000..3d74844f5c --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0148-mtd-nand-pxa3xx-Move-the-data-buffer-clean-to-prepar.patch @@ -0,0 +1,69 @@ +From 1c0aed9b4cfb7bb891aab07a429436d017ac4d7c Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +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 +Tested-by: Daniel Mack +Signed-off-by: Brian Norris +--- + 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: diff --git a/target/linux/mvebu/patches-3.10/0149-mtd-nand-pxa3xx-Fix-SEQIN-column-address-set.patch b/target/linux/mvebu/patches-3.10/0149-mtd-nand-pxa3xx-Fix-SEQIN-column-address-set.patch new file mode 100644 index 0000000000..cb59ccbd1c --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0149-mtd-nand-pxa3xx-Fix-SEQIN-column-address-set.patch @@ -0,0 +1,32 @@ +From d5c9b013c71a570737353270f94b9a52639fcea1 Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +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 +Tested-by: Daniel Mack +Signed-off-by: Brian Norris +--- + 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: diff --git a/target/linux/mvebu/patches-3.10/0150-mtd-nand-pxa3xx-Add-a-read-write-buffers-markers.patch b/target/linux/mvebu/patches-3.10/0150-mtd-nand-pxa3xx-Add-a-read-write-buffers-markers.patch new file mode 100644 index 0000000000..1251f6022a --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0150-mtd-nand-pxa3xx-Add-a-read-write-buffers-markers.patch @@ -0,0 +1,111 @@ +From 6e3022aeb5d221af838ad43a2163374aecacf929 Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +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 +Tested-by: Daniel Mack +Signed-off-by: Brian Norris +--- + 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; diff --git a/target/linux/mvebu/patches-3.10/0151-mtd-nand-pxa3xx-Introduce-multiple-page-I-O-support.patch b/target/linux/mvebu/patches-3.10/0151-mtd-nand-pxa3xx-Introduce-multiple-page-I-O-support.patch new file mode 100644 index 0000000000..f8e3c8796d --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0151-mtd-nand-pxa3xx-Introduce-multiple-page-I-O-support.patch @@ -0,0 +1,325 @@ +From cfd1799f9ec5c9820f371e1fcf2f3c458bd24ebb Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +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 +Tested-by: Daniel Mack +Signed-off-by: Brian Norris +--- + 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); diff --git a/target/linux/mvebu/patches-3.10/0152-mtd-nand-pxa3xx-Add-multiple-chunk-write-support.patch b/target/linux/mvebu/patches-3.10/0152-mtd-nand-pxa3xx-Add-multiple-chunk-write-support.patch new file mode 100644 index 0000000000..058dc0bc3c --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0152-mtd-nand-pxa3xx-Add-multiple-chunk-write-support.patch @@ -0,0 +1,146 @@ +From db95c66cebb6297595a5a32b369d1033b08775ce Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +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 +Tested-by: Daniel Mack +Signed-off-by: Brian Norris +--- + 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); + diff --git a/target/linux/mvebu/patches-3.10/0153-mtd-nand-pxa3xx-Add-ECC-BCH-correctable-errors-detec.patch b/target/linux/mvebu/patches-3.10/0153-mtd-nand-pxa3xx-Add-ECC-BCH-correctable-errors-detec.patch new file mode 100644 index 0000000000..fa68e5b033 --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0153-mtd-nand-pxa3xx-Add-ECC-BCH-correctable-errors-detec.patch @@ -0,0 +1,144 @@ +From 26d82e0081aa6f0c7db5e4bb5b154b7c528cb8d6 Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +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 +Tested-by: Daniel Mack +Signed-off-by: Brian Norris +--- + 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) diff --git a/target/linux/mvebu/patches-3.10/0154-mtd-nand-pxa3xx-make-ECC-configuration-checks-more-e.patch b/target/linux/mvebu/patches-3.10/0154-mtd-nand-pxa3xx-make-ECC-configuration-checks-more-e.patch new file mode 100644 index 0000000000..8d9d21ac0a --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0154-mtd-nand-pxa3xx-make-ECC-configuration-checks-more-e.patch @@ -0,0 +1,67 @@ +From c312e183e96bed3b727888673d4b6b54b8e6283e Mon Sep 17 00:00:00 2001 +From: Brian Norris +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 +Acked-by: Ezequiel Garcia +Tested-by: Daniel Mack +--- + 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, diff --git a/target/linux/mvebu/patches-3.10/0155-mtd-nand-pxa3xx-Use-info-use_dma-to-release-DMA-reso.patch b/target/linux/mvebu/patches-3.10/0155-mtd-nand-pxa3xx-Use-info-use_dma-to-release-DMA-reso.patch new file mode 100644 index 0000000000..d86cc9bf85 --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0155-mtd-nand-pxa3xx-Use-info-use_dma-to-release-DMA-reso.patch @@ -0,0 +1,29 @@ +From 4c6bade4cf80d77decc5ea89fbaadff8b008f5e9 Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +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 +--- + 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); diff --git a/target/linux/mvebu/patches-3.10/0156-mtd-nand-pxa3xx-Use-extended-cmdfunc-only-if-needed.patch b/target/linux/mvebu/patches-3.10/0156-mtd-nand-pxa3xx-Use-extended-cmdfunc-only-if-needed.patch new file mode 100644 index 0000000000..7b14da8cea --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0156-mtd-nand-pxa3xx-Use-extended-cmdfunc-only-if-needed.patch @@ -0,0 +1,89 @@ +From a701d8e1c4c1e31a208dae616ed9067ba4e90191 Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +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 +--- + 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); diff --git a/target/linux/mvebu/patches-3.10/0157-mtd-nand-pxa3xx-Consolidate-ECC-initialization.patch b/target/linux/mvebu/patches-3.10/0157-mtd-nand-pxa3xx-Consolidate-ECC-initialization.patch new file mode 100644 index 0000000000..28ec7d8897 --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0157-mtd-nand-pxa3xx-Consolidate-ECC-initialization.patch @@ -0,0 +1,100 @@ +From 70c36de37f357f38b5a56292534133d75e7d8870 Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +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 +--- + 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", diff --git a/target/linux/mvebu/patches-3.10/0158-mtd-nand-Allow-to-build-pxa3xx_nand-on-Orion-platfor.patch b/target/linux/mvebu/patches-3.10/0158-mtd-nand-Allow-to-build-pxa3xx_nand-on-Orion-platfor.patch new file mode 100644 index 0000000000..6ac5a67ffe --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0158-mtd-nand-Allow-to-build-pxa3xx_nand-on-Orion-platfor.patch @@ -0,0 +1,29 @@ +From 933f5de151614aee0f7b1f664f86b04f3773a075 Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +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 +Tested-by: Daniel Mack +Signed-off-by: Brian Norris +Signed-off-by: David Woodhouse +--- + 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 diff --git a/target/linux/mvebu/patches-3.10/0159-mtd-nand-pxa3xx-Make-config-menu-show-supported-plat.patch b/target/linux/mvebu/patches-3.10/0159-mtd-nand-pxa3xx-Make-config-menu-show-supported-plat.patch new file mode 100644 index 0000000000..001a9ee5a5 --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0159-mtd-nand-pxa3xx-Make-config-menu-show-supported-plat.patch @@ -0,0 +1,31 @@ +From b1abf1e5c6a7531a1a93a0ab6c75607dcb0e9947 Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +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 +Signed-off-by: Brian Norris +--- + 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" diff --git a/target/linux/mvebu/patches-3.10/0160-ARM-mvebu-config-Add-NAND-support.patch b/target/linux/mvebu/patches-3.10/0160-ARM-mvebu-config-Add-NAND-support.patch new file mode 100644 index 0000000000..4edcaf2d96 --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0160-ARM-mvebu-config-Add-NAND-support.patch @@ -0,0 +1,24 @@ +From a18945a7fd26b83c765b60bcffe306421f7efe80 Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +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 +--- + 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 diff --git a/target/linux/mvebu/patches-3.10/0161-net-mvneta-Fix-incorrect-DMA-unmapping-size.patch b/target/linux/mvebu/patches-3.10/0161-net-mvneta-Fix-incorrect-DMA-unmapping-size.patch new file mode 100644 index 0000000000..f5d600f86a --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0161-net-mvneta-Fix-incorrect-DMA-unmapping-size.patch @@ -0,0 +1,69 @@ +From f834da3962eaee5d72f152e9a066c06ec0d9c2c4 Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +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 +[] (unwind_backtrace+0x0/0xf8) from [] (show_stack+0x10/0x14) +[] (show_stack+0x10/0x14) from [] (warn_slowpath_common+0x48/0x68) +[] (warn_slowpath_common+0x48/0x68) from [] (warn_slowpath_fmt+0x30/0x40) +[] (warn_slowpath_fmt+0x30/0x40) from [] (check_unmap+0x3a8/0x860) +[] (check_unmap+0x3a8/0x860) from [] (debug_dma_unmap_page+0x64/0x70) +[] (debug_dma_unmap_page+0x64/0x70) from [] (mvneta_rx+0xec/0x468) +[] (mvneta_rx+0xec/0x468) from [] (mvneta_poll+0x78/0x16c) +[] (mvneta_poll+0x78/0x16c) from [] (net_rx_action+0x94/0x160) +[] (net_rx_action+0x94/0x160) from [] (__do_softirq+0xe8/0x1d0) +[] (__do_softirq+0xe8/0x1d0) from [] (do_softirq+0x4c/0x58) +[] (do_softirq+0x4c/0x58) from [] (irq_exit+0x58/0x90) +[] (irq_exit+0x58/0x90) from [] (handle_IRQ+0x3c/0x94) +[] (handle_IRQ+0x3c/0x94) from [] (armada_370_xp_handle_irq+0x4c/0xb4) +[] (armada_370_xp_handle_irq+0x4c/0xb4) from [] (__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 +[] (__irq_svc+0x40/0x50) from [] (cpu_startup_entry+0x54/0x128) +[] (cpu_startup_entry+0x54/0x128) from [] (start_kernel+0x29c/0x2f0) +[] (start_kernel+0x29c/0x2f0) from [<00008074>] (0x8074) +---[ end trace d4955f6acd178110 ]--- +Mapped at: + [] debug_dma_map_page+0x4c/0x11c + [] mvneta_setup_rxqs+0x398/0x598 + [] mvneta_open+0x40/0x17c + [] __dev_open+0x9c/0x100 + [] __dev_change_flags+0x7c/0x134 + +Signed-off-by: Ezequiel Garcia +--- + 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); diff --git a/target/linux/mvebu/patches-3.10/0162-mtd-nand-pxa3xx-Clear-need_wait-flag-when-starting-a.patch b/target/linux/mvebu/patches-3.10/0162-mtd-nand-pxa3xx-Clear-need_wait-flag-when-starting-a.patch new file mode 100644 index 0000000000..5665ca13e6 --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0162-mtd-nand-pxa3xx-Clear-need_wait-flag-when-starting-a.patch @@ -0,0 +1,50 @@ +From 7efaa8677ffd07d54d0122b5e92f29b74a36ad39 Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +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 +Signed-off-by: Ezequiel Garcia +--- + 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: diff --git a/target/linux/mvebu/patches-3.10/0163-ARM-mvebu-move-ARMADA_XP_MAX_CPUS-to-armada-370-xp.h.patch b/target/linux/mvebu/patches-3.10/0163-ARM-mvebu-move-ARMADA_XP_MAX_CPUS-to-armada-370-xp.h.patch new file mode 100644 index 0000000000..5f46bc1493 --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0163-ARM-mvebu-move-ARMADA_XP_MAX_CPUS-to-armada-370-xp.h.patch @@ -0,0 +1,39 @@ +From b340059540cbc90412f3e7159dc57a178e0effd6 Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni +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 +--- + 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 + ++#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); diff --git a/target/linux/mvebu/patches-3.10/0164-ARM-mvebu-fix-register-length-for-Armada-XP-PMSU.patch b/target/linux/mvebu/patches-3.10/0164-ARM-mvebu-fix-register-length-for-Armada-XP-PMSU.patch new file mode 100644 index 0000000000..7b58f61a77 --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0164-ARM-mvebu-fix-register-length-for-Armada-XP-PMSU.patch @@ -0,0 +1,34 @@ +From 10208caf7f0ebfb3d6b546aa2ae66e42462551e0 Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni +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 +--- + 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 { diff --git a/target/linux/mvebu/patches-3.10/0165-ARM-mvebu-make-armada_370_xp_pmsu_init-static.patch b/target/linux/mvebu/patches-3.10/0165-ARM-mvebu-make-armada_370_xp_pmsu_init-static.patch new file mode 100644 index 0000000000..72465a19eb --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0165-ARM-mvebu-make-armada_370_xp_pmsu_init-static.patch @@ -0,0 +1,36 @@ +From 167c442fb9adf4c2e02663a0291c6cfae31bad72 Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni +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 +--- + 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; + diff --git a/target/linux/mvebu/patches-3.10/0166-clocksource-armada-370-xp-Use-BIT.patch b/target/linux/mvebu/patches-3.10/0166-clocksource-armada-370-xp-Use-BIT.patch new file mode 100644 index 0000000000..8f07046a17 --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0166-clocksource-armada-370-xp-Use-BIT.patch @@ -0,0 +1,37 @@ +From ea331be867c791bca8200e6d707499845d8dfa87 Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +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 +Signed-off-by: Daniel Lezcano +Reviewed-by: Andrew Lunn +--- + 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) diff --git a/target/linux/mvebu/patches-3.10/0167-clocksource-armada-370-xp-Simplify-TIMER_CTRL-regist.patch b/target/linux/mvebu/patches-3.10/0167-clocksource-armada-370-xp-Simplify-TIMER_CTRL-regist.patch new file mode 100644 index 0000000000..109d52d7c2 --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0167-clocksource-armada-370-xp-Simplify-TIMER_CTRL-regist.patch @@ -0,0 +1,174 @@ +From 7a5e03909417ccecc85819837d10cbb6ffe1d759 Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +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 +Reviewed-by: Andrew Lunn +Signed-off-by: Ezequiel Garcia +Signed-off-by: Daniel Lezcano +--- + 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", diff --git a/target/linux/mvebu/patches-3.10/0168-clocksource-armada-370-xp-Introduce-new-compatibles.patch b/target/linux/mvebu/patches-3.10/0168-clocksource-armada-370-xp-Introduce-new-compatibles.patch new file mode 100644 index 0000000000..f028dfabc0 --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0168-clocksource-armada-370-xp-Introduce-new-compatibles.patch @@ -0,0 +1,101 @@ +From 9cb47bf175645d15f97e6d964dd4a4f089275ef5 Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +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 +Signed-off-by: Daniel Lezcano +Reviewed-by: Andrew Lunn +--- + 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 +@@ -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); diff --git a/target/linux/mvebu/patches-3.10/0169-clocksource-armada-370-xp-Replace-WARN_ON-with-BUG_O.patch b/target/linux/mvebu/patches-3.10/0169-clocksource-armada-370-xp-Replace-WARN_ON-with-BUG_O.patch new file mode 100644 index 0000000000..e170760303 --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0169-clocksource-armada-370-xp-Replace-WARN_ON-with-BUG_O.patch @@ -0,0 +1,29 @@ +From bcaac3d9265d751f7d20df6ed0ac24241308dff7 Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +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 +Signed-off-by: Daniel Lezcano +Acked-by: Jason Cooper +Acked-by: Gregory CLEMENT +--- + 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; + diff --git a/target/linux/mvebu/patches-3.10/0170-clocksource-armada-370-xp-Get-reference-fixed-clock-.patch b/target/linux/mvebu/patches-3.10/0170-clocksource-armada-370-xp-Get-reference-fixed-clock-.patch new file mode 100644 index 0000000000..e87f7fc7c5 --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0170-clocksource-armada-370-xp-Get-reference-fixed-clock-.patch @@ -0,0 +1,36 @@ +From 7d7214129f7bde5bb55c0691968407b48f08efb5 Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +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 +Signed-off-by: Daniel Lezcano +Acked-by: Jason Cooper +Acked-by: Gregory CLEMENT +--- + 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); + } diff --git a/target/linux/mvebu/patches-3.10/0171-clocksource-armada-370-xp-Register-sched_clock-after.patch b/target/linux/mvebu/patches-3.10/0171-clocksource-armada-370-xp-Register-sched_clock-after.patch new file mode 100644 index 0000000000..c5b4dcef77 --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0171-clocksource-armada-370-xp-Register-sched_clock-after.patch @@ -0,0 +1,65 @@ +From 3d7976bb4a0f34203456cc0e9054b4a6401c9fdb Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +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 +Signed-off-by: Daniel Lezcano +Acked-by: Jason Cooper +--- + 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); diff --git a/target/linux/mvebu/patches-3.10/0172-ARM-mvebu-Fix-the-Armada-370-XP-timer-compatible-str.patch b/target/linux/mvebu/patches-3.10/0172-ARM-mvebu-Fix-the-Armada-370-XP-timer-compatible-str.patch new file mode 100644 index 0000000000..de409aa5b7 --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0172-ARM-mvebu-Fix-the-Armada-370-XP-timer-compatible-str.patch @@ -0,0 +1,62 @@ +From e33103d8d4cfc513467eb30bc4faee5c91c8e6c2 Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +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 +Signed-off-by: Jason Cooper +--- + 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 { diff --git a/target/linux/mvebu/patches-3.10/0173-ARM-mvebu-Add-the-reference-25-MHz-fixed-clock-to-Ar.patch b/target/linux/mvebu/patches-3.10/0173-ARM-mvebu-Add-the-reference-25-MHz-fixed-clock-to-Ar.patch new file mode 100644 index 0000000000..4f7dd76cda --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0173-ARM-mvebu-Add-the-reference-25-MHz-fixed-clock-to-Ar.patch @@ -0,0 +1,34 @@ +From e4011be91332bacc5cf166e1ce92c3678fc7c646 Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +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 +Reviewed-by: Mike Turquette +Acked-by: Gregory CLEMENT +Signed-off-by: Jason Cooper +--- + 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>; ++ }; ++ }; + }; diff --git a/target/linux/mvebu/patches-3.10/0174-ARM-mvebu-Add-clock-properties-to-Armada-XP-timer-no.patch b/target/linux/mvebu/patches-3.10/0174-ARM-mvebu-Add-clock-properties-to-Armada-XP-timer-no.patch new file mode 100644 index 0000000000..51796bf241 --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0174-ARM-mvebu-Add-clock-properties-to-Armada-XP-timer-no.patch @@ -0,0 +1,30 @@ +From 200b303fc6c2709340996b02ae0c9a7130de7ec3 Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +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 +Reviewed-by: Mike Turquette +Acked-by: Gregory CLEMENT +Signed-off-by: Jason Cooper +--- + 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 { diff --git a/target/linux/mvebu/patches-3.10/0175-ARM-mvebu-Relocate-PCIe-node-in-Armada-370-RD-board.patch b/target/linux/mvebu/patches-3.10/0175-ARM-mvebu-Relocate-PCIe-node-in-Armada-370-RD-board.patch new file mode 100644 index 0000000000..3b37ab93e6 --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0175-ARM-mvebu-Relocate-PCIe-node-in-Armada-370-RD-board.patch @@ -0,0 +1,62 @@ +From 079d1ecae4bd4166a0f89bcb8e0c96bec1b39622 Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +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 +Signed-off-by: Jason Cooper +--- + 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 = ; + ++ 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"; +- }; +- }; + }; + }; + }; diff --git a/target/linux/mvebu/patches-3.10/0176-of-irq-create-interrupts-extended-property.patch b/target/linux/mvebu/patches-3.10/0176-of-irq-create-interrupts-extended-property.patch new file mode 100644 index 0000000000..a31d2d0296 --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0176-of-irq-create-interrupts-extended-property.patch @@ -0,0 +1,104 @@ +From 6dc29d94d92ccc558b946bd57cd8d7cb19d8def1 Mon Sep 17 00:00:00 2001 +From: Grant Likely +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 +Acked-by: Tony Lindgren +Acked-by: Kumar Gala +[grant.likely: removed versatile platform hunks into separate patch] +Cc: Rob Herring + +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) diff --git a/target/linux/mvebu/patches-3.10/0177-of-irq-Avoid-calling-list_first_entry-for-empty-list.patch b/target/linux/mvebu/patches-3.10/0177-of-irq-Avoid-calling-list_first_entry-for-empty-list.patch new file mode 100644 index 0000000000..14b3d13b03 --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0177-of-irq-Avoid-calling-list_first_entry-for-empty-list.patch @@ -0,0 +1,30 @@ +From f159ea8ab3bce09a098d0d56c9e8909f385b87aa Mon Sep 17 00:00:00 2001 +From: Axel Lin +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 +Signed-off-by: Grant Likely +--- + 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; + } diff --git a/target/linux/mvebu/patches-3.10/0178-of-clean-up-ifdefs-in-of_irq.h.patch b/target/linux/mvebu/patches-3.10/0178-of-clean-up-ifdefs-in-of_irq.h.patch new file mode 100644 index 0000000000..57ea574557 --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0178-of-clean-up-ifdefs-in-of_irq.h.patch @@ -0,0 +1,68 @@ +From 704f3796c741df558d624078c5094439c0b65d09 Mon Sep 17 00:00:00 2001 +From: Rob Herring +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 +Cc: Grant Likely +Signed-off-by: Rob Herring +--- + 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 + #include + #include +@@ -10,14 +8,6 @@ struct of_irq; + #include + #include + +-/* +- * 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, diff --git a/target/linux/mvebu/patches-3.10/0179-of-irq-init-struct-resource-to-0-in-of_irq_to_resour.patch b/target/linux/mvebu/patches-3.10/0179-of-irq-init-struct-resource-to-0-in-of_irq_to_resour.patch new file mode 100644 index 0000000000..1e14dbf453 --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0179-of-irq-init-struct-resource-to-0-in-of_irq_to_resour.patch @@ -0,0 +1,27 @@ +From 15a2884ede54118137708ccc72f246fe986f8a57 Mon Sep 17 00:00:00 2001 +From: Sebastian Andrzej Siewior +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 +Signed-off-by: Grant Likely +--- + 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. diff --git a/target/linux/mvebu/patches-3.10/0180-irq-of-Fix-comment-typo-for-irq_of_parse_and_map.patch b/target/linux/mvebu/patches-3.10/0180-irq-of-Fix-comment-typo-for-irq_of_parse_and_map.patch new file mode 100644 index 0000000000..b66a59f6cb --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0180-irq-of-Fix-comment-typo-for-irq_of_parse_and_map.patch @@ -0,0 +1,24 @@ +From 3d73f7a8db8a7506630174d0e8609138d97c8326 Mon Sep 17 00:00:00 2001 +From: Yijing Wang +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 +Signed-off-by: Grant Likely +--- + 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 diff --git a/target/linux/mvebu/patches-3.10/0181-of-Fix-dereferencing-node-name-in-debug-output-to-be.patch b/target/linux/mvebu/patches-3.10/0181-of-Fix-dereferencing-node-name-in-debug-output-to-be.patch new file mode 100644 index 0000000000..ce62d531c2 --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0181-of-Fix-dereferencing-node-name-in-debug-output-to-be.patch @@ -0,0 +1,82 @@ +From 02abb20a226a5a1e5c6dfaaf765dd71a90200cf9 Mon Sep 17 00:00:00 2001 +From: Grant Likely +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 +--- + 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; diff --git a/target/linux/mvebu/patches-3.10/0182-of-irq-Pass-trigger-type-in-IRQ-resource-flags.patch b/target/linux/mvebu/patches-3.10/0182-of-irq-Pass-trigger-type-in-IRQ-resource-flags.patch new file mode 100644 index 0000000000..5363b2e008 --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0182-of-irq-Pass-trigger-type-in-IRQ-resource-flags.patch @@ -0,0 +1,34 @@ +From 4bd60065fb935a5d390c9a442be3a18d2ea18eee Mon Sep 17 00:00:00 2001 +From: Tomasz Figa +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 +[grant.likely: Merged the two assignments to r->flags] +Signed-off-by: Grant Likely +--- + 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); + } + diff --git a/target/linux/mvebu/patches-3.10/0183-of-irq-Rename-of_irq_map_-functions-to-of_irq_parse_.patch b/target/linux/mvebu/patches-3.10/0183-of-irq-Rename-of_irq_map_-functions-to-of_irq_parse_.patch new file mode 100644 index 0000000000..5007d9164d --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0183-of-irq-Rename-of_irq_map_-functions-to-of_irq_parse_.patch @@ -0,0 +1,682 @@ +From fd33285b3dab183df0cea06de9f618886dc0f1c0 Mon Sep 17 00:00:00 2001 +From: Grant Likely +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 +Acked-by: Michal Simek +Acked-by: Tony Lindgren +Cc: Ralf Baechle +Cc: Benjamin Herrenschmidt + +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<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 + + /** +- * 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, diff --git a/target/linux/mvebu/patches-3.10/0184-of-irq-Replace-of_irq-with-of_phandle_args.patch b/target/linux/mvebu/patches-3.10/0184-of-irq-Replace-of_irq-with-of_phandle_args.patch new file mode 100644 index 0000000000..f22da5fa90 --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0184-of-irq-Replace-of_irq-with-of_phandle_args.patch @@ -0,0 +1,486 @@ +From 1baf727ee1d863a0eacd249cff6afc99022593c2 Mon Sep 17 00:00:00 2001 +From: Grant Likely +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 +Acked-by: Michal Simek +Acked-by: Tony Lindgren +Cc: Russell King +Cc: Ralf Baechle +Cc: Benjamin Herrenschmidt + +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 + #include + +-/** +- * 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 + + 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, diff --git a/target/linux/mvebu/patches-3.10/0185-of-irq-simplify-args-to-irq_create_of_mapping.patch b/target/linux/mvebu/patches-3.10/0185-of-irq-simplify-args-to-irq_create_of_mapping.patch new file mode 100644 index 0000000000..2de7e7b674 --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0185-of-irq-simplify-args-to-irq_create_of_mapping.patch @@ -0,0 +1,245 @@ +From 5e69ff59f7e51ddfde0b31587beb9e40ea1c85bc Mon Sep 17 00:00:00 2001 +From: Grant Likely +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 +Acked-by: Michal Simek +Acked-by: Tony Lindgren +Cc: Thomas Gleixner +Cc: Russell King +Cc: Ralf Baechle +Cc: Benjamin Herrenschmidt + +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; + } + diff --git a/target/linux/mvebu/patches-3.10/0186-of-irq-Refactor-interrupt-map-parsing.patch b/target/linux/mvebu/patches-3.10/0186-of-irq-Refactor-interrupt-map-parsing.patch new file mode 100644 index 0000000000..7f17bb737b --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0186-of-irq-Refactor-interrupt-map-parsing.patch @@ -0,0 +1,287 @@ +From 44ad702902e9e274f57edce8944e46540b978f9a Mon Sep 17 00:00:00 2001 +From: Grant Likely +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 +Acked-by: Tony Lindgren +Cc: Benjamin Herrenschmidt +--- + 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); diff --git a/target/linux/mvebu/patches-3.10/0187-of-Add-helper-for-printing-an-of_phandle_args-struct.patch b/target/linux/mvebu/patches-3.10/0187-of-Add-helper-for-printing-an-of_phandle_args-struct.patch new file mode 100644 index 0000000000..064e9a2b16 --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0187-of-Add-helper-for-printing-an-of_phandle_args-struct.patch @@ -0,0 +1,62 @@ +From 061855025b6842debdf6ea2e8bfd86f50700e263 Mon Sep 17 00:00:00 2001 +From: Grant Likely +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 + +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); diff --git a/target/linux/mvebu/patches-3.10/0188-of-irq-Rework-of_irq_count.patch b/target/linux/mvebu/patches-3.10/0188-of-irq-Rework-of_irq_count.patch new file mode 100644 index 0000000000..39fc79488b --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0188-of-irq-Rework-of_irq_count.patch @@ -0,0 +1,36 @@ +From 3665853921092bb68aa0929efb3a94ecdfc96782 Mon Sep 17 00:00:00 2001 +From: Thierry Reding +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 +Acked-by: Rob Herring +[grant.likely: fixup s/of_irq_map_one/of_irq_parse_one/] +Signed-off-by: Grant Likely +--- + 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; diff --git a/target/linux/mvebu/patches-3.10/0189-of-irq-create-interrupts-extended-property.patch b/target/linux/mvebu/patches-3.10/0189-of-irq-create-interrupts-extended-property.patch new file mode 100644 index 0000000000..7e2e2baa33 --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0189-of-irq-create-interrupts-extended-property.patch @@ -0,0 +1,192 @@ +From efd4032754a57bc258eafe30fde684ec47dc36e1 Mon Sep 17 00:00:00 2001 +From: Grant Likely +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 +Acked-by: Tony Lindgren +Acked-by: Kumar Gala +[grant.likely: removed versatile platform hunks into separate patch] +Cc: Rob Herring + +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); diff --git a/target/linux/mvebu/patches-3.10/0190-of-irq-Fix-bug-in-interrupt-parsing-refactor.patch b/target/linux/mvebu/patches-3.10/0190-of-irq-Fix-bug-in-interrupt-parsing-refactor.patch new file mode 100644 index 0000000000..5e1e6053b8 --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0190-of-irq-Fix-bug-in-interrupt-parsing-refactor.patch @@ -0,0 +1,60 @@ +From 1c67d6e7cc30a856e79664e0be3a1f705bad56e4 Mon Sep 17 00:00:00 2001 +From: Grant Likely +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 +Tested-by: Stephen Warren +Tested-by: Ming Lei +Tested-by: Stephen Warren +Cc: Rob Herring + +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 */ diff --git a/target/linux/mvebu/patches-3.10/0191-of-irq-Fix-potential-buffer-overflow.patch b/target/linux/mvebu/patches-3.10/0191-of-irq-Fix-potential-buffer-overflow.patch new file mode 100644 index 0000000000..9c7908d7b9 --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0191-of-irq-Fix-potential-buffer-overflow.patch @@ -0,0 +1,52 @@ +From 5a1bd82f089e19ba049a871a0d5538ed9eb5e5cd Mon Sep 17 00:00:00 2001 +From: Grant Likely +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 +Cc: Rob Herring +--- + 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; + diff --git a/target/linux/mvebu/patches-3.10/0192-of-irq-Fix-interrupt-map-entry-matching.patch b/target/linux/mvebu/patches-3.10/0192-of-irq-Fix-interrupt-map-entry-matching.patch new file mode 100644 index 0000000000..3de0b146dd --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0192-of-irq-Fix-interrupt-map-entry-matching.patch @@ -0,0 +1,26 @@ +From 8413f9010508998c62969827850a7434a1d5716c Mon Sep 17 00:00:00 2001 +From: Tomasz Figa +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 +Tested-by: Sachin Kamat +Signed-off-by: Rob Herring +--- + 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); + diff --git a/target/linux/mvebu/patches-3.10/0193-clocksource-armada-370-xp-Fix-device-tree-binding.patch b/target/linux/mvebu/patches-3.10/0193-clocksource-armada-370-xp-Fix-device-tree-binding.patch new file mode 100644 index 0000000000..4ee7f3f563 --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0193-clocksource-armada-370-xp-Fix-device-tree-binding.patch @@ -0,0 +1,70 @@ +From ba47ab198541f6ed822b3c9691b392d83edba8b4 Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +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 +Reviewed-by: Andrew Lunn +Signed-off-by: Ezequiel Garcia +Signed-off-by: Daniel Lezcano +--- + .../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>; ++ }; diff --git a/target/linux/mvebu/patches-3.10/0194-clocksource-armada-370-xp-Add-detailed-clock-require.patch b/target/linux/mvebu/patches-3.10/0194-clocksource-armada-370-xp-Add-detailed-clock-require.patch new file mode 100644 index 0000000000..333f7b6a9d --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0194-clocksource-armada-370-xp-Add-detailed-clock-require.patch @@ -0,0 +1,47 @@ +From d569707433b26bb70f6b595a480bcfb3043a614c Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +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 +Signed-off-by: Daniel Lezcano +Acked-by: Jason Cooper +Acked-by: Stephen Warren +Acked-by: Gregory CLEMENT +--- + .../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"; + }; diff --git a/target/linux/mvebu/patches-3.10/0195-usb-Add-Device-Tree-support-to-XHCI-Platform-driver.patch b/target/linux/mvebu/patches-3.10/0195-usb-Add-Device-Tree-support-to-XHCI-Platform-driver.patch new file mode 100644 index 0000000000..091c3a10a0 --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0195-usb-Add-Device-Tree-support-to-XHCI-Platform-driver.patch @@ -0,0 +1,68 @@ +From 956b857c1fc80164859adbe1147704b1f352e153 Mon Sep 17 00:00:00 2001 +From: Al Cooper +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 +Cc: Sergei Shtylyov +Cc: Felipe Balbi +Signed-off-by: Sarah Sharp + +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 + #include + #include ++#include + + #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"); diff --git a/target/linux/mvebu/patches-3.10/0196-ata-sata_mv-setting-PHY-speed-according-to-SControl-.patch b/target/linux/mvebu/patches-3.10/0196-ata-sata_mv-setting-PHY-speed-according-to-SControl-.patch new file mode 100644 index 0000000000..8a3162ce96 --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0196-ata-sata_mv-setting-PHY-speed-according-to-SControl-.patch @@ -0,0 +1,58 @@ +From d587c866f34aa8e59ddc3628969113e725e36eab Mon Sep 17 00:00:00 2001 +From: Lior Amsalem +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 +Signed-off-by: Nadav Haklai +Signed-off-by: Simon Guinot +Cc: Thomas Petazzoni +Cc: Jason Cooper +Cc: Andrew Lunn +Cc: Gregory Clement +Cc: Sebastian Hesselbarth +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; diff --git a/target/linux/mvebu/patches-3.10/0197-xhci-fix-dma-mask-setup-in-xhci.c.patch b/target/linux/mvebu/patches-3.10/0197-xhci-fix-dma-mask-setup-in-xhci.c.patch new file mode 100644 index 0000000000..84fcbafb5b --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0197-xhci-fix-dma-mask-setup-in-xhci.c.patch @@ -0,0 +1,124 @@ +From 5cb802766e9cdc9a56e8ce8e4686692ebbcfb5cc Mon Sep 17 00:00:00 2001 +From: Xenia Ragiadakou +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 +Signed-off-by: Sarah Sharp + +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 + #include + #include ++#include + + #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"); diff --git a/target/linux/mvebu/patches-3.10/0198-of-Add-testcases-for-interrupt-parsing.patch b/target/linux/mvebu/patches-3.10/0198-of-Add-testcases-for-interrupt-parsing.patch new file mode 100644 index 0000000000..cbb9252f36 --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0198-of-Add-testcases-for-interrupt-parsing.patch @@ -0,0 +1,104 @@ +From 39623dc5cb8814223e9580e22e78dfab10d91783 Mon Sep 17 00:00:00 2001 +From: Grant Likely +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 +--- + 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 + #include + #include ++#include + #include + #include + #include + #include + +-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"); diff --git a/target/linux/mvebu/patches-3.10/0199-PCI-mvebu-Convert-to-use-devm_ioremap_resource.patch b/target/linux/mvebu/patches-3.10/0199-PCI-mvebu-Convert-to-use-devm_ioremap_resource.patch new file mode 100644 index 0000000000..7f1bdb24d6 --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0199-PCI-mvebu-Convert-to-use-devm_ioremap_resource.patch @@ -0,0 +1,44 @@ +From 508e3a33ebe14ae4444a45b3f65dff5d5e6a4c73 Mon Sep 17 00:00:00 2001 +From: Tushar Behera +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 +Signed-off-by: Bjorn Helgaas +Acked-by: Ezequiel Garcia +--- + drivers/pci/host/pci-mvebu.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +--- a/drivers/pci/host/pci-mvebu.c ++++ b/drivers/pci/host/pci-mvebu.c +@@ -736,9 +736,9 @@ mvebu_pcie_map_registers(struct platform + + ret = of_address_to_resource(np, 0, ®s); + if (ret) +- return NULL; ++ return ERR_PTR(ret); + +- return devm_request_and_ioremap(&pdev->dev, ®s); ++ return devm_ioremap_resource(&pdev->dev, ®s); + } + + static void __init mvebu_pcie_msi_enable(struct mvebu_pcie *pcie) +@@ -897,9 +897,10 @@ static int __init mvebu_pcie_probe(struc + } + + port->base = mvebu_pcie_map_registers(pdev, child, port); +- if (!port->base) { ++ if (IS_ERR(port->base)) { + dev_err(&pdev->dev, "PCIe%d.%d: cannot map registers\n", + port->port, port->lane); ++ port->base = NULL; + continue; + } + diff --git a/target/linux/mvebu/patches-3.10/0200-PCI-mvebu-move-clock-enable-before-register-access.patch b/target/linux/mvebu/patches-3.10/0200-PCI-mvebu-move-clock-enable-before-register-access.patch new file mode 100644 index 0000000000..33fba3db7d --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0200-PCI-mvebu-move-clock-enable-before-register-access.patch @@ -0,0 +1,65 @@ +From c524c5790d413b37702013e7e83a845fd3f007ac Mon Sep 17 00:00:00 2001 +From: Sebastian Hesselbarth +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 +Signed-off-by: Jason Cooper +--- + 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++; + } + diff --git a/target/linux/mvebu/patches-3.10/0201-PCI-mvebu-increment-nports-only-for-registered-ports.patch b/target/linux/mvebu/patches-3.10/0201-PCI-mvebu-increment-nports-only-for-registered-ports.patch new file mode 100644 index 0000000000..810fbe19e7 --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0201-PCI-mvebu-increment-nports-only-for-registered-ports.patch @@ -0,0 +1,47 @@ +From e619fe9eb65d8064739f16eca2015145ac920f13 Mon Sep 17 00:00:00 2001 +From: Sebastian Hesselbarth +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 +Signed-off-by: Jason Cooper +--- + 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; diff --git a/target/linux/mvebu/patches-3.10/0202-ARM-mvebu-second-PCIe-unit-of-Armada-XP-mv78230-is-o.patch b/target/linux/mvebu/patches-3.10/0202-ARM-mvebu-second-PCIe-unit-of-Armada-XP-mv78230-is-o.patch new file mode 100644 index 0000000000..af2a59a671 --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0202-ARM-mvebu-second-PCIe-unit-of-Armada-XP-mv78230-is-o.patch @@ -0,0 +1,85 @@ +From b2ea44bd7bca49fe5696857327a1d1514edd1196 Mon Sep 17 00:00:00 2001 +From: Arnaud Ebalard +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 +Acked-by: Thomas Petazzoni +Cc: # v3.10.x +Signed-off-by: Jason Cooper +--- + 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"; + }; + }; diff --git a/target/linux/mvebu/patches-3.10/0203-ARM-mvebu-fix-second-and-third-PCIe-unit-of-Armada-X.patch b/target/linux/mvebu/patches-3.10/0203-ARM-mvebu-fix-second-and-third-PCIe-unit-of-Armada-X.patch new file mode 100644 index 0000000000..70953bfe55 --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0203-ARM-mvebu-fix-second-and-third-PCIe-unit-of-Armada-X.patch @@ -0,0 +1,180 @@ +From 9c2caf4d2d60780182d7754896c41496192b99c2 Mon Sep 17 00:00:00 2001 +From: Arnaud Ebalard +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 +Acked-by: Thomas Petazzoni +Cc: # v3.10.x +Signed-off-by: Jason Cooper +--- + 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"; + }; + };