From e6e620f0e15e3bc4b3bc3078c9f3285830f2fd3c Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Mon, 22 Jan 2018 10:38:01 +0100 Subject: [PATCH 01/89] mtd: Make sure the device supports erase operations in mtd_erase() Some devices do not implement ->_erase() or have an invalid ->erasesize value. In this case, mtd_erase() should return -ENOTSUPP. Note that the test is not done on the MTD_NO_ERASE flag because this flag means 'erasing a block before writing to it is unnecessary', not 'the erase operation is not supported'. Actually, some drivers are setting the MTD_NO_ERASE flag but still implementing the ->_erase() hook and setting a valid ->erasesize value. Signed-off-by: Boris Brezillon Reviewed-by: Miquel Raynal Signed-off-by: Boris Brezillon --- drivers/mtd/mtdcore.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index 28553c840d32..56cb037a1052 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -971,10 +971,14 @@ EXPORT_SYMBOL_GPL(__put_mtd_device); */ int mtd_erase(struct mtd_info *mtd, struct erase_info *instr) { + if (!mtd->erasesize || !mtd->_erase) + return -ENOTSUPP; + if (instr->addr >= mtd->size || instr->len > mtd->size - instr->addr) return -EINVAL; if (!(mtd->flags & MTD_WRITEABLE)) return -EROFS; + instr->fail_addr = MTD_FAIL_ADDR_UNKNOWN; if (!instr->len) { instr->state = MTD_ERASE_DONE; From 2c77c57d22adb05b21cdb333a0c42bdfa0e19835 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Tue, 16 Jan 2018 16:45:41 +0100 Subject: [PATCH 02/89] mtd: move code adding master MTD out of mtd_add_device_partitions() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This change is a small cleanup of mtd_device_parse_register(). When using MTD_PARTITIONED_MASTER it makes sure a master MTD is registered before dealing with partitions. The advantage of this is not mixing code handling master MTD with code handling partitions. This commit doesn't change any behavior except from a slightly different failure code path. The new code may need to call del_mtd_device when something goes wrong. Signed-off-by: Rafał Miłecki Signed-off-by: Boris Brezillon --- drivers/mtd/mtdcore.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index 56cb037a1052..c6a53a1e55d9 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -646,20 +646,12 @@ static int mtd_add_device_partitions(struct mtd_info *mtd, { const struct mtd_partition *real_parts = parts->parts; int nbparts = parts->nr_parts; - int ret; - if (nbparts == 0 || IS_ENABLED(CONFIG_MTD_PARTITIONED_MASTER)) { - ret = add_mtd_device(mtd); - if (ret) - return ret; - } + if (!nbparts && !device_is_registered(&mtd->dev)) + return add_mtd_device(mtd); - if (nbparts > 0) { - ret = add_mtd_partitions(mtd, real_parts, nbparts); - if (ret && IS_ENABLED(CONFIG_MTD_PARTITIONED_MASTER)) - del_mtd_device(mtd); - return ret; - } + if (nbparts > 0) + return add_mtd_partitions(mtd, real_parts, nbparts); return 0; } @@ -719,6 +711,12 @@ int mtd_device_parse_register(struct mtd_info *mtd, const char * const *types, mtd_set_dev_defaults(mtd); + if (IS_ENABLED(CONFIG_MTD_PARTITIONED_MASTER)) { + ret = add_mtd_device(mtd); + if (ret) + return ret; + } + memset(&parsed, 0, sizeof(parsed)); ret = parse_mtd_partitions(mtd, types, &parsed, parser_data); @@ -758,6 +756,9 @@ int mtd_device_parse_register(struct mtd_info *mtd, const char * const *types, out: /* Cleanup any parsed partitions */ mtd_part_parser_cleanup(&parsed); + if (ret && device_is_registered(&mtd->dev)) + del_mtd_device(mtd); + return ret; } EXPORT_SYMBOL_GPL(mtd_device_parse_register); From 0dbe4ea78d69756efeb0bba0764f6bd4a9ee9567 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Tue, 16 Jan 2018 16:45:42 +0100 Subject: [PATCH 03/89] mtd: get rid of the mtd_add_device_partitions() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This simplifies code a bit by: 1) Avoiding an extra (tiny) function 2) Checking for amount of parsed (found) partitions just once 3) Avoiding clearing/filling struct mtd_partitions manually With this commit proper functions are called directly from the mtd_device_parse_register(). It doesn't need to use minor tricks like memsetting struct to 0 to trigger an expected mtd_add_device_partitions() behavior. Signed-off-by: Rafał Miłecki Signed-off-by: Boris Brezillon --- drivers/mtd/mtdcore.c | 43 ++++++++++++------------------------------- 1 file changed, 12 insertions(+), 31 deletions(-) diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index c6a53a1e55d9..a1c94526fb88 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -641,21 +641,6 @@ out_error: return ret; } -static int mtd_add_device_partitions(struct mtd_info *mtd, - struct mtd_partitions *parts) -{ - const struct mtd_partition *real_parts = parts->parts; - int nbparts = parts->nr_parts; - - if (!nbparts && !device_is_registered(&mtd->dev)) - return add_mtd_device(mtd); - - if (nbparts > 0) - return add_mtd_partitions(mtd, real_parts, nbparts); - - return 0; -} - /* * Set a few defaults based on the parent devices, if not provided by the * driver @@ -706,7 +691,7 @@ int mtd_device_parse_register(struct mtd_info *mtd, const char * const *types, const struct mtd_partition *parts, int nr_parts) { - struct mtd_partitions parsed; + struct mtd_partitions parsed = { }; int ret; mtd_set_dev_defaults(mtd); @@ -717,24 +702,20 @@ int mtd_device_parse_register(struct mtd_info *mtd, const char * const *types, return ret; } - memset(&parsed, 0, sizeof(parsed)); - + /* Prefer parsed partitions over driver-provided fallback */ ret = parse_mtd_partitions(mtd, types, &parsed, parser_data); - if ((ret < 0 || parsed.nr_parts == 0) && parts && nr_parts) { - /* Fall back to driver-provided partitions */ - parsed = (struct mtd_partitions){ - .parts = parts, - .nr_parts = nr_parts, - }; - } else if (ret < 0) { - /* Didn't come up with parsed OR fallback partitions */ - pr_info("mtd: failed to find partitions; one or more parsers reports errors (%d)\n", - ret); - /* Don't abort on errors; we can still use unpartitioned MTD */ - memset(&parsed, 0, sizeof(parsed)); + if (!ret && parsed.nr_parts) { + parts = parsed.parts; + nr_parts = parsed.nr_parts; } - ret = mtd_add_device_partitions(mtd, &parsed); + if (nr_parts) + ret = add_mtd_partitions(mtd, parts, nr_parts); + else if (!device_is_registered(&mtd->dev)) + ret = add_mtd_device(mtd); + else + ret = 0; + if (ret) goto out; From 1549333167edcbab5e8170ae45fbee99eeb4ddb1 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 17 Jan 2018 12:32:06 +0100 Subject: [PATCH 04/89] mtd: nand: mxc: reorder functions to avoid forward declarations We'll call copy_spare() and mxc_do_addr_cycle() from another place during the next patches, so move functions up to avoid forward declarations. Signed-off-by: Sascha Hauer Signed-off-by: Boris Brezillon --- drivers/mtd/nand/mxc_nand.c | 206 ++++++++++++++++++------------------ 1 file changed, 103 insertions(+), 103 deletions(-) diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index f3be0b2a8869..6741af990dc4 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c @@ -252,6 +252,109 @@ static void memcpy16_toio(void __iomem *trg, const void *src, int size) __raw_writew(*s++, t++); } +/* + * The controller splits a page into data chunks of 512 bytes + partial oob. + * There are writesize / 512 such chunks, the size of the partial oob parts is + * oobsize / #chunks rounded down to a multiple of 2. The last oob chunk then + * contains additionally the byte lost by rounding (if any). + * This function handles the needed shuffling between host->data_buf (which + * holds a page in natural order, i.e. writesize bytes data + oobsize bytes + * spare) and the NFC buffer. + */ +static void copy_spare(struct mtd_info *mtd, bool bfrom) +{ + struct nand_chip *this = mtd_to_nand(mtd); + struct mxc_nand_host *host = nand_get_controller_data(this); + u16 i, oob_chunk_size; + u16 num_chunks = mtd->writesize / 512; + + u8 *d = host->data_buf + mtd->writesize; + u8 __iomem *s = host->spare0; + u16 sparebuf_size = host->devtype_data->spare_len; + + /* size of oob chunk for all but possibly the last one */ + oob_chunk_size = (host->used_oobsize / num_chunks) & ~1; + + if (bfrom) { + for (i = 0; i < num_chunks - 1; i++) + memcpy16_fromio(d + i * oob_chunk_size, + s + i * sparebuf_size, + oob_chunk_size); + + /* the last chunk */ + memcpy16_fromio(d + i * oob_chunk_size, + s + i * sparebuf_size, + host->used_oobsize - i * oob_chunk_size); + } else { + for (i = 0; i < num_chunks - 1; i++) + memcpy16_toio(&s[i * sparebuf_size], + &d[i * oob_chunk_size], + oob_chunk_size); + + /* the last chunk */ + memcpy16_toio(&s[i * sparebuf_size], + &d[i * oob_chunk_size], + host->used_oobsize - i * oob_chunk_size); + } +} + +/* + * MXC NANDFC can only perform full page+spare or spare-only read/write. When + * the upper layers perform a read/write buf operation, the saved column address + * is used to index into the full page. So usually this function is called with + * column == 0 (unless no column cycle is needed indicated by column == -1) + */ +static void mxc_do_addr_cycle(struct mtd_info *mtd, int column, int page_addr) +{ + struct nand_chip *nand_chip = mtd_to_nand(mtd); + struct mxc_nand_host *host = nand_get_controller_data(nand_chip); + + /* Write out column address, if necessary */ + if (column != -1) { + host->devtype_data->send_addr(host, column & 0xff, + page_addr == -1); + if (mtd->writesize > 512) + /* another col addr cycle for 2k page */ + host->devtype_data->send_addr(host, + (column >> 8) & 0xff, + false); + } + + /* Write out page address, if necessary */ + if (page_addr != -1) { + /* paddr_0 - p_addr_7 */ + host->devtype_data->send_addr(host, (page_addr & 0xff), false); + + if (mtd->writesize > 512) { + if (mtd->size >= 0x10000000) { + /* paddr_8 - paddr_15 */ + host->devtype_data->send_addr(host, + (page_addr >> 8) & 0xff, + false); + host->devtype_data->send_addr(host, + (page_addr >> 16) & 0xff, + true); + } else + /* paddr_8 - paddr_15 */ + host->devtype_data->send_addr(host, + (page_addr >> 8) & 0xff, true); + } else { + if (nand_chip->options & NAND_ROW_ADDR_3) { + /* paddr_8 - paddr_15 */ + host->devtype_data->send_addr(host, + (page_addr >> 8) & 0xff, + false); + host->devtype_data->send_addr(host, + (page_addr >> 16) & 0xff, + true); + } else + /* paddr_8 - paddr_15 */ + host->devtype_data->send_addr(host, + (page_addr >> 8) & 0xff, true); + } + } +} + static int check_int_v3(struct mxc_nand_host *host) { uint32_t tmp; @@ -772,109 +875,6 @@ static void mxc_nand_select_chip_v2(struct mtd_info *mtd, int chip) writew(host->active_cs << 4, NFC_V1_V2_BUF_ADDR); } -/* - * The controller splits a page into data chunks of 512 bytes + partial oob. - * There are writesize / 512 such chunks, the size of the partial oob parts is - * oobsize / #chunks rounded down to a multiple of 2. The last oob chunk then - * contains additionally the byte lost by rounding (if any). - * This function handles the needed shuffling between host->data_buf (which - * holds a page in natural order, i.e. writesize bytes data + oobsize bytes - * spare) and the NFC buffer. - */ -static void copy_spare(struct mtd_info *mtd, bool bfrom) -{ - struct nand_chip *this = mtd_to_nand(mtd); - struct mxc_nand_host *host = nand_get_controller_data(this); - u16 i, oob_chunk_size; - u16 num_chunks = mtd->writesize / 512; - - u8 *d = host->data_buf + mtd->writesize; - u8 __iomem *s = host->spare0; - u16 sparebuf_size = host->devtype_data->spare_len; - - /* size of oob chunk for all but possibly the last one */ - oob_chunk_size = (host->used_oobsize / num_chunks) & ~1; - - if (bfrom) { - for (i = 0; i < num_chunks - 1; i++) - memcpy16_fromio(d + i * oob_chunk_size, - s + i * sparebuf_size, - oob_chunk_size); - - /* the last chunk */ - memcpy16_fromio(d + i * oob_chunk_size, - s + i * sparebuf_size, - host->used_oobsize - i * oob_chunk_size); - } else { - for (i = 0; i < num_chunks - 1; i++) - memcpy16_toio(&s[i * sparebuf_size], - &d[i * oob_chunk_size], - oob_chunk_size); - - /* the last chunk */ - memcpy16_toio(&s[i * sparebuf_size], - &d[i * oob_chunk_size], - host->used_oobsize - i * oob_chunk_size); - } -} - -/* - * MXC NANDFC can only perform full page+spare or spare-only read/write. When - * the upper layers perform a read/write buf operation, the saved column address - * is used to index into the full page. So usually this function is called with - * column == 0 (unless no column cycle is needed indicated by column == -1) - */ -static void mxc_do_addr_cycle(struct mtd_info *mtd, int column, int page_addr) -{ - struct nand_chip *nand_chip = mtd_to_nand(mtd); - struct mxc_nand_host *host = nand_get_controller_data(nand_chip); - - /* Write out column address, if necessary */ - if (column != -1) { - host->devtype_data->send_addr(host, column & 0xff, - page_addr == -1); - if (mtd->writesize > 512) - /* another col addr cycle for 2k page */ - host->devtype_data->send_addr(host, - (column >> 8) & 0xff, - false); - } - - /* Write out page address, if necessary */ - if (page_addr != -1) { - /* paddr_0 - p_addr_7 */ - host->devtype_data->send_addr(host, (page_addr & 0xff), false); - - if (mtd->writesize > 512) { - if (mtd->size >= 0x10000000) { - /* paddr_8 - paddr_15 */ - host->devtype_data->send_addr(host, - (page_addr >> 8) & 0xff, - false); - host->devtype_data->send_addr(host, - (page_addr >> 16) & 0xff, - true); - } else - /* paddr_8 - paddr_15 */ - host->devtype_data->send_addr(host, - (page_addr >> 8) & 0xff, true); - } else { - if (nand_chip->options & NAND_ROW_ADDR_3) { - /* paddr_8 - paddr_15 */ - host->devtype_data->send_addr(host, - (page_addr >> 8) & 0xff, - false); - host->devtype_data->send_addr(host, - (page_addr >> 16) & 0xff, - true); - } else - /* paddr_8 - paddr_15 */ - host->devtype_data->send_addr(host, - (page_addr >> 8) & 0xff, true); - } - } -} - #define MXC_V1_ECCBYTES 5 static int mxc_v1_ooblayout_ecc(struct mtd_info *mtd, int section, From 040bd3f6a3aa51a7182bba4243428e9df8507146 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 17 Jan 2018 12:32:07 +0100 Subject: [PATCH 05/89] mtd: nand: mxc: Add function to control hardware ECC For proper raw read/write support need to be able to control the hardware ECC engine. Add a function to enable/disable it. Signed-off-by: Sascha Hauer Signed-off-by: Boris Brezillon --- drivers/mtd/nand/mxc_nand.c | 42 +++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index 6741af990dc4..019c58579dbc 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c @@ -154,6 +154,7 @@ struct mxc_nand_devtype_data { u_char *read_ecc, u_char *calc_ecc); int (*setup_data_interface)(struct mtd_info *mtd, int csline, const struct nand_data_interface *conf); + void (*enable_hwecc)(struct nand_chip *chip, bool enable); /* * On i.MX21 the CONFIG2:INT bit cannot be read if interrupts are masked @@ -678,6 +679,42 @@ static uint16_t get_dev_status_v1_v2(struct mxc_nand_host *host) return ret; } +static void mxc_nand_enable_hwecc_v1_v2(struct nand_chip *chip, bool enable) +{ + struct mxc_nand_host *host = nand_get_controller_data(chip); + uint16_t config1; + + if (chip->ecc.mode != NAND_ECC_HW) + return; + + config1 = readw(NFC_V1_V2_CONFIG1); + + if (enable) + config1 |= NFC_V1_V2_CONFIG1_ECC_EN; + else + config1 &= ~NFC_V1_V2_CONFIG1_ECC_EN; + + writew(config1, NFC_V1_V2_CONFIG1); +} + +static void mxc_nand_enable_hwecc_v3(struct nand_chip *chip, bool enable) +{ + struct mxc_nand_host *host = nand_get_controller_data(chip); + uint32_t config2; + + if (chip->ecc.mode != NAND_ECC_HW) + return; + + config2 = readl(NFC_V3_CONFIG2); + + if (enable) + config2 |= NFC_V3_CONFIG2_ECC_EN; + else + config2 &= ~NFC_V3_CONFIG2_ECC_EN; + + writel(config2, NFC_V3_CONFIG2); +} + /* This functions is used by upper layer to checks if device is ready */ static int mxc_nand_dev_ready(struct mtd_info *mtd) { @@ -1408,6 +1445,7 @@ static const struct mxc_nand_devtype_data imx21_nand_devtype_data = { .ooblayout = &mxc_v1_ooblayout_ops, .select_chip = mxc_nand_select_chip_v1_v3, .correct_data = mxc_nand_correct_data_v1, + .enable_hwecc = mxc_nand_enable_hwecc_v1_v2, .irqpending_quirk = 1, .needs_ip = 0, .regs_offset = 0xe00, @@ -1431,6 +1469,7 @@ static const struct mxc_nand_devtype_data imx27_nand_devtype_data = { .ooblayout = &mxc_v1_ooblayout_ops, .select_chip = mxc_nand_select_chip_v1_v3, .correct_data = mxc_nand_correct_data_v1, + .enable_hwecc = mxc_nand_enable_hwecc_v1_v2, .irqpending_quirk = 0, .needs_ip = 0, .regs_offset = 0xe00, @@ -1456,6 +1495,7 @@ static const struct mxc_nand_devtype_data imx25_nand_devtype_data = { .select_chip = mxc_nand_select_chip_v2, .correct_data = mxc_nand_correct_data_v2_v3, .setup_data_interface = mxc_nand_v2_setup_data_interface, + .enable_hwecc = mxc_nand_enable_hwecc_v1_v2, .irqpending_quirk = 0, .needs_ip = 0, .regs_offset = 0x1e00, @@ -1480,6 +1520,7 @@ static const struct mxc_nand_devtype_data imx51_nand_devtype_data = { .ooblayout = &mxc_v2_ooblayout_ops, .select_chip = mxc_nand_select_chip_v1_v3, .correct_data = mxc_nand_correct_data_v2_v3, + .enable_hwecc = mxc_nand_enable_hwecc_v3, .irqpending_quirk = 0, .needs_ip = 1, .regs_offset = 0, @@ -1505,6 +1546,7 @@ static const struct mxc_nand_devtype_data imx53_nand_devtype_data = { .ooblayout = &mxc_v2_ooblayout_ops, .select_chip = mxc_nand_select_chip_v1_v3, .correct_data = mxc_nand_correct_data_v2_v3, + .enable_hwecc = mxc_nand_enable_hwecc_v3, .irqpending_quirk = 0, .needs_ip = 1, .regs_offset = 0, From 1af0b3147448954c50e555496b80d94a0800a5e4 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 17 Jan 2018 12:32:08 +0100 Subject: [PATCH 06/89] mtd: nand: mxc: Add buffer argument to copy_spare With following patches we will have to copy the spare data to/from other buffers, so add the buffer as argument to copy_spare(). Signed-off-by: Sascha Hauer Signed-off-by: Boris Brezillon --- drivers/mtd/nand/mxc_nand.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index 019c58579dbc..ab9cd45237d3 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c @@ -262,14 +262,14 @@ static void memcpy16_toio(void __iomem *trg, const void *src, int size) * holds a page in natural order, i.e. writesize bytes data + oobsize bytes * spare) and the NFC buffer. */ -static void copy_spare(struct mtd_info *mtd, bool bfrom) +static void copy_spare(struct mtd_info *mtd, bool bfrom, void *buf) { struct nand_chip *this = mtd_to_nand(mtd); struct mxc_nand_host *host = nand_get_controller_data(this); u16 i, oob_chunk_size; u16 num_chunks = mtd->writesize / 512; - u8 *d = host->data_buf + mtd->writesize; + u8 *d = buf; u8 __iomem *s = host->spare0; u16 sparebuf_size = host->devtype_data->spare_len; @@ -1295,7 +1295,7 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command, memcpy32_fromio(host->data_buf, host->main_area0, mtd->writesize); - copy_spare(mtd, true); + copy_spare(mtd, true, host->data_buf + mtd->writesize); break; case NAND_CMD_SEQIN: @@ -1314,7 +1314,7 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command, case NAND_CMD_PAGEPROG: memcpy32_toio(host->main_area0, host->data_buf, mtd->writesize); - copy_spare(mtd, false); + copy_spare(mtd, false, host->data_buf + mtd->writesize); host->devtype_data->send_page(mtd, NFC_INPUT); host->devtype_data->send_cmd(host, command, true); WARN_ONCE(column != -1 || page_addr != -1, From 67b87f66cae0bca0dd6602739383381c10b0c9c4 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 17 Jan 2018 12:32:09 +0100 Subject: [PATCH 07/89] mtd: nand: mxc: Fix failed/corrected values for v2/v3 controllers Currently nand_read_page_hwecc() from nand_base calls mxc_nand_correct_data_v2_v3() for each subpage, but in this function we return the corrected/failed results for the whole page instead of a single subpage. On a 2k page size Nand this leads to results which are 4 times too high. The whole ecc.calculate/ecc.correct mechanism used by nand_read_page_hwecc() is not suitable for devices which correct the data in hardware, so fix this by using a driver specific read_page function which does the right thing. Also add read_page_raw and read_oob For proper raw and oob read support. Signed-off-by: Sascha Hauer Signed-off-by: Boris Brezillon --- drivers/mtd/nand/mxc_nand.c | 86 +++++++++++++++++++++++++++++++++---- 1 file changed, 77 insertions(+), 9 deletions(-) diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index ab9cd45237d3..48804320056f 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c @@ -140,6 +140,8 @@ struct mxc_nand_host; struct mxc_nand_devtype_data { void (*preset)(struct mtd_info *); + int (*read_page)(struct nand_chip *chip, void *buf, void *oob, bool ecc, + int page); void (*send_cmd)(struct mxc_nand_host *, uint16_t, int); void (*send_addr)(struct mxc_nand_host *, uint16_t, int); void (*send_page)(struct mtd_info *, unsigned int); @@ -757,13 +759,35 @@ static int mxc_nand_correct_data_v1(struct mtd_info *mtd, u_char *dat, static int mxc_nand_correct_data_v2_v3(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc) { - struct nand_chip *nand_chip = mtd_to_nand(mtd); - struct mxc_nand_host *host = nand_get_controller_data(nand_chip); + return 0; +} + +static int mxc_nand_read_page_v2_v3(struct nand_chip *chip, void *buf, + void *oob, bool ecc, int page) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + struct mxc_nand_host *host = nand_get_controller_data(chip); + unsigned int max_bitflips = 0; u32 ecc_stat, err; - int no_subpages = 1; - int ret = 0; + int no_subpages; u8 ecc_bit_mask, err_limit; + host->devtype_data->enable_hwecc(chip, ecc); + + host->devtype_data->send_cmd(host, NAND_CMD_READ0, false); + mxc_do_addr_cycle(mtd, 0, page); + + if (mtd->writesize > 512) + host->devtype_data->send_cmd(host, + NAND_CMD_READSTART, true); + + host->devtype_data->send_page(mtd, NFC_OUTPUT); + + if (buf) + memcpy32_fromio(buf, host->main_area0, mtd->writesize); + if (oob) + copy_spare(mtd, true, oob); + ecc_bit_mask = (host->eccsize == 4) ? 0x7 : 0xf; err_limit = (host->eccsize == 4) ? 0x4 : 0x8; @@ -774,17 +798,53 @@ static int mxc_nand_correct_data_v2_v3(struct mtd_info *mtd, u_char *dat, do { err = ecc_stat & ecc_bit_mask; if (err > err_limit) { - dev_dbg(host->dev, "UnCorrectable RS-ECC Error\n"); - return -EBADMSG; + mtd->ecc_stats.failed++; } else { - ret += err; + mtd->ecc_stats.corrected += err; + max_bitflips = max_t(unsigned int, max_bitflips, err); } + ecc_stat >>= 4; } while (--no_subpages); - dev_dbg(host->dev, "%d Symbol Correctable RS-ECC Error\n", ret); + return max_bitflips; +} - return ret; +static int mxc_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip, + uint8_t *buf, int oob_required, int page) +{ + struct mxc_nand_host *host = nand_get_controller_data(chip); + void *oob_buf; + + if (oob_required) + oob_buf = chip->oob_poi; + else + oob_buf = NULL; + + return host->devtype_data->read_page(chip, buf, oob_buf, 1, page); +} + +static int mxc_nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, + uint8_t *buf, int oob_required, int page) +{ + struct mxc_nand_host *host = nand_get_controller_data(chip); + void *oob_buf; + + if (oob_required) + oob_buf = chip->oob_poi; + else + oob_buf = NULL; + + return host->devtype_data->read_page(chip, buf, oob_buf, 0, page); +} + +static int mxc_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip, + int page) +{ + struct mxc_nand_host *host = nand_get_controller_data(chip); + + return host->devtype_data->read_page(chip, NULL, chip->oob_poi, 0, + page); } static int mxc_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, @@ -1483,6 +1543,7 @@ static const struct mxc_nand_devtype_data imx27_nand_devtype_data = { /* v21: i.MX25, i.MX35 */ static const struct mxc_nand_devtype_data imx25_nand_devtype_data = { .preset = preset_v2, + .read_page = mxc_nand_read_page_v2_v3, .send_cmd = send_cmd_v1_v2, .send_addr = send_addr_v1_v2, .send_page = send_page_v2, @@ -1509,6 +1570,7 @@ static const struct mxc_nand_devtype_data imx25_nand_devtype_data = { /* v3.2a: i.MX51 */ static const struct mxc_nand_devtype_data imx51_nand_devtype_data = { .preset = preset_v3, + .read_page = mxc_nand_read_page_v2_v3, .send_cmd = send_cmd_v3, .send_addr = send_addr_v3, .send_page = send_page_v3, @@ -1535,6 +1597,7 @@ static const struct mxc_nand_devtype_data imx51_nand_devtype_data = { /* v3.2b: i.MX53 */ static const struct mxc_nand_devtype_data imx53_nand_devtype_data = { .preset = preset_v3, + .read_page = mxc_nand_read_page_v2_v3, .send_cmd = send_cmd_v3, .send_addr = send_addr_v3, .send_page = send_page_v3, @@ -1793,6 +1856,11 @@ static int mxcnd_probe(struct platform_device *pdev) switch (this->ecc.mode) { case NAND_ECC_HW: + if (host->devtype_data->read_page) { + this->ecc.read_page = mxc_nand_read_page; + this->ecc.read_page_raw = mxc_nand_read_page_raw; + this->ecc.read_oob = mxc_nand_read_oob; + } this->ecc.calculate = mxc_nand_calculate_ecc; this->ecc.hwctl = mxc_nand_enable_hwecc; this->ecc.correct = host->devtype_data->correct_data; From 5039fc9f2d6db603cba48c770e29251d661ce4e2 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 17 Jan 2018 12:32:10 +0100 Subject: [PATCH 08/89] mtd: nand: mxc: Fix failed/corrected values for v1 controllers The v1 controller code has several flaws: - We do not forward the number of corrected bitflips to the upper layers - For 2k page NAND chips only the status results from the fourth subpage read are evaluated, so ECC failures in the other subpages remain uncovered - When there are uncorrectable errors we have to increase the statistics counter, but still have to return successfully. Currently we return an error This patch fixes this by introducing a v1 specific read_page function. Signed-off-by: Sascha Hauer Signed-off-by: Boris Brezillon --- drivers/mtd/nand/mxc_nand.c | 77 +++++++++++++++++++++++++++++-------- 1 file changed, 60 insertions(+), 17 deletions(-) diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index 48804320056f..49885afbcf43 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c @@ -738,22 +738,65 @@ static void mxc_nand_enable_hwecc(struct mtd_info *mtd, int mode) static int mxc_nand_correct_data_v1(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc) { - struct nand_chip *nand_chip = mtd_to_nand(mtd); - struct mxc_nand_host *host = nand_get_controller_data(nand_chip); + return 0; +} - /* - * 1-Bit errors are automatically corrected in HW. No need for - * additional correction. 2-Bit errors cannot be corrected by - * HW ECC, so we need to return failure - */ - uint16_t ecc_status = get_ecc_status_v1(host); +static int mxc_nand_read_page_v1(struct nand_chip *chip, void *buf, void *oob, + bool ecc, int page) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + struct mxc_nand_host *host = nand_get_controller_data(chip); + unsigned int bitflips_corrected = 0; + int no_subpages; + int i; - if (((ecc_status & 0x3) == 2) || ((ecc_status >> 2) == 2)) { - dev_dbg(host->dev, "HWECC uncorrectable 2-bit ECC error\n"); - return -EBADMSG; + host->devtype_data->enable_hwecc(chip, ecc); + + host->devtype_data->send_cmd(host, NAND_CMD_READ0, false); + mxc_do_addr_cycle(mtd, 0, page); + + if (mtd->writesize > 512) + host->devtype_data->send_cmd(host, NAND_CMD_READSTART, true); + + no_subpages = mtd->writesize >> 9; + + for (i = 0; i < no_subpages; i++) { + uint16_t ecc_stats; + + /* NANDFC buffer 0 is used for page read/write */ + writew((host->active_cs << 4) | i, NFC_V1_V2_BUF_ADDR); + + writew(NFC_OUTPUT, NFC_V1_V2_CONFIG2); + + /* Wait for operation to complete */ + wait_op_done(host, true); + + ecc_stats = get_ecc_status_v1(host); + + ecc_stats >>= 2; + + if (buf && ecc) { + switch (ecc_stats & 0x3) { + case 0: + default: + break; + case 1: + mtd->ecc_stats.corrected++; + bitflips_corrected = 1; + break; + case 2: + mtd->ecc_stats.failed++; + break; + } + } } - return 0; + if (buf) + memcpy32_fromio(buf, host->main_area0, mtd->writesize); + if (oob) + copy_spare(mtd, true, oob); + + return bitflips_corrected; } static int mxc_nand_correct_data_v2_v3(struct mtd_info *mtd, u_char *dat, @@ -1494,6 +1537,7 @@ static struct nand_bbt_descr bbt_mirror_descr = { /* v1 + irqpending_quirk: i.MX21 */ static const struct mxc_nand_devtype_data imx21_nand_devtype_data = { .preset = preset_v1, + .read_page = mxc_nand_read_page_v1, .send_cmd = send_cmd_v1_v2, .send_addr = send_addr_v1_v2, .send_page = send_page_v1, @@ -1518,6 +1562,7 @@ static const struct mxc_nand_devtype_data imx21_nand_devtype_data = { /* v1 + !irqpending_quirk: i.MX27, i.MX31 */ static const struct mxc_nand_devtype_data imx27_nand_devtype_data = { .preset = preset_v1, + .read_page = mxc_nand_read_page_v1, .send_cmd = send_cmd_v1_v2, .send_addr = send_addr_v1_v2, .send_page = send_page_v1, @@ -1856,11 +1901,9 @@ static int mxcnd_probe(struct platform_device *pdev) switch (this->ecc.mode) { case NAND_ECC_HW: - if (host->devtype_data->read_page) { - this->ecc.read_page = mxc_nand_read_page; - this->ecc.read_page_raw = mxc_nand_read_page_raw; - this->ecc.read_oob = mxc_nand_read_oob; - } + this->ecc.read_page = mxc_nand_read_page; + this->ecc.read_page_raw = mxc_nand_read_page_raw; + this->ecc.read_oob = mxc_nand_read_oob; this->ecc.calculate = mxc_nand_calculate_ecc; this->ecc.hwctl = mxc_nand_enable_hwecc; this->ecc.correct = host->devtype_data->correct_data; From 6811c4642aa0b40e3199aa7fb86053be1ee10ad8 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 17 Jan 2018 12:32:11 +0100 Subject: [PATCH 09/89] mtd: nand: mxc: Add own write_page Now that we have our own read_page function add a write_page function for consistency aswell. This can be a lot easier than the generic function since we do not have to iterate over subpages but can write the whole page at once. Also add write_page_raw and write_oob for proper raw and oob write support. Signed-off-by: Sascha Hauer Signed-off-by: Boris Brezillon --- drivers/mtd/nand/mxc_nand.c | 47 +++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index 49885afbcf43..2811102b0469 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c @@ -890,6 +890,50 @@ static int mxc_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip, page); } +static int mxc_nand_write_page(struct nand_chip *chip, const uint8_t *buf, + bool ecc, int page) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + struct mxc_nand_host *host = nand_get_controller_data(chip); + + host->devtype_data->enable_hwecc(chip, ecc); + + host->devtype_data->send_cmd(host, NAND_CMD_SEQIN, false); + mxc_do_addr_cycle(mtd, 0, page); + + memcpy32_toio(host->main_area0, buf, mtd->writesize); + copy_spare(mtd, false, chip->oob_poi); + + host->devtype_data->send_page(mtd, NFC_INPUT); + host->devtype_data->send_cmd(host, NAND_CMD_PAGEPROG, true); + mxc_do_addr_cycle(mtd, 0, page); + + return 0; +} + +static int mxc_nand_write_page_ecc(struct mtd_info *mtd, struct nand_chip *chip, + const uint8_t *buf, int oob_required, + int page) +{ + return mxc_nand_write_page(chip, buf, true, page); +} + +static int mxc_nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, + const uint8_t *buf, int oob_required, int page) +{ + return mxc_nand_write_page(chip, buf, false, page); +} + +static int mxc_nand_write_oob(struct mtd_info *mtd, struct nand_chip *chip, + int page) +{ + struct mxc_nand_host *host = nand_get_controller_data(chip); + + memset(host->data_buf, 0xff, mtd->writesize); + + return mxc_nand_write_page(chip, host->data_buf, false, page); +} + static int mxc_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code) { @@ -1904,6 +1948,9 @@ static int mxcnd_probe(struct platform_device *pdev) this->ecc.read_page = mxc_nand_read_page; this->ecc.read_page_raw = mxc_nand_read_page_raw; this->ecc.read_oob = mxc_nand_read_oob; + this->ecc.write_page = mxc_nand_write_page_ecc; + this->ecc.write_page_raw = mxc_nand_write_page_raw; + this->ecc.write_oob = mxc_nand_write_oob; this->ecc.calculate = mxc_nand_calculate_ecc; this->ecc.hwctl = mxc_nand_enable_hwecc; this->ecc.correct = host->devtype_data->correct_data; From cd8b4655332d45b1507a7cf1db025b869d0eb89a Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 17 Jan 2018 12:32:12 +0100 Subject: [PATCH 10/89] mtd: nand: mxc: Drop now unnecessary functions Since we have our own read_page/write_page functions correct_data and calculate are no longer needed. Remove them. Signed-off-by: Sascha Hauer Signed-off-by: Boris Brezillon --- drivers/mtd/nand/mxc_nand.c | 36 ------------------------------------ 1 file changed, 36 deletions(-) diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index 2811102b0469..a7c4fdd1988e 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c @@ -152,8 +152,6 @@ struct mxc_nand_devtype_data { u32 (*get_ecc_status)(struct mxc_nand_host *); const struct mtd_ooblayout_ops *ooblayout; void (*select_chip)(struct mtd_info *mtd, int chip); - int (*correct_data)(struct mtd_info *mtd, u_char *dat, - u_char *read_ecc, u_char *calc_ecc); int (*setup_data_interface)(struct mtd_info *mtd, int csline, const struct nand_data_interface *conf); void (*enable_hwecc)(struct nand_chip *chip, bool enable); @@ -727,20 +725,6 @@ static int mxc_nand_dev_ready(struct mtd_info *mtd) return 1; } -static void mxc_nand_enable_hwecc(struct mtd_info *mtd, int mode) -{ - /* - * If HW ECC is enabled, we turn it on during init. There is - * no need to enable again here. - */ -} - -static int mxc_nand_correct_data_v1(struct mtd_info *mtd, u_char *dat, - u_char *read_ecc, u_char *calc_ecc) -{ - return 0; -} - static int mxc_nand_read_page_v1(struct nand_chip *chip, void *buf, void *oob, bool ecc, int page) { @@ -799,12 +783,6 @@ static int mxc_nand_read_page_v1(struct nand_chip *chip, void *buf, void *oob, return bitflips_corrected; } -static int mxc_nand_correct_data_v2_v3(struct mtd_info *mtd, u_char *dat, - u_char *read_ecc, u_char *calc_ecc) -{ - return 0; -} - static int mxc_nand_read_page_v2_v3(struct nand_chip *chip, void *buf, void *oob, bool ecc, int page) { @@ -934,12 +912,6 @@ static int mxc_nand_write_oob(struct mtd_info *mtd, struct nand_chip *chip, return mxc_nand_write_page(chip, host->data_buf, false, page); } -static int mxc_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, - u_char *ecc_code) -{ - return 0; -} - static u_char mxc_nand_read_byte(struct mtd_info *mtd) { struct nand_chip *nand_chip = mtd_to_nand(mtd); @@ -1592,7 +1564,6 @@ static const struct mxc_nand_devtype_data imx21_nand_devtype_data = { .get_ecc_status = get_ecc_status_v1, .ooblayout = &mxc_v1_ooblayout_ops, .select_chip = mxc_nand_select_chip_v1_v3, - .correct_data = mxc_nand_correct_data_v1, .enable_hwecc = mxc_nand_enable_hwecc_v1_v2, .irqpending_quirk = 1, .needs_ip = 0, @@ -1617,7 +1588,6 @@ static const struct mxc_nand_devtype_data imx27_nand_devtype_data = { .get_ecc_status = get_ecc_status_v1, .ooblayout = &mxc_v1_ooblayout_ops, .select_chip = mxc_nand_select_chip_v1_v3, - .correct_data = mxc_nand_correct_data_v1, .enable_hwecc = mxc_nand_enable_hwecc_v1_v2, .irqpending_quirk = 0, .needs_ip = 0, @@ -1643,7 +1613,6 @@ static const struct mxc_nand_devtype_data imx25_nand_devtype_data = { .get_ecc_status = get_ecc_status_v2, .ooblayout = &mxc_v2_ooblayout_ops, .select_chip = mxc_nand_select_chip_v2, - .correct_data = mxc_nand_correct_data_v2_v3, .setup_data_interface = mxc_nand_v2_setup_data_interface, .enable_hwecc = mxc_nand_enable_hwecc_v1_v2, .irqpending_quirk = 0, @@ -1670,7 +1639,6 @@ static const struct mxc_nand_devtype_data imx51_nand_devtype_data = { .get_ecc_status = get_ecc_status_v3, .ooblayout = &mxc_v2_ooblayout_ops, .select_chip = mxc_nand_select_chip_v1_v3, - .correct_data = mxc_nand_correct_data_v2_v3, .enable_hwecc = mxc_nand_enable_hwecc_v3, .irqpending_quirk = 0, .needs_ip = 1, @@ -1697,7 +1665,6 @@ static const struct mxc_nand_devtype_data imx53_nand_devtype_data = { .get_ecc_status = get_ecc_status_v3, .ooblayout = &mxc_v2_ooblayout_ops, .select_chip = mxc_nand_select_chip_v1_v3, - .correct_data = mxc_nand_correct_data_v2_v3, .enable_hwecc = mxc_nand_enable_hwecc_v3, .irqpending_quirk = 0, .needs_ip = 1, @@ -1951,9 +1918,6 @@ static int mxcnd_probe(struct platform_device *pdev) this->ecc.write_page = mxc_nand_write_page_ecc; this->ecc.write_page_raw = mxc_nand_write_page_raw; this->ecc.write_oob = mxc_nand_write_oob; - this->ecc.calculate = mxc_nand_calculate_ecc; - this->ecc.hwctl = mxc_nand_enable_hwecc; - this->ecc.correct = host->devtype_data->correct_data; break; case NAND_ECC_SOFT: From 68dc8e41fdffcc26db8185dd336ee1ff91872770 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 17 Jan 2018 12:32:13 +0100 Subject: [PATCH 11/89] mtd: nand: mxc: remove now unused code Since we now have our own read_page/write_page functions mxc_nand_command() will no longer be called with NAND_CMD_READ0, NAND_CMD_READOOB, NAND_CMD_SEQIN and NAND_CMD_PAGEPROG. Remove the code handling these commands. Signed-off-by: Sascha Hauer Signed-off-by: Boris Brezillon --- drivers/mtd/nand/mxc_nand.c | 51 ------------------------------------- 1 file changed, 51 deletions(-) diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index a7c4fdd1988e..87b5ee66e501 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c @@ -1391,57 +1391,6 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command, mxc_do_addr_cycle(mtd, column, page_addr); break; - case NAND_CMD_READ0: - case NAND_CMD_READOOB: - if (command == NAND_CMD_READ0) - host->buf_start = column; - else - host->buf_start = column + mtd->writesize; - - command = NAND_CMD_READ0; /* only READ0 is valid */ - - host->devtype_data->send_cmd(host, command, false); - WARN_ONCE(column < 0, - "Unexpected column/row value (cmd=%u, col=%d, row=%d)\n", - command, column, page_addr); - mxc_do_addr_cycle(mtd, 0, page_addr); - - if (mtd->writesize > 512) - host->devtype_data->send_cmd(host, - NAND_CMD_READSTART, true); - - host->devtype_data->send_page(mtd, NFC_OUTPUT); - - memcpy32_fromio(host->data_buf, host->main_area0, - mtd->writesize); - copy_spare(mtd, true, host->data_buf + mtd->writesize); - break; - - case NAND_CMD_SEQIN: - if (column >= mtd->writesize) - /* call ourself to read a page */ - mxc_nand_command(mtd, NAND_CMD_READ0, 0, page_addr); - - host->buf_start = column; - - host->devtype_data->send_cmd(host, command, false); - WARN_ONCE(column < -1, - "Unexpected column/row value (cmd=%u, col=%d, row=%d)\n", - command, column, page_addr); - mxc_do_addr_cycle(mtd, 0, page_addr); - break; - - case NAND_CMD_PAGEPROG: - memcpy32_toio(host->main_area0, host->data_buf, mtd->writesize); - copy_spare(mtd, false, host->data_buf + mtd->writesize); - host->devtype_data->send_page(mtd, NFC_INPUT); - host->devtype_data->send_cmd(host, command, true); - WARN_ONCE(column != -1 || page_addr != -1, - "Unexpected column/row value (cmd=%u, col=%d, row=%d)\n", - command, column, page_addr); - mxc_do_addr_cycle(mtd, column, page_addr); - break; - case NAND_CMD_READID: host->devtype_data->send_cmd(host, command, true); mxc_do_addr_cycle(mtd, column, page_addr); From 07ad5a7214841704e71540493a00041fd7f4e3af Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Wed, 17 Jan 2018 00:19:34 +0100 Subject: [PATCH 12/89] mtd: nand: add ->setup_data_interface() support for Marvell NFCv1 First generation of Marvell NAND flash controllers (eg. embedded in PXA boards) did not make use of the NAND core hook ->setup_data_interface() to setup controller timings. Add support for it. Signed-off-by: Miquel Raynal Signed-off-by: Boris Brezillon --- drivers/mtd/nand/marvell_nand.c | 39 ++++++++++++++++++++++++--------- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/drivers/mtd/nand/marvell_nand.c b/drivers/mtd/nand/marvell_nand.c index 2196f2a233d6..cc21f9633edd 100644 --- a/drivers/mtd/nand/marvell_nand.c +++ b/drivers/mtd/nand/marvell_nand.c @@ -379,6 +379,8 @@ struct marvell_nfc_timings { * return the number of clock periods. */ #define TO_CYCLES(ps, period_ns) (DIV_ROUND_UP(ps / 1000, period_ns)) +#define TO_CYCLES64(ps, period_ns) (DIV_ROUND_UP_ULL(div_u64(ps, 1000), \ + period_ns)) /** * NAND driver structure filled during the parsing of the ->exec_op() subop @@ -2236,8 +2238,20 @@ static int marvell_nfc_setup_data_interface(struct mtd_info *mtd, int chipnr, nfc_tmg.tRHW = TO_CYCLES(max_t(int, sdr->tRHW_min, sdr->tCCS_min), period_ns); - /* Use WAIT_MODE (wait for RB line) instead of only relying on delays */ - nfc_tmg.tR = TO_CYCLES(sdr->tWB_max, period_ns); + /* + * NFCv2: Use WAIT_MODE (wait for RB line), do not rely only on delays. + * NFCv1: No WAIT_MODE, tR must be maximal. + */ + if (nfc->caps->is_nfcv2) { + nfc_tmg.tR = TO_CYCLES(sdr->tWB_max, period_ns); + } else { + nfc_tmg.tR = TO_CYCLES64(sdr->tWB_max + sdr->tR_max, + period_ns); + if (nfc_tmg.tR + 3 > nfc_tmg.tCH) + nfc_tmg.tR = nfc_tmg.tCH - 3; + else + nfc_tmg.tR = 0; + } if (chipnr < 0) return 0; @@ -2249,18 +2263,24 @@ static int marvell_nfc_setup_data_interface(struct mtd_info *mtd, int chipnr, NDTR0_TWP(nfc_tmg.tWP) | NDTR0_TWH(nfc_tmg.tWH) | NDTR0_TCS(nfc_tmg.tCS) | - NDTR0_TCH(nfc_tmg.tCH) | - NDTR0_RD_CNT_DEL(read_delay) | - NDTR0_SELCNTR | - NDTR0_TADL(nfc_tmg.tADL); + NDTR0_TCH(nfc_tmg.tCH); marvell_nand->ndtr1 = NDTR1_TAR(nfc_tmg.tAR) | NDTR1_TWHR(nfc_tmg.tWHR) | - NDTR1_TRHW(nfc_tmg.tRHW) | - NDTR1_WAIT_MODE | NDTR1_TR(nfc_tmg.tR); + if (nfc->caps->is_nfcv2) { + marvell_nand->ndtr0 |= + NDTR0_RD_CNT_DEL(read_delay) | + NDTR0_SELCNTR | + NDTR0_TADL(nfc_tmg.tADL); + + marvell_nand->ndtr1 |= + NDTR1_TRHW(nfc_tmg.tRHW) | + NDTR1_WAIT_MODE; + } + return 0; } @@ -2395,8 +2415,7 @@ static int marvell_nand_chip_init(struct device *dev, struct marvell_nfc *nfc, chip->exec_op = marvell_nfc_exec_op; chip->select_chip = marvell_nfc_select_chip; - if (nfc->caps->is_nfcv2 && - !of_property_read_bool(np, "marvell,nand-keep-config")) + if (!of_property_read_bool(np, "marvell,nand-keep-config")) chip->setup_data_interface = marvell_nfc_setup_data_interface; mtd = nand_to_mtd(chip); From 532a1cf9a0f22f1a8699284e74aecf0bda3ffd29 Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Fri, 9 Feb 2018 00:59:19 +0100 Subject: [PATCH 13/89] mtd: nand: vf610_nfc: remove unused function The function count_written_bits has been replaced by the generic nand_check_erased_ecc_chunk() function with commit 48c25cf44118 ("mtd: nand: vf610_nfc: use nand_check_erased_ecc_chunk() helper"). Remove the unused function. Signed-off-by: Stefan Agner Signed-off-by: Boris Brezillon --- drivers/mtd/nand/vf610_nfc.c | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/drivers/mtd/nand/vf610_nfc.c b/drivers/mtd/nand/vf610_nfc.c index 80d31a58e558..2fa61cbdbaf7 100644 --- a/drivers/mtd/nand/vf610_nfc.c +++ b/drivers/mtd/nand/vf610_nfc.c @@ -511,21 +511,6 @@ static void vf610_nfc_select_chip(struct mtd_info *mtd, int chip) vf610_nfc_write(nfc, NFC_ROW_ADDR, tmp); } -/* Count the number of 0's in buff up to max_bits */ -static inline int count_written_bits(uint8_t *buff, int size, int max_bits) -{ - uint32_t *buff32 = (uint32_t *)buff; - int k, written_bits = 0; - - for (k = 0; k < (size / 4); k++) { - written_bits += hweight32(~buff32[k]); - if (unlikely(written_bits > max_bits)) - break; - } - - return written_bits; -} - static inline int vf610_nfc_correct_data(struct mtd_info *mtd, uint8_t *dat, uint8_t *oob, int page) { From f5a666bdd585b47bea60cec3cb5f4d9fbbc6e409 Mon Sep 17 00:00:00 2001 From: Alexey Khoroshilov Date: Sat, 10 Feb 2018 01:28:34 +0300 Subject: [PATCH 14/89] mtd: nand: vf610: remove the unnecessary of_node_put() Calling of_node_put() in vf610_nfc_probe() is wrong because nothing in this code retains a reference to the DT node. Signed-off-by: Alexey Khoroshilov Reviewed-by: Stefan Agner Signed-off-by: Boris Brezillon --- drivers/mtd/nand/vf610_nfc.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/drivers/mtd/nand/vf610_nfc.c b/drivers/mtd/nand/vf610_nfc.c index 2fa61cbdbaf7..9c6d87d282c3 100644 --- a/drivers/mtd/nand/vf610_nfc.c +++ b/drivers/mtd/nand/vf610_nfc.c @@ -667,7 +667,7 @@ static int vf610_nfc_probe(struct platform_device *pdev) dev_err(nfc->dev, "Only one NAND chip supported!\n"); err = -EINVAL; - goto error; + goto err_clk; } nand_set_flash_node(chip, child); @@ -697,7 +697,7 @@ static int vf610_nfc_probe(struct platform_device *pdev) err = devm_request_irq(nfc->dev, irq, vf610_nfc_irq, 0, DRV_NAME, mtd); if (err) { dev_err(nfc->dev, "Error requesting IRQ!\n"); - goto error; + goto err_clk; } vf610_nfc_preinit_controller(nfc); @@ -705,7 +705,7 @@ static int vf610_nfc_probe(struct platform_device *pdev) /* first scan to find the device and get the page size */ err = nand_scan_ident(mtd, 1, NULL); if (err) - goto error; + goto err_clk; vf610_nfc_init_controller(nfc); @@ -717,20 +717,20 @@ static int vf610_nfc_probe(struct platform_device *pdev) if (mtd->writesize + mtd->oobsize > PAGE_2K + OOB_MAX - 8) { dev_err(nfc->dev, "Unsupported flash page size\n"); err = -ENXIO; - goto error; + goto err_clk; } if (chip->ecc.mode == NAND_ECC_HW) { if (mtd->writesize != PAGE_2K && mtd->oobsize < 64) { dev_err(nfc->dev, "Unsupported flash with hwecc\n"); err = -ENXIO; - goto error; + goto err_clk; } if (chip->ecc.size != mtd->writesize) { dev_err(nfc->dev, "Step size needs to be page size\n"); err = -ENXIO; - goto error; + goto err_clk; } /* Only 64 byte ECC layouts known */ @@ -750,7 +750,7 @@ static int vf610_nfc_probe(struct platform_device *pdev) } else { dev_err(nfc->dev, "Unsupported ECC strength\n"); err = -ENXIO; - goto error; + goto err_clk; } chip->ecc.read_page = vf610_nfc_read_page; @@ -762,15 +762,13 @@ static int vf610_nfc_probe(struct platform_device *pdev) /* second phase scan */ err = nand_scan_tail(mtd); if (err) - goto error; + goto err_clk; platform_set_drvdata(pdev, mtd); /* Register device in MTD */ return mtd_device_register(mtd, NULL, 0); -error: - of_node_put(nand_get_flash_node(chip)); err_clk: clk_disable_unprepare(nfc->clk); return err; From 196644fd09ab7bf47040c0bdd1b48fc3c2bc08a6 Mon Sep 17 00:00:00 2001 From: Alexey Khoroshilov Date: Sat, 10 Feb 2018 01:28:35 +0300 Subject: [PATCH 15/89] mtd: nand: vf610: improve readability of error label Use clearer error labels as Boris Brezillon suggested. Signed-off-by: Alexey Khoroshilov Reviewed-by: Stefan Agner Signed-off-by: Boris Brezillon --- drivers/mtd/nand/vf610_nfc.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/mtd/nand/vf610_nfc.c b/drivers/mtd/nand/vf610_nfc.c index 9c6d87d282c3..1939503b0960 100644 --- a/drivers/mtd/nand/vf610_nfc.c +++ b/drivers/mtd/nand/vf610_nfc.c @@ -667,7 +667,7 @@ static int vf610_nfc_probe(struct platform_device *pdev) dev_err(nfc->dev, "Only one NAND chip supported!\n"); err = -EINVAL; - goto err_clk; + goto err_disable_clk; } nand_set_flash_node(chip, child); @@ -677,7 +677,7 @@ static int vf610_nfc_probe(struct platform_device *pdev) if (!nand_get_flash_node(chip)) { dev_err(nfc->dev, "NAND chip sub-node missing!\n"); err = -ENODEV; - goto err_clk; + goto err_disable_clk; } chip->dev_ready = vf610_nfc_dev_ready; @@ -697,7 +697,7 @@ static int vf610_nfc_probe(struct platform_device *pdev) err = devm_request_irq(nfc->dev, irq, vf610_nfc_irq, 0, DRV_NAME, mtd); if (err) { dev_err(nfc->dev, "Error requesting IRQ!\n"); - goto err_clk; + goto err_disable_clk; } vf610_nfc_preinit_controller(nfc); @@ -705,7 +705,7 @@ static int vf610_nfc_probe(struct platform_device *pdev) /* first scan to find the device and get the page size */ err = nand_scan_ident(mtd, 1, NULL); if (err) - goto err_clk; + goto err_disable_clk; vf610_nfc_init_controller(nfc); @@ -717,20 +717,20 @@ static int vf610_nfc_probe(struct platform_device *pdev) if (mtd->writesize + mtd->oobsize > PAGE_2K + OOB_MAX - 8) { dev_err(nfc->dev, "Unsupported flash page size\n"); err = -ENXIO; - goto err_clk; + goto err_disable_clk; } if (chip->ecc.mode == NAND_ECC_HW) { if (mtd->writesize != PAGE_2K && mtd->oobsize < 64) { dev_err(nfc->dev, "Unsupported flash with hwecc\n"); err = -ENXIO; - goto err_clk; + goto err_disable_clk; } if (chip->ecc.size != mtd->writesize) { dev_err(nfc->dev, "Step size needs to be page size\n"); err = -ENXIO; - goto err_clk; + goto err_disable_clk; } /* Only 64 byte ECC layouts known */ @@ -750,7 +750,7 @@ static int vf610_nfc_probe(struct platform_device *pdev) } else { dev_err(nfc->dev, "Unsupported ECC strength\n"); err = -ENXIO; - goto err_clk; + goto err_disable_clk; } chip->ecc.read_page = vf610_nfc_read_page; @@ -762,14 +762,14 @@ static int vf610_nfc_probe(struct platform_device *pdev) /* second phase scan */ err = nand_scan_tail(mtd); if (err) - goto err_clk; + goto err_disable_clk; platform_set_drvdata(pdev, mtd); /* Register device in MTD */ return mtd_device_register(mtd, NULL, 0); -err_clk: +err_disable_clk: clk_disable_unprepare(nfc->clk); return err; } From 1b8c90985f59ccd8a1adb723b58b42628b36e668 Mon Sep 17 00:00:00 2001 From: Alexey Khoroshilov Date: Sat, 10 Feb 2018 01:28:36 +0300 Subject: [PATCH 16/89] mtd: nand: vf610: check mtd_device_register() return code vf610_nfc_probe() misses error handling of mtd_device_register(). Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Alexey Khoroshilov Reviewed-by: Stefan Agner Signed-off-by: Boris Brezillon --- drivers/mtd/nand/vf610_nfc.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/nand/vf610_nfc.c b/drivers/mtd/nand/vf610_nfc.c index 1939503b0960..5d7a1f8f580f 100644 --- a/drivers/mtd/nand/vf610_nfc.c +++ b/drivers/mtd/nand/vf610_nfc.c @@ -767,8 +767,13 @@ static int vf610_nfc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, mtd); /* Register device in MTD */ - return mtd_device_register(mtd, NULL, 0); + err = mtd_device_register(mtd, NULL, 0); + if (err) + goto err_cleanup_nand; + return 0; +err_cleanup_nand: + nand_cleanup(chip); err_disable_clk: clk_disable_unprepare(nfc->clk); return err; From fb3bff5b407e58493fa6bc44f24217f649aecd25 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Yoshitake Date: Thu, 15 Feb 2018 00:35:06 +0900 Subject: [PATCH 17/89] mtd: nand: toshiba: Retrieve ECC requirements from extended ID This patch enables support to read the ECC strength and size from the NAND flash using Toshiba Memory SLC NAND extended-ID. This patch is based on the information of the 6th ID byte of the Toshiba Memory SLC NAND. Signed-off-by: KOBAYASHI Yoshitake Signed-off-by: Boris Brezillon --- drivers/mtd/nand/nand_toshiba.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/drivers/mtd/nand/nand_toshiba.c b/drivers/mtd/nand/nand_toshiba.c index 57df857074e6..ab43f027cd23 100644 --- a/drivers/mtd/nand/nand_toshiba.c +++ b/drivers/mtd/nand/nand_toshiba.c @@ -35,6 +35,32 @@ static void toshiba_nand_decode_id(struct nand_chip *chip) (chip->id.data[5] & 0x7) == 0x6 /* 24nm */ && !(chip->id.data[4] & 0x80) /* !BENAND */) mtd->oobsize = 32 * mtd->writesize >> 9; + + /* + * Extract ECC requirements from 6th id byte. + * For Toshiba SLC, ecc requrements are as follows: + * - 43nm: 1 bit ECC for each 512Byte is required. + * - 32nm: 4 bit ECC for each 512Byte is required. + * - 24nm: 8 bit ECC for each 512Byte is required. + */ + if (chip->id.len >= 6 && nand_is_slc(chip)) { + chip->ecc_step_ds = 512; + switch (chip->id.data[5] & 0x7) { + case 0x4: + chip->ecc_strength_ds = 1; + break; + case 0x5: + chip->ecc_strength_ds = 4; + break; + case 0x6: + chip->ecc_strength_ds = 8; + break; + default: + WARN(1, "Could not get ECC info"); + chip->ecc_step_ds = 0; + break; + } + } } static int toshiba_nand_init(struct nand_chip *chip) From 43a0a45abc4ab386f3ba978c877a2b68a0cad448 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Mon, 5 Feb 2018 23:01:59 +0100 Subject: [PATCH 18/89] mtd: nand: Get rid of comments giving the file path inside the file itself Some files add a comment giving the path of the file inside the Linux tree, which is pretty useless since the reader had to find the file to open it. Getting rid of these comments will also allow us to easily move these files around when needed. Signed-off-by: Boris Brezillon --- drivers/mtd/nand/Makefile | 3 --- drivers/mtd/nand/ams-delta.c | 2 -- drivers/mtd/nand/au1550nd.c | 2 -- drivers/mtd/nand/bf5xx_nand.c | 3 +-- drivers/mtd/nand/cmx270_nand.c | 2 -- drivers/mtd/nand/cs553x_nand.c | 2 -- drivers/mtd/nand/diskonchip.c | 2 -- drivers/mtd/nand/fsmc_nand.c | 2 -- drivers/mtd/nand/gpio.c | 2 -- drivers/mtd/nand/nand_ecc.c | 2 -- drivers/mtd/nand/orion_nand.c | 2 -- drivers/mtd/nand/pxa3xx_nand.c | 2 -- drivers/mtd/nand/s3c2410.c | 3 +-- drivers/mtd/nand/sharpsl.c | 2 -- drivers/mtd/nand/socrates_nand.c | 2 -- include/linux/mtd/bbm.h | 2 -- include/linux/mtd/nand_ecc.h | 2 -- include/linux/mtd/ndfc.h | 2 -- 18 files changed, 2 insertions(+), 37 deletions(-) diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index 921634ba400c..4e0982476267 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -1,7 +1,4 @@ # SPDX-License-Identifier: GPL-2.0 -# -# linux/drivers/nand/Makefile -# obj-$(CONFIG_MTD_NAND) += nand.o obj-$(CONFIG_MTD_NAND_ECC) += nand_ecc.o diff --git a/drivers/mtd/nand/ams-delta.c b/drivers/mtd/nand/ams-delta.c index d60ada45c549..e15991d81a20 100644 --- a/drivers/mtd/nand/ams-delta.c +++ b/drivers/mtd/nand/ams-delta.c @@ -1,6 +1,4 @@ /* - * drivers/mtd/nand/ams-delta.c - * * Copyright (C) 2006 Jonathan McDowell * * Derived from drivers/mtd/toto.c diff --git a/drivers/mtd/nand/au1550nd.c b/drivers/mtd/nand/au1550nd.c index 8ab827edf94e..df0ef1f1e2f5 100644 --- a/drivers/mtd/nand/au1550nd.c +++ b/drivers/mtd/nand/au1550nd.c @@ -1,6 +1,4 @@ /* - * drivers/mtd/nand/au1550nd.c - * * Copyright (C) 2004 Embedded Edge, LLC * * This program is free software; you can redistribute it and/or modify diff --git a/drivers/mtd/nand/bf5xx_nand.c b/drivers/mtd/nand/bf5xx_nand.c index 87bbd177b3e5..4a5f56f76efd 100644 --- a/drivers/mtd/nand/bf5xx_nand.c +++ b/drivers/mtd/nand/bf5xx_nand.c @@ -1,5 +1,4 @@ -/* linux/drivers/mtd/nand/bf5xx_nand.c - * +/* * Copyright 2006-2008 Analog Devices Inc. * http://blackfin.uclinux.org/ * Bryan Wu diff --git a/drivers/mtd/nand/cmx270_nand.c b/drivers/mtd/nand/cmx270_nand.c index b01c9804590e..66749ade9654 100644 --- a/drivers/mtd/nand/cmx270_nand.c +++ b/drivers/mtd/nand/cmx270_nand.c @@ -1,6 +1,4 @@ /* - * linux/drivers/mtd/nand/cmx270-nand.c - * * Copyright (C) 2006 Compulab, Ltd. * Mike Rapoport * diff --git a/drivers/mtd/nand/cs553x_nand.c b/drivers/mtd/nand/cs553x_nand.c index d48877540f14..be1f28fc7363 100644 --- a/drivers/mtd/nand/cs553x_nand.c +++ b/drivers/mtd/nand/cs553x_nand.c @@ -1,6 +1,4 @@ /* - * drivers/mtd/nand/cs553x_nand.c - * * (C) 2005, 2006 Red Hat Inc. * * Author: David Woodhouse diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c index 6bc93ea66f50..1af77f798fe5 100644 --- a/drivers/mtd/nand/diskonchip.c +++ b/drivers/mtd/nand/diskonchip.c @@ -1,6 +1,4 @@ /* - * drivers/mtd/nand/diskonchip.c - * * (C) 2003 Red Hat, Inc. * (C) 2004 Dan Brown * (C) 2004 Kalev Lember diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/fsmc_nand.c index f49ed46fa770..e763161a7c82 100644 --- a/drivers/mtd/nand/fsmc_nand.c +++ b/drivers/mtd/nand/fsmc_nand.c @@ -1,6 +1,4 @@ /* - * drivers/mtd/nand/fsmc_nand.c - * * ST Microelectronics * Flexible Static Memory Controller (FSMC) * Driver for NAND portions diff --git a/drivers/mtd/nand/gpio.c b/drivers/mtd/nand/gpio.c index a8bde6665c24..2780af26d9ab 100644 --- a/drivers/mtd/nand/gpio.c +++ b/drivers/mtd/nand/gpio.c @@ -1,6 +1,4 @@ /* - * drivers/mtd/nand/gpio.c - * * Updated, and converted to generic GPIO based driver by Russell King. * * Written by Ben Dooks diff --git a/drivers/mtd/nand/nand_ecc.c b/drivers/mtd/nand/nand_ecc.c index 7613a0388044..3630f0fe8fa4 100644 --- a/drivers/mtd/nand/nand_ecc.c +++ b/drivers/mtd/nand/nand_ecc.c @@ -2,8 +2,6 @@ * This file contains an ECC algorithm that detects and corrects 1 bit * errors in a 256 byte block of data. * - * drivers/mtd/nand/nand_ecc.c - * * Copyright © 2008 Koninklijke Philips Electronics NV. * Author: Frans Meulenbroeks * diff --git a/drivers/mtd/nand/orion_nand.c b/drivers/mtd/nand/orion_nand.c index 5a5aa1f07d07..7825fd3ce66b 100644 --- a/drivers/mtd/nand/orion_nand.c +++ b/drivers/mtd/nand/orion_nand.c @@ -1,6 +1,4 @@ /* - * drivers/mtd/nand/orion_nand.c - * * NAND support for Marvell Orion SoC platforms * * Tzachi Perelstein diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index d1979c7dbe7e..d75f30263d21 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -1,6 +1,4 @@ /* - * drivers/mtd/nand/pxa3xx_nand.c - * * Copyright © 2005 Intel Corporation * Copyright © 2006 Marvell International Ltd. * diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c index 4c383eeec6f6..b5bc5f106c09 100644 --- a/drivers/mtd/nand/s3c2410.c +++ b/drivers/mtd/nand/s3c2410.c @@ -1,5 +1,4 @@ -/* linux/drivers/mtd/nand/s3c2410.c - * +/* * Copyright © 2004-2008 Simtec Electronics * http://armlinux.simtec.co.uk/ * Ben Dooks diff --git a/drivers/mtd/nand/sharpsl.c b/drivers/mtd/nand/sharpsl.c index f59c455d9f51..e93df02c825e 100644 --- a/drivers/mtd/nand/sharpsl.c +++ b/drivers/mtd/nand/sharpsl.c @@ -1,6 +1,4 @@ /* - * drivers/mtd/nand/sharpsl.c - * * Copyright (C) 2004 Richard Purdie * Copyright (C) 2008 Dmitry Baryshkov * diff --git a/drivers/mtd/nand/socrates_nand.c b/drivers/mtd/nand/socrates_nand.c index 575997d0ef8a..9824a9923583 100644 --- a/drivers/mtd/nand/socrates_nand.c +++ b/drivers/mtd/nand/socrates_nand.c @@ -1,6 +1,4 @@ /* - * drivers/mtd/nand/socrates_nand.c - * * Copyright © 2008 Ilya Yanok, Emcraft Systems * * diff --git a/include/linux/mtd/bbm.h b/include/linux/mtd/bbm.h index 3bf8f954b642..3102bd754d18 100644 --- a/include/linux/mtd/bbm.h +++ b/include/linux/mtd/bbm.h @@ -1,6 +1,4 @@ /* - * linux/include/linux/mtd/bbm.h - * * NAND family Bad Block Management (BBM) header file * - Bad Block Table (BBT) implementation * diff --git a/include/linux/mtd/nand_ecc.h b/include/linux/mtd/nand_ecc.h index 4d8406c81652..8a2decf7462c 100644 --- a/include/linux/mtd/nand_ecc.h +++ b/include/linux/mtd/nand_ecc.h @@ -1,6 +1,4 @@ /* - * drivers/mtd/nand_ecc.h - * * Copyright (C) 2000-2010 Steven J. Hill * David Woodhouse * Thomas Gleixner diff --git a/include/linux/mtd/ndfc.h b/include/linux/mtd/ndfc.h index d0558a982628..357e88b3263a 100644 --- a/include/linux/mtd/ndfc.h +++ b/include/linux/mtd/ndfc.h @@ -1,6 +1,4 @@ /* - * linux/include/linux/mtd/ndfc.h - * * Copyright (c) 2006 Thomas Gleixner * * This program is free software; you can redistribute it and/or modify From 93cbd6f354f178b6e0a7d80482981520be6347b4 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Mon, 5 Feb 2018 23:02:00 +0100 Subject: [PATCH 19/89] mtd: nand: Stop using full path when referring to files placed in the same dir Some NAND drivers are derived from other NAND drivers and state it in their license header. Using full path to point to other driver files sitting in the same directory is not such a good idea, since the NAND drivers might be moved to a different directory at some point, and we don't to patch all license/copyright headers everytime this happen. The only exception where we keep full path is when the referred source files no longer exist in the tree. Signed-off-by: Boris Brezillon --- drivers/mtd/nand/ams-delta.c | 2 +- drivers/mtd/nand/bf5xx_nand.c | 4 ++-- drivers/mtd/nand/mpc5121_nfc.c | 5 ++--- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/mtd/nand/ams-delta.c b/drivers/mtd/nand/ams-delta.c index e15991d81a20..f3eaea9df90b 100644 --- a/drivers/mtd/nand/ams-delta.c +++ b/drivers/mtd/nand/ams-delta.c @@ -3,7 +3,7 @@ * * Derived from drivers/mtd/toto.c * Converted to platform driver by Janusz Krzysztofik - * Partially stolen from drivers/mtd/nand/plat_nand.c + * Partially stolen from plat_nand.c * * 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 diff --git a/drivers/mtd/nand/bf5xx_nand.c b/drivers/mtd/nand/bf5xx_nand.c index 4a5f56f76efd..9a1d8d104570 100644 --- a/drivers/mtd/nand/bf5xx_nand.c +++ b/drivers/mtd/nand/bf5xx_nand.c @@ -5,10 +5,10 @@ * * Blackfin BF5xx on-chip NAND flash controller driver * - * Derived from drivers/mtd/nand/s3c2410.c + * Derived from s3c2410.c * Copyright (c) 2007 Ben Dooks * - * Derived from drivers/mtd/nand/cafe.c + * Derived from cafe.c * Copyright © 2006 Red Hat, Inc. * Copyright © 2006 David Woodhouse * diff --git a/drivers/mtd/nand/mpc5121_nfc.c b/drivers/mtd/nand/mpc5121_nfc.c index b6b97cc9fba6..913b9d1225c6 100644 --- a/drivers/mtd/nand/mpc5121_nfc.c +++ b/drivers/mtd/nand/mpc5121_nfc.c @@ -6,9 +6,8 @@ * by OSADL membership fees in 2009; for details see www.osadl.org. * * Based on original driver from Freescale Semiconductor - * written by John Rigby on basis - * of drivers/mtd/nand/mxc_nand.c. Reworked and extended - * Piotr Ziecik . + * written by John Rigby on basis of mxc_nand.c. + * Reworked and extended by Piotr Ziecik . * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License From e36f2eb6ca707853b17fea63e222e86f914617cc Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Mon, 5 Feb 2018 23:02:01 +0100 Subject: [PATCH 20/89] mtd: nand: ams-delta: Fix path to toto.c source file Last known location of toto.c was drivers/mtd/nand/toto.c. Fix the path so that one can use git log to find when the driver was deleted and possibly checkout the source code. Signed-off-by: Boris Brezillon --- drivers/mtd/nand/ams-delta.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/nand/ams-delta.c b/drivers/mtd/nand/ams-delta.c index f3eaea9df90b..25a92474fa59 100644 --- a/drivers/mtd/nand/ams-delta.c +++ b/drivers/mtd/nand/ams-delta.c @@ -1,7 +1,7 @@ /* * Copyright (C) 2006 Jonathan McDowell * - * Derived from drivers/mtd/toto.c + * Derived from drivers/mtd/nand/toto.c * Converted to platform driver by Janusz Krzysztofik * Partially stolen from plat_nand.c * From 187c54488ead35d19082d3ee75afdbe94d3d4026 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Mon, 5 Feb 2018 23:02:02 +0100 Subject: [PATCH 21/89] mtd: nand: State when references to other drivers are no longer valid A lot of NAND drivers have been derived from other old NAND drivers which have since then been removed from the Linux tree. When this is the case, specify when the file the header is referring to has been removed so that people can find the original implementation more easily. Signed-off-by: Boris Brezillon --- arch/cris/arch-v32/drivers/mach-a3/nandflash.c | 2 +- arch/cris/arch-v32/drivers/mach-fs/nandflash.c | 2 +- drivers/mtd/nand/ams-delta.c | 2 +- drivers/mtd/nand/atmel/nand-controller.c | 4 ++-- drivers/mtd/nand/atmel/pmecc.c | 4 ++-- drivers/mtd/nand/atmel/pmecc.h | 4 ++-- drivers/mtd/nand/cmx270_nand.c | 2 +- drivers/mtd/nand/fsmc_nand.c | 2 +- 8 files changed, 11 insertions(+), 11 deletions(-) diff --git a/arch/cris/arch-v32/drivers/mach-a3/nandflash.c b/arch/cris/arch-v32/drivers/mach-a3/nandflash.c index 925a98eb6d68..7ec29d2d3661 100644 --- a/arch/cris/arch-v32/drivers/mach-a3/nandflash.c +++ b/arch/cris/arch-v32/drivers/mach-a3/nandflash.c @@ -3,7 +3,7 @@ * * Copyright (c) 2007 * - * Derived from drivers/mtd/nand/spia.c + * Derived from drivers/mtd/nand/spia.c (removed in v3.8) * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) * * This program is free software; you can redistribute it and/or modify diff --git a/arch/cris/arch-v32/drivers/mach-fs/nandflash.c b/arch/cris/arch-v32/drivers/mach-fs/nandflash.c index 53b56a429dde..7ce72906039a 100644 --- a/arch/cris/arch-v32/drivers/mach-fs/nandflash.c +++ b/arch/cris/arch-v32/drivers/mach-fs/nandflash.c @@ -3,7 +3,7 @@ * * Copyright (c) 2004 * - * Derived from drivers/mtd/nand/spia.c + * Derived from drivers/mtd/nand/spia.c (removed in v3.8) * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) * * This program is free software; you can redistribute it and/or modify diff --git a/drivers/mtd/nand/ams-delta.c b/drivers/mtd/nand/ams-delta.c index 25a92474fa59..24173a0a7875 100644 --- a/drivers/mtd/nand/ams-delta.c +++ b/drivers/mtd/nand/ams-delta.c @@ -1,7 +1,7 @@ /* * Copyright (C) 2006 Jonathan McDowell * - * Derived from drivers/mtd/nand/toto.c + * Derived from drivers/mtd/nand/toto.c (removed in v2.6.28) * Converted to platform driver by Janusz Krzysztofik * Partially stolen from plat_nand.c * diff --git a/drivers/mtd/nand/atmel/nand-controller.c b/drivers/mtd/nand/atmel/nand-controller.c index b2f00b398490..12f6753d47ae 100644 --- a/drivers/mtd/nand/atmel/nand-controller.c +++ b/drivers/mtd/nand/atmel/nand-controller.c @@ -9,10 +9,10 @@ * * Copyright 2003 Rick Bronson * - * Derived from drivers/mtd/nand/autcpu12.c + * Derived from drivers/mtd/nand/autcpu12.c (removed in v3.8) * Copyright 2001 Thomas Gleixner (gleixner@autronix.de) * - * Derived from drivers/mtd/spia.c + * Derived from drivers/mtd/spia.c (removed in v3.8) * Copyright 2000 Steven J. Hill (sjhill@cotw.com) * * diff --git a/drivers/mtd/nand/atmel/pmecc.c b/drivers/mtd/nand/atmel/pmecc.c index fcbe4fd6e684..9de29c9afb0c 100644 --- a/drivers/mtd/nand/atmel/pmecc.c +++ b/drivers/mtd/nand/atmel/pmecc.c @@ -9,10 +9,10 @@ * * Copyright 2003 Rick Bronson * - * Derived from drivers/mtd/nand/autcpu12.c + * Derived from drivers/mtd/nand/autcpu12.c (removed in v3.8) * Copyright 2001 Thomas Gleixner (gleixner@autronix.de) * - * Derived from drivers/mtd/spia.c + * Derived from drivers/mtd/spia.c (removed in v3.8) * Copyright 2000 Steven J. Hill (sjhill@cotw.com) * * Add Hardware ECC support for AT91SAM9260 / AT91SAM9263 diff --git a/drivers/mtd/nand/atmel/pmecc.h b/drivers/mtd/nand/atmel/pmecc.h index 817e0dd9fd15..808f1be0d6ad 100644 --- a/drivers/mtd/nand/atmel/pmecc.h +++ b/drivers/mtd/nand/atmel/pmecc.h @@ -9,10 +9,10 @@ * * Copyright © 2003 Rick Bronson * - * Derived from drivers/mtd/nand/autcpu12.c + * Derived from drivers/mtd/nand/autcpu12.c (removed in v3.8) * Copyright © 2001 Thomas Gleixner (gleixner@autronix.de) * - * Derived from drivers/mtd/spia.c + * Derived from drivers/mtd/spia.c (removed in v3.8) * Copyright © 2000 Steven J. Hill (sjhill@cotw.com) * * diff --git a/drivers/mtd/nand/cmx270_nand.c b/drivers/mtd/nand/cmx270_nand.c index 66749ade9654..02d6751e9efe 100644 --- a/drivers/mtd/nand/cmx270_nand.c +++ b/drivers/mtd/nand/cmx270_nand.c @@ -2,7 +2,7 @@ * Copyright (C) 2006 Compulab, Ltd. * Mike Rapoport * - * Derived from drivers/mtd/nand/h1910.c + * Derived from drivers/mtd/nand/h1910.c (removed in v3.10) * Copyright (C) 2002 Marius Gröger (mag@sysgo.de) * Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de) * diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/fsmc_nand.c index e763161a7c82..a4a5da318eed 100644 --- a/drivers/mtd/nand/fsmc_nand.c +++ b/drivers/mtd/nand/fsmc_nand.c @@ -7,7 +7,7 @@ * Vipin Kumar * Ashish Priyadarshi * - * Based on drivers/mtd/nand/nomadik_nand.c + * Based on drivers/mtd/nand/nomadik_nand.c (removed in v3.8) * * This file is licensed under the terms of the GNU General Public * License version 2. This program is licensed "as is" without any From 7b6afee7291802aa8c02aa918782033992caf641 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Mon, 5 Feb 2018 23:02:03 +0100 Subject: [PATCH 22/89] mtd: nand: Add missing copyright information Some drivers have been derived from others which have then been removed from the source tree. When this is the case, add mention the copyright of the source file(s) they've been derived from. Signed-off-by: Boris Brezillon --- drivers/mtd/nand/ams-delta.c | 3 +++ drivers/mtd/nand/fsmc_nand.c | 2 ++ 2 files changed, 5 insertions(+) diff --git a/drivers/mtd/nand/ams-delta.c b/drivers/mtd/nand/ams-delta.c index 24173a0a7875..35f80523e52e 100644 --- a/drivers/mtd/nand/ams-delta.c +++ b/drivers/mtd/nand/ams-delta.c @@ -2,6 +2,9 @@ * Copyright (C) 2006 Jonathan McDowell * * Derived from drivers/mtd/nand/toto.c (removed in v2.6.28) + * Copyright (c) 2003 Texas Instruments + * Copyright (c) 2002 Thomas Gleixner + * * Converted to platform driver by Janusz Krzysztofik * Partially stolen from plat_nand.c * diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/fsmc_nand.c index a4a5da318eed..7e66268f8154 100644 --- a/drivers/mtd/nand/fsmc_nand.c +++ b/drivers/mtd/nand/fsmc_nand.c @@ -8,6 +8,8 @@ * Ashish Priyadarshi * * Based on drivers/mtd/nand/nomadik_nand.c (removed in v3.8) + * Copyright © 2007 STMicroelectronics Pvt. Ltd. + * Copyright © 2009 Alessandro Rubini * * This file is licensed under the terms of the GNU General Public * License version 2. This program is licensed "as is" without any From 93db446a424cee9387b532995e6b516667079555 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Mon, 5 Feb 2018 23:02:04 +0100 Subject: [PATCH 23/89] mtd: nand: move raw NAND related code to the raw/ subdir As part of the process of sharing more code between different NAND based devices, we need to move all raw NAND related code to the raw/ subdirectory. Signed-off-by: Boris Brezillon --- Documentation/arm/Samsung-S3C24XX/S3C2412.txt | 2 +- Documentation/driver-api/mtdnand.rst | 8 +- Documentation/gpio/drivers-on-gpio.txt | 4 +- MAINTAINERS | 22 +- drivers/mtd/nand/Kconfig | 581 +----------------- drivers/mtd/nand/Makefile | 67 +- drivers/mtd/nand/raw/Kconfig | 580 +++++++++++++++++ drivers/mtd/nand/raw/Makefile | 68 ++ drivers/mtd/nand/{ => raw}/ams-delta.c | 0 drivers/mtd/nand/{ => raw}/atmel/Makefile | 0 .../nand/{ => raw}/atmel/nand-controller.c | 0 drivers/mtd/nand/{ => raw}/atmel/pmecc.c | 0 drivers/mtd/nand/{ => raw}/atmel/pmecc.h | 0 drivers/mtd/nand/{ => raw}/au1550nd.c | 0 .../mtd/nand/{ => raw}/bcm47xxnflash/Makefile | 0 .../{ => raw}/bcm47xxnflash/bcm47xxnflash.h | 0 .../mtd/nand/{ => raw}/bcm47xxnflash/main.c | 0 .../{ => raw}/bcm47xxnflash/ops_bcm4706.c | 0 drivers/mtd/nand/{ => raw}/bf5xx_nand.c | 0 drivers/mtd/nand/{ => raw}/brcmnand/Makefile | 0 .../nand/{ => raw}/brcmnand/bcm63138_nand.c | 0 .../nand/{ => raw}/brcmnand/bcm6368_nand.c | 0 .../mtd/nand/{ => raw}/brcmnand/brcmnand.c | 0 .../mtd/nand/{ => raw}/brcmnand/brcmnand.h | 0 .../nand/{ => raw}/brcmnand/brcmstb_nand.c | 0 .../mtd/nand/{ => raw}/brcmnand/iproc_nand.c | 0 drivers/mtd/nand/{ => raw}/cafe_nand.c | 0 drivers/mtd/nand/{ => raw}/cmx270_nand.c | 0 drivers/mtd/nand/{ => raw}/cs553x_nand.c | 0 drivers/mtd/nand/{ => raw}/davinci_nand.c | 0 drivers/mtd/nand/{ => raw}/denali.c | 0 drivers/mtd/nand/{ => raw}/denali.h | 0 drivers/mtd/nand/{ => raw}/denali_dt.c | 0 drivers/mtd/nand/{ => raw}/denali_pci.c | 0 drivers/mtd/nand/{ => raw}/diskonchip.c | 0 drivers/mtd/nand/{ => raw}/docg4.c | 0 drivers/mtd/nand/{ => raw}/fsl_elbc_nand.c | 0 drivers/mtd/nand/{ => raw}/fsl_ifc_nand.c | 0 drivers/mtd/nand/{ => raw}/fsl_upm.c | 0 drivers/mtd/nand/{ => raw}/fsmc_nand.c | 0 drivers/mtd/nand/{ => raw}/gpio.c | 0 drivers/mtd/nand/{ => raw}/gpmi-nand/Makefile | 0 .../mtd/nand/{ => raw}/gpmi-nand/bch-regs.h | 0 .../mtd/nand/{ => raw}/gpmi-nand/gpmi-lib.c | 0 .../mtd/nand/{ => raw}/gpmi-nand/gpmi-nand.c | 0 .../mtd/nand/{ => raw}/gpmi-nand/gpmi-nand.h | 0 .../mtd/nand/{ => raw}/gpmi-nand/gpmi-regs.h | 0 drivers/mtd/nand/{ => raw}/hisi504_nand.c | 0 drivers/mtd/nand/{ => raw}/jz4740_nand.c | 0 drivers/mtd/nand/{ => raw}/jz4780_bch.c | 0 drivers/mtd/nand/{ => raw}/jz4780_bch.h | 0 drivers/mtd/nand/{ => raw}/jz4780_nand.c | 0 drivers/mtd/nand/{ => raw}/lpc32xx_mlc.c | 0 drivers/mtd/nand/{ => raw}/lpc32xx_slc.c | 0 drivers/mtd/nand/{ => raw}/marvell_nand.c | 0 drivers/mtd/nand/{ => raw}/mpc5121_nfc.c | 0 drivers/mtd/nand/{ => raw}/mtk_ecc.c | 0 drivers/mtd/nand/{ => raw}/mtk_ecc.h | 0 drivers/mtd/nand/{ => raw}/mtk_nand.c | 0 drivers/mtd/nand/{ => raw}/mxc_nand.c | 0 drivers/mtd/nand/{ => raw}/nand_amd.c | 0 drivers/mtd/nand/{ => raw}/nand_base.c | 0 drivers/mtd/nand/{ => raw}/nand_bbt.c | 0 drivers/mtd/nand/{ => raw}/nand_bch.c | 0 drivers/mtd/nand/{ => raw}/nand_ecc.c | 0 drivers/mtd/nand/{ => raw}/nand_hynix.c | 0 drivers/mtd/nand/{ => raw}/nand_ids.c | 0 drivers/mtd/nand/{ => raw}/nand_macronix.c | 0 drivers/mtd/nand/{ => raw}/nand_micron.c | 0 drivers/mtd/nand/{ => raw}/nand_samsung.c | 0 drivers/mtd/nand/{ => raw}/nand_timings.c | 0 drivers/mtd/nand/{ => raw}/nand_toshiba.c | 0 drivers/mtd/nand/{ => raw}/nandsim.c | 0 drivers/mtd/nand/{ => raw}/ndfc.c | 0 drivers/mtd/nand/{ => raw}/nuc900_nand.c | 0 drivers/mtd/nand/{ => raw}/omap2.c | 0 drivers/mtd/nand/{ => raw}/omap_elm.c | 0 drivers/mtd/nand/{ => raw}/orion_nand.c | 0 drivers/mtd/nand/{ => raw}/oxnas_nand.c | 0 drivers/mtd/nand/{ => raw}/pasemi_nand.c | 0 drivers/mtd/nand/{ => raw}/plat_nand.c | 0 drivers/mtd/nand/{ => raw}/pxa3xx_nand.c | 0 drivers/mtd/nand/{ => raw}/qcom_nandc.c | 0 drivers/mtd/nand/{ => raw}/r852.c | 0 drivers/mtd/nand/{ => raw}/r852.h | 0 drivers/mtd/nand/{ => raw}/s3c2410.c | 0 drivers/mtd/nand/{ => raw}/sh_flctl.c | 0 drivers/mtd/nand/{ => raw}/sharpsl.c | 0 drivers/mtd/nand/{ => raw}/sm_common.c | 0 drivers/mtd/nand/{ => raw}/sm_common.h | 0 drivers/mtd/nand/{ => raw}/socrates_nand.c | 0 drivers/mtd/nand/{ => raw}/sunxi_nand.c | 0 drivers/mtd/nand/{ => raw}/tango_nand.c | 0 drivers/mtd/nand/{ => raw}/tmio_nand.c | 0 drivers/mtd/nand/{ => raw}/txx9ndfmc.c | 0 drivers/mtd/nand/{ => raw}/vf610_nfc.c | 0 drivers/mtd/nand/{ => raw}/xway_nand.c | 0 drivers/mtd/sm_ftl.c | 2 +- 98 files changed, 669 insertions(+), 665 deletions(-) create mode 100644 drivers/mtd/nand/raw/Kconfig create mode 100644 drivers/mtd/nand/raw/Makefile rename drivers/mtd/nand/{ => raw}/ams-delta.c (100%) rename drivers/mtd/nand/{ => raw}/atmel/Makefile (100%) rename drivers/mtd/nand/{ => raw}/atmel/nand-controller.c (100%) rename drivers/mtd/nand/{ => raw}/atmel/pmecc.c (100%) rename drivers/mtd/nand/{ => raw}/atmel/pmecc.h (100%) rename drivers/mtd/nand/{ => raw}/au1550nd.c (100%) rename drivers/mtd/nand/{ => raw}/bcm47xxnflash/Makefile (100%) rename drivers/mtd/nand/{ => raw}/bcm47xxnflash/bcm47xxnflash.h (100%) rename drivers/mtd/nand/{ => raw}/bcm47xxnflash/main.c (100%) rename drivers/mtd/nand/{ => raw}/bcm47xxnflash/ops_bcm4706.c (100%) rename drivers/mtd/nand/{ => raw}/bf5xx_nand.c (100%) rename drivers/mtd/nand/{ => raw}/brcmnand/Makefile (100%) rename drivers/mtd/nand/{ => raw}/brcmnand/bcm63138_nand.c (100%) rename drivers/mtd/nand/{ => raw}/brcmnand/bcm6368_nand.c (100%) rename drivers/mtd/nand/{ => raw}/brcmnand/brcmnand.c (100%) rename drivers/mtd/nand/{ => raw}/brcmnand/brcmnand.h (100%) rename drivers/mtd/nand/{ => raw}/brcmnand/brcmstb_nand.c (100%) rename drivers/mtd/nand/{ => raw}/brcmnand/iproc_nand.c (100%) rename drivers/mtd/nand/{ => raw}/cafe_nand.c (100%) rename drivers/mtd/nand/{ => raw}/cmx270_nand.c (100%) rename drivers/mtd/nand/{ => raw}/cs553x_nand.c (100%) rename drivers/mtd/nand/{ => raw}/davinci_nand.c (100%) rename drivers/mtd/nand/{ => raw}/denali.c (100%) rename drivers/mtd/nand/{ => raw}/denali.h (100%) rename drivers/mtd/nand/{ => raw}/denali_dt.c (100%) rename drivers/mtd/nand/{ => raw}/denali_pci.c (100%) rename drivers/mtd/nand/{ => raw}/diskonchip.c (100%) rename drivers/mtd/nand/{ => raw}/docg4.c (100%) rename drivers/mtd/nand/{ => raw}/fsl_elbc_nand.c (100%) rename drivers/mtd/nand/{ => raw}/fsl_ifc_nand.c (100%) rename drivers/mtd/nand/{ => raw}/fsl_upm.c (100%) rename drivers/mtd/nand/{ => raw}/fsmc_nand.c (100%) rename drivers/mtd/nand/{ => raw}/gpio.c (100%) rename drivers/mtd/nand/{ => raw}/gpmi-nand/Makefile (100%) rename drivers/mtd/nand/{ => raw}/gpmi-nand/bch-regs.h (100%) rename drivers/mtd/nand/{ => raw}/gpmi-nand/gpmi-lib.c (100%) rename drivers/mtd/nand/{ => raw}/gpmi-nand/gpmi-nand.c (100%) rename drivers/mtd/nand/{ => raw}/gpmi-nand/gpmi-nand.h (100%) rename drivers/mtd/nand/{ => raw}/gpmi-nand/gpmi-regs.h (100%) rename drivers/mtd/nand/{ => raw}/hisi504_nand.c (100%) rename drivers/mtd/nand/{ => raw}/jz4740_nand.c (100%) rename drivers/mtd/nand/{ => raw}/jz4780_bch.c (100%) rename drivers/mtd/nand/{ => raw}/jz4780_bch.h (100%) rename drivers/mtd/nand/{ => raw}/jz4780_nand.c (100%) rename drivers/mtd/nand/{ => raw}/lpc32xx_mlc.c (100%) rename drivers/mtd/nand/{ => raw}/lpc32xx_slc.c (100%) rename drivers/mtd/nand/{ => raw}/marvell_nand.c (100%) rename drivers/mtd/nand/{ => raw}/mpc5121_nfc.c (100%) rename drivers/mtd/nand/{ => raw}/mtk_ecc.c (100%) rename drivers/mtd/nand/{ => raw}/mtk_ecc.h (100%) rename drivers/mtd/nand/{ => raw}/mtk_nand.c (100%) rename drivers/mtd/nand/{ => raw}/mxc_nand.c (100%) rename drivers/mtd/nand/{ => raw}/nand_amd.c (100%) rename drivers/mtd/nand/{ => raw}/nand_base.c (100%) rename drivers/mtd/nand/{ => raw}/nand_bbt.c (100%) rename drivers/mtd/nand/{ => raw}/nand_bch.c (100%) rename drivers/mtd/nand/{ => raw}/nand_ecc.c (100%) rename drivers/mtd/nand/{ => raw}/nand_hynix.c (100%) rename drivers/mtd/nand/{ => raw}/nand_ids.c (100%) rename drivers/mtd/nand/{ => raw}/nand_macronix.c (100%) rename drivers/mtd/nand/{ => raw}/nand_micron.c (100%) rename drivers/mtd/nand/{ => raw}/nand_samsung.c (100%) rename drivers/mtd/nand/{ => raw}/nand_timings.c (100%) rename drivers/mtd/nand/{ => raw}/nand_toshiba.c (100%) rename drivers/mtd/nand/{ => raw}/nandsim.c (100%) rename drivers/mtd/nand/{ => raw}/ndfc.c (100%) rename drivers/mtd/nand/{ => raw}/nuc900_nand.c (100%) rename drivers/mtd/nand/{ => raw}/omap2.c (100%) rename drivers/mtd/nand/{ => raw}/omap_elm.c (100%) rename drivers/mtd/nand/{ => raw}/orion_nand.c (100%) rename drivers/mtd/nand/{ => raw}/oxnas_nand.c (100%) rename drivers/mtd/nand/{ => raw}/pasemi_nand.c (100%) rename drivers/mtd/nand/{ => raw}/plat_nand.c (100%) rename drivers/mtd/nand/{ => raw}/pxa3xx_nand.c (100%) rename drivers/mtd/nand/{ => raw}/qcom_nandc.c (100%) rename drivers/mtd/nand/{ => raw}/r852.c (100%) rename drivers/mtd/nand/{ => raw}/r852.h (100%) rename drivers/mtd/nand/{ => raw}/s3c2410.c (100%) rename drivers/mtd/nand/{ => raw}/sh_flctl.c (100%) rename drivers/mtd/nand/{ => raw}/sharpsl.c (100%) rename drivers/mtd/nand/{ => raw}/sm_common.c (100%) rename drivers/mtd/nand/{ => raw}/sm_common.h (100%) rename drivers/mtd/nand/{ => raw}/socrates_nand.c (100%) rename drivers/mtd/nand/{ => raw}/sunxi_nand.c (100%) rename drivers/mtd/nand/{ => raw}/tango_nand.c (100%) rename drivers/mtd/nand/{ => raw}/tmio_nand.c (100%) rename drivers/mtd/nand/{ => raw}/txx9ndfmc.c (100%) rename drivers/mtd/nand/{ => raw}/vf610_nfc.c (100%) rename drivers/mtd/nand/{ => raw}/xway_nand.c (100%) diff --git a/Documentation/arm/Samsung-S3C24XX/S3C2412.txt b/Documentation/arm/Samsung-S3C24XX/S3C2412.txt index f057876b920b..dc1fd362d3c1 100644 --- a/Documentation/arm/Samsung-S3C24XX/S3C2412.txt +++ b/Documentation/arm/Samsung-S3C24XX/S3C2412.txt @@ -46,7 +46,7 @@ NAND ---- The NAND hardware is similar to the S3C2440, and is supported by the - s3c2410 driver in the drivers/mtd/nand directory. + s3c2410 driver in the drivers/mtd/nand/raw directory. USB Host diff --git a/Documentation/driver-api/mtdnand.rst b/Documentation/driver-api/mtdnand.rst index 2a5191b6d445..dcd63599f700 100644 --- a/Documentation/driver-api/mtdnand.rst +++ b/Documentation/driver-api/mtdnand.rst @@ -967,10 +967,10 @@ API functions which are exported. Each function has a short description which is marked with an [XXX] identifier. See the chapter "Documentation hints" for an explanation. -.. kernel-doc:: drivers/mtd/nand/nand_base.c +.. kernel-doc:: drivers/mtd/nand/raw/nand_base.c :export: -.. kernel-doc:: drivers/mtd/nand/nand_ecc.c +.. kernel-doc:: drivers/mtd/nand/raw/nand_ecc.c :export: Internal Functions Provided @@ -982,10 +982,10 @@ marked with an [XXX] identifier. See the chapter "Documentation hints" for an explanation. The functions marked with [DEFAULT] might be relevant for a board driver developer. -.. kernel-doc:: drivers/mtd/nand/nand_base.c +.. kernel-doc:: drivers/mtd/nand/raw/nand_base.c :internal: -.. kernel-doc:: drivers/mtd/nand/nand_bbt.c +.. kernel-doc:: drivers/mtd/nand/raw/nand_bbt.c :internal: Credits diff --git a/Documentation/gpio/drivers-on-gpio.txt b/Documentation/gpio/drivers-on-gpio.txt index a2ccbab12eb7..a3e612f55bc7 100644 --- a/Documentation/gpio/drivers-on-gpio.txt +++ b/Documentation/gpio/drivers-on-gpio.txt @@ -74,8 +74,8 @@ hardware descriptions such as device tree or ACPI: it from 1-to-0-to-1. If that hardware does not receive its "ping" periodically, it will reset the system. -- gpio-nand: drivers/mtd/nand/gpio.c is used to connect a NAND flash chip to - a set of simple GPIO lines: RDY, NCE, ALE, CLE, NWP. It interacts with the +- gpio-nand: drivers/mtd/nand/raw/gpio.c is used to connect a NAND flash chip + to a set of simple GPIO lines: RDY, NCE, ALE, CLE, NWP. It interacts with the NAND flash MTD subsystem and provides chip access and partition parsing like any other NAND driving hardware. diff --git a/MAINTAINERS b/MAINTAINERS index 3bdc260e36b7..34b2e9ed6d3d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1710,7 +1710,7 @@ F: drivers/input/keyboard/w90p910_keypad.c F: drivers/input/touchscreen/w90p910_ts.c F: drivers/watchdog/nuc900_wdt.c F: drivers/net/ethernet/nuvoton/w90p910_ether.c -F: drivers/mtd/nand/nuc900_nand.c +F: drivers/mtd/nand/raw/nuc900_nand.c F: drivers/rtc/rtc-nuc900.c F: drivers/spi/spi-nuc900.c F: drivers/usb/host/ehci-w90x900.c @@ -3014,7 +3014,7 @@ M: Kamal Dasu L: linux-mtd@lists.infradead.org L: bcm-kernel-feedback-list@broadcom.com S: Maintained -F: drivers/mtd/nand/brcmnand/ +F: drivers/mtd/nand/raw/brcmnand/ BROADCOM STB DPFE DRIVER M: Markus Mayer @@ -4116,7 +4116,7 @@ DENALI NAND DRIVER M: Masahiro Yamada L: linux-mtd@lists.infradead.org S: Supported -F: drivers/mtd/nand/denali* +F: drivers/mtd/nand/raw/denali* DESIGNWARE USB2 DRD IP DRIVER M: John Youn @@ -5646,7 +5646,7 @@ FREESCALE GPMI NAND DRIVER M: Han Xu L: linux-mtd@lists.infradead.org S: Maintained -F: drivers/mtd/nand/gpmi-nand/* +F: drivers/mtd/nand/raw/gpmi-nand/* FREESCALE I2C CPM DRIVER M: Jochen Friedrich @@ -6955,7 +6955,7 @@ INGENIC JZ4780 NAND DRIVER M: Harvey Hunt L: linux-mtd@lists.infradead.org S: Maintained -F: drivers/mtd/nand/jz4780_* +F: drivers/mtd/nand/raw/jz4780_* INOTIFY M: Jan Kara @@ -8474,7 +8474,7 @@ MARVELL NAND CONTROLLER DRIVER M: Miquel Raynal L: linux-mtd@lists.infradead.org S: Maintained -F: drivers/mtd/nand/marvell_nand.c +F: drivers/mtd/nand/raw/marvell_nand.c F: Documentation/devicetree/bindings/mtd/marvell-nand.txt MARVELL SOC MMC/SD/SDIO CONTROLLER DRIVER @@ -9136,7 +9136,7 @@ M: Wenyou Yang M: Josh Wu L: linux-mtd@lists.infradead.org S: Supported -F: drivers/mtd/nand/atmel/* +F: drivers/mtd/nand/raw/atmel/* F: Documentation/devicetree/bindings/mtd/atmel-nand.txt MICROCHIP KSZ SERIES ETHERNET SWITCH DRIVER @@ -11331,7 +11331,7 @@ PXA3xx NAND FLASH DRIVER M: Ezequiel Garcia L: linux-mtd@lists.infradead.org S: Maintained -F: drivers/mtd/nand/pxa3xx_nand.c +F: drivers/mtd/nand/raw/pxa3xx_nand.c QAT DRIVER M: Giovanni Cabiddu @@ -11815,8 +11815,8 @@ F: drivers/memstick/host/r592.* RICOH SMARTMEDIA/XD DRIVER M: Maxim Levitsky S: Maintained -F: drivers/mtd/nand/r852.c -F: drivers/mtd/nand/r852.h +F: drivers/mtd/nand/raw/r852.c +F: drivers/mtd/nand/raw/r852.h RISC-V ARCHITECTURE M: Palmer Dabbelt @@ -14635,7 +14635,7 @@ VF610 NAND DRIVER M: Stefan Agner L: linux-mtd@lists.infradead.org S: Supported -F: drivers/mtd/nand/vf610_nfc.c +F: drivers/mtd/nand/raw/vf610_nfc.c VFAT/FAT/MSDOS FILESYSTEM M: OGAWA Hirofumi diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index e6b8c59f2c0d..6d5373471809 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -1,580 +1 @@ -config MTD_NAND_ECC - tristate - -config MTD_NAND_ECC_SMC - bool "NAND ECC Smart Media byte order" - depends on MTD_NAND_ECC - default n - help - Software ECC according to the Smart Media Specification. - The original Linux implementation had byte 0 and 1 swapped. - - -menuconfig MTD_NAND - tristate "NAND Device Support" - depends on MTD - select MTD_NAND_ECC - help - This enables support for accessing all type of NAND flash - devices. For further information see - . - -if MTD_NAND - -config MTD_NAND_BCH - tristate - select BCH - depends on MTD_NAND_ECC_BCH - default MTD_NAND - -config MTD_NAND_ECC_BCH - bool "Support software BCH ECC" - default n - help - This enables support for software BCH error correction. Binary BCH - codes are more powerful and cpu intensive than traditional Hamming - ECC codes. They are used with NAND devices requiring more than 1 bit - of error correction. - -config MTD_SM_COMMON - tristate - default n - -config MTD_NAND_DENALI - tristate - -config MTD_NAND_DENALI_PCI - tristate "Support Denali NAND controller on Intel Moorestown" - select MTD_NAND_DENALI - depends on HAS_DMA && PCI - help - Enable the driver for NAND flash on Intel Moorestown, using the - Denali NAND controller core. - -config MTD_NAND_DENALI_DT - tristate "Support Denali NAND controller as a DT device" - select MTD_NAND_DENALI - depends on HAS_DMA && HAVE_CLK && OF - help - Enable the driver for NAND flash on platforms using a Denali NAND - controller as a DT device. - -config MTD_NAND_GPIO - tristate "GPIO assisted NAND Flash driver" - depends on GPIOLIB || COMPILE_TEST - depends on HAS_IOMEM - help - This enables a NAND flash driver where control signals are - connected to GPIO pins, and commands and data are communicated - via a memory mapped interface. - -config MTD_NAND_AMS_DELTA - tristate "NAND Flash device on Amstrad E3" - depends on MACH_AMS_DELTA - default y - help - Support for NAND flash on Amstrad E3 (Delta). - -config MTD_NAND_OMAP2 - tristate "NAND Flash device on OMAP2, OMAP3, OMAP4 and Keystone" - depends on (ARCH_OMAP2PLUS || ARCH_KEYSTONE) - help - Support for NAND flash on Texas Instruments OMAP2, OMAP3, OMAP4 - and Keystone platforms. - -config MTD_NAND_OMAP_BCH - depends on MTD_NAND_OMAP2 - bool "Support hardware based BCH error correction" - default n - select BCH - help - This config enables the ELM hardware engine, which can be used to - locate and correct errors when using BCH ECC scheme. This offloads - the cpu from doing ECC error searching and correction. However some - legacy OMAP families like OMAP2xxx, OMAP3xxx do not have ELM engine - so this is optional for them. - -config MTD_NAND_OMAP_BCH_BUILD - def_tristate MTD_NAND_OMAP2 && MTD_NAND_OMAP_BCH - -config MTD_NAND_RICOH - tristate "Ricoh xD card reader" - default n - depends on PCI - select MTD_SM_COMMON - help - Enable support for Ricoh R5C852 xD card reader - You also need to enable ether - NAND SSFDC (SmartMedia) read only translation layer' or new - expermental, readwrite - 'SmartMedia/xD new translation layer' - -config MTD_NAND_AU1550 - tristate "Au1550/1200 NAND support" - depends on MIPS_ALCHEMY - help - This enables the driver for the NAND flash controller on the - AMD/Alchemy 1550 SOC. - -config MTD_NAND_BF5XX - tristate "Blackfin on-chip NAND Flash Controller driver" - depends on BF54x || BF52x - help - This enables the Blackfin on-chip NAND flash controller - - No board specific support is done by this driver, each board - must advertise a platform_device for the driver to attach. - - This driver can also be built as a module. If so, the module - will be called bf5xx-nand. - -config MTD_NAND_BF5XX_HWECC - bool "BF5XX NAND Hardware ECC" - default y - depends on MTD_NAND_BF5XX - help - Enable the use of the BF5XX's internal ECC generator when - using NAND. - -config MTD_NAND_BF5XX_BOOTROM_ECC - bool "Use Blackfin BootROM ECC Layout" - default n - depends on MTD_NAND_BF5XX_HWECC - help - If you wish to modify NAND pages and allow the Blackfin on-chip - BootROM to boot from them, say Y here. This is only necessary - if you are booting U-Boot out of NAND and you wish to update - U-Boot from Linux' userspace. Otherwise, you should say N here. - - If unsure, say N. - -config MTD_NAND_S3C2410 - tristate "NAND Flash support for Samsung S3C SoCs" - depends on ARCH_S3C24XX || ARCH_S3C64XX - help - This enables the NAND flash controller on the S3C24xx and S3C64xx - SoCs - - No board specific support is done by this driver, each board - must advertise a platform_device for the driver to attach. - -config MTD_NAND_S3C2410_DEBUG - bool "Samsung S3C NAND driver debug" - depends on MTD_NAND_S3C2410 - help - Enable debugging of the S3C NAND driver - -config MTD_NAND_NDFC - tristate "NDFC NanD Flash Controller" - depends on 4xx - select MTD_NAND_ECC_SMC - help - NDFC Nand Flash Controllers are integrated in IBM/AMCC's 4xx SoCs - -config MTD_NAND_S3C2410_CLKSTOP - bool "Samsung S3C NAND IDLE clock stop" - depends on MTD_NAND_S3C2410 - default n - help - Stop the clock to the NAND controller when there is no chip - selected to save power. This will mean there is a small delay - when the is NAND chip selected or released, but will save - approximately 5mA of power when there is nothing happening. - -config MTD_NAND_TANGO - tristate "NAND Flash support for Tango chips" - depends on ARCH_TANGO || COMPILE_TEST - depends on HAS_DMA - help - Enables the NAND Flash controller on Tango chips. - -config MTD_NAND_DISKONCHIP - tristate "DiskOnChip 2000, Millennium and Millennium Plus (NAND reimplementation)" - depends on HAS_IOMEM - select REED_SOLOMON - select REED_SOLOMON_DEC16 - help - This is a reimplementation of M-Systems DiskOnChip 2000, - Millennium and Millennium Plus as a standard NAND device driver, - as opposed to the earlier self-contained MTD device drivers. - This should enable, among other things, proper JFFS2 operation on - these devices. - -config MTD_NAND_DISKONCHIP_PROBE_ADVANCED - bool "Advanced detection options for DiskOnChip" - depends on MTD_NAND_DISKONCHIP - help - This option allows you to specify nonstandard address at which to - probe for a DiskOnChip, or to change the detection options. You - are unlikely to need any of this unless you are using LinuxBIOS. - Say 'N'. - -config MTD_NAND_DISKONCHIP_PROBE_ADDRESS - hex "Physical address of DiskOnChip" if MTD_NAND_DISKONCHIP_PROBE_ADVANCED - depends on MTD_NAND_DISKONCHIP - default "0" - ---help--- - By default, the probe for DiskOnChip devices will look for a - DiskOnChip at every multiple of 0x2000 between 0xC8000 and 0xEE000. - This option allows you to specify a single address at which to probe - for the device, which is useful if you have other devices in that - range which get upset when they are probed. - - (Note that on PowerPC, the normal probe will only check at - 0xE4000000.) - - Normally, you should leave this set to zero, to allow the probe at - the normal addresses. - -config MTD_NAND_DISKONCHIP_PROBE_HIGH - bool "Probe high addresses" - depends on MTD_NAND_DISKONCHIP_PROBE_ADVANCED - help - By default, the probe for DiskOnChip devices will look for a - DiskOnChip at every multiple of 0x2000 between 0xC8000 and 0xEE000. - This option changes to make it probe between 0xFFFC8000 and - 0xFFFEE000. Unless you are using LinuxBIOS, this is unlikely to be - useful to you. Say 'N'. - -config MTD_NAND_DISKONCHIP_BBTWRITE - bool "Allow BBT writes on DiskOnChip Millennium and 2000TSOP" - depends on MTD_NAND_DISKONCHIP - help - On DiskOnChip devices shipped with the INFTL filesystem (Millennium - and 2000 TSOP/Alon), Linux reserves some space at the end of the - device for the Bad Block Table (BBT). If you have existing INFTL - data on your device (created by non-Linux tools such as M-Systems' - DOS drivers), your data might overlap the area Linux wants to use for - the BBT. If this is a concern for you, leave this option disabled and - Linux will not write BBT data into this area. - The downside of leaving this option disabled is that if bad blocks - are detected by Linux, they will not be recorded in the BBT, which - could cause future problems. - Once you enable this option, new filesystems (INFTL or others, created - in Linux or other operating systems) will not use the reserved area. - The only reason not to enable this option is to prevent damage to - preexisting filesystems. - Even if you leave this disabled, you can enable BBT writes at module - load time (assuming you build diskonchip as a module) with the module - parameter "inftl_bbt_write=1". - -config MTD_NAND_DOCG4 - tristate "Support for DiskOnChip G4" - depends on HAS_IOMEM - select BCH - select BITREVERSE - help - Support for diskonchip G4 nand flash, found in various smartphones and - PDAs, among them the Palm Treo680, HTC Prophet and Wizard, Toshiba - Portege G900, Asus P526, and O2 XDA Zinc. - - With this driver you will be able to use UBI and create a ubifs on the - device, so you may wish to consider enabling UBI and UBIFS as well. - - These devices ship with the Mys/Sandisk SAFTL formatting, for which - there is currently no mtd parser, so you may want to use command line - partitioning to segregate write-protected blocks. On the Treo680, the - first five erase blocks (256KiB each) are write-protected, followed - by the block containing the saftl partition table. This is probably - typical. - -config MTD_NAND_SHARPSL - tristate "Support for NAND Flash on Sharp SL Series (C7xx + others)" - depends on ARCH_PXA - -config MTD_NAND_CAFE - tristate "NAND support for OLPC CAFÉ chip" - depends on PCI - select REED_SOLOMON - select REED_SOLOMON_DEC16 - help - Use NAND flash attached to the CAFÉ chip designed for the OLPC - laptop. - -config MTD_NAND_CS553X - tristate "NAND support for CS5535/CS5536 (AMD Geode companion chip)" - depends on X86_32 - depends on !UML && HAS_IOMEM - help - The CS553x companion chips for the AMD Geode processor - include NAND flash controllers with built-in hardware ECC - capabilities; enabling this option will allow you to use - these. The driver will check the MSRs to verify that the - controller is enabled for NAND, and currently requires that - the controller be in MMIO mode. - - If you say "m", the module will be called cs553x_nand. - -config MTD_NAND_ATMEL - tristate "Support for NAND Flash / SmartMedia on AT91" - depends on ARCH_AT91 - select MFD_ATMEL_SMC - help - Enables support for NAND Flash / Smart Media Card interface - on Atmel AT91 processors. - -config MTD_NAND_PXA3xx - tristate "NAND support on PXA3xx and Armada 370/XP" - depends on !MTD_NAND_MARVELL - depends on PXA3xx || ARCH_MMP || PLAT_ORION || ARCH_MVEBU - help - - This enables the driver for the NAND flash device found on - PXA3xx processors (NFCv1) and also on 32-bit Armada - platforms (XP, 370, 375, 38x, 39x) and 64-bit Armada - platforms (7K, 8K) (NFCv2). - -config MTD_NAND_MARVELL - tristate "NAND controller support on Marvell boards" - depends on PXA3xx || ARCH_MMP || PLAT_ORION || ARCH_MVEBU || \ - COMPILE_TEST - depends on HAS_IOMEM - help - This enables the NAND flash controller driver for Marvell boards, - including: - - PXA3xx processors (NFCv1) - - 32-bit Armada platforms (XP, 37x, 38x, 39x) (NFCv2) - - 64-bit Aramda platforms (7k, 8k) (NFCv2) - -config MTD_NAND_SLC_LPC32XX - tristate "NXP LPC32xx SLC Controller" - depends on ARCH_LPC32XX - help - Enables support for NXP's LPC32XX SLC (i.e. for Single Level Cell - chips) NAND controller. This is the default for the PHYTEC 3250 - reference board which contains a NAND256R3A2CZA6 chip. - - Please check the actual NAND chip connected and its support - by the SLC NAND controller. - -config MTD_NAND_MLC_LPC32XX - tristate "NXP LPC32xx MLC Controller" - depends on ARCH_LPC32XX - help - Uses the LPC32XX MLC (i.e. for Multi Level Cell chips) NAND - controller. This is the default for the WORK92105 controller - board. - - Please check the actual NAND chip connected and its support - by the MLC NAND controller. - -config MTD_NAND_CM_X270 - tristate "Support for NAND Flash on CM-X270 modules" - depends on MACH_ARMCORE - -config MTD_NAND_PASEMI - tristate "NAND support for PA Semi PWRficient" - depends on PPC_PASEMI - help - Enables support for NAND Flash interface on PA Semi PWRficient - based boards - -config MTD_NAND_TMIO - tristate "NAND Flash device on Toshiba Mobile IO Controller" - depends on MFD_TMIO - help - Support for NAND flash connected to a Toshiba Mobile IO - Controller in some PDAs, including the Sharp SL6000x. - -config MTD_NAND_NANDSIM - tristate "Support for NAND Flash Simulator" - help - The simulator may simulate various NAND flash chips for the - MTD nand layer. - -config MTD_NAND_GPMI_NAND - tristate "GPMI NAND Flash Controller driver" - depends on MTD_NAND && MXS_DMA - help - Enables NAND Flash support for IMX23, IMX28 or IMX6. - The GPMI controller is very powerful, with the help of BCH - module, it can do the hardware ECC. The GPMI supports several - NAND flashs at the same time. - -config MTD_NAND_BRCMNAND - tristate "Broadcom STB NAND controller" - depends on ARM || ARM64 || MIPS - help - Enables the Broadcom NAND controller driver. The controller was - originally designed for Set-Top Box but is used on various BCM7xxx, - BCM3xxx, BCM63xxx, iProc/Cygnus and more. - -config MTD_NAND_BCM47XXNFLASH - tristate "Support for NAND flash on BCM4706 BCMA bus" - depends on BCMA_NFLASH - help - BCMA bus can have various flash memories attached, they are - registered by bcma as platform devices. This enables driver for - NAND flash memories. For now only BCM4706 is supported. - -config MTD_NAND_PLATFORM - tristate "Support for generic platform NAND driver" - depends on HAS_IOMEM - help - This implements a generic NAND driver for on-SOC platform - devices. You will need to provide platform-specific functions - via platform_data. - -config MTD_NAND_ORION - tristate "NAND Flash support for Marvell Orion SoC" - depends on PLAT_ORION - help - This enables the NAND flash controller on Orion machines. - - No board specific support is done by this driver, each board - must advertise a platform_device for the driver to attach. - -config MTD_NAND_OXNAS - tristate "NAND Flash support for Oxford Semiconductor SoC" - depends on ARCH_OXNAS || COMPILE_TEST - depends on HAS_IOMEM - help - This enables the NAND flash controller on Oxford Semiconductor SoCs. - -config MTD_NAND_FSL_ELBC - tristate "NAND support for Freescale eLBC controllers" - depends on FSL_SOC - select FSL_LBC - help - Various Freescale chips, including the 8313, include a NAND Flash - Controller Module with built-in hardware ECC capabilities. - Enabling this option will enable you to use this to control - external NAND devices. - -config MTD_NAND_FSL_IFC - tristate "NAND support for Freescale IFC controller" - depends on FSL_SOC || ARCH_LAYERSCAPE || SOC_LS1021A - select FSL_IFC - select MEMORY - help - Various Freescale chips e.g P1010, include a NAND Flash machine - with built-in hardware ECC capabilities. - Enabling this option will enable you to use this to control - external NAND devices. - -config MTD_NAND_FSL_UPM - tristate "Support for NAND on Freescale UPM" - depends on PPC_83xx || PPC_85xx - select FSL_LBC - help - Enables support for NAND Flash chips wired onto Freescale PowerPC - processor localbus with User-Programmable Machine support. - -config MTD_NAND_MPC5121_NFC - tristate "MPC5121 built-in NAND Flash Controller support" - depends on PPC_MPC512x - help - This enables the driver for the NAND flash controller on the - MPC5121 SoC. - -config MTD_NAND_VF610_NFC - tristate "Support for Freescale NFC for VF610/MPC5125" - depends on (SOC_VF610 || COMPILE_TEST) - depends on HAS_IOMEM - help - Enables support for NAND Flash Controller on some Freescale - processors like the VF610, MPC5125, MCF54418 or Kinetis K70. - The driver supports a maximum 2k page size. With 2k pages and - 64 bytes or more of OOB, hardware ECC with up to 32-bit error - correction is supported. Hardware ECC is only enabled through - device tree. - -config MTD_NAND_MXC - tristate "MXC NAND support" - depends on ARCH_MXC - help - This enables the driver for the NAND flash controller on the - MXC processors. - -config MTD_NAND_SH_FLCTL - tristate "Support for NAND on Renesas SuperH FLCTL" - depends on SUPERH || COMPILE_TEST - depends on HAS_IOMEM - depends on HAS_DMA - help - Several Renesas SuperH CPU has FLCTL. This option enables support - for NAND Flash using FLCTL. - -config MTD_NAND_DAVINCI - tristate "Support NAND on DaVinci/Keystone SoC" - depends on ARCH_DAVINCI || (ARCH_KEYSTONE && TI_AEMIF) - help - Enable the driver for NAND flash chips on Texas Instruments - DaVinci/Keystone processors. - -config MTD_NAND_TXX9NDFMC - tristate "NAND Flash support for TXx9 SoC" - depends on SOC_TX4938 || SOC_TX4939 - help - This enables the NAND flash controller on the TXx9 SoCs. - -config MTD_NAND_SOCRATES - tristate "Support for NAND on Socrates board" - depends on SOCRATES - help - Enables support for NAND Flash chips wired onto Socrates board. - -config MTD_NAND_NUC900 - tristate "Support for NAND on Nuvoton NUC9xx/w90p910 evaluation boards." - depends on ARCH_W90X900 - help - This enables the driver for the NAND Flash on evaluation board based - on w90p910 / NUC9xx. - -config MTD_NAND_JZ4740 - tristate "Support for JZ4740 SoC NAND controller" - depends on MACH_JZ4740 - help - Enables support for NAND Flash on JZ4740 SoC based boards. - -config MTD_NAND_JZ4780 - tristate "Support for NAND on JZ4780 SoC" - depends on MACH_JZ4780 && JZ4780_NEMC - help - Enables support for NAND Flash connected to the NEMC on JZ4780 SoC - based boards, using the BCH controller for hardware error correction. - -config MTD_NAND_FSMC - tristate "Support for NAND on ST Micros FSMC" - depends on OF - depends on PLAT_SPEAR || ARCH_NOMADIK || ARCH_U8500 || MACH_U300 - help - Enables support for NAND Flash chips on the ST Microelectronics - Flexible Static Memory Controller (FSMC) - -config MTD_NAND_XWAY - bool "Support for NAND on Lantiq XWAY SoC" - depends on LANTIQ && SOC_TYPE_XWAY - help - Enables support for NAND Flash chips on Lantiq XWAY SoCs. NAND is attached - to the External Bus Unit (EBU). - -config MTD_NAND_SUNXI - tristate "Support for NAND on Allwinner SoCs" - depends on ARCH_SUNXI - help - Enables support for NAND Flash chips on Allwinner SoCs. - -config MTD_NAND_HISI504 - tristate "Support for NAND controller on Hisilicon SoC Hip04" - depends on ARCH_HISI || COMPILE_TEST - depends on HAS_DMA - help - Enables support for NAND controller on Hisilicon SoC Hip04. - -config MTD_NAND_QCOM - tristate "Support for NAND on QCOM SoCs" - depends on ARCH_QCOM - help - Enables support for NAND flash chips on SoCs containing the EBI2 NAND - controller. This controller is found on IPQ806x SoC. - -config MTD_NAND_MTK - tristate "Support for NAND controller on MTK SoCs" - depends on ARCH_MEDIATEK || COMPILE_TEST - depends on HAS_DMA - help - Enables support for NAND controller on MTK SoCs. - This controller is found on mt27xx, mt81xx, mt65xx SoCs. - -endif # MTD_NAND +source "drivers/mtd/nand/raw/Kconfig" diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index 4e0982476267..32af7168c5ba 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -1,68 +1,3 @@ # SPDX-License-Identifier: GPL-2.0 -obj-$(CONFIG_MTD_NAND) += nand.o -obj-$(CONFIG_MTD_NAND_ECC) += nand_ecc.o -obj-$(CONFIG_MTD_NAND_BCH) += nand_bch.o -obj-$(CONFIG_MTD_SM_COMMON) += sm_common.o - -obj-$(CONFIG_MTD_NAND_CAFE) += cafe_nand.o -obj-$(CONFIG_MTD_NAND_AMS_DELTA) += ams-delta.o -obj-$(CONFIG_MTD_NAND_DENALI) += denali.o -obj-$(CONFIG_MTD_NAND_DENALI_PCI) += denali_pci.o -obj-$(CONFIG_MTD_NAND_DENALI_DT) += denali_dt.o -obj-$(CONFIG_MTD_NAND_AU1550) += au1550nd.o -obj-$(CONFIG_MTD_NAND_BF5XX) += bf5xx_nand.o -obj-$(CONFIG_MTD_NAND_S3C2410) += s3c2410.o -obj-$(CONFIG_MTD_NAND_TANGO) += tango_nand.o -obj-$(CONFIG_MTD_NAND_DAVINCI) += davinci_nand.o -obj-$(CONFIG_MTD_NAND_DISKONCHIP) += diskonchip.o -obj-$(CONFIG_MTD_NAND_DOCG4) += docg4.o -obj-$(CONFIG_MTD_NAND_FSMC) += fsmc_nand.o -obj-$(CONFIG_MTD_NAND_SHARPSL) += sharpsl.o -obj-$(CONFIG_MTD_NAND_NANDSIM) += nandsim.o -obj-$(CONFIG_MTD_NAND_CS553X) += cs553x_nand.o -obj-$(CONFIG_MTD_NAND_NDFC) += ndfc.o -obj-$(CONFIG_MTD_NAND_ATMEL) += atmel/ -obj-$(CONFIG_MTD_NAND_GPIO) += gpio.o -omap2_nand-objs := omap2.o -obj-$(CONFIG_MTD_NAND_OMAP2) += omap2_nand.o -obj-$(CONFIG_MTD_NAND_OMAP_BCH_BUILD) += omap_elm.o -obj-$(CONFIG_MTD_NAND_CM_X270) += cmx270_nand.o -obj-$(CONFIG_MTD_NAND_PXA3xx) += pxa3xx_nand.o -obj-$(CONFIG_MTD_NAND_MARVELL) += marvell_nand.o -obj-$(CONFIG_MTD_NAND_TMIO) += tmio_nand.o -obj-$(CONFIG_MTD_NAND_PLATFORM) += plat_nand.o -obj-$(CONFIG_MTD_NAND_PASEMI) += pasemi_nand.o -obj-$(CONFIG_MTD_NAND_ORION) += orion_nand.o -obj-$(CONFIG_MTD_NAND_OXNAS) += oxnas_nand.o -obj-$(CONFIG_MTD_NAND_FSL_ELBC) += fsl_elbc_nand.o -obj-$(CONFIG_MTD_NAND_FSL_IFC) += fsl_ifc_nand.o -obj-$(CONFIG_MTD_NAND_FSL_UPM) += fsl_upm.o -obj-$(CONFIG_MTD_NAND_SLC_LPC32XX) += lpc32xx_slc.o -obj-$(CONFIG_MTD_NAND_MLC_LPC32XX) += lpc32xx_mlc.o -obj-$(CONFIG_MTD_NAND_SH_FLCTL) += sh_flctl.o -obj-$(CONFIG_MTD_NAND_MXC) += mxc_nand.o -obj-$(CONFIG_MTD_NAND_SOCRATES) += socrates_nand.o -obj-$(CONFIG_MTD_NAND_TXX9NDFMC) += txx9ndfmc.o -obj-$(CONFIG_MTD_NAND_NUC900) += nuc900_nand.o -obj-$(CONFIG_MTD_NAND_MPC5121_NFC) += mpc5121_nfc.o -obj-$(CONFIG_MTD_NAND_VF610_NFC) += vf610_nfc.o -obj-$(CONFIG_MTD_NAND_RICOH) += r852.o -obj-$(CONFIG_MTD_NAND_JZ4740) += jz4740_nand.o -obj-$(CONFIG_MTD_NAND_JZ4780) += jz4780_nand.o jz4780_bch.o -obj-$(CONFIG_MTD_NAND_GPMI_NAND) += gpmi-nand/ -obj-$(CONFIG_MTD_NAND_XWAY) += xway_nand.o -obj-$(CONFIG_MTD_NAND_BCM47XXNFLASH) += bcm47xxnflash/ -obj-$(CONFIG_MTD_NAND_SUNXI) += sunxi_nand.o -obj-$(CONFIG_MTD_NAND_HISI504) += hisi504_nand.o -obj-$(CONFIG_MTD_NAND_BRCMNAND) += brcmnand/ -obj-$(CONFIG_MTD_NAND_QCOM) += qcom_nandc.o -obj-$(CONFIG_MTD_NAND_MTK) += mtk_ecc.o mtk_nand.o - -nand-objs := nand_base.o nand_bbt.o nand_timings.o nand_ids.o -nand-objs += nand_amd.o -nand-objs += nand_hynix.o -nand-objs += nand_macronix.o -nand-objs += nand_micron.o -nand-objs += nand_samsung.o -nand-objs += nand_toshiba.o +obj-y += raw/ diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig new file mode 100644 index 000000000000..e6b8c59f2c0d --- /dev/null +++ b/drivers/mtd/nand/raw/Kconfig @@ -0,0 +1,580 @@ +config MTD_NAND_ECC + tristate + +config MTD_NAND_ECC_SMC + bool "NAND ECC Smart Media byte order" + depends on MTD_NAND_ECC + default n + help + Software ECC according to the Smart Media Specification. + The original Linux implementation had byte 0 and 1 swapped. + + +menuconfig MTD_NAND + tristate "NAND Device Support" + depends on MTD + select MTD_NAND_ECC + help + This enables support for accessing all type of NAND flash + devices. For further information see + . + +if MTD_NAND + +config MTD_NAND_BCH + tristate + select BCH + depends on MTD_NAND_ECC_BCH + default MTD_NAND + +config MTD_NAND_ECC_BCH + bool "Support software BCH ECC" + default n + help + This enables support for software BCH error correction. Binary BCH + codes are more powerful and cpu intensive than traditional Hamming + ECC codes. They are used with NAND devices requiring more than 1 bit + of error correction. + +config MTD_SM_COMMON + tristate + default n + +config MTD_NAND_DENALI + tristate + +config MTD_NAND_DENALI_PCI + tristate "Support Denali NAND controller on Intel Moorestown" + select MTD_NAND_DENALI + depends on HAS_DMA && PCI + help + Enable the driver for NAND flash on Intel Moorestown, using the + Denali NAND controller core. + +config MTD_NAND_DENALI_DT + tristate "Support Denali NAND controller as a DT device" + select MTD_NAND_DENALI + depends on HAS_DMA && HAVE_CLK && OF + help + Enable the driver for NAND flash on platforms using a Denali NAND + controller as a DT device. + +config MTD_NAND_GPIO + tristate "GPIO assisted NAND Flash driver" + depends on GPIOLIB || COMPILE_TEST + depends on HAS_IOMEM + help + This enables a NAND flash driver where control signals are + connected to GPIO pins, and commands and data are communicated + via a memory mapped interface. + +config MTD_NAND_AMS_DELTA + tristate "NAND Flash device on Amstrad E3" + depends on MACH_AMS_DELTA + default y + help + Support for NAND flash on Amstrad E3 (Delta). + +config MTD_NAND_OMAP2 + tristate "NAND Flash device on OMAP2, OMAP3, OMAP4 and Keystone" + depends on (ARCH_OMAP2PLUS || ARCH_KEYSTONE) + help + Support for NAND flash on Texas Instruments OMAP2, OMAP3, OMAP4 + and Keystone platforms. + +config MTD_NAND_OMAP_BCH + depends on MTD_NAND_OMAP2 + bool "Support hardware based BCH error correction" + default n + select BCH + help + This config enables the ELM hardware engine, which can be used to + locate and correct errors when using BCH ECC scheme. This offloads + the cpu from doing ECC error searching and correction. However some + legacy OMAP families like OMAP2xxx, OMAP3xxx do not have ELM engine + so this is optional for them. + +config MTD_NAND_OMAP_BCH_BUILD + def_tristate MTD_NAND_OMAP2 && MTD_NAND_OMAP_BCH + +config MTD_NAND_RICOH + tristate "Ricoh xD card reader" + default n + depends on PCI + select MTD_SM_COMMON + help + Enable support for Ricoh R5C852 xD card reader + You also need to enable ether + NAND SSFDC (SmartMedia) read only translation layer' or new + expermental, readwrite + 'SmartMedia/xD new translation layer' + +config MTD_NAND_AU1550 + tristate "Au1550/1200 NAND support" + depends on MIPS_ALCHEMY + help + This enables the driver for the NAND flash controller on the + AMD/Alchemy 1550 SOC. + +config MTD_NAND_BF5XX + tristate "Blackfin on-chip NAND Flash Controller driver" + depends on BF54x || BF52x + help + This enables the Blackfin on-chip NAND flash controller + + No board specific support is done by this driver, each board + must advertise a platform_device for the driver to attach. + + This driver can also be built as a module. If so, the module + will be called bf5xx-nand. + +config MTD_NAND_BF5XX_HWECC + bool "BF5XX NAND Hardware ECC" + default y + depends on MTD_NAND_BF5XX + help + Enable the use of the BF5XX's internal ECC generator when + using NAND. + +config MTD_NAND_BF5XX_BOOTROM_ECC + bool "Use Blackfin BootROM ECC Layout" + default n + depends on MTD_NAND_BF5XX_HWECC + help + If you wish to modify NAND pages and allow the Blackfin on-chip + BootROM to boot from them, say Y here. This is only necessary + if you are booting U-Boot out of NAND and you wish to update + U-Boot from Linux' userspace. Otherwise, you should say N here. + + If unsure, say N. + +config MTD_NAND_S3C2410 + tristate "NAND Flash support for Samsung S3C SoCs" + depends on ARCH_S3C24XX || ARCH_S3C64XX + help + This enables the NAND flash controller on the S3C24xx and S3C64xx + SoCs + + No board specific support is done by this driver, each board + must advertise a platform_device for the driver to attach. + +config MTD_NAND_S3C2410_DEBUG + bool "Samsung S3C NAND driver debug" + depends on MTD_NAND_S3C2410 + help + Enable debugging of the S3C NAND driver + +config MTD_NAND_NDFC + tristate "NDFC NanD Flash Controller" + depends on 4xx + select MTD_NAND_ECC_SMC + help + NDFC Nand Flash Controllers are integrated in IBM/AMCC's 4xx SoCs + +config MTD_NAND_S3C2410_CLKSTOP + bool "Samsung S3C NAND IDLE clock stop" + depends on MTD_NAND_S3C2410 + default n + help + Stop the clock to the NAND controller when there is no chip + selected to save power. This will mean there is a small delay + when the is NAND chip selected or released, but will save + approximately 5mA of power when there is nothing happening. + +config MTD_NAND_TANGO + tristate "NAND Flash support for Tango chips" + depends on ARCH_TANGO || COMPILE_TEST + depends on HAS_DMA + help + Enables the NAND Flash controller on Tango chips. + +config MTD_NAND_DISKONCHIP + tristate "DiskOnChip 2000, Millennium and Millennium Plus (NAND reimplementation)" + depends on HAS_IOMEM + select REED_SOLOMON + select REED_SOLOMON_DEC16 + help + This is a reimplementation of M-Systems DiskOnChip 2000, + Millennium and Millennium Plus as a standard NAND device driver, + as opposed to the earlier self-contained MTD device drivers. + This should enable, among other things, proper JFFS2 operation on + these devices. + +config MTD_NAND_DISKONCHIP_PROBE_ADVANCED + bool "Advanced detection options for DiskOnChip" + depends on MTD_NAND_DISKONCHIP + help + This option allows you to specify nonstandard address at which to + probe for a DiskOnChip, or to change the detection options. You + are unlikely to need any of this unless you are using LinuxBIOS. + Say 'N'. + +config MTD_NAND_DISKONCHIP_PROBE_ADDRESS + hex "Physical address of DiskOnChip" if MTD_NAND_DISKONCHIP_PROBE_ADVANCED + depends on MTD_NAND_DISKONCHIP + default "0" + ---help--- + By default, the probe for DiskOnChip devices will look for a + DiskOnChip at every multiple of 0x2000 between 0xC8000 and 0xEE000. + This option allows you to specify a single address at which to probe + for the device, which is useful if you have other devices in that + range which get upset when they are probed. + + (Note that on PowerPC, the normal probe will only check at + 0xE4000000.) + + Normally, you should leave this set to zero, to allow the probe at + the normal addresses. + +config MTD_NAND_DISKONCHIP_PROBE_HIGH + bool "Probe high addresses" + depends on MTD_NAND_DISKONCHIP_PROBE_ADVANCED + help + By default, the probe for DiskOnChip devices will look for a + DiskOnChip at every multiple of 0x2000 between 0xC8000 and 0xEE000. + This option changes to make it probe between 0xFFFC8000 and + 0xFFFEE000. Unless you are using LinuxBIOS, this is unlikely to be + useful to you. Say 'N'. + +config MTD_NAND_DISKONCHIP_BBTWRITE + bool "Allow BBT writes on DiskOnChip Millennium and 2000TSOP" + depends on MTD_NAND_DISKONCHIP + help + On DiskOnChip devices shipped with the INFTL filesystem (Millennium + and 2000 TSOP/Alon), Linux reserves some space at the end of the + device for the Bad Block Table (BBT). If you have existing INFTL + data on your device (created by non-Linux tools such as M-Systems' + DOS drivers), your data might overlap the area Linux wants to use for + the BBT. If this is a concern for you, leave this option disabled and + Linux will not write BBT data into this area. + The downside of leaving this option disabled is that if bad blocks + are detected by Linux, they will not be recorded in the BBT, which + could cause future problems. + Once you enable this option, new filesystems (INFTL or others, created + in Linux or other operating systems) will not use the reserved area. + The only reason not to enable this option is to prevent damage to + preexisting filesystems. + Even if you leave this disabled, you can enable BBT writes at module + load time (assuming you build diskonchip as a module) with the module + parameter "inftl_bbt_write=1". + +config MTD_NAND_DOCG4 + tristate "Support for DiskOnChip G4" + depends on HAS_IOMEM + select BCH + select BITREVERSE + help + Support for diskonchip G4 nand flash, found in various smartphones and + PDAs, among them the Palm Treo680, HTC Prophet and Wizard, Toshiba + Portege G900, Asus P526, and O2 XDA Zinc. + + With this driver you will be able to use UBI and create a ubifs on the + device, so you may wish to consider enabling UBI and UBIFS as well. + + These devices ship with the Mys/Sandisk SAFTL formatting, for which + there is currently no mtd parser, so you may want to use command line + partitioning to segregate write-protected blocks. On the Treo680, the + first five erase blocks (256KiB each) are write-protected, followed + by the block containing the saftl partition table. This is probably + typical. + +config MTD_NAND_SHARPSL + tristate "Support for NAND Flash on Sharp SL Series (C7xx + others)" + depends on ARCH_PXA + +config MTD_NAND_CAFE + tristate "NAND support for OLPC CAFÉ chip" + depends on PCI + select REED_SOLOMON + select REED_SOLOMON_DEC16 + help + Use NAND flash attached to the CAFÉ chip designed for the OLPC + laptop. + +config MTD_NAND_CS553X + tristate "NAND support for CS5535/CS5536 (AMD Geode companion chip)" + depends on X86_32 + depends on !UML && HAS_IOMEM + help + The CS553x companion chips for the AMD Geode processor + include NAND flash controllers with built-in hardware ECC + capabilities; enabling this option will allow you to use + these. The driver will check the MSRs to verify that the + controller is enabled for NAND, and currently requires that + the controller be in MMIO mode. + + If you say "m", the module will be called cs553x_nand. + +config MTD_NAND_ATMEL + tristate "Support for NAND Flash / SmartMedia on AT91" + depends on ARCH_AT91 + select MFD_ATMEL_SMC + help + Enables support for NAND Flash / Smart Media Card interface + on Atmel AT91 processors. + +config MTD_NAND_PXA3xx + tristate "NAND support on PXA3xx and Armada 370/XP" + depends on !MTD_NAND_MARVELL + depends on PXA3xx || ARCH_MMP || PLAT_ORION || ARCH_MVEBU + help + + This enables the driver for the NAND flash device found on + PXA3xx processors (NFCv1) and also on 32-bit Armada + platforms (XP, 370, 375, 38x, 39x) and 64-bit Armada + platforms (7K, 8K) (NFCv2). + +config MTD_NAND_MARVELL + tristate "NAND controller support on Marvell boards" + depends on PXA3xx || ARCH_MMP || PLAT_ORION || ARCH_MVEBU || \ + COMPILE_TEST + depends on HAS_IOMEM + help + This enables the NAND flash controller driver for Marvell boards, + including: + - PXA3xx processors (NFCv1) + - 32-bit Armada platforms (XP, 37x, 38x, 39x) (NFCv2) + - 64-bit Aramda platforms (7k, 8k) (NFCv2) + +config MTD_NAND_SLC_LPC32XX + tristate "NXP LPC32xx SLC Controller" + depends on ARCH_LPC32XX + help + Enables support for NXP's LPC32XX SLC (i.e. for Single Level Cell + chips) NAND controller. This is the default for the PHYTEC 3250 + reference board which contains a NAND256R3A2CZA6 chip. + + Please check the actual NAND chip connected and its support + by the SLC NAND controller. + +config MTD_NAND_MLC_LPC32XX + tristate "NXP LPC32xx MLC Controller" + depends on ARCH_LPC32XX + help + Uses the LPC32XX MLC (i.e. for Multi Level Cell chips) NAND + controller. This is the default for the WORK92105 controller + board. + + Please check the actual NAND chip connected and its support + by the MLC NAND controller. + +config MTD_NAND_CM_X270 + tristate "Support for NAND Flash on CM-X270 modules" + depends on MACH_ARMCORE + +config MTD_NAND_PASEMI + tristate "NAND support for PA Semi PWRficient" + depends on PPC_PASEMI + help + Enables support for NAND Flash interface on PA Semi PWRficient + based boards + +config MTD_NAND_TMIO + tristate "NAND Flash device on Toshiba Mobile IO Controller" + depends on MFD_TMIO + help + Support for NAND flash connected to a Toshiba Mobile IO + Controller in some PDAs, including the Sharp SL6000x. + +config MTD_NAND_NANDSIM + tristate "Support for NAND Flash Simulator" + help + The simulator may simulate various NAND flash chips for the + MTD nand layer. + +config MTD_NAND_GPMI_NAND + tristate "GPMI NAND Flash Controller driver" + depends on MTD_NAND && MXS_DMA + help + Enables NAND Flash support for IMX23, IMX28 or IMX6. + The GPMI controller is very powerful, with the help of BCH + module, it can do the hardware ECC. The GPMI supports several + NAND flashs at the same time. + +config MTD_NAND_BRCMNAND + tristate "Broadcom STB NAND controller" + depends on ARM || ARM64 || MIPS + help + Enables the Broadcom NAND controller driver. The controller was + originally designed for Set-Top Box but is used on various BCM7xxx, + BCM3xxx, BCM63xxx, iProc/Cygnus and more. + +config MTD_NAND_BCM47XXNFLASH + tristate "Support for NAND flash on BCM4706 BCMA bus" + depends on BCMA_NFLASH + help + BCMA bus can have various flash memories attached, they are + registered by bcma as platform devices. This enables driver for + NAND flash memories. For now only BCM4706 is supported. + +config MTD_NAND_PLATFORM + tristate "Support for generic platform NAND driver" + depends on HAS_IOMEM + help + This implements a generic NAND driver for on-SOC platform + devices. You will need to provide platform-specific functions + via platform_data. + +config MTD_NAND_ORION + tristate "NAND Flash support for Marvell Orion SoC" + depends on PLAT_ORION + help + This enables the NAND flash controller on Orion machines. + + No board specific support is done by this driver, each board + must advertise a platform_device for the driver to attach. + +config MTD_NAND_OXNAS + tristate "NAND Flash support for Oxford Semiconductor SoC" + depends on ARCH_OXNAS || COMPILE_TEST + depends on HAS_IOMEM + help + This enables the NAND flash controller on Oxford Semiconductor SoCs. + +config MTD_NAND_FSL_ELBC + tristate "NAND support for Freescale eLBC controllers" + depends on FSL_SOC + select FSL_LBC + help + Various Freescale chips, including the 8313, include a NAND Flash + Controller Module with built-in hardware ECC capabilities. + Enabling this option will enable you to use this to control + external NAND devices. + +config MTD_NAND_FSL_IFC + tristate "NAND support for Freescale IFC controller" + depends on FSL_SOC || ARCH_LAYERSCAPE || SOC_LS1021A + select FSL_IFC + select MEMORY + help + Various Freescale chips e.g P1010, include a NAND Flash machine + with built-in hardware ECC capabilities. + Enabling this option will enable you to use this to control + external NAND devices. + +config MTD_NAND_FSL_UPM + tristate "Support for NAND on Freescale UPM" + depends on PPC_83xx || PPC_85xx + select FSL_LBC + help + Enables support for NAND Flash chips wired onto Freescale PowerPC + processor localbus with User-Programmable Machine support. + +config MTD_NAND_MPC5121_NFC + tristate "MPC5121 built-in NAND Flash Controller support" + depends on PPC_MPC512x + help + This enables the driver for the NAND flash controller on the + MPC5121 SoC. + +config MTD_NAND_VF610_NFC + tristate "Support for Freescale NFC for VF610/MPC5125" + depends on (SOC_VF610 || COMPILE_TEST) + depends on HAS_IOMEM + help + Enables support for NAND Flash Controller on some Freescale + processors like the VF610, MPC5125, MCF54418 or Kinetis K70. + The driver supports a maximum 2k page size. With 2k pages and + 64 bytes or more of OOB, hardware ECC with up to 32-bit error + correction is supported. Hardware ECC is only enabled through + device tree. + +config MTD_NAND_MXC + tristate "MXC NAND support" + depends on ARCH_MXC + help + This enables the driver for the NAND flash controller on the + MXC processors. + +config MTD_NAND_SH_FLCTL + tristate "Support for NAND on Renesas SuperH FLCTL" + depends on SUPERH || COMPILE_TEST + depends on HAS_IOMEM + depends on HAS_DMA + help + Several Renesas SuperH CPU has FLCTL. This option enables support + for NAND Flash using FLCTL. + +config MTD_NAND_DAVINCI + tristate "Support NAND on DaVinci/Keystone SoC" + depends on ARCH_DAVINCI || (ARCH_KEYSTONE && TI_AEMIF) + help + Enable the driver for NAND flash chips on Texas Instruments + DaVinci/Keystone processors. + +config MTD_NAND_TXX9NDFMC + tristate "NAND Flash support for TXx9 SoC" + depends on SOC_TX4938 || SOC_TX4939 + help + This enables the NAND flash controller on the TXx9 SoCs. + +config MTD_NAND_SOCRATES + tristate "Support for NAND on Socrates board" + depends on SOCRATES + help + Enables support for NAND Flash chips wired onto Socrates board. + +config MTD_NAND_NUC900 + tristate "Support for NAND on Nuvoton NUC9xx/w90p910 evaluation boards." + depends on ARCH_W90X900 + help + This enables the driver for the NAND Flash on evaluation board based + on w90p910 / NUC9xx. + +config MTD_NAND_JZ4740 + tristate "Support for JZ4740 SoC NAND controller" + depends on MACH_JZ4740 + help + Enables support for NAND Flash on JZ4740 SoC based boards. + +config MTD_NAND_JZ4780 + tristate "Support for NAND on JZ4780 SoC" + depends on MACH_JZ4780 && JZ4780_NEMC + help + Enables support for NAND Flash connected to the NEMC on JZ4780 SoC + based boards, using the BCH controller for hardware error correction. + +config MTD_NAND_FSMC + tristate "Support for NAND on ST Micros FSMC" + depends on OF + depends on PLAT_SPEAR || ARCH_NOMADIK || ARCH_U8500 || MACH_U300 + help + Enables support for NAND Flash chips on the ST Microelectronics + Flexible Static Memory Controller (FSMC) + +config MTD_NAND_XWAY + bool "Support for NAND on Lantiq XWAY SoC" + depends on LANTIQ && SOC_TYPE_XWAY + help + Enables support for NAND Flash chips on Lantiq XWAY SoCs. NAND is attached + to the External Bus Unit (EBU). + +config MTD_NAND_SUNXI + tristate "Support for NAND on Allwinner SoCs" + depends on ARCH_SUNXI + help + Enables support for NAND Flash chips on Allwinner SoCs. + +config MTD_NAND_HISI504 + tristate "Support for NAND controller on Hisilicon SoC Hip04" + depends on ARCH_HISI || COMPILE_TEST + depends on HAS_DMA + help + Enables support for NAND controller on Hisilicon SoC Hip04. + +config MTD_NAND_QCOM + tristate "Support for NAND on QCOM SoCs" + depends on ARCH_QCOM + help + Enables support for NAND flash chips on SoCs containing the EBI2 NAND + controller. This controller is found on IPQ806x SoC. + +config MTD_NAND_MTK + tristate "Support for NAND controller on MTK SoCs" + depends on ARCH_MEDIATEK || COMPILE_TEST + depends on HAS_DMA + help + Enables support for NAND controller on MTK SoCs. + This controller is found on mt27xx, mt81xx, mt65xx SoCs. + +endif # MTD_NAND diff --git a/drivers/mtd/nand/raw/Makefile b/drivers/mtd/nand/raw/Makefile new file mode 100644 index 000000000000..4e0982476267 --- /dev/null +++ b/drivers/mtd/nand/raw/Makefile @@ -0,0 +1,68 @@ +# SPDX-License-Identifier: GPL-2.0 + +obj-$(CONFIG_MTD_NAND) += nand.o +obj-$(CONFIG_MTD_NAND_ECC) += nand_ecc.o +obj-$(CONFIG_MTD_NAND_BCH) += nand_bch.o +obj-$(CONFIG_MTD_SM_COMMON) += sm_common.o + +obj-$(CONFIG_MTD_NAND_CAFE) += cafe_nand.o +obj-$(CONFIG_MTD_NAND_AMS_DELTA) += ams-delta.o +obj-$(CONFIG_MTD_NAND_DENALI) += denali.o +obj-$(CONFIG_MTD_NAND_DENALI_PCI) += denali_pci.o +obj-$(CONFIG_MTD_NAND_DENALI_DT) += denali_dt.o +obj-$(CONFIG_MTD_NAND_AU1550) += au1550nd.o +obj-$(CONFIG_MTD_NAND_BF5XX) += bf5xx_nand.o +obj-$(CONFIG_MTD_NAND_S3C2410) += s3c2410.o +obj-$(CONFIG_MTD_NAND_TANGO) += tango_nand.o +obj-$(CONFIG_MTD_NAND_DAVINCI) += davinci_nand.o +obj-$(CONFIG_MTD_NAND_DISKONCHIP) += diskonchip.o +obj-$(CONFIG_MTD_NAND_DOCG4) += docg4.o +obj-$(CONFIG_MTD_NAND_FSMC) += fsmc_nand.o +obj-$(CONFIG_MTD_NAND_SHARPSL) += sharpsl.o +obj-$(CONFIG_MTD_NAND_NANDSIM) += nandsim.o +obj-$(CONFIG_MTD_NAND_CS553X) += cs553x_nand.o +obj-$(CONFIG_MTD_NAND_NDFC) += ndfc.o +obj-$(CONFIG_MTD_NAND_ATMEL) += atmel/ +obj-$(CONFIG_MTD_NAND_GPIO) += gpio.o +omap2_nand-objs := omap2.o +obj-$(CONFIG_MTD_NAND_OMAP2) += omap2_nand.o +obj-$(CONFIG_MTD_NAND_OMAP_BCH_BUILD) += omap_elm.o +obj-$(CONFIG_MTD_NAND_CM_X270) += cmx270_nand.o +obj-$(CONFIG_MTD_NAND_PXA3xx) += pxa3xx_nand.o +obj-$(CONFIG_MTD_NAND_MARVELL) += marvell_nand.o +obj-$(CONFIG_MTD_NAND_TMIO) += tmio_nand.o +obj-$(CONFIG_MTD_NAND_PLATFORM) += plat_nand.o +obj-$(CONFIG_MTD_NAND_PASEMI) += pasemi_nand.o +obj-$(CONFIG_MTD_NAND_ORION) += orion_nand.o +obj-$(CONFIG_MTD_NAND_OXNAS) += oxnas_nand.o +obj-$(CONFIG_MTD_NAND_FSL_ELBC) += fsl_elbc_nand.o +obj-$(CONFIG_MTD_NAND_FSL_IFC) += fsl_ifc_nand.o +obj-$(CONFIG_MTD_NAND_FSL_UPM) += fsl_upm.o +obj-$(CONFIG_MTD_NAND_SLC_LPC32XX) += lpc32xx_slc.o +obj-$(CONFIG_MTD_NAND_MLC_LPC32XX) += lpc32xx_mlc.o +obj-$(CONFIG_MTD_NAND_SH_FLCTL) += sh_flctl.o +obj-$(CONFIG_MTD_NAND_MXC) += mxc_nand.o +obj-$(CONFIG_MTD_NAND_SOCRATES) += socrates_nand.o +obj-$(CONFIG_MTD_NAND_TXX9NDFMC) += txx9ndfmc.o +obj-$(CONFIG_MTD_NAND_NUC900) += nuc900_nand.o +obj-$(CONFIG_MTD_NAND_MPC5121_NFC) += mpc5121_nfc.o +obj-$(CONFIG_MTD_NAND_VF610_NFC) += vf610_nfc.o +obj-$(CONFIG_MTD_NAND_RICOH) += r852.o +obj-$(CONFIG_MTD_NAND_JZ4740) += jz4740_nand.o +obj-$(CONFIG_MTD_NAND_JZ4780) += jz4780_nand.o jz4780_bch.o +obj-$(CONFIG_MTD_NAND_GPMI_NAND) += gpmi-nand/ +obj-$(CONFIG_MTD_NAND_XWAY) += xway_nand.o +obj-$(CONFIG_MTD_NAND_BCM47XXNFLASH) += bcm47xxnflash/ +obj-$(CONFIG_MTD_NAND_SUNXI) += sunxi_nand.o +obj-$(CONFIG_MTD_NAND_HISI504) += hisi504_nand.o +obj-$(CONFIG_MTD_NAND_BRCMNAND) += brcmnand/ +obj-$(CONFIG_MTD_NAND_QCOM) += qcom_nandc.o +obj-$(CONFIG_MTD_NAND_MTK) += mtk_ecc.o mtk_nand.o + +nand-objs := nand_base.o nand_bbt.o nand_timings.o nand_ids.o +nand-objs += nand_amd.o +nand-objs += nand_hynix.o +nand-objs += nand_macronix.o +nand-objs += nand_micron.o +nand-objs += nand_samsung.o +nand-objs += nand_toshiba.o diff --git a/drivers/mtd/nand/ams-delta.c b/drivers/mtd/nand/raw/ams-delta.c similarity index 100% rename from drivers/mtd/nand/ams-delta.c rename to drivers/mtd/nand/raw/ams-delta.c diff --git a/drivers/mtd/nand/atmel/Makefile b/drivers/mtd/nand/raw/atmel/Makefile similarity index 100% rename from drivers/mtd/nand/atmel/Makefile rename to drivers/mtd/nand/raw/atmel/Makefile diff --git a/drivers/mtd/nand/atmel/nand-controller.c b/drivers/mtd/nand/raw/atmel/nand-controller.c similarity index 100% rename from drivers/mtd/nand/atmel/nand-controller.c rename to drivers/mtd/nand/raw/atmel/nand-controller.c diff --git a/drivers/mtd/nand/atmel/pmecc.c b/drivers/mtd/nand/raw/atmel/pmecc.c similarity index 100% rename from drivers/mtd/nand/atmel/pmecc.c rename to drivers/mtd/nand/raw/atmel/pmecc.c diff --git a/drivers/mtd/nand/atmel/pmecc.h b/drivers/mtd/nand/raw/atmel/pmecc.h similarity index 100% rename from drivers/mtd/nand/atmel/pmecc.h rename to drivers/mtd/nand/raw/atmel/pmecc.h diff --git a/drivers/mtd/nand/au1550nd.c b/drivers/mtd/nand/raw/au1550nd.c similarity index 100% rename from drivers/mtd/nand/au1550nd.c rename to drivers/mtd/nand/raw/au1550nd.c diff --git a/drivers/mtd/nand/bcm47xxnflash/Makefile b/drivers/mtd/nand/raw/bcm47xxnflash/Makefile similarity index 100% rename from drivers/mtd/nand/bcm47xxnflash/Makefile rename to drivers/mtd/nand/raw/bcm47xxnflash/Makefile diff --git a/drivers/mtd/nand/bcm47xxnflash/bcm47xxnflash.h b/drivers/mtd/nand/raw/bcm47xxnflash/bcm47xxnflash.h similarity index 100% rename from drivers/mtd/nand/bcm47xxnflash/bcm47xxnflash.h rename to drivers/mtd/nand/raw/bcm47xxnflash/bcm47xxnflash.h diff --git a/drivers/mtd/nand/bcm47xxnflash/main.c b/drivers/mtd/nand/raw/bcm47xxnflash/main.c similarity index 100% rename from drivers/mtd/nand/bcm47xxnflash/main.c rename to drivers/mtd/nand/raw/bcm47xxnflash/main.c diff --git a/drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c b/drivers/mtd/nand/raw/bcm47xxnflash/ops_bcm4706.c similarity index 100% rename from drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c rename to drivers/mtd/nand/raw/bcm47xxnflash/ops_bcm4706.c diff --git a/drivers/mtd/nand/bf5xx_nand.c b/drivers/mtd/nand/raw/bf5xx_nand.c similarity index 100% rename from drivers/mtd/nand/bf5xx_nand.c rename to drivers/mtd/nand/raw/bf5xx_nand.c diff --git a/drivers/mtd/nand/brcmnand/Makefile b/drivers/mtd/nand/raw/brcmnand/Makefile similarity index 100% rename from drivers/mtd/nand/brcmnand/Makefile rename to drivers/mtd/nand/raw/brcmnand/Makefile diff --git a/drivers/mtd/nand/brcmnand/bcm63138_nand.c b/drivers/mtd/nand/raw/brcmnand/bcm63138_nand.c similarity index 100% rename from drivers/mtd/nand/brcmnand/bcm63138_nand.c rename to drivers/mtd/nand/raw/brcmnand/bcm63138_nand.c diff --git a/drivers/mtd/nand/brcmnand/bcm6368_nand.c b/drivers/mtd/nand/raw/brcmnand/bcm6368_nand.c similarity index 100% rename from drivers/mtd/nand/brcmnand/bcm6368_nand.c rename to drivers/mtd/nand/raw/brcmnand/bcm6368_nand.c diff --git a/drivers/mtd/nand/brcmnand/brcmnand.c b/drivers/mtd/nand/raw/brcmnand/brcmnand.c similarity index 100% rename from drivers/mtd/nand/brcmnand/brcmnand.c rename to drivers/mtd/nand/raw/brcmnand/brcmnand.c diff --git a/drivers/mtd/nand/brcmnand/brcmnand.h b/drivers/mtd/nand/raw/brcmnand/brcmnand.h similarity index 100% rename from drivers/mtd/nand/brcmnand/brcmnand.h rename to drivers/mtd/nand/raw/brcmnand/brcmnand.h diff --git a/drivers/mtd/nand/brcmnand/brcmstb_nand.c b/drivers/mtd/nand/raw/brcmnand/brcmstb_nand.c similarity index 100% rename from drivers/mtd/nand/brcmnand/brcmstb_nand.c rename to drivers/mtd/nand/raw/brcmnand/brcmstb_nand.c diff --git a/drivers/mtd/nand/brcmnand/iproc_nand.c b/drivers/mtd/nand/raw/brcmnand/iproc_nand.c similarity index 100% rename from drivers/mtd/nand/brcmnand/iproc_nand.c rename to drivers/mtd/nand/raw/brcmnand/iproc_nand.c diff --git a/drivers/mtd/nand/cafe_nand.c b/drivers/mtd/nand/raw/cafe_nand.c similarity index 100% rename from drivers/mtd/nand/cafe_nand.c rename to drivers/mtd/nand/raw/cafe_nand.c diff --git a/drivers/mtd/nand/cmx270_nand.c b/drivers/mtd/nand/raw/cmx270_nand.c similarity index 100% rename from drivers/mtd/nand/cmx270_nand.c rename to drivers/mtd/nand/raw/cmx270_nand.c diff --git a/drivers/mtd/nand/cs553x_nand.c b/drivers/mtd/nand/raw/cs553x_nand.c similarity index 100% rename from drivers/mtd/nand/cs553x_nand.c rename to drivers/mtd/nand/raw/cs553x_nand.c diff --git a/drivers/mtd/nand/davinci_nand.c b/drivers/mtd/nand/raw/davinci_nand.c similarity index 100% rename from drivers/mtd/nand/davinci_nand.c rename to drivers/mtd/nand/raw/davinci_nand.c diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/raw/denali.c similarity index 100% rename from drivers/mtd/nand/denali.c rename to drivers/mtd/nand/raw/denali.c diff --git a/drivers/mtd/nand/denali.h b/drivers/mtd/nand/raw/denali.h similarity index 100% rename from drivers/mtd/nand/denali.h rename to drivers/mtd/nand/raw/denali.h diff --git a/drivers/mtd/nand/denali_dt.c b/drivers/mtd/nand/raw/denali_dt.c similarity index 100% rename from drivers/mtd/nand/denali_dt.c rename to drivers/mtd/nand/raw/denali_dt.c diff --git a/drivers/mtd/nand/denali_pci.c b/drivers/mtd/nand/raw/denali_pci.c similarity index 100% rename from drivers/mtd/nand/denali_pci.c rename to drivers/mtd/nand/raw/denali_pci.c diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/raw/diskonchip.c similarity index 100% rename from drivers/mtd/nand/diskonchip.c rename to drivers/mtd/nand/raw/diskonchip.c diff --git a/drivers/mtd/nand/docg4.c b/drivers/mtd/nand/raw/docg4.c similarity index 100% rename from drivers/mtd/nand/docg4.c rename to drivers/mtd/nand/raw/docg4.c diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/raw/fsl_elbc_nand.c similarity index 100% rename from drivers/mtd/nand/fsl_elbc_nand.c rename to drivers/mtd/nand/raw/fsl_elbc_nand.c diff --git a/drivers/mtd/nand/fsl_ifc_nand.c b/drivers/mtd/nand/raw/fsl_ifc_nand.c similarity index 100% rename from drivers/mtd/nand/fsl_ifc_nand.c rename to drivers/mtd/nand/raw/fsl_ifc_nand.c diff --git a/drivers/mtd/nand/fsl_upm.c b/drivers/mtd/nand/raw/fsl_upm.c similarity index 100% rename from drivers/mtd/nand/fsl_upm.c rename to drivers/mtd/nand/raw/fsl_upm.c diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/raw/fsmc_nand.c similarity index 100% rename from drivers/mtd/nand/fsmc_nand.c rename to drivers/mtd/nand/raw/fsmc_nand.c diff --git a/drivers/mtd/nand/gpio.c b/drivers/mtd/nand/raw/gpio.c similarity index 100% rename from drivers/mtd/nand/gpio.c rename to drivers/mtd/nand/raw/gpio.c diff --git a/drivers/mtd/nand/gpmi-nand/Makefile b/drivers/mtd/nand/raw/gpmi-nand/Makefile similarity index 100% rename from drivers/mtd/nand/gpmi-nand/Makefile rename to drivers/mtd/nand/raw/gpmi-nand/Makefile diff --git a/drivers/mtd/nand/gpmi-nand/bch-regs.h b/drivers/mtd/nand/raw/gpmi-nand/bch-regs.h similarity index 100% rename from drivers/mtd/nand/gpmi-nand/bch-regs.h rename to drivers/mtd/nand/raw/gpmi-nand/bch-regs.h diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c b/drivers/mtd/nand/raw/gpmi-nand/gpmi-lib.c similarity index 100% rename from drivers/mtd/nand/gpmi-nand/gpmi-lib.c rename to drivers/mtd/nand/raw/gpmi-nand/gpmi-lib.c diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c similarity index 100% rename from drivers/mtd/nand/gpmi-nand/gpmi-nand.c rename to drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.h b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.h similarity index 100% rename from drivers/mtd/nand/gpmi-nand/gpmi-nand.h rename to drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.h diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-regs.h b/drivers/mtd/nand/raw/gpmi-nand/gpmi-regs.h similarity index 100% rename from drivers/mtd/nand/gpmi-nand/gpmi-regs.h rename to drivers/mtd/nand/raw/gpmi-nand/gpmi-regs.h diff --git a/drivers/mtd/nand/hisi504_nand.c b/drivers/mtd/nand/raw/hisi504_nand.c similarity index 100% rename from drivers/mtd/nand/hisi504_nand.c rename to drivers/mtd/nand/raw/hisi504_nand.c diff --git a/drivers/mtd/nand/jz4740_nand.c b/drivers/mtd/nand/raw/jz4740_nand.c similarity index 100% rename from drivers/mtd/nand/jz4740_nand.c rename to drivers/mtd/nand/raw/jz4740_nand.c diff --git a/drivers/mtd/nand/jz4780_bch.c b/drivers/mtd/nand/raw/jz4780_bch.c similarity index 100% rename from drivers/mtd/nand/jz4780_bch.c rename to drivers/mtd/nand/raw/jz4780_bch.c diff --git a/drivers/mtd/nand/jz4780_bch.h b/drivers/mtd/nand/raw/jz4780_bch.h similarity index 100% rename from drivers/mtd/nand/jz4780_bch.h rename to drivers/mtd/nand/raw/jz4780_bch.h diff --git a/drivers/mtd/nand/jz4780_nand.c b/drivers/mtd/nand/raw/jz4780_nand.c similarity index 100% rename from drivers/mtd/nand/jz4780_nand.c rename to drivers/mtd/nand/raw/jz4780_nand.c diff --git a/drivers/mtd/nand/lpc32xx_mlc.c b/drivers/mtd/nand/raw/lpc32xx_mlc.c similarity index 100% rename from drivers/mtd/nand/lpc32xx_mlc.c rename to drivers/mtd/nand/raw/lpc32xx_mlc.c diff --git a/drivers/mtd/nand/lpc32xx_slc.c b/drivers/mtd/nand/raw/lpc32xx_slc.c similarity index 100% rename from drivers/mtd/nand/lpc32xx_slc.c rename to drivers/mtd/nand/raw/lpc32xx_slc.c diff --git a/drivers/mtd/nand/marvell_nand.c b/drivers/mtd/nand/raw/marvell_nand.c similarity index 100% rename from drivers/mtd/nand/marvell_nand.c rename to drivers/mtd/nand/raw/marvell_nand.c diff --git a/drivers/mtd/nand/mpc5121_nfc.c b/drivers/mtd/nand/raw/mpc5121_nfc.c similarity index 100% rename from drivers/mtd/nand/mpc5121_nfc.c rename to drivers/mtd/nand/raw/mpc5121_nfc.c diff --git a/drivers/mtd/nand/mtk_ecc.c b/drivers/mtd/nand/raw/mtk_ecc.c similarity index 100% rename from drivers/mtd/nand/mtk_ecc.c rename to drivers/mtd/nand/raw/mtk_ecc.c diff --git a/drivers/mtd/nand/mtk_ecc.h b/drivers/mtd/nand/raw/mtk_ecc.h similarity index 100% rename from drivers/mtd/nand/mtk_ecc.h rename to drivers/mtd/nand/raw/mtk_ecc.h diff --git a/drivers/mtd/nand/mtk_nand.c b/drivers/mtd/nand/raw/mtk_nand.c similarity index 100% rename from drivers/mtd/nand/mtk_nand.c rename to drivers/mtd/nand/raw/mtk_nand.c diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/raw/mxc_nand.c similarity index 100% rename from drivers/mtd/nand/mxc_nand.c rename to drivers/mtd/nand/raw/mxc_nand.c diff --git a/drivers/mtd/nand/nand_amd.c b/drivers/mtd/nand/raw/nand_amd.c similarity index 100% rename from drivers/mtd/nand/nand_amd.c rename to drivers/mtd/nand/raw/nand_amd.c diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/raw/nand_base.c similarity index 100% rename from drivers/mtd/nand/nand_base.c rename to drivers/mtd/nand/raw/nand_base.c diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/raw/nand_bbt.c similarity index 100% rename from drivers/mtd/nand/nand_bbt.c rename to drivers/mtd/nand/raw/nand_bbt.c diff --git a/drivers/mtd/nand/nand_bch.c b/drivers/mtd/nand/raw/nand_bch.c similarity index 100% rename from drivers/mtd/nand/nand_bch.c rename to drivers/mtd/nand/raw/nand_bch.c diff --git a/drivers/mtd/nand/nand_ecc.c b/drivers/mtd/nand/raw/nand_ecc.c similarity index 100% rename from drivers/mtd/nand/nand_ecc.c rename to drivers/mtd/nand/raw/nand_ecc.c diff --git a/drivers/mtd/nand/nand_hynix.c b/drivers/mtd/nand/raw/nand_hynix.c similarity index 100% rename from drivers/mtd/nand/nand_hynix.c rename to drivers/mtd/nand/raw/nand_hynix.c diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/raw/nand_ids.c similarity index 100% rename from drivers/mtd/nand/nand_ids.c rename to drivers/mtd/nand/raw/nand_ids.c diff --git a/drivers/mtd/nand/nand_macronix.c b/drivers/mtd/nand/raw/nand_macronix.c similarity index 100% rename from drivers/mtd/nand/nand_macronix.c rename to drivers/mtd/nand/raw/nand_macronix.c diff --git a/drivers/mtd/nand/nand_micron.c b/drivers/mtd/nand/raw/nand_micron.c similarity index 100% rename from drivers/mtd/nand/nand_micron.c rename to drivers/mtd/nand/raw/nand_micron.c diff --git a/drivers/mtd/nand/nand_samsung.c b/drivers/mtd/nand/raw/nand_samsung.c similarity index 100% rename from drivers/mtd/nand/nand_samsung.c rename to drivers/mtd/nand/raw/nand_samsung.c diff --git a/drivers/mtd/nand/nand_timings.c b/drivers/mtd/nand/raw/nand_timings.c similarity index 100% rename from drivers/mtd/nand/nand_timings.c rename to drivers/mtd/nand/raw/nand_timings.c diff --git a/drivers/mtd/nand/nand_toshiba.c b/drivers/mtd/nand/raw/nand_toshiba.c similarity index 100% rename from drivers/mtd/nand/nand_toshiba.c rename to drivers/mtd/nand/raw/nand_toshiba.c diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/raw/nandsim.c similarity index 100% rename from drivers/mtd/nand/nandsim.c rename to drivers/mtd/nand/raw/nandsim.c diff --git a/drivers/mtd/nand/ndfc.c b/drivers/mtd/nand/raw/ndfc.c similarity index 100% rename from drivers/mtd/nand/ndfc.c rename to drivers/mtd/nand/raw/ndfc.c diff --git a/drivers/mtd/nand/nuc900_nand.c b/drivers/mtd/nand/raw/nuc900_nand.c similarity index 100% rename from drivers/mtd/nand/nuc900_nand.c rename to drivers/mtd/nand/raw/nuc900_nand.c diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/raw/omap2.c similarity index 100% rename from drivers/mtd/nand/omap2.c rename to drivers/mtd/nand/raw/omap2.c diff --git a/drivers/mtd/nand/omap_elm.c b/drivers/mtd/nand/raw/omap_elm.c similarity index 100% rename from drivers/mtd/nand/omap_elm.c rename to drivers/mtd/nand/raw/omap_elm.c diff --git a/drivers/mtd/nand/orion_nand.c b/drivers/mtd/nand/raw/orion_nand.c similarity index 100% rename from drivers/mtd/nand/orion_nand.c rename to drivers/mtd/nand/raw/orion_nand.c diff --git a/drivers/mtd/nand/oxnas_nand.c b/drivers/mtd/nand/raw/oxnas_nand.c similarity index 100% rename from drivers/mtd/nand/oxnas_nand.c rename to drivers/mtd/nand/raw/oxnas_nand.c diff --git a/drivers/mtd/nand/pasemi_nand.c b/drivers/mtd/nand/raw/pasemi_nand.c similarity index 100% rename from drivers/mtd/nand/pasemi_nand.c rename to drivers/mtd/nand/raw/pasemi_nand.c diff --git a/drivers/mtd/nand/plat_nand.c b/drivers/mtd/nand/raw/plat_nand.c similarity index 100% rename from drivers/mtd/nand/plat_nand.c rename to drivers/mtd/nand/raw/plat_nand.c diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/raw/pxa3xx_nand.c similarity index 100% rename from drivers/mtd/nand/pxa3xx_nand.c rename to drivers/mtd/nand/raw/pxa3xx_nand.c diff --git a/drivers/mtd/nand/qcom_nandc.c b/drivers/mtd/nand/raw/qcom_nandc.c similarity index 100% rename from drivers/mtd/nand/qcom_nandc.c rename to drivers/mtd/nand/raw/qcom_nandc.c diff --git a/drivers/mtd/nand/r852.c b/drivers/mtd/nand/raw/r852.c similarity index 100% rename from drivers/mtd/nand/r852.c rename to drivers/mtd/nand/raw/r852.c diff --git a/drivers/mtd/nand/r852.h b/drivers/mtd/nand/raw/r852.h similarity index 100% rename from drivers/mtd/nand/r852.h rename to drivers/mtd/nand/raw/r852.h diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/raw/s3c2410.c similarity index 100% rename from drivers/mtd/nand/s3c2410.c rename to drivers/mtd/nand/raw/s3c2410.c diff --git a/drivers/mtd/nand/sh_flctl.c b/drivers/mtd/nand/raw/sh_flctl.c similarity index 100% rename from drivers/mtd/nand/sh_flctl.c rename to drivers/mtd/nand/raw/sh_flctl.c diff --git a/drivers/mtd/nand/sharpsl.c b/drivers/mtd/nand/raw/sharpsl.c similarity index 100% rename from drivers/mtd/nand/sharpsl.c rename to drivers/mtd/nand/raw/sharpsl.c diff --git a/drivers/mtd/nand/sm_common.c b/drivers/mtd/nand/raw/sm_common.c similarity index 100% rename from drivers/mtd/nand/sm_common.c rename to drivers/mtd/nand/raw/sm_common.c diff --git a/drivers/mtd/nand/sm_common.h b/drivers/mtd/nand/raw/sm_common.h similarity index 100% rename from drivers/mtd/nand/sm_common.h rename to drivers/mtd/nand/raw/sm_common.h diff --git a/drivers/mtd/nand/socrates_nand.c b/drivers/mtd/nand/raw/socrates_nand.c similarity index 100% rename from drivers/mtd/nand/socrates_nand.c rename to drivers/mtd/nand/raw/socrates_nand.c diff --git a/drivers/mtd/nand/sunxi_nand.c b/drivers/mtd/nand/raw/sunxi_nand.c similarity index 100% rename from drivers/mtd/nand/sunxi_nand.c rename to drivers/mtd/nand/raw/sunxi_nand.c diff --git a/drivers/mtd/nand/tango_nand.c b/drivers/mtd/nand/raw/tango_nand.c similarity index 100% rename from drivers/mtd/nand/tango_nand.c rename to drivers/mtd/nand/raw/tango_nand.c diff --git a/drivers/mtd/nand/tmio_nand.c b/drivers/mtd/nand/raw/tmio_nand.c similarity index 100% rename from drivers/mtd/nand/tmio_nand.c rename to drivers/mtd/nand/raw/tmio_nand.c diff --git a/drivers/mtd/nand/txx9ndfmc.c b/drivers/mtd/nand/raw/txx9ndfmc.c similarity index 100% rename from drivers/mtd/nand/txx9ndfmc.c rename to drivers/mtd/nand/raw/txx9ndfmc.c diff --git a/drivers/mtd/nand/vf610_nfc.c b/drivers/mtd/nand/raw/vf610_nfc.c similarity index 100% rename from drivers/mtd/nand/vf610_nfc.c rename to drivers/mtd/nand/raw/vf610_nfc.c diff --git a/drivers/mtd/nand/xway_nand.c b/drivers/mtd/nand/raw/xway_nand.c similarity index 100% rename from drivers/mtd/nand/xway_nand.c rename to drivers/mtd/nand/raw/xway_nand.c diff --git a/drivers/mtd/sm_ftl.c b/drivers/mtd/sm_ftl.c index 4237c7cebf02..fa176f5937bb 100644 --- a/drivers/mtd/sm_ftl.c +++ b/drivers/mtd/sm_ftl.c @@ -17,7 +17,7 @@ #include #include #include -#include "nand/sm_common.h" +#include "nand/raw/sm_common.h" #include "sm_ftl.h" From 9c3736a3de21d916a6af0594418b85a112f4bef6 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Mon, 5 Feb 2018 23:02:05 +0100 Subject: [PATCH 24/89] mtd: nand: Add core infrastructure to deal with NAND devices Add an intermediate layer to abstract NAND device interface so that some logic can be shared between SPI NANDs, parallel/raw NANDs, OneNANDs, ... Signed-off-by: Boris Brezillon --- drivers/mtd/nand/Kconfig | 3 + drivers/mtd/nand/Makefile | 3 + drivers/mtd/nand/bbt.c | 130 +++++++ drivers/mtd/nand/core.c | 244 +++++++++++++ include/linux/mtd/nand.h | 731 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 1111 insertions(+) create mode 100644 drivers/mtd/nand/bbt.c create mode 100644 drivers/mtd/nand/core.c create mode 100644 include/linux/mtd/nand.h diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index 6d5373471809..1c1a1f487e20 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -1 +1,4 @@ +config MTD_NAND_CORE + tristate + source "drivers/mtd/nand/raw/Kconfig" diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index 32af7168c5ba..a72d3cb0f325 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -1,3 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 +nandcore-objs := core.o bbt.o +obj-$(CONFIG_MTD_NAND_CORE) += nandcore.o + obj-y += raw/ diff --git a/drivers/mtd/nand/bbt.c b/drivers/mtd/nand/bbt.c new file mode 100644 index 000000000000..56cde38b92c0 --- /dev/null +++ b/drivers/mtd/nand/bbt.c @@ -0,0 +1,130 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2017 Free Electrons + * + * Authors: + * Boris Brezillon + * Peter Pan + */ + +#define pr_fmt(fmt) "nand-bbt: " fmt + +#include +#include + +/** + * nanddev_bbt_init() - Initialize the BBT (Bad Block Table) + * @nand: NAND device + * + * Initialize the in-memory BBT. + * + * Return: 0 in case of success, a negative error code otherwise. + */ +int nanddev_bbt_init(struct nand_device *nand) +{ + unsigned int bits_per_block = fls(NAND_BBT_BLOCK_NUM_STATUS); + unsigned int nblocks = nanddev_neraseblocks(nand); + unsigned int nwords = DIV_ROUND_UP(nblocks * bits_per_block, + BITS_PER_LONG); + + nand->bbt.cache = kzalloc(nwords, GFP_KERNEL); + if (!nand->bbt.cache) + return -ENOMEM; + + return 0; +} +EXPORT_SYMBOL_GPL(nanddev_bbt_init); + +/** + * nanddev_bbt_cleanup() - Cleanup the BBT (Bad Block Table) + * @nand: NAND device + * + * Undoes what has been done in nanddev_bbt_init() + */ +void nanddev_bbt_cleanup(struct nand_device *nand) +{ + kfree(nand->bbt.cache); +} +EXPORT_SYMBOL_GPL(nanddev_bbt_cleanup); + +/** + * nanddev_bbt_update() - Update a BBT + * @nand: nand device + * + * Update the BBT. Currently a NOP function since on-flash bbt is not yet + * supported. + * + * Return: 0 in case of success, a negative error code otherwise. + */ +int nanddev_bbt_update(struct nand_device *nand) +{ + return 0; +} +EXPORT_SYMBOL_GPL(nanddev_bbt_update); + +/** + * nanddev_bbt_get_block_status() - Return the status of an eraseblock + * @nand: nand device + * @entry: the BBT entry + * + * Return: a positive number nand_bbt_block_status status or -%ERANGE if @entry + * is bigger than the BBT size. + */ +int nanddev_bbt_get_block_status(const struct nand_device *nand, + unsigned int entry) +{ + unsigned int bits_per_block = fls(NAND_BBT_BLOCK_NUM_STATUS); + unsigned long *pos = nand->bbt.cache + + ((entry * bits_per_block) / BITS_PER_LONG); + unsigned int offs = (entry * bits_per_block) % BITS_PER_LONG; + unsigned long status; + + if (entry >= nanddev_neraseblocks(nand)) + return -ERANGE; + + status = pos[0] >> offs; + if (bits_per_block + offs > BITS_PER_LONG) + status |= pos[1] << (BITS_PER_LONG - offs); + + return status & GENMASK(bits_per_block - 1, 0); +} +EXPORT_SYMBOL_GPL(nanddev_bbt_get_block_status); + +/** + * nanddev_bbt_set_block_status() - Update the status of an eraseblock in the + * in-memory BBT + * @nand: nand device + * @entry: the BBT entry to update + * @status: the new status + * + * Update an entry of the in-memory BBT. If you want to push the updated BBT + * the NAND you should call nanddev_bbt_update(). + * + * Return: 0 in case of success or -%ERANGE if @entry is bigger than the BBT + * size. + */ +int nanddev_bbt_set_block_status(struct nand_device *nand, unsigned int entry, + enum nand_bbt_block_status status) +{ + unsigned int bits_per_block = fls(NAND_BBT_BLOCK_NUM_STATUS); + unsigned long *pos = nand->bbt.cache + + ((entry * bits_per_block) / BITS_PER_LONG); + unsigned int offs = (entry * bits_per_block) % BITS_PER_LONG; + unsigned long val = status & GENMASK(bits_per_block - 1, 0); + + if (entry >= nanddev_neraseblocks(nand)) + return -ERANGE; + + pos[0] &= ~GENMASK(offs + bits_per_block - 1, offs); + pos[0] |= val << offs; + + if (bits_per_block + offs > BITS_PER_LONG) { + unsigned int rbits = bits_per_block + offs - BITS_PER_LONG; + + pos[1] &= ~GENMASK(rbits - 1, 0); + pos[1] |= val >> rbits; + } + + return 0; +} +EXPORT_SYMBOL_GPL(nanddev_bbt_set_block_status); diff --git a/drivers/mtd/nand/core.c b/drivers/mtd/nand/core.c new file mode 100644 index 000000000000..f237a688f8e9 --- /dev/null +++ b/drivers/mtd/nand/core.c @@ -0,0 +1,244 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2017 Free Electrons + * + * Authors: + * Boris Brezillon + * Peter Pan + */ + +#define pr_fmt(fmt) "nand: " fmt + +#include +#include + +/** + * nanddev_isbad() - Check if a block is bad + * @nand: NAND device + * @pos: position pointing to the block we want to check + * + * Return: true if the block is bad, false otherwise. + */ +bool nanddev_isbad(struct nand_device *nand, const struct nand_pos *pos) +{ + if (nanddev_bbt_is_initialized(nand)) { + unsigned int entry; + int status; + + entry = nanddev_bbt_pos_to_entry(nand, pos); + status = nanddev_bbt_get_block_status(nand, entry); + /* Lazy block status retrieval */ + if (status == NAND_BBT_BLOCK_STATUS_UNKNOWN) { + if (nand->ops->isbad(nand, pos)) + status = NAND_BBT_BLOCK_FACTORY_BAD; + else + status = NAND_BBT_BLOCK_GOOD; + + nanddev_bbt_set_block_status(nand, entry, status); + } + + if (status == NAND_BBT_BLOCK_WORN || + status == NAND_BBT_BLOCK_FACTORY_BAD) + return true; + + return false; + } + + return nand->ops->isbad(nand, pos); +} +EXPORT_SYMBOL_GPL(nanddev_isbad); + +/** + * nanddev_markbad() - Mark a block as bad + * @nand: NAND device + * @block: block to mark bad + * + * Mark a block bad. This function is updating the BBT if available and + * calls the low-level markbad hook (nand->ops->markbad()). + * + * Return: 0 in case of success, a negative error code otherwise. + */ +int nanddev_markbad(struct nand_device *nand, const struct nand_pos *pos) +{ + struct mtd_info *mtd = nanddev_to_mtd(nand); + unsigned int entry; + int ret = 0; + + if (nanddev_isbad(nand, pos)) + return 0; + + ret = nand->ops->markbad(nand, pos); + if (ret) + pr_warn("failed to write BBM to block @%llx (err = %d)\n", + nanddev_pos_to_offs(nand, pos), ret); + + if (!nanddev_bbt_is_initialized(nand)) + goto out; + + entry = nanddev_bbt_pos_to_entry(nand, pos); + ret = nanddev_bbt_set_block_status(nand, entry, NAND_BBT_BLOCK_WORN); + if (ret) + goto out; + + ret = nanddev_bbt_update(nand); + +out: + if (!ret) + mtd->ecc_stats.badblocks++; + + return ret; +} +EXPORT_SYMBOL_GPL(nanddev_markbad); + +/** + * nanddev_isreserved() - Check whether an eraseblock is reserved or not + * @nand: NAND device + * @pos: NAND position to test + * + * Checks whether the eraseblock pointed by @pos is reserved or not. + * + * Return: true if the eraseblock is reserved, false otherwise. + */ +bool nanddev_isreserved(struct nand_device *nand, const struct nand_pos *pos) +{ + unsigned int entry; + int status; + + if (!nanddev_bbt_is_initialized(nand)) + return false; + + /* Return info from the table */ + entry = nanddev_bbt_pos_to_entry(nand, pos); + status = nanddev_bbt_get_block_status(nand, entry); + return status == NAND_BBT_BLOCK_RESERVED; +} +EXPORT_SYMBOL_GPL(nanddev_isreserved); + +/** + * nanddev_erase() - Erase a NAND portion + * @nand: NAND device + * @block: eraseblock to erase + * + * Erases @block if it's not bad. + * + * Return: 0 in case of success, a negative error code otherwise. + */ +int nanddev_erase(struct nand_device *nand, const struct nand_pos *pos) +{ + if (nanddev_isbad(nand, pos) || nanddev_isreserved(nand, pos)) { + pr_warn("attempt to erase a bad/reserved block @%llx\n", + nanddev_pos_to_offs(nand, pos)); + return -EIO; + } + + return nand->ops->erase(nand, pos); +} +EXPORT_SYMBOL_GPL(nanddev_erase); + +/** + * nanddev_mtd_erase() - Generic mtd->_erase() implementation for NAND devices + * @mtd: MTD device + * @einfo: erase request + * + * This is a simple mtd->_erase() implementation iterating over all blocks + * concerned by @einfo and calling nand->ops->erase() on each of them. + * + * Note that mtd->_erase should not be directly assigned to this helper, + * because there's no locking here. NAND specialized layers should instead + * implement there own wrapper around nanddev_mtd_erase() taking the + * appropriate lock before calling nanddev_mtd_erase(). + * + * Return: 0 in case of success, a negative error code otherwise. + */ +int nanddev_mtd_erase(struct mtd_info *mtd, struct erase_info *einfo) +{ + struct nand_device *nand = mtd_to_nanddev(mtd); + struct nand_pos pos, last; + int ret; + + nanddev_offs_to_pos(nand, einfo->addr, &pos); + nanddev_offs_to_pos(nand, einfo->addr + einfo->len - 1, &last); + while (nanddev_pos_cmp(&pos, &last) <= 0) { + ret = nanddev_erase(nand, &pos); + if (ret) { + einfo->fail_addr = nanddev_pos_to_offs(nand, &pos); + einfo->state = MTD_ERASE_FAILED; + + return ret; + } + + nanddev_pos_next_eraseblock(nand, &pos); + } + + einfo->state = MTD_ERASE_DONE; + + return 0; +} +EXPORT_SYMBOL_GPL(nanddev_mtd_erase); + +/** + * nanddev_init() - Initialize a NAND device + * @nand: NAND device + * @memorg: NAND memory organization descriptor + * @ops: NAND device operations + * + * Initializes a NAND device object. Consistency checks are done on @memorg and + * @ops. Also takes care of initializing the BBT. + * + * Return: 0 in case of success, a negative error code otherwise. + */ +int nanddev_init(struct nand_device *nand, const struct nand_ops *ops, + struct module *owner) +{ + struct mtd_info *mtd = nanddev_to_mtd(nand); + struct nand_memory_organization *memorg = nanddev_get_memorg(nand); + + if (!nand || !ops) + return -EINVAL; + + if (!ops->erase || !ops->markbad || !ops->isbad) + return -EINVAL; + + if (!memorg->bits_per_cell || !memorg->pagesize || + !memorg->pages_per_eraseblock || !memorg->eraseblocks_per_lun || + !memorg->planes_per_lun || !memorg->luns_per_target || + !memorg->ntargets) + return -EINVAL; + + nand->rowconv.eraseblock_addr_shift = + fls(memorg->pages_per_eraseblock - 1); + nand->rowconv.lun_addr_shift = fls(memorg->eraseblocks_per_lun - 1) + + nand->rowconv.eraseblock_addr_shift; + + nand->ops = ops; + + mtd->type = memorg->bits_per_cell == 1 ? + MTD_NANDFLASH : MTD_MLCNANDFLASH; + mtd->flags = MTD_CAP_NANDFLASH; + mtd->erasesize = memorg->pagesize * memorg->pages_per_eraseblock; + mtd->writesize = memorg->pagesize; + mtd->writebufsize = memorg->pagesize; + mtd->oobsize = memorg->oobsize; + mtd->size = nanddev_size(nand); + mtd->owner = owner; + + return nanddev_bbt_init(nand); +} +EXPORT_SYMBOL_GPL(nanddev_init); + +/** + * nanddev_cleanup() - Release resources allocated in nanddev_init() + * @nand: NAND device + * + * Basically undoes what has been done in nanddev_init(). + */ +void nanddev_cleanup(struct nand_device *nand) +{ + if (nanddev_bbt_is_initialized(nand)) + nanddev_bbt_cleanup(nand); +} +EXPORT_SYMBOL_GPL(nanddev_cleanup); + +MODULE_DESCRIPTION("Generic NAND framework"); +MODULE_AUTHOR("Boris Brezillon "); +MODULE_LICENSE("GPL v2"); diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h new file mode 100644 index 000000000000..792ea5c26329 --- /dev/null +++ b/include/linux/mtd/nand.h @@ -0,0 +1,731 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright 2017 - Free Electrons + * + * Authors: + * Boris Brezillon + * Peter Pan + */ + +#ifndef __LINUX_MTD_NAND_H +#define __LINUX_MTD_NAND_H + +#include + +/** + * struct nand_memory_organization - Memory organization structure + * @bits_per_cell: number of bits per NAND cell + * @pagesize: page size + * @oobsize: OOB area size + * @pages_per_eraseblock: number of pages per eraseblock + * @eraseblocks_per_lun: number of eraseblocks per LUN (Logical Unit Number) + * @planes_per_lun: number of planes per LUN + * @luns_per_target: number of LUN per target (target is a synonym for die) + * @ntargets: total number of targets exposed by the NAND device + */ +struct nand_memory_organization { + unsigned int bits_per_cell; + unsigned int pagesize; + unsigned int oobsize; + unsigned int pages_per_eraseblock; + unsigned int eraseblocks_per_lun; + unsigned int planes_per_lun; + unsigned int luns_per_target; + unsigned int ntargets; +}; + +#define NAND_MEMORG(bpc, ps, os, ppe, epl, ppl, lpt, nt) \ + { \ + .bits_per_cell = (bpc), \ + .pagesize = (ps), \ + .oobsize = (os), \ + .pages_per_eraseblock = (ppe), \ + .eraseblocks_per_lun = (epl), \ + .planes_per_lun = (ppl), \ + .luns_per_target = (lpt), \ + .ntargets = (nt), \ + } + +/** + * struct nand_row_converter - Information needed to convert an absolute offset + * into a row address + * @lun_addr_shift: position of the LUN identifier in the row address + * @eraseblock_addr_shift: position of the eraseblock identifier in the row + * address + */ +struct nand_row_converter { + unsigned int lun_addr_shift; + unsigned int eraseblock_addr_shift; +}; + +/** + * struct nand_pos - NAND position object + * @target: the NAND target/die + * @lun: the LUN identifier + * @plane: the plane within the LUN + * @eraseblock: the eraseblock within the LUN + * @page: the page within the LUN + * + * These information are usually used by specific sub-layers to select the + * appropriate target/die and generate a row address to pass to the device. + */ +struct nand_pos { + unsigned int target; + unsigned int lun; + unsigned int plane; + unsigned int eraseblock; + unsigned int page; +}; + +/** + * struct nand_page_io_req - NAND I/O request object + * @pos: the position this I/O request is targeting + * @dataoffs: the offset within the page + * @datalen: number of data bytes to read from/write to this page + * @databuf: buffer to store data in or get data from + * @ooboffs: the OOB offset within the page + * @ooblen: the number of OOB bytes to read from/write to this page + * @oobbuf: buffer to store OOB data in or get OOB data from + * + * This object is used to pass per-page I/O requests to NAND sub-layers. This + * way all useful information are already formatted in a useful way and + * specific NAND layers can focus on translating these information into + * specific commands/operations. + */ +struct nand_page_io_req { + struct nand_pos pos; + unsigned int dataoffs; + unsigned int datalen; + union { + const void *out; + void *in; + } databuf; + unsigned int ooboffs; + unsigned int ooblen; + union { + const void *out; + void *in; + } oobbuf; +}; + +/** + * struct nand_ecc_req - NAND ECC requirements + * @strength: ECC strength + * @step_size: ECC step/block size + */ +struct nand_ecc_req { + unsigned int strength; + unsigned int step_size; +}; + +#define NAND_ECCREQ(str, stp) { .strength = (str), .step_size = (stp) } + +/** + * struct nand_bbt - bad block table object + * @cache: in memory BBT cache + */ +struct nand_bbt { + unsigned long *cache; +}; + +struct nand_device; + +/** + * struct nand_ops - NAND operations + * @erase: erase a specific block. No need to check if the block is bad before + * erasing, this has been taken care of by the generic NAND layer + * @markbad: mark a specific block bad. No need to check if the block is + * already marked bad, this has been taken care of by the generic + * NAND layer. This method should just write the BBM (Bad Block + * Marker) so that future call to struct_nand_ops->isbad() return + * true + * @isbad: check whether a block is bad or not. This method should just read + * the BBM and return whether the block is bad or not based on what it + * reads + * + * These are all low level operations that should be implemented by specialized + * NAND layers (SPI NAND, raw NAND, ...). + */ +struct nand_ops { + int (*erase)(struct nand_device *nand, const struct nand_pos *pos); + int (*markbad)(struct nand_device *nand, const struct nand_pos *pos); + bool (*isbad)(struct nand_device *nand, const struct nand_pos *pos); +}; + +/** + * struct nand_device - NAND device + * @mtd: MTD instance attached to the NAND device + * @memorg: memory layout + * @eccreq: ECC requirements + * @rowconv: position to row address converter + * @bbt: bad block table info + * @ops: NAND operations attached to the NAND device + * + * Generic NAND object. Specialized NAND layers (raw NAND, SPI NAND, OneNAND) + * should declare their own NAND object embedding a nand_device struct (that's + * how inheritance is done). + * struct_nand_device->memorg and struct_nand_device->eccreq should be filled + * at device detection time to reflect the NAND device + * capabilities/requirements. Once this is done nanddev_init() can be called. + * It will take care of converting NAND information into MTD ones, which means + * the specialized NAND layers should never manually tweak + * struct_nand_device->mtd except for the ->_read/write() hooks. + */ +struct nand_device { + struct mtd_info mtd; + struct nand_memory_organization memorg; + struct nand_ecc_req eccreq; + struct nand_row_converter rowconv; + struct nand_bbt bbt; + const struct nand_ops *ops; +}; + +/** + * struct nand_io_iter - NAND I/O iterator + * @req: current I/O request + * @oobbytes_per_page: maximum number of OOB bytes per page + * @dataleft: remaining number of data bytes to read/write + * @oobleft: remaining number of OOB bytes to read/write + * + * Can be used by specialized NAND layers to iterate over all pages covered + * by an MTD I/O request, which should greatly simplifies the boiler-plate + * code needed to read/write data from/to a NAND device. + */ +struct nand_io_iter { + struct nand_page_io_req req; + unsigned int oobbytes_per_page; + unsigned int dataleft; + unsigned int oobleft; +}; + +/** + * mtd_to_nanddev() - Get the NAND device attached to the MTD instance + * @mtd: MTD instance + * + * Return: the NAND device embedding @mtd. + */ +static inline struct nand_device *mtd_to_nanddev(struct mtd_info *mtd) +{ + return container_of(mtd, struct nand_device, mtd); +} + +/** + * nanddev_to_mtd() - Get the MTD device attached to a NAND device + * @nand: NAND device + * + * Return: the MTD device embedded in @nand. + */ +static inline struct mtd_info *nanddev_to_mtd(struct nand_device *nand) +{ + return &nand->mtd; +} + +/* + * nanddev_bits_per_cell() - Get the number of bits per cell + * @nand: NAND device + * + * Return: the number of bits per cell. + */ +static inline unsigned int nanddev_bits_per_cell(const struct nand_device *nand) +{ + return nand->memorg.bits_per_cell; +} + +/** + * nanddev_page_size() - Get NAND page size + * @nand: NAND device + * + * Return: the page size. + */ +static inline size_t nanddev_page_size(const struct nand_device *nand) +{ + return nand->memorg.pagesize; +} + +/** + * nanddev_per_page_oobsize() - Get NAND OOB size + * @nand: NAND device + * + * Return: the OOB size. + */ +static inline unsigned int +nanddev_per_page_oobsize(const struct nand_device *nand) +{ + return nand->memorg.oobsize; +} + +/** + * nanddev_pages_per_eraseblock() - Get the number of pages per eraseblock + * @nand: NAND device + * + * Return: the number of pages per eraseblock. + */ +static inline unsigned int +nanddev_pages_per_eraseblock(const struct nand_device *nand) +{ + return nand->memorg.pages_per_eraseblock; +} + +/** + * nanddev_per_page_oobsize() - Get NAND erase block size + * @nand: NAND device + * + * Return: the eraseblock size. + */ +static inline size_t nanddev_eraseblock_size(const struct nand_device *nand) +{ + return nand->memorg.pagesize * nand->memorg.pages_per_eraseblock; +} + +/** + * nanddev_eraseblocks_per_lun() - Get the number of eraseblocks per LUN + * @nand: NAND device + * + * Return: the number of eraseblocks per LUN. + */ +static inline unsigned int +nanddev_eraseblocks_per_lun(const struct nand_device *nand) +{ + return nand->memorg.eraseblocks_per_lun; +} + +/** + * nanddev_target_size() - Get the total size provided by a single target/die + * @nand: NAND device + * + * Return: the total size exposed by a single target/die in bytes. + */ +static inline u64 nanddev_target_size(const struct nand_device *nand) +{ + return (u64)nand->memorg.luns_per_target * + nand->memorg.eraseblocks_per_lun * + nand->memorg.pages_per_eraseblock * + nand->memorg.pagesize; +} + +/** + * nanddev_ntarget() - Get the total of targets + * @nand: NAND device + * + * Return: the number of targets/dies exposed by @nand. + */ +static inline unsigned int nanddev_ntargets(const struct nand_device *nand) +{ + return nand->memorg.ntargets; +} + +/** + * nanddev_neraseblocks() - Get the total number of erasablocks + * @nand: NAND device + * + * Return: the total number of eraseblocks exposed by @nand. + */ +static inline unsigned int nanddev_neraseblocks(const struct nand_device *nand) +{ + return (u64)nand->memorg.luns_per_target * + nand->memorg.eraseblocks_per_lun * + nand->memorg.pages_per_eraseblock; +} + +/** + * nanddev_size() - Get NAND size + * @nand: NAND device + * + * Return: the total size (in bytes) exposed by @nand. + */ +static inline u64 nanddev_size(const struct nand_device *nand) +{ + return nanddev_target_size(nand) * nanddev_ntargets(nand); +} + +/** + * nanddev_get_memorg() - Extract memory organization info from a NAND device + * @nand: NAND device + * + * This can be used by the upper layer to fill the memorg info before calling + * nanddev_init(). + * + * Return: the memorg object embedded in the NAND device. + */ +static inline struct nand_memory_organization * +nanddev_get_memorg(struct nand_device *nand) +{ + return &nand->memorg; +} + +int nanddev_init(struct nand_device *nand, const struct nand_ops *ops, + struct module *owner); +void nanddev_cleanup(struct nand_device *nand); + +/** + * nanddev_register() - Register a NAND device + * @nand: NAND device + * + * Register a NAND device. + * This function is just a wrapper around mtd_device_register() + * registering the MTD device embedded in @nand. + * + * Return: 0 in case of success, a negative error code otherwise. + */ +static inline int nanddev_register(struct nand_device *nand) +{ + return mtd_device_register(&nand->mtd, NULL, 0); +} + +/** + * nanddev_unregister() - Unregister a NAND device + * @nand: NAND device + * + * Unregister a NAND device. + * This function is just a wrapper around mtd_device_unregister() + * unregistering the MTD device embedded in @nand. + * + * Return: 0 in case of success, a negative error code otherwise. + */ +static inline int nanddev_unregister(struct nand_device *nand) +{ + return mtd_device_unregister(&nand->mtd); +} + +/** + * nanddev_set_of_node() - Attach a DT node to a NAND device + * @nand: NAND device + * @np: DT node + * + * Attach a DT node to a NAND device. + */ +static inline void nanddev_set_of_node(struct nand_device *nand, + struct device_node *np) +{ + mtd_set_of_node(&nand->mtd, np); +} + +/** + * nanddev_get_of_node() - Retrieve the DT node attached to a NAND device + * @nand: NAND device + * + * Return: the DT node attached to @nand. + */ +static inline struct device_node *nanddev_get_of_node(struct nand_device *nand) +{ + return mtd_get_of_node(&nand->mtd); +} + +/** + * nanddev_offs_to_pos() - Convert an absolute NAND offset into a NAND position + * @nand: NAND device + * @offs: absolute NAND offset (usually passed by the MTD layer) + * @pos: a NAND position object to fill in + * + * Converts @offs into a nand_pos representation. + * + * Return: the offset within the NAND page pointed by @pos. + */ +static inline unsigned int nanddev_offs_to_pos(struct nand_device *nand, + loff_t offs, + struct nand_pos *pos) +{ + unsigned int pageoffs; + u64 tmp = offs; + + pageoffs = do_div(tmp, nand->memorg.pagesize); + pos->page = do_div(tmp, nand->memorg.pages_per_eraseblock); + pos->eraseblock = do_div(tmp, nand->memorg.eraseblocks_per_lun); + pos->plane = pos->eraseblock % nand->memorg.planes_per_lun; + pos->lun = do_div(tmp, nand->memorg.luns_per_target); + pos->target = tmp; + + return pageoffs; +} + +/** + * nanddev_pos_cmp() - Compare two NAND positions + * @a: First NAND position + * @b: Second NAND position + * + * Compares two NAND positions. + * + * Return: -1 if @a < @b, 0 if @a == @b and 1 if @a > @b. + */ +static inline int nanddev_pos_cmp(const struct nand_pos *a, + const struct nand_pos *b) +{ + if (a->target != b->target) + return a->target < b->target ? -1 : 1; + + if (a->lun != b->lun) + return a->lun < b->lun ? -1 : 1; + + if (a->eraseblock != b->eraseblock) + return a->eraseblock < b->eraseblock ? -1 : 1; + + if (a->page != b->page) + return a->page < b->page ? -1 : 1; + + return 0; +} + +/** + * nanddev_pos_to_offs() - Convert a NAND position into an absolute offset + * @nand: NAND device + * @pos: the NAND position to convert + * + * Converts @pos NAND position into an absolute offset. + * + * Return: the absolute offset. Note that @pos points to the beginning of a + * page, if one wants to point to a specific offset within this page + * the returned offset has to be adjusted manually. + */ +static inline loff_t nanddev_pos_to_offs(struct nand_device *nand, + const struct nand_pos *pos) +{ + unsigned int npages; + + npages = pos->page + + ((pos->eraseblock + + (pos->lun + + (pos->target * nand->memorg.luns_per_target)) * + nand->memorg.eraseblocks_per_lun) * + nand->memorg.pages_per_eraseblock); + + return (loff_t)npages * nand->memorg.pagesize; +} + +/** + * nanddev_pos_to_row() - Extract a row address from a NAND position + * @nand: NAND device + * @pos: the position to convert + * + * Converts a NAND position into a row address that can then be passed to the + * device. + * + * Return: the row address extracted from @pos. + */ +static inline unsigned int nanddev_pos_to_row(struct nand_device *nand, + const struct nand_pos *pos) +{ + return (pos->lun << nand->rowconv.lun_addr_shift) | + (pos->eraseblock << nand->rowconv.eraseblock_addr_shift) | + pos->page; +} + +/** + * nanddev_pos_next_target() - Move a position to the next target/die + * @nand: NAND device + * @pos: the position to update + * + * Updates @pos to point to the start of the next target/die. Useful when you + * want to iterate over all targets/dies of a NAND device. + */ +static inline void nanddev_pos_next_target(struct nand_device *nand, + struct nand_pos *pos) +{ + pos->page = 0; + pos->plane = 0; + pos->eraseblock = 0; + pos->lun = 0; + pos->target++; +} + +/** + * nanddev_pos_next_lun() - Move a position to the next LUN + * @nand: NAND device + * @pos: the position to update + * + * Updates @pos to point to the start of the next LUN. Useful when you want to + * iterate over all LUNs of a NAND device. + */ +static inline void nanddev_pos_next_lun(struct nand_device *nand, + struct nand_pos *pos) +{ + if (pos->lun >= nand->memorg.luns_per_target - 1) + return nanddev_pos_next_target(nand, pos); + + pos->lun++; + pos->page = 0; + pos->plane = 0; + pos->eraseblock = 0; +} + +/** + * nanddev_pos_next_eraseblock() - Move a position to the next eraseblock + * @nand: NAND device + * @pos: the position to update + * + * Updates @pos to point to the start of the next eraseblock. Useful when you + * want to iterate over all eraseblocks of a NAND device. + */ +static inline void nanddev_pos_next_eraseblock(struct nand_device *nand, + struct nand_pos *pos) +{ + if (pos->eraseblock >= nand->memorg.eraseblocks_per_lun - 1) + return nanddev_pos_next_lun(nand, pos); + + pos->eraseblock++; + pos->page = 0; + pos->plane = pos->eraseblock % nand->memorg.planes_per_lun; +} + +/** + * nanddev_pos_next_eraseblock() - Move a position to the next page + * @nand: NAND device + * @pos: the position to update + * + * Updates @pos to point to the start of the next page. Useful when you want to + * iterate over all pages of a NAND device. + */ +static inline void nanddev_pos_next_page(struct nand_device *nand, + struct nand_pos *pos) +{ + if (pos->page >= nand->memorg.pages_per_eraseblock - 1) + return nanddev_pos_next_eraseblock(nand, pos); + + pos->page++; +} + +/** + * nand_io_iter_init - Initialize a NAND I/O iterator + * @nand: NAND device + * @offs: absolute offset + * @req: MTD request + * @iter: NAND I/O iterator + * + * Initializes a NAND iterator based on the information passed by the MTD + * layer. + */ +static inline void nanddev_io_iter_init(struct nand_device *nand, + loff_t offs, struct mtd_oob_ops *req, + struct nand_io_iter *iter) +{ + struct mtd_info *mtd = nanddev_to_mtd(nand); + + iter->req.dataoffs = nanddev_offs_to_pos(nand, offs, &iter->req.pos); + iter->req.ooboffs = req->ooboffs; + iter->oobbytes_per_page = mtd_oobavail(mtd, req); + iter->dataleft = req->len; + iter->oobleft = req->ooblen; + iter->req.databuf.in = req->datbuf; + iter->req.datalen = min_t(unsigned int, + nand->memorg.pagesize - iter->req.dataoffs, + iter->dataleft); + iter->req.oobbuf.in = req->oobbuf; + iter->req.ooblen = min_t(unsigned int, + iter->oobbytes_per_page - iter->req.ooboffs, + iter->oobleft); +} + +/** + * nand_io_iter_next_page - Move to the next page + * @nand: NAND device + * @iter: NAND I/O iterator + * + * Updates the @iter to point to the next page. + */ +static inline void nanddev_io_iter_next_page(struct nand_device *nand, + struct nand_io_iter *iter) +{ + nanddev_pos_next_page(nand, &iter->req.pos); + iter->dataleft -= iter->req.datalen; + iter->req.databuf.in += iter->req.datalen; + iter->oobleft -= iter->req.ooblen; + iter->req.oobbuf.in += iter->req.ooblen; + iter->req.dataoffs = 0; + iter->req.ooboffs = 0; + iter->req.datalen = min_t(unsigned int, nand->memorg.pagesize, + iter->dataleft); + iter->req.ooblen = min_t(unsigned int, iter->oobbytes_per_page, + iter->oobleft); +} + +/** + * nand_io_iter_end - Should end iteration or not + * @nand: NAND device + * @iter: NAND I/O iterator + * + * Check whether @iter has reached the end of the NAND portion it was asked to + * iterate on or not. + * + * Return: true if @iter has reached the end of the iteration request, false + * otherwise. + */ +static inline bool nanddev_io_iter_end(struct nand_device *nand, + const struct nand_io_iter *iter) +{ + if (iter->dataleft || iter->oobleft) + return false; + + return true; +} + +/** + * nand_io_for_each_page - Iterate over all NAND pages contained in an MTD I/O + * request + * @nand: NAND device + * @start: start address to read/write from + * @req: MTD I/O request + * @iter: NAND I/O iterator + * + * Should be used for iterate over pages that are contained in an MTD request. + */ +#define nanddev_io_for_each_page(nand, start, req, iter) \ + for (nanddev_io_iter_init(nand, start, req, iter); \ + !nanddev_io_iter_end(nand, iter); \ + nanddev_io_iter_next_page(nand, iter)) + +bool nanddev_isbad(struct nand_device *nand, const struct nand_pos *pos); +bool nanddev_isreserved(struct nand_device *nand, const struct nand_pos *pos); +int nanddev_erase(struct nand_device *nand, const struct nand_pos *pos); +int nanddev_markbad(struct nand_device *nand, const struct nand_pos *pos); + +/* BBT related functions */ +enum nand_bbt_block_status { + NAND_BBT_BLOCK_STATUS_UNKNOWN, + NAND_BBT_BLOCK_GOOD, + NAND_BBT_BLOCK_WORN, + NAND_BBT_BLOCK_RESERVED, + NAND_BBT_BLOCK_FACTORY_BAD, + NAND_BBT_BLOCK_NUM_STATUS, +}; + +int nanddev_bbt_init(struct nand_device *nand); +void nanddev_bbt_cleanup(struct nand_device *nand); +int nanddev_bbt_update(struct nand_device *nand); +int nanddev_bbt_get_block_status(const struct nand_device *nand, + unsigned int entry); +int nanddev_bbt_set_block_status(struct nand_device *nand, unsigned int entry, + enum nand_bbt_block_status status); +int nanddev_bbt_markbad(struct nand_device *nand, unsigned int block); + +/** + * nanddev_bbt_pos_to_entry() - Convert a NAND position into a BBT entry + * @nand: NAND device + * @pos: the NAND position we want to get BBT entry for + * + * Return the BBT entry used to store information about the eraseblock pointed + * by @pos. + * + * Return: the BBT entry storing information about eraseblock pointed by @pos. + */ +static inline unsigned int nanddev_bbt_pos_to_entry(struct nand_device *nand, + const struct nand_pos *pos) +{ + return pos->eraseblock + + ((pos->lun + (pos->target * nand->memorg.luns_per_target)) * + nand->memorg.eraseblocks_per_lun); +} + +/** + * nanddev_bbt_is_initialized() - Check if the BBT has been initialized + * @nand: NAND device + * + * Return: true if the BBT has been initialized, false otherwise. + */ +static inline bool nanddev_bbt_is_initialized(struct nand_device *nand) +{ + return !!nand->bbt.cache; +} + +/* MTD -> NAND helper functions. */ +int nanddev_mtd_erase(struct mtd_info *mtd, struct erase_info *einfo); + +#endif /* __LINUX_MTD_NAND_H */ From 4df6ed4f0ac9a1bb776eabb5a669321b68296ff2 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Fri, 16 Feb 2018 15:22:47 +0100 Subject: [PATCH 25/89] mtd: nand: fsmc: get rid of IO_ADDR_[R|W] Remove the use of IO_ADDR_[R|W] in the fsmc_nand driver. Instead, use a pointer to the control registers to avoid doing several arithmetic operations (including a multiplication) each time a control register is read or written. All references to IO_ADDR_[R|W] are not entirely removed from the driver as, at this time, these values are needed by the NAND core in the default ->read/write_byte/word() hooks. These references will be entirely removed when switching to ->exec_op(), that does not make use of these hooks anymore. Signed-off-by: Miquel Raynal Signed-off-by: Boris Brezillon --- drivers/mtd/nand/raw/fsmc_nand.c | 96 +++++++++++++------------------- 1 file changed, 40 insertions(+), 56 deletions(-) diff --git a/drivers/mtd/nand/raw/fsmc_nand.c b/drivers/mtd/nand/raw/fsmc_nand.c index 7e66268f8154..75a825dc5a4c 100644 --- a/drivers/mtd/nand/raw/fsmc_nand.c +++ b/drivers/mtd/nand/raw/fsmc_nand.c @@ -103,10 +103,6 @@ #define ECC3 0x1C #define FSMC_NAND_BANK_SZ 0x20 -#define FSMC_NAND_REG(base, bank, reg) (base + FSMC_NOR_REG_SIZE + \ - (FSMC_NAND_BANK_SZ * (bank)) + \ - reg) - #define FSMC_BUSY_WAIT_TIMEOUT (1 * HZ) struct fsmc_nand_timings { @@ -143,7 +139,7 @@ enum access_mode { * @data_va: NAND port for Data. * @cmd_va: NAND port for Command. * @addr_va: NAND port for Address. - * @regs_va: FSMC regs base address. + * @regs_va: Registers base address for a given bank. */ struct fsmc_nand_data { u32 pid; @@ -265,8 +261,6 @@ static void fsmc_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) { struct nand_chip *this = mtd_to_nand(mtd); struct fsmc_nand_data *host = mtd_to_fsmc(mtd); - void __iomem *regs = host->regs_va; - unsigned int bank = host->bank; if (ctrl & NAND_CTRL_CHANGE) { u32 pc; @@ -282,12 +276,12 @@ static void fsmc_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) this->IO_ADDR_W = host->data_va; } - pc = readl(FSMC_NAND_REG(regs, bank, PC)); + pc = readl(host->regs_va + PC); if (ctrl & NAND_NCE) pc |= FSMC_ENABLE; else pc &= ~FSMC_ENABLE; - writel_relaxed(pc, FSMC_NAND_REG(regs, bank, PC)); + writel_relaxed(pc, host->regs_va + PC); } mb(); @@ -307,8 +301,6 @@ static void fsmc_nand_setup(struct fsmc_nand_data *host, { uint32_t value = FSMC_DEVTYPE_NAND | FSMC_ENABLE | FSMC_WAITON; uint32_t tclr, tar, thiz, thold, twait, tset; - unsigned int bank = host->bank; - void __iomem *regs = host->regs_va; tclr = (tims->tclr & FSMC_TCLR_MASK) << FSMC_TCLR_SHIFT; tar = (tims->tar & FSMC_TAR_MASK) << FSMC_TAR_SHIFT; @@ -318,18 +310,14 @@ static void fsmc_nand_setup(struct fsmc_nand_data *host, tset = (tims->tset & FSMC_TSET_MASK) << FSMC_TSET_SHIFT; if (host->nand.options & NAND_BUSWIDTH_16) - writel_relaxed(value | FSMC_DEVWID_16, - FSMC_NAND_REG(regs, bank, PC)); + writel_relaxed(value | FSMC_DEVWID_16, host->regs_va + PC); else - writel_relaxed(value | FSMC_DEVWID_8, - FSMC_NAND_REG(regs, bank, PC)); + writel_relaxed(value | FSMC_DEVWID_8, host->regs_va + PC); - writel_relaxed(readl(FSMC_NAND_REG(regs, bank, PC)) | tclr | tar, - FSMC_NAND_REG(regs, bank, PC)); - writel_relaxed(thiz | thold | twait | tset, - FSMC_NAND_REG(regs, bank, COMM)); - writel_relaxed(thiz | thold | twait | tset, - FSMC_NAND_REG(regs, bank, ATTRIB)); + writel_relaxed(readl(host->regs_va + PC) | tclr | tar, + host->regs_va + PC); + writel_relaxed(thiz | thold | twait | tset, host->regs_va + COMM); + writel_relaxed(thiz | thold | twait | tset, host->regs_va + ATTRIB); } static int fsmc_calc_timings(struct fsmc_nand_data *host, @@ -419,15 +407,13 @@ static int fsmc_setup_data_interface(struct mtd_info *mtd, int csline, static void fsmc_enable_hwecc(struct mtd_info *mtd, int mode) { struct fsmc_nand_data *host = mtd_to_fsmc(mtd); - void __iomem *regs = host->regs_va; - uint32_t bank = host->bank; - writel_relaxed(readl(FSMC_NAND_REG(regs, bank, PC)) & ~FSMC_ECCPLEN_256, - FSMC_NAND_REG(regs, bank, PC)); - writel_relaxed(readl(FSMC_NAND_REG(regs, bank, PC)) & ~FSMC_ECCEN, - FSMC_NAND_REG(regs, bank, PC)); - writel_relaxed(readl(FSMC_NAND_REG(regs, bank, PC)) | FSMC_ECCEN, - FSMC_NAND_REG(regs, bank, PC)); + writel_relaxed(readl(host->regs_va + PC) & ~FSMC_ECCPLEN_256, + host->regs_va + PC); + writel_relaxed(readl(host->regs_va + PC) & ~FSMC_ECCEN, + host->regs_va + PC); + writel_relaxed(readl(host->regs_va + PC) | FSMC_ECCEN, + host->regs_va + PC); } /* @@ -439,13 +425,11 @@ static int fsmc_read_hwecc_ecc4(struct mtd_info *mtd, const uint8_t *data, uint8_t *ecc) { struct fsmc_nand_data *host = mtd_to_fsmc(mtd); - void __iomem *regs = host->regs_va; - uint32_t bank = host->bank; uint32_t ecc_tmp; unsigned long deadline = jiffies + FSMC_BUSY_WAIT_TIMEOUT; do { - if (readl_relaxed(FSMC_NAND_REG(regs, bank, STS)) & FSMC_CODE_RDY) + if (readl_relaxed(host->regs_va + STS) & FSMC_CODE_RDY) break; else cond_resched(); @@ -456,25 +440,25 @@ static int fsmc_read_hwecc_ecc4(struct mtd_info *mtd, const uint8_t *data, return -ETIMEDOUT; } - ecc_tmp = readl_relaxed(FSMC_NAND_REG(regs, bank, ECC1)); + ecc_tmp = readl_relaxed(host->regs_va + ECC1); ecc[0] = (uint8_t) (ecc_tmp >> 0); ecc[1] = (uint8_t) (ecc_tmp >> 8); ecc[2] = (uint8_t) (ecc_tmp >> 16); ecc[3] = (uint8_t) (ecc_tmp >> 24); - ecc_tmp = readl_relaxed(FSMC_NAND_REG(regs, bank, ECC2)); + ecc_tmp = readl_relaxed(host->regs_va + ECC2); ecc[4] = (uint8_t) (ecc_tmp >> 0); ecc[5] = (uint8_t) (ecc_tmp >> 8); ecc[6] = (uint8_t) (ecc_tmp >> 16); ecc[7] = (uint8_t) (ecc_tmp >> 24); - ecc_tmp = readl_relaxed(FSMC_NAND_REG(regs, bank, ECC3)); + ecc_tmp = readl_relaxed(host->regs_va + ECC3); ecc[8] = (uint8_t) (ecc_tmp >> 0); ecc[9] = (uint8_t) (ecc_tmp >> 8); ecc[10] = (uint8_t) (ecc_tmp >> 16); ecc[11] = (uint8_t) (ecc_tmp >> 24); - ecc_tmp = readl_relaxed(FSMC_NAND_REG(regs, bank, STS)); + ecc_tmp = readl_relaxed(host->regs_va + STS); ecc[12] = (uint8_t) (ecc_tmp >> 16); return 0; @@ -489,11 +473,9 @@ static int fsmc_read_hwecc_ecc1(struct mtd_info *mtd, const uint8_t *data, uint8_t *ecc) { struct fsmc_nand_data *host = mtd_to_fsmc(mtd); - void __iomem *regs = host->regs_va; - uint32_t bank = host->bank; uint32_t ecc_tmp; - ecc_tmp = readl_relaxed(FSMC_NAND_REG(regs, bank, ECC1)); + ecc_tmp = readl_relaxed(host->regs_va + ECC1); ecc[0] = (uint8_t) (ecc_tmp >> 0); ecc[1] = (uint8_t) (ecc_tmp >> 8); ecc[2] = (uint8_t) (ecc_tmp >> 16); @@ -598,18 +580,18 @@ unmap_dma: */ static void fsmc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) { + struct fsmc_nand_data *host = mtd_to_fsmc(mtd); int i; - struct nand_chip *chip = mtd_to_nand(mtd); if (IS_ALIGNED((uint32_t)buf, sizeof(uint32_t)) && IS_ALIGNED(len, sizeof(uint32_t))) { uint32_t *p = (uint32_t *)buf; len = len >> 2; for (i = 0; i < len; i++) - writel_relaxed(p[i], chip->IO_ADDR_W); + writel_relaxed(p[i], host->data_va); } else { for (i = 0; i < len; i++) - writeb_relaxed(buf[i], chip->IO_ADDR_W); + writeb_relaxed(buf[i], host->data_va); } } @@ -621,18 +603,18 @@ static void fsmc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) */ static void fsmc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) { + struct fsmc_nand_data *host = mtd_to_fsmc(mtd); int i; - struct nand_chip *chip = mtd_to_nand(mtd); if (IS_ALIGNED((uint32_t)buf, sizeof(uint32_t)) && IS_ALIGNED(len, sizeof(uint32_t))) { uint32_t *p = (uint32_t *)buf; len = len >> 2; for (i = 0; i < len; i++) - p[i] = readl_relaxed(chip->IO_ADDR_R); + p[i] = readl_relaxed(host->data_va); } else { for (i = 0; i < len; i++) - buf[i] = readb_relaxed(chip->IO_ADDR_R); + buf[i] = readb_relaxed(host->data_va); } } @@ -754,13 +736,11 @@ static int fsmc_bch8_correct_data(struct mtd_info *mtd, uint8_t *dat, { struct nand_chip *chip = mtd_to_nand(mtd); struct fsmc_nand_data *host = mtd_to_fsmc(mtd); - void __iomem *regs = host->regs_va; - unsigned int bank = host->bank; uint32_t err_idx[8]; uint32_t num_err, i; uint32_t ecc1, ecc2, ecc3, ecc4; - num_err = (readl_relaxed(FSMC_NAND_REG(regs, bank, STS)) >> 10) & 0xF; + num_err = (readl_relaxed(host->regs_va + STS) >> 10) & 0xF; /* no bit flipping */ if (likely(num_err == 0)) @@ -803,10 +783,10 @@ static int fsmc_bch8_correct_data(struct mtd_info *mtd, uint8_t *dat, * uint64_t array and error offset indexes are populated in err_idx * array */ - ecc1 = readl_relaxed(FSMC_NAND_REG(regs, bank, ECC1)); - ecc2 = readl_relaxed(FSMC_NAND_REG(regs, bank, ECC2)); - ecc3 = readl_relaxed(FSMC_NAND_REG(regs, bank, ECC3)); - ecc4 = readl_relaxed(FSMC_NAND_REG(regs, bank, STS)); + ecc1 = readl_relaxed(host->regs_va + ECC1); + ecc2 = readl_relaxed(host->regs_va + ECC2); + ecc3 = readl_relaxed(host->regs_va + ECC3); + ecc4 = readl_relaxed(host->regs_va + STS); err_idx[0] = (ecc1 >> 0) & 0x1FFF; err_idx[1] = (ecc1 >> 13) & 0x1FFF; @@ -889,6 +869,7 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) struct mtd_info *mtd; struct nand_chip *nand; struct resource *res; + void __iomem *base; dma_cap_mask_t mask; int ret = 0; u32 pid; @@ -923,9 +904,12 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) return PTR_ERR(host->cmd_va); res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fsmc_regs"); - host->regs_va = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(host->regs_va)) - return PTR_ERR(host->regs_va); + base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); + + host->regs_va = base + FSMC_NOR_REG_SIZE + + (host->bank * FSMC_NAND_BANK_SZ); host->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(host->clk)) { @@ -942,7 +926,7 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) * AMBA PrimeCell bus. However it is not a PrimeCell. */ for (pid = 0, i = 0; i < 4; i++) - pid |= (readl(host->regs_va + resource_size(res) - 0x20 + 4 * i) & 255) << (i * 8); + pid |= (readl(base + resource_size(res) - 0x20 + 4 * i) & 255) << (i * 8); host->pid = pid; dev_info(&pdev->dev, "FSMC device partno %03x, manufacturer %02x, " "revision %02x, config %02x\n", From 4da712e702941daa849ccd7fbcaa677dce7855b2 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Fri, 16 Feb 2018 15:22:48 +0100 Subject: [PATCH 26/89] mtd: nand: fsmc: use ->exec_op() Remove the deprecated ->cmd_ctrl() implementation to use ->exec_op() in the fsmc_nand driver. Implement the ->select_chip() hook to avoid having to support the hack from the core that send a NAND_CMD_NONE with NAND_NCE to signal a deassertion of nCE. Also get rid of the last references to ->IO_ADDR_[R|W] that are not used anymore. Signed-off-by: Miquel Raynal Signed-off-by: Boris Brezillon --- drivers/mtd/nand/raw/fsmc_nand.c | 150 ++++++++++++++++++++----------- 1 file changed, 99 insertions(+), 51 deletions(-) diff --git a/drivers/mtd/nand/raw/fsmc_nand.c b/drivers/mtd/nand/raw/fsmc_nand.c index 75a825dc5a4c..28c48dcc514e 100644 --- a/drivers/mtd/nand/raw/fsmc_nand.c +++ b/drivers/mtd/nand/raw/fsmc_nand.c @@ -253,43 +253,6 @@ static inline struct fsmc_nand_data *mtd_to_fsmc(struct mtd_info *mtd) return container_of(mtd_to_nand(mtd), struct fsmc_nand_data, nand); } -/* - * fsmc_cmd_ctrl - For facilitaing Hardware access - * This routine allows hardware specific access to control-lines(ALE,CLE) - */ -static void fsmc_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) -{ - struct nand_chip *this = mtd_to_nand(mtd); - struct fsmc_nand_data *host = mtd_to_fsmc(mtd); - - if (ctrl & NAND_CTRL_CHANGE) { - u32 pc; - - if (ctrl & NAND_CLE) { - this->IO_ADDR_R = host->cmd_va; - this->IO_ADDR_W = host->cmd_va; - } else if (ctrl & NAND_ALE) { - this->IO_ADDR_R = host->addr_va; - this->IO_ADDR_W = host->addr_va; - } else { - this->IO_ADDR_R = host->data_va; - this->IO_ADDR_W = host->data_va; - } - - pc = readl(host->regs_va + PC); - if (ctrl & NAND_NCE) - pc |= FSMC_ENABLE; - else - pc &= ~FSMC_ENABLE; - writel_relaxed(pc, host->regs_va + PC); - } - - mb(); - - if (cmd != NAND_CMD_NONE) - writeb_relaxed(cmd, this->IO_ADDR_W); -} - /* * fsmc_nand_setup - FSMC (Flexible Static Memory Controller) init routine * @@ -645,6 +608,102 @@ static void fsmc_write_buf_dma(struct mtd_info *mtd, const uint8_t *buf, dma_xfer(host, (void *)buf, len, DMA_TO_DEVICE); } +/* fsmc_select_chip - assert or deassert nCE */ +static void fsmc_select_chip(struct mtd_info *mtd, int chipnr) +{ + struct fsmc_nand_data *host = mtd_to_fsmc(mtd); + u32 pc; + + /* Support only one CS */ + if (chipnr > 0) + return; + + pc = readl(host->regs_va + PC); + if (chipnr < 0) + writel_relaxed(pc & ~FSMC_ENABLE, host->regs_va + PC); + else + writel_relaxed(pc | FSMC_ENABLE, host->regs_va + PC); + + /* nCE line must be asserted before starting any operation */ + mb(); +} + +/* + * fsmc_exec_op - hook called by the core to execute NAND operations + * + * This controller is simple enough and thus does not need to use the parser + * provided by the core, instead, handle every situation here. + */ +static int fsmc_exec_op(struct nand_chip *chip, const struct nand_operation *op, + bool check_only) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + struct fsmc_nand_data *host = mtd_to_fsmc(mtd); + const struct nand_op_instr *instr = NULL; + int ret = 0; + unsigned int op_id; + int i; + + pr_debug("Executing operation [%d instructions]:\n", op->ninstrs); + for (op_id = 0; op_id < op->ninstrs; op_id++) { + instr = &op->instrs[op_id]; + + switch (instr->type) { + case NAND_OP_CMD_INSTR: + pr_debug(" ->CMD [0x%02x]\n", + instr->ctx.cmd.opcode); + + writeb_relaxed(instr->ctx.cmd.opcode, host->cmd_va); + break; + + case NAND_OP_ADDR_INSTR: + pr_debug(" ->ADDR [%d cyc]", + instr->ctx.addr.naddrs); + + for (i = 0; i < instr->ctx.addr.naddrs; i++) + writeb_relaxed(instr->ctx.addr.addrs[i], + host->addr_va); + break; + + case NAND_OP_DATA_IN_INSTR: + pr_debug(" ->DATA_IN [%d B%s]\n", instr->ctx.data.len, + instr->ctx.data.force_8bit ? + ", force 8-bit" : ""); + + if (host->mode == USE_DMA_ACCESS) + fsmc_read_buf_dma(mtd, instr->ctx.data.buf.in, + instr->ctx.data.len); + else + fsmc_read_buf(mtd, instr->ctx.data.buf.in, + instr->ctx.data.len); + break; + + case NAND_OP_DATA_OUT_INSTR: + pr_debug(" ->DATA_OUT [%d B%s]\n", instr->ctx.data.len, + instr->ctx.data.force_8bit ? + ", force 8-bit" : ""); + + if (host->mode == USE_DMA_ACCESS) + fsmc_write_buf_dma(mtd, instr->ctx.data.buf.out, + instr->ctx.data.len); + else + fsmc_write_buf(mtd, instr->ctx.data.buf.out, + instr->ctx.data.len); + break; + + case NAND_OP_WAITRDY_INSTR: + pr_debug(" ->WAITRDY [max %d ms]\n", + instr->ctx.waitrdy.timeout_ms); + + ret = nand_soft_waitrdy(chip, + instr->ctx.waitrdy.timeout_ms); + break; + } + } + + return ret; +} + /* * fsmc_read_page_hwecc * @mtd: mtd info structure @@ -944,9 +1003,8 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) nand_set_flash_node(nand, pdev->dev.of_node); mtd->dev.parent = &pdev->dev; - nand->IO_ADDR_R = host->data_va; - nand->IO_ADDR_W = host->data_va; - nand->cmd_ctrl = fsmc_cmd_ctrl; + nand->exec_op = fsmc_exec_op; + nand->select_chip = fsmc_select_chip; nand->chip_delay = 30; /* @@ -958,8 +1016,7 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) nand->ecc.size = 512; nand->badblockbits = 7; - switch (host->mode) { - case USE_DMA_ACCESS: + if (host->mode == USE_DMA_ACCESS) { dma_cap_zero(mask); dma_cap_set(DMA_MEMCPY, mask); host->read_dma_chan = dma_request_channel(mask, filter, NULL); @@ -972,15 +1029,6 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) dev_err(&pdev->dev, "Unable to get write dma channel\n"); goto err_req_write_chnl; } - nand->read_buf = fsmc_read_buf_dma; - nand->write_buf = fsmc_write_buf_dma; - break; - - default: - case USE_WORD_ACCESS: - nand->read_buf = fsmc_read_buf; - nand->write_buf = fsmc_write_buf; - break; } if (host->dev_timings) From 645be665a5932829239eea151c042dd5a6481e62 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Mon, 19 Feb 2018 23:57:59 +0100 Subject: [PATCH 27/89] MAINTAINERS: Update email address for Miquel Raynal Free Electrons is now Bootlin. Signed-off-by: Miquel Raynal Signed-off-by: Boris Brezillon --- .mailmap | 1 + MAINTAINERS | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.mailmap b/.mailmap index e18cab73e209..6cc2d5a94cc2 100644 --- a/.mailmap +++ b/.mailmap @@ -126,6 +126,7 @@ Mayuresh Janorkar Michael Buesch Michel Dänzer Miodrag Dinic +Miquel Raynal Mitesh shah Mohit Kumar Morten Welinder diff --git a/MAINTAINERS b/MAINTAINERS index 34b2e9ed6d3d..ab9c367f03c7 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8471,7 +8471,7 @@ S: Odd Fixes F: drivers/net/wireless/marvell/mwl8k.c MARVELL NAND CONTROLLER DRIVER -M: Miquel Raynal +M: Miquel Raynal L: linux-mtd@lists.infradead.org S: Maintained F: drivers/mtd/nand/raw/marvell_nand.c From d8757f4c59c9fafe5a1ce75a237164f268904b18 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Fri, 16 Feb 2018 11:44:49 +0100 Subject: [PATCH 28/89] Update Boris Brezillon email address Free Electrons is now Bootlin. Signed-off-by: Boris Brezillon --- .mailmap | 6 +++--- MAINTAINERS | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.mailmap b/.mailmap index 6cc2d5a94cc2..85b28e8eb8ee 100644 --- a/.mailmap +++ b/.mailmap @@ -33,9 +33,9 @@ Axel Lin Ben Gardner Ben M Cahill Björn Steinbrink -Boris Brezillon -Boris Brezillon -Boris Brezillon +Boris Brezillon +Boris Brezillon +Boris Brezillon Brian Avery Brian King Christoph Hellwig diff --git a/MAINTAINERS b/MAINTAINERS index ab9c367f03c7..14890e5d3708 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1232,7 +1232,7 @@ F: arch/arm/boot/dts/aspeed-* F: drivers/*/*aspeed* ARM/ATMEL AT91 Clock Support -M: Boris Brezillon +M: Boris Brezillon S: Maintained F: drivers/clk/at91 @@ -4644,7 +4644,7 @@ F: Documentation/gpu/meson.rst T: git git://anongit.freedesktop.org/drm/drm-misc DRM DRIVERS FOR ATMEL HLCDC -M: Boris Brezillon +M: Boris Brezillon L: dri-devel@lists.freedesktop.org S: Supported F: drivers/gpu/drm/atmel-hlcdc/ @@ -8412,7 +8412,7 @@ F: include/uapi/drm/armada_drm.h F: Documentation/devicetree/bindings/display/armada/ MARVELL CRYPTO DRIVER -M: Boris Brezillon +M: Boris Brezillon M: Arnaud Ebalard F: drivers/crypto/marvell/ S: Maintained @@ -9034,7 +9034,7 @@ F: mm/ MEMORY TECHNOLOGY DEVICES (MTD) M: David Woodhouse M: Brian Norris -M: Boris Brezillon +M: Boris Brezillon M: Marek Vasut M: Richard Weinberger M: Cyrille Pitchen @@ -9452,7 +9452,7 @@ S: Supported F: drivers/net/ethernet/myricom/myri10ge/ NAND FLASH SUBSYSTEM -M: Boris Brezillon +M: Boris Brezillon R: Richard Weinberger L: linux-mtd@lists.infradead.org W: http://www.linux-mtd.infradead.org/ From 801492c508f617d5bdc383b98b4a49d7de90c154 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Sun, 18 Feb 2018 17:05:15 +0100 Subject: [PATCH 29/89] mtd: onenand: Get rid of comments giving the file path inside the file itself Some files add a comment giving the path of the file inside the Linux tree, which is pretty useless since the reader had to find the file to open it. Getting rid of these comments will also allow us to easily move these files around when needed. Signed-off-by: Boris Brezillon --- drivers/mtd/onenand/generic.c | 2 -- drivers/mtd/onenand/omap2.c | 2 -- drivers/mtd/onenand/onenand_base.c | 2 -- drivers/mtd/onenand/onenand_bbt.c | 2 -- 4 files changed, 8 deletions(-) diff --git a/drivers/mtd/onenand/generic.c b/drivers/mtd/onenand/generic.c index 125da34d8ff9..d5ccaf943b91 100644 --- a/drivers/mtd/onenand/generic.c +++ b/drivers/mtd/onenand/generic.c @@ -1,6 +1,4 @@ /* - * linux/drivers/mtd/onenand/generic.c - * * Copyright (c) 2005 Samsung Electronics * Kyungmin Park * diff --git a/drivers/mtd/onenand/omap2.c b/drivers/mtd/onenand/omap2.c index 87c34f607a75..9c159f0dd9a6 100644 --- a/drivers/mtd/onenand/omap2.c +++ b/drivers/mtd/onenand/omap2.c @@ -1,6 +1,4 @@ /* - * linux/drivers/mtd/onenand/omap2.c - * * OneNAND driver for OMAP2 / OMAP3 * * Copyright © 2005-2006 Nokia Corporation diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index 979f4031f23c..05907b1b4098 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c @@ -1,6 +1,4 @@ /* - * linux/drivers/mtd/onenand/onenand_base.c - * * Copyright © 2005-2009 Samsung Electronics * Copyright © 2007 Nokia Corporation * diff --git a/drivers/mtd/onenand/onenand_bbt.c b/drivers/mtd/onenand/onenand_bbt.c index 420260c25ca0..dde20487937d 100644 --- a/drivers/mtd/onenand/onenand_bbt.c +++ b/drivers/mtd/onenand/onenand_bbt.c @@ -1,7 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 /* - * linux/drivers/mtd/onenand/onenand_bbt.c - * * Bad Block Table support for the OneNAND driver * * Copyright(c) 2005 Samsung Electronics From 26777d37216c976cf6fd196700133a38aa2c4b0f Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Sun, 18 Feb 2018 17:05:16 +0100 Subject: [PATCH 30/89] mtd: Move onenand code base to drivers/mtd/nand/onenand Move onenand code base to the drivers/mtd/nand directory in the hope that someday someone will patch it to use the generic NAND helpers. If it never happens, at least we'll have all NAND related support in a single directory and not spread over the drivers/mtd/ directory. Signed-off-by: Boris Brezillon --- MAINTAINERS | 2 +- drivers/mtd/Kconfig | 2 -- drivers/mtd/Makefile | 2 +- drivers/mtd/nand/Kconfig | 2 ++ drivers/mtd/nand/Makefile | 1 + drivers/mtd/{ => nand}/onenand/Kconfig | 0 drivers/mtd/{ => nand}/onenand/Makefile | 0 drivers/mtd/{ => nand}/onenand/generic.c | 0 drivers/mtd/{ => nand}/onenand/omap2.c | 0 drivers/mtd/{ => nand}/onenand/onenand_base.c | 0 drivers/mtd/{ => nand}/onenand/onenand_bbt.c | 0 drivers/mtd/{ => nand}/onenand/samsung.c | 0 drivers/mtd/{ => nand}/onenand/samsung.h | 0 13 files changed, 5 insertions(+), 4 deletions(-) rename drivers/mtd/{ => nand}/onenand/Kconfig (100%) rename drivers/mtd/{ => nand}/onenand/Makefile (100%) rename drivers/mtd/{ => nand}/onenand/generic.c (100%) rename drivers/mtd/{ => nand}/onenand/omap2.c (100%) rename drivers/mtd/{ => nand}/onenand/onenand_base.c (100%) rename drivers/mtd/{ => nand}/onenand/onenand_bbt.c (100%) rename drivers/mtd/{ => nand}/onenand/samsung.c (100%) rename drivers/mtd/{ => nand}/onenand/samsung.h (100%) diff --git a/MAINTAINERS b/MAINTAINERS index d5ebb8a1a7c2..d262f177c65b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -10206,7 +10206,7 @@ ONENAND FLASH DRIVER M: Kyungmin Park L: linux-mtd@lists.infradead.org S: Maintained -F: drivers/mtd/onenand/ +F: drivers/mtd/nand/onenand/ F: include/linux/mtd/onenand*.h ONSTREAM SCSI TAPE DRIVER diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig index 2a8ac6829d42..46ab7feec6b6 100644 --- a/drivers/mtd/Kconfig +++ b/drivers/mtd/Kconfig @@ -333,8 +333,6 @@ source "drivers/mtd/devices/Kconfig" source "drivers/mtd/nand/Kconfig" -source "drivers/mtd/onenand/Kconfig" - source "drivers/mtd/lpddr/Kconfig" source "drivers/mtd/spi-nor/Kconfig" diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile index d6f8f625e1ff..93473d215a38 100644 --- a/drivers/mtd/Makefile +++ b/drivers/mtd/Makefile @@ -32,7 +32,7 @@ obj-$(CONFIG_MTD_SWAP) += mtdswap.o nftl-objs := nftlcore.o nftlmount.o inftl-objs := inftlcore.o inftlmount.o -obj-y += chips/ lpddr/ maps/ devices/ nand/ onenand/ tests/ +obj-y += chips/ lpddr/ maps/ devices/ nand/ tests/ obj-$(CONFIG_MTD_SPI_NOR) += spi-nor/ obj-$(CONFIG_MTD_UBI) += ubi/ diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index 1c1a1f487e20..88c7d3b4ff8b 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -1,4 +1,6 @@ config MTD_NAND_CORE tristate +source "drivers/mtd/nand/onenand/Kconfig" + source "drivers/mtd/nand/raw/Kconfig" diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index a72d3cb0f325..3f0cb87f1a57 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -3,4 +3,5 @@ nandcore-objs := core.o bbt.o obj-$(CONFIG_MTD_NAND_CORE) += nandcore.o +obj-y += onenand/ obj-y += raw/ diff --git a/drivers/mtd/onenand/Kconfig b/drivers/mtd/nand/onenand/Kconfig similarity index 100% rename from drivers/mtd/onenand/Kconfig rename to drivers/mtd/nand/onenand/Kconfig diff --git a/drivers/mtd/onenand/Makefile b/drivers/mtd/nand/onenand/Makefile similarity index 100% rename from drivers/mtd/onenand/Makefile rename to drivers/mtd/nand/onenand/Makefile diff --git a/drivers/mtd/onenand/generic.c b/drivers/mtd/nand/onenand/generic.c similarity index 100% rename from drivers/mtd/onenand/generic.c rename to drivers/mtd/nand/onenand/generic.c diff --git a/drivers/mtd/onenand/omap2.c b/drivers/mtd/nand/onenand/omap2.c similarity index 100% rename from drivers/mtd/onenand/omap2.c rename to drivers/mtd/nand/onenand/omap2.c diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/nand/onenand/onenand_base.c similarity index 100% rename from drivers/mtd/onenand/onenand_base.c rename to drivers/mtd/nand/onenand/onenand_base.c diff --git a/drivers/mtd/onenand/onenand_bbt.c b/drivers/mtd/nand/onenand/onenand_bbt.c similarity index 100% rename from drivers/mtd/onenand/onenand_bbt.c rename to drivers/mtd/nand/onenand/onenand_bbt.c diff --git a/drivers/mtd/onenand/samsung.c b/drivers/mtd/nand/onenand/samsung.c similarity index 100% rename from drivers/mtd/onenand/samsung.c rename to drivers/mtd/nand/onenand/samsung.c diff --git a/drivers/mtd/onenand/samsung.h b/drivers/mtd/nand/onenand/samsung.h similarity index 100% rename from drivers/mtd/onenand/samsung.h rename to drivers/mtd/nand/onenand/samsung.h From 63fa37f0c512481bd942e84b596ad58e1d4c84e2 Mon Sep 17 00:00:00 2001 From: Shreeya Patel Date: Thu, 22 Feb 2018 22:01:22 +0530 Subject: [PATCH 31/89] mtd: rawnand: Replace printk() with appropriate pr_*() macro Using pr_() is more concise than printk(KERN_). Replace printks having a log level with the appropriate pr_*() macros. Define pr_fmt() and remove other additional macros from the replaced printks. Signed-off-by: Shreeya Patel Signed-off-by: Boris Brezillon --- drivers/mtd/nand/raw/ams-delta.c | 4 +- drivers/mtd/nand/raw/cafe_nand.c | 4 +- drivers/mtd/nand/raw/cs553x_nand.c | 9 ++-- drivers/mtd/nand/raw/diskonchip.c | 76 +++++++++++++++------------- drivers/mtd/nand/raw/fsl_elbc_nand.c | 4 +- drivers/mtd/nand/raw/fsl_ifc_nand.c | 2 +- drivers/mtd/nand/raw/nand_bch.c | 12 ++--- drivers/mtd/nand/raw/nandsim.c | 15 +++--- drivers/mtd/nand/raw/r852.c | 5 +- drivers/mtd/nand/raw/r852.h | 9 ++-- drivers/mtd/nand/raw/sh_flctl.c | 2 +- drivers/mtd/nand/raw/sm_common.c | 5 +- 12 files changed, 75 insertions(+), 72 deletions(-) diff --git a/drivers/mtd/nand/raw/ams-delta.c b/drivers/mtd/nand/raw/ams-delta.c index 35f80523e52e..37a3cc21c7bc 100644 --- a/drivers/mtd/nand/raw/ams-delta.c +++ b/drivers/mtd/nand/raw/ams-delta.c @@ -186,7 +186,7 @@ static int ams_delta_init(struct platform_device *pdev) /* Allocate memory for MTD device structure and private data */ this = kzalloc(sizeof(struct nand_chip), GFP_KERNEL); if (!this) { - printk (KERN_WARNING "Unable to allocate E3 NAND MTD device structure.\n"); + pr_warn("Unable to allocate E3 NAND MTD device structure.\n"); err = -ENOMEM; goto out; } @@ -220,7 +220,7 @@ static int ams_delta_init(struct platform_device *pdev) this->dev_ready = ams_delta_nand_ready; } else { this->dev_ready = NULL; - printk(KERN_NOTICE "Couldn't request gpio for Delta NAND ready.\n"); + pr_notice("Couldn't request gpio for Delta NAND ready.\n"); } /* 25 us command delay time */ this->chip_delay = 30; diff --git a/drivers/mtd/nand/raw/cafe_nand.c b/drivers/mtd/nand/raw/cafe_nand.c index 567ff972d5fc..37cfae2761d4 100644 --- a/drivers/mtd/nand/raw/cafe_nand.c +++ b/drivers/mtd/nand/raw/cafe_nand.c @@ -751,8 +751,8 @@ static int cafe_nand_probe(struct pci_dev *pdev, cafe->nand.bbt_td = &cafe_bbt_main_descr_512; cafe->nand.bbt_md = &cafe_bbt_mirror_descr_512; } else { - printk(KERN_WARNING "Unexpected NAND flash writesize %d. Aborting\n", - mtd->writesize); + pr_warn("Unexpected NAND flash writesize %d. Aborting\n", + mtd->writesize); goto out_free_dma; } cafe->nand.ecc.mode = NAND_ECC_HW_SYNDROME; diff --git a/drivers/mtd/nand/raw/cs553x_nand.c b/drivers/mtd/nand/raw/cs553x_nand.c index be1f28fc7363..82269fde9e66 100644 --- a/drivers/mtd/nand/raw/cs553x_nand.c +++ b/drivers/mtd/nand/raw/cs553x_nand.c @@ -187,10 +187,11 @@ static int __init cs553x_init_one(int cs, int mmio, unsigned long adr) struct nand_chip *this; struct mtd_info *new_mtd; - printk(KERN_NOTICE "Probing CS553x NAND controller CS#%d at %sIO 0x%08lx\n", cs, mmio?"MM":"P", adr); + pr_notice("Probing CS553x NAND controller CS#%d at %sIO 0x%08lx\n", + cs, mmio ? "MM" : "P", adr); if (!mmio) { - printk(KERN_NOTICE "PIO mode not yet implemented for CS553X NAND controller\n"); + pr_notice("PIO mode not yet implemented for CS553X NAND controller\n"); return -ENXIO; } @@ -209,7 +210,7 @@ static int __init cs553x_init_one(int cs, int mmio, unsigned long adr) /* map physical address */ this->IO_ADDR_R = this->IO_ADDR_W = ioremap(adr, 4096); if (!this->IO_ADDR_R) { - printk(KERN_WARNING "ioremap cs553x NAND @0x%08lx failed\n", adr); + pr_warn("ioremap cs553x NAND @0x%08lx failed\n", adr); err = -EIO; goto out_mtd; } @@ -293,7 +294,7 @@ static int __init cs553x_init(void) /* If it doesn't have the NAND controller enabled, abort */ rdmsrl(MSR_DIVIL_BALL_OPTS, val); if (val & PIN_OPT_IDE) { - printk(KERN_INFO "CS553x NAND controller: Flash I/O not enabled in MSR_DIVIL_BALL_OPTS.\n"); + pr_info("CS553x NAND controller: Flash I/O not enabled in MSR_DIVIL_BALL_OPTS.\n"); return -ENXIO; } diff --git a/drivers/mtd/nand/raw/diskonchip.c b/drivers/mtd/nand/raw/diskonchip.c index 1af77f798fe5..86a258de0b75 100644 --- a/drivers/mtd/nand/raw/diskonchip.c +++ b/drivers/mtd/nand/raw/diskonchip.c @@ -409,7 +409,7 @@ static uint16_t __init doc200x_ident_chip(struct mtd_info *mtd, int nr) ident.dword = readl(docptr + DoC_2k_CDSN_IO); if (((ident.byte[0] << 8) | ident.byte[1]) == ret) { - printk(KERN_INFO "DiskOnChip 2000 responds to DWORD access\n"); + pr_info("DiskOnChip 2000 responds to DWORD access\n"); this->read_buf = &doc2000_readbuf_dword; } } @@ -436,7 +436,7 @@ static void __init doc2000_count_chips(struct mtd_info *mtd) break; } doc->chips_per_floor = i; - printk(KERN_DEBUG "Detected %d chips per floor.\n", i); + pr_debug("Detected %d chips per floor.\n", i); } static int doc200x_wait(struct mtd_info *mtd, struct nand_chip *this) @@ -932,14 +932,15 @@ static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat, ret = doc_ecc_decode(rs_decoder, dat, calc_ecc); if (ret > 0) - printk(KERN_ERR "doc200x_correct_data corrected %d errors\n", ret); + pr_err("doc200x_correct_data corrected %d errors\n", + ret); } if (DoC_is_MillenniumPlus(doc)) WriteDOC(DOC_ECC_DIS, docptr, Mplus_ECCConf); else WriteDOC(DOC_ECC_DIS, docptr, ECCConf); if (no_ecc_failures && mtd_is_eccerr(ret)) { - printk(KERN_ERR "suppressing ECC failure\n"); + pr_err("suppressing ECC failure\n"); ret = 0; } return ret; @@ -1012,11 +1013,11 @@ static int __init find_media_headers(struct mtd_info *mtd, u_char *buf, const ch if (retlen != mtd->writesize) continue; if (ret) { - printk(KERN_WARNING "ECC error scanning DOC at 0x%x\n", offs); + pr_warn("ECC error scanning DOC at 0x%x\n", offs); } if (memcmp(buf, id, 6)) continue; - printk(KERN_INFO "Found DiskOnChip %s Media Header at 0x%x\n", id, offs); + pr_info("Found DiskOnChip %s Media Header at 0x%x\n", id, offs); if (doc->mh0_page == -1) { doc->mh0_page = offs >> this->page_shift; if (!findmirror) @@ -1027,7 +1028,7 @@ static int __init find_media_headers(struct mtd_info *mtd, u_char *buf, const ch return 2; } if (doc->mh0_page == -1) { - printk(KERN_WARNING "DiskOnChip %s Media Header not found.\n", id); + pr_warn("DiskOnChip %s Media Header not found.\n", id); return 0; } /* Only one mediaheader was found. We want buf to contain a @@ -1036,7 +1037,7 @@ static int __init find_media_headers(struct mtd_info *mtd, u_char *buf, const ch ret = mtd_read(mtd, offs, mtd->writesize, &retlen, buf); if (retlen != mtd->writesize) { /* Insanity. Give up. */ - printk(KERN_ERR "Read DiskOnChip Media Header once, but can't reread it???\n"); + pr_err("Read DiskOnChip Media Header once, but can't reread it???\n"); return 0; } return 1; @@ -1066,11 +1067,11 @@ static inline int __init nftl_partscan(struct mtd_info *mtd, struct mtd_partitio le16_to_cpus(&mh->FirstPhysicalEUN); le32_to_cpus(&mh->FormattedSize); - printk(KERN_INFO " DataOrgID = %s\n" - " NumEraseUnits = %d\n" - " FirstPhysicalEUN = %d\n" - " FormattedSize = %d\n" - " UnitSizeFactor = %d\n", + pr_info(" DataOrgID = %s\n" + " NumEraseUnits = %d\n" + " FirstPhysicalEUN = %d\n" + " FormattedSize = %d\n" + " UnitSizeFactor = %d\n", mh->DataOrgID, mh->NumEraseUnits, mh->FirstPhysicalEUN, mh->FormattedSize, mh->UnitSizeFactor); @@ -1090,7 +1091,7 @@ static inline int __init nftl_partscan(struct mtd_info *mtd, struct mtd_partitio maxblocks = min(32768U, (maxblocks << 1) + psize); mh->UnitSizeFactor--; } - printk(KERN_WARNING "UnitSizeFactor=0x00 detected. Correct value is assumed to be 0x%02x.\n", mh->UnitSizeFactor); + pr_warn("UnitSizeFactor=0x00 detected. Correct value is assumed to be 0x%02x.\n", mh->UnitSizeFactor); } /* NOTE: The lines below modify internal variables of the NAND and MTD @@ -1101,13 +1102,13 @@ static inline int __init nftl_partscan(struct mtd_info *mtd, struct mtd_partitio if (mh->UnitSizeFactor != 0xff) { this->bbt_erase_shift += (0xff - mh->UnitSizeFactor); mtd->erasesize <<= (0xff - mh->UnitSizeFactor); - printk(KERN_INFO "Setting virtual erase size to %d\n", mtd->erasesize); + pr_info("Setting virtual erase size to %d\n", mtd->erasesize); blocks = mtd->size >> this->bbt_erase_shift; maxblocks = min(32768U, mtd->erasesize - psize); } if (blocks > maxblocks) { - printk(KERN_ERR "UnitSizeFactor of 0x%02x is inconsistent with device size. Aborting.\n", mh->UnitSizeFactor); + pr_err("UnitSizeFactor of 0x%02x is inconsistent with device size. Aborting.\n", mh->UnitSizeFactor); goto out; } @@ -1178,14 +1179,14 @@ static inline int __init inftl_partscan(struct mtd_info *mtd, struct mtd_partiti le32_to_cpus(&mh->FormatFlags); le32_to_cpus(&mh->PercentUsed); - printk(KERN_INFO " bootRecordID = %s\n" - " NoOfBootImageBlocks = %d\n" - " NoOfBinaryPartitions = %d\n" - " NoOfBDTLPartitions = %d\n" - " BlockMultiplerBits = %d\n" - " FormatFlgs = %d\n" - " OsakVersion = %d.%d.%d.%d\n" - " PercentUsed = %d\n", + pr_info(" bootRecordID = %s\n" + " NoOfBootImageBlocks = %d\n" + " NoOfBinaryPartitions = %d\n" + " NoOfBDTLPartitions = %d\n" + " BlockMultiplerBits = %d\n" + " FormatFlgs = %d\n" + " OsakVersion = %d.%d.%d.%d\n" + " PercentUsed = %d\n", mh->bootRecordID, mh->NoOfBootImageBlocks, mh->NoOfBinaryPartitions, mh->NoOfBDTLPartitions, @@ -1200,13 +1201,13 @@ static inline int __init inftl_partscan(struct mtd_info *mtd, struct mtd_partiti blocks = mtd->size >> vshift; if (blocks > 32768) { - printk(KERN_ERR "BlockMultiplierBits=%d is inconsistent with device size. Aborting.\n", mh->BlockMultiplierBits); + pr_err("BlockMultiplierBits=%d is inconsistent with device size. Aborting.\n", mh->BlockMultiplierBits); goto out; } blocks = doc->chips_per_floor << (this->chip_shift - this->phys_erase_shift); if (inftl_bbt_write && (blocks > mtd->erasesize)) { - printk(KERN_ERR "Writeable BBTs spanning more than one erase block are not yet supported. FIX ME!\n"); + pr_err("Writeable BBTs spanning more than one erase block are not yet supported. FIX ME!\n"); goto out; } @@ -1220,7 +1221,7 @@ static inline int __init inftl_partscan(struct mtd_info *mtd, struct mtd_partiti le32_to_cpus(&ip->spareUnits); le32_to_cpus(&ip->Reserved0); - printk(KERN_INFO " PARTITION[%d] ->\n" + pr_info(" PARTITION[%d] ->\n" " virtualUnits = %d\n" " firstUnit = %d\n" " lastUnit = %d\n" @@ -1306,7 +1307,7 @@ static int __init inftl_scan_bbt(struct mtd_info *mtd) struct mtd_partition parts[5]; if (this->numchips > doc->chips_per_floor) { - printk(KERN_ERR "Multi-floor INFTL devices not yet supported.\n"); + pr_err("Multi-floor INFTL devices not yet supported.\n"); return -EIO; } @@ -1434,7 +1435,8 @@ static int __init doc_probe(unsigned long physadr) return -EBUSY; virtadr = ioremap(physadr, DOC_IOREMAP_LEN); if (!virtadr) { - printk(KERN_ERR "Diskonchip ioremap failed: 0x%x bytes at 0x%lx\n", DOC_IOREMAP_LEN, physadr); + pr_err("Diskonchip ioremap failed: 0x%x bytes at 0x%lx\n", + DOC_IOREMAP_LEN, physadr); ret = -EIO; goto error_ioremap; } @@ -1493,7 +1495,7 @@ static int __init doc_probe(unsigned long physadr) reg = DoC_Mplus_Toggle; break; case DOC_ChipID_DocMilPlus32: - printk(KERN_ERR "DiskOnChip Millennium Plus 32MB is not supported, ignoring.\n"); + pr_err("DiskOnChip Millennium Plus 32MB is not supported, ignoring.\n"); default: ret = -ENODEV; goto notfound; @@ -1509,7 +1511,7 @@ static int __init doc_probe(unsigned long physadr) tmpb = ReadDOC_(virtadr, reg) & DOC_TOGGLE_BIT; tmpc = ReadDOC_(virtadr, reg) & DOC_TOGGLE_BIT; if ((tmp == tmpb) || (tmp != tmpc)) { - printk(KERN_WARNING "Possible DiskOnChip at 0x%lx failed TOGGLE test, dropping.\n", physadr); + pr_warn("Possible DiskOnChip at 0x%lx failed TOGGLE test, dropping.\n", physadr); ret = -ENODEV; goto notfound; } @@ -1543,12 +1545,13 @@ static int __init doc_probe(unsigned long physadr) } newval = ~newval; if (oldval == newval) { - printk(KERN_DEBUG "Found alias of DOC at 0x%lx to 0x%lx\n", doc->physadr, physadr); + pr_debug("Found alias of DOC at 0x%lx to 0x%lx\n", + doc->physadr, physadr); goto notfound; } } - printk(KERN_NOTICE "DiskOnChip found at 0x%lx\n", physadr); + pr_notice("DiskOnChip found at 0x%lx\n", physadr); len = sizeof(struct nand_chip) + sizeof(struct doc_priv) + (2 * sizeof(struct nand_bbt_descr)); @@ -1663,12 +1666,13 @@ static int __init init_nanddoc(void) */ rs_decoder = init_rs(10, 0x409, FCR, 1, NROOTS); if (!rs_decoder) { - printk(KERN_ERR "DiskOnChip: Could not create a RS decoder\n"); + pr_err("DiskOnChip: Could not create a RS decoder\n"); return -ENOMEM; } if (doc_config_location) { - printk(KERN_INFO "Using configured DiskOnChip probe address 0x%lx\n", doc_config_location); + pr_info("Using configured DiskOnChip probe address 0x%lx\n", + doc_config_location); ret = doc_probe(doc_config_location); if (ret < 0) goto outerr; @@ -1680,7 +1684,7 @@ static int __init init_nanddoc(void) /* No banner message any more. Print a message if no DiskOnChip found, so the user knows we at least tried. */ if (!doclist) { - printk(KERN_INFO "No valid DiskOnChip devices found\n"); + pr_info("No valid DiskOnChip devices found\n"); ret = -ENODEV; goto outerr; } diff --git a/drivers/mtd/nand/raw/fsl_elbc_nand.c b/drivers/mtd/nand/raw/fsl_elbc_nand.c index 8b6dcd739ecb..84f7d6a94be7 100644 --- a/drivers/mtd/nand/raw/fsl_elbc_nand.c +++ b/drivers/mtd/nand/raw/fsl_elbc_nand.c @@ -929,8 +929,8 @@ static int fsl_elbc_nand_probe(struct platform_device *pdev) mtd_device_parse_register(mtd, part_probe_types, NULL, NULL, 0); - printk(KERN_INFO "eLBC NAND device at 0x%llx, bank %d\n", - (unsigned long long)res.start, priv->bank); + pr_info("eLBC NAND device at 0x%llx, bank %d\n", + (unsigned long long)res.start, priv->bank); return 0; err: diff --git a/drivers/mtd/nand/raw/fsl_ifc_nand.c b/drivers/mtd/nand/raw/fsl_ifc_nand.c index 4872a7ba6503..4f0bbc8a803d 100644 --- a/drivers/mtd/nand/raw/fsl_ifc_nand.c +++ b/drivers/mtd/nand/raw/fsl_ifc_nand.c @@ -805,7 +805,7 @@ static void fsl_ifc_sram_init(struct fsl_ifc_mtd *priv) msecs_to_jiffies(IFC_TIMEOUT_MSECS)); if (ctrl->nand_stat != IFC_NAND_EVTER_STAT_OPC) - printk(KERN_ERR "fsl-ifc: Failed to Initialise SRAM\n"); + pr_err("fsl-ifc: Failed to Initialise SRAM\n"); /* Restore CSOR and CSOR_ext */ ifc_out32(csor, &ifc_global->csor_cs[cs].csor); diff --git a/drivers/mtd/nand/raw/nand_bch.c b/drivers/mtd/nand/raw/nand_bch.c index 505441c9373b..7f11b68f6db1 100644 --- a/drivers/mtd/nand/raw/nand_bch.c +++ b/drivers/mtd/nand/raw/nand_bch.c @@ -95,7 +95,7 @@ int nand_bch_correct_data(struct mtd_info *mtd, unsigned char *buf, errloc[i]); } } else if (count < 0) { - printk(KERN_ERR "ecc unrecoverable error\n"); + pr_err("ecc unrecoverable error\n"); count = -EBADMSG; } return count; @@ -134,7 +134,7 @@ struct nand_bch_control *nand_bch_init(struct mtd_info *mtd) } if (!eccsize || !eccbytes) { - printk(KERN_WARNING "ecc parameters not supplied\n"); + pr_warn("ecc parameters not supplied\n"); goto fail; } @@ -151,8 +151,8 @@ struct nand_bch_control *nand_bch_init(struct mtd_info *mtd) /* verify that eccbytes has the expected value */ if (nbc->bch->ecc_bytes != eccbytes) { - printk(KERN_WARNING "invalid eccbytes %u, should be %u\n", - eccbytes, nbc->bch->ecc_bytes); + pr_warn("invalid eccbytes %u, should be %u\n", + eccbytes, nbc->bch->ecc_bytes); goto fail; } @@ -166,7 +166,7 @@ struct nand_bch_control *nand_bch_init(struct mtd_info *mtd) /* sanity checks */ if (8*(eccsize+eccbytes) >= (1 << m)) { - printk(KERN_WARNING "eccsize %u is too large\n", eccsize); + pr_warn("eccsize %u is too large\n", eccsize); goto fail; } @@ -181,7 +181,7 @@ struct nand_bch_control *nand_bch_init(struct mtd_info *mtd) nand->ecc.steps = eccsteps; nand->ecc.total = eccsteps * eccbytes; if (mtd_ooblayout_count_eccbytes(mtd) != (eccsteps*eccbytes)) { - printk(KERN_WARNING "invalid ecc layout\n"); + pr_warn("invalid ecc layout\n"); goto fail; } diff --git a/drivers/mtd/nand/raw/nandsim.c b/drivers/mtd/nand/raw/nandsim.c index 44322a363ba5..e027c6f9d327 100644 --- a/drivers/mtd/nand/raw/nandsim.c +++ b/drivers/mtd/nand/raw/nandsim.c @@ -23,6 +23,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA */ +#define pr_fmt(fmt) "[nandsim]" fmt + #include #include #include @@ -179,20 +181,17 @@ MODULE_PARM_DESC(bch, "Enable BCH ecc and set how many bits should " /* The largest possible page size */ #define NS_LARGEST_PAGE_SIZE 4096 -/* The prefix for simulator output */ -#define NS_OUTPUT_PREFIX "[nandsim]" - /* Simulator's output macros (logging, debugging, warning, error) */ #define NS_LOG(args...) \ - do { if (log) printk(KERN_DEBUG NS_OUTPUT_PREFIX " log: " args); } while(0) + do { if (log) pr_debug(" log: " args); } while(0) #define NS_DBG(args...) \ - do { if (dbg) printk(KERN_DEBUG NS_OUTPUT_PREFIX " debug: " args); } while(0) + do { if (dbg) pr_debug(" debug: " args); } while(0) #define NS_WARN(args...) \ - do { printk(KERN_WARNING NS_OUTPUT_PREFIX " warning: " args); } while(0) + do { pr_warn(" warning: " args); } while(0) #define NS_ERR(args...) \ - do { printk(KERN_ERR NS_OUTPUT_PREFIX " error: " args); } while(0) + do { pr_err(" error: " args); } while(0) #define NS_INFO(args...) \ - do { printk(KERN_INFO NS_OUTPUT_PREFIX " " args); } while(0) + do { pr_info(" " args); } while(0) /* Busy-wait delay macros (microseconds, milliseconds) */ #define NS_UDELAY(us) \ diff --git a/drivers/mtd/nand/raw/r852.c b/drivers/mtd/nand/raw/r852.c index 595635b9e9de..dcdeb0660e5e 100644 --- a/drivers/mtd/nand/raw/r852.c +++ b/drivers/mtd/nand/raw/r852.c @@ -7,6 +7,9 @@ * published by the Free Software Foundation. */ +#define DRV_NAME "r852" +#define pr_fmt(fmt) DRV_NAME ": " fmt + #include #include #include @@ -932,7 +935,7 @@ static int r852_probe(struct pci_dev *pci_dev, const struct pci_device_id *id) &dev->card_detect_work, 0); - printk(KERN_NOTICE DRV_NAME ": driver loaded successfully\n"); + pr_notice("driver loaded successfully\n"); return 0; error10: diff --git a/drivers/mtd/nand/raw/r852.h b/drivers/mtd/nand/raw/r852.h index 8713c57f6207..1eed2fc2fa42 100644 --- a/drivers/mtd/nand/raw/r852.h +++ b/drivers/mtd/nand/raw/r852.h @@ -144,17 +144,14 @@ struct r852_device { uint8_t ctlreg; /* cached contents of control reg */ }; -#define DRV_NAME "r852" - - #define dbg(format, ...) \ if (debug) \ - printk(KERN_DEBUG DRV_NAME ": " format "\n", ## __VA_ARGS__) + pr_debug(format "\n", ## __VA_ARGS__) #define dbg_verbose(format, ...) \ if (debug > 1) \ - printk(KERN_DEBUG DRV_NAME ": " format "\n", ## __VA_ARGS__) + pr_debug(format "\n", ## __VA_ARGS__) #define message(format, ...) \ - printk(KERN_INFO DRV_NAME ": " format "\n", ## __VA_ARGS__) + pr_info(format "\n", ## __VA_ARGS__) diff --git a/drivers/mtd/nand/raw/sh_flctl.c b/drivers/mtd/nand/raw/sh_flctl.c index c4e7755448e6..a60d43adff3c 100644 --- a/drivers/mtd/nand/raw/sh_flctl.c +++ b/drivers/mtd/nand/raw/sh_flctl.c @@ -877,7 +877,7 @@ static void flctl_cmdfunc(struct mtd_info *mtd, unsigned int command, else if (!flctl->seqin_column) execmd_write_page_sector(mtd); else - printk(KERN_ERR "Invalid address !?\n"); + pr_err("Invalid address !?\n"); break; } set_cmd_regs(mtd, command, (command << 8) | NAND_CMD_SEQIN); diff --git a/drivers/mtd/nand/raw/sm_common.c b/drivers/mtd/nand/raw/sm_common.c index c378705c6e2b..7f5044a79f01 100644 --- a/drivers/mtd/nand/raw/sm_common.c +++ b/drivers/mtd/nand/raw/sm_common.c @@ -119,9 +119,8 @@ static int sm_block_markbad(struct mtd_info *mtd, loff_t ofs) ret = mtd_write_oob(mtd, ofs, &ops); if (ret < 0 || ops.oobretlen != SM_OOB_SIZE) { - printk(KERN_NOTICE - "sm_common: can't mark sector at %i as bad\n", - (int)ofs); + pr_notice("sm_common: can't mark sector at %i as bad\n", + (int)ofs); return -EIO; } From 828814e6a4cf2337be7cfde0b35b60a13cbc1ee7 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 9 Mar 2018 22:03:52 +0900 Subject: [PATCH 32/89] mtd: rawnand: remove STANDALONE compile mode of nand_ecc This file can not be built independently any more. We would have to bring in more to resolve mtd_to_nand(mtd)->ecc.size, for example. It is difficult to notice a breakage since nobody compiles this mode. It is not worth fixing or maintaining in my opinion. Remove. Signed-off-by: Masahiro Yamada Signed-off-by: Boris Brezillon --- drivers/mtd/nand/raw/nand_ecc.c | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/drivers/mtd/nand/raw/nand_ecc.c b/drivers/mtd/nand/raw/nand_ecc.c index 3630f0fe8fa4..8e132edbc5ce 100644 --- a/drivers/mtd/nand/raw/nand_ecc.c +++ b/drivers/mtd/nand/raw/nand_ecc.c @@ -28,15 +28,6 @@ * */ -/* - * The STANDALONE macro is useful when running the code outside the kernel - * e.g. when running the code in a testbed or a benchmark program. - * When STANDALONE is used, the module related macros are commented out - * as well as the linux include files. - * Instead a private definition of mtd_info is given to satisfy the compiler - * (the code does not use mtd_info, so the code does not care) - */ -#ifndef STANDALONE #include #include #include @@ -44,17 +35,6 @@ #include #include #include -#else -#include -struct mtd_info; -#define EXPORT_SYMBOL(x) /* x */ - -#define MODULE_LICENSE(x) /* x */ -#define MODULE_AUTHOR(x) /* x */ -#define MODULE_DESCRIPTION(x) /* x */ - -#define pr_err printf -#endif /* * invparity is a 256 byte table that contains the odd parity From d40a18fec04ae6dc6f6760923aa5f487d1af2444 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Sat, 20 Jan 2018 22:09:34 +0000 Subject: [PATCH 33/89] mtd: block2mtd: remove redundant initialization of 'bdev' Pointer bdev is being initialized however this value is never read as bdev is assigned an updated value from the returned call to blkdev_get_by_path. Remove the redundant assignment. Cleans up clang warning: drivers/mtd/devices/block2mtd.c:228:23: warning: Value stored to 'bdev' during its initialization is never read Signed-off-by: Colin Ian King Signed-off-by: Boris Brezillon --- drivers/mtd/devices/block2mtd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/devices/block2mtd.c b/drivers/mtd/devices/block2mtd.c index 62fd6905c648..bb0734600a07 100644 --- a/drivers/mtd/devices/block2mtd.c +++ b/drivers/mtd/devices/block2mtd.c @@ -225,7 +225,7 @@ static struct block2mtd_dev *add_device(char *devname, int erase_size, int i; #endif const fmode_t mode = FMODE_READ | FMODE_WRITE | FMODE_EXCL; - struct block_device *bdev = ERR_PTR(-ENODEV); + struct block_device *bdev; struct block2mtd_dev *dev; char *name; From f0a37a8db81ea9c7034e0fff4a430b221019fc50 Mon Sep 17 00:00:00 2001 From: Antonio Cardace Date: Mon, 12 Feb 2018 18:41:30 +0000 Subject: [PATCH 34/89] mtd: st_spi_fsm: use %*ph to print small buffer Use %*ph format to print small buffer as hex string. Suggested-by: Andy Shevchenko Signed-off-by: Antonio Cardace Signed-off-by: Boris Brezillon --- drivers/mtd/devices/st_spi_fsm.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/mtd/devices/st_spi_fsm.c b/drivers/mtd/devices/st_spi_fsm.c index 7bc29d725200..a33f5fd6818c 100644 --- a/drivers/mtd/devices/st_spi_fsm.c +++ b/drivers/mtd/devices/st_spi_fsm.c @@ -1868,8 +1868,7 @@ static struct flash_info *stfsm_jedec_probe(struct stfsm *fsm) */ ext_jedec = id[3] << 8 | id[4]; - dev_dbg(fsm->dev, "JEDEC = 0x%08x [%02x %02x %02x %02x %02x]\n", - jedec, id[0], id[1], id[2], id[3], id[4]); + dev_dbg(fsm->dev, "JEDEC = 0x%08x [%5ph]\n", jedec, id); for (info = flash_types; info->name; info++) { if (info->jedec_id == jedec) { From c585da9f5f6186739f0b123b8a5b6353e425f51b Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Mon, 12 Feb 2018 22:03:07 +0100 Subject: [PATCH 35/89] mtd: Initialize ->fail_addr early in mtd_erase() mtd_erase() can return an error before ->fail_addr is initialized to MTD_FAIL_ADDR_UNKNOWN. Move this initialization at the very beginning of the function. Signed-off-by: Boris Brezillon Reviewed-by: Richard Weinberger --- drivers/mtd/mtdcore.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index a1c94526fb88..c87859ff338b 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -953,6 +953,8 @@ EXPORT_SYMBOL_GPL(__put_mtd_device); */ int mtd_erase(struct mtd_info *mtd, struct erase_info *instr) { + instr->fail_addr = MTD_FAIL_ADDR_UNKNOWN; + if (!mtd->erasesize || !mtd->_erase) return -ENOTSUPP; @@ -961,7 +963,6 @@ int mtd_erase(struct mtd_info *mtd, struct erase_info *instr) if (!(mtd->flags & MTD_WRITEABLE)) return -EROFS; - instr->fail_addr = MTD_FAIL_ADDR_UNKNOWN; if (!instr->len) { instr->state = MTD_ERASE_DONE; mtd_erase_callback(instr); From dcba51bbb9e0cc7f80d36eb20a033a4dff2ce9cc Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Mon, 12 Feb 2018 22:03:08 +0100 Subject: [PATCH 36/89] mtd: Get rid of unused fields in struct erase_info Some fields are not used by MTD drivers, users or core code. Moreover, those fields are not documented, so get rid of them to avoid any confusion. Signed-off-by: Boris Brezillon Reviewed-by: Richard Weinberger --- include/linux/mtd/mtd.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h index 205ededccc60..2a407dc9beaa 100644 --- a/include/linux/mtd/mtd.h +++ b/include/linux/mtd/mtd.h @@ -48,14 +48,9 @@ struct erase_info { uint64_t addr; uint64_t len; uint64_t fail_addr; - u_long time; - u_long retries; - unsigned dev; - unsigned cell; void (*callback) (struct erase_info *self); u_long priv; u_char state; - struct erase_info *next; }; struct mtd_erase_region_info { From 884cfd9023ce6afe8bcf181ec988d8516eb32bf0 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Mon, 12 Feb 2018 22:03:09 +0100 Subject: [PATCH 37/89] mtd: Stop assuming mtd_erase() is asynchronous None of the mtd->_erase() implementations work in an asynchronous manner, so let's simplify MTD users that call mtd_erase(). All they need to do is check the value returned by mtd_erase() and assume that != 0 means failure. Signed-off-by: Boris Brezillon Reviewed-by: Richard Weinberger --- drivers/mtd/devices/bcm47xxsflash.c | 3 - drivers/mtd/ftl.c | 51 +++------------- drivers/mtd/inftlmount.c | 5 +- drivers/mtd/mtdblock.c | 20 ------- drivers/mtd/mtdchar.c | 31 ---------- drivers/mtd/mtdconcat.c | 48 +-------------- drivers/mtd/mtdcore.c | 8 +-- drivers/mtd/mtdoops.c | 19 ------ drivers/mtd/mtdpart.c | 2 - drivers/mtd/mtdswap.c | 32 ---------- drivers/mtd/nftlmount.c | 4 +- drivers/mtd/rfd_ftl.c | 92 +++++++++-------------------- drivers/mtd/sm_ftl.c | 18 ------ drivers/mtd/sm_ftl.h | 4 -- drivers/mtd/tests/mtd_test.c | 4 -- drivers/mtd/tests/speedtest.c | 6 -- drivers/mtd/ubi/io.c | 35 ----------- fs/jffs2/erase.c | 36 ++--------- include/linux/mtd/mtd.h | 2 - 19 files changed, 51 insertions(+), 369 deletions(-) diff --git a/drivers/mtd/devices/bcm47xxsflash.c b/drivers/mtd/devices/bcm47xxsflash.c index e2bd81817df4..6b84947cfbea 100644 --- a/drivers/mtd/devices/bcm47xxsflash.c +++ b/drivers/mtd/devices/bcm47xxsflash.c @@ -95,9 +95,6 @@ static int bcm47xxsflash_erase(struct mtd_info *mtd, struct erase_info *erase) else erase->state = MTD_ERASE_DONE; - if (erase->callback) - erase->callback(erase); - return err; } diff --git a/drivers/mtd/ftl.c b/drivers/mtd/ftl.c index 664d206a4cbe..fcf9907e7987 100644 --- a/drivers/mtd/ftl.c +++ b/drivers/mtd/ftl.c @@ -140,12 +140,6 @@ typedef struct partition_t { #define XFER_PREPARED 0x03 #define XFER_FAILED 0x04 -/*====================================================================*/ - - -static void ftl_erase_callback(struct erase_info *done); - - /*====================================================================== Scan_header() checks to see if a memory region contains an FTL @@ -349,17 +343,19 @@ static int erase_xfer(partition_t *part, return -ENOMEM; erase->mtd = part->mbd.mtd; - erase->callback = ftl_erase_callback; erase->addr = xfer->Offset; erase->len = 1 << part->header.EraseUnitSize; - erase->priv = (u_long)part; ret = mtd_erase(part->mbd.mtd, erase); + if (!ret) { + xfer->state = XFER_ERASED; + xfer->EraseCount++; + } else { + xfer->state = XFER_FAILED; + pr_notice("ftl_cs: erase failed: err = %d\n", ret); + } - if (!ret) - xfer->EraseCount++; - else - kfree(erase); + kfree(erase); return ret; } /* erase_xfer */ @@ -371,37 +367,6 @@ static int erase_xfer(partition_t *part, ======================================================================*/ -static void ftl_erase_callback(struct erase_info *erase) -{ - partition_t *part; - struct xfer_info_t *xfer; - int i; - - /* Look up the transfer unit */ - part = (partition_t *)(erase->priv); - - for (i = 0; i < part->header.NumTransferUnits; i++) - if (part->XferInfo[i].Offset == erase->addr) break; - - if (i == part->header.NumTransferUnits) { - printk(KERN_NOTICE "ftl_cs: internal error: " - "erase lookup failed!\n"); - return; - } - - xfer = &part->XferInfo[i]; - if (erase->state == MTD_ERASE_DONE) - xfer->state = XFER_ERASED; - else { - xfer->state = XFER_FAILED; - printk(KERN_NOTICE "ftl_cs: erase failed: state = %d\n", - erase->state); - } - - kfree(erase); - -} /* ftl_erase_callback */ - static int prepare_xfer(partition_t *part, int i) { erase_unit_header_t header; diff --git a/drivers/mtd/inftlmount.c b/drivers/mtd/inftlmount.c index 8d6bb189ea8e..0f47be4834d8 100644 --- a/drivers/mtd/inftlmount.c +++ b/drivers/mtd/inftlmount.c @@ -393,9 +393,10 @@ int INFTL_formatblock(struct INFTLrecord *inftl, int block) mark only the failed block in the bbt. */ for (physblock = 0; physblock < inftl->EraseSize; physblock += instr->len, instr->addr += instr->len) { - mtd_erase(inftl->mbd.mtd, instr); + int ret; - if (instr->state == MTD_ERASE_FAILED) { + ret = mtd_erase(inftl->mbd.mtd, instr); + if (ret) { printk(KERN_WARNING "INFTL: error while formatting block %d\n", block); goto fail; diff --git a/drivers/mtd/mtdblock.c b/drivers/mtd/mtdblock.c index bb4c14f83c75..7b2b7f651181 100644 --- a/drivers/mtd/mtdblock.c +++ b/drivers/mtd/mtdblock.c @@ -55,48 +55,28 @@ struct mtdblk_dev { * being written to until a different sector is required. */ -static void erase_callback(struct erase_info *done) -{ - wait_queue_head_t *wait_q = (wait_queue_head_t *)done->priv; - wake_up(wait_q); -} - static int erase_write (struct mtd_info *mtd, unsigned long pos, int len, const char *buf) { struct erase_info erase; - DECLARE_WAITQUEUE(wait, current); - wait_queue_head_t wait_q; size_t retlen; int ret; /* * First, let's erase the flash block. */ - - init_waitqueue_head(&wait_q); erase.mtd = mtd; - erase.callback = erase_callback; erase.addr = pos; erase.len = len; - erase.priv = (u_long)&wait_q; - - set_current_state(TASK_INTERRUPTIBLE); - add_wait_queue(&wait_q, &wait); ret = mtd_erase(mtd, &erase); if (ret) { - set_current_state(TASK_RUNNING); - remove_wait_queue(&wait_q, &wait); printk (KERN_WARNING "mtdblock: erase of region [0x%lx, 0x%x] " "on \"%s\" failed\n", pos, len, mtd->name); return ret; } - schedule(); /* Wait for erase to finish. */ - remove_wait_queue(&wait_q, &wait); - /* * Next, write the data to flash. */ diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index de8c902059b8..2beb22dd6bbb 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c @@ -324,10 +324,6 @@ static ssize_t mtdchar_write(struct file *file, const char __user *buf, size_t c IOCTL calls for getting device parameters. ======================================================================*/ -static void mtdchar_erase_callback (struct erase_info *instr) -{ - wake_up((wait_queue_head_t *)instr->priv); -} static int otp_select_filemode(struct mtd_file_info *mfi, int mode) { @@ -709,11 +705,6 @@ static int mtdchar_ioctl(struct file *file, u_int cmd, u_long arg) if (!erase) ret = -ENOMEM; else { - wait_queue_head_t waitq; - DECLARE_WAITQUEUE(wait, current); - - init_waitqueue_head(&waitq); - if (cmd == MEMERASE64) { struct erase_info_user64 einfo64; @@ -736,30 +727,8 @@ static int mtdchar_ioctl(struct file *file, u_int cmd, u_long arg) erase->len = einfo32.length; } erase->mtd = mtd; - erase->callback = mtdchar_erase_callback; - erase->priv = (unsigned long)&waitq; - /* - FIXME: Allow INTERRUPTIBLE. Which means - not having the wait_queue head on the stack. - - If the wq_head is on the stack, and we - leave because we got interrupted, then the - wq_head is no longer there when the - callback routine tries to wake us up. - */ ret = mtd_erase(mtd, erase); - if (!ret) { - set_current_state(TASK_UNINTERRUPTIBLE); - add_wait_queue(&waitq, &wait); - if (erase->state != MTD_ERASE_DONE && - erase->state != MTD_ERASE_FAILED) - schedule(); - remove_wait_queue(&waitq, &wait); - set_current_state(TASK_RUNNING); - - ret = (erase->state == MTD_ERASE_FAILED)?-EIO:0; - } kfree(erase); } break; diff --git a/drivers/mtd/mtdconcat.c b/drivers/mtd/mtdconcat.c index 60bf53df5454..caa09bf6e572 100644 --- a/drivers/mtd/mtdconcat.c +++ b/drivers/mtd/mtdconcat.c @@ -333,45 +333,6 @@ concat_write_oob(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops) return -EINVAL; } -static void concat_erase_callback(struct erase_info *instr) -{ - wake_up((wait_queue_head_t *) instr->priv); -} - -static int concat_dev_erase(struct mtd_info *mtd, struct erase_info *erase) -{ - int err; - wait_queue_head_t waitq; - DECLARE_WAITQUEUE(wait, current); - - /* - * This code was stol^H^H^H^Hinspired by mtdchar.c - */ - init_waitqueue_head(&waitq); - - erase->mtd = mtd; - erase->callback = concat_erase_callback; - erase->priv = (unsigned long) &waitq; - - /* - * FIXME: Allow INTERRUPTIBLE. Which means - * not having the wait_queue head on the stack. - */ - err = mtd_erase(mtd, erase); - if (!err) { - set_current_state(TASK_UNINTERRUPTIBLE); - add_wait_queue(&waitq, &wait); - if (erase->state != MTD_ERASE_DONE - && erase->state != MTD_ERASE_FAILED) - schedule(); - remove_wait_queue(&waitq, &wait); - set_current_state(TASK_RUNNING); - - err = (erase->state == MTD_ERASE_FAILED) ? -EIO : 0; - } - return err; -} - static int concat_erase(struct mtd_info *mtd, struct erase_info *instr) { struct mtd_concat *concat = CONCAT(mtd); @@ -466,7 +427,8 @@ static int concat_erase(struct mtd_info *mtd, struct erase_info *instr) erase->len = length; length -= erase->len; - if ((err = concat_dev_erase(subdev, erase))) { + erase->mtd = subdev; + if ((err = mtd_erase(subdev, erase))) { /* sanity check: should never happen since * block alignment has been checked above */ BUG_ON(err == -EINVAL); @@ -487,12 +449,8 @@ static int concat_erase(struct mtd_info *mtd, struct erase_info *instr) } instr->state = erase->state; kfree(erase); - if (err) - return err; - if (instr->callback) - instr->callback(instr); - return 0; + return err; } static int concat_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index c87859ff338b..f92ad02959eb 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -945,11 +945,9 @@ void __put_mtd_device(struct mtd_info *mtd) EXPORT_SYMBOL_GPL(__put_mtd_device); /* - * Erase is an asynchronous operation. Device drivers are supposed - * to call instr->callback() whenever the operation completes, even - * if it completes with a failure. - * Callers are supposed to pass a callback function and wait for it - * to be called before writing to the block. + * Erase is an synchronous operation. Device drivers are epected to return a + * negative error code if the operation failed and update instr->fail_addr + * to point the portion that was not properly erased. */ int mtd_erase(struct mtd_info *mtd, struct erase_info *instr) { diff --git a/drivers/mtd/mtdoops.c b/drivers/mtd/mtdoops.c index 97bb8f6304d4..028ded59297b 100644 --- a/drivers/mtd/mtdoops.c +++ b/drivers/mtd/mtdoops.c @@ -84,12 +84,6 @@ static int page_is_used(struct mtdoops_context *cxt, int page) return test_bit(page, cxt->oops_page_used); } -static void mtdoops_erase_callback(struct erase_info *done) -{ - wait_queue_head_t *wait_q = (wait_queue_head_t *)done->priv; - wake_up(wait_q); -} - static int mtdoops_erase_block(struct mtdoops_context *cxt, int offset) { struct mtd_info *mtd = cxt->mtd; @@ -97,34 +91,21 @@ static int mtdoops_erase_block(struct mtdoops_context *cxt, int offset) u32 start_page = start_page_offset / record_size; u32 erase_pages = mtd->erasesize / record_size; struct erase_info erase; - DECLARE_WAITQUEUE(wait, current); - wait_queue_head_t wait_q; int ret; int page; - init_waitqueue_head(&wait_q); erase.mtd = mtd; - erase.callback = mtdoops_erase_callback; erase.addr = offset; erase.len = mtd->erasesize; - erase.priv = (u_long)&wait_q; - - set_current_state(TASK_INTERRUPTIBLE); - add_wait_queue(&wait_q, &wait); ret = mtd_erase(mtd, &erase); if (ret) { - set_current_state(TASK_RUNNING); - remove_wait_queue(&wait_q, &wait); printk(KERN_WARNING "mtdoops: erase of region [0x%llx, 0x%llx] on \"%s\" failed\n", (unsigned long long)erase.addr, (unsigned long long)erase.len, mtddev); return ret; } - schedule(); /* Wait for erase to finish. */ - remove_wait_queue(&wait_q, &wait); - /* Mark pages as unused */ for (page = start_page; page < start_page + erase_pages; page++) mark_page_unused(cxt, page); diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index 76cd21d1171b..ae1206633d9d 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c @@ -222,8 +222,6 @@ void mtd_erase_callback(struct erase_info *instr) instr->fail_addr -= part->offset; instr->addr -= part->offset; } - if (instr->callback) - instr->callback(instr); } EXPORT_SYMBOL_GPL(mtd_erase_callback); diff --git a/drivers/mtd/mtdswap.c b/drivers/mtd/mtdswap.c index 7eb0e1f4f980..d390324d102e 100644 --- a/drivers/mtd/mtdswap.c +++ b/drivers/mtd/mtdswap.c @@ -536,18 +536,10 @@ static void mtdswap_store_eb(struct mtdswap_dev *d, struct swap_eb *eb) mtdswap_rb_add(d, eb, MTDSWAP_HIFRAG); } - -static void mtdswap_erase_callback(struct erase_info *done) -{ - wait_queue_head_t *wait_q = (wait_queue_head_t *)done->priv; - wake_up(wait_q); -} - static int mtdswap_erase_block(struct mtdswap_dev *d, struct swap_eb *eb) { struct mtd_info *mtd = d->mtd; struct erase_info erase; - wait_queue_head_t wq; unsigned int retries = 0; int ret; @@ -556,14 +548,11 @@ static int mtdswap_erase_block(struct mtdswap_dev *d, struct swap_eb *eb) d->max_erase_count = eb->erase_count; retry: - init_waitqueue_head(&wq); memset(&erase, 0, sizeof(struct erase_info)); erase.mtd = mtd; - erase.callback = mtdswap_erase_callback; erase.addr = mtdswap_eb_offset(d, eb); erase.len = mtd->erasesize; - erase.priv = (u_long)&wq; ret = mtd_erase(mtd, &erase); if (ret) { @@ -582,27 +571,6 @@ retry: return -EIO; } - ret = wait_event_interruptible(wq, erase.state == MTD_ERASE_DONE || - erase.state == MTD_ERASE_FAILED); - if (ret) { - dev_err(d->dev, "Interrupted erase block %#llx erasure on %s\n", - erase.addr, mtd->name); - return -EINTR; - } - - if (erase.state == MTD_ERASE_FAILED) { - if (retries++ < MTDSWAP_ERASE_RETRIES) { - dev_warn(d->dev, - "erase of erase block %#llx on %s failed", - erase.addr, mtd->name); - yield(); - goto retry; - } - - mtdswap_handle_badblock(d, eb); - return -EIO; - } - return 0; } diff --git a/drivers/mtd/nftlmount.c b/drivers/mtd/nftlmount.c index 184c8fbfe465..07e122449759 100644 --- a/drivers/mtd/nftlmount.c +++ b/drivers/mtd/nftlmount.c @@ -331,9 +331,7 @@ int NFTL_formatblock(struct NFTLrecord *nftl, int block) instr->mtd = nftl->mbd.mtd; instr->addr = block * nftl->EraseSize; instr->len = nftl->EraseSize; - mtd_erase(mtd, instr); - - if (instr->state == MTD_ERASE_FAILED) { + if (mtd_erase(mtd, instr)) { printk("Error while formatting block %d\n", block); goto fail; } diff --git a/drivers/mtd/rfd_ftl.c b/drivers/mtd/rfd_ftl.c index d1cbf26db2c0..4e0b55cd08e2 100644 --- a/drivers/mtd/rfd_ftl.c +++ b/drivers/mtd/rfd_ftl.c @@ -266,91 +266,55 @@ static int rfd_ftl_readsect(struct mtd_blktrans_dev *dev, u_long sector, char *b return 0; } -static void erase_callback(struct erase_info *erase) -{ - struct partition *part; - u16 magic; - int i, rc; - size_t retlen; - - part = (struct partition*)erase->priv; - - i = (u32)erase->addr / part->block_size; - if (i >= part->total_blocks || part->blocks[i].offset != erase->addr || - erase->addr > UINT_MAX) { - printk(KERN_ERR PREFIX "erase callback for unknown offset %llx " - "on '%s'\n", (unsigned long long)erase->addr, part->mbd.mtd->name); - return; - } - - if (erase->state != MTD_ERASE_DONE) { - printk(KERN_WARNING PREFIX "erase failed at 0x%llx on '%s', " - "state %d\n", (unsigned long long)erase->addr, - part->mbd.mtd->name, erase->state); - - part->blocks[i].state = BLOCK_FAILED; - part->blocks[i].free_sectors = 0; - part->blocks[i].used_sectors = 0; - - kfree(erase); - - return; - } - - magic = cpu_to_le16(RFD_MAGIC); - - part->blocks[i].state = BLOCK_ERASED; - part->blocks[i].free_sectors = part->data_sectors_per_block; - part->blocks[i].used_sectors = 0; - part->blocks[i].erases++; - - rc = mtd_write(part->mbd.mtd, part->blocks[i].offset, sizeof(magic), - &retlen, (u_char *)&magic); - - if (!rc && retlen != sizeof(magic)) - rc = -EIO; - - if (rc) { - printk(KERN_ERR PREFIX "'%s': unable to write RFD " - "header at 0x%lx\n", - part->mbd.mtd->name, - part->blocks[i].offset); - part->blocks[i].state = BLOCK_FAILED; - } - else - part->blocks[i].state = BLOCK_OK; - - kfree(erase); -} - static int erase_block(struct partition *part, int block) { struct erase_info *erase; - int rc = -ENOMEM; + int rc; erase = kmalloc(sizeof(struct erase_info), GFP_KERNEL); if (!erase) - goto err; + return -ENOMEM; erase->mtd = part->mbd.mtd; - erase->callback = erase_callback; erase->addr = part->blocks[block].offset; erase->len = part->block_size; - erase->priv = (u_long)part; part->blocks[block].state = BLOCK_ERASING; part->blocks[block].free_sectors = 0; rc = mtd_erase(part->mbd.mtd, erase); - if (rc) { printk(KERN_ERR PREFIX "erase of region %llx,%llx on '%s' " "failed\n", (unsigned long long)erase->addr, (unsigned long long)erase->len, part->mbd.mtd->name); - kfree(erase); + part->blocks[block].state = BLOCK_FAILED; + part->blocks[block].free_sectors = 0; + part->blocks[block].used_sectors = 0; + } else { + u16 magic = cpu_to_le16(RFD_MAGIC); + size_t retlen; + + part->blocks[block].state = BLOCK_ERASED; + part->blocks[block].free_sectors = part->data_sectors_per_block; + part->blocks[block].used_sectors = 0; + part->blocks[block].erases++; + + rc = mtd_write(part->mbd.mtd, part->blocks[block].offset, + sizeof(magic), &retlen, (u_char *)&magic); + if (!rc && retlen != sizeof(magic)) + rc = -EIO; + + if (rc) { + pr_err(PREFIX "'%s': unable to write RFD header at 0x%lx\n", + part->mbd.mtd->name, part->blocks[block].offset); + part->blocks[block].state = BLOCK_FAILED; + } else { + part->blocks[block].state = BLOCK_OK; + } } -err: + kfree(erase); + return rc; } diff --git a/drivers/mtd/sm_ftl.c b/drivers/mtd/sm_ftl.c index 4237c7cebf02..c11156f9d96f 100644 --- a/drivers/mtd/sm_ftl.c +++ b/drivers/mtd/sm_ftl.c @@ -461,10 +461,8 @@ static int sm_erase_block(struct sm_ftl *ftl, int zone_num, uint16_t block, struct erase_info erase; erase.mtd = mtd; - erase.callback = sm_erase_callback; erase.addr = sm_mkoffset(ftl, zone_num, block, 0); erase.len = ftl->block_size; - erase.priv = (u_long)ftl; if (ftl->unstable) return -EIO; @@ -482,15 +480,6 @@ static int sm_erase_block(struct sm_ftl *ftl, int zone_num, uint16_t block, goto error; } - if (erase.state == MTD_ERASE_PENDING) - wait_for_completion(&ftl->erase_completion); - - if (erase.state != MTD_ERASE_DONE) { - sm_printk("erase of block %d in zone %d failed after wait", - block, zone_num); - goto error; - } - if (put_free) kfifo_in(&zone->free_sectors, (const unsigned char *)&block, sizeof(block)); @@ -501,12 +490,6 @@ error: return -EIO; } -static void sm_erase_callback(struct erase_info *self) -{ - struct sm_ftl *ftl = (struct sm_ftl *)self->priv; - complete(&ftl->erase_completion); -} - /* Thoroughly test that block is valid. */ static int sm_check_block(struct sm_ftl *ftl, int zone, int block) { @@ -1141,7 +1124,6 @@ static void sm_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) mutex_init(&ftl->mutex); timer_setup(&ftl->timer, sm_cache_flush_timer, 0); INIT_WORK(&ftl->flush_work, sm_cache_flush_work); - init_completion(&ftl->erase_completion); /* Read media information */ if (sm_get_media_info(ftl, mtd)) { diff --git a/drivers/mtd/sm_ftl.h b/drivers/mtd/sm_ftl.h index 43bb7300785b..0a46d75cdc6a 100644 --- a/drivers/mtd/sm_ftl.h +++ b/drivers/mtd/sm_ftl.h @@ -53,9 +53,6 @@ struct sm_ftl { struct work_struct flush_work; struct timer_list timer; - /* Async erase stuff */ - struct completion erase_completion; - /* Geometry stuff */ int heads; int sectors; @@ -86,7 +83,6 @@ struct chs_entry { printk(KERN_DEBUG "sm_ftl" ": " format "\n", ## __VA_ARGS__) -static void sm_erase_callback(struct erase_info *self); static int sm_erase_block(struct sm_ftl *ftl, int zone_num, uint16_t block, int put_free); static void sm_mark_block_bad(struct sm_ftl *ftl, int zone_num, int block); diff --git a/drivers/mtd/tests/mtd_test.c b/drivers/mtd/tests/mtd_test.c index 3d0b8b5c1a53..0ac625e8f798 100644 --- a/drivers/mtd/tests/mtd_test.c +++ b/drivers/mtd/tests/mtd_test.c @@ -24,10 +24,6 @@ int mtdtest_erase_eraseblock(struct mtd_info *mtd, unsigned int ebnum) return err; } - if (ei.state == MTD_ERASE_FAILED) { - pr_info("some erase error occurred at EB %d\n", ebnum); - return -EIO; - } return 0; } diff --git a/drivers/mtd/tests/speedtest.c b/drivers/mtd/tests/speedtest.c index 0b89418a0888..f8e5dc11f943 100644 --- a/drivers/mtd/tests/speedtest.c +++ b/drivers/mtd/tests/speedtest.c @@ -70,12 +70,6 @@ static int multiblock_erase(int ebnum, int blocks) return err; } - if (ei.state == MTD_ERASE_FAILED) { - pr_err("some erase error occurred at EB %d," - "blocks %d\n", ebnum, blocks); - return -EIO; - } - return 0; } diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c index 8290432017ce..8843d26837b2 100644 --- a/drivers/mtd/ubi/io.c +++ b/drivers/mtd/ubi/io.c @@ -308,18 +308,6 @@ int ubi_io_write(struct ubi_device *ubi, const void *buf, int pnum, int offset, return err; } -/** - * erase_callback - MTD erasure call-back. - * @ei: MTD erase information object. - * - * Note, even though MTD erase interface is asynchronous, all the current - * implementations are synchronous anyway. - */ -static void erase_callback(struct erase_info *ei) -{ - wake_up_interruptible((wait_queue_head_t *)ei->priv); -} - /** * do_sync_erase - synchronously erase a physical eraseblock. * @ubi: UBI device description object @@ -333,7 +321,6 @@ static int do_sync_erase(struct ubi_device *ubi, int pnum) { int err, retries = 0; struct erase_info ei; - wait_queue_head_t wq; dbg_io("erase PEB %d", pnum); ubi_assert(pnum >= 0 && pnum < ubi->peb_count); @@ -344,14 +331,11 @@ static int do_sync_erase(struct ubi_device *ubi, int pnum) } retry: - init_waitqueue_head(&wq); memset(&ei, 0, sizeof(struct erase_info)); ei.mtd = ubi->mtd; ei.addr = (loff_t)pnum * ubi->peb_size; ei.len = ubi->peb_size; - ei.callback = erase_callback; - ei.priv = (unsigned long)&wq; err = mtd_erase(ubi->mtd, &ei); if (err) { @@ -366,25 +350,6 @@ retry: return err; } - err = wait_event_interruptible(wq, ei.state == MTD_ERASE_DONE || - ei.state == MTD_ERASE_FAILED); - if (err) { - ubi_err(ubi, "interrupted PEB %d erasure", pnum); - return -EINTR; - } - - if (ei.state == MTD_ERASE_FAILED) { - if (retries++ < UBI_IO_RETRIES) { - ubi_warn(ubi, "error while erasing PEB %d, retry", - pnum); - yield(); - goto retry; - } - ubi_err(ubi, "cannot erase PEB %d", pnum); - dump_stack(); - return -EIO; - } - err = ubi_self_check_all_ff(ubi, pnum, 0, ubi->peb_size); if (err) return err; diff --git a/fs/jffs2/erase.c b/fs/jffs2/erase.c index 4a6cf289be24..09bb6c00b869 100644 --- a/fs/jffs2/erase.c +++ b/fs/jffs2/erase.c @@ -21,14 +21,6 @@ #include #include "nodelist.h" -struct erase_priv_struct { - struct jffs2_eraseblock *jeb; - struct jffs2_sb_info *c; -}; - -#ifndef __ECOS -static void jffs2_erase_callback(struct erase_info *); -#endif static void jffs2_erase_failed(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, uint32_t bad_offset); static void jffs2_erase_succeeded(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb); static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb); @@ -51,7 +43,7 @@ static void jffs2_erase_block(struct jffs2_sb_info *c, jffs2_dbg(1, "%s(): erase block %#08x (range %#08x-%#08x)\n", __func__, jeb->offset, jeb->offset, jeb->offset + c->sector_size); - instr = kmalloc(sizeof(struct erase_info) + sizeof(struct erase_priv_struct), GFP_KERNEL); + instr = kmalloc(sizeof(struct erase_info), GFP_KERNEL); if (!instr) { pr_warn("kmalloc for struct erase_info in jffs2_erase_block failed. Refiling block for later\n"); mutex_lock(&c->erase_free_sem); @@ -70,15 +62,13 @@ static void jffs2_erase_block(struct jffs2_sb_info *c, instr->mtd = c->mtd; instr->addr = jeb->offset; instr->len = c->sector_size; - instr->callback = jffs2_erase_callback; - instr->priv = (unsigned long)(&instr[1]); - - ((struct erase_priv_struct *)instr->priv)->jeb = jeb; - ((struct erase_priv_struct *)instr->priv)->c = c; ret = mtd_erase(c->mtd, instr); - if (!ret) + if (!ret) { + jffs2_erase_succeeded(c, jeb); + kfree(instr); return; + } bad_offset = instr->fail_addr; kfree(instr); @@ -214,22 +204,6 @@ static void jffs2_erase_failed(struct jffs2_sb_info *c, struct jffs2_eraseblock wake_up(&c->erase_wait); } -#ifndef __ECOS -static void jffs2_erase_callback(struct erase_info *instr) -{ - struct erase_priv_struct *priv = (void *)instr->priv; - - if(instr->state != MTD_ERASE_DONE) { - pr_warn("Erase at 0x%08llx finished, but state != MTD_ERASE_DONE. State is 0x%x instead.\n", - (unsigned long long)instr->addr, instr->state); - jffs2_erase_failed(priv->c, priv->jeb, instr->fail_addr); - } else { - jffs2_erase_succeeded(priv->c, priv->jeb); - } - kfree(instr); -} -#endif /* !__ECOS */ - /* Hmmm. Maybe we should accept the extra space it takes and make this a standard doubly-linked list? */ static inline void jffs2_remove_node_refs_from_ino_list(struct jffs2_sb_info *c, diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h index 2a407dc9beaa..5018437d7999 100644 --- a/include/linux/mtd/mtd.h +++ b/include/linux/mtd/mtd.h @@ -48,8 +48,6 @@ struct erase_info { uint64_t addr; uint64_t len; uint64_t fail_addr; - void (*callback) (struct erase_info *self); - u_long priv; u_char state; }; From 8f347c4232d5fc097599b711a3385722a6834005 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Mon, 12 Feb 2018 22:03:10 +0100 Subject: [PATCH 38/89] mtd: Unconditionally update ->fail_addr and ->addr in part_erase() ->fail_addr and ->addr can be updated no matter the result of parent->_erase(), we just need to remove the code doing the same thing in mtd_erase_callback() to avoid adjusting those fields twice. Note that this can be done because all MTD users have been converted to not pass an erase_info->callback() and are thus only taking the ->addr_fail and ->addr fields into account after part_erase() has returned. While we're at it, get rid of the erase_info->mtd field which was only needed to let mtd_erase_callback() get the partition device back. Signed-off-by: Boris Brezillon Reviewed-by: Richard Weinberger --- drivers/mtd/ftl.c | 1 - drivers/mtd/inftlmount.c | 3 --- drivers/mtd/mtdblock.c | 1 - drivers/mtd/mtdchar.c | 1 - drivers/mtd/mtdconcat.c | 1 - drivers/mtd/mtdoops.c | 1 - drivers/mtd/mtdpart.c | 16 ++++------------ drivers/mtd/mtdswap.c | 2 -- drivers/mtd/nand/nand_base.c | 1 - drivers/mtd/nand/nand_bbt.c | 1 - drivers/mtd/nftlmount.c | 1 - drivers/mtd/rfd_ftl.c | 1 - drivers/mtd/sm_ftl.c | 1 - drivers/mtd/tests/mtd_test.c | 1 - drivers/mtd/tests/speedtest.c | 1 - drivers/mtd/ubi/io.c | 1 - fs/jffs2/erase.c | 1 - include/linux/mtd/mtd.h | 3 ++- 18 files changed, 6 insertions(+), 32 deletions(-) diff --git a/drivers/mtd/ftl.c b/drivers/mtd/ftl.c index fcf9907e7987..0a6adfaec7b5 100644 --- a/drivers/mtd/ftl.c +++ b/drivers/mtd/ftl.c @@ -342,7 +342,6 @@ static int erase_xfer(partition_t *part, if (!erase) return -ENOMEM; - erase->mtd = part->mbd.mtd; erase->addr = xfer->Offset; erase->len = 1 << part->header.EraseUnitSize; diff --git a/drivers/mtd/inftlmount.c b/drivers/mtd/inftlmount.c index 0f47be4834d8..aab4f68bd36f 100644 --- a/drivers/mtd/inftlmount.c +++ b/drivers/mtd/inftlmount.c @@ -208,8 +208,6 @@ static int find_boot_record(struct INFTLrecord *inftl) if (ip->Reserved0 != ip->firstUnit) { struct erase_info *instr = &inftl->instr; - instr->mtd = inftl->mbd.mtd; - /* * Most likely this is using the * undocumented qiuck mount feature. @@ -385,7 +383,6 @@ int INFTL_formatblock(struct INFTLrecord *inftl, int block) _first_? */ /* Use async erase interface, test return code */ - instr->mtd = inftl->mbd.mtd; instr->addr = block * inftl->EraseSize; instr->len = inftl->mbd.mtd->erasesize; /* Erase one physical eraseblock at a time, even though the NAND api diff --git a/drivers/mtd/mtdblock.c b/drivers/mtd/mtdblock.c index 7b2b7f651181..a5b1933c0490 100644 --- a/drivers/mtd/mtdblock.c +++ b/drivers/mtd/mtdblock.c @@ -65,7 +65,6 @@ static int erase_write (struct mtd_info *mtd, unsigned long pos, /* * First, let's erase the flash block. */ - erase.mtd = mtd; erase.addr = pos; erase.len = len; diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index 2beb22dd6bbb..c06b33f80e75 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c @@ -726,7 +726,6 @@ static int mtdchar_ioctl(struct file *file, u_int cmd, u_long arg) erase->addr = einfo32.start; erase->len = einfo32.length; } - erase->mtd = mtd; ret = mtd_erase(mtd, erase); kfree(erase); diff --git a/drivers/mtd/mtdconcat.c b/drivers/mtd/mtdconcat.c index caa09bf6e572..93c47e56d9d8 100644 --- a/drivers/mtd/mtdconcat.c +++ b/drivers/mtd/mtdconcat.c @@ -427,7 +427,6 @@ static int concat_erase(struct mtd_info *mtd, struct erase_info *instr) erase->len = length; length -= erase->len; - erase->mtd = subdev; if ((err = mtd_erase(subdev, erase))) { /* sanity check: should never happen since * block alignment has been checked above */ diff --git a/drivers/mtd/mtdoops.c b/drivers/mtd/mtdoops.c index 028ded59297b..9f25111fd559 100644 --- a/drivers/mtd/mtdoops.c +++ b/drivers/mtd/mtdoops.c @@ -94,7 +94,6 @@ static int mtdoops_erase_block(struct mtdoops_context *cxt, int offset) int ret; int page; - erase.mtd = mtd; erase.addr = offset; erase.len = mtd->erasesize; diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index ae1206633d9d..1c07a6f0dfe5 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c @@ -205,23 +205,15 @@ static int part_erase(struct mtd_info *mtd, struct erase_info *instr) instr->addr += part->offset; ret = part->parent->_erase(part->parent, instr); - if (ret) { - if (instr->fail_addr != MTD_FAIL_ADDR_UNKNOWN) - instr->fail_addr -= part->offset; - instr->addr -= part->offset; - } + if (instr->fail_addr != MTD_FAIL_ADDR_UNKNOWN) + instr->fail_addr -= part->offset; + instr->addr -= part->offset; + return ret; } void mtd_erase_callback(struct erase_info *instr) { - if (instr->mtd->_erase == part_erase) { - struct mtd_part *part = mtd_to_part(instr->mtd); - - if (instr->fail_addr != MTD_FAIL_ADDR_UNKNOWN) - instr->fail_addr -= part->offset; - instr->addr -= part->offset; - } } EXPORT_SYMBOL_GPL(mtd_erase_callback); diff --git a/drivers/mtd/mtdswap.c b/drivers/mtd/mtdswap.c index d390324d102e..7161f8a17f62 100644 --- a/drivers/mtd/mtdswap.c +++ b/drivers/mtd/mtdswap.c @@ -549,8 +549,6 @@ static int mtdswap_erase_block(struct mtdswap_dev *d, struct swap_eb *eb) retry: memset(&erase, 0, sizeof(struct erase_info)); - - erase.mtd = mtd; erase.addr = mtdswap_eb_offset(d, eb); erase.len = mtd->erasesize; diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index e70ca16a5118..16c8bc06975d 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -527,7 +527,6 @@ static int nand_block_markbad_lowlevel(struct mtd_info *mtd, loff_t ofs) /* Attempt erase before marking OOB */ memset(&einfo, 0, sizeof(einfo)); - einfo.mtd = mtd; einfo.addr = ofs; einfo.len = 1ULL << chip->phys_erase_shift; nand_erase_nand(mtd, &einfo, 0); diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index 36092850be2c..d9f4ceff2568 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c @@ -852,7 +852,6 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, } memset(&einfo, 0, sizeof(einfo)); - einfo.mtd = mtd; einfo.addr = to; einfo.len = 1 << this->bbt_erase_shift; res = nand_erase_nand(mtd, &einfo, 1); diff --git a/drivers/mtd/nftlmount.c b/drivers/mtd/nftlmount.c index 07e122449759..d8f6dba01c87 100644 --- a/drivers/mtd/nftlmount.c +++ b/drivers/mtd/nftlmount.c @@ -328,7 +328,6 @@ int NFTL_formatblock(struct NFTLrecord *nftl, int block) memset(instr, 0, sizeof(struct erase_info)); /* XXX: use async erase interface, XXX: test return code */ - instr->mtd = nftl->mbd.mtd; instr->addr = block * nftl->EraseSize; instr->len = nftl->EraseSize; if (mtd_erase(mtd, instr)) { diff --git a/drivers/mtd/rfd_ftl.c b/drivers/mtd/rfd_ftl.c index 4e0b55cd08e2..df27f24ce0fa 100644 --- a/drivers/mtd/rfd_ftl.c +++ b/drivers/mtd/rfd_ftl.c @@ -275,7 +275,6 @@ static int erase_block(struct partition *part, int block) if (!erase) return -ENOMEM; - erase->mtd = part->mbd.mtd; erase->addr = part->blocks[block].offset; erase->len = part->block_size; diff --git a/drivers/mtd/sm_ftl.c b/drivers/mtd/sm_ftl.c index c11156f9d96f..72740ede9f05 100644 --- a/drivers/mtd/sm_ftl.c +++ b/drivers/mtd/sm_ftl.c @@ -460,7 +460,6 @@ static int sm_erase_block(struct sm_ftl *ftl, int zone_num, uint16_t block, struct mtd_info *mtd = ftl->trans->mtd; struct erase_info erase; - erase.mtd = mtd; erase.addr = sm_mkoffset(ftl, zone_num, block, 0); erase.len = ftl->block_size; diff --git a/drivers/mtd/tests/mtd_test.c b/drivers/mtd/tests/mtd_test.c index 0ac625e8f798..c84250beffdc 100644 --- a/drivers/mtd/tests/mtd_test.c +++ b/drivers/mtd/tests/mtd_test.c @@ -14,7 +14,6 @@ int mtdtest_erase_eraseblock(struct mtd_info *mtd, unsigned int ebnum) loff_t addr = (loff_t)ebnum * mtd->erasesize; memset(&ei, 0, sizeof(struct erase_info)); - ei.mtd = mtd; ei.addr = addr; ei.len = mtd->erasesize; diff --git a/drivers/mtd/tests/speedtest.c b/drivers/mtd/tests/speedtest.c index f8e5dc11f943..20edb3b49c77 100644 --- a/drivers/mtd/tests/speedtest.c +++ b/drivers/mtd/tests/speedtest.c @@ -59,7 +59,6 @@ static int multiblock_erase(int ebnum, int blocks) loff_t addr = (loff_t)ebnum * mtd->erasesize; memset(&ei, 0, sizeof(struct erase_info)); - ei.mtd = mtd; ei.addr = addr; ei.len = mtd->erasesize * blocks; diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c index 8843d26837b2..0e3a76a9e2f8 100644 --- a/drivers/mtd/ubi/io.c +++ b/drivers/mtd/ubi/io.c @@ -333,7 +333,6 @@ static int do_sync_erase(struct ubi_device *ubi, int pnum) retry: memset(&ei, 0, sizeof(struct erase_info)); - ei.mtd = ubi->mtd; ei.addr = (loff_t)pnum * ubi->peb_size; ei.len = ubi->peb_size; diff --git a/fs/jffs2/erase.c b/fs/jffs2/erase.c index 09bb6c00b869..83b8f06b4a64 100644 --- a/fs/jffs2/erase.c +++ b/fs/jffs2/erase.c @@ -59,7 +59,6 @@ static void jffs2_erase_block(struct jffs2_sb_info *c, memset(instr, 0, sizeof(*instr)); - instr->mtd = c->mtd; instr->addr = jeb->offset; instr->len = c->sector_size; diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h index 5018437d7999..4cbb7f555244 100644 --- a/include/linux/mtd/mtd.h +++ b/include/linux/mtd/mtd.h @@ -38,13 +38,14 @@ #define MTD_FAIL_ADDR_UNKNOWN -1LL +struct mtd_info; + /* * If the erase fails, fail_addr might indicate exactly which block failed. If * fail_addr = MTD_FAIL_ADDR_UNKNOWN, the failure was not at the device level * or was not specific to any particular block. */ struct erase_info { - struct mtd_info *mtd; uint64_t addr; uint64_t len; uint64_t fail_addr; From 1cbe30b0ddc7afa3009dbe10f1c3d34f5adbef3f Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Fri, 9 Mar 2018 15:50:36 +0100 Subject: [PATCH 39/89] mtd: rawnand: vf610_nfc: make use of ->exec_op() This reworks the driver to make use of ->exec_op() callback. The command sequencer of the VF610 NFC aligns well with the new ops interface. The operations are translated to a NFC command code while filling the necessary registers. Instead of using the special status and read ID command codes (which require to read status/ID from special registers instead of the regular data area) the driver now now uses the main data buffer for all commands. This simplifies the driver as no special casing is needed. For control data (status byte, id bytes and parameter page) the driver needs to reverse byte order for little endian CPUs since the controller seems to store the bytes in big endian order in the data buffer. The current state seems to pass MTD tests on a Colibri VF61. Signed-off-by: Stefan Agner Reviewed-by: Miquel Raynal Signed-off-by: Boris Brezillon --- drivers/mtd/nand/raw/vf610_nfc.c | 424 ++++++++++++++++++++++++++++++- 1 file changed, 412 insertions(+), 12 deletions(-) diff --git a/drivers/mtd/nand/raw/vf610_nfc.c b/drivers/mtd/nand/raw/vf610_nfc.c index 5d7a1f8f580f..15fcefaba43e 100644 --- a/drivers/mtd/nand/raw/vf610_nfc.c +++ b/drivers/mtd/nand/raw/vf610_nfc.c @@ -36,6 +36,7 @@ #include #include #include +#include #define DRV_NAME "vf610_nfc" @@ -74,6 +75,22 @@ #define RESET_CMD_CODE 0x4040 #define STATUS_READ_CMD_CODE 0x4068 +/* NFC_CMD2[CODE] controller cycle bit masks */ +#define COMMAND_CMD_BYTE1 BIT(14) +#define COMMAND_CAR_BYTE1 BIT(13) +#define COMMAND_CAR_BYTE2 BIT(12) +#define COMMAND_RAR_BYTE1 BIT(11) +#define COMMAND_RAR_BYTE2 BIT(10) +#define COMMAND_RAR_BYTE3 BIT(9) +#define COMMAND_NADDR_BYTES(x) GENMASK(13, 13 - (x) + 1) +#define COMMAND_WRITE_DATA BIT(8) +#define COMMAND_CMD_BYTE2 BIT(7) +#define COMMAND_RB_HANDSHAKE BIT(6) +#define COMMAND_READ_DATA BIT(5) +#define COMMAND_CMD_BYTE3 BIT(4) +#define COMMAND_READ_STATUS BIT(3) +#define COMMAND_READ_ID BIT(2) + /* NFC ECC mode define */ #define ECC_BYPASS 0 #define ECC_45_BYTE 6 @@ -97,10 +114,13 @@ /* NFC_COL_ADDR Field */ #define COL_ADDR_MASK 0x0000FFFF #define COL_ADDR_SHIFT 0 +#define COL_ADDR(pos, val) (((val) & 0xFF) << (8 * (pos))) /* NFC_ROW_ADDR Field */ #define ROW_ADDR_MASK 0x00FFFFFF #define ROW_ADDR_SHIFT 0 +#define ROW_ADDR(pos, val) (((val) & 0xFF) << (8 * (pos))) + #define ROW_ADDR_CHIP_SEL_RB_MASK 0xF0000000 #define ROW_ADDR_CHIP_SEL_RB_SHIFT 28 #define ROW_ADDR_CHIP_SEL_MASK 0x0F000000 @@ -165,6 +185,12 @@ struct vf610_nfc { enum vf610_nfc_variant variant; struct clk *clk; bool use_hw_ecc; + /* + * Indicate that user data is accessed (full page/oob). This is + * useful to indicate the driver whether to swap byte endianness. + * See comments in vf610_nfc_rd_from_sram/vf610_nfc_wr_to_sram. + */ + bool data_access; u32 ecc_mode; }; @@ -173,6 +199,11 @@ static inline struct vf610_nfc *mtd_to_nfc(struct mtd_info *mtd) return container_of(mtd_to_nand(mtd), struct vf610_nfc, chip); } +static inline struct vf610_nfc *chip_to_nfc(struct nand_chip *chip) +{ + return container_of(chip, struct vf610_nfc, chip); +} + static inline u32 vf610_nfc_read(struct vf610_nfc *nfc, uint reg) { return readl(nfc->regs + reg); @@ -214,6 +245,86 @@ static inline void vf610_nfc_memcpy(void *dst, const void __iomem *src, memcpy(dst, src, n); } +static inline bool vf610_nfc_kernel_is_little_endian(void) +{ +#ifdef __LITTLE_ENDIAN + return true; +#else + return false; +#endif +} + +/** + * Read accessor for internal SRAM buffer + * @dst: destination address in regular memory + * @src: source address in SRAM buffer + * @len: bytes to copy + * @fix_endian: Fix endianness if required + * + * Use this accessor for the internal SRAM buffers. On the ARM + * Freescale Vybrid SoC it's known that the driver can treat + * the SRAM buffer as if it's memory. Other platform might need + * to treat the buffers differently. + * + * The controller stores bytes from the NAND chip internally in big + * endianness. On little endian platforms such as Vybrid this leads + * to reversed byte order. + * For performance reason (and earlier probably due to unawareness) + * the driver avoids correcting endianness where it has control over + * write and read side (e.g. page wise data access). + */ +static inline void vf610_nfc_rd_from_sram(void *dst, const void __iomem *src, + size_t len, bool fix_endian) +{ + if (vf610_nfc_kernel_is_little_endian() && fix_endian) { + unsigned int i; + + for (i = 0; i < len; i += 4) { + u32 val = swab32(__raw_readl(src + i)); + + memcpy(dst + i, &val, min(sizeof(val), len - i)); + } + } else { + memcpy_fromio(dst, src, len); + } +} + +/** + * Write accessor for internal SRAM buffer + * @dst: destination address in SRAM buffer + * @src: source address in regular memory + * @len: bytes to copy + * @fix_endian: Fix endianness if required + * + * Use this accessor for the internal SRAM buffers. On the ARM + * Freescale Vybrid SoC it's known that the driver can treat + * the SRAM buffer as if it's memory. Other platform might need + * to treat the buffers differently. + * + * The controller stores bytes from the NAND chip internally in big + * endianness. On little endian platforms such as Vybrid this leads + * to reversed byte order. + * For performance reason (and earlier probably due to unawareness) + * the driver avoids correcting endianness where it has control over + * write and read side (e.g. page wise data access). + */ +static inline void vf610_nfc_wr_to_sram(void __iomem *dst, const void *src, + size_t len, bool fix_endian) +{ + if (vf610_nfc_kernel_is_little_endian() && fix_endian) { + unsigned int i; + + for (i = 0; i < len; i += 4) { + u32 val; + + memcpy(&val, src + i, min(sizeof(val), len - i)); + __raw_writel(swab32(val), dst + i); + } + } else { + memcpy_toio(dst, src, len); + } +} + /* Clear flags for upcoming command */ static inline void vf610_nfc_clear_status(struct vf610_nfc *nfc) { @@ -489,6 +600,164 @@ static int vf610_nfc_dev_ready(struct mtd_info *mtd) return 1; } +static inline void vf610_nfc_run(struct vf610_nfc *nfc, u32 col, u32 row, + u32 cmd1, u32 cmd2, u32 trfr_sz) +{ + vf610_nfc_set_field(nfc, NFC_COL_ADDR, COL_ADDR_MASK, + COL_ADDR_SHIFT, col); + + vf610_nfc_set_field(nfc, NFC_ROW_ADDR, ROW_ADDR_MASK, + ROW_ADDR_SHIFT, row); + + vf610_nfc_write(nfc, NFC_SECTOR_SIZE, trfr_sz); + vf610_nfc_write(nfc, NFC_FLASH_CMD1, cmd1); + vf610_nfc_write(nfc, NFC_FLASH_CMD2, cmd2); + + dev_dbg(nfc->dev, + "col 0x%04x, row 0x%08x, cmd1 0x%08x, cmd2 0x%08x, len %d\n", + col, row, cmd1, cmd2, trfr_sz); + + vf610_nfc_done(nfc); +} + +static inline const struct nand_op_instr * +vf610_get_next_instr(const struct nand_subop *subop, int *op_id) +{ + if (*op_id + 1 >= subop->ninstrs) + return NULL; + + (*op_id)++; + + return &subop->instrs[*op_id]; +} + +static int vf610_nfc_cmd(struct nand_chip *chip, + const struct nand_subop *subop) +{ + const struct nand_op_instr *instr; + struct vf610_nfc *nfc = chip_to_nfc(chip); + int op_id = -1, trfr_sz = 0, offset; + u32 col = 0, row = 0, cmd1 = 0, cmd2 = 0, code = 0; + bool force8bit = false; + + /* + * Some ops are optional, but the hardware requires the operations + * to be in this exact order. + * The op parser enforces the order and makes sure that there isn't + * a read and write element in a single operation. + */ + instr = vf610_get_next_instr(subop, &op_id); + if (!instr) + return -EINVAL; + + if (instr && instr->type == NAND_OP_CMD_INSTR) { + cmd2 |= instr->ctx.cmd.opcode << CMD_BYTE1_SHIFT; + code |= COMMAND_CMD_BYTE1; + + instr = vf610_get_next_instr(subop, &op_id); + } + + if (instr && instr->type == NAND_OP_ADDR_INSTR) { + int naddrs = nand_subop_get_num_addr_cyc(subop, op_id); + int i = nand_subop_get_addr_start_off(subop, op_id); + + for (; i < naddrs; i++) { + u8 val = instr->ctx.addr.addrs[i]; + + if (i < 2) + col |= COL_ADDR(i, val); + else + row |= ROW_ADDR(i - 2, val); + } + code |= COMMAND_NADDR_BYTES(naddrs); + + instr = vf610_get_next_instr(subop, &op_id); + } + + if (instr && instr->type == NAND_OP_DATA_OUT_INSTR) { + trfr_sz = nand_subop_get_data_len(subop, op_id); + offset = nand_subop_get_data_start_off(subop, op_id); + force8bit = instr->ctx.data.force_8bit; + + /* + * Don't fix endianness on page access for historical reasons. + * See comment in vf610_nfc_wr_to_sram + */ + vf610_nfc_wr_to_sram(nfc->regs + NFC_MAIN_AREA(0) + offset, + instr->ctx.data.buf.out + offset, + trfr_sz, !nfc->data_access); + code |= COMMAND_WRITE_DATA; + + instr = vf610_get_next_instr(subop, &op_id); + } + + if (instr && instr->type == NAND_OP_CMD_INSTR) { + cmd1 |= instr->ctx.cmd.opcode << CMD_BYTE2_SHIFT; + code |= COMMAND_CMD_BYTE2; + + instr = vf610_get_next_instr(subop, &op_id); + } + + if (instr && instr->type == NAND_OP_WAITRDY_INSTR) { + code |= COMMAND_RB_HANDSHAKE; + + instr = vf610_get_next_instr(subop, &op_id); + } + + if (instr && instr->type == NAND_OP_DATA_IN_INSTR) { + trfr_sz = nand_subop_get_data_len(subop, op_id); + offset = nand_subop_get_data_start_off(subop, op_id); + force8bit = instr->ctx.data.force_8bit; + + code |= COMMAND_READ_DATA; + } + + if (force8bit && (chip->options & NAND_BUSWIDTH_16)) + vf610_nfc_clear(nfc, NFC_FLASH_CONFIG, CONFIG_16BIT); + + cmd2 |= code << CMD_CODE_SHIFT; + + vf610_nfc_run(nfc, col, row, cmd1, cmd2, trfr_sz); + + if (instr && instr->type == NAND_OP_DATA_IN_INSTR) { + /* + * Don't fix endianness on page access for historical reasons. + * See comment in vf610_nfc_rd_from_sram + */ + vf610_nfc_rd_from_sram(instr->ctx.data.buf.in + offset, + nfc->regs + NFC_MAIN_AREA(0) + offset, + trfr_sz, !nfc->data_access); + } + + if (force8bit && (chip->options & NAND_BUSWIDTH_16)) + vf610_nfc_set(nfc, NFC_FLASH_CONFIG, CONFIG_16BIT); + + return 0; +} + +static const struct nand_op_parser vf610_nfc_op_parser = NAND_OP_PARSER( + NAND_OP_PARSER_PATTERN(vf610_nfc_cmd, + NAND_OP_PARSER_PAT_CMD_ELEM(true), + NAND_OP_PARSER_PAT_ADDR_ELEM(true, 5), + NAND_OP_PARSER_PAT_DATA_OUT_ELEM(true, PAGE_2K + OOB_MAX), + NAND_OP_PARSER_PAT_CMD_ELEM(true), + NAND_OP_PARSER_PAT_WAITRDY_ELEM(true)), + NAND_OP_PARSER_PATTERN(vf610_nfc_cmd, + NAND_OP_PARSER_PAT_CMD_ELEM(true), + NAND_OP_PARSER_PAT_ADDR_ELEM(true, 5), + NAND_OP_PARSER_PAT_CMD_ELEM(true), + NAND_OP_PARSER_PAT_WAITRDY_ELEM(true), + NAND_OP_PARSER_PAT_DATA_IN_ELEM(true, PAGE_2K + OOB_MAX)), + ); + +static int vf610_nfc_exec_op(struct nand_chip *chip, + const struct nand_operation *op, + bool check_only) +{ + return nand_op_parser_exec_op(chip, &vf610_nfc_op_parser, op, + check_only); +} + /* * This function supports Vybrid only (MPC5125 would have full RB and four CS) */ @@ -526,9 +795,9 @@ static inline int vf610_nfc_correct_data(struct mtd_info *mtd, uint8_t *dat, if (!(ecc_status & ECC_STATUS_MASK)) return ecc_count; - /* Read OOB without ECC unit enabled */ - vf610_nfc_command(mtd, NAND_CMD_READOOB, 0, page); - vf610_nfc_read_buf(mtd, oob, mtd->oobsize); + nfc->data_access = true; + nand_read_oob_op(&nfc->chip, page, 0, oob, mtd->oobsize); + nfc->data_access = false; /* * On an erased page, bit count (including OOB) should be zero or @@ -539,15 +808,51 @@ static inline int vf610_nfc_correct_data(struct mtd_info *mtd, uint8_t *dat, flips_threshold); } +static void vf610_nfc_fill_row(struct nand_chip *chip, int page, u32 *code, + u32 *row) +{ + *row = ROW_ADDR(0, page & 0xff) | ROW_ADDR(1, page >> 8); + *code |= COMMAND_RAR_BYTE1 | COMMAND_RAR_BYTE2; + + if (chip->options & NAND_ROW_ADDR_3) { + *row |= ROW_ADDR(2, page >> 16); + *code |= COMMAND_RAR_BYTE3; + } +} + static int vf610_nfc_read_page(struct mtd_info *mtd, struct nand_chip *chip, uint8_t *buf, int oob_required, int page) { - int eccsize = chip->ecc.size; + struct vf610_nfc *nfc = mtd_to_nfc(mtd); + int trfr_sz = mtd->writesize + mtd->oobsize; + u32 row = 0, cmd1 = 0, cmd2 = 0, code = 0; int stat; - nand_read_page_op(chip, page, 0, buf, eccsize); + cmd2 |= NAND_CMD_READ0 << CMD_BYTE1_SHIFT; + code |= COMMAND_CMD_BYTE1 | COMMAND_CAR_BYTE1 | COMMAND_CAR_BYTE2; + + vf610_nfc_fill_row(chip, page, &code, &row); + + cmd1 |= NAND_CMD_READSTART << CMD_BYTE2_SHIFT; + code |= COMMAND_CMD_BYTE2 | COMMAND_RB_HANDSHAKE | COMMAND_READ_DATA; + + cmd2 |= code << CMD_CODE_SHIFT; + + vf610_nfc_ecc_mode(nfc, nfc->ecc_mode); + vf610_nfc_run(nfc, 0, row, cmd1, cmd2, trfr_sz); + vf610_nfc_ecc_mode(nfc, ECC_BYPASS); + + /* + * Don't fix endianness on page access for historical reasons. + * See comment in vf610_nfc_rd_from_sram + */ + vf610_nfc_rd_from_sram(buf, nfc->regs + NFC_MAIN_AREA(0), + mtd->writesize, false); if (oob_required) - vf610_nfc_read_buf(mtd, chip->oob_poi, mtd->oobsize); + vf610_nfc_rd_from_sram(chip->oob_poi, + nfc->regs + NFC_MAIN_AREA(0) + + mtd->writesize, + mtd->oobsize, false); stat = vf610_nfc_correct_data(mtd, buf, chip->oob_poi, page); @@ -564,14 +869,103 @@ static int vf610_nfc_write_page(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf, int oob_required, int page) { struct vf610_nfc *nfc = mtd_to_nfc(mtd); + int trfr_sz = mtd->writesize + mtd->oobsize; + u32 row = 0, cmd1 = 0, cmd2 = 0, code = 0; + u8 status; + int ret; - nand_prog_page_begin_op(chip, page, 0, buf, mtd->writesize); - if (oob_required) - vf610_nfc_write_buf(mtd, chip->oob_poi, mtd->oobsize); + cmd2 |= NAND_CMD_SEQIN << CMD_BYTE1_SHIFT; + code |= COMMAND_CMD_BYTE1 | COMMAND_CAR_BYTE1 | COMMAND_CAR_BYTE2; - /* Always write whole page including OOB due to HW ECC */ - nfc->use_hw_ecc = true; - nfc->write_sz = mtd->writesize + mtd->oobsize; + vf610_nfc_fill_row(chip, page, &code, &row); + + cmd1 |= NAND_CMD_PAGEPROG << CMD_BYTE2_SHIFT; + code |= COMMAND_CMD_BYTE2 | COMMAND_WRITE_DATA; + + /* + * Don't fix endianness on page access for historical reasons. + * See comment in vf610_nfc_wr_to_sram + */ + vf610_nfc_wr_to_sram(nfc->regs + NFC_MAIN_AREA(0), buf, + mtd->writesize, false); + + code |= COMMAND_RB_HANDSHAKE; + cmd2 |= code << CMD_CODE_SHIFT; + + vf610_nfc_ecc_mode(nfc, nfc->ecc_mode); + vf610_nfc_run(nfc, 0, row, cmd1, cmd2, trfr_sz); + vf610_nfc_ecc_mode(nfc, ECC_BYPASS); + + ret = nand_status_op(chip, &status); + if (ret) + return ret; + + if (status & NAND_STATUS_FAIL) + return -EIO; + + return 0; +} + +static int vf610_nfc_read_page_raw(struct mtd_info *mtd, + struct nand_chip *chip, u8 *buf, + int oob_required, int page) +{ + struct vf610_nfc *nfc = mtd_to_nfc(mtd); + int ret; + + nfc->data_access = true; + ret = nand_read_page_raw(mtd, chip, buf, oob_required, page); + nfc->data_access = false; + + return ret; +} + +static int vf610_nfc_write_page_raw(struct mtd_info *mtd, + struct nand_chip *chip, const u8 *buf, + int oob_required, int page) +{ + struct vf610_nfc *nfc = mtd_to_nfc(mtd); + int ret; + + nfc->data_access = true; + ret = nand_prog_page_begin_op(chip, page, 0, buf, mtd->writesize); + if (!ret && oob_required) + ret = nand_write_data_op(chip, chip->oob_poi, mtd->oobsize, + false); + nfc->data_access = false; + + if (ret) + return ret; + + return nand_prog_page_end_op(chip); +} + +static int vf610_nfc_read_oob(struct mtd_info *mtd, struct nand_chip *chip, + int page) +{ + struct vf610_nfc *nfc = mtd_to_nfc(mtd); + int ret; + + nfc->data_access = true; + ret = nand_read_oob_std(mtd, chip, page); + nfc->data_access = false; + + return ret; +} + +static int vf610_nfc_write_oob(struct mtd_info *mtd, struct nand_chip *chip, + int page) +{ + struct vf610_nfc *nfc = mtd_to_nfc(mtd); + int ret; + + nfc->data_access = true; + ret = nand_prog_page_begin_op(chip, page, mtd->writesize, + chip->oob_poi, mtd->oobsize); + nfc->data_access = false; + + if (ret) + return ret; return nand_prog_page_end_op(chip); } @@ -590,6 +984,7 @@ static void vf610_nfc_preinit_controller(struct vf610_nfc *nfc) vf610_nfc_clear(nfc, NFC_FLASH_CONFIG, CONFIG_BOOT_MODE_BIT); vf610_nfc_clear(nfc, NFC_FLASH_CONFIG, CONFIG_DMA_REQ_BIT); vf610_nfc_set(nfc, NFC_FLASH_CONFIG, CONFIG_FAST_FLASH_BIT); + vf610_nfc_ecc_mode(nfc, ECC_BYPASS); /* Disable virtual pages, only one elementary transfer unit */ vf610_nfc_set_field(nfc, NFC_FLASH_CONFIG, CONFIG_PAGE_CNT_MASK, @@ -686,6 +1081,7 @@ static int vf610_nfc_probe(struct platform_device *pdev) chip->read_word = vf610_nfc_read_word; chip->read_buf = vf610_nfc_read_buf; chip->write_buf = vf610_nfc_write_buf; + chip->exec_op = vf610_nfc_exec_op; chip->select_chip = vf610_nfc_select_chip; chip->onfi_set_features = nand_onfi_get_set_features_notsupp; chip->onfi_get_features = nand_onfi_get_set_features_notsupp; @@ -755,6 +1151,10 @@ static int vf610_nfc_probe(struct platform_device *pdev) chip->ecc.read_page = vf610_nfc_read_page; chip->ecc.write_page = vf610_nfc_write_page; + chip->ecc.read_page_raw = vf610_nfc_read_page_raw; + chip->ecc.write_page_raw = vf610_nfc_write_page_raw; + chip->ecc.read_oob = vf610_nfc_read_oob; + chip->ecc.write_oob = vf610_nfc_write_oob; chip->ecc.size = PAGE_2K; } From ecc40b8df59a13dc1c1abd8abe4361e4160d29ea Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Fri, 9 Mar 2018 15:50:37 +0100 Subject: [PATCH 40/89] mtd: rawnand: vf610_nfc: remove old hooks Now that the driver is using ->exec_op(), remove the old hooks. Signed-off-by: Stefan Agner Reviewed-by: Miquel Raynal Signed-off-by: Boris Brezillon --- drivers/mtd/nand/raw/vf610_nfc.c | 269 ------------------------------- 1 file changed, 269 deletions(-) diff --git a/drivers/mtd/nand/raw/vf610_nfc.c b/drivers/mtd/nand/raw/vf610_nfc.c index 15fcefaba43e..bbec33f178d5 100644 --- a/drivers/mtd/nand/raw/vf610_nfc.c +++ b/drivers/mtd/nand/raw/vf610_nfc.c @@ -60,21 +60,6 @@ #define OOB_64 0x0040 #define OOB_MAX 0x0100 -/* - * NFC_CMD2[CODE] values. See section: - * - 31.4.7 Flash Command Code Description, Vybrid manual - * - 23.8.6 Flash Command Sequencer, MPC5125 manual - * - * Briefly these are bitmasks of controller cycles. - */ -#define READ_PAGE_CMD_CODE 0x7EE0 -#define READ_ONFI_PARAM_CMD_CODE 0x4860 -#define PROGRAM_PAGE_CMD_CODE 0x7FC0 -#define ERASE_CMD_CODE 0x4EC0 -#define READ_ID_CMD_CODE 0x4804 -#define RESET_CMD_CODE 0x4040 -#define STATUS_READ_CMD_CODE 0x4068 - /* NFC_CMD2[CODE] controller cycle bit masks */ #define COMMAND_CMD_BYTE1 BIT(14) #define COMMAND_CAR_BYTE1 BIT(13) @@ -162,13 +147,6 @@ #define ECC_STATUS_MASK 0x80 #define ECC_STATUS_ERR_COUNT 0x3F -enum vf610_nfc_alt_buf { - ALT_BUF_DATA = 0, - ALT_BUF_ID = 1, - ALT_BUF_STAT = 2, - ALT_BUF_ONFI = 3, -}; - enum vf610_nfc_variant { NFC_VFC610 = 1, }; @@ -178,13 +156,9 @@ struct vf610_nfc { struct device *dev; void __iomem *regs; struct completion cmd_done; - uint buf_offset; - int write_sz; /* Status and ID are in alternate locations. */ - enum vf610_nfc_alt_buf alt_buf; enum vf610_nfc_variant variant; struct clk *clk; - bool use_hw_ecc; /* * Indicate that user data is accessed (full page/oob). This is * useful to indicate the driver whether to swap byte endianness. @@ -231,20 +205,6 @@ static inline void vf610_nfc_set_field(struct vf610_nfc *nfc, u32 reg, (vf610_nfc_read(nfc, reg) & (~mask)) | val << shift); } -static inline void vf610_nfc_memcpy(void *dst, const void __iomem *src, - size_t n) -{ - /* - * Use this accessor for the internal SRAM buffers. On the ARM - * Freescale Vybrid SoC it's known that the driver can treat - * the SRAM buffer as if it's memory. Other platform might need - * to treat the buffers differently. - * - * For the time being, use memcpy - */ - memcpy(dst, src, n); -} - static inline bool vf610_nfc_kernel_is_little_endian(void) { #ifdef __LITTLE_ENDIAN @@ -354,53 +314,6 @@ static void vf610_nfc_done(struct vf610_nfc *nfc) vf610_nfc_clear_status(nfc); } -static u8 vf610_nfc_get_id(struct vf610_nfc *nfc, int col) -{ - u32 flash_id; - - if (col < 4) { - flash_id = vf610_nfc_read(nfc, NFC_FLASH_STATUS1); - flash_id >>= (3 - col) * 8; - } else { - flash_id = vf610_nfc_read(nfc, NFC_FLASH_STATUS2); - flash_id >>= 24; - } - - return flash_id & 0xff; -} - -static u8 vf610_nfc_get_status(struct vf610_nfc *nfc) -{ - return vf610_nfc_read(nfc, NFC_FLASH_STATUS2) & STATUS_BYTE1_MASK; -} - -static void vf610_nfc_send_command(struct vf610_nfc *nfc, u32 cmd_byte1, - u32 cmd_code) -{ - u32 tmp; - - vf610_nfc_clear_status(nfc); - - tmp = vf610_nfc_read(nfc, NFC_FLASH_CMD2); - tmp &= ~(CMD_BYTE1_MASK | CMD_CODE_MASK | BUFNO_MASK); - tmp |= cmd_byte1 << CMD_BYTE1_SHIFT; - tmp |= cmd_code << CMD_CODE_SHIFT; - vf610_nfc_write(nfc, NFC_FLASH_CMD2, tmp); -} - -static void vf610_nfc_send_commands(struct vf610_nfc *nfc, u32 cmd_byte1, - u32 cmd_byte2, u32 cmd_code) -{ - u32 tmp; - - vf610_nfc_send_command(nfc, cmd_byte1, cmd_code); - - tmp = vf610_nfc_read(nfc, NFC_FLASH_CMD1); - tmp &= ~CMD_BYTE2_MASK; - tmp |= cmd_byte2 << CMD_BYTE2_SHIFT; - vf610_nfc_write(nfc, NFC_FLASH_CMD1, tmp); -} - static irqreturn_t vf610_nfc_irq(int irq, void *data) { struct mtd_info *mtd = data; @@ -412,19 +325,6 @@ static irqreturn_t vf610_nfc_irq(int irq, void *data) return IRQ_HANDLED; } -static void vf610_nfc_addr_cycle(struct vf610_nfc *nfc, int column, int page) -{ - if (column != -1) { - if (nfc->chip.options & NAND_BUSWIDTH_16) - column = column / 2; - vf610_nfc_set_field(nfc, NFC_COL_ADDR, COL_ADDR_MASK, - COL_ADDR_SHIFT, column); - } - if (page != -1) - vf610_nfc_set_field(nfc, NFC_ROW_ADDR, ROW_ADDR_MASK, - ROW_ADDR_SHIFT, page); -} - static inline void vf610_nfc_ecc_mode(struct vf610_nfc *nfc, int ecc_mode) { vf610_nfc_set_field(nfc, NFC_FLASH_CONFIG, @@ -437,169 +337,6 @@ static inline void vf610_nfc_transfer_size(struct vf610_nfc *nfc, int size) vf610_nfc_write(nfc, NFC_SECTOR_SIZE, size); } -static void vf610_nfc_command(struct mtd_info *mtd, unsigned command, - int column, int page) -{ - struct vf610_nfc *nfc = mtd_to_nfc(mtd); - int trfr_sz = nfc->chip.options & NAND_BUSWIDTH_16 ? 1 : 0; - - nfc->buf_offset = max(column, 0); - nfc->alt_buf = ALT_BUF_DATA; - - switch (command) { - case NAND_CMD_SEQIN: - /* Use valid column/page from preread... */ - vf610_nfc_addr_cycle(nfc, column, page); - nfc->buf_offset = 0; - - /* - * SEQIN => data => PAGEPROG sequence is done by the controller - * hence we do not need to issue the command here... - */ - return; - case NAND_CMD_PAGEPROG: - trfr_sz += nfc->write_sz; - vf610_nfc_transfer_size(nfc, trfr_sz); - vf610_nfc_send_commands(nfc, NAND_CMD_SEQIN, - command, PROGRAM_PAGE_CMD_CODE); - if (nfc->use_hw_ecc) - vf610_nfc_ecc_mode(nfc, nfc->ecc_mode); - else - vf610_nfc_ecc_mode(nfc, ECC_BYPASS); - break; - - case NAND_CMD_RESET: - vf610_nfc_transfer_size(nfc, 0); - vf610_nfc_send_command(nfc, command, RESET_CMD_CODE); - break; - - case NAND_CMD_READOOB: - trfr_sz += mtd->oobsize; - column = mtd->writesize; - vf610_nfc_transfer_size(nfc, trfr_sz); - vf610_nfc_send_commands(nfc, NAND_CMD_READ0, - NAND_CMD_READSTART, READ_PAGE_CMD_CODE); - vf610_nfc_addr_cycle(nfc, column, page); - vf610_nfc_ecc_mode(nfc, ECC_BYPASS); - break; - - case NAND_CMD_READ0: - trfr_sz += mtd->writesize + mtd->oobsize; - vf610_nfc_transfer_size(nfc, trfr_sz); - vf610_nfc_send_commands(nfc, NAND_CMD_READ0, - NAND_CMD_READSTART, READ_PAGE_CMD_CODE); - vf610_nfc_addr_cycle(nfc, column, page); - vf610_nfc_ecc_mode(nfc, nfc->ecc_mode); - break; - - case NAND_CMD_PARAM: - nfc->alt_buf = ALT_BUF_ONFI; - trfr_sz = 3 * sizeof(struct nand_onfi_params); - vf610_nfc_transfer_size(nfc, trfr_sz); - vf610_nfc_send_command(nfc, command, READ_ONFI_PARAM_CMD_CODE); - vf610_nfc_addr_cycle(nfc, -1, column); - vf610_nfc_ecc_mode(nfc, ECC_BYPASS); - break; - - case NAND_CMD_ERASE1: - vf610_nfc_transfer_size(nfc, 0); - vf610_nfc_send_commands(nfc, command, - NAND_CMD_ERASE2, ERASE_CMD_CODE); - vf610_nfc_addr_cycle(nfc, column, page); - break; - - case NAND_CMD_READID: - nfc->alt_buf = ALT_BUF_ID; - nfc->buf_offset = 0; - vf610_nfc_transfer_size(nfc, 0); - vf610_nfc_send_command(nfc, command, READ_ID_CMD_CODE); - vf610_nfc_addr_cycle(nfc, -1, column); - break; - - case NAND_CMD_STATUS: - nfc->alt_buf = ALT_BUF_STAT; - vf610_nfc_transfer_size(nfc, 0); - vf610_nfc_send_command(nfc, command, STATUS_READ_CMD_CODE); - break; - default: - return; - } - - vf610_nfc_done(nfc); - - nfc->use_hw_ecc = false; - nfc->write_sz = 0; -} - -static void vf610_nfc_read_buf(struct mtd_info *mtd, u_char *buf, int len) -{ - struct vf610_nfc *nfc = mtd_to_nfc(mtd); - uint c = nfc->buf_offset; - - /* Alternate buffers are only supported through read_byte */ - WARN_ON(nfc->alt_buf); - - vf610_nfc_memcpy(buf, nfc->regs + NFC_MAIN_AREA(0) + c, len); - - nfc->buf_offset += len; -} - -static void vf610_nfc_write_buf(struct mtd_info *mtd, const uint8_t *buf, - int len) -{ - struct vf610_nfc *nfc = mtd_to_nfc(mtd); - uint c = nfc->buf_offset; - uint l; - - l = min_t(uint, len, mtd->writesize + mtd->oobsize - c); - vf610_nfc_memcpy(nfc->regs + NFC_MAIN_AREA(0) + c, buf, l); - - nfc->write_sz += l; - nfc->buf_offset += l; -} - -static uint8_t vf610_nfc_read_byte(struct mtd_info *mtd) -{ - struct vf610_nfc *nfc = mtd_to_nfc(mtd); - u8 tmp; - uint c = nfc->buf_offset; - - switch (nfc->alt_buf) { - case ALT_BUF_ID: - tmp = vf610_nfc_get_id(nfc, c); - break; - case ALT_BUF_STAT: - tmp = vf610_nfc_get_status(nfc); - break; -#ifdef __LITTLE_ENDIAN - case ALT_BUF_ONFI: - /* Reverse byte since the controller uses big endianness */ - c = nfc->buf_offset ^ 0x3; - /* fall-through */ -#endif - default: - tmp = *((u8 *)(nfc->regs + NFC_MAIN_AREA(0) + c)); - break; - } - nfc->buf_offset++; - return tmp; -} - -static u16 vf610_nfc_read_word(struct mtd_info *mtd) -{ - u16 tmp; - - vf610_nfc_read_buf(mtd, (u_char *)&tmp, sizeof(tmp)); - return tmp; -} - -/* If not provided, upper layers apply a fixed delay. */ -static int vf610_nfc_dev_ready(struct mtd_info *mtd) -{ - /* NFC handles R/B internally; always ready. */ - return 1; -} - static inline void vf610_nfc_run(struct vf610_nfc *nfc, u32 col, u32 row, u32 cmd1, u32 cmd2, u32 trfr_sz) { @@ -1075,12 +812,6 @@ static int vf610_nfc_probe(struct platform_device *pdev) goto err_disable_clk; } - chip->dev_ready = vf610_nfc_dev_ready; - chip->cmdfunc = vf610_nfc_command; - chip->read_byte = vf610_nfc_read_byte; - chip->read_word = vf610_nfc_read_word; - chip->read_buf = vf610_nfc_read_buf; - chip->write_buf = vf610_nfc_write_buf; chip->exec_op = vf610_nfc_exec_op; chip->select_chip = vf610_nfc_select_chip; chip->onfi_set_features = nand_onfi_get_set_features_notsupp; From a722932a5af92189af45216e642bf9eb8f5fb883 Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Fri, 9 Mar 2018 15:50:38 +0100 Subject: [PATCH 41/89] mtd: rawnand: vf610_nfc: support ONFI SET/GET_FEATURES commands With the move to ->exec_op() the driver should now support ONFI SET/GET_FEATURES commands. Signed-off-by: Stefan Agner Reviewed-by: Miquel Raynal Signed-off-by: Boris Brezillon --- drivers/mtd/nand/raw/vf610_nfc.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/mtd/nand/raw/vf610_nfc.c b/drivers/mtd/nand/raw/vf610_nfc.c index bbec33f178d5..7872a9ed3df8 100644 --- a/drivers/mtd/nand/raw/vf610_nfc.c +++ b/drivers/mtd/nand/raw/vf610_nfc.c @@ -814,8 +814,6 @@ static int vf610_nfc_probe(struct platform_device *pdev) chip->exec_op = vf610_nfc_exec_op; chip->select_chip = vf610_nfc_select_chip; - chip->onfi_set_features = nand_onfi_get_set_features_notsupp; - chip->onfi_get_features = nand_onfi_get_set_features_notsupp; chip->options |= NAND_NO_SUBPAGE_WRITE; From 00324da71e660702dd59abaaf9a5fcfe9d4baf93 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 14 Mar 2018 17:30:23 +0100 Subject: [PATCH 42/89] mtd: rawnand: remove bf5xx_nand driver The blackfin architecture is getting removed, so this driver has become obsolete. Signed-off-by: Arnd Bergmann Signed-off-by: Boris Brezillon --- drivers/mtd/nand/raw/Kconfig | 32 -- drivers/mtd/nand/raw/Makefile | 1 - drivers/mtd/nand/raw/bf5xx_nand.c | 861 ------------------------------ 3 files changed, 894 deletions(-) delete mode 100644 drivers/mtd/nand/raw/bf5xx_nand.c diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig index 2c6ecb7ae753..9b1918af0064 100644 --- a/drivers/mtd/nand/raw/Kconfig +++ b/drivers/mtd/nand/raw/Kconfig @@ -116,38 +116,6 @@ config MTD_NAND_AU1550 This enables the driver for the NAND flash controller on the AMD/Alchemy 1550 SOC. -config MTD_NAND_BF5XX - tristate "Blackfin on-chip NAND Flash Controller driver" - depends on BF54x || BF52x - help - This enables the Blackfin on-chip NAND flash controller - - No board specific support is done by this driver, each board - must advertise a platform_device for the driver to attach. - - This driver can also be built as a module. If so, the module - will be called bf5xx-nand. - -config MTD_NAND_BF5XX_HWECC - bool "BF5XX NAND Hardware ECC" - default y - depends on MTD_NAND_BF5XX - help - Enable the use of the BF5XX's internal ECC generator when - using NAND. - -config MTD_NAND_BF5XX_BOOTROM_ECC - bool "Use Blackfin BootROM ECC Layout" - default n - depends on MTD_NAND_BF5XX_HWECC - help - If you wish to modify NAND pages and allow the Blackfin on-chip - BootROM to boot from them, say Y here. This is only necessary - if you are booting U-Boot out of NAND and you wish to update - U-Boot from Linux' userspace. Otherwise, you should say N here. - - If unsure, say N. - config MTD_NAND_S3C2410 tristate "NAND Flash support for Samsung S3C SoCs" depends on ARCH_S3C24XX || ARCH_S3C64XX diff --git a/drivers/mtd/nand/raw/Makefile b/drivers/mtd/nand/raw/Makefile index f16f59a197a3..165b7ef9e9a1 100644 --- a/drivers/mtd/nand/raw/Makefile +++ b/drivers/mtd/nand/raw/Makefile @@ -11,7 +11,6 @@ obj-$(CONFIG_MTD_NAND_DENALI) += denali.o obj-$(CONFIG_MTD_NAND_DENALI_PCI) += denali_pci.o obj-$(CONFIG_MTD_NAND_DENALI_DT) += denali_dt.o obj-$(CONFIG_MTD_NAND_AU1550) += au1550nd.o -obj-$(CONFIG_MTD_NAND_BF5XX) += bf5xx_nand.o obj-$(CONFIG_MTD_NAND_S3C2410) += s3c2410.o obj-$(CONFIG_MTD_NAND_TANGO) += tango_nand.o obj-$(CONFIG_MTD_NAND_DAVINCI) += davinci_nand.o diff --git a/drivers/mtd/nand/raw/bf5xx_nand.c b/drivers/mtd/nand/raw/bf5xx_nand.c deleted file mode 100644 index 9a1d8d104570..000000000000 --- a/drivers/mtd/nand/raw/bf5xx_nand.c +++ /dev/null @@ -1,861 +0,0 @@ -/* - * Copyright 2006-2008 Analog Devices Inc. - * http://blackfin.uclinux.org/ - * Bryan Wu - * - * Blackfin BF5xx on-chip NAND flash controller driver - * - * Derived from s3c2410.c - * Copyright (c) 2007 Ben Dooks - * - * Derived from cafe.c - * Copyright © 2006 Red Hat, Inc. - * Copyright © 2006 David Woodhouse - * - * Changelog: - * 12-Jun-2007 Bryan Wu: Initial version - * 18-Jul-2007 Bryan Wu: - * - ECC_HW and ECC_SW supported - * - DMA supported in ECC_HW - * - YAFFS tested as rootfs in both ECC_HW and ECC_SW - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#define DRV_NAME "bf5xx-nand" -#define DRV_VERSION "1.2" -#define DRV_AUTHOR "Bryan Wu " -#define DRV_DESC "BF5xx on-chip NAND FLash Controller Driver" - -/* NFC_STAT Masks */ -#define NBUSY 0x01 /* Not Busy */ -#define WB_FULL 0x02 /* Write Buffer Full */ -#define PG_WR_STAT 0x04 /* Page Write Pending */ -#define PG_RD_STAT 0x08 /* Page Read Pending */ -#define WB_EMPTY 0x10 /* Write Buffer Empty */ - -/* NFC_IRQSTAT Masks */ -#define NBUSYIRQ 0x01 /* Not Busy IRQ */ -#define WB_OVF 0x02 /* Write Buffer Overflow */ -#define WB_EDGE 0x04 /* Write Buffer Edge Detect */ -#define RD_RDY 0x08 /* Read Data Ready */ -#define WR_DONE 0x10 /* Page Write Done */ - -/* NFC_RST Masks */ -#define ECC_RST 0x01 /* ECC (and NFC counters) Reset */ - -/* NFC_PGCTL Masks */ -#define PG_RD_START 0x01 /* Page Read Start */ -#define PG_WR_START 0x02 /* Page Write Start */ - -#ifdef CONFIG_MTD_NAND_BF5XX_HWECC -static int hardware_ecc = 1; -#else -static int hardware_ecc; -#endif - -static const unsigned short bfin_nfc_pin_req[] = - {P_NAND_CE, - P_NAND_RB, - P_NAND_D0, - P_NAND_D1, - P_NAND_D2, - P_NAND_D3, - P_NAND_D4, - P_NAND_D5, - P_NAND_D6, - P_NAND_D7, - P_NAND_WE, - P_NAND_RE, - P_NAND_CLE, - P_NAND_ALE, - 0}; - -#ifdef CONFIG_MTD_NAND_BF5XX_BOOTROM_ECC -static int bootrom_ooblayout_ecc(struct mtd_info *mtd, int section, - struct mtd_oob_region *oobregion) -{ - if (section > 7) - return -ERANGE; - - oobregion->offset = section * 8; - oobregion->length = 3; - - return 0; -} - -static int bootrom_ooblayout_free(struct mtd_info *mtd, int section, - struct mtd_oob_region *oobregion) -{ - if (section > 7) - return -ERANGE; - - oobregion->offset = (section * 8) + 3; - oobregion->length = 5; - - return 0; -} - -static const struct mtd_ooblayout_ops bootrom_ooblayout_ops = { - .ecc = bootrom_ooblayout_ecc, - .free = bootrom_ooblayout_free, -}; -#endif - -/* - * Data structures for bf5xx nand flash controller driver - */ - -/* bf5xx nand info */ -struct bf5xx_nand_info { - /* mtd info */ - struct nand_hw_control controller; - struct nand_chip chip; - - /* platform info */ - struct bf5xx_nand_platform *platform; - - /* device info */ - struct device *device; - - /* DMA stuff */ - struct completion dma_completion; -}; - -/* - * Conversion functions - */ -static struct bf5xx_nand_info *mtd_to_nand_info(struct mtd_info *mtd) -{ - return container_of(mtd_to_nand(mtd), struct bf5xx_nand_info, - chip); -} - -static struct bf5xx_nand_info *to_nand_info(struct platform_device *pdev) -{ - return platform_get_drvdata(pdev); -} - -static struct bf5xx_nand_platform *to_nand_plat(struct platform_device *pdev) -{ - return dev_get_platdata(&pdev->dev); -} - -/* - * struct nand_chip interface function pointers - */ - -/* - * bf5xx_nand_hwcontrol - * - * Issue command and address cycles to the chip - */ -static void bf5xx_nand_hwcontrol(struct mtd_info *mtd, int cmd, - unsigned int ctrl) -{ - if (cmd == NAND_CMD_NONE) - return; - - while (bfin_read_NFC_STAT() & WB_FULL) - cpu_relax(); - - if (ctrl & NAND_CLE) - bfin_write_NFC_CMD(cmd); - else if (ctrl & NAND_ALE) - bfin_write_NFC_ADDR(cmd); - SSYNC(); -} - -/* - * bf5xx_nand_devready() - * - * returns 0 if the nand is busy, 1 if it is ready - */ -static int bf5xx_nand_devready(struct mtd_info *mtd) -{ - unsigned short val = bfin_read_NFC_STAT(); - - if ((val & NBUSY) == NBUSY) - return 1; - else - return 0; -} - -/* - * ECC functions - * These allow the bf5xx to use the controller's ECC - * generator block to ECC the data as it passes through - */ - -/* - * ECC error correction function - */ -static int bf5xx_nand_correct_data_256(struct mtd_info *mtd, u_char *dat, - u_char *read_ecc, u_char *calc_ecc) -{ - struct bf5xx_nand_info *info = mtd_to_nand_info(mtd); - u32 syndrome[5]; - u32 calced, stored; - int i; - unsigned short failing_bit, failing_byte; - u_char data; - - calced = calc_ecc[0] | (calc_ecc[1] << 8) | (calc_ecc[2] << 16); - stored = read_ecc[0] | (read_ecc[1] << 8) | (read_ecc[2] << 16); - - syndrome[0] = (calced ^ stored); - - /* - * syndrome 0: all zero - * No error in data - * No action - */ - if (!syndrome[0] || !calced || !stored) - return 0; - - /* - * sysdrome 0: only one bit is one - * ECC data was incorrect - * No action - */ - if (hweight32(syndrome[0]) == 1) { - dev_err(info->device, "ECC data was incorrect!\n"); - return -EBADMSG; - } - - syndrome[1] = (calced & 0x7FF) ^ (stored & 0x7FF); - syndrome[2] = (calced & 0x7FF) ^ ((calced >> 11) & 0x7FF); - syndrome[3] = (stored & 0x7FF) ^ ((stored >> 11) & 0x7FF); - syndrome[4] = syndrome[2] ^ syndrome[3]; - - for (i = 0; i < 5; i++) - dev_info(info->device, "syndrome[%d] 0x%08x\n", i, syndrome[i]); - - dev_info(info->device, - "calced[0x%08x], stored[0x%08x]\n", - calced, stored); - - /* - * sysdrome 0: exactly 11 bits are one, each parity - * and parity' pair is 1 & 0 or 0 & 1. - * 1-bit correctable error - * Correct the error - */ - if (hweight32(syndrome[0]) == 11 && syndrome[4] == 0x7FF) { - dev_info(info->device, - "1-bit correctable error, correct it.\n"); - dev_info(info->device, - "syndrome[1] 0x%08x\n", syndrome[1]); - - failing_bit = syndrome[1] & 0x7; - failing_byte = syndrome[1] >> 0x3; - data = *(dat + failing_byte); - data = data ^ (0x1 << failing_bit); - *(dat + failing_byte) = data; - - return 1; - } - - /* - * sysdrome 0: random data - * More than 1-bit error, non-correctable error - * Discard data, mark bad block - */ - dev_err(info->device, - "More than 1-bit error, non-correctable error.\n"); - dev_err(info->device, - "Please discard data, mark bad block\n"); - - return -EBADMSG; -} - -static int bf5xx_nand_correct_data(struct mtd_info *mtd, u_char *dat, - u_char *read_ecc, u_char *calc_ecc) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - int ret, bitflips = 0; - - ret = bf5xx_nand_correct_data_256(mtd, dat, read_ecc, calc_ecc); - if (ret < 0) - return ret; - - bitflips = ret; - - /* If ecc size is 512, correct second 256 bytes */ - if (chip->ecc.size == 512) { - dat += 256; - read_ecc += 3; - calc_ecc += 3; - ret = bf5xx_nand_correct_data_256(mtd, dat, read_ecc, calc_ecc); - if (ret < 0) - return ret; - - bitflips += ret; - } - - return bitflips; -} - -static void bf5xx_nand_enable_hwecc(struct mtd_info *mtd, int mode) -{ - return; -} - -static int bf5xx_nand_calculate_ecc(struct mtd_info *mtd, - const u_char *dat, u_char *ecc_code) -{ - struct bf5xx_nand_info *info = mtd_to_nand_info(mtd); - struct nand_chip *chip = mtd_to_nand(mtd); - u16 ecc0, ecc1; - u32 code[2]; - u8 *p; - - /* first 3 bytes ECC code for 256 page size */ - ecc0 = bfin_read_NFC_ECC0(); - ecc1 = bfin_read_NFC_ECC1(); - - code[0] = (ecc0 & 0x7ff) | ((ecc1 & 0x7ff) << 11); - - dev_dbg(info->device, "returning ecc 0x%08x\n", code[0]); - - p = (u8 *) code; - memcpy(ecc_code, p, 3); - - /* second 3 bytes ECC code for 512 ecc size */ - if (chip->ecc.size == 512) { - ecc0 = bfin_read_NFC_ECC2(); - ecc1 = bfin_read_NFC_ECC3(); - code[1] = (ecc0 & 0x7ff) | ((ecc1 & 0x7ff) << 11); - - /* second 3 bytes in ecc_code for second 256 - * bytes of 512 page size - */ - p = (u8 *) (code + 1); - memcpy((ecc_code + 3), p, 3); - dev_dbg(info->device, "returning ecc 0x%08x\n", code[1]); - } - - return 0; -} - -/* - * PIO mode for buffer writing and reading - */ -static void bf5xx_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) -{ - int i; - unsigned short val; - - /* - * Data reads are requested by first writing to NFC_DATA_RD - * and then reading back from NFC_READ. - */ - for (i = 0; i < len; i++) { - while (bfin_read_NFC_STAT() & WB_FULL) - cpu_relax(); - - /* Contents do not matter */ - bfin_write_NFC_DATA_RD(0x0000); - SSYNC(); - - while ((bfin_read_NFC_IRQSTAT() & RD_RDY) != RD_RDY) - cpu_relax(); - - buf[i] = bfin_read_NFC_READ(); - - val = bfin_read_NFC_IRQSTAT(); - val |= RD_RDY; - bfin_write_NFC_IRQSTAT(val); - SSYNC(); - } -} - -static uint8_t bf5xx_nand_read_byte(struct mtd_info *mtd) -{ - uint8_t val; - - bf5xx_nand_read_buf(mtd, &val, 1); - - return val; -} - -static void bf5xx_nand_write_buf(struct mtd_info *mtd, - const uint8_t *buf, int len) -{ - int i; - - for (i = 0; i < len; i++) { - while (bfin_read_NFC_STAT() & WB_FULL) - cpu_relax(); - - bfin_write_NFC_DATA_WR(buf[i]); - SSYNC(); - } -} - -static void bf5xx_nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len) -{ - int i; - u16 *p = (u16 *) buf; - len >>= 1; - - /* - * Data reads are requested by first writing to NFC_DATA_RD - * and then reading back from NFC_READ. - */ - bfin_write_NFC_DATA_RD(0x5555); - - SSYNC(); - - for (i = 0; i < len; i++) - p[i] = bfin_read_NFC_READ(); -} - -static void bf5xx_nand_write_buf16(struct mtd_info *mtd, - const uint8_t *buf, int len) -{ - int i; - u16 *p = (u16 *) buf; - len >>= 1; - - for (i = 0; i < len; i++) - bfin_write_NFC_DATA_WR(p[i]); - - SSYNC(); -} - -/* - * DMA functions for buffer writing and reading - */ -static irqreturn_t bf5xx_nand_dma_irq(int irq, void *dev_id) -{ - struct bf5xx_nand_info *info = dev_id; - - clear_dma_irqstat(CH_NFC); - disable_dma(CH_NFC); - complete(&info->dma_completion); - - return IRQ_HANDLED; -} - -static void bf5xx_nand_dma_rw(struct mtd_info *mtd, - uint8_t *buf, int is_read) -{ - struct bf5xx_nand_info *info = mtd_to_nand_info(mtd); - struct nand_chip *chip = mtd_to_nand(mtd); - unsigned short val; - - dev_dbg(info->device, " mtd->%p, buf->%p, is_read %d\n", - mtd, buf, is_read); - - /* - * Before starting a dma transfer, be sure to invalidate/flush - * the cache over the address range of your DMA buffer to - * prevent cache coherency problems. Otherwise very subtle bugs - * can be introduced to your driver. - */ - if (is_read) - invalidate_dcache_range((unsigned int)buf, - (unsigned int)(buf + chip->ecc.size)); - else - flush_dcache_range((unsigned int)buf, - (unsigned int)(buf + chip->ecc.size)); - - /* - * This register must be written before each page is - * transferred to generate the correct ECC register - * values. - */ - bfin_write_NFC_RST(ECC_RST); - SSYNC(); - while (bfin_read_NFC_RST() & ECC_RST) - cpu_relax(); - - disable_dma(CH_NFC); - clear_dma_irqstat(CH_NFC); - - /* setup DMA register with Blackfin DMA API */ - set_dma_config(CH_NFC, 0x0); - set_dma_start_addr(CH_NFC, (unsigned long) buf); - - /* The DMAs have different size on BF52x and BF54x */ -#ifdef CONFIG_BF52x - set_dma_x_count(CH_NFC, (chip->ecc.size >> 1)); - set_dma_x_modify(CH_NFC, 2); - val = DI_EN | WDSIZE_16; -#endif - -#ifdef CONFIG_BF54x - set_dma_x_count(CH_NFC, (chip->ecc.size >> 2)); - set_dma_x_modify(CH_NFC, 4); - val = DI_EN | WDSIZE_32; -#endif - /* setup write or read operation */ - if (is_read) - val |= WNR; - set_dma_config(CH_NFC, val); - enable_dma(CH_NFC); - - /* Start PAGE read/write operation */ - if (is_read) - bfin_write_NFC_PGCTL(PG_RD_START); - else - bfin_write_NFC_PGCTL(PG_WR_START); - wait_for_completion(&info->dma_completion); -} - -static void bf5xx_nand_dma_read_buf(struct mtd_info *mtd, - uint8_t *buf, int len) -{ - struct bf5xx_nand_info *info = mtd_to_nand_info(mtd); - struct nand_chip *chip = mtd_to_nand(mtd); - - dev_dbg(info->device, "mtd->%p, buf->%p, int %d\n", mtd, buf, len); - - if (len == chip->ecc.size) - bf5xx_nand_dma_rw(mtd, buf, 1); - else - bf5xx_nand_read_buf(mtd, buf, len); -} - -static void bf5xx_nand_dma_write_buf(struct mtd_info *mtd, - const uint8_t *buf, int len) -{ - struct bf5xx_nand_info *info = mtd_to_nand_info(mtd); - struct nand_chip *chip = mtd_to_nand(mtd); - - dev_dbg(info->device, "mtd->%p, buf->%p, len %d\n", mtd, buf, len); - - if (len == chip->ecc.size) - bf5xx_nand_dma_rw(mtd, (uint8_t *)buf, 0); - else - bf5xx_nand_write_buf(mtd, buf, len); -} - -static int bf5xx_nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf, int oob_required, int page) -{ - nand_read_page_op(chip, page, 0, NULL, 0); - - bf5xx_nand_read_buf(mtd, buf, mtd->writesize); - bf5xx_nand_read_buf(mtd, chip->oob_poi, mtd->oobsize); - - return 0; -} - -static int bf5xx_nand_write_page_raw(struct mtd_info *mtd, - struct nand_chip *chip, const uint8_t *buf, int oob_required, - int page) -{ - nand_prog_page_begin_op(chip, page, 0, buf, mtd->writesize); - bf5xx_nand_write_buf(mtd, chip->oob_poi, mtd->oobsize); - - return nand_prog_page_end_op(chip); -} - -/* - * System initialization functions - */ -static int bf5xx_nand_dma_init(struct bf5xx_nand_info *info) -{ - int ret; - - /* Do not use dma */ - if (!hardware_ecc) - return 0; - - init_completion(&info->dma_completion); - - /* Request NFC DMA channel */ - ret = request_dma(CH_NFC, "BF5XX NFC driver"); - if (ret < 0) { - dev_err(info->device, " unable to get DMA channel\n"); - return ret; - } - -#ifdef CONFIG_BF54x - /* Setup DMAC1 channel mux for NFC which shared with SDH */ - bfin_write_DMAC1_PERIMUX(bfin_read_DMAC1_PERIMUX() & ~1); - SSYNC(); -#endif - - set_dma_callback(CH_NFC, bf5xx_nand_dma_irq, info); - - /* Turn off the DMA channel first */ - disable_dma(CH_NFC); - return 0; -} - -static void bf5xx_nand_dma_remove(struct bf5xx_nand_info *info) -{ - /* Free NFC DMA channel */ - if (hardware_ecc) - free_dma(CH_NFC); -} - -/* - * BF5XX NFC hardware initialization - * - pin mux setup - * - clear interrupt status - */ -static int bf5xx_nand_hw_init(struct bf5xx_nand_info *info) -{ - int err = 0; - unsigned short val; - struct bf5xx_nand_platform *plat = info->platform; - - /* setup NFC_CTL register */ - dev_info(info->device, - "data_width=%d, wr_dly=%d, rd_dly=%d\n", - (plat->data_width ? 16 : 8), - plat->wr_dly, plat->rd_dly); - - val = (1 << NFC_PG_SIZE_OFFSET) | - (plat->data_width << NFC_NWIDTH_OFFSET) | - (plat->rd_dly << NFC_RDDLY_OFFSET) | - (plat->wr_dly << NFC_WRDLY_OFFSET); - dev_dbg(info->device, "NFC_CTL is 0x%04x\n", val); - - bfin_write_NFC_CTL(val); - SSYNC(); - - /* clear interrupt status */ - bfin_write_NFC_IRQMASK(0x0); - SSYNC(); - val = bfin_read_NFC_IRQSTAT(); - bfin_write_NFC_IRQSTAT(val); - SSYNC(); - - /* DMA initialization */ - if (bf5xx_nand_dma_init(info)) - err = -ENXIO; - - return err; -} - -/* - * Device management interface - */ -static int bf5xx_nand_add_partition(struct bf5xx_nand_info *info) -{ - struct mtd_info *mtd = nand_to_mtd(&info->chip); - struct mtd_partition *parts = info->platform->partitions; - int nr = info->platform->nr_partitions; - - return mtd_device_register(mtd, parts, nr); -} - -static int bf5xx_nand_remove(struct platform_device *pdev) -{ - struct bf5xx_nand_info *info = to_nand_info(pdev); - - /* first thing we need to do is release all our mtds - * and their partitions, then go through freeing the - * resources used - */ - nand_release(nand_to_mtd(&info->chip)); - - peripheral_free_list(bfin_nfc_pin_req); - bf5xx_nand_dma_remove(info); - - return 0; -} - -static int bf5xx_nand_scan(struct mtd_info *mtd) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - int ret; - - ret = nand_scan_ident(mtd, 1, NULL); - if (ret) - return ret; - - if (hardware_ecc) { - /* - * for nand with page size > 512B, think it as several sections with 512B - */ - if (likely(mtd->writesize >= 512)) { - chip->ecc.size = 512; - chip->ecc.bytes = 6; - chip->ecc.strength = 2; - } else { - chip->ecc.size = 256; - chip->ecc.bytes = 3; - chip->ecc.strength = 1; - bfin_write_NFC_CTL(bfin_read_NFC_CTL() & ~(1 << NFC_PG_SIZE_OFFSET)); - SSYNC(); - } - } - - return nand_scan_tail(mtd); -} - -/* - * bf5xx_nand_probe - * - * called by device layer when it finds a device matching - * one our driver can handled. This code checks to see if - * it can allocate all necessary resources then calls the - * nand layer to look for devices - */ -static int bf5xx_nand_probe(struct platform_device *pdev) -{ - struct bf5xx_nand_platform *plat = to_nand_plat(pdev); - struct bf5xx_nand_info *info = NULL; - struct nand_chip *chip = NULL; - struct mtd_info *mtd = NULL; - int err = 0; - - dev_dbg(&pdev->dev, "(%p)\n", pdev); - - if (!plat) { - dev_err(&pdev->dev, "no platform specific information\n"); - return -EINVAL; - } - - if (peripheral_request_list(bfin_nfc_pin_req, DRV_NAME)) { - dev_err(&pdev->dev, "requesting Peripherals failed\n"); - return -EFAULT; - } - - info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); - if (info == NULL) { - err = -ENOMEM; - goto out_err; - } - - platform_set_drvdata(pdev, info); - - nand_hw_control_init(&info->controller); - - info->device = &pdev->dev; - info->platform = plat; - - /* initialise chip data struct */ - chip = &info->chip; - mtd = nand_to_mtd(&info->chip); - - if (plat->data_width) - chip->options |= NAND_BUSWIDTH_16; - - chip->options |= NAND_CACHEPRG | NAND_SKIP_BBTSCAN; - - chip->read_buf = (plat->data_width) ? - bf5xx_nand_read_buf16 : bf5xx_nand_read_buf; - chip->write_buf = (plat->data_width) ? - bf5xx_nand_write_buf16 : bf5xx_nand_write_buf; - - chip->read_byte = bf5xx_nand_read_byte; - - chip->cmd_ctrl = bf5xx_nand_hwcontrol; - chip->dev_ready = bf5xx_nand_devready; - - nand_set_controller_data(chip, mtd); - chip->controller = &info->controller; - - chip->IO_ADDR_R = (void __iomem *) NFC_READ; - chip->IO_ADDR_W = (void __iomem *) NFC_DATA_WR; - - chip->chip_delay = 0; - - /* initialise mtd info data struct */ - mtd->dev.parent = &pdev->dev; - - /* initialise the hardware */ - err = bf5xx_nand_hw_init(info); - if (err) - goto out_err; - - /* setup hardware ECC data struct */ - if (hardware_ecc) { -#ifdef CONFIG_MTD_NAND_BF5XX_BOOTROM_ECC - mtd_set_ooblayout(mtd, &bootrom_ooblayout_ops); -#endif - chip->read_buf = bf5xx_nand_dma_read_buf; - chip->write_buf = bf5xx_nand_dma_write_buf; - chip->ecc.calculate = bf5xx_nand_calculate_ecc; - chip->ecc.correct = bf5xx_nand_correct_data; - chip->ecc.mode = NAND_ECC_HW; - chip->ecc.hwctl = bf5xx_nand_enable_hwecc; - chip->ecc.read_page_raw = bf5xx_nand_read_page_raw; - chip->ecc.write_page_raw = bf5xx_nand_write_page_raw; - } else { - chip->ecc.mode = NAND_ECC_SOFT; - chip->ecc.algo = NAND_ECC_HAMMING; - } - - /* scan hardware nand chip and setup mtd info data struct */ - if (bf5xx_nand_scan(mtd)) { - err = -ENXIO; - goto out_err_nand_scan; - } - -#ifdef CONFIG_MTD_NAND_BF5XX_BOOTROM_ECC - chip->badblockpos = 63; -#endif - - /* add NAND partition */ - bf5xx_nand_add_partition(info); - - dev_dbg(&pdev->dev, "initialised ok\n"); - return 0; - -out_err_nand_scan: - bf5xx_nand_dma_remove(info); -out_err: - peripheral_free_list(bfin_nfc_pin_req); - - return err; -} - -/* driver device registration */ -static struct platform_driver bf5xx_nand_driver = { - .probe = bf5xx_nand_probe, - .remove = bf5xx_nand_remove, - .driver = { - .name = DRV_NAME, - }, -}; - -module_platform_driver(bf5xx_nand_driver); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR(DRV_AUTHOR); -MODULE_DESCRIPTION(DRV_DESC); -MODULE_ALIAS("platform:" DRV_NAME); From daf9a874c9cf0dd379195362f3bd8ef8280d82cb Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Mon, 19 Mar 2018 10:21:58 +0100 Subject: [PATCH 43/89] mtd: rawnand: makes the Kconfig entry clear when it comes to raw NANDs Files have been moved in the NAND subsystem to reflect the different flavors of NAND devices. Raw/Parallel NAND devices have been moved to a "raw" subdirectory to make the difference with OneNAND and SPI NAND for instance. So adjust the Kconfig entry to clarify things. Signed-off-by: Miquel Raynal Signed-off-by: Boris Brezillon --- drivers/mtd/nand/raw/Kconfig | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig index 9b1918af0064..46b29d277804 100644 --- a/drivers/mtd/nand/raw/Kconfig +++ b/drivers/mtd/nand/raw/Kconfig @@ -11,12 +11,12 @@ config MTD_NAND_ECC_SMC menuconfig MTD_NAND - tristate "NAND Device Support" + tristate "Raw/Parallel NAND Device Support" depends on MTD select MTD_NAND_ECC help - This enables support for accessing all type of NAND flash - devices. For further information see + This enables support for accessing all type of raw/parallel + NAND flash devices. For further information see . if MTD_NAND From fc2f30a4b411b9e8e19c158840598a19b768bf11 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Mon, 19 Mar 2018 14:47:18 +0100 Subject: [PATCH 44/89] mtd: rawnand: rename default ->onfi_get/set_features() implementations Prepare future work on the ->onfi_get/set_features() hooks by renaming the core's implementation as 'default' ones. Signed-off-by: Miquel Raynal Signed-off-by: Boris Brezillon --- drivers/mtd/nand/raw/nand_base.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c index e70ca16a5118..d1d5e2281860 100644 --- a/drivers/mtd/nand/raw/nand_base.c +++ b/drivers/mtd/nand/raw/nand_base.c @@ -4769,14 +4769,15 @@ static int nand_max_bad_blocks(struct mtd_info *mtd, loff_t ofs, size_t len) } /** - * nand_onfi_set_features- [REPLACEABLE] set features for ONFI nand + * nand_default_onfi_set_features- [REPLACEABLE] set features for ONFI nand * @mtd: MTD device structure * @chip: nand chip info structure * @addr: feature address. * @subfeature_param: the subfeature parameters, a four bytes array. */ -static int nand_onfi_set_features(struct mtd_info *mtd, struct nand_chip *chip, - int addr, uint8_t *subfeature_param) +static int nand_default_onfi_set_features(struct mtd_info *mtd, + struct nand_chip *chip, int addr, + uint8_t *subfeature_param) { if (!chip->onfi_version || !(le16_to_cpu(chip->onfi_params.opt_cmd) @@ -4787,14 +4788,15 @@ static int nand_onfi_set_features(struct mtd_info *mtd, struct nand_chip *chip, } /** - * nand_onfi_get_features- [REPLACEABLE] get features for ONFI nand + * nand_default_onfi_get_features- [REPLACEABLE] get features for ONFI nand * @mtd: MTD device structure * @chip: nand chip info structure * @addr: feature address. * @subfeature_param: the subfeature parameters, a four bytes array. */ -static int nand_onfi_get_features(struct mtd_info *mtd, struct nand_chip *chip, - int addr, uint8_t *subfeature_param) +static int nand_default_onfi_get_features(struct mtd_info *mtd, + struct nand_chip *chip, int addr, + uint8_t *subfeature_param) { if (!chip->onfi_version || !(le16_to_cpu(chip->onfi_params.opt_cmd) @@ -4879,9 +4881,9 @@ static void nand_set_defaults(struct nand_chip *chip) /* set for ONFI nand */ if (!chip->onfi_set_features) - chip->onfi_set_features = nand_onfi_set_features; + chip->onfi_set_features = nand_default_onfi_set_features; if (!chip->onfi_get_features) - chip->onfi_get_features = nand_onfi_get_features; + chip->onfi_get_features = nand_default_onfi_get_features; /* If called twice, pointers that depend on busw may need to be reset */ if (!chip->read_byte || chip->read_byte == nand_read_byte) From b958758e686aebe84672acc8871aca87d04f13a3 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Mon, 19 Mar 2018 14:47:19 +0100 Subject: [PATCH 45/89] mtd: rawnand: rename SET/GET FEATURES related functions SET/GET FEATURES are flagged ONFI-compliant because of their name. This is not accurate as non-ONFI NAND chips support it and use it. Rename the hooks and helpers to remove the "onfi" prefix. Signed-off-by: Miquel Raynal Signed-off-by: Boris Brezillon --- .../mtd/nand/raw/bcm47xxnflash/ops_bcm4706.c | 4 +- drivers/mtd/nand/raw/cafe_nand.c | 4 +- drivers/mtd/nand/raw/docg4.c | 4 +- drivers/mtd/nand/raw/fsl_elbc_nand.c | 4 +- drivers/mtd/nand/raw/fsl_ifc_nand.c | 4 +- drivers/mtd/nand/raw/gpmi-nand/gpmi-lib.c | 8 ++-- drivers/mtd/nand/raw/hisi504_nand.c | 4 +- drivers/mtd/nand/raw/mpc5121_nfc.c | 4 +- drivers/mtd/nand/raw/mxc_nand.c | 14 +++---- drivers/mtd/nand/raw/nand_base.c | 42 +++++++++---------- drivers/mtd/nand/raw/nand_micron.c | 16 +++---- drivers/mtd/nand/raw/qcom_nandc.c | 4 +- drivers/mtd/nand/raw/sh_flctl.c | 4 +- drivers/staging/mt29f_spinand/mt29f_spinand.c | 4 +- include/linux/mtd/rawnand.h | 17 ++++---- 15 files changed, 66 insertions(+), 71 deletions(-) diff --git a/drivers/mtd/nand/raw/bcm47xxnflash/ops_bcm4706.c b/drivers/mtd/nand/raw/bcm47xxnflash/ops_bcm4706.c index 54bac5b73f0a..60874de430eb 100644 --- a/drivers/mtd/nand/raw/bcm47xxnflash/ops_bcm4706.c +++ b/drivers/mtd/nand/raw/bcm47xxnflash/ops_bcm4706.c @@ -392,8 +392,8 @@ int bcm47xxnflash_ops_bcm4706_init(struct bcm47xxnflash *b47n) b47n->nand_chip.read_byte = bcm47xxnflash_ops_bcm4706_read_byte; b47n->nand_chip.read_buf = bcm47xxnflash_ops_bcm4706_read_buf; b47n->nand_chip.write_buf = bcm47xxnflash_ops_bcm4706_write_buf; - b47n->nand_chip.onfi_set_features = nand_onfi_get_set_features_notsupp; - b47n->nand_chip.onfi_get_features = nand_onfi_get_set_features_notsupp; + b47n->nand_chip.set_features = nand_get_set_features_notsupp; + b47n->nand_chip.get_features = nand_get_set_features_notsupp; nand_chip->chip_delay = 50; b47n->nand_chip.bbt_options = NAND_BBT_USE_FLASH; diff --git a/drivers/mtd/nand/raw/cafe_nand.c b/drivers/mtd/nand/raw/cafe_nand.c index 37cfae2761d4..3c1b6a3786b2 100644 --- a/drivers/mtd/nand/raw/cafe_nand.c +++ b/drivers/mtd/nand/raw/cafe_nand.c @@ -645,8 +645,8 @@ static int cafe_nand_probe(struct pci_dev *pdev, cafe->nand.read_buf = cafe_read_buf; cafe->nand.write_buf = cafe_write_buf; cafe->nand.select_chip = cafe_select_chip; - cafe->nand.onfi_set_features = nand_onfi_get_set_features_notsupp; - cafe->nand.onfi_get_features = nand_onfi_get_set_features_notsupp; + cafe->nand.set_features = nand_get_set_features_notsupp; + cafe->nand.get_features = nand_get_set_features_notsupp; cafe->nand.chip_delay = 0; diff --git a/drivers/mtd/nand/raw/docg4.c b/drivers/mtd/nand/raw/docg4.c index 72f1327c4430..1314aa99b9ab 100644 --- a/drivers/mtd/nand/raw/docg4.c +++ b/drivers/mtd/nand/raw/docg4.c @@ -1269,8 +1269,8 @@ static void __init init_mtd_structs(struct mtd_info *mtd) nand->read_buf = docg4_read_buf; nand->write_buf = docg4_write_buf16; nand->erase = docg4_erase_block; - nand->onfi_set_features = nand_onfi_get_set_features_notsupp; - nand->onfi_get_features = nand_onfi_get_set_features_notsupp; + nand->set_features = nand_get_set_features_notsupp; + nand->get_features = nand_get_set_features_notsupp; nand->ecc.read_page = docg4_read_page; nand->ecc.write_page = docg4_write_page; nand->ecc.read_page_raw = docg4_read_page_raw; diff --git a/drivers/mtd/nand/raw/fsl_elbc_nand.c b/drivers/mtd/nand/raw/fsl_elbc_nand.c index 84f7d6a94be7..d28df991c73c 100644 --- a/drivers/mtd/nand/raw/fsl_elbc_nand.c +++ b/drivers/mtd/nand/raw/fsl_elbc_nand.c @@ -775,8 +775,8 @@ static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv) chip->select_chip = fsl_elbc_select_chip; chip->cmdfunc = fsl_elbc_cmdfunc; chip->waitfunc = fsl_elbc_wait; - chip->onfi_set_features = nand_onfi_get_set_features_notsupp; - chip->onfi_get_features = nand_onfi_get_set_features_notsupp; + chip->set_features = nand_get_set_features_notsupp; + chip->get_features = nand_get_set_features_notsupp; chip->bbt_td = &bbt_main_descr; chip->bbt_md = &bbt_mirror_descr; diff --git a/drivers/mtd/nand/raw/fsl_ifc_nand.c b/drivers/mtd/nand/raw/fsl_ifc_nand.c index 4f0bbc8a803d..7ca678f05ae3 100644 --- a/drivers/mtd/nand/raw/fsl_ifc_nand.c +++ b/drivers/mtd/nand/raw/fsl_ifc_nand.c @@ -838,8 +838,8 @@ static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv) chip->select_chip = fsl_ifc_select_chip; chip->cmdfunc = fsl_ifc_cmdfunc; chip->waitfunc = fsl_ifc_wait; - chip->onfi_set_features = nand_onfi_get_set_features_notsupp; - chip->onfi_get_features = nand_onfi_get_set_features_notsupp; + chip->set_features = nand_get_set_features_notsupp; + chip->get_features = nand_get_set_features_notsupp; chip->bbt_td = &bbt_main_descr; chip->bbt_md = &bbt_mirror_descr; diff --git a/drivers/mtd/nand/raw/gpmi-nand/gpmi-lib.c b/drivers/mtd/nand/raw/gpmi-nand/gpmi-lib.c index 97787246af41..f78d907ca61e 100644 --- a/drivers/mtd/nand/raw/gpmi-nand/gpmi-lib.c +++ b/drivers/mtd/nand/raw/gpmi-nand/gpmi-lib.c @@ -934,15 +934,15 @@ static int enable_edo_mode(struct gpmi_nand_data *this, int mode) /* [1] send SET FEATURE command to NAND */ feature[0] = mode; - ret = nand->onfi_set_features(mtd, nand, - ONFI_FEATURE_ADDR_TIMING_MODE, feature); + ret = nand->set_features(mtd, nand, + ONFI_FEATURE_ADDR_TIMING_MODE, feature); if (ret) goto err_out; /* [2] send GET FEATURE command to double-check the timing mode */ memset(feature, 0, ONFI_SUBFEATURE_PARAM_LEN); - ret = nand->onfi_get_features(mtd, nand, - ONFI_FEATURE_ADDR_TIMING_MODE, feature); + ret = nand->get_features(mtd, nand, + ONFI_FEATURE_ADDR_TIMING_MODE, feature); if (ret || feature[0] != mode) goto err_out; diff --git a/drivers/mtd/nand/raw/hisi504_nand.c b/drivers/mtd/nand/raw/hisi504_nand.c index cb862793ab6d..27558a67fa41 100644 --- a/drivers/mtd/nand/raw/hisi504_nand.c +++ b/drivers/mtd/nand/raw/hisi504_nand.c @@ -762,8 +762,8 @@ static int hisi_nfc_probe(struct platform_device *pdev) chip->write_buf = hisi_nfc_write_buf; chip->read_buf = hisi_nfc_read_buf; chip->chip_delay = HINFC504_CHIP_DELAY; - chip->onfi_set_features = nand_onfi_get_set_features_notsupp; - chip->onfi_get_features = nand_onfi_get_set_features_notsupp; + chip->set_features = nand_get_set_features_notsupp; + chip->get_features = nand_get_set_features_notsupp; hisi_nfc_host_init(host); diff --git a/drivers/mtd/nand/raw/mpc5121_nfc.c b/drivers/mtd/nand/raw/mpc5121_nfc.c index 913b9d1225c6..6d1740d54e0d 100644 --- a/drivers/mtd/nand/raw/mpc5121_nfc.c +++ b/drivers/mtd/nand/raw/mpc5121_nfc.c @@ -707,8 +707,8 @@ static int mpc5121_nfc_probe(struct platform_device *op) chip->read_buf = mpc5121_nfc_read_buf; chip->write_buf = mpc5121_nfc_write_buf; chip->select_chip = mpc5121_nfc_select_chip; - chip->onfi_set_features = nand_onfi_get_set_features_notsupp; - chip->onfi_get_features = nand_onfi_get_set_features_notsupp; + chip->set_features = nand_get_set_features_notsupp; + chip->get_features = nand_get_set_features_notsupp; chip->bbt_options = NAND_BBT_USE_FLASH; chip->ecc.mode = NAND_ECC_SOFT; chip->ecc.algo = NAND_ECC_HAMMING; diff --git a/drivers/mtd/nand/raw/mxc_nand.c b/drivers/mtd/nand/raw/mxc_nand.c index 87b5ee66e501..61501654e708 100644 --- a/drivers/mtd/nand/raw/mxc_nand.c +++ b/drivers/mtd/nand/raw/mxc_nand.c @@ -1421,9 +1421,8 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command, } } -static int mxc_nand_onfi_set_features(struct mtd_info *mtd, - struct nand_chip *chip, int addr, - u8 *subfeature_param) +static int mxc_nand_set_features(struct mtd_info *mtd, struct nand_chip *chip, + int addr, u8 *subfeature_param) { struct nand_chip *nand_chip = mtd_to_nand(mtd); struct mxc_nand_host *host = nand_get_controller_data(nand_chip); @@ -1447,9 +1446,8 @@ static int mxc_nand_onfi_set_features(struct mtd_info *mtd, return 0; } -static int mxc_nand_onfi_get_features(struct mtd_info *mtd, - struct nand_chip *chip, int addr, - u8 *subfeature_param) +static int mxc_nand_get_features(struct mtd_info *mtd, struct nand_chip *chip, + int addr, u8 *subfeature_param) { struct nand_chip *nand_chip = mtd_to_nand(mtd); struct mxc_nand_host *host = nand_get_controller_data(nand_chip); @@ -1752,8 +1750,8 @@ static int mxcnd_probe(struct platform_device *pdev) this->read_word = mxc_nand_read_word; this->write_buf = mxc_nand_write_buf; this->read_buf = mxc_nand_read_buf; - this->onfi_set_features = mxc_nand_onfi_set_features; - this->onfi_get_features = mxc_nand_onfi_get_features; + this->set_features = mxc_nand_set_features; + this->get_features = mxc_nand_get_features; host->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(host->clk)) diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c index d1d5e2281860..802cd9ed44a1 100644 --- a/drivers/mtd/nand/raw/nand_base.c +++ b/drivers/mtd/nand/raw/nand_base.c @@ -349,7 +349,7 @@ static void nand_write_byte16(struct mtd_info *mtd, uint8_t byte) * 8-bits of the data bus. During address transfers, the host shall * set the upper 8-bits of the data bus to 00h. * - * One user of the write_byte callback is nand_onfi_set_features. The + * One user of the write_byte callback is nand_set_features. The * four parameters are specified to be written to I/O[7:0], but this is * neither an address nor a command transfer. Let's assume a 0 on the * upper I/O lines is OK. @@ -1231,9 +1231,9 @@ static int nand_setup_data_interface(struct nand_chip *chip, int chipnr) chip->onfi_timing_mode_default, }; - ret = chip->onfi_set_features(mtd, chip, - ONFI_FEATURE_ADDR_TIMING_MODE, - tmode_param); + ret = chip->set_features(mtd, chip, + ONFI_FEATURE_ADDR_TIMING_MODE, + tmode_param); if (ret) goto err; } @@ -4769,15 +4769,15 @@ static int nand_max_bad_blocks(struct mtd_info *mtd, loff_t ofs, size_t len) } /** - * nand_default_onfi_set_features- [REPLACEABLE] set features for ONFI nand + * nand_default_set_features- [REPLACEABLE] set NAND chip features * @mtd: MTD device structure * @chip: nand chip info structure * @addr: feature address. * @subfeature_param: the subfeature parameters, a four bytes array. */ -static int nand_default_onfi_set_features(struct mtd_info *mtd, - struct nand_chip *chip, int addr, - uint8_t *subfeature_param) +static int nand_default_set_features(struct mtd_info *mtd, + struct nand_chip *chip, int addr, + uint8_t *subfeature_param) { if (!chip->onfi_version || !(le16_to_cpu(chip->onfi_params.opt_cmd) @@ -4788,15 +4788,15 @@ static int nand_default_onfi_set_features(struct mtd_info *mtd, } /** - * nand_default_onfi_get_features- [REPLACEABLE] get features for ONFI nand + * nand_default_get_features- [REPLACEABLE] get NAND chip features * @mtd: MTD device structure * @chip: nand chip info structure * @addr: feature address. * @subfeature_param: the subfeature parameters, a four bytes array. */ -static int nand_default_onfi_get_features(struct mtd_info *mtd, - struct nand_chip *chip, int addr, - uint8_t *subfeature_param) +static int nand_default_get_features(struct mtd_info *mtd, + struct nand_chip *chip, int addr, + uint8_t *subfeature_param) { if (!chip->onfi_version || !(le16_to_cpu(chip->onfi_params.opt_cmd) @@ -4807,8 +4807,7 @@ static int nand_default_onfi_get_features(struct mtd_info *mtd, } /** - * nand_onfi_get_set_features_notsupp - set/get features stub returning - * -ENOTSUPP + * nand_get_set_features_notsupp - set/get features stub returning -ENOTSUPP * @mtd: MTD device structure * @chip: nand chip info structure * @addr: feature address. @@ -4817,13 +4816,12 @@ static int nand_default_onfi_get_features(struct mtd_info *mtd, * Should be used by NAND controller drivers that do not support the SET/GET * FEATURES operations. */ -int nand_onfi_get_set_features_notsupp(struct mtd_info *mtd, - struct nand_chip *chip, int addr, - u8 *subfeature_param) +int nand_get_set_features_notsupp(struct mtd_info *mtd, struct nand_chip *chip, + int addr, u8 *subfeature_param) { return -ENOTSUPP; } -EXPORT_SYMBOL(nand_onfi_get_set_features_notsupp); +EXPORT_SYMBOL(nand_get_set_features_notsupp); /** * nand_suspend - [MTD Interface] Suspend the NAND flash @@ -4880,10 +4878,10 @@ static void nand_set_defaults(struct nand_chip *chip) chip->select_chip = nand_select_chip; /* set for ONFI nand */ - if (!chip->onfi_set_features) - chip->onfi_set_features = nand_default_onfi_set_features; - if (!chip->onfi_get_features) - chip->onfi_get_features = nand_default_onfi_get_features; + if (!chip->set_features) + chip->set_features = nand_default_set_features; + if (!chip->get_features) + chip->get_features = nand_default_get_features; /* If called twice, pointers that depend on busw may need to be reset */ if (!chip->read_byte || chip->read_byte == nand_read_byte) diff --git a/drivers/mtd/nand/raw/nand_micron.c b/drivers/mtd/nand/raw/nand_micron.c index 02e109ae73f1..ab3e3a1a5212 100644 --- a/drivers/mtd/nand/raw/nand_micron.c +++ b/drivers/mtd/nand/raw/nand_micron.c @@ -48,8 +48,8 @@ static int micron_nand_setup_read_retry(struct mtd_info *mtd, int retry_mode) struct nand_chip *chip = mtd_to_nand(mtd); u8 feature[ONFI_SUBFEATURE_PARAM_LEN] = {retry_mode}; - return chip->onfi_set_features(mtd, chip, ONFI_FEATURE_ADDR_READ_RETRY, - feature); + return chip->set_features(mtd, chip, ONFI_FEATURE_ADDR_READ_RETRY, + feature); } /* @@ -108,8 +108,8 @@ static int micron_nand_on_die_ecc_setup(struct nand_chip *chip, bool enable) if (enable) feature[0] |= ONFI_FEATURE_ON_DIE_ECC_EN; - return chip->onfi_set_features(nand_to_mtd(chip), chip, - ONFI_FEATURE_ON_DIE_ECC, feature); + return chip->set_features(nand_to_mtd(chip), chip, + ONFI_FEATURE_ON_DIE_ECC, feature); } static int @@ -219,8 +219,8 @@ static int micron_supports_on_die_ecc(struct nand_chip *chip) if (ret) return MICRON_ON_DIE_UNSUPPORTED; - chip->onfi_get_features(nand_to_mtd(chip), chip, - ONFI_FEATURE_ON_DIE_ECC, feature); + chip->get_features(nand_to_mtd(chip), chip, + ONFI_FEATURE_ON_DIE_ECC, feature); if ((feature[0] & ONFI_FEATURE_ON_DIE_ECC_EN) == 0) return MICRON_ON_DIE_UNSUPPORTED; @@ -228,8 +228,8 @@ static int micron_supports_on_die_ecc(struct nand_chip *chip) if (ret) return MICRON_ON_DIE_UNSUPPORTED; - chip->onfi_get_features(nand_to_mtd(chip), chip, - ONFI_FEATURE_ON_DIE_ECC, feature); + chip->get_features(nand_to_mtd(chip), chip, + ONFI_FEATURE_ON_DIE_ECC, feature); if (feature[0] & ONFI_FEATURE_ON_DIE_ECC_EN) return MICRON_ON_DIE_MANDATORY; diff --git a/drivers/mtd/nand/raw/qcom_nandc.c b/drivers/mtd/nand/raw/qcom_nandc.c index 563b759ffca6..b554fb6e609c 100644 --- a/drivers/mtd/nand/raw/qcom_nandc.c +++ b/drivers/mtd/nand/raw/qcom_nandc.c @@ -2651,8 +2651,8 @@ static int qcom_nand_host_init(struct qcom_nand_controller *nandc, chip->read_byte = qcom_nandc_read_byte; chip->read_buf = qcom_nandc_read_buf; chip->write_buf = qcom_nandc_write_buf; - chip->onfi_set_features = nand_onfi_get_set_features_notsupp; - chip->onfi_get_features = nand_onfi_get_set_features_notsupp; + chip->set_features = nand_get_set_features_notsupp; + chip->get_features = nand_get_set_features_notsupp; /* * the bad block marker is readable only when we read the last codeword diff --git a/drivers/mtd/nand/raw/sh_flctl.c b/drivers/mtd/nand/raw/sh_flctl.c index a60d43adff3c..7a740d583866 100644 --- a/drivers/mtd/nand/raw/sh_flctl.c +++ b/drivers/mtd/nand/raw/sh_flctl.c @@ -1180,8 +1180,8 @@ static int flctl_probe(struct platform_device *pdev) nand->read_buf = flctl_read_buf; nand->select_chip = flctl_select_chip; nand->cmdfunc = flctl_cmdfunc; - nand->onfi_set_features = nand_onfi_get_set_features_notsupp; - nand->onfi_get_features = nand_onfi_get_set_features_notsupp; + nand->set_features = nand_get_set_features_notsupp; + nand->get_features = nand_get_set_features_notsupp; if (pdata->flcmncr_val & SEL_16BIT) nand->options |= NAND_BUSWIDTH_16; diff --git a/drivers/staging/mt29f_spinand/mt29f_spinand.c b/drivers/staging/mt29f_spinand/mt29f_spinand.c index 264ad362d858..6819dd2c1117 100644 --- a/drivers/staging/mt29f_spinand/mt29f_spinand.c +++ b/drivers/staging/mt29f_spinand/mt29f_spinand.c @@ -918,8 +918,8 @@ static int spinand_probe(struct spi_device *spi_nand) chip->waitfunc = spinand_wait; chip->options |= NAND_CACHEPRG; chip->select_chip = spinand_select_chip; - chip->onfi_set_features = nand_onfi_get_set_features_notsupp; - chip->onfi_get_features = nand_onfi_get_set_features_notsupp; + chip->set_features = nand_get_set_features_notsupp; + chip->get_features = nand_get_set_features_notsupp; mtd = nand_to_mtd(chip); diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h index 56c5570aadbe..fb2e288ef8b1 100644 --- a/include/linux/mtd/rawnand.h +++ b/include/linux/mtd/rawnand.h @@ -1170,8 +1170,8 @@ int nand_op_parser_exec_op(struct nand_chip *chip, * @blocks_per_die: [INTERN] The number of PEBs in a die * @data_interface: [INTERN] NAND interface timing information * @read_retries: [INTERN] the number of read retry modes supported - * @onfi_set_features: [REPLACEABLE] set the features for ONFI nand - * @onfi_get_features: [REPLACEABLE] get the features for ONFI nand + * @set_features: [REPLACEABLE] set the NAND chip features + * @get_features: [REPLACEABLE] get the NAND chip features * @setup_data_interface: [OPTIONAL] setup the data interface and timing. If * chipnr is set to %NAND_DATA_IFACE_CHECK_ONLY this * means the configuration should not be applied but @@ -1212,10 +1212,10 @@ struct nand_chip { bool check_only); int (*erase)(struct mtd_info *mtd, int page); int (*scan_bbt)(struct mtd_info *mtd); - int (*onfi_set_features)(struct mtd_info *mtd, struct nand_chip *chip, - int feature_addr, uint8_t *subfeature_para); - int (*onfi_get_features)(struct mtd_info *mtd, struct nand_chip *chip, - int feature_addr, uint8_t *subfeature_para); + int (*set_features)(struct mtd_info *mtd, struct nand_chip *chip, + int feature_addr, uint8_t *subfeature_para); + int (*get_features)(struct mtd_info *mtd, struct nand_chip *chip, + int feature_addr, uint8_t *subfeature_para); int (*setup_read_retry)(struct mtd_info *mtd, int retry_mode); int (*setup_data_interface)(struct mtd_info *mtd, int chipnr, const struct nand_data_interface *conf); @@ -1630,9 +1630,8 @@ int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip, int page); /* Stub used by drivers that do not support GET/SET FEATURES operations */ -int nand_onfi_get_set_features_notsupp(struct mtd_info *mtd, - struct nand_chip *chip, int addr, - u8 *subfeature_param); +int nand_get_set_features_notsupp(struct mtd_info *mtd, struct nand_chip *chip, + int addr, u8 *subfeature_param); /* Default read_page_raw implementation */ int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, From 97baea1e6b74c73973fa0922252f880ab15450ea Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Mon, 19 Mar 2018 14:47:20 +0100 Subject: [PATCH 46/89] mtd: rawnand: use wrappers to call onfi GET/SET_FEATURES Prepare the fact that some features managed by GET/SET_FEATURES could be overloaded by vendor code. To handle this logic, use new wrappers instead of directly call the ->get/set_features() hooks. Signed-off-by: Miquel Raynal Signed-off-by: Boris Brezillon --- drivers/mtd/nand/raw/gpmi-nand/gpmi-lib.c | 6 +- drivers/mtd/nand/raw/nand_base.c | 89 +++++++++++++++-------- drivers/mtd/nand/raw/nand_micron.c | 18 +++-- include/linux/mtd/rawnand.h | 3 + 4 files changed, 74 insertions(+), 42 deletions(-) diff --git a/drivers/mtd/nand/raw/gpmi-nand/gpmi-lib.c b/drivers/mtd/nand/raw/gpmi-nand/gpmi-lib.c index f78d907ca61e..039f2795617f 100644 --- a/drivers/mtd/nand/raw/gpmi-nand/gpmi-lib.c +++ b/drivers/mtd/nand/raw/gpmi-nand/gpmi-lib.c @@ -934,15 +934,13 @@ static int enable_edo_mode(struct gpmi_nand_data *this, int mode) /* [1] send SET FEATURE command to NAND */ feature[0] = mode; - ret = nand->set_features(mtd, nand, - ONFI_FEATURE_ADDR_TIMING_MODE, feature); + ret = nand_set_features(nand, ONFI_FEATURE_ADDR_TIMING_MODE, feature); if (ret) goto err_out; /* [2] send GET FEATURE command to double-check the timing mode */ memset(feature, 0, ONFI_SUBFEATURE_PARAM_LEN); - ret = nand->get_features(mtd, nand, - ONFI_FEATURE_ADDR_TIMING_MODE, feature); + ret = nand_get_features(nand, ONFI_FEATURE_ADDR_TIMING_MODE, feature); if (ret || feature[0] != mode) goto err_out; diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c index 802cd9ed44a1..d344dcb12620 100644 --- a/drivers/mtd/nand/raw/nand_base.c +++ b/drivers/mtd/nand/raw/nand_base.c @@ -1160,6 +1160,55 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip) return status; } +static bool nand_supports_set_get_features(struct nand_chip *chip) +{ + return (chip->onfi_version && + (le16_to_cpu(chip->onfi_params.opt_cmd) & + ONFI_OPT_CMD_SET_GET_FEATURES)); +} + +/** + * nand_get_features - wrapper to perform a GET_FEATURE + * @chip: NAND chip info structure + * @addr: feature address + * @subfeature_param: the subfeature parameters, a four bytes array + * + * Returns 0 for success, a negative error otherwise. Returns -ENOTSUPP if the + * operation cannot be handled. + */ +int nand_get_features(struct nand_chip *chip, int addr, + u8 *subfeature_param) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + + if (!nand_supports_set_get_features(chip)) + return -ENOTSUPP; + + return chip->get_features(mtd, chip, addr, subfeature_param); +} +EXPORT_SYMBOL_GPL(nand_get_features); + +/** + * nand_set_features - wrapper to perform a SET_FEATURE + * @chip: NAND chip info structure + * @addr: feature address + * @subfeature_param: the subfeature parameters, a four bytes array + * + * Returns 0 for success, a negative error otherwise. Returns -ENOTSUPP if the + * operation cannot be handled. + */ +int nand_set_features(struct nand_chip *chip, int addr, + u8 *subfeature_param) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + + if (!nand_supports_set_get_features(chip)) + return -ENOTSUPP; + + return chip->set_features(mtd, chip, addr, subfeature_param); +} +EXPORT_SYMBOL_GPL(nand_set_features); + /** * nand_reset_data_interface - Reset data interface and timings * @chip: The NAND chip @@ -1215,32 +1264,22 @@ static int nand_reset_data_interface(struct nand_chip *chip, int chipnr) static int nand_setup_data_interface(struct nand_chip *chip, int chipnr) { struct mtd_info *mtd = nand_to_mtd(chip); + u8 tmode_param[ONFI_SUBFEATURE_PARAM_LEN] = { + chip->onfi_timing_mode_default, + }; int ret; if (!chip->setup_data_interface) return 0; - /* - * Ensure the timing mode has been changed on the chip side - * before changing timings on the controller side. - */ - if (chip->onfi_version && - (le16_to_cpu(chip->onfi_params.opt_cmd) & - ONFI_OPT_CMD_SET_GET_FEATURES)) { - u8 tmode_param[ONFI_SUBFEATURE_PARAM_LEN] = { - chip->onfi_timing_mode_default, - }; + /* Change the mode on the chip side */ + ret = nand_set_features(chip, ONFI_FEATURE_ADDR_TIMING_MODE, + tmode_param); + if (ret) + return ret; - ret = chip->set_features(mtd, chip, - ONFI_FEATURE_ADDR_TIMING_MODE, - tmode_param); - if (ret) - goto err; - } - - ret = chip->setup_data_interface(mtd, chipnr, &chip->data_interface); -err: - return ret; + /* Change the mode on the controller side */ + return chip->setup_data_interface(mtd, chipnr, &chip->data_interface); } /** @@ -4779,11 +4818,6 @@ static int nand_default_set_features(struct mtd_info *mtd, struct nand_chip *chip, int addr, uint8_t *subfeature_param) { - if (!chip->onfi_version || - !(le16_to_cpu(chip->onfi_params.opt_cmd) - & ONFI_OPT_CMD_SET_GET_FEATURES)) - return -EINVAL; - return nand_set_features_op(chip, addr, subfeature_param); } @@ -4798,11 +4832,6 @@ static int nand_default_get_features(struct mtd_info *mtd, struct nand_chip *chip, int addr, uint8_t *subfeature_param) { - if (!chip->onfi_version || - !(le16_to_cpu(chip->onfi_params.opt_cmd) - & ONFI_OPT_CMD_SET_GET_FEATURES)) - return -EINVAL; - return nand_get_features_op(chip, addr, subfeature_param); } diff --git a/drivers/mtd/nand/raw/nand_micron.c b/drivers/mtd/nand/raw/nand_micron.c index ab3e3a1a5212..b825656f6284 100644 --- a/drivers/mtd/nand/raw/nand_micron.c +++ b/drivers/mtd/nand/raw/nand_micron.c @@ -48,8 +48,7 @@ static int micron_nand_setup_read_retry(struct mtd_info *mtd, int retry_mode) struct nand_chip *chip = mtd_to_nand(mtd); u8 feature[ONFI_SUBFEATURE_PARAM_LEN] = {retry_mode}; - return chip->set_features(mtd, chip, ONFI_FEATURE_ADDR_READ_RETRY, - feature); + return nand_set_features(chip, ONFI_FEATURE_ADDR_READ_RETRY, feature); } /* @@ -108,8 +107,7 @@ static int micron_nand_on_die_ecc_setup(struct nand_chip *chip, bool enable) if (enable) feature[0] |= ONFI_FEATURE_ON_DIE_ECC_EN; - return chip->set_features(nand_to_mtd(chip), chip, - ONFI_FEATURE_ON_DIE_ECC, feature); + return nand_set_features(chip, ONFI_FEATURE_ON_DIE_ECC, feature); } static int @@ -219,8 +217,10 @@ static int micron_supports_on_die_ecc(struct nand_chip *chip) if (ret) return MICRON_ON_DIE_UNSUPPORTED; - chip->get_features(nand_to_mtd(chip), chip, - ONFI_FEATURE_ON_DIE_ECC, feature); + ret = nand_get_features(chip, ONFI_FEATURE_ON_DIE_ECC, feature); + if (ret < 0) + return ret; + if ((feature[0] & ONFI_FEATURE_ON_DIE_ECC_EN) == 0) return MICRON_ON_DIE_UNSUPPORTED; @@ -228,8 +228,10 @@ static int micron_supports_on_die_ecc(struct nand_chip *chip) if (ret) return MICRON_ON_DIE_UNSUPPORTED; - chip->get_features(nand_to_mtd(chip), chip, - ONFI_FEATURE_ON_DIE_ECC, feature); + ret = nand_get_features(chip, ONFI_FEATURE_ON_DIE_ECC, feature); + if (ret < 0) + return ret; + if (feature[0] & ONFI_FEATURE_ON_DIE_ECC_EN) return MICRON_ON_DIE_MANDATORY; diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h index fb2e288ef8b1..3cc2a3435b20 100644 --- a/include/linux/mtd/rawnand.h +++ b/include/linux/mtd/rawnand.h @@ -1629,6 +1629,9 @@ int nand_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip, int page); int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip, int page); +/* Wrapper to use in order for controllers/vendors to GET/SET FEATURES */ +int nand_get_features(struct nand_chip *chip, int addr, u8 *subfeature_param); +int nand_set_features(struct nand_chip *chip, int addr, u8 *subfeature_param); /* Stub used by drivers that do not support GET/SET FEATURES operations */ int nand_get_set_features_notsupp(struct mtd_info *mtd, struct nand_chip *chip, int addr, u8 *subfeature_param); From 993447b746820259e21b6c7962523631128d5ca6 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Mon, 19 Mar 2018 14:47:21 +0100 Subject: [PATCH 47/89] mtd: rawnand: handle differently chip/controller errors about timings Usually, the source of the error when setting/getting features does not matter (if the controller does not support sending the command or if the chip does not support the operation). When it comes to timings, if the controller fails it is an error while if the chip does not support the operation, it can be silently supposed that it already works with the maximum supported timings. Introduce some logic in nand_setup_data_interface() to handle that difference. Signed-off-by: Miquel Raynal Signed-off-by: Boris Brezillon --- drivers/mtd/nand/raw/nand_base.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c index d344dcb12620..2109fc223ff2 100644 --- a/drivers/mtd/nand/raw/nand_base.c +++ b/drivers/mtd/nand/raw/nand_base.c @@ -1272,11 +1272,13 @@ static int nand_setup_data_interface(struct nand_chip *chip, int chipnr) if (!chip->setup_data_interface) return 0; - /* Change the mode on the chip side */ - ret = nand_set_features(chip, ONFI_FEATURE_ADDR_TIMING_MODE, - tmode_param); - if (ret) - return ret; + /* Change the mode on the chip side (if supported by the NAND chip) */ + if (nand_supports_set_get_features(chip)) { + ret = nand_set_features(chip, ONFI_FEATURE_ADDR_TIMING_MODE, + tmode_param); + if (ret) + return ret; + } /* Change the mode on the controller side */ return chip->setup_data_interface(mtd, chipnr, &chip->data_interface); From 939da44758447c64a272d7a87e706872271a2fab Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Mon, 19 Mar 2018 14:47:22 +0100 Subject: [PATCH 48/89] mtd: rawnand: mxc: remove useless checks in GET/SET_FEATURES functions All the calls to the chip's hooks ->get/set_features() go through the core's wrappers nand_get/set_features() that already do the necessary checks about feature support. Remove these checks from the mxc's functions. Signed-off-by: Miquel Raynal Signed-off-by: Boris Brezillon --- drivers/mtd/nand/raw/mxc_nand.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/drivers/mtd/nand/raw/mxc_nand.c b/drivers/mtd/nand/raw/mxc_nand.c index 61501654e708..944ecf03d3b1 100644 --- a/drivers/mtd/nand/raw/mxc_nand.c +++ b/drivers/mtd/nand/raw/mxc_nand.c @@ -1428,11 +1428,6 @@ static int mxc_nand_set_features(struct mtd_info *mtd, struct nand_chip *chip, struct mxc_nand_host *host = nand_get_controller_data(nand_chip); int i; - if (!chip->onfi_version || - !(le16_to_cpu(chip->onfi_params.opt_cmd) - & ONFI_OPT_CMD_SET_GET_FEATURES)) - return -EINVAL; - host->buf_start = 0; for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i) @@ -1453,11 +1448,6 @@ static int mxc_nand_get_features(struct mtd_info *mtd, struct nand_chip *chip, struct mxc_nand_host *host = nand_get_controller_data(nand_chip); int i; - if (!chip->onfi_version || - !(le16_to_cpu(chip->onfi_params.opt_cmd) - & ONFI_OPT_CMD_SET_GET_FEATURES)) - return -EINVAL; - host->devtype_data->send_cmd(host, NAND_CMD_GET_FEATURES, false); mxc_do_addr_cycle(mtd, addr, -1); host->devtype_data->send_page(mtd, NFC_OUTPUT); From 29714d6bd72b2de163a89240a70550f23d25c324 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Mon, 19 Mar 2018 14:47:23 +0100 Subject: [PATCH 49/89] mtd: rawnand: move calls to ->select_chip() in nand_setup_data_interface() After a ->set_features(TIMINGS), the chip is supposed to be working at a new speed. In order for all the transactions to be perperly handled, the NAND controller should also be configured to this same speed. Calling ->setup_data_interface() is not enough and the chip should be de-asserted/re-asserted through calls to ->select_chip(). Prepare the next change in nand_setup_data_interface() where timings will be checked after being applied. Because assertions of the CS pin will be needed from within this function, move the calls to ->select_chip() inside nand_setup_data_interface() for later consistency. Signed-off-by: Miquel Raynal Signed-off-by: Boris Brezillon --- drivers/mtd/nand/raw/nand_base.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c index 2109fc223ff2..9d5c2739fe6d 100644 --- a/drivers/mtd/nand/raw/nand_base.c +++ b/drivers/mtd/nand/raw/nand_base.c @@ -1274,8 +1274,10 @@ static int nand_setup_data_interface(struct nand_chip *chip, int chipnr) /* Change the mode on the chip side (if supported by the NAND chip) */ if (nand_supports_set_get_features(chip)) { + chip->select_chip(mtd, chipnr); ret = nand_set_features(chip, ONFI_FEATURE_ADDR_TIMING_MODE, tmode_param); + chip->select_chip(mtd, -1); if (ret) return ret; } @@ -2780,10 +2782,8 @@ int nand_reset(struct nand_chip *chip, int chipnr) if (ret) return ret; - chip->select_chip(mtd, chipnr); chip->data_interface = saved_data_intf; ret = nand_setup_data_interface(chip, chipnr); - chip->select_chip(mtd, -1); if (ret) return ret; @@ -6505,10 +6505,7 @@ int nand_scan_tail(struct mtd_info *mtd) /* Enter fastest possible mode on all dies. */ for (i = 0; i < chip->numchips; i++) { - chip->select_chip(mtd, i); ret = nand_setup_data_interface(chip, i); - chip->select_chip(mtd, -1); - if (ret) goto err_nand_manuf_cleanup; } From 415ae78ffb5d97343ada8e4c2d4bda5f6416b5ef Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Mon, 19 Mar 2018 14:47:24 +0100 Subject: [PATCH 50/89] mtd: rawnand: check ONFI timings have been acked by the chip Choosing ONFI timings when ->set/get_features() calls are supported by the NAND chip is a matter of reading the chip's ONFI parameter page and telling the chip the chosen mode (between all of the supported ones) with ->set_feature(). Add a check on whether the chip "acked" the timing mode or not. This can be a problem for NAND chips that do not follow entirely the ONFI specification. These chips actually support other modes than "mode 0", but either: 1/ do not update the timing mode register once a timing mode has been selected. or 2/ do not support the TIMING_MODE featured and thus do not require users to change the timing mode at all. These issues will be addressed in another patch that will add the feature to overwrite NAND chips features within the parameter page, from the NAND chip driver. Signed-off-by: Miquel Raynal Tested-by: Han Xu Signed-off-by: Boris Brezillon --- drivers/mtd/nand/raw/nand_base.c | 36 +++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c index 9d5c2739fe6d..837ea698af08 100644 --- a/drivers/mtd/nand/raw/nand_base.c +++ b/drivers/mtd/nand/raw/nand_base.c @@ -1283,7 +1283,41 @@ static int nand_setup_data_interface(struct nand_chip *chip, int chipnr) } /* Change the mode on the controller side */ - return chip->setup_data_interface(mtd, chipnr, &chip->data_interface); + ret = chip->setup_data_interface(mtd, chipnr, &chip->data_interface); + if (ret) + return ret; + + /* Check the mode has been accepted by the chip, if supported */ + if (!nand_supports_set_get_features(chip)) + return 0; + + memset(tmode_param, 0, ONFI_SUBFEATURE_PARAM_LEN); + chip->select_chip(mtd, chipnr); + ret = nand_get_features(chip, ONFI_FEATURE_ADDR_TIMING_MODE, + tmode_param); + chip->select_chip(mtd, -1); + if (ret) + goto err_reset_chip; + + if (tmode_param[0] != chip->onfi_timing_mode_default) { + pr_warn("timing mode %d not acknowledged by the NAND chip\n", + chip->onfi_timing_mode_default); + goto err_reset_chip; + } + + return 0; + +err_reset_chip: + /* + * Fallback to mode 0 if the chip explicitly did not ack the chosen + * timing mode. + */ + nand_reset_data_interface(chip, chipnr); + chip->select_chip(mtd, chipnr); + nand_reset_op(chip); + chip->select_chip(mtd, -1); + + return ret; } /** From 107b7d6a7ad4927e1b217cf5667ac94bab021e42 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Mon, 19 Mar 2018 14:47:25 +0100 Subject: [PATCH 51/89] mtd: rawnand: avoid setting again the timings to mode 0 after a reset After a nand_reset_data_interface(), both the NAND chip and the NAND controller use timing mode 0. The previously defined data interface for this chip has been saved and is supposed to be restored after that. However, if the saved data interface also refers to timing mode 0, there is no need to re-apply them again. Also, as nand_setup_data_interface() uses ->set/get_features(), it could lead to issues when doing the reset at probe time as the parameter page is not available yet to know if these functions are supported or not. Signed-off-by: Miquel Raynal Signed-off-by: Boris Brezillon --- drivers/mtd/nand/raw/nand_base.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c index 837ea698af08..4099d8a1e25e 100644 --- a/drivers/mtd/nand/raw/nand_base.c +++ b/drivers/mtd/nand/raw/nand_base.c @@ -2816,6 +2816,16 @@ int nand_reset(struct nand_chip *chip, int chipnr) if (ret) return ret; + /* + * A nand_reset_data_interface() put both the NAND chip and the NAND + * controller in timings mode 0. If the default mode for this chip is + * also 0, no need to proceed to the change again. Plus, at probe time, + * nand_setup_data_interface() uses ->set/get_features() which would + * fail anyway as the parameter page is not available yet. + */ + if (!chip->onfi_timing_mode_default) + return 0; + chip->data_interface = saved_data_intf; ret = nand_setup_data_interface(chip, chipnr); if (ret) From f4531b2b1929806d2bec1a2f19805031d8bc0806 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Mon, 19 Mar 2018 14:47:26 +0100 Subject: [PATCH 52/89] mtd: rawnand: prepare the removal of ONFI/JEDEC parameter pages The NAND chip parameter page is statically allocated within the nand_chip structure, which reserves a lot of space. Even not ONFI nor JEDEC chips have it embedded. Also, only a few parameters are actually read from the parameter page after the detection. To prepare to the removal of such huge structure, a small NAND parameter structure is allocated statically and contains only very few members that are generic to all chips and actually used elsewhere in the code. Signed-off-by: Miquel Raynal Signed-off-by: Boris Brezillon --- drivers/mtd/nand/raw/nand_base.c | 39 ++++++++++++++------------------ include/linux/mtd/rawnand.h | 13 +++++++++++ 2 files changed, 30 insertions(+), 22 deletions(-) diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c index 4099d8a1e25e..0f1f45526c7f 100644 --- a/drivers/mtd/nand/raw/nand_base.c +++ b/drivers/mtd/nand/raw/nand_base.c @@ -1162,9 +1162,7 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip) static bool nand_supports_set_get_features(struct nand_chip *chip) { - return (chip->onfi_version && - (le16_to_cpu(chip->onfi_params.opt_cmd) & - ONFI_OPT_CMD_SET_GET_FEATURES)); + return chip->parameters.supports_set_get_features; } /** @@ -5145,8 +5143,8 @@ static int nand_flash_detect_onfi(struct nand_chip *chip) sanitize_string(p->manufacturer, sizeof(p->manufacturer)); sanitize_string(p->model, sizeof(p->model)); - if (!mtd->name) - mtd->name = p->model; + strncpy(chip->parameters.model, p->model, + sizeof(chip->parameters.model) - 1); mtd->writesize = le32_to_cpu(p->byte_per_page); @@ -5193,6 +5191,10 @@ static int nand_flash_detect_onfi(struct nand_chip *chip) pr_warn("Could not retrieve ONFI ECC requirements\n"); } + /* Save some parameters from the parameter page for future use */ + if (le16_to_cpu(p->opt_cmd) & ONFI_OPT_CMD_SET_GET_FEATURES) + chip->parameters.supports_set_get_features = true; + return 1; } @@ -5245,8 +5247,8 @@ static int nand_flash_detect_jedec(struct nand_chip *chip) sanitize_string(p->manufacturer, sizeof(p->manufacturer)); sanitize_string(p->model, sizeof(p->model)); - if (!mtd->name) - mtd->name = p->model; + strncpy(chip->parameters.model, p->model, + sizeof(chip->parameters.model) - 1); mtd->writesize = le32_to_cpu(p->byte_per_page); @@ -5433,8 +5435,8 @@ static bool find_full_id_nand(struct nand_chip *chip, chip->onfi_timing_mode_default = type->onfi_timing_mode_default; - if (!mtd->name) - mtd->name = type->name; + strncpy(chip->parameters.model, type->name, + sizeof(chip->parameters.model) - 1); return true; } @@ -5587,8 +5589,8 @@ static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type) if (!type->name) return -ENODEV; - if (!mtd->name) - mtd->name = type->name; + strncpy(chip->parameters.model, type->name, + sizeof(chip->parameters.model) - 1); chip->chipsize = (uint64_t)type->chipsize << 20; @@ -5601,6 +5603,8 @@ static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type) chip->options |= type->options; ident_done: + if (!mtd->name) + mtd->name = chip->parameters.model; if (chip->options & NAND_BUSWIDTH_AUTO) { WARN_ON(busw & NAND_BUSWIDTH_16); @@ -5647,17 +5651,8 @@ ident_done: pr_info("device found, Manufacturer ID: 0x%02x, Chip ID: 0x%02x\n", maf_id, dev_id); - - if (chip->onfi_version) - pr_info("%s %s\n", nand_manufacturer_name(manufacturer), - chip->onfi_params.model); - else if (chip->jedec_version) - pr_info("%s %s\n", nand_manufacturer_name(manufacturer), - chip->jedec_params.model); - else - pr_info("%s %s\n", nand_manufacturer_name(manufacturer), - type->name); - + pr_info("%s %s\n", nand_manufacturer_name(manufacturer), + chip->parameters.model); pr_info("%d MiB, %s, erase size: %d KiB, page size: %d, OOB size: %d\n", (int)(chip->chipsize >> 20), nand_is_slc(chip) ? "SLC" : "MLC", mtd->erasesize >> 10, mtd->writesize, mtd->oobsize); diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h index 3cc2a3435b20..a24591411d78 100644 --- a/include/linux/mtd/rawnand.h +++ b/include/linux/mtd/rawnand.h @@ -429,6 +429,16 @@ struct nand_jedec_params { __le16 crc; } __packed; +/** + * struct nand_parameters - NAND generic parameters from the parameter page + * @model: Model name + * @supports_set_get_features: The NAND chip supports setting/getting features + */ +struct nand_parameters { + char model[100]; + bool supports_set_get_features; +}; + /* The maximum expected count of bytes in the NAND ID sequence */ #define NAND_MAX_ID_LEN 8 @@ -1165,6 +1175,8 @@ int nand_op_parser_exec_op(struct nand_chip *chip, * supported, 0 otherwise. * @jedec_params: [INTERN] holds the JEDEC parameter page when JEDEC is * supported, 0 otherwise. + * @parameters: [INTERN] holds generic parameters under an easily + * readable form. * @max_bb_per_die: [INTERN] the max number of bad blocks each die of a * this nand device will encounter their life times. * @blocks_per_die: [INTERN] The number of PEBs in a die @@ -1249,6 +1261,7 @@ struct nand_chip { struct nand_onfi_params onfi_params; struct nand_jedec_params jedec_params; }; + struct nand_parameters parameters; u16 max_bb_per_die; u32 blocks_per_die; From a97421c7532d382ab560ca153bdf9450f97c7e41 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Mon, 19 Mar 2018 14:47:27 +0100 Subject: [PATCH 53/89] mtd: rawnand: prepare the removal of the ONFI parameter page The NAND chip parameter page is statically allocated within the nand_chip structure, which reserves a lot of space. Even not ONFI nor JEDEC chips have it embedded. Also, only a few parameters are actually read from the parameter page after the detection. ONFI-related parameters that will be used outside from the identification function are stored in a separate onfi_parameters structure embedded in nand_parameters, this small structure that already hold generic parameters. For now, the onfi_parameters structure is allocated statically. However, after some deep rework in the NAND framework, it will be possible to do dynamic allocations from the NAND identification phase, and this strcuture will then be dynamically allocated when needed. Signed-off-by: Miquel Raynal Signed-off-by: Boris Brezillon --- drivers/mtd/nand/raw/gpmi-nand/gpmi-lib.c | 2 +- drivers/mtd/nand/raw/nand_base.c | 30 ++++++++++----- drivers/mtd/nand/raw/nand_micron.c | 19 ++++----- drivers/mtd/nand/raw/nand_timings.c | 12 +++--- include/linux/mtd/rawnand.h | 47 ++++++++++++++--------- 5 files changed, 64 insertions(+), 46 deletions(-) diff --git a/drivers/mtd/nand/raw/gpmi-nand/gpmi-lib.c b/drivers/mtd/nand/raw/gpmi-nand/gpmi-lib.c index 039f2795617f..f3cc38372d79 100644 --- a/drivers/mtd/nand/raw/gpmi-nand/gpmi-lib.c +++ b/drivers/mtd/nand/raw/gpmi-nand/gpmi-lib.c @@ -971,7 +971,7 @@ int gpmi_extra_init(struct gpmi_nand_data *this) struct nand_chip *chip = &this->nand; /* Enable the asynchronous EDO feature. */ - if (GPMI_IS_MX6(this) && chip->onfi_version) { + if (GPMI_IS_MX6(this) && chip->parameters.onfi.version) { int mode = onfi_get_async_timing_mode(chip); /* We only support the timing mode 4 and mode 5. */ diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c index 0f1f45526c7f..789c11e0925e 100644 --- a/drivers/mtd/nand/raw/nand_base.c +++ b/drivers/mtd/nand/raw/nand_base.c @@ -5126,17 +5126,17 @@ static int nand_flash_detect_onfi(struct nand_chip *chip) /* Check version */ val = le16_to_cpu(p->revision); if (val & (1 << 5)) - chip->onfi_version = 23; + chip->parameters.onfi.version = 23; else if (val & (1 << 4)) - chip->onfi_version = 22; + chip->parameters.onfi.version = 22; else if (val & (1 << 3)) - chip->onfi_version = 21; + chip->parameters.onfi.version = 21; else if (val & (1 << 2)) - chip->onfi_version = 20; + chip->parameters.onfi.version = 20; else if (val & (1 << 1)) - chip->onfi_version = 10; + chip->parameters.onfi.version = 10; - if (!chip->onfi_version) { + if (!chip->parameters.onfi.version) { pr_info("unsupported ONFI version: %d\n", val); return 0; } @@ -5166,14 +5166,14 @@ static int nand_flash_detect_onfi(struct nand_chip *chip) chip->max_bb_per_die = le16_to_cpu(p->bb_per_lun); chip->blocks_per_die = le32_to_cpu(p->blocks_per_lun); - if (onfi_feature(chip) & ONFI_FEATURE_16_BIT_BUS) + if (le16_to_cpu(p->features) & ONFI_FEATURE_16_BIT_BUS) chip->options |= NAND_BUSWIDTH_16; if (p->ecc_bits != 0xff) { chip->ecc_strength_ds = p->ecc_bits; chip->ecc_step_ds = 512; - } else if (chip->onfi_version >= 21 && - (onfi_feature(chip) & ONFI_FEATURE_EXT_PARAM_PAGE)) { + } else if (chip->parameters.onfi.version >= 21 && + (le16_to_cpu(p->features) & ONFI_FEATURE_EXT_PARAM_PAGE)) { /* * The nand_flash_detect_ext_param_page() uses the @@ -5194,6 +5194,16 @@ static int nand_flash_detect_onfi(struct nand_chip *chip) /* Save some parameters from the parameter page for future use */ if (le16_to_cpu(p->opt_cmd) & ONFI_OPT_CMD_SET_GET_FEATURES) chip->parameters.supports_set_get_features = true; + chip->parameters.onfi.tPROG = le16_to_cpu(p->t_prog); + chip->parameters.onfi.tBERS = le16_to_cpu(p->t_bers); + chip->parameters.onfi.tR = le16_to_cpu(p->t_r); + chip->parameters.onfi.tCCS = le16_to_cpu(p->t_ccs); + chip->parameters.onfi.async_timing_mode = + le16_to_cpu(p->async_timing_mode); + chip->parameters.onfi.vendor_revision = + le16_to_cpu(p->vendor_revision); + memcpy(chip->parameters.onfi.vendor, p->vendor, + sizeof(p->vendor)); return 1; } @@ -5575,7 +5585,7 @@ static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type) } } - chip->onfi_version = 0; + chip->parameters.onfi.version = 0; if (!type->name || !type->pagesize) { /* Check if the chip is ONFI compliant */ if (nand_flash_detect_onfi(chip)) diff --git a/drivers/mtd/nand/raw/nand_micron.c b/drivers/mtd/nand/raw/nand_micron.c index b825656f6284..c5974d8313e7 100644 --- a/drivers/mtd/nand/raw/nand_micron.c +++ b/drivers/mtd/nand/raw/nand_micron.c @@ -56,17 +56,14 @@ static int micron_nand_setup_read_retry(struct mtd_info *mtd, int retry_mode) */ static int micron_nand_onfi_init(struct nand_chip *chip) { - struct nand_onfi_params *p = &chip->onfi_params; - struct nand_onfi_vendor_micron *micron = (void *)p->vendor; + struct nand_parameters *p = &chip->parameters; + struct nand_onfi_vendor_micron *micron = (void *)p->onfi.vendor; - if (!chip->onfi_version) - return 0; + if (chip->parameters.onfi.version && p->onfi.vendor_revision) { + chip->read_retries = micron->read_retry_options; + chip->setup_read_retry = micron_nand_setup_read_retry; + } - if (le16_to_cpu(p->vendor_revision) < 1) - return 0; - - chip->read_retries = micron->read_retry_options; - chip->setup_read_retry = micron_nand_setup_read_retry; return 0; } @@ -207,7 +204,7 @@ static int micron_supports_on_die_ecc(struct nand_chip *chip) u8 feature[ONFI_SUBFEATURE_PARAM_LEN] = { 0, }; int ret; - if (chip->onfi_version == 0) + if (!chip->parameters.onfi.version) return MICRON_ON_DIE_UNSUPPORTED; if (chip->bits_per_cell != 1) @@ -239,7 +236,7 @@ static int micron_supports_on_die_ecc(struct nand_chip *chip) * Some Micron NANDs have an on-die ECC of 4/512, some other * 8/512. We only support the former. */ - if (chip->onfi_params.ecc_bits != 4) + if (chip->ecc_strength_ds != 4) return MICRON_ON_DIE_UNSUPPORTED; return MICRON_ON_DIE_SUPPORTED; diff --git a/drivers/mtd/nand/raw/nand_timings.c b/drivers/mtd/nand/raw/nand_timings.c index 9400d039ddbd..7c4e4a371bbc 100644 --- a/drivers/mtd/nand/raw/nand_timings.c +++ b/drivers/mtd/nand/raw/nand_timings.c @@ -306,17 +306,17 @@ int onfi_fill_data_interface(struct nand_chip *chip, * tR, tPROG, tCCS, ... * These information are part of the ONFI parameter page. */ - if (chip->onfi_version) { - struct nand_onfi_params *params = &chip->onfi_params; + if (chip->parameters.onfi.version) { + struct nand_parameters *params = &chip->parameters; struct nand_sdr_timings *timings = &iface->timings.sdr; /* microseconds -> picoseconds */ - timings->tPROG_max = 1000000ULL * le16_to_cpu(params->t_prog); - timings->tBERS_max = 1000000ULL * le16_to_cpu(params->t_bers); - timings->tR_max = 1000000ULL * le16_to_cpu(params->t_r); + timings->tPROG_max = 1000000ULL * params->onfi.tPROG; + timings->tBERS_max = 1000000ULL * params->onfi.tBERS; + timings->tR_max = 1000000ULL * params->onfi.tR; /* nanoseconds -> picoseconds */ - timings->tCCS_min = 1000UL * le16_to_cpu(params->t_ccs); + timings->tCCS_min = 1000UL * params->onfi.tCCS; } return 0; diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h index a24591411d78..7b5afa6ef5a9 100644 --- a/include/linux/mtd/rawnand.h +++ b/include/linux/mtd/rawnand.h @@ -429,14 +429,41 @@ struct nand_jedec_params { __le16 crc; } __packed; +/** + * struct onfi_params - ONFI specific parameters that will be reused + * @version: ONFI version (BCD encoded), 0 if ONFI is not supported + * @tPROG: Page program time + * @tBERS: Block erase time + * @tR: Page read time + * @tCCS: Change column setup time + * @async_timing_mode: Supported asynchronous timing mode + * @vendor_revision: Vendor specific revision number + * @vendor: Vendor specific data + */ +struct onfi_params { + int version; + u16 tPROG; + u16 tBERS; + u16 tR; + u16 tCCS; + u16 async_timing_mode; + u16 vendor_revision; + u8 vendor[88]; +}; + /** * struct nand_parameters - NAND generic parameters from the parameter page * @model: Model name * @supports_set_get_features: The NAND chip supports setting/getting features + * @onfi: ONFI specific parameters */ struct nand_parameters { + /* Generic parameters */ char model[100]; bool supports_set_get_features; + + /* ONFI parameters */ + struct onfi_params onfi; }; /* The maximum expected count of bytes in the NAND ID sequence */ @@ -1167,8 +1194,6 @@ int nand_op_parser_exec_op(struct nand_chip *chip, * currently in data_buf. * @subpagesize: [INTERN] holds the subpagesize * @id: [INTERN] holds NAND ID - * @onfi_version: [INTERN] holds the chip ONFI version (BCD encoded), - * non 0 if ONFI supported. * @jedec_version: [INTERN] holds the chip JEDEC version (BCD encoded), * non 0 if JEDEC supported. * @onfi_params: [INTERN] holds the ONFI page parameter when ONFI is @@ -1255,7 +1280,6 @@ struct nand_chip { int badblockbits; struct nand_id id; - int onfi_version; int jedec_version; union { struct nand_onfi_params onfi_params; @@ -1548,26 +1572,13 @@ struct platform_nand_data { struct platform_nand_ctrl ctrl; }; -/* return the supported features. */ -static inline int onfi_feature(struct nand_chip *chip) -{ - return chip->onfi_version ? le16_to_cpu(chip->onfi_params.features) : 0; -} - /* return the supported asynchronous timing mode. */ static inline int onfi_get_async_timing_mode(struct nand_chip *chip) { - if (!chip->onfi_version) + if (!chip->parameters.onfi.version) return ONFI_TIMING_MODE_UNKNOWN; - return le16_to_cpu(chip->onfi_params.async_timing_mode); -} -/* return the supported synchronous timing mode. */ -static inline int onfi_get_sync_timing_mode(struct nand_chip *chip) -{ - if (!chip->onfi_version) - return ONFI_TIMING_MODE_UNKNOWN; - return le16_to_cpu(chip->onfi_params.src_sync_timing_mode); + return chip->parameters.onfi.async_timing_mode; } int onfi_fill_data_interface(struct nand_chip *chip, From 789157e41a0694e70bf80bceecd79438c3de98d6 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Mon, 19 Mar 2018 14:47:28 +0100 Subject: [PATCH 54/89] mtd: rawnand: allow vendors to declare (un)supported features If SET/GET_FEATURES is available (from the parameter page), use a bitmap to declare what feature is actually supported. Initialize the bitmap in the core to support timing changes (only feature used by the core), also add support for Micron specific features used in Micron initialization code (in the init routine). Signed-off-by: Miquel Raynal Signed-off-by: Boris Brezillon --- drivers/mtd/nand/raw/nand_base.c | 26 +++++++++++++++++++------- drivers/mtd/nand/raw/nand_micron.c | 4 ++++ include/linux/mtd/rawnand.h | 8 +++++++- 3 files changed, 30 insertions(+), 8 deletions(-) diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c index 789c11e0925e..0bd9f22973e9 100644 --- a/drivers/mtd/nand/raw/nand_base.c +++ b/drivers/mtd/nand/raw/nand_base.c @@ -1160,9 +1160,16 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip) return status; } -static bool nand_supports_set_get_features(struct nand_chip *chip) +static bool nand_supports_get_features(struct nand_chip *chip, int addr) { - return chip->parameters.supports_set_get_features; + return (chip->parameters.supports_set_get_features && + test_bit(addr, chip->parameters.get_feature_list)); +} + +static bool nand_supports_set_features(struct nand_chip *chip, int addr) +{ + return (chip->parameters.supports_set_get_features && + test_bit(addr, chip->parameters.set_feature_list)); } /** @@ -1179,7 +1186,7 @@ int nand_get_features(struct nand_chip *chip, int addr, { struct mtd_info *mtd = nand_to_mtd(chip); - if (!nand_supports_set_get_features(chip)) + if (!nand_supports_get_features(chip, addr)) return -ENOTSUPP; return chip->get_features(mtd, chip, addr, subfeature_param); @@ -1200,7 +1207,7 @@ int nand_set_features(struct nand_chip *chip, int addr, { struct mtd_info *mtd = nand_to_mtd(chip); - if (!nand_supports_set_get_features(chip)) + if (!nand_supports_set_features(chip, addr)) return -ENOTSUPP; return chip->set_features(mtd, chip, addr, subfeature_param); @@ -1271,7 +1278,7 @@ static int nand_setup_data_interface(struct nand_chip *chip, int chipnr) return 0; /* Change the mode on the chip side (if supported by the NAND chip) */ - if (nand_supports_set_get_features(chip)) { + if (nand_supports_set_features(chip, ONFI_FEATURE_ADDR_TIMING_MODE)) { chip->select_chip(mtd, chipnr); ret = nand_set_features(chip, ONFI_FEATURE_ADDR_TIMING_MODE, tmode_param); @@ -1286,7 +1293,7 @@ static int nand_setup_data_interface(struct nand_chip *chip, int chipnr) return ret; /* Check the mode has been accepted by the chip, if supported */ - if (!nand_supports_set_get_features(chip)) + if (!nand_supports_get_features(chip, ONFI_FEATURE_ADDR_TIMING_MODE)) return 0; memset(tmode_param, 0, ONFI_SUBFEATURE_PARAM_LEN); @@ -5192,8 +5199,13 @@ static int nand_flash_detect_onfi(struct nand_chip *chip) } /* Save some parameters from the parameter page for future use */ - if (le16_to_cpu(p->opt_cmd) & ONFI_OPT_CMD_SET_GET_FEATURES) + if (le16_to_cpu(p->opt_cmd) & ONFI_OPT_CMD_SET_GET_FEATURES) { chip->parameters.supports_set_get_features = true; + bitmap_set(chip->parameters.get_feature_list, + ONFI_FEATURE_ADDR_TIMING_MODE, 1); + bitmap_set(chip->parameters.set_feature_list, + ONFI_FEATURE_ADDR_TIMING_MODE, 1); + } chip->parameters.onfi.tPROG = le16_to_cpu(p->t_prog); chip->parameters.onfi.tBERS = le16_to_cpu(p->t_bers); chip->parameters.onfi.tR = le16_to_cpu(p->t_r); diff --git a/drivers/mtd/nand/raw/nand_micron.c b/drivers/mtd/nand/raw/nand_micron.c index c5974d8313e7..0af45b134c0c 100644 --- a/drivers/mtd/nand/raw/nand_micron.c +++ b/drivers/mtd/nand/raw/nand_micron.c @@ -64,6 +64,10 @@ static int micron_nand_onfi_init(struct nand_chip *chip) chip->setup_read_retry = micron_nand_setup_read_retry; } + if (p->supports_set_get_features) { + set_bit(ONFI_FEATURE_ADDR_READ_RETRY, p->set_feature_list); + set_bit(ONFI_FEATURE_ADDR_READ_RETRY, p->get_feature_list); + } return 0; } diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h index 7b5afa6ef5a9..d9f417719d36 100644 --- a/include/linux/mtd/rawnand.h +++ b/include/linux/mtd/rawnand.h @@ -21,6 +21,7 @@ #include #include #include +#include struct mtd_info; struct nand_flash_dev; @@ -235,7 +236,8 @@ struct nand_chip; #define ONFI_TIMING_MODE_5 (1 << 5) #define ONFI_TIMING_MODE_UNKNOWN (1 << 6) -/* ONFI feature address */ +/* ONFI feature number/address */ +#define ONFI_FEATURE_NUMBER 256 #define ONFI_FEATURE_ADDR_TIMING_MODE 0x1 /* Vendor-specific feature address (Micron) */ @@ -455,12 +457,16 @@ struct onfi_params { * struct nand_parameters - NAND generic parameters from the parameter page * @model: Model name * @supports_set_get_features: The NAND chip supports setting/getting features + * @set_feature_list: Bitmap of features that can be set + * @get_feature_list: Bitmap of features that can be get * @onfi: ONFI specific parameters */ struct nand_parameters { /* Generic parameters */ char model[100]; bool supports_set_get_features; + DECLARE_BITMAP(set_feature_list, ONFI_FEATURE_NUMBER); + DECLARE_BITMAP(get_feature_list, ONFI_FEATURE_NUMBER); /* ONFI parameters */ struct onfi_params onfi; From 34c5c01e0c8c35c01e9353d0166bfc0eb19b571c Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Mon, 19 Mar 2018 14:47:29 +0100 Subject: [PATCH 55/89] mtd: rawnand: macronix: nack the support of changing timings for one chip The MX30LF2G18AC chip declares in its parameter page supporting SET/GET_FEATURES but when it comes to timings, experience shows that it is not the case. Unflag this feature for this particular chip in the nand_parameters structure to avoid unnecessary errors and downturns. Signed-off-by: Miquel Raynal Signed-off-by: Boris Brezillon --- drivers/mtd/nand/raw/nand_macronix.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/mtd/nand/raw/nand_macronix.c b/drivers/mtd/nand/raw/nand_macronix.c index d290ff2a6d2f..7ed1f87e742a 100644 --- a/drivers/mtd/nand/raw/nand_macronix.c +++ b/drivers/mtd/nand/raw/nand_macronix.c @@ -22,6 +22,19 @@ static int macronix_nand_init(struct nand_chip *chip) if (nand_is_slc(chip)) chip->bbt_options |= NAND_BBT_SCAN2NDPAGE; + /* + * MX30LF2G18AC chip does not support using SET/GET_FEATURES to change + * the timings unlike what is declared in the parameter page. Unflag + * this feature to avoid unnecessary downturns. + */ + if (chip->parameters.supports_set_get_features && + !strcmp("MX30LF2G18AC", chip->parameters.model)) { + bitmap_clear(chip->parameters.get_feature_list, + ONFI_FEATURE_ADDR_TIMING_MODE, 1); + bitmap_clear(chip->parameters.set_feature_list, + ONFI_FEATURE_ADDR_TIMING_MODE, 1); + } + return 0; } From 480139d9229e3be0530bc548da208b5f49b1ab90 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Mon, 19 Mar 2018 14:47:30 +0100 Subject: [PATCH 56/89] mtd: rawnand: get rid of the JEDEC parameter page in nand_chip The NAND chip parameter page is statically allocated within the nand_chip structure, which reserves a lot of space. Even not ONFI nor JEDEC chips have it embedded. Also, only a few parameters are actually read from the parameter page after the detection. Now that there is a small nand_parameters structure that can held generic parameters, remove the JEDEC page from the nand_chip structure by just allocating it during the identification phase and removing it right after. Signed-off-by: Miquel Raynal Signed-off-by: Boris Brezillon --- drivers/mtd/nand/raw/nand_base.c | 41 ++++++++++++++++++++++---------- include/linux/mtd/rawnand.h | 17 +------------ 2 files changed, 29 insertions(+), 29 deletions(-) diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c index 0bd9f22973e9..79348165e4a3 100644 --- a/drivers/mtd/nand/raw/nand_base.c +++ b/drivers/mtd/nand/raw/nand_base.c @@ -5226,8 +5226,9 @@ static int nand_flash_detect_onfi(struct nand_chip *chip) static int nand_flash_detect_jedec(struct nand_chip *chip) { struct mtd_info *mtd = nand_to_mtd(chip); - struct nand_jedec_params *p = &chip->jedec_params; + struct nand_jedec_params *p; struct jedec_ecc_info *ecc; + int jedec_version = 0; char id[5]; int i, val, ret; @@ -5236,14 +5237,23 @@ static int nand_flash_detect_jedec(struct nand_chip *chip) if (ret || strncmp(id, "JEDEC", sizeof(id))) return 0; + /* JEDEC chip: allocate a buffer to hold its parameter page */ + p = kzalloc(sizeof(*p), GFP_KERNEL); + if (!p) + return -ENOMEM; + ret = nand_read_param_page_op(chip, 0x40, NULL, 0); - if (ret) - return 0; + if (ret) { + ret = 0; + goto free_jedec_param_page; + } for (i = 0; i < 3; i++) { ret = nand_read_data_op(chip, p, sizeof(*p), true); - if (ret) - return 0; + if (ret) { + ret = 0; + goto free_jedec_param_page; + } if (onfi_crc16(ONFI_CRC_BASE, (uint8_t *)p, 510) == le16_to_cpu(p->crc)) @@ -5252,19 +5262,19 @@ static int nand_flash_detect_jedec(struct nand_chip *chip) if (i == 3) { pr_err("Could not find valid JEDEC parameter page; aborting\n"); - return 0; + goto free_jedec_param_page; } /* Check version */ val = le16_to_cpu(p->revision); if (val & (1 << 2)) - chip->jedec_version = 10; + jedec_version = 10; else if (val & (1 << 1)) - chip->jedec_version = 1; /* vendor specific version */ + jedec_version = 1; /* vendor specific version */ - if (!chip->jedec_version) { + if (!jedec_version) { pr_info("unsupported JEDEC version: %d\n", val); - return 0; + goto free_jedec_param_page; } sanitize_string(p->manufacturer, sizeof(p->manufacturer)); @@ -5285,7 +5295,7 @@ static int nand_flash_detect_jedec(struct nand_chip *chip) chip->chipsize *= (uint64_t)mtd->erasesize * p->lun_count; chip->bits_per_cell = p->bits_per_cell; - if (jedec_feature(chip) & JEDEC_FEATURE_16_BIT_BUS) + if (le16_to_cpu(p->features) & JEDEC_FEATURE_16_BIT_BUS) chip->options |= NAND_BUSWIDTH_16; /* ECC info */ @@ -5298,7 +5308,9 @@ static int nand_flash_detect_jedec(struct nand_chip *chip) pr_warn("Invalid codeword size\n"); } - return 1; +free_jedec_param_page: + kfree(p); + return ret; } /* @@ -5604,7 +5616,10 @@ static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type) goto ident_done; /* Check if the chip is JEDEC compliant */ - if (nand_flash_detect_jedec(chip)) + ret = nand_flash_detect_jedec(chip); + if (ret < 0) + return ret; + else if (ret) goto ident_done; } diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h index d9f417719d36..cf82a959b0f3 100644 --- a/include/linux/mtd/rawnand.h +++ b/include/linux/mtd/rawnand.h @@ -1200,12 +1200,8 @@ int nand_op_parser_exec_op(struct nand_chip *chip, * currently in data_buf. * @subpagesize: [INTERN] holds the subpagesize * @id: [INTERN] holds NAND ID - * @jedec_version: [INTERN] holds the chip JEDEC version (BCD encoded), - * non 0 if JEDEC supported. * @onfi_params: [INTERN] holds the ONFI page parameter when ONFI is * supported, 0 otherwise. - * @jedec_params: [INTERN] holds the JEDEC parameter page when JEDEC is - * supported, 0 otherwise. * @parameters: [INTERN] holds generic parameters under an easily * readable form. * @max_bb_per_die: [INTERN] the max number of bad blocks each die of a @@ -1286,11 +1282,7 @@ struct nand_chip { int badblockbits; struct nand_id id; - int jedec_version; - union { - struct nand_onfi_params onfi_params; - struct nand_jedec_params jedec_params; - }; + struct nand_onfi_params onfi_params; struct nand_parameters parameters; u16 max_bb_per_die; u32 blocks_per_die; @@ -1621,13 +1613,6 @@ static inline int nand_opcode_8bits(unsigned int command) return 0; } -/* return the supported JEDEC features. */ -static inline int jedec_feature(struct nand_chip *chip) -{ - return chip->jedec_version ? le16_to_cpu(chip->jedec_params.features) - : 0; -} - /* get timing characteristics from ONFI timing mode. */ const struct nand_sdr_timings *onfi_async_timing_mode_to_sdr_timings(int mode); From bd0b64340c2d66c0fe1aa99b0b23159d7e0c21f2 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Mon, 19 Mar 2018 14:47:31 +0100 Subject: [PATCH 57/89] mtd: rawnand: get rid of the ONFI parameter page in nand_chip The NAND chip parameter page is statically allocated within the nand_chip structure, which reserves a lot of space. Even not ONFI nor JEDEC chips have it embedded. Also, only a few parameters are actually read from the parameter page after the detection. Now that there is a small nand_parameters structure that hold all needed ONFI parameters, remove the ONFI page from the nand_chip structure by just allocating it during the identification phase and removing it right after. Signed-off-by: Miquel Raynal Signed-off-by: Boris Brezillon --- drivers/mtd/nand/raw/nand_base.c | 34 +++++++++++++++++++++++--------- include/linux/mtd/rawnand.h | 3 --- 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c index 79348165e4a3..d0b993fcf3a5 100644 --- a/drivers/mtd/nand/raw/nand_base.c +++ b/drivers/mtd/nand/raw/nand_base.c @@ -5101,7 +5101,7 @@ ext_out: static int nand_flash_detect_onfi(struct nand_chip *chip) { struct mtd_info *mtd = nand_to_mtd(chip); - struct nand_onfi_params *p = &chip->onfi_params; + struct nand_onfi_params *p; char id[4]; int i, ret, val; @@ -5110,14 +5110,23 @@ static int nand_flash_detect_onfi(struct nand_chip *chip) if (ret || strncmp(id, "ONFI", 4)) return 0; + /* ONFI chip: allocate a buffer to hold its parameter page */ + p = kzalloc(sizeof(*p), GFP_KERNEL); + if (!p) + return -ENOMEM; + ret = nand_read_param_page_op(chip, 0, NULL, 0); - if (ret) - return 0; + if (ret) { + ret = 0; + goto free_onfi_param_page; + } for (i = 0; i < 3; i++) { ret = nand_read_data_op(chip, p, sizeof(*p), true); - if (ret) - return 0; + if (ret) { + ret = 0; + goto free_onfi_param_page; + } if (onfi_crc16(ONFI_CRC_BASE, (uint8_t *)p, 254) == le16_to_cpu(p->crc)) { @@ -5127,7 +5136,7 @@ static int nand_flash_detect_onfi(struct nand_chip *chip) if (i == 3) { pr_err("Could not find valid ONFI parameter page; aborting\n"); - return 0; + goto free_onfi_param_page; } /* Check version */ @@ -5145,7 +5154,9 @@ static int nand_flash_detect_onfi(struct nand_chip *chip) if (!chip->parameters.onfi.version) { pr_info("unsupported ONFI version: %d\n", val); - return 0; + goto free_onfi_param_page; + } else { + ret = 1; } sanitize_string(p->manufacturer, sizeof(p->manufacturer)); @@ -5217,7 +5228,9 @@ static int nand_flash_detect_onfi(struct nand_chip *chip) memcpy(chip->parameters.onfi.vendor, p->vendor, sizeof(p->vendor)); - return 1; +free_onfi_param_page: + kfree(p); + return ret; } /* @@ -5612,7 +5625,10 @@ static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type) chip->parameters.onfi.version = 0; if (!type->name || !type->pagesize) { /* Check if the chip is ONFI compliant */ - if (nand_flash_detect_onfi(chip)) + ret = nand_flash_detect_onfi(chip); + if (ret < 0) + return ret; + else if (ret) goto ident_done; /* Check if the chip is JEDEC compliant */ diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h index cf82a959b0f3..5dad59b31244 100644 --- a/include/linux/mtd/rawnand.h +++ b/include/linux/mtd/rawnand.h @@ -1200,8 +1200,6 @@ int nand_op_parser_exec_op(struct nand_chip *chip, * currently in data_buf. * @subpagesize: [INTERN] holds the subpagesize * @id: [INTERN] holds NAND ID - * @onfi_params: [INTERN] holds the ONFI page parameter when ONFI is - * supported, 0 otherwise. * @parameters: [INTERN] holds generic parameters under an easily * readable form. * @max_bb_per_die: [INTERN] the max number of bad blocks each die of a @@ -1282,7 +1280,6 @@ struct nand_chip { int badblockbits; struct nand_id id; - struct nand_onfi_params onfi_params; struct nand_parameters parameters; u16 max_bb_per_die; u32 blocks_per_die; From 76e1a0086a0c3276b384f77905345e0fcc886fdd Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Fri, 2 Mar 2018 15:38:39 +0100 Subject: [PATCH 58/89] mtd: rawnand: gpmi: support ->setup_data_interface() Until now the GPMI driver had its own timings logic while the core already handles that and request the NAND controller drivers to support the ->setup_data_interface() hook. Implement that hook by reusing the already existing function. No real glue is necessary between core timing delays and GPMI registers because the driver already translates the ONFI timing modes into register values. Make use of the core's tREA, tRLOH and tRHOH values that allow computing more precise timings for mode [0-3] and get significantly better values (+20% with an i.MX6 Sabre Auto board). Otherwise use the existing logic. Signed-off-by: Miquel Raynal Tested-by: Han Xu Signed-off-by: Boris Brezillon --- drivers/mtd/nand/raw/gpmi-nand/gpmi-lib.c | 276 ++++++--------------- drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c | 42 ++-- drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.h | 82 +++--- 3 files changed, 150 insertions(+), 250 deletions(-) diff --git a/drivers/mtd/nand/raw/gpmi-nand/gpmi-lib.c b/drivers/mtd/nand/raw/gpmi-nand/gpmi-lib.c index f3cc38372d79..cf71cb9cee6a 100644 --- a/drivers/mtd/nand/raw/gpmi-nand/gpmi-lib.c +++ b/drivers/mtd/nand/raw/gpmi-nand/gpmi-lib.c @@ -151,8 +151,15 @@ err_clk: return ret; } -#define gpmi_enable_clk(x) __gpmi_enable_clk(x, true) -#define gpmi_disable_clk(x) __gpmi_enable_clk(x, false) +int gpmi_enable_clk(struct gpmi_nand_data *this) +{ + return __gpmi_enable_clk(this, true); +} + +int gpmi_disable_clk(struct gpmi_nand_data *this) +{ + return __gpmi_enable_clk(this, false); +} int gpmi_init(struct gpmi_nand_data *this) { @@ -326,14 +333,13 @@ static unsigned int ns_to_cycles(unsigned int time, #define DEF_MIN_PROP_DELAY 5 #define DEF_MAX_PROP_DELAY 9 /* Apply timing to current hardware conditions. */ -static int gpmi_nfc_compute_hardware_timing(struct gpmi_nand_data *this, - struct gpmi_nfc_hardware_timing *hw) +static void +gpmi_nfc_compute_hardware_timings(struct gpmi_nand_data *this) { + struct gpmi_nfc_hardware_timing *hw = &this->hw; struct timing_threshold *nfc = &timing_default_threshold; - struct resources *r = &this->resources; struct nand_chip *nand = &this->nand; struct nand_timing target = this->timing; - bool improved_timing_is_available; unsigned long clock_frequency_in_hz; unsigned int clock_period_in_ns; bool dll_use_half_periods; @@ -349,6 +355,9 @@ static int gpmi_nfc_compute_hardware_timing(struct gpmi_nand_data *this, unsigned int min_prop_delay_in_ns = DEF_MIN_PROP_DELAY; unsigned int max_prop_delay_in_ns = DEF_MAX_PROP_DELAY; + /* Clock rate for non-EDO modes */ + hw->clk_rate = 22000000; + /* * If there are multiple chips, we need to relax the timings to allow * for signal distortion due to higher capacitance. @@ -363,14 +372,8 @@ static int gpmi_nfc_compute_hardware_timing(struct gpmi_nand_data *this, target.address_setup_in_ns += 5; } - /* Check if improved timing information is available. */ - improved_timing_is_available = - (target.tREA_in_ns >= 0) && - (target.tRLOH_in_ns >= 0) && - (target.tRHOH_in_ns >= 0); - /* Inspect the clock. */ - nfc->clock_frequency_in_hz = clk_get_rate(r->clock[0]); + nfc->clock_frequency_in_hz = hw->clk_rate; clock_frequency_in_hz = nfc->clock_frequency_in_hz; clock_period_in_ns = NSEC_PER_SEC / clock_frequency_in_hz; @@ -481,65 +484,6 @@ static int gpmi_nfc_compute_hardware_timing(struct gpmi_nand_data *this, max_sample_delay_in_ns = nfc->max_dll_delay_in_ns; } - /* - * Check if improved timing information is available. If not, we have to - * use a less-sophisticated algorithm. - */ - if (!improved_timing_is_available) { - /* - * Fold the read setup time required by the NFC into the ideal - * sample delay. - */ - ideal_sample_delay_in_ns = target.gpmi_sample_delay_in_ns + - nfc->internal_data_setup_in_ns; - - /* - * The ideal sample delay may be greater than the maximum - * allowed by the NFC. If so, we can trade off sample delay time - * for more data setup time. - * - * In each iteration of the following loop, we add a cycle to - * the data setup time and subtract a corresponding amount from - * the sample delay until we've satisified the constraints or - * can't do any better. - */ - while ((ideal_sample_delay_in_ns > max_sample_delay_in_ns) && - (data_setup_in_cycles < nfc->max_data_setup_cycles)) { - - data_setup_in_cycles++; - ideal_sample_delay_in_ns -= clock_period_in_ns; - - if (ideal_sample_delay_in_ns < 0) - ideal_sample_delay_in_ns = 0; - - } - - /* - * Compute the sample delay factor that corresponds most closely - * to the ideal sample delay. If the result is too large for the - * NFC, use the maximum value. - * - * Notice that we use the ns_to_cycles function to compute the - * sample delay factor. We do this because the form of the - * computation is the same as that for calculating cycles. - */ - sample_delay_factor = - ns_to_cycles( - ideal_sample_delay_in_ns << dll_delay_shift, - clock_period_in_ns, 0); - - if (sample_delay_factor > nfc->max_sample_delay_factor) - sample_delay_factor = nfc->max_sample_delay_factor; - - /* Skip to the part where we return our results. */ - goto return_results; - } - - /* - * If control arrives here, we have more detailed timing information, - * so we can use a better algorithm. - */ - /* * Fold the read setup time required by the NFC into the maximum * propagation delay. @@ -760,8 +704,6 @@ static int gpmi_nfc_compute_hardware_timing(struct gpmi_nand_data *this, sample_delay_factor = nfc->max_sample_delay_factor; } - /* Control arrives here when we're ready to return our results. */ -return_results: hw->data_setup_in_cycles = data_setup_in_cycles; hw->data_hold_in_cycles = data_hold_in_cycles; hw->address_setup_in_cycles = address_setup_in_cycles; @@ -769,9 +711,6 @@ return_results: hw->sample_delay_factor = sample_delay_factor; hw->device_busy_timeout = GPMI_DEFAULT_BUSY_TIMEOUT; hw->wrn_dly_sel = BV_GPMI_CTRL1_WRN_DLY_SEL_4_TO_8NS; - - /* Return success. */ - return 0; } /* @@ -857,19 +796,17 @@ return_results: * So we only support the mode 4 and mode 5. It is no need to * support other modes. */ -static void gpmi_compute_edo_timing(struct gpmi_nand_data *this, - struct gpmi_nfc_hardware_timing *hw) +static void gpmi_nfc_compute_edo_timings(struct gpmi_nand_data *this, + int mode) { - struct resources *r = &this->resources; - unsigned long rate = clk_get_rate(r->clock[0]); - int mode = this->timing_mode; + struct gpmi_nfc_hardware_timing *hw = &this->hw; int dll_threshold = this->devdata->max_chain_delay; unsigned long delay; unsigned long clk_period; - int t_rea; - int c = 4; - int t_rp; - int rp; + int t_rp, t_rea, rp; + + /* Set the main clock to: 100MHz (mode 5) or 80MHz (mode 4) */ + hw->clk_rate = (mode == 5) ? 100000000 : 80000000; /* * [1] for GPMI_HW_GPMI_TIMING0: @@ -880,7 +817,7 @@ static void gpmi_compute_edo_timing(struct gpmi_nand_data *this, */ hw->data_setup_in_cycles = 1; hw->data_hold_in_cycles = 1; - hw->address_setup_in_cycles = ((mode == 5) ? 1 : 0); + hw->address_setup_in_cycles = (mode == 5) ? 1 : 0; /* [2] for GPMI_HW_GPMI_TIMING1 */ hw->device_busy_timeout = 0x9000; @@ -892,11 +829,9 @@ static void gpmi_compute_edo_timing(struct gpmi_nand_data *this, * Enlarge 10 times for the numerator and denominator in {3}. * This make us to get more accurate result. */ - clk_period = NSEC_PER_SEC / (rate / 10); + clk_period = NSEC_PER_SEC / (hw->clk_rate / 10); dll_threshold *= 10; - t_rea = ((mode == 5) ? 16 : 20) * 10; - c *= 10; - + t_rea = this->timing.tREA_in_ns * 10; t_rp = clk_period * 1; /* DATA_SETUP is 1 */ if (clk_period > dll_threshold) { @@ -911,127 +846,41 @@ static void gpmi_compute_edo_timing(struct gpmi_nand_data *this, * Multiply the numerator with 10, we could do a round off: * 7.8 round up to 8; 7.4 round down to 7. */ - delay = (((t_rea + c - t_rp) * 8) * 10) / rp; + delay = (((t_rea + 40 - t_rp) * 8) * 10) / rp; delay = (delay + 5) / 10; hw->sample_delay_factor = delay; } -static int enable_edo_mode(struct gpmi_nand_data *this, int mode) -{ - struct resources *r = &this->resources; - struct nand_chip *nand = &this->nand; - struct mtd_info *mtd = nand_to_mtd(nand); - uint8_t *feature; - unsigned long rate; - int ret; - - feature = kzalloc(ONFI_SUBFEATURE_PARAM_LEN, GFP_KERNEL); - if (!feature) - return -ENOMEM; - - nand->select_chip(mtd, 0); - - /* [1] send SET FEATURE command to NAND */ - feature[0] = mode; - ret = nand_set_features(nand, ONFI_FEATURE_ADDR_TIMING_MODE, feature); - if (ret) - goto err_out; - - /* [2] send GET FEATURE command to double-check the timing mode */ - memset(feature, 0, ONFI_SUBFEATURE_PARAM_LEN); - ret = nand_get_features(nand, ONFI_FEATURE_ADDR_TIMING_MODE, feature); - if (ret || feature[0] != mode) - goto err_out; - - nand->select_chip(mtd, -1); - - /* [3] set the main IO clock, 100MHz for mode 5, 80MHz for mode 4. */ - rate = (mode == 5) ? 100000000 : 80000000; - clk_set_rate(r->clock[0], rate); - - /* Let the gpmi_begin() re-compute the timing again. */ - this->flags &= ~GPMI_TIMING_INIT_OK; - - this->flags |= GPMI_ASYNC_EDO_ENABLED; - this->timing_mode = mode; - kfree(feature); - dev_info(this->dev, "enable the asynchronous EDO mode %d\n", mode); - return 0; - -err_out: - nand->select_chip(mtd, -1); - kfree(feature); - dev_err(this->dev, "mode:%d ,failed in set feature.\n", mode); - return -EINVAL; -} - -int gpmi_extra_init(struct gpmi_nand_data *this) -{ - struct nand_chip *chip = &this->nand; - - /* Enable the asynchronous EDO feature. */ - if (GPMI_IS_MX6(this) && chip->parameters.onfi.version) { - int mode = onfi_get_async_timing_mode(chip); - - /* We only support the timing mode 4 and mode 5. */ - if (mode & ONFI_TIMING_MODE_5) - mode = 5; - else if (mode & ONFI_TIMING_MODE_4) - mode = 4; - else - return 0; - - return enable_edo_mode(this, mode); - } - return 0; -} - -/* Begin the I/O */ -void gpmi_begin(struct gpmi_nand_data *this) +void gpmi_nfc_apply_timings(struct gpmi_nand_data *this) { + struct gpmi_nfc_hardware_timing *hw = &this->hw; struct resources *r = &this->resources; void __iomem *gpmi_regs = r->gpmi_regs; unsigned int clock_period_in_ns; uint32_t reg; unsigned int dll_wait_time_in_us; - struct gpmi_nfc_hardware_timing hw; - int ret; - /* Enable the clock. */ - ret = gpmi_enable_clk(this); - if (ret) { - dev_err(this->dev, "We failed in enable the clk\n"); - goto err_out; - } - - /* Only initialize the timing once */ - if (this->flags & GPMI_TIMING_INIT_OK) - return; - this->flags |= GPMI_TIMING_INIT_OK; - - if (this->flags & GPMI_ASYNC_EDO_ENABLED) - gpmi_compute_edo_timing(this, &hw); - else - gpmi_nfc_compute_hardware_timing(this, &hw); + /* [0] Set the main clock rate */ + clk_set_rate(r->clock[0], hw->clk_rate); /* [1] Set HW_GPMI_TIMING0 */ - reg = BF_GPMI_TIMING0_ADDRESS_SETUP(hw.address_setup_in_cycles) | - BF_GPMI_TIMING0_DATA_HOLD(hw.data_hold_in_cycles) | - BF_GPMI_TIMING0_DATA_SETUP(hw.data_setup_in_cycles); + reg = BF_GPMI_TIMING0_ADDRESS_SETUP(hw->address_setup_in_cycles) | + BF_GPMI_TIMING0_DATA_HOLD(hw->data_hold_in_cycles) | + BF_GPMI_TIMING0_DATA_SETUP(hw->data_setup_in_cycles); writel(reg, gpmi_regs + HW_GPMI_TIMING0); /* [2] Set HW_GPMI_TIMING1 */ - writel(BF_GPMI_TIMING1_BUSY_TIMEOUT(hw.device_busy_timeout), - gpmi_regs + HW_GPMI_TIMING1); + writel(BF_GPMI_TIMING1_BUSY_TIMEOUT(hw->device_busy_timeout), + gpmi_regs + HW_GPMI_TIMING1); /* [3] The following code is to set the HW_GPMI_CTRL1. */ /* Set the WRN_DLY_SEL */ writel(BM_GPMI_CTRL1_WRN_DLY_SEL, gpmi_regs + HW_GPMI_CTRL1_CLR); - writel(BF_GPMI_CTRL1_WRN_DLY_SEL(hw.wrn_dly_sel), - gpmi_regs + HW_GPMI_CTRL1_SET); + writel(BF_GPMI_CTRL1_WRN_DLY_SEL(hw->wrn_dly_sel), + gpmi_regs + HW_GPMI_CTRL1_SET); /* DLL_ENABLE must be set to 0 when setting RDN_DELAY or HALF_PERIOD. */ writel(BM_GPMI_CTRL1_DLL_ENABLE, gpmi_regs + HW_GPMI_CTRL1_CLR); @@ -1041,12 +890,12 @@ void gpmi_begin(struct gpmi_nand_data *this) writel(reg, gpmi_regs + HW_GPMI_CTRL1_CLR); /* If no sample delay is called for, return immediately. */ - if (!hw.sample_delay_factor) + if (!hw->sample_delay_factor) return; /* Set RDN_DELAY or HALF_PERIOD. */ - reg = ((hw.use_half_periods) ? BM_GPMI_CTRL1_HALF_PERIOD : 0) - | BF_GPMI_CTRL1_RDN_DELAY(hw.sample_delay_factor); + reg = ((hw->use_half_periods) ? BM_GPMI_CTRL1_HALF_PERIOD : 0) + | BF_GPMI_CTRL1_RDN_DELAY(hw->sample_delay_factor); writel(reg, gpmi_regs + HW_GPMI_CTRL1_SET); @@ -1058,7 +907,7 @@ void gpmi_begin(struct gpmi_nand_data *this) * we can use the GPMI. Calculate the amount of time we need to wait, * in microseconds. */ - clock_period_in_ns = NSEC_PER_SEC / clk_get_rate(r->clock[0]); + clock_period_in_ns = NSEC_PER_SEC / hw->clk_rate; dll_wait_time_in_us = (clock_period_in_ns * 64) / 1000; if (!dll_wait_time_in_us) @@ -1066,14 +915,45 @@ void gpmi_begin(struct gpmi_nand_data *this) /* Wait for the DLL to settle. */ udelay(dll_wait_time_in_us); - -err_out: - return; } -void gpmi_end(struct gpmi_nand_data *this) +int gpmi_setup_data_interface(struct mtd_info *mtd, int chipnr, + const struct nand_data_interface *conf) { - gpmi_disable_clk(this); + struct nand_chip *chip = mtd_to_nand(mtd); + struct gpmi_nand_data *this = nand_get_controller_data(chip); + const struct nand_sdr_timings *sdr; + bool edo_mode = false; + + /* Retrieve required NAND timings */ + sdr = nand_get_sdr_timings(conf); + if (IS_ERR(sdr)) + return PTR_ERR(sdr); + + if (sdr->tRC_min <= 25000) + edo_mode = true; + + /* Only MX6 GPMI controller can reach EDO timings */ + if (edo_mode && !GPMI_IS_MX6(this)) + return -ENOTSUPP; + + if (chipnr < 0) + return 0; + + this->timing.tREA_in_ns = sdr->tREA_max / 1000; + this->timing.tRLOH_in_ns = sdr->tRLOH_min / 1000; + this->timing.tRHOH_in_ns = sdr->tRHOH_min / 1000; + + /* Compute GPMI parameters depending on the mode */ + if (edo_mode) + gpmi_nfc_compute_edo_timings(this, + sdr->tRC_min > 20000 ? 4 : 5); + else + gpmi_nfc_compute_hardware_timings(this); + + this->hw.must_apply_timings = true; + + return 0; } /* Clears a BCH interrupt. */ diff --git a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c index 61fdd733492f..e7e01934f50d 100644 --- a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c +++ b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c @@ -938,11 +938,32 @@ static void gpmi_select_chip(struct mtd_info *mtd, int chipnr) { struct nand_chip *chip = mtd_to_nand(mtd); struct gpmi_nand_data *this = nand_get_controller_data(chip); + int ret; - if ((this->current_chip < 0) && (chipnr >= 0)) - gpmi_begin(this); - else if ((this->current_chip >= 0) && (chipnr < 0)) - gpmi_end(this); + /* + * For power consumption matters, disable/enable the clock each time a + * die is selected/unselected. + */ + if (this->current_chip < 0 && chipnr >= 0) { + ret = gpmi_enable_clk(this); + if (ret) + dev_err(this->dev, "Failed to enable the clock\n"); + } else if (this->current_chip >= 0 && chipnr < 0) { + ret = gpmi_disable_clk(this); + if (ret) + dev_err(this->dev, "Failed to disable the clock\n"); + } + + /* + * This driver currently supports only one NAND chip. Plus, dies share + * the same configuration. So once timings have been applied on the + * controller side, they will not change anymore. When the time will + * come, the check on must_apply_timings will have to be dropped. + */ + if (chipnr >= 0 && this->hw.must_apply_timings) { + this->hw.must_apply_timings = false; + gpmi_nfc_apply_timings(this); + } this->current_chip = chipnr; } @@ -1955,14 +1976,6 @@ static int gpmi_init_last(struct gpmi_nand_data *this) chip->options |= NAND_SUBPAGE_READ; } - /* - * Can we enable the extra features? such as EDO or Sync mode. - * - * We do not check the return value now. That's means if we fail in - * enable the extra features, we still can run in the normal way. - */ - gpmi_extra_init(this); - return 0; } @@ -1983,6 +1996,7 @@ static int gpmi_nand_init(struct gpmi_nand_data *this) nand_set_controller_data(chip, this); nand_set_flash_node(chip, this->pdev->dev.of_node); chip->select_chip = gpmi_select_chip; + chip->setup_data_interface = gpmi_setup_data_interface; chip->cmd_ctrl = gpmi_cmd_ctrl; chip->dev_ready = gpmi_dev_ready; chip->read_byte = gpmi_read_byte; @@ -2141,7 +2155,6 @@ static int gpmi_pm_resume(struct device *dev) return ret; /* re-init the GPMI registers */ - this->flags &= ~GPMI_TIMING_INIT_OK; ret = gpmi_init(this); if (ret) { dev_err(this->dev, "Error setting GPMI : %d\n", ret); @@ -2155,9 +2168,6 @@ static int gpmi_pm_resume(struct device *dev) return ret; } - /* re-init others */ - gpmi_extra_init(this); - return 0; } #endif /* CONFIG_PM_SLEEP */ diff --git a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.h b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.h index 06c1f993912c..23f9030cf6d2 100644 --- a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.h +++ b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.h @@ -135,11 +135,47 @@ struct gpmi_devdata { const int clks_count; }; +/** + * struct gpmi_nfc_hardware_timing - GPMI hardware timing parameters. + * @timing_mode: The timing mode to comply with. + * @must_apply_timings: Whether controller timings have already been + * applied or not (useful only while there is + * support for only one chip select) + * @clk_rate: The clock rate that must be used to derive the + * following parameters. + * @data_setup_in_cycles: The data setup time, in cycles. + * @data_hold_in_cycles: The data hold time, in cycles. + * @address_setup_in_cycles: The address setup time, in cycles. + * @device_busy_timeout: The timeout waiting for NAND Ready/Busy, + * this value is the number of cycles multiplied + * by 4096. + * @use_half_periods: Indicates the clock is running slowly, so the + * NFC DLL should use half-periods. + * @sample_delay_factor: The sample delay factor. + * @wrn_dly_sel: The delay on the GPMI write strobe. + */ +struct gpmi_nfc_hardware_timing { + unsigned int timing_mode; + bool must_apply_timings; + unsigned long int clk_rate; + + /* for HW_GPMI_TIMING0 */ + u8 data_setup_in_cycles; + u8 data_hold_in_cycles; + u8 address_setup_in_cycles; + + /* for HW_GPMI_TIMING1 */ + u16 device_busy_timeout; +#define GPMI_DEFAULT_BUSY_TIMEOUT 0x500 /* default busy timeout value.*/ + + /* for HW_GPMI_CTRL1 */ + bool use_half_periods; + u8 sample_delay_factor; + u8 wrn_dly_sel; +}; + struct gpmi_nand_data { - /* flags */ -#define GPMI_ASYNC_EDO_ENABLED (1 << 0) -#define GPMI_TIMING_INIT_OK (1 << 1) - int flags; + /* Devdata */ const struct gpmi_devdata *devdata; /* System Interface */ @@ -152,6 +188,7 @@ struct gpmi_nand_data { /* Flash Hardware */ struct nand_timing timing; int timing_mode; + struct gpmi_nfc_hardware_timing hw; /* BCH */ struct bch_geometry bch_geometry; @@ -204,35 +241,6 @@ struct gpmi_nand_data { void *private; }; -/** - * struct gpmi_nfc_hardware_timing - GPMI hardware timing parameters. - * @data_setup_in_cycles: The data setup time, in cycles. - * @data_hold_in_cycles: The data hold time, in cycles. - * @address_setup_in_cycles: The address setup time, in cycles. - * @device_busy_timeout: The timeout waiting for NAND Ready/Busy, - * this value is the number of cycles multiplied - * by 4096. - * @use_half_periods: Indicates the clock is running slowly, so the - * NFC DLL should use half-periods. - * @sample_delay_factor: The sample delay factor. - * @wrn_dly_sel: The delay on the GPMI write strobe. - */ -struct gpmi_nfc_hardware_timing { - /* for HW_GPMI_TIMING0 */ - uint8_t data_setup_in_cycles; - uint8_t data_hold_in_cycles; - uint8_t address_setup_in_cycles; - - /* for HW_GPMI_TIMING1 */ - uint16_t device_busy_timeout; -#define GPMI_DEFAULT_BUSY_TIMEOUT 0x500 /* default busy timeout value.*/ - - /* for HW_GPMI_CTRL1 */ - bool use_half_periods; - uint8_t sample_delay_factor; - uint8_t wrn_dly_sel; -}; - /** * struct timing_threshold - Timing threshold * @max_data_setup_cycles: The maximum number of data setup cycles that @@ -279,14 +287,16 @@ int start_dma_with_bch_irq(struct gpmi_nand_data *, /* GPMI-NAND helper function library */ int gpmi_init(struct gpmi_nand_data *); -int gpmi_extra_init(struct gpmi_nand_data *); void gpmi_clear_bch(struct gpmi_nand_data *); void gpmi_dump_info(struct gpmi_nand_data *); int bch_set_geometry(struct gpmi_nand_data *); int gpmi_is_ready(struct gpmi_nand_data *, unsigned chip); int gpmi_send_command(struct gpmi_nand_data *); -void gpmi_begin(struct gpmi_nand_data *); -void gpmi_end(struct gpmi_nand_data *); +int gpmi_enable_clk(struct gpmi_nand_data *this); +int gpmi_disable_clk(struct gpmi_nand_data *this); +int gpmi_setup_data_interface(struct mtd_info *mtd, int chipnr, + const struct nand_data_interface *conf); +void gpmi_nfc_apply_timings(struct gpmi_nand_data *this); int gpmi_read_data(struct gpmi_nand_data *); int gpmi_send_data(struct gpmi_nand_data *); int gpmi_send_page(struct gpmi_nand_data *, From b1206122069aadabe1a8c50789277a978aaa4df7 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Fri, 2 Mar 2018 15:38:40 +0100 Subject: [PATCH 59/89] mtd: rawnand: gpmi: use core timings instead of an empirical derivation GPMI driver timings derivation looks very empirical and does not use the known timings that the core wants to use with the NAND chip, by using local defined constants that have no special meaning from the outside world. Simplify the way all of this is computed and use the NAND core's SDR timings. Integrity of the reads/writes has been checked with nandbiterrs, speed improvements with flash_speed on a Freescale i.MX6 DualLite/Solo SABRE Automotive Board. Measures are below, variations of less than 150kiB/s between tests are common and then not significant. Speeds using mode 5 are the same, while speeds using mode 0 are quite improved (+40/50% from non-optimal computation). Forcing timings mode 0: ======================= Before this patch: ------------------ eraseblock write speed is 2298 KiB/s eraseblock read speed is 3636 KiB/s page write speed is 2136 KiB/s page read speed is 3316 KiB/s 2 page write speed is 2199 KiB/s 2 page read speed is 3468 KiB/s After this patch: ----------------- eraseblock write speed is 3232 KiB/s eraseblock read speed is 5663 KiB/s page write speed is 2915 KiB/s page read speed is 4904 KiB/s 2 page write speed is 3084 KiB/s 2 page read speed is 5267 KiB/s Forcing timings mode 5: ======================= Before this patch: ------------------ eraseblock write speed is 4338 KiB/s eraseblock read speed is 14883 KiB/s page write speed is 3786 KiB/s page read speed is 12800 KiB/s 2 page write speed is 4076 KiB/s 2 page read speed is 14065 KiB/s After this patch: ----------------- eraseblock write speed is 4309 KiB/s eraseblock read speed is 14712 KiB/s page write speed is 3764 KiB/s page read speed is 12673 KiB/s 2 page write speed is 4076 KiB/s 2 page read speed is 14065 KiB/s Signed-off-by: Miquel Raynal Signed-off-by: Boris Brezillon --- drivers/mtd/nand/raw/gpmi-nand/gpmi-lib.c | 615 +++------------------ drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c | 40 +- drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.h | 103 +--- drivers/mtd/nand/raw/gpmi-nand/gpmi-regs.h | 5 + 4 files changed, 103 insertions(+), 660 deletions(-) diff --git a/drivers/mtd/nand/raw/gpmi-nand/gpmi-lib.c b/drivers/mtd/nand/raw/gpmi-nand/gpmi-lib.c index cf71cb9cee6a..e94556705dc7 100644 --- a/drivers/mtd/nand/raw/gpmi-nand/gpmi-lib.c +++ b/drivers/mtd/nand/raw/gpmi-nand/gpmi-lib.c @@ -26,15 +26,8 @@ #include "gpmi-regs.h" #include "bch-regs.h" -static struct timing_threshold timing_default_threshold = { - .max_data_setup_cycles = (BM_GPMI_TIMING0_DATA_SETUP >> - BP_GPMI_TIMING0_DATA_SETUP), - .internal_data_setup_in_ns = 0, - .max_sample_delay_factor = (BM_GPMI_CTRL1_RDN_DELAY >> - BP_GPMI_CTRL1_RDN_DELAY), - .max_dll_clock_period_in_ns = 32, - .max_dll_delay_in_ns = 16, -}; +/* Converts time to clock cycles */ +#define TO_CYCLES(duration, period) DIV_ROUND_UP_ULL(duration, period) #define MXS_SET_ADDR 0x4 #define MXS_CLR_ADDR 0x8 @@ -181,7 +174,6 @@ int gpmi_init(struct gpmi_nand_data *this) if (ret) goto err_out; - /* Choose NAND mode. */ writel(BM_GPMI_CTRL1_GPMI_MODE, r->gpmi_regs + HW_GPMI_CTRL1_CLR); @@ -320,399 +312,6 @@ err_out: return ret; } -/* Converts time in nanoseconds to cycles. */ -static unsigned int ns_to_cycles(unsigned int time, - unsigned int period, unsigned int min) -{ - unsigned int k; - - k = (time + period - 1) / period; - return max(k, min); -} - -#define DEF_MIN_PROP_DELAY 5 -#define DEF_MAX_PROP_DELAY 9 -/* Apply timing to current hardware conditions. */ -static void -gpmi_nfc_compute_hardware_timings(struct gpmi_nand_data *this) -{ - struct gpmi_nfc_hardware_timing *hw = &this->hw; - struct timing_threshold *nfc = &timing_default_threshold; - struct nand_chip *nand = &this->nand; - struct nand_timing target = this->timing; - unsigned long clock_frequency_in_hz; - unsigned int clock_period_in_ns; - bool dll_use_half_periods; - unsigned int dll_delay_shift; - unsigned int max_sample_delay_in_ns; - unsigned int address_setup_in_cycles; - unsigned int data_setup_in_ns; - unsigned int data_setup_in_cycles; - unsigned int data_hold_in_cycles; - int ideal_sample_delay_in_ns; - unsigned int sample_delay_factor; - int tEYE; - unsigned int min_prop_delay_in_ns = DEF_MIN_PROP_DELAY; - unsigned int max_prop_delay_in_ns = DEF_MAX_PROP_DELAY; - - /* Clock rate for non-EDO modes */ - hw->clk_rate = 22000000; - - /* - * If there are multiple chips, we need to relax the timings to allow - * for signal distortion due to higher capacitance. - */ - if (nand->numchips > 2) { - target.data_setup_in_ns += 10; - target.data_hold_in_ns += 10; - target.address_setup_in_ns += 10; - } else if (nand->numchips > 1) { - target.data_setup_in_ns += 5; - target.data_hold_in_ns += 5; - target.address_setup_in_ns += 5; - } - - /* Inspect the clock. */ - nfc->clock_frequency_in_hz = hw->clk_rate; - clock_frequency_in_hz = nfc->clock_frequency_in_hz; - clock_period_in_ns = NSEC_PER_SEC / clock_frequency_in_hz; - - /* - * The NFC quantizes setup and hold parameters in terms of clock cycles. - * Here, we quantize the setup and hold timing parameters to the - * next-highest clock period to make sure we apply at least the - * specified times. - * - * For data setup and data hold, the hardware interprets a value of zero - * as the largest possible delay. This is not what's intended by a zero - * in the input parameter, so we impose a minimum of one cycle. - */ - data_setup_in_cycles = ns_to_cycles(target.data_setup_in_ns, - clock_period_in_ns, 1); - data_hold_in_cycles = ns_to_cycles(target.data_hold_in_ns, - clock_period_in_ns, 1); - address_setup_in_cycles = ns_to_cycles(target.address_setup_in_ns, - clock_period_in_ns, 0); - - /* - * The clock's period affects the sample delay in a number of ways: - * - * (1) The NFC HAL tells us the maximum clock period the sample delay - * DLL can tolerate. If the clock period is greater than half that - * maximum, we must configure the DLL to be driven by half periods. - * - * (2) We need to convert from an ideal sample delay, in ns, to a - * "sample delay factor," which the NFC uses. This factor depends on - * whether we're driving the DLL with full or half periods. - * Paraphrasing the reference manual: - * - * AD = SDF x 0.125 x RP - * - * where: - * - * AD is the applied delay, in ns. - * SDF is the sample delay factor, which is dimensionless. - * RP is the reference period, in ns, which is a full clock period - * if the DLL is being driven by full periods, or half that if - * the DLL is being driven by half periods. - * - * Let's re-arrange this in a way that's more useful to us: - * - * 8 - * SDF = AD x ---- - * RP - * - * The reference period is either the clock period or half that, so this - * is: - * - * 8 AD x DDF - * SDF = AD x ----- = -------- - * f x P P - * - * where: - * - * f is 1 or 1/2, depending on how we're driving the DLL. - * P is the clock period. - * DDF is the DLL Delay Factor, a dimensionless value that - * incorporates all the constants in the conversion. - * - * DDF will be either 8 or 16, both of which are powers of two. We can - * reduce the cost of this conversion by using bit shifts instead of - * multiplication or division. Thus: - * - * AD << DDS - * SDF = --------- - * P - * - * or - * - * AD = (SDF >> DDS) x P - * - * where: - * - * DDS is the DLL Delay Shift, the logarithm to base 2 of the DDF. - */ - if (clock_period_in_ns > (nfc->max_dll_clock_period_in_ns >> 1)) { - dll_use_half_periods = true; - dll_delay_shift = 3 + 1; - } else { - dll_use_half_periods = false; - dll_delay_shift = 3; - } - - /* - * Compute the maximum sample delay the NFC allows, under current - * conditions. If the clock is running too slowly, no sample delay is - * possible. - */ - if (clock_period_in_ns > nfc->max_dll_clock_period_in_ns) - max_sample_delay_in_ns = 0; - else { - /* - * Compute the delay implied by the largest sample delay factor - * the NFC allows. - */ - max_sample_delay_in_ns = - (nfc->max_sample_delay_factor * clock_period_in_ns) >> - dll_delay_shift; - - /* - * Check if the implied sample delay larger than the NFC - * actually allows. - */ - if (max_sample_delay_in_ns > nfc->max_dll_delay_in_ns) - max_sample_delay_in_ns = nfc->max_dll_delay_in_ns; - } - - /* - * Fold the read setup time required by the NFC into the maximum - * propagation delay. - */ - max_prop_delay_in_ns += nfc->internal_data_setup_in_ns; - - /* - * Earlier, we computed the number of clock cycles required to satisfy - * the data setup time. Now, we need to know the actual nanoseconds. - */ - data_setup_in_ns = clock_period_in_ns * data_setup_in_cycles; - - /* - * Compute tEYE, the width of the data eye when reading from the NAND - * Flash. The eye width is fundamentally determined by the data setup - * time, perturbed by propagation delays and some characteristics of the - * NAND Flash device. - * - * start of the eye = max_prop_delay + tREA - * end of the eye = min_prop_delay + tRHOH + data_setup - */ - tEYE = (int)min_prop_delay_in_ns + (int)target.tRHOH_in_ns + - (int)data_setup_in_ns; - - tEYE -= (int)max_prop_delay_in_ns + (int)target.tREA_in_ns; - - /* - * The eye must be open. If it's not, we can try to open it by - * increasing its main forcer, the data setup time. - * - * In each iteration of the following loop, we increase the data setup - * time by a single clock cycle. We do this until either the eye is - * open or we run into NFC limits. - */ - while ((tEYE <= 0) && - (data_setup_in_cycles < nfc->max_data_setup_cycles)) { - /* Give a cycle to data setup. */ - data_setup_in_cycles++; - /* Synchronize the data setup time with the cycles. */ - data_setup_in_ns += clock_period_in_ns; - /* Adjust tEYE accordingly. */ - tEYE += clock_period_in_ns; - } - - /* - * When control arrives here, the eye is open. The ideal time to sample - * the data is in the center of the eye: - * - * end of the eye + start of the eye - * --------------------------------- - data_setup - * 2 - * - * After some algebra, this simplifies to the code immediately below. - */ - ideal_sample_delay_in_ns = - ((int)max_prop_delay_in_ns + - (int)target.tREA_in_ns + - (int)min_prop_delay_in_ns + - (int)target.tRHOH_in_ns - - (int)data_setup_in_ns) >> 1; - - /* - * The following figure illustrates some aspects of a NAND Flash read: - * - * - * __ _____________________________________ - * RDN \_________________/ - * - * <---- tEYE -----> - * /-----------------\ - * Read Data ----------------------------< >--------- - * \-----------------/ - * ^ ^ ^ ^ - * | | | | - * |<--Data Setup -->|<--Delay Time -->| | - * | | | | - * | | | - * | |<-- Quantized Delay Time -->| - * | | | - * - * - * We have some issues we must now address: - * - * (1) The *ideal* sample delay time must not be negative. If it is, we - * jam it to zero. - * - * (2) The *ideal* sample delay time must not be greater than that - * allowed by the NFC. If it is, we can increase the data setup - * time, which will reduce the delay between the end of the data - * setup and the center of the eye. It will also make the eye - * larger, which might help with the next issue... - * - * (3) The *quantized* sample delay time must not fall either before the - * eye opens or after it closes (the latter is the problem - * illustrated in the above figure). - */ - - /* Jam a negative ideal sample delay to zero. */ - if (ideal_sample_delay_in_ns < 0) - ideal_sample_delay_in_ns = 0; - - /* - * Extend the data setup as needed to reduce the ideal sample delay - * below the maximum permitted by the NFC. - */ - while ((ideal_sample_delay_in_ns > max_sample_delay_in_ns) && - (data_setup_in_cycles < nfc->max_data_setup_cycles)) { - - /* Give a cycle to data setup. */ - data_setup_in_cycles++; - /* Synchronize the data setup time with the cycles. */ - data_setup_in_ns += clock_period_in_ns; - /* Adjust tEYE accordingly. */ - tEYE += clock_period_in_ns; - - /* - * Decrease the ideal sample delay by one half cycle, to keep it - * in the middle of the eye. - */ - ideal_sample_delay_in_ns -= (clock_period_in_ns >> 1); - - /* Jam a negative ideal sample delay to zero. */ - if (ideal_sample_delay_in_ns < 0) - ideal_sample_delay_in_ns = 0; - } - - /* - * Compute the sample delay factor that corresponds to the ideal sample - * delay. If the result is too large, then use the maximum allowed - * value. - * - * Notice that we use the ns_to_cycles function to compute the sample - * delay factor. We do this because the form of the computation is the - * same as that for calculating cycles. - */ - sample_delay_factor = - ns_to_cycles(ideal_sample_delay_in_ns << dll_delay_shift, - clock_period_in_ns, 0); - - if (sample_delay_factor > nfc->max_sample_delay_factor) - sample_delay_factor = nfc->max_sample_delay_factor; - - /* - * These macros conveniently encapsulate a computation we'll use to - * continuously evaluate whether or not the data sample delay is inside - * the eye. - */ - #define IDEAL_DELAY ((int) ideal_sample_delay_in_ns) - - #define QUANTIZED_DELAY \ - ((int) ((sample_delay_factor * clock_period_in_ns) >> \ - dll_delay_shift)) - - #define DELAY_ERROR (abs(QUANTIZED_DELAY - IDEAL_DELAY)) - - #define SAMPLE_IS_NOT_WITHIN_THE_EYE (DELAY_ERROR > (tEYE >> 1)) - - /* - * While the quantized sample time falls outside the eye, reduce the - * sample delay or extend the data setup to move the sampling point back - * toward the eye. Do not allow the number of data setup cycles to - * exceed the maximum allowed by the NFC. - */ - while (SAMPLE_IS_NOT_WITHIN_THE_EYE && - (data_setup_in_cycles < nfc->max_data_setup_cycles)) { - /* - * If control arrives here, the quantized sample delay falls - * outside the eye. Check if it's before the eye opens, or after - * the eye closes. - */ - if (QUANTIZED_DELAY > IDEAL_DELAY) { - /* - * If control arrives here, the quantized sample delay - * falls after the eye closes. Decrease the quantized - * delay time and then go back to re-evaluate. - */ - if (sample_delay_factor != 0) - sample_delay_factor--; - continue; - } - - /* - * If control arrives here, the quantized sample delay falls - * before the eye opens. Shift the sample point by increasing - * data setup time. This will also make the eye larger. - */ - - /* Give a cycle to data setup. */ - data_setup_in_cycles++; - /* Synchronize the data setup time with the cycles. */ - data_setup_in_ns += clock_period_in_ns; - /* Adjust tEYE accordingly. */ - tEYE += clock_period_in_ns; - - /* - * Decrease the ideal sample delay by one half cycle, to keep it - * in the middle of the eye. - */ - ideal_sample_delay_in_ns -= (clock_period_in_ns >> 1); - - /* ...and one less period for the delay time. */ - ideal_sample_delay_in_ns -= clock_period_in_ns; - - /* Jam a negative ideal sample delay to zero. */ - if (ideal_sample_delay_in_ns < 0) - ideal_sample_delay_in_ns = 0; - - /* - * We have a new ideal sample delay, so re-compute the quantized - * delay. - */ - sample_delay_factor = - ns_to_cycles( - ideal_sample_delay_in_ns << dll_delay_shift, - clock_period_in_ns, 0); - - if (sample_delay_factor > nfc->max_sample_delay_factor) - sample_delay_factor = nfc->max_sample_delay_factor; - } - - hw->data_setup_in_cycles = data_setup_in_cycles; - hw->data_hold_in_cycles = data_hold_in_cycles; - hw->address_setup_in_cycles = address_setup_in_cycles; - hw->use_half_periods = dll_use_half_periods; - hw->sample_delay_factor = sample_delay_factor; - hw->device_busy_timeout = GPMI_DEFAULT_BUSY_TIMEOUT; - hw->wrn_dly_sel = BV_GPMI_CTRL1_WRN_DLY_SEL_4_TO_8NS; -} - /* * <1> Firstly, we should know what's the GPMI-clock means. * The GPMI-clock is the internal clock in the gpmi nand controller. @@ -763,13 +362,10 @@ gpmi_nfc_compute_hardware_timings(struct gpmi_nand_data *this) * 4.1) From the aspect of the nand chip pins: * Delay = (tREA + C - tRP) {1} * - * tREA : the maximum read access time. From the ONFI nand standards, - * we know that tREA is 16ns in mode 5, tREA is 20ns is mode 4. - * Please check it in : www.onfi.org - * C : a constant for adjust the delay. default is 4. - * tRP : the read pulse width. - * Specified by the HW_GPMI_TIMING0:DATA_SETUP: - * tRP = (GPMI-clock-period) * DATA_SETUP + * tREA : the maximum read access time. + * C : a constant to adjust the delay. default is 4000ps. + * tRP : the read pulse width, which is exactly: + * tRP = (GPMI-clock-period) * DATA_SETUP * * 4.2) From the aspect of the GPMI nand controller: * Delay = RDN_DELAY * 0.125 * RP {2} @@ -782,74 +378,81 @@ gpmi_nfc_compute_hardware_timings(struct gpmi_nand_data *this) * * Set the HW_GPMI_CTRL1:HALF_PERIOD if GPMI-clock-period * is greater DLL_THRETHOLD. In other SOCs, the DLL_THRETHOLD - * is 16ns, but in mx6q, we use 12ns. + * is 16000ps, but in mx6q, we use 12000ps. * * 4.3) since {1} equals {2}, we get: * - * (tREA + 4 - tRP) * 8 - * RDN_DELAY = --------------------- {3} + * (tREA + 4000 - tRP) * 8 + * RDN_DELAY = ----------------------- {3} * RP - * - * 4.4) We only support the fastest asynchronous mode of ONFI nand. - * For some ONFI nand, the mode 4 is the fastest mode; - * while for some ONFI nand, the mode 5 is the fastest mode. - * So we only support the mode 4 and mode 5. It is no need to - * support other modes. */ -static void gpmi_nfc_compute_edo_timings(struct gpmi_nand_data *this, - int mode) +static void gpmi_nfc_compute_timings(struct gpmi_nand_data *this, + const struct nand_sdr_timings *sdr) { struct gpmi_nfc_hardware_timing *hw = &this->hw; - int dll_threshold = this->devdata->max_chain_delay; - unsigned long delay; - unsigned long clk_period; - int t_rp, t_rea, rp; + unsigned int dll_threshold_ps = this->devdata->max_chain_delay; + unsigned int period_ps, reference_period_ps; + unsigned int data_setup_cycles, data_hold_cycles, addr_setup_cycles; + unsigned int tRP_ps; + bool use_half_period; + int sample_delay_ps, sample_delay_factor; + u16 busy_timeout_cycles; + u8 wrn_dly_sel; - /* Set the main clock to: 100MHz (mode 5) or 80MHz (mode 4) */ - hw->clk_rate = (mode == 5) ? 100000000 : 80000000; - - /* - * [1] for GPMI_HW_GPMI_TIMING0: - * The async mode requires 40MHz for mode 4, 50MHz for mode 5. - * The GPMI can support 100MHz at most. So if we want to - * get the 40MHz or 50MHz, we have to set DS=1, DH=1. - * Set the ADDRESS_SETUP to 0 in mode 4. - */ - hw->data_setup_in_cycles = 1; - hw->data_hold_in_cycles = 1; - hw->address_setup_in_cycles = (mode == 5) ? 1 : 0; - - /* [2] for GPMI_HW_GPMI_TIMING1 */ - hw->device_busy_timeout = 0x9000; - - /* [3] for GPMI_HW_GPMI_CTRL1 */ - hw->wrn_dly_sel = BV_GPMI_CTRL1_WRN_DLY_SEL_NO_DELAY; - - /* - * Enlarge 10 times for the numerator and denominator in {3}. - * This make us to get more accurate result. - */ - clk_period = NSEC_PER_SEC / (hw->clk_rate / 10); - dll_threshold *= 10; - t_rea = this->timing.tREA_in_ns * 10; - t_rp = clk_period * 1; /* DATA_SETUP is 1 */ - - if (clk_period > dll_threshold) { - hw->use_half_periods = 1; - rp = clk_period / 2; + if (sdr->tRC_min >= 30000) { + /* ONFI non-EDO modes [0-3] */ + hw->clk_rate = 22000000; + wrn_dly_sel = BV_GPMI_CTRL1_WRN_DLY_SEL_4_TO_8NS; + } else if (sdr->tRC_min >= 25000) { + /* ONFI EDO mode 4 */ + hw->clk_rate = 80000000; + wrn_dly_sel = BV_GPMI_CTRL1_WRN_DLY_SEL_NO_DELAY; } else { - hw->use_half_periods = 0; - rp = clk_period; + /* ONFI EDO mode 5 */ + hw->clk_rate = 100000000; + wrn_dly_sel = BV_GPMI_CTRL1_WRN_DLY_SEL_NO_DELAY; } - /* - * Multiply the numerator with 10, we could do a round off: - * 7.8 round up to 8; 7.4 round down to 7. - */ - delay = (((t_rea + 40 - t_rp) * 8) * 10) / rp; - delay = (delay + 5) / 10; + /* SDR core timings are given in picoseconds */ + period_ps = div_u64((u64)NSEC_PER_SEC * 1000, hw->clk_rate); - hw->sample_delay_factor = delay; + addr_setup_cycles = TO_CYCLES(sdr->tALS_min, period_ps); + data_setup_cycles = TO_CYCLES(sdr->tDS_min, period_ps); + data_hold_cycles = TO_CYCLES(sdr->tDH_min, period_ps); + busy_timeout_cycles = TO_CYCLES(sdr->tWB_max + sdr->tR_max, period_ps); + + hw->timing0 = BF_GPMI_TIMING0_ADDRESS_SETUP(addr_setup_cycles) | + BF_GPMI_TIMING0_DATA_HOLD(data_hold_cycles) | + BF_GPMI_TIMING0_DATA_SETUP(data_setup_cycles); + hw->timing1 = BF_GPMI_TIMING1_BUSY_TIMEOUT(busy_timeout_cycles * 4096); + + /* + * Derive NFC ideal delay from {3}: + * + * (tREA + 4000 - tRP) * 8 + * RDN_DELAY = ----------------------- + * RP + */ + if (period_ps > dll_threshold_ps) { + use_half_period = true; + reference_period_ps = period_ps / 2; + } else { + use_half_period = false; + reference_period_ps = period_ps; + } + + tRP_ps = data_setup_cycles * period_ps; + sample_delay_ps = (sdr->tREA_max + 4000 - tRP_ps) * 8; + if (sample_delay_ps > 0) + sample_delay_factor = sample_delay_ps / reference_period_ps; + else + sample_delay_factor = 0; + + hw->ctrl1n = BF_GPMI_CTRL1_WRN_DLY_SEL(wrn_dly_sel); + if (sample_delay_factor) + hw->ctrl1n |= BF_GPMI_CTRL1_RDN_DELAY(sample_delay_factor) | + BM_GPMI_CTRL1_DLL_ENABLE | + (use_half_period ? BM_GPMI_CTRL1_HALF_PERIOD : 0); } void gpmi_nfc_apply_timings(struct gpmi_nand_data *this) @@ -857,64 +460,27 @@ void gpmi_nfc_apply_timings(struct gpmi_nand_data *this) struct gpmi_nfc_hardware_timing *hw = &this->hw; struct resources *r = &this->resources; void __iomem *gpmi_regs = r->gpmi_regs; - unsigned int clock_period_in_ns; - uint32_t reg; - unsigned int dll_wait_time_in_us; + unsigned int dll_wait_time_us; - /* [0] Set the main clock rate */ clk_set_rate(r->clock[0], hw->clk_rate); - /* [1] Set HW_GPMI_TIMING0 */ - reg = BF_GPMI_TIMING0_ADDRESS_SETUP(hw->address_setup_in_cycles) | - BF_GPMI_TIMING0_DATA_HOLD(hw->data_hold_in_cycles) | - BF_GPMI_TIMING0_DATA_SETUP(hw->data_setup_in_cycles); - - writel(reg, gpmi_regs + HW_GPMI_TIMING0); - - /* [2] Set HW_GPMI_TIMING1 */ - writel(BF_GPMI_TIMING1_BUSY_TIMEOUT(hw->device_busy_timeout), - gpmi_regs + HW_GPMI_TIMING1); - - /* [3] The following code is to set the HW_GPMI_CTRL1. */ - - /* Set the WRN_DLY_SEL */ - writel(BM_GPMI_CTRL1_WRN_DLY_SEL, gpmi_regs + HW_GPMI_CTRL1_CLR); - writel(BF_GPMI_CTRL1_WRN_DLY_SEL(hw->wrn_dly_sel), - gpmi_regs + HW_GPMI_CTRL1_SET); - - /* DLL_ENABLE must be set to 0 when setting RDN_DELAY or HALF_PERIOD. */ - writel(BM_GPMI_CTRL1_DLL_ENABLE, gpmi_regs + HW_GPMI_CTRL1_CLR); - - /* Clear out the DLL control fields. */ - reg = BM_GPMI_CTRL1_RDN_DELAY | BM_GPMI_CTRL1_HALF_PERIOD; - writel(reg, gpmi_regs + HW_GPMI_CTRL1_CLR); - - /* If no sample delay is called for, return immediately. */ - if (!hw->sample_delay_factor) - return; - - /* Set RDN_DELAY or HALF_PERIOD. */ - reg = ((hw->use_half_periods) ? BM_GPMI_CTRL1_HALF_PERIOD : 0) - | BF_GPMI_CTRL1_RDN_DELAY(hw->sample_delay_factor); - - writel(reg, gpmi_regs + HW_GPMI_CTRL1_SET); - - /* At last, we enable the DLL. */ - writel(BM_GPMI_CTRL1_DLL_ENABLE, gpmi_regs + HW_GPMI_CTRL1_SET); + writel(hw->timing0, gpmi_regs + HW_GPMI_TIMING0); + writel(hw->timing1, gpmi_regs + HW_GPMI_TIMING1); /* - * After we enable the GPMI DLL, we have to wait 64 clock cycles before - * we can use the GPMI. Calculate the amount of time we need to wait, - * in microseconds. + * Clear several CTRL1 fields, DLL must be disabled when setting + * RDN_DELAY or HALF_PERIOD. */ - clock_period_in_ns = NSEC_PER_SEC / hw->clk_rate; - dll_wait_time_in_us = (clock_period_in_ns * 64) / 1000; + writel(BM_GPMI_CTRL1_CLEAR_MASK, gpmi_regs + HW_GPMI_CTRL1_CLR); + writel(hw->ctrl1n, gpmi_regs + HW_GPMI_CTRL1_SET); - if (!dll_wait_time_in_us) - dll_wait_time_in_us = 1; + /* Wait 64 clock cycles before using the GPMI after enabling the DLL */ + dll_wait_time_us = USEC_PER_SEC / hw->clk_rate * 64; + if (!dll_wait_time_us) + dll_wait_time_us = 1; /* Wait for the DLL to settle. */ - udelay(dll_wait_time_in_us); + udelay(dll_wait_time_us); } int gpmi_setup_data_interface(struct mtd_info *mtd, int chipnr, @@ -923,33 +489,22 @@ int gpmi_setup_data_interface(struct mtd_info *mtd, int chipnr, struct nand_chip *chip = mtd_to_nand(mtd); struct gpmi_nand_data *this = nand_get_controller_data(chip); const struct nand_sdr_timings *sdr; - bool edo_mode = false; /* Retrieve required NAND timings */ sdr = nand_get_sdr_timings(conf); if (IS_ERR(sdr)) return PTR_ERR(sdr); - if (sdr->tRC_min <= 25000) - edo_mode = true; - /* Only MX6 GPMI controller can reach EDO timings */ - if (edo_mode && !GPMI_IS_MX6(this)) + if (sdr->tRC_min <= 25000 && !GPMI_IS_MX6(this)) return -ENOTSUPP; + /* Stop here if this call was just a check */ if (chipnr < 0) return 0; - this->timing.tREA_in_ns = sdr->tREA_max / 1000; - this->timing.tRLOH_in_ns = sdr->tRLOH_min / 1000; - this->timing.tRHOH_in_ns = sdr->tRHOH_min / 1000; - - /* Compute GPMI parameters depending on the mode */ - if (edo_mode) - gpmi_nfc_compute_edo_timings(this, - sdr->tRC_min > 20000 ? 4 : 5); - else - gpmi_nfc_compute_hardware_timings(this); + /* Do the actual derivation of the controller timings */ + gpmi_nfc_compute_timings(this, sdr); this->hw.must_apply_timings = true; diff --git a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c index e7e01934f50d..c2597c8107a0 100644 --- a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c +++ b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c @@ -94,7 +94,7 @@ static const struct mtd_ooblayout_ops gpmi_ooblayout_ops = { static const struct gpmi_devdata gpmi_devdata_imx23 = { .type = IS_MX23, .bch_max_ecc_strength = 20, - .max_chain_delay = 16, + .max_chain_delay = 16000, .clks = gpmi_clks_for_mx2x, .clks_count = ARRAY_SIZE(gpmi_clks_for_mx2x), }; @@ -102,7 +102,7 @@ static const struct gpmi_devdata gpmi_devdata_imx23 = { static const struct gpmi_devdata gpmi_devdata_imx28 = { .type = IS_MX28, .bch_max_ecc_strength = 20, - .max_chain_delay = 16, + .max_chain_delay = 16000, .clks = gpmi_clks_for_mx2x, .clks_count = ARRAY_SIZE(gpmi_clks_for_mx2x), }; @@ -114,7 +114,7 @@ static const char * const gpmi_clks_for_mx6[] = { static const struct gpmi_devdata gpmi_devdata_imx6q = { .type = IS_MX6Q, .bch_max_ecc_strength = 40, - .max_chain_delay = 12, + .max_chain_delay = 12000, .clks = gpmi_clks_for_mx6, .clks_count = ARRAY_SIZE(gpmi_clks_for_mx6), }; @@ -122,7 +122,7 @@ static const struct gpmi_devdata gpmi_devdata_imx6q = { static const struct gpmi_devdata gpmi_devdata_imx6sx = { .type = IS_MX6SX, .bch_max_ecc_strength = 62, - .max_chain_delay = 12, + .max_chain_delay = 12000, .clks = gpmi_clks_for_mx6, .clks_count = ARRAY_SIZE(gpmi_clks_for_mx6), }; @@ -134,7 +134,7 @@ static const char * const gpmi_clks_for_mx7d[] = { static const struct gpmi_devdata gpmi_devdata_imx7d = { .type = IS_MX7D, .bch_max_ecc_strength = 62, - .max_chain_delay = 12, + .max_chain_delay = 12000, .clks = gpmi_clks_for_mx7d, .clks_count = ARRAY_SIZE(gpmi_clks_for_mx7d), }; @@ -695,34 +695,6 @@ static void release_resources(struct gpmi_nand_data *this) release_dma_channels(this); } -static int init_hardware(struct gpmi_nand_data *this) -{ - int ret; - - /* - * This structure contains the "safe" GPMI timing that should succeed - * with any NAND Flash device - * (although, with less-than-optimal performance). - */ - struct nand_timing safe_timing = { - .data_setup_in_ns = 80, - .data_hold_in_ns = 60, - .address_setup_in_ns = 25, - .gpmi_sample_delay_in_ns = 6, - .tREA_in_ns = -1, - .tRLOH_in_ns = -1, - .tRHOH_in_ns = -1, - }; - - /* Initialize the hardwares. */ - ret = gpmi_init(this); - if (ret) - return ret; - - this->timing = safe_timing; - return 0; -} - static int read_page_prepare(struct gpmi_nand_data *this, void *destination, unsigned length, void *alt_virt, dma_addr_t alt_phys, unsigned alt_size, @@ -2107,7 +2079,7 @@ static int gpmi_nand_probe(struct platform_device *pdev) if (ret) goto exit_acquire_resources; - ret = init_hardware(this); + ret = gpmi_init(this); if (ret) goto exit_nfc_init; diff --git a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.h b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.h index 23f9030cf6d2..62fde59b995f 100644 --- a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.h +++ b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.h @@ -86,39 +86,6 @@ enum dma_ops_type { DMA_FOR_WRITE_ECC_PAGE }; -/** - * struct nand_timing - Fundamental timing attributes for NAND. - * @data_setup_in_ns: The data setup time, in nanoseconds. Usually the - * maximum of tDS and tWP. A negative value - * indicates this characteristic isn't known. - * @data_hold_in_ns: The data hold time, in nanoseconds. Usually the - * maximum of tDH, tWH and tREH. A negative value - * indicates this characteristic isn't known. - * @address_setup_in_ns: The address setup time, in nanoseconds. Usually - * the maximum of tCLS, tCS and tALS. A negative - * value indicates this characteristic isn't known. - * @gpmi_sample_delay_in_ns: A GPMI-specific timing parameter. A negative value - * indicates this characteristic isn't known. - * @tREA_in_ns: tREA, in nanoseconds, from the data sheet. A - * negative value indicates this characteristic isn't - * known. - * @tRLOH_in_ns: tRLOH, in nanoseconds, from the data sheet. A - * negative value indicates this characteristic isn't - * known. - * @tRHOH_in_ns: tRHOH, in nanoseconds, from the data sheet. A - * negative value indicates this characteristic isn't - * known. - */ -struct nand_timing { - int8_t data_setup_in_ns; - int8_t data_hold_in_ns; - int8_t address_setup_in_ns; - int8_t gpmi_sample_delay_in_ns; - int8_t tREA_in_ns; - int8_t tRLOH_in_ns; - int8_t tRHOH_in_ns; -}; - enum gpmi_type { IS_MX23, IS_MX28, @@ -137,41 +104,21 @@ struct gpmi_devdata { /** * struct gpmi_nfc_hardware_timing - GPMI hardware timing parameters. - * @timing_mode: The timing mode to comply with. * @must_apply_timings: Whether controller timings have already been * applied or not (useful only while there is * support for only one chip select) * @clk_rate: The clock rate that must be used to derive the - * following parameters. - * @data_setup_in_cycles: The data setup time, in cycles. - * @data_hold_in_cycles: The data hold time, in cycles. - * @address_setup_in_cycles: The address setup time, in cycles. - * @device_busy_timeout: The timeout waiting for NAND Ready/Busy, - * this value is the number of cycles multiplied - * by 4096. - * @use_half_periods: Indicates the clock is running slowly, so the - * NFC DLL should use half-periods. - * @sample_delay_factor: The sample delay factor. - * @wrn_dly_sel: The delay on the GPMI write strobe. + * following parameters + * @timing0: HW_GPMI_TIMING0 register + * @timing1: HW_GPMI_TIMING1 register + * @ctrl1n: HW_GPMI_CTRL1n register */ struct gpmi_nfc_hardware_timing { - unsigned int timing_mode; bool must_apply_timings; unsigned long int clk_rate; - - /* for HW_GPMI_TIMING0 */ - u8 data_setup_in_cycles; - u8 data_hold_in_cycles; - u8 address_setup_in_cycles; - - /* for HW_GPMI_TIMING1 */ - u16 device_busy_timeout; -#define GPMI_DEFAULT_BUSY_TIMEOUT 0x500 /* default busy timeout value.*/ - - /* for HW_GPMI_CTRL1 */ - bool use_half_periods; - u8 sample_delay_factor; - u8 wrn_dly_sel; + u32 timing0; + u32 timing1; + u32 ctrl1n; }; struct gpmi_nand_data { @@ -186,8 +133,6 @@ struct gpmi_nand_data { struct resources resources; /* Flash Hardware */ - struct nand_timing timing; - int timing_mode; struct gpmi_nfc_hardware_timing hw; /* BCH */ @@ -241,40 +186,6 @@ struct gpmi_nand_data { void *private; }; -/** - * struct timing_threshold - Timing threshold - * @max_data_setup_cycles: The maximum number of data setup cycles that - * can be expressed in the hardware. - * @internal_data_setup_in_ns: The time, in ns, that the NFC hardware requires - * for data read internal setup. In the Reference - * Manual, see the chapter "High-Speed NAND - * Timing" for more details. - * @max_sample_delay_factor: The maximum sample delay factor that can be - * expressed in the hardware. - * @max_dll_clock_period_in_ns: The maximum period of the GPMI clock that the - * sample delay DLL hardware can possibly work - * with (the DLL is unusable with longer periods). - * If the full-cycle period is greater than HALF - * this value, the DLL must be configured to use - * half-periods. - * @max_dll_delay_in_ns: The maximum amount of delay, in ns, that the - * DLL can implement. - * @clock_frequency_in_hz: The clock frequency, in Hz, during the current - * I/O transaction. If no I/O transaction is in - * progress, this is the clock frequency during - * the most recent I/O transaction. - */ -struct timing_threshold { - const unsigned int max_chip_count; - const unsigned int max_data_setup_cycles; - const unsigned int internal_data_setup_in_ns; - const unsigned int max_sample_delay_factor; - const unsigned int max_dll_clock_period_in_ns; - const unsigned int max_dll_delay_in_ns; - unsigned long clock_frequency_in_hz; - -}; - /* Common Services */ int common_nfc_set_geometry(struct gpmi_nand_data *); struct dma_chan *get_dma_chan(struct gpmi_nand_data *); diff --git a/drivers/mtd/nand/raw/gpmi-nand/gpmi-regs.h b/drivers/mtd/nand/raw/gpmi-nand/gpmi-regs.h index 82114cdc8330..d92bf32221ca 100644 --- a/drivers/mtd/nand/raw/gpmi-nand/gpmi-regs.h +++ b/drivers/mtd/nand/raw/gpmi-nand/gpmi-regs.h @@ -147,6 +147,11 @@ #define BM_GPMI_CTRL1_GPMI_MODE (1 << 0) +#define BM_GPMI_CTRL1_CLEAR_MASK (BM_GPMI_CTRL1_WRN_DLY_SEL | \ + BM_GPMI_CTRL1_DLL_ENABLE | \ + BM_GPMI_CTRL1_RDN_DELAY | \ + BM_GPMI_CTRL1_HALF_PERIOD) + #define HW_GPMI_TIMING0 0x00000070 #define BP_GPMI_TIMING0_ADDRESS_SETUP 16 From e7bfb3fdbde3bfeeeb64e2d73ac6babe59519c9e Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Mon, 12 Feb 2018 22:03:11 +0100 Subject: [PATCH 60/89] mtd: Stop updating erase_info->state and calling mtd_erase_callback() MTD users are no longer checking erase_info->state to determine if the erase operation failed or succeeded. Moreover, mtd_erase_callback() is now a NOP. We can safely get rid of all mtd_erase_callback() calls and all erase_info->state assignments. While at it, get rid of the erase_info->state field, all MTD_ERASE_XXX definitions and the mtd_erase_callback() function. Signed-off-by: Boris Brezillon Reviewed-by: Richard Weinberger Reviewed-by: Miquel Raynal Acked-by: Bert Kenward --- Changes in v2: - Address a few coding style issues (reported by Miquel) - Remove comments that are no longer valid (reported by Miquel) --- drivers/mtd/chips/cfi_cmdset_0001.c | 16 ++------------- drivers/mtd/chips/cfi_cmdset_0002.c | 26 +++--------------------- drivers/mtd/chips/cfi_cmdset_0020.c | 3 --- drivers/mtd/chips/map_ram.c | 2 -- drivers/mtd/devices/bcm47xxsflash.c | 9 +------- drivers/mtd/devices/block2mtd.c | 7 +------ drivers/mtd/devices/docg3.c | 16 ++------------- drivers/mtd/devices/lart.c | 6 ------ drivers/mtd/devices/mtd_dataflash.c | 4 ---- drivers/mtd/devices/mtdram.c | 3 +-- drivers/mtd/devices/phram.c | 7 ------- drivers/mtd/devices/pmc551.c | 2 -- drivers/mtd/devices/powernv_flash.c | 12 ++--------- drivers/mtd/devices/slram.c | 7 +------ drivers/mtd/devices/spear_smi.c | 3 --- drivers/mtd/devices/sst25l.c | 3 --- drivers/mtd/devices/st_spi_fsm.c | 4 ---- drivers/mtd/lpddr/lpddr2_nvm.c | 10 ++------- drivers/mtd/lpddr/lpddr_cmds.c | 2 -- drivers/mtd/mtdconcat.c | 1 - drivers/mtd/mtdcore.c | 6 ++---- drivers/mtd/mtdpart.c | 5 ----- drivers/mtd/nand/nand_base.c | 16 ++++----------- drivers/mtd/onenand/onenand_base.c | 17 ---------------- drivers/mtd/spi-nor/spi-nor.c | 3 --- drivers/mtd/ubi/gluebi.c | 3 --- drivers/net/ethernet/sfc/falcon/mtd.c | 11 +--------- drivers/net/ethernet/sfc/mtd.c | 11 +--------- drivers/staging/goldfish/goldfish_nand.c | 3 --- include/linux/mtd/mtd.h | 9 -------- 30 files changed, 23 insertions(+), 204 deletions(-) diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c index 5e1b68cbcd0a..d4c07b85f18e 100644 --- a/drivers/mtd/chips/cfi_cmdset_0001.c +++ b/drivers/mtd/chips/cfi_cmdset_0001.c @@ -1993,20 +1993,8 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip, static int cfi_intelext_erase_varsize(struct mtd_info *mtd, struct erase_info *instr) { - unsigned long ofs, len; - int ret; - - ofs = instr->addr; - len = instr->len; - - ret = cfi_varsize_frob(mtd, do_erase_oneblock, ofs, len, NULL); - if (ret) - return ret; - - instr->state = MTD_ERASE_DONE; - mtd_erase_callback(instr); - - return 0; + return cfi_varsize_frob(mtd, do_erase_oneblock, instr->addr, + instr->len, NULL); } static void cfi_intelext_sync (struct mtd_info *mtd) diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c index 56aa6b75213d..668e2cbc155b 100644 --- a/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/drivers/mtd/chips/cfi_cmdset_0002.c @@ -2415,20 +2415,8 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip, static int cfi_amdstd_erase_varsize(struct mtd_info *mtd, struct erase_info *instr) { - unsigned long ofs, len; - int ret; - - ofs = instr->addr; - len = instr->len; - - ret = cfi_varsize_frob(mtd, do_erase_oneblock, ofs, len, NULL); - if (ret) - return ret; - - instr->state = MTD_ERASE_DONE; - mtd_erase_callback(instr); - - return 0; + return cfi_varsize_frob(mtd, do_erase_oneblock, instr->addr, + instr->len, NULL); } @@ -2436,7 +2424,6 @@ static int cfi_amdstd_erase_chip(struct mtd_info *mtd, struct erase_info *instr) { struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; - int ret = 0; if (instr->addr != 0) return -EINVAL; @@ -2444,14 +2431,7 @@ static int cfi_amdstd_erase_chip(struct mtd_info *mtd, struct erase_info *instr) if (instr->len != mtd->size) return -EINVAL; - ret = do_erase_chip(map, &cfi->chips[0]); - if (ret) - return ret; - - instr->state = MTD_ERASE_DONE; - mtd_erase_callback(instr); - - return 0; + return do_erase_chip(map, &cfi->chips[0]); } static int do_atmel_lock(struct map_info *map, struct flchip *chip, diff --git a/drivers/mtd/chips/cfi_cmdset_0020.c b/drivers/mtd/chips/cfi_cmdset_0020.c index 7d342965f392..7b7658a05036 100644 --- a/drivers/mtd/chips/cfi_cmdset_0020.c +++ b/drivers/mtd/chips/cfi_cmdset_0020.c @@ -965,9 +965,6 @@ static int cfi_staa_erase_varsize(struct mtd_info *mtd, } } - instr->state = MTD_ERASE_DONE; - mtd_erase_callback(instr); - return 0; } diff --git a/drivers/mtd/chips/map_ram.c b/drivers/mtd/chips/map_ram.c index 1cd0fff0e940..c37fce926864 100644 --- a/drivers/mtd/chips/map_ram.c +++ b/drivers/mtd/chips/map_ram.c @@ -131,8 +131,6 @@ static int mapram_erase (struct mtd_info *mtd, struct erase_info *instr) allff = map_word_ff(map); for (i=0; ilen; i += map_bankwidth(map)) map_write(map, allff, instr->addr + i); - instr->state = MTD_ERASE_DONE; - mtd_erase_callback(instr); return 0; } diff --git a/drivers/mtd/devices/bcm47xxsflash.c b/drivers/mtd/devices/bcm47xxsflash.c index 6b84947cfbea..9baa81b8780c 100644 --- a/drivers/mtd/devices/bcm47xxsflash.c +++ b/drivers/mtd/devices/bcm47xxsflash.c @@ -68,7 +68,6 @@ static int bcm47xxsflash_poll(struct bcm47xxsflash *b47s, int timeout) static int bcm47xxsflash_erase(struct mtd_info *mtd, struct erase_info *erase) { struct bcm47xxsflash *b47s = mtd->priv; - int err; switch (b47s->type) { case BCM47XXSFLASH_TYPE_ST: @@ -89,13 +88,7 @@ static int bcm47xxsflash_erase(struct mtd_info *mtd, struct erase_info *erase) break; } - err = bcm47xxsflash_poll(b47s, HZ); - if (err) - erase->state = MTD_ERASE_FAILED; - else - erase->state = MTD_ERASE_DONE; - - return err; + return bcm47xxsflash_poll(b47s, HZ); } static int bcm47xxsflash_read(struct mtd_info *mtd, loff_t from, size_t len, diff --git a/drivers/mtd/devices/block2mtd.c b/drivers/mtd/devices/block2mtd.c index bb0734600a07..c9e424993e37 100644 --- a/drivers/mtd/devices/block2mtd.c +++ b/drivers/mtd/devices/block2mtd.c @@ -88,17 +88,12 @@ static int block2mtd_erase(struct mtd_info *mtd, struct erase_info *instr) size_t len = instr->len; int err; - instr->state = MTD_ERASING; mutex_lock(&dev->write_mutex); err = _block2mtd_erase(dev, from, len); mutex_unlock(&dev->write_mutex); - if (err) { + if (err) pr_err("erase failed err = %d\n", err); - instr->state = MTD_ERASE_FAILED; - } else - instr->state = MTD_ERASE_DONE; - mtd_erase_callback(instr); return err; } diff --git a/drivers/mtd/devices/docg3.c b/drivers/mtd/devices/docg3.c index a85af236b44d..c594fe5eac08 100644 --- a/drivers/mtd/devices/docg3.c +++ b/drivers/mtd/devices/docg3.c @@ -1191,39 +1191,27 @@ static int doc_erase(struct mtd_info *mtd, struct erase_info *info) { struct docg3 *docg3 = mtd->priv; uint64_t len; - int block0, block1, page, ret, ofs = 0; + int block0, block1, page, ret = 0, ofs = 0; doc_dbg("doc_erase(from=%lld, len=%lld\n", info->addr, info->len); - info->state = MTD_ERASE_PENDING; calc_block_sector(info->addr + info->len, &block0, &block1, &page, &ofs, docg3->reliable); - ret = -EINVAL; if (info->addr + info->len > mtd->size || page || ofs) - goto reset_err; + return -EINVAL; - ret = 0; calc_block_sector(info->addr, &block0, &block1, &page, &ofs, docg3->reliable); mutex_lock(&docg3->cascade->lock); doc_set_device_id(docg3, docg3->device_id); doc_set_reliable_mode(docg3); for (len = info->len; !ret && len > 0; len -= mtd->erasesize) { - info->state = MTD_ERASING; ret = doc_erase_block(docg3, block0, block1); block0 += 2; block1 += 2; } mutex_unlock(&docg3->cascade->lock); - if (ret) - goto reset_err; - - info->state = MTD_ERASE_DONE; - return 0; - -reset_err: - info->state = MTD_ERASE_FAILED; return ret; } diff --git a/drivers/mtd/devices/lart.c b/drivers/mtd/devices/lart.c index 555b94406e0b..f67b653c17d7 100644 --- a/drivers/mtd/devices/lart.c +++ b/drivers/mtd/devices/lart.c @@ -414,10 +414,7 @@ static int flash_erase (struct mtd_info *mtd,struct erase_info *instr) while (len) { if (!erase_block (addr)) - { - instr->state = MTD_ERASE_FAILED; return (-EIO); - } addr += mtd->eraseregions[i].erasesize; len -= mtd->eraseregions[i].erasesize; @@ -425,9 +422,6 @@ static int flash_erase (struct mtd_info *mtd,struct erase_info *instr) if (addr == mtd->eraseregions[i].offset + (mtd->eraseregions[i].erasesize * mtd->eraseregions[i].numblocks)) i++; } - instr->state = MTD_ERASE_DONE; - mtd_erase_callback(instr); - return (0); } diff --git a/drivers/mtd/devices/mtd_dataflash.c b/drivers/mtd/devices/mtd_dataflash.c index 5dc8bd042cc5..aaaeaae01e1d 100644 --- a/drivers/mtd/devices/mtd_dataflash.c +++ b/drivers/mtd/devices/mtd_dataflash.c @@ -220,10 +220,6 @@ static int dataflash_erase(struct mtd_info *mtd, struct erase_info *instr) } mutex_unlock(&priv->lock); - /* Inform MTD subsystem that erase is complete */ - instr->state = MTD_ERASE_DONE; - mtd_erase_callback(instr); - return 0; } diff --git a/drivers/mtd/devices/mtdram.c b/drivers/mtd/devices/mtdram.c index 0bf4aeaf0cb8..46238796145f 100644 --- a/drivers/mtd/devices/mtdram.c +++ b/drivers/mtd/devices/mtdram.c @@ -60,8 +60,7 @@ static int ram_erase(struct mtd_info *mtd, struct erase_info *instr) if (check_offs_len(mtd, instr->addr, instr->len)) return -EINVAL; memset((char *)mtd->priv + instr->addr, 0xff, instr->len); - instr->state = MTD_ERASE_DONE; - mtd_erase_callback(instr); + return 0; } diff --git a/drivers/mtd/devices/phram.c b/drivers/mtd/devices/phram.c index 7287696a21f9..9ee04b5f9311 100644 --- a/drivers/mtd/devices/phram.c +++ b/drivers/mtd/devices/phram.c @@ -39,13 +39,6 @@ static int phram_erase(struct mtd_info *mtd, struct erase_info *instr) memset(start + instr->addr, 0xff, instr->len); - /* - * This'll catch a few races. Free the thing before returning :) - * I don't feel at all ashamed. This kind of thing is possible anyway - * with flash, but unlikely. - */ - instr->state = MTD_ERASE_DONE; - mtd_erase_callback(instr); return 0; } diff --git a/drivers/mtd/devices/pmc551.c b/drivers/mtd/devices/pmc551.c index cadea0620cd0..5d842cbca3de 100644 --- a/drivers/mtd/devices/pmc551.c +++ b/drivers/mtd/devices/pmc551.c @@ -184,12 +184,10 @@ static int pmc551_erase(struct mtd_info *mtd, struct erase_info *instr) } out: - instr->state = MTD_ERASE_DONE; #ifdef CONFIG_MTD_PMC551_DEBUG printk(KERN_DEBUG "pmc551_erase() done\n"); #endif - mtd_erase_callback(instr); return 0; } diff --git a/drivers/mtd/devices/powernv_flash.c b/drivers/mtd/devices/powernv_flash.c index 26f9feaa5d17..c1312b141ae0 100644 --- a/drivers/mtd/devices/powernv_flash.c +++ b/drivers/mtd/devices/powernv_flash.c @@ -175,19 +175,11 @@ static int powernv_flash_erase(struct mtd_info *mtd, struct erase_info *erase) { int rc; - erase->state = MTD_ERASING; - - /* todo: register our own notifier to do a true async implementation */ rc = powernv_flash_async_op(mtd, FLASH_OP_ERASE, erase->addr, erase->len, NULL, NULL); - - if (rc) { + if (rc) erase->fail_addr = erase->addr; - erase->state = MTD_ERASE_FAILED; - } else { - erase->state = MTD_ERASE_DONE; - } - mtd_erase_callback(erase); + return rc; } diff --git a/drivers/mtd/devices/slram.c b/drivers/mtd/devices/slram.c index 0ec85f316d24..10183ee4e12b 100644 --- a/drivers/mtd/devices/slram.c +++ b/drivers/mtd/devices/slram.c @@ -84,12 +84,7 @@ static int slram_erase(struct mtd_info *mtd, struct erase_info *instr) slram_priv_t *priv = mtd->priv; memset(priv->start + instr->addr, 0xff, instr->len); - /* This'll catch a few races. Free the thing before returning :) - * I don't feel at all ashamed. This kind of thing is possible anyway - * with flash, but unlikely. - */ - instr->state = MTD_ERASE_DONE; - mtd_erase_callback(instr); + return(0); } diff --git a/drivers/mtd/devices/spear_smi.c b/drivers/mtd/devices/spear_smi.c index ddf478976013..986f81d2f93e 100644 --- a/drivers/mtd/devices/spear_smi.c +++ b/drivers/mtd/devices/spear_smi.c @@ -518,7 +518,6 @@ static int spear_mtd_erase(struct mtd_info *mtd, struct erase_info *e_info) /* preparing the command for flash */ ret = spear_smi_erase_sector(dev, bank, command, 4); if (ret) { - e_info->state = MTD_ERASE_FAILED; mutex_unlock(&flash->lock); return ret; } @@ -527,8 +526,6 @@ static int spear_mtd_erase(struct mtd_info *mtd, struct erase_info *e_info) } mutex_unlock(&flash->lock); - e_info->state = MTD_ERASE_DONE; - mtd_erase_callback(e_info); return 0; } diff --git a/drivers/mtd/devices/sst25l.c b/drivers/mtd/devices/sst25l.c index 5b84d71efb36..1897f33fe3e7 100644 --- a/drivers/mtd/devices/sst25l.c +++ b/drivers/mtd/devices/sst25l.c @@ -195,7 +195,6 @@ static int sst25l_erase(struct mtd_info *mtd, struct erase_info *instr) err = sst25l_erase_sector(flash, addr); if (err) { mutex_unlock(&flash->lock); - instr->state = MTD_ERASE_FAILED; dev_err(&flash->spi->dev, "Erase failed\n"); return err; } @@ -205,8 +204,6 @@ static int sst25l_erase(struct mtd_info *mtd, struct erase_info *instr) mutex_unlock(&flash->lock); - instr->state = MTD_ERASE_DONE; - mtd_erase_callback(instr); return 0; } diff --git a/drivers/mtd/devices/st_spi_fsm.c b/drivers/mtd/devices/st_spi_fsm.c index a33f5fd6818c..55d4a77f3b7f 100644 --- a/drivers/mtd/devices/st_spi_fsm.c +++ b/drivers/mtd/devices/st_spi_fsm.c @@ -1825,13 +1825,9 @@ static int stfsm_mtd_erase(struct mtd_info *mtd, struct erase_info *instr) mutex_unlock(&fsm->lock); - instr->state = MTD_ERASE_DONE; - mtd_erase_callback(instr); - return 0; out1: - instr->state = MTD_ERASE_FAILED; mutex_unlock(&fsm->lock); return ret; diff --git a/drivers/mtd/lpddr/lpddr2_nvm.c b/drivers/mtd/lpddr/lpddr2_nvm.c index 2342277c9bcb..5d73db2a496d 100644 --- a/drivers/mtd/lpddr/lpddr2_nvm.c +++ b/drivers/mtd/lpddr/lpddr2_nvm.c @@ -380,14 +380,8 @@ out: */ static int lpddr2_nvm_erase(struct mtd_info *mtd, struct erase_info *instr) { - int ret = lpddr2_nvm_do_block_op(mtd, instr->addr, instr->len, - LPDDR2_NVM_ERASE); - if (!ret) { - instr->state = MTD_ERASE_DONE; - mtd_erase_callback(instr); - } - - return ret; + return lpddr2_nvm_do_block_op(mtd, instr->addr, instr->len, + LPDDR2_NVM_ERASE); } /* diff --git a/drivers/mtd/lpddr/lpddr_cmds.c b/drivers/mtd/lpddr/lpddr_cmds.c index 018c75faadb3..5c5ba3c7c79d 100644 --- a/drivers/mtd/lpddr/lpddr_cmds.c +++ b/drivers/mtd/lpddr/lpddr_cmds.c @@ -693,8 +693,6 @@ static int lpddr_erase(struct mtd_info *mtd, struct erase_info *instr) ofs += size; len -= size; } - instr->state = MTD_ERASE_DONE; - mtd_erase_callback(instr); return 0; } diff --git a/drivers/mtd/mtdconcat.c b/drivers/mtd/mtdconcat.c index 93c47e56d9d8..6b86d1a73cf2 100644 --- a/drivers/mtd/mtdconcat.c +++ b/drivers/mtd/mtdconcat.c @@ -446,7 +446,6 @@ static int concat_erase(struct mtd_info *mtd, struct erase_info *instr) erase->addr = 0; offset += subdev->size; } - instr->state = erase->state; kfree(erase); return err; diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index f92ad02959eb..f25d65ea7149 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -961,11 +961,9 @@ int mtd_erase(struct mtd_info *mtd, struct erase_info *instr) if (!(mtd->flags & MTD_WRITEABLE)) return -EROFS; - if (!instr->len) { - instr->state = MTD_ERASE_DONE; - mtd_erase_callback(instr); + if (!instr->len) return 0; - } + ledtrig_mtd_activity(); return mtd->_erase(mtd, instr); } diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index 1c07a6f0dfe5..85fea8ea3423 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c @@ -212,11 +212,6 @@ static int part_erase(struct mtd_info *mtd, struct erase_info *instr) return ret; } -void mtd_erase_callback(struct erase_info *instr) -{ -} -EXPORT_SYMBOL_GPL(mtd_erase_callback); - static int part_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) { struct mtd_part *part = mtd_to_part(mtd); diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 16c8bc06975d..87b72bf626ae 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -4604,22 +4604,20 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, if (nand_check_wp(mtd)) { pr_debug("%s: device is write protected!\n", __func__); - instr->state = MTD_ERASE_FAILED; + ret = -EIO; goto erase_exit; } /* Loop through the pages */ len = instr->len; - instr->state = MTD_ERASING; - while (len) { /* Check if we have a bad block, we do not erase bad blocks! */ if (nand_block_checkbad(mtd, ((loff_t) page) << chip->page_shift, allowbbt)) { pr_warn("%s: attempt to erase a bad block at page 0x%08x\n", __func__, page); - instr->state = MTD_ERASE_FAILED; + ret = -EIO; goto erase_exit; } @@ -4637,7 +4635,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, if (status) { pr_debug("%s: failed erase, page 0x%08x\n", __func__, page); - instr->state = MTD_ERASE_FAILED; + ret = -EIO; instr->fail_addr = ((loff_t)page << chip->page_shift); goto erase_exit; @@ -4654,20 +4652,14 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, chip->select_chip(mtd, chipnr); } } - instr->state = MTD_ERASE_DONE; + ret = 0; erase_exit: - ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO; - /* Deselect and wake up anyone waiting on the device */ chip->select_chip(mtd, -1); nand_release_device(mtd); - /* Do call back function */ - if (!ret) - mtd_erase_callback(instr); - /* Return more or less happy */ return ret; } diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index 979f4031f23c..8d19b78777b5 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c @@ -2143,7 +2143,6 @@ static int onenand_multiblock_erase_verify(struct mtd_info *mtd, if (ret) { printk(KERN_ERR "%s: Failed verify, block %d\n", __func__, onenand_block(this, addr)); - instr->state = MTD_ERASE_FAILED; instr->fail_addr = addr; return -1; } @@ -2172,8 +2171,6 @@ static int onenand_multiblock_erase(struct mtd_info *mtd, int ret = 0; int bdry_block = 0; - instr->state = MTD_ERASING; - if (ONENAND_IS_DDP(this)) { loff_t bdry_addr = this->chipsize >> 1; if (addr < bdry_addr && (addr + len) > bdry_addr) @@ -2187,7 +2184,6 @@ static int onenand_multiblock_erase(struct mtd_info *mtd, printk(KERN_WARNING "%s: attempt to erase a bad block " "at addr 0x%012llx\n", __func__, (unsigned long long) addr); - instr->state = MTD_ERASE_FAILED; return -EIO; } len -= block_size; @@ -2227,7 +2223,6 @@ static int onenand_multiblock_erase(struct mtd_info *mtd, printk(KERN_ERR "%s: Failed multiblock erase, " "block %d\n", __func__, onenand_block(this, addr)); - instr->state = MTD_ERASE_FAILED; instr->fail_addr = MTD_FAIL_ADDR_UNKNOWN; return -EIO; } @@ -2247,7 +2242,6 @@ static int onenand_multiblock_erase(struct mtd_info *mtd, if (ret) { printk(KERN_ERR "%s: Failed erase, block %d\n", __func__, onenand_block(this, addr)); - instr->state = MTD_ERASE_FAILED; instr->fail_addr = MTD_FAIL_ADDR_UNKNOWN; return -EIO; } @@ -2259,7 +2253,6 @@ static int onenand_multiblock_erase(struct mtd_info *mtd, /* verify */ verify_instr.len = eb_count * block_size; if (onenand_multiblock_erase_verify(mtd, &verify_instr)) { - instr->state = verify_instr.state; instr->fail_addr = verify_instr.fail_addr; return -EIO; } @@ -2294,8 +2287,6 @@ static int onenand_block_by_block_erase(struct mtd_info *mtd, region_end = region->offset + region->erasesize * region->numblocks; } - instr->state = MTD_ERASING; - /* Loop through the blocks */ while (len) { cond_resched(); @@ -2305,7 +2296,6 @@ static int onenand_block_by_block_erase(struct mtd_info *mtd, printk(KERN_WARNING "%s: attempt to erase a bad block " "at addr 0x%012llx\n", __func__, (unsigned long long) addr); - instr->state = MTD_ERASE_FAILED; return -EIO; } @@ -2318,7 +2308,6 @@ static int onenand_block_by_block_erase(struct mtd_info *mtd, if (ret) { printk(KERN_ERR "%s: Failed erase, block %d\n", __func__, onenand_block(this, addr)); - instr->state = MTD_ERASE_FAILED; instr->fail_addr = addr; return -EIO; } @@ -2407,12 +2396,6 @@ static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr) /* Deselect and wake up anyone waiting on the device */ onenand_release_device(mtd); - /* Do call back function */ - if (!ret) { - instr->state = MTD_ERASE_DONE; - mtd_erase_callback(instr); - } - return ret; } diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index d445a4d3b770..5bfa36e95f35 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -560,9 +560,6 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr) erase_err: spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_ERASE); - instr->state = ret ? MTD_ERASE_FAILED : MTD_ERASE_DONE; - mtd_erase_callback(instr); - return ret; } diff --git a/drivers/mtd/ubi/gluebi.c b/drivers/mtd/ubi/gluebi.c index 1cb287ec32ad..6b655a53113b 100644 --- a/drivers/mtd/ubi/gluebi.c +++ b/drivers/mtd/ubi/gluebi.c @@ -272,12 +272,9 @@ static int gluebi_erase(struct mtd_info *mtd, struct erase_info *instr) if (err) goto out_err; - instr->state = MTD_ERASE_DONE; - mtd_erase_callback(instr); return 0; out_err: - instr->state = MTD_ERASE_FAILED; instr->fail_addr = (long long)lnum * mtd->erasesize; return err; } diff --git a/drivers/net/ethernet/sfc/falcon/mtd.c b/drivers/net/ethernet/sfc/falcon/mtd.c index cde593cb1052..2d67e4621a3d 100644 --- a/drivers/net/ethernet/sfc/falcon/mtd.c +++ b/drivers/net/ethernet/sfc/falcon/mtd.c @@ -24,17 +24,8 @@ static int ef4_mtd_erase(struct mtd_info *mtd, struct erase_info *erase) { struct ef4_nic *efx = mtd->priv; - int rc; - rc = efx->type->mtd_erase(mtd, erase->addr, erase->len); - if (rc == 0) { - erase->state = MTD_ERASE_DONE; - } else { - erase->state = MTD_ERASE_FAILED; - erase->fail_addr = MTD_FAIL_ADDR_UNKNOWN; - } - mtd_erase_callback(erase); - return rc; + return efx->type->mtd_erase(mtd, erase->addr, erase->len); } static void ef4_mtd_sync(struct mtd_info *mtd) diff --git a/drivers/net/ethernet/sfc/mtd.c b/drivers/net/ethernet/sfc/mtd.c index a77a8bd2dd70..4ac30b6e5dab 100644 --- a/drivers/net/ethernet/sfc/mtd.c +++ b/drivers/net/ethernet/sfc/mtd.c @@ -24,17 +24,8 @@ static int efx_mtd_erase(struct mtd_info *mtd, struct erase_info *erase) { struct efx_nic *efx = mtd->priv; - int rc; - rc = efx->type->mtd_erase(mtd, erase->addr, erase->len); - if (rc == 0) { - erase->state = MTD_ERASE_DONE; - } else { - erase->state = MTD_ERASE_FAILED; - erase->fail_addr = MTD_FAIL_ADDR_UNKNOWN; - } - mtd_erase_callback(erase); - return rc; + return efx->type->mtd_erase(mtd, erase->addr, erase->len); } static void efx_mtd_sync(struct mtd_info *mtd) diff --git a/drivers/staging/goldfish/goldfish_nand.c b/drivers/staging/goldfish/goldfish_nand.c index 52cc1363993e..f5e002ecba75 100644 --- a/drivers/staging/goldfish/goldfish_nand.c +++ b/drivers/staging/goldfish/goldfish_nand.c @@ -119,9 +119,6 @@ static int goldfish_nand_erase(struct mtd_info *mtd, struct erase_info *instr) return -EIO; } - instr->state = MTD_ERASE_DONE; - mtd_erase_callback(instr); - return 0; invalid_arg: diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h index 4cbb7f555244..a86c4fa93115 100644 --- a/include/linux/mtd/mtd.h +++ b/include/linux/mtd/mtd.h @@ -30,12 +30,6 @@ #include -#define MTD_ERASE_PENDING 0x01 -#define MTD_ERASING 0x02 -#define MTD_ERASE_SUSPEND 0x04 -#define MTD_ERASE_DONE 0x08 -#define MTD_ERASE_FAILED 0x10 - #define MTD_FAIL_ADDR_UNKNOWN -1LL struct mtd_info; @@ -49,7 +43,6 @@ struct erase_info { uint64_t addr; uint64_t len; uint64_t fail_addr; - u_char state; }; struct mtd_erase_region_info { @@ -589,8 +582,6 @@ extern void register_mtd_user (struct mtd_notifier *new); extern int unregister_mtd_user (struct mtd_notifier *old); void *mtd_kmalloc_up_to(const struct mtd_info *mtd, size_t *size); -void mtd_erase_callback(struct erase_info *instr); - static inline int mtd_is_bitflip(int err) { return err == -EUCLEAN; } From ac9cd36c7a5dc79b3d10f0110bc096918109fdf8 Mon Sep 17 00:00:00 2001 From: Antonio Cardace Date: Tue, 13 Feb 2018 17:52:45 +0000 Subject: [PATCH 61/89] mtd: nftl: use %*ph to print small buffer Use %*ph format to print small buffer as hex string. Suggested-by: Andy Shevchenko Signed-off-by: Antonio Cardace Signed-off-by: Boris Brezillon --- drivers/mtd/nftlmount.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/mtd/nftlmount.c b/drivers/mtd/nftlmount.c index d8f6dba01c87..a6fbfa4e5799 100644 --- a/drivers/mtd/nftlmount.c +++ b/drivers/mtd/nftlmount.c @@ -122,8 +122,7 @@ static int find_boot_record(struct NFTLrecord *nftl) if (memcmp(buf, "ANAND", 6)) { printk(KERN_NOTICE "ANAND header found at 0x%x in mtd%d, but went away on reread!\n", block * nftl->EraseSize, nftl->mbd.mtd->index); - printk(KERN_NOTICE "New data are: %02x %02x %02x %02x %02x %02x\n", - buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]); + printk(KERN_NOTICE "New data are: %6ph\n", buf); continue; } #endif From 148a1a5d74485c5595481c3a2bd78daf50cd346a Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Sat, 3 Mar 2018 23:26:22 +0100 Subject: [PATCH 62/89] mtd: tests: check erase block count in page test When there is only a single erase block, the cross erase test does not report sensible errors. Warn in case there is only a single erase block instead of executing the test. Signed-off-by: Stefan Agner Signed-off-by: Boris Brezillon --- drivers/mtd/tests/pagetest.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/mtd/tests/pagetest.c b/drivers/mtd/tests/pagetest.c index ff1e0565b020..bc303cac9f43 100644 --- a/drivers/mtd/tests/pagetest.c +++ b/drivers/mtd/tests/pagetest.c @@ -435,9 +435,13 @@ static int __init mtd_pagetest_init(void) if (err) goto out; - err = erasecrosstest(); - if (err) - goto out; + if (ebcnt > 1) { + err = erasecrosstest(); + if (err) + goto out; + } else { + pr_info("skipping erasecrosstest, 2 erase blocks needed\n"); + } err = erasetest(); if (err) From 5741a164ff6fb5abbea8548ad0f3846bad2b9aec Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 14 Mar 2018 17:30:22 +0100 Subject: [PATCH 63/89] mtd: maps: remove bfin-async-flash driver The blackfin architecture is getting removed, so this driver has become obsolete. Signed-off-by: Arnd Bergmann Signed-off-by: Boris Brezillon --- drivers/mtd/maps/Kconfig | 10 -- drivers/mtd/maps/Makefile | 1 - drivers/mtd/maps/bfin-async-flash.c | 196 ---------------------------- 3 files changed, 207 deletions(-) delete mode 100644 drivers/mtd/maps/bfin-async-flash.c diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig index 542fdf8e81fa..bdc1283f30fb 100644 --- a/drivers/mtd/maps/Kconfig +++ b/drivers/mtd/maps/Kconfig @@ -334,16 +334,6 @@ config MTD_PCMCIA_ANONYMOUS If unsure, say N. -config MTD_BFIN_ASYNC - tristate "Blackfin BF533-STAMP Flash Chip Support" - depends on BFIN533_STAMP && MTD_CFI && MTD_COMPLEX_MAPPINGS - default y - help - Map driver which allows for simultaneous utilization of - ethernet and CFI parallel flash. - - If compiled as a module, it will be called bfin-async-flash. - config MTD_GPIO_ADDR tristate "GPIO-assisted Flash Chip Support" depends on GPIOLIB || COMPILE_TEST diff --git a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile index b849aaf85c34..51acf1fec19b 100644 --- a/drivers/mtd/maps/Makefile +++ b/drivers/mtd/maps/Makefile @@ -42,7 +42,6 @@ obj-$(CONFIG_MTD_SCB2_FLASH) += scb2_flash.o obj-$(CONFIG_MTD_IXP4XX) += ixp4xx.o obj-$(CONFIG_MTD_PLATRAM) += plat-ram.o obj-$(CONFIG_MTD_INTEL_VR_NOR) += intel_vr_nor.o -obj-$(CONFIG_MTD_BFIN_ASYNC) += bfin-async-flash.o obj-$(CONFIG_MTD_RBTX4939) += rbtx4939-flash.o obj-$(CONFIG_MTD_VMU) += vmu-flash.o obj-$(CONFIG_MTD_GPIO_ADDR) += gpio-addr-flash.o diff --git a/drivers/mtd/maps/bfin-async-flash.c b/drivers/mtd/maps/bfin-async-flash.c deleted file mode 100644 index 41730feeace8..000000000000 --- a/drivers/mtd/maps/bfin-async-flash.c +++ /dev/null @@ -1,196 +0,0 @@ -/* - * drivers/mtd/maps/bfin-async-flash.c - * - * Handle the case where flash memory and ethernet mac/phy are - * mapped onto the same async bank. The BF533-STAMP does this - * for example. All board-specific configuration goes in your - * board resources file. - * - * Copyright 2000 Nicolas Pitre - * Copyright 2005-2008 Analog Devices Inc. - * - * Enter bugs at http://blackfin.uclinux.org/ - * - * Licensed under the GPL-2 or later. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#define pr_devinit(fmt, args...) \ - ({ static const char __fmt[] = fmt; printk(__fmt, ## args); }) - -#define DRIVER_NAME "bfin-async-flash" - -struct async_state { - struct mtd_info *mtd; - struct map_info map; - int enet_flash_pin; - uint32_t flash_ambctl0, flash_ambctl1; - uint32_t save_ambctl0, save_ambctl1; - unsigned long irq_flags; -}; - -static void switch_to_flash(struct async_state *state) -{ - local_irq_save(state->irq_flags); - - gpio_set_value(state->enet_flash_pin, 0); - - state->save_ambctl0 = bfin_read_EBIU_AMBCTL0(); - state->save_ambctl1 = bfin_read_EBIU_AMBCTL1(); - bfin_write_EBIU_AMBCTL0(state->flash_ambctl0); - bfin_write_EBIU_AMBCTL1(state->flash_ambctl1); - SSYNC(); -} - -static void switch_back(struct async_state *state) -{ - bfin_write_EBIU_AMBCTL0(state->save_ambctl0); - bfin_write_EBIU_AMBCTL1(state->save_ambctl1); - SSYNC(); - - gpio_set_value(state->enet_flash_pin, 1); - - local_irq_restore(state->irq_flags); -} - -static map_word bfin_flash_read(struct map_info *map, unsigned long ofs) -{ - struct async_state *state = (struct async_state *)map->map_priv_1; - uint16_t word; - map_word test; - - switch_to_flash(state); - - word = readw(map->virt + ofs); - - switch_back(state); - - test.x[0] = word; - return test; -} - -static void bfin_flash_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) -{ - struct async_state *state = (struct async_state *)map->map_priv_1; - - switch_to_flash(state); - - memcpy(to, map->virt + from, len); - - switch_back(state); -} - -static void bfin_flash_write(struct map_info *map, map_word d1, unsigned long ofs) -{ - struct async_state *state = (struct async_state *)map->map_priv_1; - uint16_t d; - - d = d1.x[0]; - - switch_to_flash(state); - - writew(d, map->virt + ofs); - SSYNC(); - - switch_back(state); -} - -static void bfin_flash_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) -{ - struct async_state *state = (struct async_state *)map->map_priv_1; - - switch_to_flash(state); - - memcpy(map->virt + to, from, len); - SSYNC(); - - switch_back(state); -} - -static const char * const part_probe_types[] = { - "cmdlinepart", "RedBoot", NULL }; - -static int bfin_flash_probe(struct platform_device *pdev) -{ - struct physmap_flash_data *pdata = dev_get_platdata(&pdev->dev); - struct resource *memory = platform_get_resource(pdev, IORESOURCE_MEM, 0); - struct resource *flash_ambctl = platform_get_resource(pdev, IORESOURCE_MEM, 1); - struct async_state *state; - - state = kzalloc(sizeof(*state), GFP_KERNEL); - if (!state) - return -ENOMEM; - - state->map.name = DRIVER_NAME; - state->map.read = bfin_flash_read; - state->map.copy_from = bfin_flash_copy_from; - state->map.write = bfin_flash_write; - state->map.copy_to = bfin_flash_copy_to; - state->map.bankwidth = pdata->width; - state->map.size = resource_size(memory); - state->map.virt = (void __iomem *)memory->start; - state->map.phys = memory->start; - state->map.map_priv_1 = (unsigned long)state; - state->enet_flash_pin = platform_get_irq(pdev, 0); - state->flash_ambctl0 = flash_ambctl->start; - state->flash_ambctl1 = flash_ambctl->end; - - if (gpio_request(state->enet_flash_pin, DRIVER_NAME)) { - pr_devinit(KERN_ERR DRIVER_NAME ": Failed to request gpio %d\n", state->enet_flash_pin); - kfree(state); - return -EBUSY; - } - gpio_direction_output(state->enet_flash_pin, 1); - - pr_devinit(KERN_NOTICE DRIVER_NAME ": probing %d-bit flash bus\n", state->map.bankwidth * 8); - state->mtd = do_map_probe(memory->name, &state->map); - if (!state->mtd) { - gpio_free(state->enet_flash_pin); - kfree(state); - return -ENXIO; - } - - mtd_device_parse_register(state->mtd, part_probe_types, NULL, - pdata->parts, pdata->nr_parts); - - platform_set_drvdata(pdev, state); - - return 0; -} - -static int bfin_flash_remove(struct platform_device *pdev) -{ - struct async_state *state = platform_get_drvdata(pdev); - gpio_free(state->enet_flash_pin); - mtd_device_unregister(state->mtd); - map_destroy(state->mtd); - kfree(state); - return 0; -} - -static struct platform_driver bfin_flash_driver = { - .probe = bfin_flash_probe, - .remove = bfin_flash_remove, - .driver = { - .name = DRIVER_NAME, - }, -}; - -module_platform_driver(bfin_flash_driver); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("MTD map driver for Blackfins with flash/ethernet on same async bank"); From 5b644aa012f67fd211138a067b9f351f30bdcc60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Wed, 14 Mar 2018 13:10:42 +0100 Subject: [PATCH 64/89] mtd: partitions: add of_match_table parser matching for the "ofpart" type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In order to properly support compatibility strings as described in the bindings/mtd/partition.txt "ofpart" type should be treated as an indication for looking into OF. MTD should check "compatible" property and search for a matching parser rather than blindly trying the one supporting "fixed-partitions". It also means that existing "fixed-partitions" parser should get renamed to use a more meaningful name. This commit achievies that aim by introducing a new mtd_part_of_parse(). It works by looking for a matching parser for every string in the "compatibility" property (starting with the most specific one). Please note that driver-specified parsers still take a precedence. It's assumed that driver providing a parser type has a good reason for that (e.g. having platform data with device-specific info). Also doing otherwise could break existing setups. The same applies to using default parsers (including "cmdlinepart") as some overwrite DT data with cmdline argument. Partition parsers can now provide an of_match_table to enable flash<-->parser matching via device tree as documented in the mtd/partition.txt. This support is currently limited to built-in parsers as it uses request_module() and friends. This should be sufficient for most cases though as compiling parsers as modules isn't a common choice. Signed-off-by: Brian Norris Signed-off-by: Rafał Miłecki Tested-by: Peter Rosin Reviewed-by: Richard Weinberger Signed-off-by: Boris Brezillon --- drivers/mtd/mtdpart.c | 116 ++++++++++++++++++++++++++++++--- include/linux/mtd/partitions.h | 1 + 2 files changed, 108 insertions(+), 9 deletions(-) diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index 85fea8ea3423..2b7bb834ff40 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c @@ -30,6 +30,7 @@ #include #include #include +#include #include "mtdcore.h" @@ -845,6 +846,92 @@ static int mtd_part_do_parse(struct mtd_part_parser *parser, return ret; } +/** + * mtd_part_get_compatible_parser - find MTD parser by a compatible string + * + * @compat: compatible string describing partitions in a device tree + * + * MTD parsers can specify supported partitions by providing a table of + * compatibility strings. This function finds a parser that advertises support + * for a passed value of "compatible". + */ +static struct mtd_part_parser *mtd_part_get_compatible_parser(const char *compat) +{ + struct mtd_part_parser *p, *ret = NULL; + + spin_lock(&part_parser_lock); + + list_for_each_entry(p, &part_parsers, list) { + const struct of_device_id *matches; + + matches = p->of_match_table; + if (!matches) + continue; + + for (; matches->compatible[0]; matches++) { + if (!strcmp(matches->compatible, compat) && + try_module_get(p->owner)) { + ret = p; + break; + } + } + + if (ret) + break; + } + + spin_unlock(&part_parser_lock); + + return ret; +} + +static int mtd_part_of_parse(struct mtd_info *master, + struct mtd_partitions *pparts) +{ + struct mtd_part_parser *parser; + struct device_node *np; + struct property *prop; + const char *compat; + const char *fixed = "ofpart"; + int ret, err = 0; + + np = of_get_child_by_name(mtd_get_of_node(master), "partitions"); + of_property_for_each_string(np, "compatible", prop, compat) { + parser = mtd_part_get_compatible_parser(compat); + if (!parser) + continue; + ret = mtd_part_do_parse(parser, master, pparts, NULL); + if (ret > 0) { + of_node_put(np); + return ret; + } + mtd_part_parser_put(parser); + if (ret < 0 && !err) + err = ret; + } + of_node_put(np); + + /* + * For backward compatibility we have to try the "ofpart" + * parser. It supports old DT format with partitions specified as a + * direct subnodes of a flash device DT node without any compatibility + * specified we could match. + */ + parser = mtd_part_parser_get(fixed); + if (!parser && !request_module("%s", fixed)) + parser = mtd_part_parser_get(fixed); + if (parser) { + ret = mtd_part_do_parse(parser, master, pparts, NULL); + if (ret > 0) + return ret; + mtd_part_parser_put(parser); + if (ret < 0 && !err) + err = ret; + } + + return err; +} + /** * parse_mtd_partitions - parse MTD partitions * @master: the master partition (describes whole MTD device) @@ -877,19 +964,30 @@ int parse_mtd_partitions(struct mtd_info *master, const char *const *types, types = default_mtd_part_types; for ( ; *types; types++) { - pr_debug("%s: parsing partitions %s\n", master->name, *types); - parser = mtd_part_parser_get(*types); - if (!parser && !request_module("%s", *types)) + /* + * ofpart is a special type that means OF partitioning info + * should be used. It requires a bit different logic so it is + * handled in a separated function. + */ + if (!strcmp(*types, "ofpart")) { + ret = mtd_part_of_parse(master, pparts); + } else { + pr_debug("%s: parsing partitions %s\n", master->name, + *types); parser = mtd_part_parser_get(*types); - pr_debug("%s: got parser %s\n", master->name, - parser ? parser->name : NULL); - if (!parser) - continue; - ret = mtd_part_do_parse(parser, master, pparts, data); + if (!parser && !request_module("%s", *types)) + parser = mtd_part_parser_get(*types); + pr_debug("%s: got parser %s\n", master->name, + parser ? parser->name : NULL); + if (!parser) + continue; + ret = mtd_part_do_parse(parser, master, pparts, data); + if (ret <= 0) + mtd_part_parser_put(parser); + } /* Found partitions! */ if (ret > 0) return 0; - mtd_part_parser_put(parser); /* * Stash the first error we see; only report it if no parser * succeeds diff --git a/include/linux/mtd/partitions.h b/include/linux/mtd/partitions.h index c4beb70dacbd..11cb0c50cd84 100644 --- a/include/linux/mtd/partitions.h +++ b/include/linux/mtd/partitions.h @@ -77,6 +77,7 @@ struct mtd_part_parser { struct list_head list; struct module *owner; const char *name; + const struct of_device_id *of_match_table; int (*parse_fn)(struct mtd_info *, const struct mtd_partition **, struct mtd_part_parser_data *); void (*cleanup)(const struct mtd_partition *pparts, int nr_parts); From c0faf43482e7f7dfb6d61847cb93d17748560b24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Wed, 14 Mar 2018 13:10:43 +0100 Subject: [PATCH 65/89] mtd: rename "ofpart" parser to "fixed-partitions" as it fits it better MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Type "ofpart" means that OF should be used to get partitioning info and this driver supports "fixed-partitions" binding only. Renaming it should lead to less confusion especially when parsers for new compatibility strings start to appear. Signed-off-by: Rafał Miłecki Reviewed-by: Richard Weinberger Signed-off-by: Boris Brezillon --- drivers/mtd/mtdpart.c | 4 ++-- drivers/mtd/ofpart.c | 11 ++++++----- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index 2b7bb834ff40..023516a63276 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c @@ -892,7 +892,7 @@ static int mtd_part_of_parse(struct mtd_info *master, struct device_node *np; struct property *prop; const char *compat; - const char *fixed = "ofpart"; + const char *fixed = "fixed-partitions"; int ret, err = 0; np = of_get_child_by_name(mtd_get_of_node(master), "partitions"); @@ -912,7 +912,7 @@ static int mtd_part_of_parse(struct mtd_info *master, of_node_put(np); /* - * For backward compatibility we have to try the "ofpart" + * For backward compatibility we have to try the "fixed-partitions" * parser. It supports old DT format with partitions specified as a * direct subnodes of a flash device DT node without any compatibility * specified we could match. diff --git a/drivers/mtd/ofpart.c b/drivers/mtd/ofpart.c index 6bdf4e525677..9f497315e65d 100644 --- a/drivers/mtd/ofpart.c +++ b/drivers/mtd/ofpart.c @@ -25,9 +25,9 @@ static bool node_has_compatible(struct device_node *pp) return of_get_property(pp, "compatible", NULL); } -static int parse_ofpart_partitions(struct mtd_info *master, - const struct mtd_partition **pparts, - struct mtd_part_parser_data *data) +static int parse_fixed_partitions(struct mtd_info *master, + const struct mtd_partition **pparts, + struct mtd_part_parser_data *data) { struct mtd_partition *parts; struct device_node *mtd_node; @@ -141,8 +141,8 @@ ofpart_none: } static struct mtd_part_parser ofpart_parser = { - .parse_fn = parse_ofpart_partitions, - .name = "ofpart", + .parse_fn = parse_fixed_partitions, + .name = "fixed-partitions", }; static int parse_ofoldpart_partitions(struct mtd_info *master, @@ -229,4 +229,5 @@ MODULE_AUTHOR("Vitaly Wool, David Gibson"); * with the same name. Since we provide the ofoldpart parser, we should have * the corresponding alias. */ +MODULE_ALIAS("fixed-partitions"); MODULE_ALIAS("ofoldpart"); From 97b0c7c0df3efd7048ed39d7e2dee34cafd55887 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Wed, 14 Mar 2018 13:10:44 +0100 Subject: [PATCH 66/89] mtd: ofpart: add of_match_table with "fixed-partitions" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This allows using this parser with any flash driver that takes care of setting of_node (using mtd_set_of_node helper) correctly. Up to now support for "fixed-partitions" DT compatibility string was working only with flash drivers that were specifying "ofpart" (manually or by letting mtd use the default set of parsers). This matches existing bindings documentation. Signed-off-by: Rafał Miłecki Reviewed-by: Brian Norris Tested-by: Brian Norris Reviewed-by: Richard Weinberger Signed-off-by: Boris Brezillon --- drivers/mtd/ofpart.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/mtd/ofpart.c b/drivers/mtd/ofpart.c index 9f497315e65d..615f8c173162 100644 --- a/drivers/mtd/ofpart.c +++ b/drivers/mtd/ofpart.c @@ -140,9 +140,16 @@ ofpart_none: return ret; } +static const struct of_device_id parse_ofpart_match_table[] = { + { .compatible = "fixed-partitions" }, + {}, +}; +MODULE_DEVICE_TABLE(of, parse_ofpart_match_table); + static struct mtd_part_parser ofpart_parser = { .parse_fn = parse_fixed_partitions, .name = "fixed-partitions", + .of_match_table = parse_ofpart_match_table, }; static int parse_ofoldpart_partitions(struct mtd_info *master, From 974f2936b360500f9658fb5b698024d2439c18bf Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 3 Mar 2018 23:31:45 +0100 Subject: [PATCH 67/89] mtd: jedec_probe: add Eon EN29LV400A IDs This adds the JEDEC IDs for Eon EN29LV400A variants EN29LV400AB and EN29LV400AT. This chip is found in the D-Link DNS-313. Signed-off-by: Linus Walleij Signed-off-by: Boris Brezillon --- drivers/mtd/chips/jedec_probe.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/drivers/mtd/chips/jedec_probe.c b/drivers/mtd/chips/jedec_probe.c index 7c0b27d132b1..9516439bb1a5 100644 --- a/drivers/mtd/chips/jedec_probe.c +++ b/drivers/mtd/chips/jedec_probe.c @@ -53,6 +53,8 @@ #define AT49BV32XT 0x00C9 /* Eon */ +#define EN29LV400AT 0x22B9 +#define EN29LV400AB 0x22BA #define EN29SL800BB 0x226B #define EN29SL800BT 0x22EA @@ -641,6 +643,36 @@ static const struct amd_flash_info jedec_table[] = { ERASEINFO(0x10000,63), ERASEINFO(0x02000,8) } + }, { + .mfr_id = CFI_MFR_EON, + .dev_id = EN29LV400AT, + .name = "Eon EN29LV400AT", + .devtypes = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8, + .uaddr = MTD_UADDR_0x0AAA_0x0555, + .dev_size = SIZE_512KiB, + .cmd_set = P_ID_AMD_STD, + .nr_regions = 4, + .regions = { + ERASEINFO(0x10000,7), + ERASEINFO(0x08000,1), + ERASEINFO(0x02000,2), + ERASEINFO(0x04000,1), + } + }, { + .mfr_id = CFI_MFR_EON, + .dev_id = EN29LV400AB, + .name = "Eon EN29LV400AB", + .devtypes = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8, + .uaddr = MTD_UADDR_0x0AAA_0x0555, + .dev_size = SIZE_512KiB, + .cmd_set = P_ID_AMD_STD, + .nr_regions = 4, + .regions = { + ERASEINFO(0x04000,1), + ERASEINFO(0x02000,2), + ERASEINFO(0x08000,1), + ERASEINFO(0x10000,7), + } }, { .mfr_id = CFI_MFR_EON, .dev_id = EN29SL800BT, From 9e7eb9c90d769ad724136f47e374b2edfa351f9b Mon Sep 17 00:00:00 2001 From: Cyrille Pitchen Date: Thu, 15 Mar 2018 20:04:38 +0100 Subject: [PATCH 68/89] MAINTAINERS: update maintainers for MTD and SPI NOR subsystems remove myself as MTD and SPI NOR maintainer. Signed-off-by: Cyrille Pitchen Signed-off-by: Boris Brezillon --- MAINTAINERS | 2 -- 1 file changed, 2 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 3bdc260e36b7..7892db9a9494 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9037,7 +9037,6 @@ M: Brian Norris M: Boris Brezillon M: Marek Vasut M: Richard Weinberger -M: Cyrille Pitchen L: linux-mtd@lists.infradead.org W: http://www.linux-mtd.infradead.org/ Q: http://patchwork.ozlabs.org/project/linux-mtd/list/ @@ -13006,7 +13005,6 @@ F: arch/arm/boot/dts/spear* F: arch/arm/mach-spear/ SPI NOR SUBSYSTEM -M: Cyrille Pitchen M: Marek Vasut L: linux-mtd@lists.infradead.org W: http://www.linux-mtd.infradead.org/ From 55a999a04159dfb33d3d3d293a70cce766f6db27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Tue, 27 Mar 2018 15:36:47 +0200 Subject: [PATCH 69/89] mtd: update documentation of mtd_device_parse_register() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In the commit 2c77c57d22adb ("mtd: move code adding master MTD out of mtd_add_device_partitions()") behavior of mtd_device_parse_register() has very slightly changed. It's a pretty non-significant order change to match updated function behavior. Signed-off-by: Rafał Miłecki Reviewed-by: Richard Weinberger Signed-off-by: Boris Brezillon --- drivers/mtd/mtdcore.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index f25d65ea7149..20d5262c5b5c 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -673,14 +673,13 @@ static void mtd_set_dev_defaults(struct mtd_info *mtd) * 'parse_mtd_partitions()') and MTD device and partitions registering. It * basically follows the most common pattern found in many MTD drivers: * - * * It first tries to probe partitions on MTD device @mtd using parsers + * * If the MTD_PARTITIONED_MASTER option is set, then the device as a whole is + * registered first. + * * Then It tries to probe partitions on MTD device @mtd using parsers * specified in @types (if @types is %NULL, then the default list of parsers * is used, see 'parse_mtd_partitions()' for more information). If none are * found this functions tries to fallback to information specified in * @parts/@nr_parts. - * * If any partitioning info was found, this function registers the found - * partitions. If the MTD_PARTITIONED_MASTER option is set, then the device - * as a whole is registered first. * * If no partitions were found this function just registers the MTD device * @mtd and exits. * From 147395ea40b36b8652b6df3e50a1cb745be75c93 Mon Sep 17 00:00:00 2001 From: Prabhakar Kushwaha Date: Wed, 28 Mar 2018 11:14:43 +0530 Subject: [PATCH 70/89] dt-bindings: mtd-physmap: Add endianness supports Provide a way to specify the endianness to use when accessing a memory-mapped flash. Signed-off-by: Prabhakar Kushwaha Reviewed-by: Rob Herring Signed-off-by: Boris Brezillon --- Documentation/devicetree/bindings/mtd/mtd-physmap.txt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Documentation/devicetree/bindings/mtd/mtd-physmap.txt b/Documentation/devicetree/bindings/mtd/mtd-physmap.txt index 4a0a48bf4ecb..232fa12e90ef 100644 --- a/Documentation/devicetree/bindings/mtd/mtd-physmap.txt +++ b/Documentation/devicetree/bindings/mtd/mtd-physmap.txt @@ -41,6 +41,13 @@ additional (optional) property is defined: - erase-size : The chip's physical erase block size in bytes. + The device tree may optionally contain endianness property. + little-endian or big-endian : It Represents the endianness that should be used + by the controller to properly read/write data + from/to the flash. If this property is missing, + the endianness is chosen by the system + (potentially based on extra configuration options). + The device tree may optionally contain sub-nodes describing partitions of the address space. See partition.txt for more detail. From 7d5cba597dbfc55c43761e255f1be646ef3ab633 Mon Sep 17 00:00:00 2001 From: Prabhakar Kushwaha Date: Wed, 28 Mar 2018 11:15:52 +0530 Subject: [PATCH 71/89] mtd: physmap_of: update struct map_info's swap as per map requirement It is not necessary for all device's maps to be CFI_HOST_ENDIAN. Maps device can be Big endian or little endian. Currently it is being taken care using CONFIG_MTD_CFI_LE_BYTE_SWAP or CONFIG_MTD_CFI_BE_BYTE_SWAP i.e. compile time. Now update struct map_info's swap field based on device characteristics defined in device tree. Signed-off-by: Jagdish Gediya Signed-off-by: Prabhakar Kushwaha Signed-off-by: Boris Brezillon --- drivers/mtd/maps/physmap_of_core.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/mtd/maps/physmap_of_core.c b/drivers/mtd/maps/physmap_of_core.c index b1bd4faecfb2..527b1682381f 100644 --- a/drivers/mtd/maps/physmap_of_core.c +++ b/drivers/mtd/maps/physmap_of_core.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -233,6 +234,11 @@ static int of_flash_probe(struct platform_device *dev) info->list[i].map.bankwidth = be32_to_cpup(width); info->list[i].map.device_node = dp; + if (of_property_read_bool(dp, "big-endian")) + info->list[i].map.swap = CFI_BIG_ENDIAN; + else if (of_property_read_bool(dp, "little-endian")) + info->list[i].map.swap = CFI_LITTLE_ENDIAN; + err = of_flash_probe_gemini(dev, dp, &info->list[i].map); if (err) goto err_out; From c77a93120640057bd7c3fd7eca25c427bb6de409 Mon Sep 17 00:00:00 2001 From: Xiaolei Li Date: Thu, 29 Mar 2018 09:34:58 +0800 Subject: [PATCH 72/89] mtd: Fix some function description mismatches in mtdcore.c In mtdcore.c, some function descriptions do not match function definitions. Just fix these mismatches. Signed-off-by: Xiaolei Li Signed-off-by: Boris Brezillon --- drivers/mtd/mtdcore.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index 20d5262c5b5c..807d17d863b3 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -419,7 +419,7 @@ int mtd_wunit_to_pairing_info(struct mtd_info *mtd, int wunit, EXPORT_SYMBOL_GPL(mtd_wunit_to_pairing_info); /** - * mtd_wunit_to_pairing_info - get wunit from pairing information + * mtd_pairing_info_to_wunit - get wunit from pairing information * @mtd: pointer to new MTD device info structure * @info: pairing information struct * @@ -1507,9 +1507,9 @@ int mtd_ooblayout_get_databytes(struct mtd_info *mtd, u8 *databuf, EXPORT_SYMBOL_GPL(mtd_ooblayout_get_databytes); /** - * mtd_ooblayout_get_eccbytes - set data bytes into the oob buffer + * mtd_ooblayout_set_databytes - set data bytes into the oob buffer * @mtd: mtd info structure - * @eccbuf: source buffer to get data bytes from + * @databuf: source buffer to get data bytes from * @oobbuf: OOB buffer * @start: first ECC byte to set * @nbytes: number of ECC bytes to set @@ -1541,7 +1541,7 @@ int mtd_ooblayout_count_freebytes(struct mtd_info *mtd) EXPORT_SYMBOL_GPL(mtd_ooblayout_count_freebytes); /** - * mtd_ooblayout_count_freebytes - count the number of ECC bytes in OOB + * mtd_ooblayout_count_eccbytes - count the number of ECC bytes in OOB * @mtd: mtd info structure * * Works like mtd_ooblayout_count_bytes(), except it count ECC bytes. From b756816dad0aaca4f57c857a86a6a4a85a9f478b Mon Sep 17 00:00:00 2001 From: Arushi Singhal Date: Sun, 25 Mar 2018 21:07:43 +0530 Subject: [PATCH 73/89] mtd: ftl: Use DIV_ROUND_UP() The kernel.h macro DIV_ROUND_UP performs the computation (((n) + (d) - 1) / (d)) but is perhaps more readable. Signed-off-by: Arushi Singhal Signed-off-by: Boris Brezillon --- drivers/mtd/ftl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/ftl.c b/drivers/mtd/ftl.c index 0a6adfaec7b5..ef6ad2551d57 100644 --- a/drivers/mtd/ftl.c +++ b/drivers/mtd/ftl.c @@ -393,8 +393,8 @@ static int prepare_xfer(partition_t *part, int i) } /* Write the BAM stub */ - nbam = (part->BlocksPerUnit * sizeof(uint32_t) + - le32_to_cpu(part->header.BAMOffset) + SECTOR_SIZE - 1) / SECTOR_SIZE; + nbam = DIV_ROUND_UP(part->BlocksPerUnit * sizeof(uint32_t) + + le32_to_cpu(part->header.BAMOffset), SECTOR_SIZE); offset = xfer->Offset + le32_to_cpu(part->header.BAMOffset); ctl = cpu_to_le32(BLOCK_CONTROL); From 961ba15c48dd465fdbef1b9379bd8031c374d62e Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Tue, 13 Mar 2018 11:30:16 +0100 Subject: [PATCH 74/89] mtd: rawnand: marvell: Fix clock resource by adding a register clock On Armada 7K/8K we need to explicitly enable the register clock. This clock is optional because not all the SoCs using this IP need it but at least for Armada 7K/8K it is actually mandatory. The binding documentation is updated accordingly. Signed-off-by: Gregory CLEMENT Signed-off-by: Boris Brezillon --- .../devicetree/bindings/mtd/marvell-nand.txt | 5 ++- drivers/mtd/nand/raw/marvell_nand.c | 34 +++++++++++++++---- 2 files changed, 32 insertions(+), 7 deletions(-) diff --git a/Documentation/devicetree/bindings/mtd/marvell-nand.txt b/Documentation/devicetree/bindings/mtd/marvell-nand.txt index c08fb477b3c6..e0c790706b9b 100644 --- a/Documentation/devicetree/bindings/mtd/marvell-nand.txt +++ b/Documentation/devicetree/bindings/mtd/marvell-nand.txt @@ -14,7 +14,10 @@ Required properties: - #address-cells: shall be set to 1. Encode the NAND CS. - #size-cells: shall be set to 0. - interrupts: shall define the NAND controller interrupt. -- clocks: shall reference the NAND controller clock. +- clocks: shall reference the NAND controller clocks, the second one is + is only needed for the Armada 7K/8K SoCs +- clock-names: mandatory if there is a second clock, in this case there + should be one clock named "core" and another one named "reg" - marvell,system-controller: Set to retrieve the syscon node that handles NAND controller related registers (only required with the "marvell,armada-8k-nand[-controller]" compatibles). diff --git a/drivers/mtd/nand/raw/marvell_nand.c b/drivers/mtd/nand/raw/marvell_nand.c index 528a8e0342bd..3d84f4252af4 100644 --- a/drivers/mtd/nand/raw/marvell_nand.c +++ b/drivers/mtd/nand/raw/marvell_nand.c @@ -308,6 +308,7 @@ struct marvell_nfc_caps { * @dev: Parent device (used to print error messages) * @regs: NAND controller registers * @ecc_clk: ECC block clock, two times the NAND controller clock + * @reg_clk: Regiters clock * @complete: Completion object to wait for NAND controller events * @assigned_cs: Bitmask describing already assigned CS lines * @chips: List containing all the NAND chips attached to @@ -321,6 +322,7 @@ struct marvell_nfc { struct device *dev; void __iomem *regs; struct clk *ecc_clk; + struct clk *reg_clk; struct completion complete; unsigned long assigned_cs; struct list_head chips; @@ -2757,7 +2759,12 @@ static int marvell_nfc_probe(struct platform_device *pdev) return irq; } - nfc->ecc_clk = devm_clk_get(&pdev->dev, NULL); + nfc->ecc_clk = devm_clk_get(&pdev->dev, "core"); + + /* Managed the legacy case (when the first clock was not named) */ + if (nfc->ecc_clk == ERR_PTR(-ENOENT)) + nfc->ecc_clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(nfc->ecc_clk)) return PTR_ERR(nfc->ecc_clk); @@ -2765,12 +2772,24 @@ static int marvell_nfc_probe(struct platform_device *pdev) if (ret) return ret; + nfc->reg_clk = devm_clk_get(&pdev->dev, "reg"); + if (PTR_ERR(nfc->reg_clk) != -ENOENT) { + if (!IS_ERR(nfc->reg_clk)) { + ret = clk_prepare_enable(nfc->reg_clk); + if (ret) + goto unprepare_ecc_clk; + } else { + ret = PTR_ERR(nfc->reg_clk); + goto unprepare_ecc_clk; + } + } + marvell_nfc_disable_int(nfc, NDCR_ALL_INT); marvell_nfc_clear_int(nfc, NDCR_ALL_INT); ret = devm_request_irq(dev, irq, marvell_nfc_isr, 0, "marvell-nfc", nfc); if (ret) - goto unprepare_clk; + goto unprepare_reg_clk; /* Get NAND controller capabilities */ if (pdev->id_entry) @@ -2781,23 +2800,25 @@ static int marvell_nfc_probe(struct platform_device *pdev) if (!nfc->caps) { dev_err(dev, "Could not retrieve NFC caps\n"); ret = -EINVAL; - goto unprepare_clk; + goto unprepare_reg_clk; } /* Init the controller and then probe the chips */ ret = marvell_nfc_init(nfc); if (ret) - goto unprepare_clk; + goto unprepare_reg_clk; platform_set_drvdata(pdev, nfc); ret = marvell_nand_chips_init(dev, nfc); if (ret) - goto unprepare_clk; + goto unprepare_reg_clk; return 0; -unprepare_clk: +unprepare_reg_clk: + clk_disable_unprepare(nfc->reg_clk); +unprepare_ecc_clk: clk_disable_unprepare(nfc->ecc_clk); return ret; @@ -2814,6 +2835,7 @@ static int marvell_nfc_remove(struct platform_device *pdev) dma_release_channel(nfc->dma_chan); } + clk_disable_unprepare(nfc->reg_clk); clk_disable_unprepare(nfc->ecc_clk); return 0; From 15d6f118285f2ffc73fc8de75ecf7c36c3c6fe18 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Wed, 21 Mar 2018 09:36:18 +0100 Subject: [PATCH 75/89] mtd: rawnand: sunxi: Stop supporting ECC_HW_SYNDROME mode This mode is not used by any existing setup and should not be used because it overwrites the BBMs. Let's just remove it before someone starts using it. Signed-off-by: Boris Brezillon Acked-by: Maxime Ripard Tested-by: Miquel Raynal --- .../devicetree/bindings/mtd/sunxi-nand.txt | 4 +- drivers/mtd/nand/raw/sunxi_nand.c | 155 +++--------------- 2 files changed, 22 insertions(+), 137 deletions(-) diff --git a/Documentation/devicetree/bindings/mtd/sunxi-nand.txt b/Documentation/devicetree/bindings/mtd/sunxi-nand.txt index 5e13a5cdff03..0734f03bf3d3 100644 --- a/Documentation/devicetree/bindings/mtd/sunxi-nand.txt +++ b/Documentation/devicetree/bindings/mtd/sunxi-nand.txt @@ -24,8 +24,8 @@ Optional properties: - allwinner,rb : shall contain the native Ready/Busy ids. or - rb-gpios : shall contain the gpios used as R/B pins. -- nand-ecc-mode : one of the supported ECC modes ("hw", "hw_syndrome", "soft", - "soft_bch" or "none") +- nand-ecc-mode : one of the supported ECC modes ("hw", "soft", "soft_bch" or + "none") see Documentation/devicetree/bindings/mtd/nand.txt for generic bindings. diff --git a/drivers/mtd/nand/raw/sunxi_nand.c b/drivers/mtd/nand/raw/sunxi_nand.c index f5a55c63935c..aad42812a353 100644 --- a/drivers/mtd/nand/raw/sunxi_nand.c +++ b/drivers/mtd/nand/raw/sunxi_nand.c @@ -1475,92 +1475,18 @@ pio_fallback: return sunxi_nfc_hw_ecc_write_page(mtd, chip, buf, oob_required, page); } -static int sunxi_nfc_hw_syndrome_ecc_read_page(struct mtd_info *mtd, - struct nand_chip *chip, - uint8_t *buf, int oob_required, - int page) -{ - struct nand_ecc_ctrl *ecc = &chip->ecc; - unsigned int max_bitflips = 0; - int ret, i, cur_off = 0; - bool raw_mode = false; - - nand_read_page_op(chip, page, 0, NULL, 0); - - sunxi_nfc_hw_ecc_enable(mtd); - - for (i = 0; i < ecc->steps; i++) { - int data_off = i * (ecc->size + ecc->bytes + 4); - int oob_off = data_off + ecc->size; - u8 *data = buf + (i * ecc->size); - u8 *oob = chip->oob_poi + (i * (ecc->bytes + 4)); - - ret = sunxi_nfc_hw_ecc_read_chunk(mtd, data, data_off, oob, - oob_off, &cur_off, - &max_bitflips, !i, - oob_required, - page); - if (ret < 0) - return ret; - else if (ret) - raw_mode = true; - } - - if (oob_required) - sunxi_nfc_hw_ecc_read_extra_oob(mtd, chip->oob_poi, &cur_off, - !raw_mode, page); - - sunxi_nfc_hw_ecc_disable(mtd); - - return max_bitflips; -} - -static int sunxi_nfc_hw_syndrome_ecc_write_page(struct mtd_info *mtd, - struct nand_chip *chip, - const uint8_t *buf, - int oob_required, int page) -{ - struct nand_ecc_ctrl *ecc = &chip->ecc; - int ret, i, cur_off = 0; - - nand_prog_page_begin_op(chip, page, 0, NULL, 0); - - sunxi_nfc_hw_ecc_enable(mtd); - - for (i = 0; i < ecc->steps; i++) { - int data_off = i * (ecc->size + ecc->bytes + 4); - int oob_off = data_off + ecc->size; - const u8 *data = buf + (i * ecc->size); - const u8 *oob = chip->oob_poi + (i * (ecc->bytes + 4)); - - ret = sunxi_nfc_hw_ecc_write_chunk(mtd, data, data_off, - oob, oob_off, &cur_off, - false, page); - if (ret) - return ret; - } - - if (oob_required || (chip->options & NAND_NEED_SCRAMBLING)) - sunxi_nfc_hw_ecc_write_extra_oob(mtd, chip->oob_poi, - &cur_off, page); - - sunxi_nfc_hw_ecc_disable(mtd); - - return nand_prog_page_end_op(chip); -} - -static int sunxi_nfc_hw_common_ecc_read_oob(struct mtd_info *mtd, - struct nand_chip *chip, - int page) +static int sunxi_nfc_hw_ecc_read_oob(struct mtd_info *mtd, + struct nand_chip *chip, + int page) { chip->pagebuf = -1; return chip->ecc.read_page(mtd, chip, chip->data_buf, 1, page); } -static int sunxi_nfc_hw_common_ecc_write_oob(struct mtd_info *mtd, - struct nand_chip *chip, - int page) +static int sunxi_nfc_hw_ecc_write_oob(struct mtd_info *mtd, + struct nand_chip *chip, + int page) { int ret; @@ -1801,9 +1727,14 @@ static const struct mtd_ooblayout_ops sunxi_nand_ooblayout_ops = { .free = sunxi_nand_ooblayout_free, }; -static int sunxi_nand_hw_common_ecc_ctrl_init(struct mtd_info *mtd, - struct nand_ecc_ctrl *ecc, - struct device_node *np) +static void sunxi_nand_hw_ecc_ctrl_cleanup(struct nand_ecc_ctrl *ecc) +{ + kfree(ecc->priv); +} + +static int sunxi_nand_hw_ecc_ctrl_init(struct mtd_info *mtd, + struct nand_ecc_ctrl *ecc, + struct device_node *np) { static const u8 strengths[] = { 16, 24, 28, 32, 40, 48, 56, 60, 64 }; struct nand_chip *nand = mtd_to_nand(mtd); @@ -1889,37 +1820,11 @@ static int sunxi_nand_hw_common_ecc_ctrl_init(struct mtd_info *mtd, goto err; } - ecc->read_oob = sunxi_nfc_hw_common_ecc_read_oob; - ecc->write_oob = sunxi_nfc_hw_common_ecc_write_oob; + ecc->read_oob = sunxi_nfc_hw_ecc_read_oob; + ecc->write_oob = sunxi_nfc_hw_ecc_write_oob; mtd_set_ooblayout(mtd, &sunxi_nand_ooblayout_ops); ecc->priv = data; - return 0; - -err: - kfree(data); - - return ret; -} - -static void sunxi_nand_hw_common_ecc_ctrl_cleanup(struct nand_ecc_ctrl *ecc) -{ - kfree(ecc->priv); -} - -static int sunxi_nand_hw_ecc_ctrl_init(struct mtd_info *mtd, - struct nand_ecc_ctrl *ecc, - struct device_node *np) -{ - struct nand_chip *nand = mtd_to_nand(mtd); - struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand); - struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller); - int ret; - - ret = sunxi_nand_hw_common_ecc_ctrl_init(mtd, ecc, np); - if (ret) - return ret; - if (nfc->dmac) { ecc->read_page = sunxi_nfc_hw_ecc_read_page_dma; ecc->read_subpage = sunxi_nfc_hw_ecc_read_subpage_dma; @@ -1937,33 +1842,18 @@ static int sunxi_nand_hw_ecc_ctrl_init(struct mtd_info *mtd, ecc->write_oob_raw = nand_write_oob_std; return 0; -} -static int sunxi_nand_hw_syndrome_ecc_ctrl_init(struct mtd_info *mtd, - struct nand_ecc_ctrl *ecc, - struct device_node *np) -{ - int ret; +err: + kfree(data); - ret = sunxi_nand_hw_common_ecc_ctrl_init(mtd, ecc, np); - if (ret) - return ret; - - ecc->prepad = 4; - ecc->read_page = sunxi_nfc_hw_syndrome_ecc_read_page; - ecc->write_page = sunxi_nfc_hw_syndrome_ecc_write_page; - ecc->read_oob_raw = nand_read_oob_syndrome; - ecc->write_oob_raw = nand_write_oob_syndrome; - - return 0; + return ret; } static void sunxi_nand_ecc_cleanup(struct nand_ecc_ctrl *ecc) { switch (ecc->mode) { case NAND_ECC_HW: - case NAND_ECC_HW_SYNDROME: - sunxi_nand_hw_common_ecc_ctrl_cleanup(ecc); + sunxi_nand_hw_ecc_ctrl_cleanup(ecc); break; case NAND_ECC_NONE: default: @@ -1991,11 +1881,6 @@ static int sunxi_nand_ecc_init(struct mtd_info *mtd, struct nand_ecc_ctrl *ecc, if (ret) return ret; break; - case NAND_ECC_HW_SYNDROME: - ret = sunxi_nand_hw_syndrome_ecc_ctrl_init(mtd, ecc, np); - if (ret) - return ret; - break; case NAND_ECC_NONE: case NAND_ECC_SOFT: break; From 5826b8802a970d2b0aaf097951de42040ee32480 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Wed, 21 Mar 2018 14:01:42 +0100 Subject: [PATCH 76/89] mtd: rawnand: brcmnand: fix probe function error path An error after nand_scan_tail() should trigger a nand_cleanup(). The helper mtd_device_register() returns an error code that should be checked and nand_cleanup() called accordingly. Signed-off-by: Miquel Raynal Signed-off-by: Boris Brezillon --- drivers/mtd/nand/raw/brcmnand/brcmnand.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/nand/raw/brcmnand/brcmnand.c b/drivers/mtd/nand/raw/brcmnand/brcmnand.c index c28fd2bc1a84..1306aaa7a8bf 100644 --- a/drivers/mtd/nand/raw/brcmnand/brcmnand.c +++ b/drivers/mtd/nand/raw/brcmnand/brcmnand.c @@ -2297,7 +2297,11 @@ static int brcmnand_init_cs(struct brcmnand_host *host, struct device_node *dn) if (ret) return ret; - return mtd_device_register(mtd, NULL, 0); + ret = mtd_device_register(mtd, NULL, 0); + if (ret) + nand_cleanup(chip); + + return ret; } static void brcmnand_save_restore_cs_config(struct brcmnand_host *host, From a446c998ff0cd49fa8023f607e9fc15ce45ec576 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Wed, 21 Mar 2018 14:01:43 +0100 Subject: [PATCH 77/89] mtd: rawnand: cafe: fix probe function error path An error after nand_scan_tail() should trigger a nand_cleanup(). The helper mtd_device_parse_register() returns an error code that should be checked and nand_cleanup() called accordingly. Signed-off-by: Miquel Raynal Signed-off-by: Boris Brezillon --- drivers/mtd/nand/raw/cafe_nand.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/nand/raw/cafe_nand.c b/drivers/mtd/nand/raw/cafe_nand.c index 3c1b6a3786b2..d8c8c9d1e640 100644 --- a/drivers/mtd/nand/raw/cafe_nand.c +++ b/drivers/mtd/nand/raw/cafe_nand.c @@ -774,10 +774,14 @@ static int cafe_nand_probe(struct pci_dev *pdev, pci_set_drvdata(pdev, mtd); mtd->name = "cafe_nand"; - mtd_device_parse_register(mtd, part_probes, NULL, NULL, 0); + err = mtd_device_parse_register(mtd, part_probes, NULL, NULL, 0); + if (err) + goto out_cleanup_nand; goto out; + out_cleanup_nand: + nand_cleanup(&cafe->nand); out_free_dma: dma_free_coherent(&cafe->pdev->dev, 2112, cafe->dmabuf, cafe->dmaaddr); out_irq: From 4acc3046ed5c1641874b89fe66ef8707d81ff80e Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Wed, 21 Mar 2018 14:01:44 +0100 Subject: [PATCH 78/89] mtd: rawnand: davinci: fix probe function error path An error after nand_scan_tail() should trigger a nand_cleanup(). The helper mtd_device_register() returns an error code that should be checked and nand_cleanup() called accordingly. Signed-off-by: Miquel Raynal Signed-off-by: Boris Brezillon --- drivers/mtd/nand/raw/davinci_nand.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/nand/raw/davinci_nand.c b/drivers/mtd/nand/raw/davinci_nand.c index ccc8c43abcff..0f09518d980f 100644 --- a/drivers/mtd/nand/raw/davinci_nand.c +++ b/drivers/mtd/nand/raw/davinci_nand.c @@ -826,7 +826,7 @@ static int nand_davinci_probe(struct platform_device *pdev) else ret = mtd_device_register(mtd, NULL, 0); if (ret < 0) - goto err; + goto err_cleanup_nand; val = davinci_nand_readl(info, NRCSR_OFFSET); dev_info(&pdev->dev, "controller rev. %d.%d\n", @@ -834,6 +834,9 @@ static int nand_davinci_probe(struct platform_device *pdev) return 0; +err_cleanup_nand: + nand_cleanup(&info->chip); + err: clk_disable_unprepare(info->clk); From 4e5d1d9078eda3de65f478b248cae882e2c0a839 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Wed, 21 Mar 2018 14:01:45 +0100 Subject: [PATCH 79/89] mtd: rawnand: denali: fix probe function error path An error after nand_scan_tail() should trigger a nand_cleanup(). The helper mtd_device_register() returns an error code that should be checked and nand_cleanup() called accordingly. Signed-off-by: Miquel Raynal Signed-off-by: Boris Brezillon --- drivers/mtd/nand/raw/denali.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/nand/raw/denali.c b/drivers/mtd/nand/raw/denali.c index 313c7f50621b..2a302a1d1430 100644 --- a/drivers/mtd/nand/raw/denali.c +++ b/drivers/mtd/nand/raw/denali.c @@ -1384,10 +1384,12 @@ int denali_init(struct denali_nand_info *denali) ret = mtd_device_register(mtd, NULL, 0); if (ret) { dev_err(denali->dev, "Failed to register MTD: %d\n", ret); - goto free_buf; + goto cleanup_nand; } return 0; +cleanup_nand: + nand_cleanup(chip); free_buf: kfree(denali->buf); disable_irq: From be051bf28f8084bd75f6fd67b2f3fb7d4883751d Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Wed, 21 Mar 2018 14:01:50 +0100 Subject: [PATCH 80/89] mtd: rawnand: mxc: fix probe function error path An error after nand_scan_tail() should trigger a nand_cleanup(). The helper mtd_device_parse_register() returns an error code that should be checked and nand_cleanup() called accordingly. Signed-off-by: Miquel Raynal Signed-off-by: Boris Brezillon --- drivers/mtd/nand/raw/mxc_nand.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/mtd/nand/raw/mxc_nand.c b/drivers/mtd/nand/raw/mxc_nand.c index 944ecf03d3b1..45786e707b7b 100644 --- a/drivers/mtd/nand/raw/mxc_nand.c +++ b/drivers/mtd/nand/raw/mxc_nand.c @@ -1911,15 +1911,18 @@ static int mxcnd_probe(struct platform_device *pdev) goto escan; /* Register the partitions */ - mtd_device_parse_register(mtd, part_probes, - NULL, - host->pdata.parts, - host->pdata.nr_parts); + err = mtd_device_parse_register(mtd, part_probes, NULL, + host->pdata.parts, + host->pdata.nr_parts); + if (err) + goto cleanup_nand; platform_set_drvdata(pdev, host); return 0; +cleanup_nand: + nand_cleanup(this); escan: if (host->clk_act) clk_disable_unprepare(host->clk); From 122bb3cb8b009aaa19fd8b09df8028ba8d49c043 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Wed, 21 Mar 2018 14:01:51 +0100 Subject: [PATCH 81/89] mtd: rawnand: omap2: fix the probe function error path An error after nand_scan_tail() should trigger a nand_cleanup(). The helper mtd_device_parse_register() returns an error code that should be checked and nand_cleanup() called accordingly. Signed-off-by: Miquel Raynal Signed-off-by: Boris Brezillon --- drivers/mtd/nand/raw/omap2.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/nand/raw/omap2.c b/drivers/mtd/nand/raw/omap2.c index 8cdf7d3d8fa7..e50c64adc3c8 100644 --- a/drivers/mtd/nand/raw/omap2.c +++ b/drivers/mtd/nand/raw/omap2.c @@ -2263,12 +2263,15 @@ scan_tail: err = mtd_device_register(mtd, NULL, 0); if (err) - goto return_error; + goto cleanup_nand; platform_set_drvdata(pdev, mtd); return 0; +cleanup_nand: + nand_cleanup(nand_chip); + return_error: if (!IS_ERR_OR_NULL(info->dma)) dma_release_channel(info->dma); From 5a3e8cde101209edb962ed42091db257f9f5ce5c Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Wed, 21 Mar 2018 14:01:52 +0100 Subject: [PATCH 82/89] mtd: rawnand: sh_flctl: fix the probe function error path An error after nand_scan_tail() should trigger a nand_cleanup(). The helper mtd_device_parse_register() returns an error code that should be checked and nand_cleanup() called accordingly. Signed-off-by: Miquel Raynal Signed-off-by: Boris Brezillon --- drivers/mtd/nand/raw/sh_flctl.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/mtd/nand/raw/sh_flctl.c b/drivers/mtd/nand/raw/sh_flctl.c index 7a740d583866..c7abceffcc40 100644 --- a/drivers/mtd/nand/raw/sh_flctl.c +++ b/drivers/mtd/nand/raw/sh_flctl.c @@ -1214,9 +1214,13 @@ static int flctl_probe(struct platform_device *pdev) goto err_chip; ret = mtd_device_register(flctl_mtd, pdata->parts, pdata->nr_parts); + if (ret) + goto cleanup_nand; return 0; +cleanup_nand: + nand_cleanup(nand); err_chip: flctl_release_dma(flctl); pm_runtime_disable(&pdev->dev); From 0eaa879be623f5e209e79a40f5e281f9c5c9170b Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Wed, 21 Mar 2018 14:01:53 +0100 Subject: [PATCH 83/89] mtd: rawnand: tango: fix probe function error path An error after nand_scan_tail() should trigger a nand_cleanup(). The helper mtd_device_parse_register() returns an error code that should be checked and nand_cleanup() called accordingly. Signed-off-by: Miquel Raynal Signed-off-by: Boris Brezillon --- drivers/mtd/nand/raw/tango_nand.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/nand/raw/tango_nand.c b/drivers/mtd/nand/raw/tango_nand.c index c5bee00b7f5e..f54518ffb36a 100644 --- a/drivers/mtd/nand/raw/tango_nand.c +++ b/drivers/mtd/nand/raw/tango_nand.c @@ -591,8 +591,10 @@ static int chip_init(struct device *dev, struct device_node *np) tchip->bb_cfg = BB_CFG(mtd->writesize, BBM_SIZE); err = mtd_device_register(mtd, NULL, 0); - if (err) + if (err) { + nand_cleanup(chip); return err; + } nfc->chips[cs] = tchip; From bb00ff2f4a746db95a44758d45bd3f715169ef6f Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Wed, 21 Mar 2018 14:01:57 +0100 Subject: [PATCH 84/89] mtd: rawnand: s3c2410: enhance the probe function error path Prepare the migration of the lpc32xx_slc driver to use nand_scan() by cleaning the error path in the probe function. Signed-off-by: Miquel Raynal Signed-off-by: Boris Brezillon --- drivers/mtd/nand/raw/s3c2410.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/mtd/nand/raw/s3c2410.c b/drivers/mtd/nand/raw/s3c2410.c index b5bc5f106c09..1bc0458063d8 100644 --- a/drivers/mtd/nand/raw/s3c2410.c +++ b/drivers/mtd/nand/raw/s3c2410.c @@ -124,13 +124,11 @@ struct s3c2410_nand_info; * @chip: The NAND chip information. * @set: The platform information supplied for this set of NAND chips. * @info: Link back to the hardware information. - * @scan_res: The result from calling nand_scan_ident(). */ struct s3c2410_nand_mtd { struct nand_chip chip; struct s3c2410_nand_set *set; struct s3c2410_nand_info *info; - int scan_res; }; enum s3c_cpu_type { @@ -1163,17 +1161,19 @@ static int s3c24xx_nand_probe(struct platform_device *pdev) mtd->dev.parent = &pdev->dev; s3c2410_nand_init_chip(info, nmtd, sets); - nmtd->scan_res = nand_scan_ident(mtd, - (sets) ? sets->nr_chips : 1, - NULL); + err = nand_scan_ident(mtd, (sets) ? sets->nr_chips : 1, NULL); + if (err) + goto exit_error; - if (nmtd->scan_res == 0) { - err = s3c2410_nand_update_chip(info, nmtd); - if (err < 0) - goto exit_error; - nand_scan_tail(mtd); - s3c2410_nand_add_partition(info, nmtd, sets); - } + err = s3c2410_nand_update_chip(info, nmtd); + if (err < 0) + goto exit_error; + + err = nand_scan_tail(mtd); + if (err) + goto exit_error; + + s3c2410_nand_add_partition(info, nmtd, sets); if (sets != NULL) sets++; From 6b6de6543dd5040727afc56a69c7ba6698dd3090 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Mon, 26 Mar 2018 11:53:01 +0200 Subject: [PATCH 85/89] mtd: rawnand: marvell: Rename ->ecc_clk into ->core_clk The core clock field was badly named ->ecc_clk which might lead to some confusion. Rename it ->core_clk. Signed-off-by: Boris Brezillon Acked-by: Miquel Raynal --- drivers/mtd/nand/raw/marvell_nand.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/mtd/nand/raw/marvell_nand.c b/drivers/mtd/nand/raw/marvell_nand.c index 3d84f4252af4..10e953218948 100644 --- a/drivers/mtd/nand/raw/marvell_nand.c +++ b/drivers/mtd/nand/raw/marvell_nand.c @@ -307,7 +307,7 @@ struct marvell_nfc_caps { * @controller: Base controller structure * @dev: Parent device (used to print error messages) * @regs: NAND controller registers - * @ecc_clk: ECC block clock, two times the NAND controller clock + * @core_clk: Core clock * @reg_clk: Regiters clock * @complete: Completion object to wait for NAND controller events * @assigned_cs: Bitmask describing already assigned CS lines @@ -321,7 +321,7 @@ struct marvell_nfc { struct nand_hw_control controller; struct device *dev; void __iomem *regs; - struct clk *ecc_clk; + struct clk *core_clk; struct clk *reg_clk; struct completion complete; unsigned long assigned_cs; @@ -2193,7 +2193,7 @@ static int marvell_nfc_setup_data_interface(struct mtd_info *mtd, int chipnr, struct nand_chip *chip = mtd_to_nand(mtd); struct marvell_nand_chip *marvell_nand = to_marvell_nand(chip); struct marvell_nfc *nfc = to_marvell_nfc(chip->controller); - unsigned int period_ns = 1000000000 / clk_get_rate(nfc->ecc_clk) * 2; + unsigned int period_ns = 1000000000 / clk_get_rate(nfc->core_clk) * 2; const struct nand_sdr_timings *sdr; struct marvell_nfc_timings nfc_tmg; int read_delay; @@ -2759,16 +2759,16 @@ static int marvell_nfc_probe(struct platform_device *pdev) return irq; } - nfc->ecc_clk = devm_clk_get(&pdev->dev, "core"); + nfc->core_clk = devm_clk_get(&pdev->dev, "core"); /* Managed the legacy case (when the first clock was not named) */ - if (nfc->ecc_clk == ERR_PTR(-ENOENT)) - nfc->ecc_clk = devm_clk_get(&pdev->dev, NULL); + if (nfc->core_clk == ERR_PTR(-ENOENT)) + nfc->core_clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(nfc->ecc_clk)) - return PTR_ERR(nfc->ecc_clk); + if (IS_ERR(nfc->core_clk)) + return PTR_ERR(nfc->core_clk); - ret = clk_prepare_enable(nfc->ecc_clk); + ret = clk_prepare_enable(nfc->core_clk); if (ret) return ret; @@ -2777,10 +2777,10 @@ static int marvell_nfc_probe(struct platform_device *pdev) if (!IS_ERR(nfc->reg_clk)) { ret = clk_prepare_enable(nfc->reg_clk); if (ret) - goto unprepare_ecc_clk; + goto unprepare_core_clk; } else { ret = PTR_ERR(nfc->reg_clk); - goto unprepare_ecc_clk; + goto unprepare_core_clk; } } @@ -2818,8 +2818,8 @@ static int marvell_nfc_probe(struct platform_device *pdev) unprepare_reg_clk: clk_disable_unprepare(nfc->reg_clk); -unprepare_ecc_clk: - clk_disable_unprepare(nfc->ecc_clk); +unprepare_core_clk: + clk_disable_unprepare(nfc->core_clk); return ret; } @@ -2836,7 +2836,7 @@ static int marvell_nfc_remove(struct platform_device *pdev) } clk_disable_unprepare(nfc->reg_clk); - clk_disable_unprepare(nfc->ecc_clk); + clk_disable_unprepare(nfc->core_clk); return 0; } From 94bf11bddad836380ecced299f4d5cb7d17a7dd1 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Wed, 14 Feb 2018 13:46:25 +0100 Subject: [PATCH 86/89] mtd: fsl-quadspi: Remove unneeded driver.bus assignment platform_driver_register() takes care of assigning driver->bus to &platform_bus_type, no need to explicitly assign it in the driver. Signed-off-by: Boris Brezillon Acked-by: Han Xu Signed-off-by: Cyrille Pitchen --- drivers/mtd/spi-nor/fsl-quadspi.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/mtd/spi-nor/fsl-quadspi.c b/drivers/mtd/spi-nor/fsl-quadspi.c index 2901c7bd9e30..dc9914fce296 100644 --- a/drivers/mtd/spi-nor/fsl-quadspi.c +++ b/drivers/mtd/spi-nor/fsl-quadspi.c @@ -1174,7 +1174,6 @@ static int fsl_qspi_resume(struct platform_device *pdev) static struct platform_driver fsl_qspi_driver = { .driver = { .name = "fsl-quadspi", - .bus = &platform_bus_type, .of_match_table = fsl_qspi_dt_ids, }, .probe = fsl_qspi_probe, From 097ccca726ffedb277c104aba45c59d075969e51 Mon Sep 17 00:00:00 2001 From: Xiaolei Li Date: Thu, 29 Mar 2018 09:34:59 +0800 Subject: [PATCH 87/89] mtd: nand: Fix some function description mismatches in core.c In core.c, some function descriptions do not match function definitions. Just fix these mismatches. Signed-off-by: Xiaolei Li Signed-off-by: Boris Brezillon --- drivers/mtd/nand/core.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/mtd/nand/core.c b/drivers/mtd/nand/core.c index f237a688f8e9..d0cd6f8635d7 100644 --- a/drivers/mtd/nand/core.c +++ b/drivers/mtd/nand/core.c @@ -51,7 +51,7 @@ EXPORT_SYMBOL_GPL(nanddev_isbad); /** * nanddev_markbad() - Mark a block as bad * @nand: NAND device - * @block: block to mark bad + * @pos: position of the block to mark bad * * Mark a block bad. This function is updating the BBT if available and * calls the low-level markbad hook (nand->ops->markbad()). @@ -117,9 +117,9 @@ EXPORT_SYMBOL_GPL(nanddev_isreserved); /** * nanddev_erase() - Erase a NAND portion * @nand: NAND device - * @block: eraseblock to erase + * @pos: position of the block to erase * - * Erases @block if it's not bad. + * Erases the block if it's not bad. * * Return: 0 in case of success, a negative error code otherwise. */ @@ -179,11 +179,11 @@ EXPORT_SYMBOL_GPL(nanddev_mtd_erase); /** * nanddev_init() - Initialize a NAND device * @nand: NAND device - * @memorg: NAND memory organization descriptor * @ops: NAND device operations + * @owner: NAND device owner * - * Initializes a NAND device object. Consistency checks are done on @memorg and - * @ops. Also takes care of initializing the BBT. + * Initializes a NAND device object. Consistency checks are done on @ops and + * @nand->memorg. Also takes care of initializing the BBT. * * Return: 0 in case of success, a negative error code otherwise. */ From 6898b240f8a16be8323ec58ad1214dd3ed121592 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Fri, 26 Jan 2018 19:23:24 -0200 Subject: [PATCH 88/89] mtd: fsl-quadspi: Distinguish the mtd device names Currently on a imx6sx-sdb board, which has two SPI NOR chips connected to QSPI2 the following output from /proc/mtd is seen: dev: size erasesize name mtd0: 01000000 00010000 "21e4000.qspi" mtd1: 01000000 00010000 "21e4000.qspi" Attempts to partition them on the kernel command line result in both chips with identical (and identically named) partitions, which is an inconvenient behavior. Assign a different mtd->name for each mtd device to avoid this problem. After this change the output from /proc/mtd becomes: dev: size erasesize name mtd0: 01000000 00010000 "21e4000.qspi-0" mtd1: 01000000 00010000 "21e4000.qspi-1" In order to keep mtdparts compatibility keep the mtd->name unchanged when a single SPI NOR is present. Reported-by: David Wolfe Signed-off-by: Fabio Estevam Reviewed-by: Boris Brezillon Acked-by: Han Xu Signed-off-by: Cyrille Pitchen Signed-off-by: Boris Brezillon --- drivers/mtd/spi-nor/fsl-quadspi.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/drivers/mtd/spi-nor/fsl-quadspi.c b/drivers/mtd/spi-nor/fsl-quadspi.c index dc9914fce296..3e3c0bbc45c0 100644 --- a/drivers/mtd/spi-nor/fsl-quadspi.c +++ b/drivers/mtd/spi-nor/fsl-quadspi.c @@ -1051,6 +1051,24 @@ static int fsl_qspi_probe(struct platform_device *pdev) spi_nor_set_flash_node(nor, np); nor->priv = q; + if (q->nor_num > 1 && !mtd->name) { + int spiflash_idx; + + ret = of_property_read_u32(np, "reg", &spiflash_idx); + if (!ret) { + mtd->name = devm_kasprintf(dev, GFP_KERNEL, + "%s-%d", + dev_name(dev), + spiflash_idx); + if (!mtd->name) { + ret = -ENOMEM; + goto mutex_failed; + } + } else { + dev_warn(dev, "reg property is missing\n"); + } + } + /* fill the hooks */ nor->read_reg = fsl_qspi_read_reg; nor->write_reg = fsl_qspi_write_reg; From e8de85d5a107352ff428f735b0afc8133bcbc3e5 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Fri, 26 Jan 2018 19:23:25 -0200 Subject: [PATCH 89/89] dt-bindings: fsl-quadspi: Add the example of two SPI NOR Improve the bindings example by adding an example of how to represent two SPI NOR devices. Signed-off-by: Fabio Estevam Acked-by: Han Xu Signed-off-by: Cyrille Pitchen Signed-off-by: Boris Brezillon --- .../devicetree/bindings/mtd/fsl-quadspi.txt | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/Documentation/devicetree/bindings/mtd/fsl-quadspi.txt b/Documentation/devicetree/bindings/mtd/fsl-quadspi.txt index 63d4d626fbd5..483e9cfac1b1 100644 --- a/Documentation/devicetree/bindings/mtd/fsl-quadspi.txt +++ b/Documentation/devicetree/bindings/mtd/fsl-quadspi.txt @@ -39,3 +39,27 @@ qspi0: quadspi@40044000 { .... }; }; + +Example showing the usage of two SPI NOR devices: + +&qspi2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_qspi2>; + status = "okay"; + + flash0: n25q256a@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "micron,n25q256a", "jedec,spi-nor"; + spi-max-frequency = <29000000>; + reg = <0>; + }; + + flash1: n25q256a@1 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "micron,n25q256a", "jedec,spi-nor"; + spi-max-frequency = <29000000>; + reg = <1>; + }; +};