From 981d1aa0697ce1393e00933f154d181e965703d0 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Thu, 24 Jan 2019 15:56:43 +0100 Subject: mtd: spinand: Use the spi-mem dirmap API Make use of the spi-mem direct mapping API to let advanced controllers optimize read/write operations when they support direct mapping. Signed-off-by: Boris Brezillon Cc: Stefan Roese Signed-off-by: Miquel Raynal Tested-by: Stefan Roese --- drivers/mtd/nand/spi/core.c | 168 ++++++++++++++++++++++---------------------- include/linux/mtd/spinand.h | 7 ++ 2 files changed, 91 insertions(+), 84 deletions(-) diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c index fa87ae28cdfe..fa54fe446b2d 100644 --- a/drivers/mtd/nand/spi/core.c +++ b/drivers/mtd/nand/spi/core.c @@ -19,21 +19,6 @@ #include #include -static void spinand_cache_op_adjust_colum(struct spinand_device *spinand, - const struct nand_page_io_req *req, - u16 *column) -{ - struct nand_device *nand = spinand_to_nand(spinand); - unsigned int shift; - - if (nand->memorg.planes_per_lun < 2) - return; - - /* The plane number is passed in MSB just above the column address */ - shift = fls(nand->memorg.pagesize); - *column |= req->pos.plane << shift; -} - static int spinand_read_reg_op(struct spinand_device *spinand, u8 reg, u8 *val) { struct spi_mem_op op = SPINAND_GET_FEATURE_OP(reg, @@ -227,27 +212,21 @@ static int spinand_load_page_op(struct spinand_device *spinand, static int spinand_read_from_cache_op(struct spinand_device *spinand, const struct nand_page_io_req *req) { - struct spi_mem_op op = *spinand->op_templates.read_cache; struct nand_device *nand = spinand_to_nand(spinand); struct mtd_info *mtd = nanddev_to_mtd(nand); - struct nand_page_io_req adjreq = *req; + struct spi_mem_dirmap_desc *rdesc; unsigned int nbytes = 0; void *buf = NULL; u16 column = 0; - int ret; + ssize_t ret; if (req->datalen) { - adjreq.datalen = nanddev_page_size(nand); - adjreq.dataoffs = 0; - adjreq.databuf.in = spinand->databuf; buf = spinand->databuf; - nbytes = adjreq.datalen; + nbytes = nanddev_page_size(nand); + column = 0; } if (req->ooblen) { - adjreq.ooblen = nanddev_per_page_oobsize(nand); - adjreq.ooboffs = 0; - adjreq.oobbuf.in = spinand->oobbuf; nbytes += nanddev_per_page_oobsize(nand); if (!buf) { buf = spinand->oobbuf; @@ -255,28 +234,19 @@ static int spinand_read_from_cache_op(struct spinand_device *spinand, } } - spinand_cache_op_adjust_colum(spinand, &adjreq, &column); - op.addr.val = column; + rdesc = spinand->dirmaps[req->pos.plane].rdesc; - /* - * Some controllers are limited in term of max RX data size. In this - * case, just repeat the READ_CACHE operation after updating the - * column. - */ while (nbytes) { - op.data.buf.in = buf; - op.data.nbytes = nbytes; - ret = spi_mem_adjust_op_size(spinand->spimem, &op); - if (ret) + ret = spi_mem_dirmap_read(rdesc, column, nbytes, buf); + if (ret < 0) return ret; - ret = spi_mem_exec_op(spinand->spimem, &op); - if (ret) - return ret; + if (!ret || ret > nbytes) + return -EIO; - buf += op.data.nbytes; - nbytes -= op.data.nbytes; - op.addr.val += op.data.nbytes; + nbytes -= ret; + column += ret; + buf += ret; } if (req->datalen) @@ -300,14 +270,12 @@ static int spinand_read_from_cache_op(struct spinand_device *spinand, static int spinand_write_to_cache_op(struct spinand_device *spinand, const struct nand_page_io_req *req) { - struct spi_mem_op op = *spinand->op_templates.write_cache; struct nand_device *nand = spinand_to_nand(spinand); struct mtd_info *mtd = nanddev_to_mtd(nand); - struct nand_page_io_req adjreq = *req; + struct spi_mem_dirmap_desc *wdesc; + unsigned int nbytes, column = 0; void *buf = spinand->databuf; - unsigned int nbytes; - u16 column = 0; - int ret; + ssize_t ret; /* * Looks like PROGRAM LOAD (AKA write cache) does not necessarily reset @@ -318,12 +286,6 @@ static int spinand_write_to_cache_op(struct spinand_device *spinand, */ nbytes = nanddev_page_size(nand) + nanddev_per_page_oobsize(nand); memset(spinand->databuf, 0xff, nbytes); - adjreq.dataoffs = 0; - adjreq.datalen = nanddev_page_size(nand); - adjreq.databuf.out = spinand->databuf; - adjreq.ooblen = nanddev_per_page_oobsize(nand); - adjreq.ooboffs = 0; - adjreq.oobbuf.out = spinand->oobbuf; if (req->datalen) memcpy(spinand->databuf + req->dataoffs, req->databuf.out, @@ -340,42 +302,19 @@ static int spinand_write_to_cache_op(struct spinand_device *spinand, req->ooblen); } - spinand_cache_op_adjust_colum(spinand, &adjreq, &column); + wdesc = spinand->dirmaps[req->pos.plane].wdesc; - op = *spinand->op_templates.write_cache; - op.addr.val = column; - - /* - * Some controllers are limited in term of max TX data size. In this - * case, split the operation into one LOAD CACHE and one or more - * LOAD RANDOM CACHE. - */ while (nbytes) { - op.data.buf.out = buf; - op.data.nbytes = nbytes; - - ret = spi_mem_adjust_op_size(spinand->spimem, &op); - if (ret) - return ret; - - ret = spi_mem_exec_op(spinand->spimem, &op); - if (ret) + ret = spi_mem_dirmap_write(wdesc, column, nbytes, buf); + if (ret < 0) return ret; - buf += op.data.nbytes; - nbytes -= op.data.nbytes; - op.addr.val += op.data.nbytes; + if (!ret || ret > nbytes) + return -EIO; - /* - * We need to use the RANDOM LOAD CACHE operation if there's - * more than one iteration, because the LOAD operation might - * reset the cache to 0xff. - */ - if (nbytes) { - column = op.addr.val; - op = *spinand->op_templates.update_cache; - op.addr.val = column; - } + nbytes -= ret; + column += ret; + buf += ret; } return 0; @@ -755,6 +694,59 @@ static int spinand_mtd_block_isreserved(struct mtd_info *mtd, loff_t offs) return ret; } +static int spinand_create_dirmap(struct spinand_device *spinand, + unsigned int plane) +{ + struct nand_device *nand = spinand_to_nand(spinand); + struct spi_mem_dirmap_info info = { + .length = nanddev_page_size(nand) + + nanddev_per_page_oobsize(nand), + }; + struct spi_mem_dirmap_desc *desc; + + /* The plane number is passed in MSB just above the column address */ + info.offset = plane << fls(nand->memorg.pagesize); + + info.op_tmpl = *spinand->op_templates.update_cache; + desc = devm_spi_mem_dirmap_create(&spinand->spimem->spi->dev, + spinand->spimem, &info); + if (IS_ERR(desc)) + return PTR_ERR(desc); + + spinand->dirmaps[plane].wdesc = desc; + + info.op_tmpl = *spinand->op_templates.read_cache; + desc = devm_spi_mem_dirmap_create(&spinand->spimem->spi->dev, + spinand->spimem, &info); + if (IS_ERR(desc)) + return PTR_ERR(desc); + + spinand->dirmaps[plane].rdesc = desc; + + return 0; +} + +static int spinand_create_dirmaps(struct spinand_device *spinand) +{ + struct nand_device *nand = spinand_to_nand(spinand); + int i, ret; + + spinand->dirmaps = devm_kzalloc(&spinand->spimem->spi->dev, + sizeof(*spinand->dirmaps) * + nand->memorg.planes_per_lun, + GFP_KERNEL); + if (!spinand->dirmaps) + return -ENOMEM; + + for (i = 0; i < nand->memorg.planes_per_lun; i++) { + ret = spinand_create_dirmap(spinand, i); + if (ret) + return ret; + } + + return 0; +} + static const struct nand_ops spinand_ops = { .erase = spinand_erase, .markbad = spinand_markbad, @@ -1012,6 +1004,14 @@ static int spinand_init(struct spinand_device *spinand) goto err_free_bufs; } + ret = spinand_create_dirmaps(spinand); + if (ret) { + dev_err(dev, + "Failed to create direct mappings for read/write operations (err = %d)\n", + ret); + goto err_manuf_cleanup; + } + /* After power up, all blocks are locked, so unlock them here. */ for (i = 0; i < nand->memorg.ntargets; i++) { ret = spinand_select_target(spinand, i); diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h index b92e2aa955b6..507f7e289bd1 100644 --- a/include/linux/mtd/spinand.h +++ b/include/linux/mtd/spinand.h @@ -302,6 +302,11 @@ struct spinand_info { __VA_ARGS__ \ } +struct spinand_dirmap { + struct spi_mem_dirmap_desc *wdesc; + struct spi_mem_dirmap_desc *rdesc; +}; + /** * struct spinand_device - SPI NAND device instance * @base: NAND device instance @@ -341,6 +346,8 @@ struct spinand_device { const struct spi_mem_op *update_cache; } op_templates; + struct spinand_dirmap *dirmaps; + int (*select_target)(struct spinand_device *spinand, unsigned int target); unsigned int cur_target; -- cgit From f67ed1461eff527f1b84867708ae17d92e4d76d0 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Thu, 7 Feb 2019 08:50:54 -0200 Subject: mtd: rawnand: gpmi: Introduce GPMI_IS_MXS() macro Introduce a GPMI_IS_MXS() macro to take into account the cases when mx23 or mx28 are used, which helps readability. Signed-off-by: Fabio Estevam Signed-off-by: Miquel Raynal --- drivers/mtd/nand/raw/gpmi-nand/gpmi-lib.c | 6 ++---- drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c | 2 +- drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.h | 1 + 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/mtd/nand/raw/gpmi-nand/gpmi-lib.c b/drivers/mtd/nand/raw/gpmi-nand/gpmi-lib.c index a4768df5083f..a8b26d2e793c 100644 --- a/drivers/mtd/nand/raw/gpmi-nand/gpmi-lib.c +++ b/drivers/mtd/nand/raw/gpmi-nand/gpmi-lib.c @@ -157,8 +157,7 @@ int gpmi_init(struct gpmi_nand_data *this) * Reset BCH here, too. We got failures otherwise :( * See later BCH reset for explanation of MX23 and MX28 handling */ - ret = gpmi_reset_block(r->bch_regs, - GPMI_IS_MX23(this) || GPMI_IS_MX28(this)); + ret = gpmi_reset_block(r->bch_regs, GPMI_IS_MXS(this)); if (ret) goto err_out; @@ -266,8 +265,7 @@ int bch_set_geometry(struct gpmi_nand_data *this) * chip, otherwise it will lock up. So we skip resetting BCH on the MX23. * and MX28. */ - ret = gpmi_reset_block(r->bch_regs, - GPMI_IS_MX23(this) || GPMI_IS_MX28(this)); + ret = gpmi_reset_block(r->bch_regs, GPMI_IS_MXS(this)); if (ret) goto err_out; diff --git a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c index ed405c9434fe..bcf5328cf239 100644 --- a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c +++ b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c @@ -171,7 +171,7 @@ static inline bool gpmi_check_ecc(struct gpmi_nand_data *this) struct bch_geometry *geo = &this->bch_geometry; /* Do the sanity check. */ - if (GPMI_IS_MX23(this) || GPMI_IS_MX28(this)) { + if (GPMI_IS_MXS(this)) { /* The mx23/mx28 only support the GF13. */ if (geo->gf_len == 14) return false; diff --git a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.h b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.h index d0b79bac2728..a804a4a5bd46 100644 --- a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.h +++ b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.h @@ -207,4 +207,5 @@ void gpmi_copy_bits(u8 *dst, size_t dst_bit_off, #define GPMI_IS_MX6(x) (GPMI_IS_MX6Q(x) || GPMI_IS_MX6SX(x) || \ GPMI_IS_MX7D(x)) +#define GPMI_IS_MXS(x) (GPMI_IS_MX23(x) || GPMI_IS_MX28(x)) #endif -- cgit From 64f1da10ca5e8a92bf397c43f852db1683d2e172 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Fri, 8 Feb 2019 11:49:30 -0600 Subject: mtd: rawnand: Mark expected switch fall-throughs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In preparation to enabling -Wimplicit-fallthrough, mark switch cases where we are expecting to fall through. This patch fixes the following warning: drivers/mtd/nand/raw/diskonchip.c: In function ‘doc_probe’: ./include/linux/printk.h:303:2: warning: this statement may fall through [-Wimplicit-fallthrough=] printk(KERN_ERR pr_fmt(fmt), ##__VA_ARGS__) ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ drivers/mtd/nand/raw/diskonchip.c:1479:4: note: in expansion of macro ‘pr_err’ pr_err("DiskOnChip Millennium Plus 32MB is not supported, ignoring.\n"); ^~~~~~ drivers/mtd/nand/raw/diskonchip.c:1480:3: note: here default: ^~~~~~~ drivers/mtd/nand/raw/nandsim.c: In function ‘ns_init_module’: drivers/mtd/nand/raw/nandsim.c:2254:22: warning: this statement may fall through [-Wimplicit-fallthrough=] chip->bbt_options |= NAND_BBT_NO_OOB; drivers/mtd/nand/raw/nandsim.c:2255:2: note: here case 1: ^~~~ drivers/mtd/nand/raw/nuc900_nand.c: In function ‘nuc900_nand_command_lp’: ./arch/x86/include/asm/io.h:91:22: warning: this statement may fall through [-Wimplicit-fallthrough=] #define __raw_writel __writel drivers/mtd/nand/raw/nuc900_nand.c:52:2: note: in expansion of macro ‘__raw_writel’ __raw_writel((val), (dev)->reg + REG_SMCMD) ^~~~~~~~~~~~ drivers/mtd/nand/raw/nuc900_nand.c:196:3: note: in expansion of macro ‘write_cmd_reg’ write_cmd_reg(nand, NAND_CMD_READSTART); ^~~~~~~~~~~~~ drivers/mtd/nand/raw/nuc900_nand.c:197:2: note: here default: ^~~~~~~ drivers/mtd/nand/raw/omap_elm.c: In function ‘elm_context_restore’: drivers/mtd/nand/raw/omap_elm.c:512:4: warning: this statement may fall through [-Wimplicit-fallthrough=] elm_write_reg(info, ELM_SYNDROME_FRAGMENT_4 + offset, ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ regs->elm_syndrome_fragment_4[i]); ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ drivers/mtd/nand/raw/omap_elm.c:514:3: note: here case BCH8_ECC: ^~~~ drivers/mtd/nand/raw/omap_elm.c:517:4: warning: this statement may fall through [-Wimplicit-fallthrough=] elm_write_reg(info, ELM_SYNDROME_FRAGMENT_2 + offset, ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ regs->elm_syndrome_fragment_2[i]); ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ drivers/mtd/nand/raw/omap_elm.c:519:3: note: here case BCH4_ECC: ^~~~ drivers/mtd/nand/raw/omap_elm.c: In function ‘elm_context_save’: drivers/mtd/nand/raw/omap_elm.c:466:37: warning: this statement may fall through [-Wimplicit-fallthrough=] regs->elm_syndrome_fragment_4[i] = elm_read_reg(info, ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~ ELM_SYNDROME_FRAGMENT_4 + offset); ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ drivers/mtd/nand/raw/omap_elm.c:468:3: note: here case BCH8_ECC: ^~~~ drivers/mtd/nand/raw/omap_elm.c:471:37: warning: this statement may fall through [-Wimplicit-fallthrough=] regs->elm_syndrome_fragment_2[i] = elm_read_reg(info, ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~ ELM_SYNDROME_FRAGMENT_2 + offset); ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ drivers/mtd/nand/raw/omap_elm.c:473:3: note: here case BCH4_ECC: ^~~~ Warning level 3 was used: -Wimplicit-fallthrough=3 This patch is part of the ongoing efforts to enabling -Wimplicit-fallthrough. Signed-off-by: Gustavo A. R. Silva Signed-off-by: Miquel Raynal --- drivers/mtd/nand/raw/diskonchip.c | 1 + drivers/mtd/nand/raw/nandsim.c | 6 ++++-- drivers/mtd/nand/raw/nuc900_nand.c | 3 ++- drivers/mtd/nand/raw/omap_elm.c | 4 ++++ 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/mtd/nand/raw/diskonchip.c b/drivers/mtd/nand/raw/diskonchip.c index 53f57e0f007e..ead54c90f2d1 100644 --- a/drivers/mtd/nand/raw/diskonchip.c +++ b/drivers/mtd/nand/raw/diskonchip.c @@ -1477,6 +1477,7 @@ static int __init doc_probe(unsigned long physadr) break; case DOC_ChipID_DocMilPlus32: pr_err("DiskOnChip Millennium Plus 32MB is not supported, ignoring.\n"); + /* fall through */ default: ret = -ENODEV; goto notfound; diff --git a/drivers/mtd/nand/raw/nandsim.c b/drivers/mtd/nand/raw/nandsim.c index 933d1a629c51..edf5fd3d5f07 100644 --- a/drivers/mtd/nand/raw/nandsim.c +++ b/drivers/mtd/nand/raw/nandsim.c @@ -2251,9 +2251,11 @@ static int __init ns_init_module(void) switch (bbt) { case 2: - chip->bbt_options |= NAND_BBT_NO_OOB; + chip->bbt_options |= NAND_BBT_NO_OOB; + /* fall through */ case 1: - chip->bbt_options |= NAND_BBT_USE_FLASH; + chip->bbt_options |= NAND_BBT_USE_FLASH; + /* fall through */ case 0: break; default: diff --git a/drivers/mtd/nand/raw/nuc900_nand.c b/drivers/mtd/nand/raw/nuc900_nand.c index 38b1994e7ed3..56fa84029482 100644 --- a/drivers/mtd/nand/raw/nuc900_nand.c +++ b/drivers/mtd/nand/raw/nuc900_nand.c @@ -192,8 +192,9 @@ static void nuc900_nand_command_lp(struct nand_chip *chip, return; case NAND_CMD_READ0: - write_cmd_reg(nand, NAND_CMD_READSTART); + /* fall through */ + default: if (!chip->legacy.dev_ready) { diff --git a/drivers/mtd/nand/raw/omap_elm.c b/drivers/mtd/nand/raw/omap_elm.c index a3f32f939cc1..94c6401ef32f 100644 --- a/drivers/mtd/nand/raw/omap_elm.c +++ b/drivers/mtd/nand/raw/omap_elm.c @@ -465,11 +465,13 @@ static int elm_context_save(struct elm_info *info) ELM_SYNDROME_FRAGMENT_5 + offset); regs->elm_syndrome_fragment_4[i] = elm_read_reg(info, ELM_SYNDROME_FRAGMENT_4 + offset); + /* fall through */ case BCH8_ECC: regs->elm_syndrome_fragment_3[i] = elm_read_reg(info, ELM_SYNDROME_FRAGMENT_3 + offset); regs->elm_syndrome_fragment_2[i] = elm_read_reg(info, ELM_SYNDROME_FRAGMENT_2 + offset); + /* fall through */ case BCH4_ECC: regs->elm_syndrome_fragment_1[i] = elm_read_reg(info, ELM_SYNDROME_FRAGMENT_1 + offset); @@ -511,11 +513,13 @@ static int elm_context_restore(struct elm_info *info) regs->elm_syndrome_fragment_5[i]); elm_write_reg(info, ELM_SYNDROME_FRAGMENT_4 + offset, regs->elm_syndrome_fragment_4[i]); + /* fall through */ case BCH8_ECC: elm_write_reg(info, ELM_SYNDROME_FRAGMENT_3 + offset, regs->elm_syndrome_fragment_3[i]); elm_write_reg(info, ELM_SYNDROME_FRAGMENT_2 + offset, regs->elm_syndrome_fragment_2[i]); + /* fall through */ case BCH4_ECC: elm_write_reg(info, ELM_SYNDROME_FRAGMENT_1 + offset, regs->elm_syndrome_fragment_1[i]); -- cgit From b309df2422c052330a2411c827eb697ee0114ac6 Mon Sep 17 00:00:00 2001 From: Tudor Ambarus Date: Wed, 13 Feb 2019 08:59:44 +0000 Subject: ARM: at91: add sam9x60 SFR definitions Keep generic names, as there are no conflicts with previous SFR definitions. While touching bits, update AT91_OHCIICR_USB_SUSPEND to use GENMASK, replace unused AT91_OHCIICR_SUSPEND_A/B/C with a more generic macro, align values on tab-width. Signed-off-by: Tudor Ambarus Acked-by: Alexandre Belloni Signed-off-by: Miquel Raynal --- include/soc/at91/atmel-sfr.h | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/include/soc/at91/atmel-sfr.h b/include/soc/at91/atmel-sfr.h index 482337af06b8..532fd784e86c 100644 --- a/include/soc/at91/atmel-sfr.h +++ b/include/soc/at91/atmel-sfr.h @@ -14,21 +14,41 @@ #define _LINUX_MFD_SYSCON_ATMEL_SFR_H #define AT91_SFR_DDRCFG 0x04 /* DDR Configuration Register */ +#define AT91_SFR_CCFG_EBICSA 0x04 /* EBI Chip Select Register */ /* 0x08 ~ 0x0c: Reserved */ #define AT91_SFR_OHCIICR 0x10 /* OHCI INT Configuration Register */ #define AT91_SFR_OHCIISR 0x14 /* OHCI INT Status Register */ #define AT91_SFR_UTMICKTRIM 0x30 /* UTMI Clock Trimming Register */ +#define AT91_SFR_UTMISWAP 0x3c /* UTMI DP/DM Pin Swapping Register */ +#define AT91_SFR_LS 0x7c /* Light Sleep Register */ #define AT91_SFR_I2SCLKSEL 0x90 /* I2SC Register */ +#define AT91_SFR_WPMR 0xe4 /* Write Protection Mode Register */ /* Field definitions */ -#define AT91_OHCIICR_SUSPEND_A BIT(8) -#define AT91_OHCIICR_SUSPEND_B BIT(9) -#define AT91_OHCIICR_SUSPEND_C BIT(10) +#define AT91_SFR_CCFG_EBI_CSA(cs, val) ((val) << (cs)) +#define AT91_SFR_CCFG_EBI_DBPUC BIT(8) +#define AT91_SFR_CCFG_EBI_DBPDC BIT(9) +#define AT91_SFR_CCFG_EBI_DRIVE BIT(17) +#define AT91_SFR_CCFG_NFD0_ON_D16 BIT(24) +#define AT91_SFR_CCFG_DDR_MP_EN BIT(25) -#define AT91_OHCIICR_USB_SUSPEND (AT91_OHCIICR_SUSPEND_A | \ - AT91_OHCIICR_SUSPEND_B | \ - AT91_OHCIICR_SUSPEND_C) +#define AT91_SFR_OHCIICR_RES(x) BIT(x) +#define AT91_SFR_OHCIICR_ARIE BIT(4) +#define AT91_SFR_OHCIICR_APPSTART BIT(5) +#define AT91_SFR_OHCIICR_USB_SUSP(x) BIT(8 + (x)) +#define AT91_SFR_OHCIICR_UDPPUDIS BIT(23) +#define AT91_OHCIICR_USB_SUSPEND GENMASK(10, 8) -#define AT91_UTMICKTRIM_FREQ GENMASK(1, 0) +#define AT91_SFR_OHCIISR_RIS(x) BIT(x) + +#define AT91_UTMICKTRIM_FREQ GENMASK(1, 0) + +#define AT91_SFR_UTMISWAP_PORT(x) BIT(x) + +#define AT91_SFR_LS_VALUE(x) BIT(x) +#define AT91_SFR_LS_MEM_POWER_GATING_ULP1_EN BIT(16) + +#define AT91_SFR_WPMR_WPEN BIT(0) +#define AT91_SFR_WPMR_WPKEY_MASK GENMASK(31, 8) #endif /* _LINUX_MFD_SYSCON_ATMEL_SFR_H */ -- cgit From ad7bdbc84730a898fba6eb5e839f20dab2098afd Mon Sep 17 00:00:00 2001 From: Tudor Ambarus Date: Wed, 13 Feb 2019 08:59:48 +0000 Subject: memory: atmel-ebi: add generic name for ebi regmap The sam9x60 board defines the CCFG_EBICSA register under SFR, and not as a MATRIX register, as previous boards do. Add a more generic name for the EBI regmap as a prerequisite for sam9x60 ebi support. Signed-off-by: Tudor Ambarus Acked-by: Alexandre Belloni Signed-off-by: Miquel Raynal --- drivers/memory/atmel-ebi.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/drivers/memory/atmel-ebi.c b/drivers/memory/atmel-ebi.c index c3748b414c27..b45914cfa212 100644 --- a/drivers/memory/atmel-ebi.c +++ b/drivers/memory/atmel-ebi.c @@ -36,6 +36,7 @@ struct atmel_ebi_dev { struct atmel_ebi_caps { unsigned int available_cs; unsigned int ebi_csa_offs; + const char *regmap_name; void (*get_config)(struct atmel_ebi_dev *ebid, struct atmel_ebi_dev_config *conf); int (*xlate_config)(struct atmel_ebi_dev *ebid, @@ -47,7 +48,7 @@ struct atmel_ebi_caps { struct atmel_ebi { struct clk *clk; - struct regmap *matrix; + struct regmap *regmap; struct { struct regmap *regmap; struct clk *clk; @@ -357,7 +358,7 @@ static int atmel_ebi_dev_setup(struct atmel_ebi *ebi, struct device_node *np, * one "atmel,smc-" property is present. */ if (ebi->caps->ebi_csa_offs && apply) - regmap_update_bits(ebi->matrix, + regmap_update_bits(ebi->regmap, ebi->caps->ebi_csa_offs, BIT(cs), 0); @@ -372,6 +373,7 @@ static int atmel_ebi_dev_setup(struct atmel_ebi *ebi, struct device_node *np, static const struct atmel_ebi_caps at91sam9260_ebi_caps = { .available_cs = 0xff, .ebi_csa_offs = AT91SAM9260_MATRIX_EBICSA, + .regmap_name = "atmel,matrix", .get_config = at91sam9_ebi_get_config, .xlate_config = atmel_ebi_xslate_smc_config, .apply_config = at91sam9_ebi_apply_config, @@ -380,6 +382,7 @@ static const struct atmel_ebi_caps at91sam9260_ebi_caps = { static const struct atmel_ebi_caps at91sam9261_ebi_caps = { .available_cs = 0xff, .ebi_csa_offs = AT91SAM9261_MATRIX_EBICSA, + .regmap_name = "atmel,matrix", .get_config = at91sam9_ebi_get_config, .xlate_config = atmel_ebi_xslate_smc_config, .apply_config = at91sam9_ebi_apply_config, @@ -388,6 +391,7 @@ static const struct atmel_ebi_caps at91sam9261_ebi_caps = { static const struct atmel_ebi_caps at91sam9263_ebi0_caps = { .available_cs = 0x3f, .ebi_csa_offs = AT91SAM9263_MATRIX_EBI0CSA, + .regmap_name = "atmel,matrix", .get_config = at91sam9_ebi_get_config, .xlate_config = atmel_ebi_xslate_smc_config, .apply_config = at91sam9_ebi_apply_config, @@ -396,6 +400,7 @@ static const struct atmel_ebi_caps at91sam9263_ebi0_caps = { static const struct atmel_ebi_caps at91sam9263_ebi1_caps = { .available_cs = 0x7, .ebi_csa_offs = AT91SAM9263_MATRIX_EBI1CSA, + .regmap_name = "atmel,matrix", .get_config = at91sam9_ebi_get_config, .xlate_config = atmel_ebi_xslate_smc_config, .apply_config = at91sam9_ebi_apply_config, @@ -404,6 +409,7 @@ static const struct atmel_ebi_caps at91sam9263_ebi1_caps = { static const struct atmel_ebi_caps at91sam9rl_ebi_caps = { .available_cs = 0x3f, .ebi_csa_offs = AT91SAM9RL_MATRIX_EBICSA, + .regmap_name = "atmel,matrix", .get_config = at91sam9_ebi_get_config, .xlate_config = atmel_ebi_xslate_smc_config, .apply_config = at91sam9_ebi_apply_config, @@ -412,6 +418,7 @@ static const struct atmel_ebi_caps at91sam9rl_ebi_caps = { static const struct atmel_ebi_caps at91sam9g45_ebi_caps = { .available_cs = 0x3f, .ebi_csa_offs = AT91SAM9G45_MATRIX_EBICSA, + .regmap_name = "atmel,matrix", .get_config = at91sam9_ebi_get_config, .xlate_config = atmel_ebi_xslate_smc_config, .apply_config = at91sam9_ebi_apply_config, @@ -420,6 +427,7 @@ static const struct atmel_ebi_caps at91sam9g45_ebi_caps = { static const struct atmel_ebi_caps at91sam9x5_ebi_caps = { .available_cs = 0x3f, .ebi_csa_offs = AT91SAM9X5_MATRIX_EBICSA, + .regmap_name = "atmel,matrix", .get_config = at91sam9_ebi_get_config, .xlate_config = atmel_ebi_xslate_smc_config, .apply_config = at91sam9_ebi_apply_config, @@ -543,13 +551,14 @@ static int atmel_ebi_probe(struct platform_device *pdev) /* * The sama5d3 does not provide an EBICSA register and thus does need - * to access the matrix registers. + * to access it. */ if (ebi->caps->ebi_csa_offs) { - ebi->matrix = - syscon_regmap_lookup_by_phandle(np, "atmel,matrix"); - if (IS_ERR(ebi->matrix)) - return PTR_ERR(ebi->matrix); + ebi->regmap = + syscon_regmap_lookup_by_phandle(np, + ebi->caps->regmap_name); + if (IS_ERR(ebi->regmap)) + return PTR_ERR(ebi->regmap); } ret = of_property_read_u32(np, "#address-cells", &val); -- cgit From 996acbfb1fe370cfaa3c7469e93fc54c634fba08 Mon Sep 17 00:00:00 2001 From: Tudor Ambarus Date: Wed, 13 Feb 2019 08:59:52 +0000 Subject: dt-bindings: memory: atmel-ebi: add sam9x60 compatible Add compatibility string for the sam9x60 EBI. Signed-off-by: Tudor Ambarus Acked-by: Alexandre Belloni Reviewed-by: Rob Herring Signed-off-by: Miquel Raynal --- Documentation/devicetree/bindings/memory-controllers/atmel,ebi.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/memory-controllers/atmel,ebi.txt b/Documentation/devicetree/bindings/memory-controllers/atmel,ebi.txt index 9bb5f57e2066..94bf7896a688 100644 --- a/Documentation/devicetree/bindings/memory-controllers/atmel,ebi.txt +++ b/Documentation/devicetree/bindings/memory-controllers/atmel,ebi.txt @@ -15,6 +15,7 @@ Required properties: "atmel,at91sam9g45-ebi" "atmel,at91sam9x5-ebi" "atmel,sama5d3-ebi" + "microchip,sam9x60-ebi" - reg: Contains offset/length value for EBI memory mapping. This property might contain several entries if the EBI -- cgit From 3e0863dd4c1f5b2c3b0ecd4320d3802ad975525d Mon Sep 17 00:00:00 2001 From: Tudor Ambarus Date: Wed, 13 Feb 2019 08:59:55 +0000 Subject: memory: atmel-ebi: add sam9x60 EBI support The sam9x60 board defines the CCFG_EBICSA register under SFR, and not as a MATRIX register, as previous boards do. Signed-off-by: Tudor Ambarus Acked-by: Alexandre Belloni Signed-off-by: Miquel Raynal --- drivers/memory/atmel-ebi.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/memory/atmel-ebi.c b/drivers/memory/atmel-ebi.c index b45914cfa212..0322df9dc249 100644 --- a/drivers/memory/atmel-ebi.c +++ b/drivers/memory/atmel-ebi.c @@ -17,6 +17,7 @@ #include #include #include +#include struct atmel_ebi_dev_config { int cs; @@ -440,6 +441,15 @@ static const struct atmel_ebi_caps sama5d3_ebi_caps = { .apply_config = sama5_ebi_apply_config, }; +static const struct atmel_ebi_caps sam9x60_ebi_caps = { + .available_cs = 0x3f, + .ebi_csa_offs = AT91_SFR_CCFG_EBICSA, + .regmap_name = "microchip,sfr", + .get_config = at91sam9_ebi_get_config, + .xlate_config = atmel_ebi_xslate_smc_config, + .apply_config = at91sam9_ebi_apply_config, +}; + static const struct of_device_id atmel_ebi_id_table[] = { { .compatible = "atmel,at91sam9260-ebi", @@ -473,6 +483,10 @@ static const struct of_device_id atmel_ebi_id_table[] = { .compatible = "atmel,sama5d3-ebi", .data = &sama5d3_ebi_caps, }, + { + .compatible = "microchip,sam9x60-ebi", + .data = &sam9x60_ebi_caps, + }, { /* sentinel */ } }; -- cgit From e2c19c506c87638559d436a068d11173c3991ffd Mon Sep 17 00:00:00 2001 From: Tudor Ambarus Date: Wed, 13 Feb 2019 08:59:58 +0000 Subject: mtd: rawnand: atmel: add generic name for EBICSA regmap The sam9x60 board defines the CCFG_EBICSA register under SFR, and not as a MATRIX register, as previous boards do. Add a more generic name for the EBICSA regmap, as a prerequisite for sam9x60 nand controller support. Signed-off-by: Tudor Ambarus Signed-off-by: Miquel Raynal --- drivers/mtd/nand/raw/atmel/nand-controller.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/drivers/mtd/nand/raw/atmel/nand-controller.c b/drivers/mtd/nand/raw/atmel/nand-controller.c index 5781fcf6b76c..6aef98b7338a 100644 --- a/drivers/mtd/nand/raw/atmel/nand-controller.c +++ b/drivers/mtd/nand/raw/atmel/nand-controller.c @@ -211,6 +211,7 @@ struct atmel_nand_controller_caps { bool legacy_of_bindings; u32 ale_offs; u32 cle_offs; + const char *ebi_csa_regmap_name; const struct atmel_nand_controller_ops *ops; }; @@ -233,7 +234,7 @@ to_nand_controller(struct nand_controller *ctl) struct atmel_smc_nand_controller { struct atmel_nand_controller base; - struct regmap *matrix; + struct regmap *ebi_csa_regmap; unsigned int ebi_csa_offs; }; @@ -1507,12 +1508,12 @@ static void atmel_smc_nand_init(struct atmel_nand_controller *nc, atmel_nand_init(nc, nand); smc_nc = to_smc_nand_controller(chip->controller); - if (!smc_nc->matrix) + if (!smc_nc->ebi_csa_regmap) return; /* Attach the CS to the NAND Flash logic. */ for (i = 0; i < nand->numcs; i++) - regmap_update_bits(smc_nc->matrix, smc_nc->ebi_csa_offs, + regmap_update_bits(smc_nc->ebi_csa_regmap, smc_nc->ebi_csa_offs, BIT(nand->cs[i].id), BIT(nand->cs[i].id)); } @@ -1833,7 +1834,7 @@ static void atmel_nand_controller_cleanup(struct atmel_nand_controller *nc) clk_put(nc->mck); } -static const struct of_device_id atmel_matrix_of_ids[] = { +static const struct of_device_id atmel_ebi_csa_regmap_of_ids[] = { { .compatible = "atmel,at91sam9260-matrix", .data = (void *)AT91SAM9260_MATRIX_EBICSA, @@ -1982,25 +1983,26 @@ atmel_smc_nand_controller_init(struct atmel_smc_nand_controller *nc) struct device_node *np; int ret; - /* We do not retrieve the matrix syscon when parsing old DTs. */ + /* We do not retrieve the EBICSA regmap when parsing old DTs. */ if (nc->base.caps->legacy_of_bindings) return 0; - np = of_parse_phandle(dev->parent->of_node, "atmel,matrix", 0); + np = of_parse_phandle(dev->parent->of_node, + nc->base.caps->ebi_csa_regmap_name, 0); if (!np) return 0; - match = of_match_node(atmel_matrix_of_ids, np); + match = of_match_node(atmel_ebi_csa_regmap_of_ids, np); if (!match) { of_node_put(np); return 0; } - nc->matrix = syscon_node_to_regmap(np); + nc->ebi_csa_regmap = syscon_node_to_regmap(np); of_node_put(np); - if (IS_ERR(nc->matrix)) { - ret = PTR_ERR(nc->matrix); - dev_err(dev, "Could not get Matrix regmap (err = %d)\n", ret); + if (IS_ERR(nc->ebi_csa_regmap)) { + ret = PTR_ERR(nc->ebi_csa_regmap); + dev_err(dev, "Could not get EBICSA regmap (err = %d)\n", ret); return ret; } @@ -2341,6 +2343,7 @@ static const struct atmel_nand_controller_ops at91rm9200_nc_ops = { static const struct atmel_nand_controller_caps atmel_rm9200_nc_caps = { .ale_offs = BIT(21), .cle_offs = BIT(22), + .ebi_csa_regmap_name = "atmel,matrix", .ops = &at91rm9200_nc_ops, }; @@ -2355,12 +2358,14 @@ static const struct atmel_nand_controller_ops atmel_smc_nc_ops = { static const struct atmel_nand_controller_caps atmel_sam9260_nc_caps = { .ale_offs = BIT(21), .cle_offs = BIT(22), + .ebi_csa_regmap_name = "atmel,matrix", .ops = &atmel_smc_nc_ops, }; static const struct atmel_nand_controller_caps atmel_sam9261_nc_caps = { .ale_offs = BIT(22), .cle_offs = BIT(21), + .ebi_csa_regmap_name = "atmel,matrix", .ops = &atmel_smc_nc_ops, }; @@ -2368,6 +2373,7 @@ static const struct atmel_nand_controller_caps atmel_sam9g45_nc_caps = { .has_dma = true, .ale_offs = BIT(21), .cle_offs = BIT(22), + .ebi_csa_regmap_name = "atmel,matrix", .ops = &atmel_smc_nc_ops, }; -- cgit From b1e8e0aa15a08a40af496b3377efa90e1750ab3d Mon Sep 17 00:00:00 2001 From: Tudor Ambarus Date: Wed, 13 Feb 2019 09:00:01 +0000 Subject: dt-bindings: mtd: atmel-nand: add sam9x60 compatible Add compatibility string for the sam9x60 nand controller. Signed-off-by: Tudor Ambarus Reviewed-by: Rob Herring Signed-off-by: Miquel Raynal --- Documentation/devicetree/bindings/mtd/atmel-nand.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/mtd/atmel-nand.txt b/Documentation/devicetree/bindings/mtd/atmel-nand.txt index 9bb66e476672..68b51dc58816 100644 --- a/Documentation/devicetree/bindings/mtd/atmel-nand.txt +++ b/Documentation/devicetree/bindings/mtd/atmel-nand.txt @@ -14,6 +14,7 @@ Required properties: "atmel,at91sam9261-nand-controller" "atmel,at91sam9g45-nand-controller" "atmel,sama5d3-nand-controller" + "microchip,sam9x60-nand-controller" - ranges: empty ranges property to forward EBI ranges definitions. - #address-cells: should be set to 2. - #size-cells: should be set to 1. -- cgit From ccf20ccccea39446fe15fe503d050c6a8fae1eff Mon Sep 17 00:00:00 2001 From: Tudor Ambarus Date: Wed, 13 Feb 2019 09:00:05 +0000 Subject: mtd: rawnand: atmel: add sam9x60 nand controller support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The sam9x60 board defines the CCFG_EBICSA register under SFR, and not as a MATRIX register, as previous boards do. NAND Flash I/Os are connected to D16–D23, thus SFR_CCFG_EBICSA.NFD0_ON_D16 is set to 1. Signed-off-by: Tudor Ambarus Signed-off-by: Miquel Raynal --- drivers/mtd/nand/raw/atmel/nand-controller.c | 86 ++++++++++++++++++++++++---- 1 file changed, 74 insertions(+), 12 deletions(-) diff --git a/drivers/mtd/nand/raw/atmel/nand-controller.c b/drivers/mtd/nand/raw/atmel/nand-controller.c index 6aef98b7338a..ff85be0e2de3 100644 --- a/drivers/mtd/nand/raw/atmel/nand-controller.c +++ b/drivers/mtd/nand/raw/atmel/nand-controller.c @@ -65,6 +65,7 @@ #include #include #include +#include #include "pmecc.h" @@ -232,10 +233,15 @@ to_nand_controller(struct nand_controller *ctl) return container_of(ctl, struct atmel_nand_controller, base); } +struct atmel_smc_nand_ebi_csa_cfg { + u32 offs; + u32 nfd0_on_d16; +}; + struct atmel_smc_nand_controller { struct atmel_nand_controller base; struct regmap *ebi_csa_regmap; - unsigned int ebi_csa_offs; + struct atmel_smc_nand_ebi_csa_cfg *ebi_csa; }; static inline struct atmel_smc_nand_controller * @@ -1513,8 +1519,15 @@ static void atmel_smc_nand_init(struct atmel_nand_controller *nc, /* Attach the CS to the NAND Flash logic. */ for (i = 0; i < nand->numcs; i++) - regmap_update_bits(smc_nc->ebi_csa_regmap, smc_nc->ebi_csa_offs, + regmap_update_bits(smc_nc->ebi_csa_regmap, + smc_nc->ebi_csa->offs, BIT(nand->cs[i].id), BIT(nand->cs[i].id)); + + if (smc_nc->ebi_csa->nfd0_on_d16) + regmap_update_bits(smc_nc->ebi_csa_regmap, + smc_nc->ebi_csa->offs, + smc_nc->ebi_csa->nfd0_on_d16, + smc_nc->ebi_csa->nfd0_on_d16); } static void atmel_hsmc_nand_init(struct atmel_nand_controller *nc, @@ -1834,34 +1847,71 @@ static void atmel_nand_controller_cleanup(struct atmel_nand_controller *nc) clk_put(nc->mck); } +static const struct atmel_smc_nand_ebi_csa_cfg at91sam9260_ebi_csa = { + .offs = AT91SAM9260_MATRIX_EBICSA, +}; + +static const struct atmel_smc_nand_ebi_csa_cfg at91sam9261_ebi_csa = { + .offs = AT91SAM9261_MATRIX_EBICSA, +}; + +static const struct atmel_smc_nand_ebi_csa_cfg at91sam9263_ebi_csa = { + .offs = AT91SAM9263_MATRIX_EBI0CSA, +}; + +static const struct atmel_smc_nand_ebi_csa_cfg at91sam9rl_ebi_csa = { + .offs = AT91SAM9RL_MATRIX_EBICSA, +}; + +static const struct atmel_smc_nand_ebi_csa_cfg at91sam9g45_ebi_csa = { + .offs = AT91SAM9G45_MATRIX_EBICSA, +}; + +static const struct atmel_smc_nand_ebi_csa_cfg at91sam9n12_ebi_csa = { + .offs = AT91SAM9N12_MATRIX_EBICSA, +}; + +static const struct atmel_smc_nand_ebi_csa_cfg at91sam9x5_ebi_csa = { + .offs = AT91SAM9X5_MATRIX_EBICSA, +}; + +static const struct atmel_smc_nand_ebi_csa_cfg sam9x60_ebi_csa = { + .offs = AT91_SFR_CCFG_EBICSA, + .nfd0_on_d16 = AT91_SFR_CCFG_NFD0_ON_D16, +}; + static const struct of_device_id atmel_ebi_csa_regmap_of_ids[] = { { .compatible = "atmel,at91sam9260-matrix", - .data = (void *)AT91SAM9260_MATRIX_EBICSA, + .data = &at91sam9260_ebi_csa, }, { .compatible = "atmel,at91sam9261-matrix", - .data = (void *)AT91SAM9261_MATRIX_EBICSA, + .data = &at91sam9261_ebi_csa, }, { .compatible = "atmel,at91sam9263-matrix", - .data = (void *)AT91SAM9263_MATRIX_EBI0CSA, + .data = &at91sam9263_ebi_csa, }, { .compatible = "atmel,at91sam9rl-matrix", - .data = (void *)AT91SAM9RL_MATRIX_EBICSA, + .data = &at91sam9rl_ebi_csa, }, { .compatible = "atmel,at91sam9g45-matrix", - .data = (void *)AT91SAM9G45_MATRIX_EBICSA, + .data = &at91sam9g45_ebi_csa, }, { .compatible = "atmel,at91sam9n12-matrix", - .data = (void *)AT91SAM9N12_MATRIX_EBICSA, + .data = &at91sam9n12_ebi_csa, }, { .compatible = "atmel,at91sam9x5-matrix", - .data = (void *)AT91SAM9X5_MATRIX_EBICSA, + .data = &at91sam9x5_ebi_csa, + }, + { + .compatible = "microchip,sam9x60-sfr", + .data = &sam9x60_ebi_csa, }, { /* sentinel */ }, }; @@ -2006,15 +2056,15 @@ atmel_smc_nand_controller_init(struct atmel_smc_nand_controller *nc) return ret; } - nc->ebi_csa_offs = (uintptr_t)match->data; + nc->ebi_csa = (struct atmel_smc_nand_ebi_csa_cfg *)match->data; /* * The at91sam9263 has 2 EBIs, if the NAND controller is under EBI1 - * add 4 to ->ebi_csa_offs. + * add 4 to ->ebi_csa->offs. */ if (of_device_is_compatible(dev->parent->of_node, "atmel,at91sam9263-ebi1")) - nc->ebi_csa_offs += 4; + nc->ebi_csa->offs += 4; return 0; } @@ -2377,6 +2427,14 @@ static const struct atmel_nand_controller_caps atmel_sam9g45_nc_caps = { .ops = &atmel_smc_nc_ops, }; +static const struct atmel_nand_controller_caps microchip_sam9x60_nc_caps = { + .has_dma = true, + .ale_offs = BIT(21), + .cle_offs = BIT(22), + .ebi_csa_regmap_name = "microchip,sfr", + .ops = &atmel_smc_nc_ops, +}; + /* Only used to parse old bindings. */ static const struct atmel_nand_controller_caps atmel_rm9200_nand_caps = { .ale_offs = BIT(21), @@ -2421,6 +2479,10 @@ static const struct of_device_id atmel_nand_controller_of_ids[] = { .compatible = "atmel,sama5d3-nand-controller", .data = &atmel_sama5_nc_caps, }, + { + .compatible = "microchip,sam9x60-nand-controller", + .data = µchip_sam9x60_nc_caps, + }, /* Support for old/deprecated bindings: */ { .compatible = "atmel,at91rm9200-nand", -- cgit From b849f8b59c682c2f3c55e14224d6d4d5360fc605 Mon Sep 17 00:00:00 2001 From: Tudor Ambarus Date: Wed, 13 Feb 2019 09:00:17 +0000 Subject: mtd: rawnand: atmel: switch to SPDX license identifiers Adopt the SPDX license identifiers to ease license compliance management. Signed-off-by: Tudor Ambarus Signed-off-by: Miquel Raynal --- drivers/mtd/nand/raw/atmel/nand-controller.c | 5 +---- drivers/mtd/nand/raw/atmel/pmecc.c | 5 +---- drivers/mtd/nand/raw/atmel/pmecc.h | 6 +----- 3 files changed, 3 insertions(+), 13 deletions(-) diff --git a/drivers/mtd/nand/raw/atmel/nand-controller.c b/drivers/mtd/nand/raw/atmel/nand-controller.c index ff85be0e2de3..3205b705d734 100644 --- a/drivers/mtd/nand/raw/atmel/nand-controller.c +++ b/drivers/mtd/nand/raw/atmel/nand-controller.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright 2017 ATMEL * Copyright 2017 Free Electrons @@ -29,10 +30,6 @@ * Add Nand Flash Controller support for SAMA5 SoC * Copyright 2013 ATMEL, Josh Wu (josh.wu@atmel.com) * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * A few words about the naming convention in this file. This convention * applies to structure and function names. * diff --git a/drivers/mtd/nand/raw/atmel/pmecc.c b/drivers/mtd/nand/raw/atmel/pmecc.c index 9d3997840889..cbb023bf00f7 100644 --- a/drivers/mtd/nand/raw/atmel/pmecc.c +++ b/drivers/mtd/nand/raw/atmel/pmecc.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright 2017 ATMEL * Copyright 2017 Free Electrons @@ -28,10 +29,6 @@ * Add Nand Flash Controller support for SAMA5 SoC * Copyright 2013 ATMEL, Josh Wu (josh.wu@atmel.com) * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * The PMECC is an hardware assisted BCH engine, which means part of the * ECC algorithm is left to the software. The hardware/software repartition * is explained in the "PMECC Controller Functional Description" chapter in diff --git a/drivers/mtd/nand/raw/atmel/pmecc.h b/drivers/mtd/nand/raw/atmel/pmecc.h index 808f1be0d6ad..7851c05126cf 100644 --- a/drivers/mtd/nand/raw/atmel/pmecc.h +++ b/drivers/mtd/nand/raw/atmel/pmecc.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * © Copyright 2016 ATMEL * © Copyright 2016 Free Electrons @@ -28,11 +29,6 @@ * * Add Nand Flash Controller support for SAMA5 SoC * © Copyright 2013 ATMEL, Josh Wu (josh.wu@atmel.com) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #ifndef ATMEL_PMECC_H -- cgit From 91e9dd7720848fc0bd1c0a96d4dd0b169d8e542a Mon Sep 17 00:00:00 2001 From: Martin Blumenstingl Date: Mon, 18 Mar 2019 21:47:21 +0100 Subject: mtd: rawnand: meson: add missing ENOMEM check in meson_nfc_read_buf() kzalloc() can return NULL if memory could not be allocated. Check the return value of the kzalloc() call in meson_nfc_read_buf() to make it consistent with other memory allocations within the meson_nand driver. Fixes: 8fae856c53500a ("mtd: rawnand: meson: add support for Amlogic NAND flash controller") Signed-off-by: Martin Blumenstingl Acked-by: Liang Yang Reviewed-by: Kevin Hilman Signed-off-by: Miquel Raynal --- drivers/mtd/nand/raw/meson_nand.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/mtd/nand/raw/meson_nand.c b/drivers/mtd/nand/raw/meson_nand.c index 3e8aa71407b5..a1d8506b61c7 100644 --- a/drivers/mtd/nand/raw/meson_nand.c +++ b/drivers/mtd/nand/raw/meson_nand.c @@ -528,6 +528,9 @@ static int meson_nfc_read_buf(struct nand_chip *nand, u8 *buf, int len) u8 *info; info = kzalloc(PER_INFO_BYTE, GFP_KERNEL); + if (!info) + return -ENOMEM; + ret = meson_nfc_dma_buffer_setup(nand, buf, len, info, PER_INFO_BYTE, DMA_FROM_DEVICE); if (ret) -- cgit From 6d50e9b6dcd0013c2ab690fcd1f3efce9daf9ce9 Mon Sep 17 00:00:00 2001 From: Martin Blumenstingl Date: Mon, 18 Mar 2019 21:47:22 +0100 Subject: mtd: rawnand: meson: fix a potential memory leak in meson_nfc_read_buf meson_nfc_dma_buffer_setup() is called with the "info" buffer which is allocated a few lines before using kzalloc(). If meson_nfc_dma_buffer_setup() fails we need to free the allocated "info" buffer instead of only freeing it upon success. Fixes: 8fae856c53500a ("mtd: rawnand: meson: add support for Amlogic NAND flash controller") Signed-off-by: Martin Blumenstingl Acked-by: Liang Yang Reviewed-by: Kevin Hilman Signed-off-by: Miquel Raynal --- drivers/mtd/nand/raw/meson_nand.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/nand/raw/meson_nand.c b/drivers/mtd/nand/raw/meson_nand.c index a1d8506b61c7..38db4fd61459 100644 --- a/drivers/mtd/nand/raw/meson_nand.c +++ b/drivers/mtd/nand/raw/meson_nand.c @@ -534,7 +534,7 @@ static int meson_nfc_read_buf(struct nand_chip *nand, u8 *buf, int len) ret = meson_nfc_dma_buffer_setup(nand, buf, len, info, PER_INFO_BYTE, DMA_FROM_DEVICE); if (ret) - return ret; + goto out; cmd = NFC_CMD_N2M | (len & GENMASK(5, 0)); writel(cmd, nfc->reg_base + NFC_REG_CMD); @@ -542,6 +542,8 @@ static int meson_nfc_read_buf(struct nand_chip *nand, u8 *buf, int len) meson_nfc_drain_cmd(nfc); meson_nfc_wait_cmd_finish(nfc, 1000); meson_nfc_dma_buffer_release(nand, len, PER_INFO_BYTE, DMA_FROM_DEVICE); + +out: kfree(info); return ret; -- cgit From a07c63d3e95de359f71e991dfdf53b47cb23c15d Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Tue, 19 Mar 2019 15:53:51 +0100 Subject: dt-bindings: mtd: ingenic: Add compatible strings for JZ4740 and JZ4725B Add compatible strings to probe the jz4780-nand and jz4780-bch drivers from devicetree on the JZ4725B and JZ4740 SoCs from Ingenic. Signed-off-by: Paul Cercueil Reviewed-by: Rob Herring Signed-off-by: Miquel Raynal --- Documentation/devicetree/bindings/mtd/ingenic,jz4780-nand.txt | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/mtd/ingenic,jz4780-nand.txt b/Documentation/devicetree/bindings/mtd/ingenic,jz4780-nand.txt index 29ea5853ca91..a5b940f18bf6 100644 --- a/Documentation/devicetree/bindings/mtd/ingenic,jz4780-nand.txt +++ b/Documentation/devicetree/bindings/mtd/ingenic,jz4780-nand.txt @@ -6,7 +6,10 @@ memory-controllers/ingenic,jz4780-nemc.txt), and thus NAND device nodes must be children of the NEMC node. Required NAND controller device properties: -- compatible: Should be set to "ingenic,jz4780-nand". +- compatible: Should be one of: + * ingenic,jz4740-nand + * ingenic,jz4725b-nand + * ingenic,jz4780-nand - reg: For each bank with a NAND chip attached, should specify a bank number, an offset of 0 and a size of 0x1000000 (i.e. the whole NEMC bank). @@ -72,7 +75,10 @@ NAND devices. The following is a description of the device properties for a BCH controller. Required BCH properties: -- compatible: Should be set to "ingenic,jz4780-bch". +- compatible: Should be one of: + * ingenic,jz4740-ecc + * ingenic,jz4725b-bch + * ingenic,jz4780-bch - reg: Should specify the BCH controller registers location and length. - clocks: Clock for the BCH controller. -- cgit From 057c319a0fe697b2fc9c55015fec601123f7ac4b Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Tue, 19 Mar 2019 15:53:52 +0100 Subject: dt-bindings: mtd: ingenic: Change 'BCH' to 'ECC' in documentation The JZ4740 ECC hardware is not BCH but Reed-Solomon, so it makes more sense to use the more generic ECC term. Signed-off-by: Paul Cercueil Reviewed-by: Rob Herring Signed-off-by: Miquel Raynal --- .../devicetree/bindings/mtd/ingenic,jz4780-nand.txt | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Documentation/devicetree/bindings/mtd/ingenic,jz4780-nand.txt b/Documentation/devicetree/bindings/mtd/ingenic,jz4780-nand.txt index a5b940f18bf6..5a45cc54f46d 100644 --- a/Documentation/devicetree/bindings/mtd/ingenic,jz4780-nand.txt +++ b/Documentation/devicetree/bindings/mtd/ingenic,jz4780-nand.txt @@ -1,4 +1,4 @@ -* Ingenic JZ4780 NAND/BCH +* Ingenic JZ4780 NAND/ECC This file documents the device tree bindings for NAND flash devices on the JZ4780. NAND devices are connected to the NEMC controller (described in @@ -14,10 +14,10 @@ Required NAND controller device properties: an offset of 0 and a size of 0x1000000 (i.e. the whole NEMC bank). Optional NAND controller device properties: -- ingenic,bch-controller: To make use of the hardware BCH controller, this - property must contain a phandle for the BCH controller node. The required +- ingenic,bch-controller: To make use of the hardware ECC controller, this + property must contain a phandle for the ECC controller node. The required properties for this node are described below. If this is not specified, - software BCH will be used instead. + software ECC will be used instead. Optional children nodes: - Individual NAND chips are children of the NAND controller node. @@ -70,17 +70,17 @@ nemc: nemc@13410000 { }; }; -The BCH controller is a separate SoC component used for error correction on +The ECC controller is a separate SoC component used for error correction on NAND devices. The following is a description of the device properties for a -BCH controller. +ECC controller. -Required BCH properties: +Required ECC properties: - compatible: Should be one of: * ingenic,jz4740-ecc * ingenic,jz4725b-bch * ingenic,jz4780-bch -- reg: Should specify the BCH controller registers location and length. -- clocks: Clock for the BCH controller. +- reg: Should specify the ECC controller registers location and length. +- clocks: Clock for the ECC controller. Example: -- cgit From badb37f1601de0642330125928104e2d19dcc8da Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Tue, 19 Mar 2019 15:53:53 +0100 Subject: dt-bindings: mtd: ingenic: Use standard ecc-engine property The 'ingenic,bch-controller' property is now deprecated and the 'ecc-engine' property should be used instead. Signed-off-by: Paul Cercueil Reviewed-by: Rob Herring Signed-off-by: Miquel Raynal --- Documentation/devicetree/bindings/mtd/ingenic,jz4780-nand.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/mtd/ingenic,jz4780-nand.txt b/Documentation/devicetree/bindings/mtd/ingenic,jz4780-nand.txt index 5a45cc54f46d..c02259353327 100644 --- a/Documentation/devicetree/bindings/mtd/ingenic,jz4780-nand.txt +++ b/Documentation/devicetree/bindings/mtd/ingenic,jz4780-nand.txt @@ -14,7 +14,7 @@ Required NAND controller device properties: an offset of 0 and a size of 0x1000000 (i.e. the whole NEMC bank). Optional NAND controller device properties: -- ingenic,bch-controller: To make use of the hardware ECC controller, this +- ecc-engine: To make use of the hardware ECC controller, this property must contain a phandle for the ECC controller node. The required properties for this node are described below. If this is not specified, software ECC will be used instead. @@ -48,7 +48,7 @@ nemc: nemc@13410000 { #address-cells = <1>; #size-cells = <0>; - ingenic,bch-controller = <&bch>; + ecc-engine = <&bch>; nand@1 { reg = <1>; -- cgit From 1838a7b31fcb634df771e1ae1beb9723de47f6bd Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Tue, 19 Mar 2019 15:53:54 +0100 Subject: mtd: rawnand: Move drivers for Ingenic SoCs to subfolder Before adding support for more SoCs and seeing the number of files for these drivers grow, we move them to their own subfolder to keep it tidy. Signed-off-by: Paul Cercueil Signed-off-by: Miquel Raynal --- drivers/mtd/nand/raw/Kconfig | 14 +- drivers/mtd/nand/raw/Makefile | 3 +- drivers/mtd/nand/raw/ingenic/Kconfig | 13 + drivers/mtd/nand/raw/ingenic/Makefile | 2 + drivers/mtd/nand/raw/ingenic/jz4740_nand.c | 542 +++++++++++++++++++++++++++++ drivers/mtd/nand/raw/ingenic/jz4780_bch.c | 385 ++++++++++++++++++++ drivers/mtd/nand/raw/ingenic/jz4780_bch.h | 43 +++ drivers/mtd/nand/raw/ingenic/jz4780_nand.c | 415 ++++++++++++++++++++++ drivers/mtd/nand/raw/jz4740_nand.c | 542 ----------------------------- drivers/mtd/nand/raw/jz4780_bch.c | 385 -------------------- drivers/mtd/nand/raw/jz4780_bch.h | 43 --- drivers/mtd/nand/raw/jz4780_nand.c | 415 ---------------------- 12 files changed, 1402 insertions(+), 1400 deletions(-) create mode 100644 drivers/mtd/nand/raw/ingenic/Kconfig create mode 100644 drivers/mtd/nand/raw/ingenic/Makefile create mode 100644 drivers/mtd/nand/raw/ingenic/jz4740_nand.c create mode 100644 drivers/mtd/nand/raw/ingenic/jz4780_bch.c create mode 100644 drivers/mtd/nand/raw/ingenic/jz4780_bch.h create mode 100644 drivers/mtd/nand/raw/ingenic/jz4780_nand.c delete mode 100644 drivers/mtd/nand/raw/jz4740_nand.c delete mode 100644 drivers/mtd/nand/raw/jz4780_bch.c delete mode 100644 drivers/mtd/nand/raw/jz4780_bch.h delete mode 100644 drivers/mtd/nand/raw/jz4780_nand.c diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig index e604625e2dfa..705863c6709a 100644 --- a/drivers/mtd/nand/raw/Kconfig +++ b/drivers/mtd/nand/raw/Kconfig @@ -470,19 +470,7 @@ config MTD_NAND_NUC900 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 || COMPILE_TEST - depends on HAS_IOMEM - help - Enables support for NAND Flash on JZ4740 SoC based boards. - -config MTD_NAND_JZ4780 - tristate "Support for NAND on JZ4780 SoC" - depends on 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. +source "drivers/mtd/nand/raw/ingenic/Kconfig" config MTD_NAND_FSMC tristate "Support for NAND on ST Micros FSMC" diff --git a/drivers/mtd/nand/raw/Makefile b/drivers/mtd/nand/raw/Makefile index 5a5a72f0793e..5552c4a9f2cf 100644 --- a/drivers/mtd/nand/raw/Makefile +++ b/drivers/mtd/nand/raw/Makefile @@ -45,8 +45,7 @@ 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-y += ingenic/ obj-$(CONFIG_MTD_NAND_GPMI_NAND) += gpmi-nand/ obj-$(CONFIG_MTD_NAND_XWAY) += xway_nand.o obj-$(CONFIG_MTD_NAND_BCM47XXNFLASH) += bcm47xxnflash/ diff --git a/drivers/mtd/nand/raw/ingenic/Kconfig b/drivers/mtd/nand/raw/ingenic/Kconfig new file mode 100644 index 000000000000..67806c87b2c4 --- /dev/null +++ b/drivers/mtd/nand/raw/ingenic/Kconfig @@ -0,0 +1,13 @@ +config MTD_NAND_JZ4740 + tristate "Support for JZ4740 SoC NAND controller" + depends on MACH_JZ4740 || COMPILE_TEST + depends on HAS_IOMEM + help + Enables support for NAND Flash on JZ4740 SoC based boards. + +config MTD_NAND_JZ4780 + tristate "Support for NAND on JZ4780 SoC" + depends on 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. diff --git a/drivers/mtd/nand/raw/ingenic/Makefile b/drivers/mtd/nand/raw/ingenic/Makefile new file mode 100644 index 000000000000..44c2ca053d24 --- /dev/null +++ b/drivers/mtd/nand/raw/ingenic/Makefile @@ -0,0 +1,2 @@ +obj-$(CONFIG_MTD_NAND_JZ4740) += jz4740_nand.o +obj-$(CONFIG_MTD_NAND_JZ4780) += jz4780_nand.o jz4780_bch.o diff --git a/drivers/mtd/nand/raw/ingenic/jz4740_nand.c b/drivers/mtd/nand/raw/ingenic/jz4740_nand.c new file mode 100644 index 000000000000..9526d5b23c80 --- /dev/null +++ b/drivers/mtd/nand/raw/ingenic/jz4740_nand.c @@ -0,0 +1,542 @@ +/* + * Copyright (C) 2009-2010, Lars-Peter Clausen + * JZ4740 SoC NAND controller driver + * + * 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. + * + * 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., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include + +#define JZ_REG_NAND_CTRL 0x50 +#define JZ_REG_NAND_ECC_CTRL 0x100 +#define JZ_REG_NAND_DATA 0x104 +#define JZ_REG_NAND_PAR0 0x108 +#define JZ_REG_NAND_PAR1 0x10C +#define JZ_REG_NAND_PAR2 0x110 +#define JZ_REG_NAND_IRQ_STAT 0x114 +#define JZ_REG_NAND_IRQ_CTRL 0x118 +#define JZ_REG_NAND_ERR(x) (0x11C + ((x) << 2)) + +#define JZ_NAND_ECC_CTRL_PAR_READY BIT(4) +#define JZ_NAND_ECC_CTRL_ENCODING BIT(3) +#define JZ_NAND_ECC_CTRL_RS BIT(2) +#define JZ_NAND_ECC_CTRL_RESET BIT(1) +#define JZ_NAND_ECC_CTRL_ENABLE BIT(0) + +#define JZ_NAND_STATUS_ERR_COUNT (BIT(31) | BIT(30) | BIT(29)) +#define JZ_NAND_STATUS_PAD_FINISH BIT(4) +#define JZ_NAND_STATUS_DEC_FINISH BIT(3) +#define JZ_NAND_STATUS_ENC_FINISH BIT(2) +#define JZ_NAND_STATUS_UNCOR_ERROR BIT(1) +#define JZ_NAND_STATUS_ERROR BIT(0) + +#define JZ_NAND_CTRL_ENABLE_CHIP(x) BIT((x) << 1) +#define JZ_NAND_CTRL_ASSERT_CHIP(x) BIT(((x) << 1) + 1) +#define JZ_NAND_CTRL_ASSERT_CHIP_MASK 0xaa + +#define JZ_NAND_MEM_CMD_OFFSET 0x08000 +#define JZ_NAND_MEM_ADDR_OFFSET 0x10000 + +struct jz_nand { + struct nand_chip chip; + void __iomem *base; + struct resource *mem; + + unsigned char banks[JZ_NAND_NUM_BANKS]; + void __iomem *bank_base[JZ_NAND_NUM_BANKS]; + struct resource *bank_mem[JZ_NAND_NUM_BANKS]; + + int selected_bank; + + struct gpio_desc *busy_gpio; + bool is_reading; +}; + +static inline struct jz_nand *mtd_to_jz_nand(struct mtd_info *mtd) +{ + return container_of(mtd_to_nand(mtd), struct jz_nand, chip); +} + +static void jz_nand_select_chip(struct nand_chip *chip, int chipnr) +{ + struct jz_nand *nand = mtd_to_jz_nand(nand_to_mtd(chip)); + uint32_t ctrl; + int banknr; + + ctrl = readl(nand->base + JZ_REG_NAND_CTRL); + ctrl &= ~JZ_NAND_CTRL_ASSERT_CHIP_MASK; + + if (chipnr == -1) { + banknr = -1; + } else { + banknr = nand->banks[chipnr] - 1; + chip->legacy.IO_ADDR_R = nand->bank_base[banknr]; + chip->legacy.IO_ADDR_W = nand->bank_base[banknr]; + } + writel(ctrl, nand->base + JZ_REG_NAND_CTRL); + + nand->selected_bank = banknr; +} + +static void jz_nand_cmd_ctrl(struct nand_chip *chip, int dat, + unsigned int ctrl) +{ + struct jz_nand *nand = mtd_to_jz_nand(nand_to_mtd(chip)); + uint32_t reg; + void __iomem *bank_base = nand->bank_base[nand->selected_bank]; + + BUG_ON(nand->selected_bank < 0); + + if (ctrl & NAND_CTRL_CHANGE) { + BUG_ON((ctrl & NAND_ALE) && (ctrl & NAND_CLE)); + if (ctrl & NAND_ALE) + bank_base += JZ_NAND_MEM_ADDR_OFFSET; + else if (ctrl & NAND_CLE) + bank_base += JZ_NAND_MEM_CMD_OFFSET; + chip->legacy.IO_ADDR_W = bank_base; + + reg = readl(nand->base + JZ_REG_NAND_CTRL); + if (ctrl & NAND_NCE) + reg |= JZ_NAND_CTRL_ASSERT_CHIP(nand->selected_bank); + else + reg &= ~JZ_NAND_CTRL_ASSERT_CHIP(nand->selected_bank); + writel(reg, nand->base + JZ_REG_NAND_CTRL); + } + if (dat != NAND_CMD_NONE) + writeb(dat, chip->legacy.IO_ADDR_W); +} + +static int jz_nand_dev_ready(struct nand_chip *chip) +{ + struct jz_nand *nand = mtd_to_jz_nand(nand_to_mtd(chip)); + return gpiod_get_value_cansleep(nand->busy_gpio); +} + +static void jz_nand_hwctl(struct nand_chip *chip, int mode) +{ + struct jz_nand *nand = mtd_to_jz_nand(nand_to_mtd(chip)); + uint32_t reg; + + writel(0, nand->base + JZ_REG_NAND_IRQ_STAT); + reg = readl(nand->base + JZ_REG_NAND_ECC_CTRL); + + reg |= JZ_NAND_ECC_CTRL_RESET; + reg |= JZ_NAND_ECC_CTRL_ENABLE; + reg |= JZ_NAND_ECC_CTRL_RS; + + switch (mode) { + case NAND_ECC_READ: + reg &= ~JZ_NAND_ECC_CTRL_ENCODING; + nand->is_reading = true; + break; + case NAND_ECC_WRITE: + reg |= JZ_NAND_ECC_CTRL_ENCODING; + nand->is_reading = false; + break; + default: + break; + } + + writel(reg, nand->base + JZ_REG_NAND_ECC_CTRL); +} + +static int jz_nand_calculate_ecc_rs(struct nand_chip *chip, const uint8_t *dat, + uint8_t *ecc_code) +{ + struct jz_nand *nand = mtd_to_jz_nand(nand_to_mtd(chip)); + uint32_t reg, status; + int i; + unsigned int timeout = 1000; + static uint8_t empty_block_ecc[] = {0xcd, 0x9d, 0x90, 0x58, 0xf4, + 0x8b, 0xff, 0xb7, 0x6f}; + + if (nand->is_reading) + return 0; + + do { + status = readl(nand->base + JZ_REG_NAND_IRQ_STAT); + } while (!(status & JZ_NAND_STATUS_ENC_FINISH) && --timeout); + + if (timeout == 0) + return -1; + + reg = readl(nand->base + JZ_REG_NAND_ECC_CTRL); + reg &= ~JZ_NAND_ECC_CTRL_ENABLE; + writel(reg, nand->base + JZ_REG_NAND_ECC_CTRL); + + for (i = 0; i < 9; ++i) + ecc_code[i] = readb(nand->base + JZ_REG_NAND_PAR0 + i); + + /* If the written data is completly 0xff, we also want to write 0xff as + * ecc, otherwise we will get in trouble when doing subpage writes. */ + if (memcmp(ecc_code, empty_block_ecc, 9) == 0) + memset(ecc_code, 0xff, 9); + + return 0; +} + +static void jz_nand_correct_data(uint8_t *dat, int index, int mask) +{ + int offset = index & 0x7; + uint16_t data; + + index += (index >> 3); + + data = dat[index]; + data |= dat[index+1] << 8; + + mask ^= (data >> offset) & 0x1ff; + data &= ~(0x1ff << offset); + data |= (mask << offset); + + dat[index] = data & 0xff; + dat[index+1] = (data >> 8) & 0xff; +} + +static int jz_nand_correct_ecc_rs(struct nand_chip *chip, uint8_t *dat, + uint8_t *read_ecc, uint8_t *calc_ecc) +{ + struct jz_nand *nand = mtd_to_jz_nand(nand_to_mtd(chip)); + int i, error_count, index; + uint32_t reg, status, error; + unsigned int timeout = 1000; + + for (i = 0; i < 9; ++i) + writeb(read_ecc[i], nand->base + JZ_REG_NAND_PAR0 + i); + + reg = readl(nand->base + JZ_REG_NAND_ECC_CTRL); + reg |= JZ_NAND_ECC_CTRL_PAR_READY; + writel(reg, nand->base + JZ_REG_NAND_ECC_CTRL); + + do { + status = readl(nand->base + JZ_REG_NAND_IRQ_STAT); + } while (!(status & JZ_NAND_STATUS_DEC_FINISH) && --timeout); + + if (timeout == 0) + return -ETIMEDOUT; + + reg = readl(nand->base + JZ_REG_NAND_ECC_CTRL); + reg &= ~JZ_NAND_ECC_CTRL_ENABLE; + writel(reg, nand->base + JZ_REG_NAND_ECC_CTRL); + + if (status & JZ_NAND_STATUS_ERROR) { + if (status & JZ_NAND_STATUS_UNCOR_ERROR) + return -EBADMSG; + + error_count = (status & JZ_NAND_STATUS_ERR_COUNT) >> 29; + + for (i = 0; i < error_count; ++i) { + error = readl(nand->base + JZ_REG_NAND_ERR(i)); + index = ((error >> 16) & 0x1ff) - 1; + if (index >= 0 && index < 512) + jz_nand_correct_data(dat, index, error & 0x1ff); + } + + return error_count; + } + + return 0; +} + +static int jz_nand_ioremap_resource(struct platform_device *pdev, + const char *name, struct resource **res, void __iomem **base) +{ + int ret; + + *res = platform_get_resource_byname(pdev, IORESOURCE_MEM, name); + if (!*res) { + dev_err(&pdev->dev, "Failed to get platform %s memory\n", name); + ret = -ENXIO; + goto err; + } + + *res = request_mem_region((*res)->start, resource_size(*res), + pdev->name); + if (!*res) { + dev_err(&pdev->dev, "Failed to request %s memory region\n", name); + ret = -EBUSY; + goto err; + } + + *base = ioremap((*res)->start, resource_size(*res)); + if (!*base) { + dev_err(&pdev->dev, "Failed to ioremap %s memory region\n", name); + ret = -EBUSY; + goto err_release_mem; + } + + return 0; + +err_release_mem: + release_mem_region((*res)->start, resource_size(*res)); +err: + *res = NULL; + *base = NULL; + return ret; +} + +static inline void jz_nand_iounmap_resource(struct resource *res, + void __iomem *base) +{ + iounmap(base); + release_mem_region(res->start, resource_size(res)); +} + +static int jz_nand_detect_bank(struct platform_device *pdev, + struct jz_nand *nand, unsigned char bank, + size_t chipnr, uint8_t *nand_maf_id, + uint8_t *nand_dev_id) +{ + int ret; + char res_name[6]; + uint32_t ctrl; + struct nand_chip *chip = &nand->chip; + struct mtd_info *mtd = nand_to_mtd(chip); + u8 id[2]; + + /* Request I/O resource. */ + sprintf(res_name, "bank%d", bank); + ret = jz_nand_ioremap_resource(pdev, res_name, + &nand->bank_mem[bank - 1], + &nand->bank_base[bank - 1]); + if (ret) + return ret; + + /* Enable chip in bank. */ + ctrl = readl(nand->base + JZ_REG_NAND_CTRL); + ctrl |= JZ_NAND_CTRL_ENABLE_CHIP(bank - 1); + writel(ctrl, nand->base + JZ_REG_NAND_CTRL); + + if (chipnr == 0) { + /* Detect first chip. */ + ret = nand_scan(chip, 1); + if (ret) + goto notfound_id; + + /* Retrieve the IDs from the first chip. */ + nand_select_target(chip, 0); + nand_reset_op(chip); + nand_readid_op(chip, 0, id, sizeof(id)); + *nand_maf_id = id[0]; + *nand_dev_id = id[1]; + } else { + /* Detect additional chip. */ + nand_select_target(chip, chipnr); + nand_reset_op(chip); + nand_readid_op(chip, 0, id, sizeof(id)); + if (*nand_maf_id != id[0] || *nand_dev_id != id[1]) { + ret = -ENODEV; + goto notfound_id; + } + + /* Update size of the MTD. */ + chip->numchips++; + mtd->size += chip->chipsize; + } + + dev_info(&pdev->dev, "Found chip %zu on bank %i\n", chipnr, bank); + return 0; + +notfound_id: + dev_info(&pdev->dev, "No chip found on bank %i\n", bank); + ctrl &= ~(JZ_NAND_CTRL_ENABLE_CHIP(bank - 1)); + writel(ctrl, nand->base + JZ_REG_NAND_CTRL); + jz_nand_iounmap_resource(nand->bank_mem[bank - 1], + nand->bank_base[bank - 1]); + return ret; +} + +static int jz_nand_attach_chip(struct nand_chip *chip) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + struct device *dev = mtd->dev.parent; + struct jz_nand_platform_data *pdata = dev_get_platdata(dev); + struct platform_device *pdev = to_platform_device(dev); + + if (pdata && pdata->ident_callback) + pdata->ident_callback(pdev, mtd, &pdata->partitions, + &pdata->num_partitions); + + return 0; +} + +static const struct nand_controller_ops jz_nand_controller_ops = { + .attach_chip = jz_nand_attach_chip, +}; + +static int jz_nand_probe(struct platform_device *pdev) +{ + int ret; + struct jz_nand *nand; + struct nand_chip *chip; + struct mtd_info *mtd; + struct jz_nand_platform_data *pdata = dev_get_platdata(&pdev->dev); + size_t chipnr, bank_idx; + uint8_t nand_maf_id = 0, nand_dev_id = 0; + + nand = kzalloc(sizeof(*nand), GFP_KERNEL); + if (!nand) + return -ENOMEM; + + ret = jz_nand_ioremap_resource(pdev, "mmio", &nand->mem, &nand->base); + if (ret) + goto err_free; + + nand->busy_gpio = devm_gpiod_get_optional(&pdev->dev, "busy", GPIOD_IN); + if (IS_ERR(nand->busy_gpio)) { + ret = PTR_ERR(nand->busy_gpio); + dev_err(&pdev->dev, "Failed to request busy gpio %d\n", + ret); + goto err_iounmap_mmio; + } + + chip = &nand->chip; + mtd = nand_to_mtd(chip); + mtd->dev.parent = &pdev->dev; + mtd->name = "jz4740-nand"; + + chip->ecc.hwctl = jz_nand_hwctl; + chip->ecc.calculate = jz_nand_calculate_ecc_rs; + chip->ecc.correct = jz_nand_correct_ecc_rs; + chip->ecc.mode = NAND_ECC_HW_OOB_FIRST; + chip->ecc.size = 512; + chip->ecc.bytes = 9; + chip->ecc.strength = 4; + chip->ecc.options = NAND_ECC_GENERIC_ERASED_CHECK; + + chip->legacy.chip_delay = 50; + chip->legacy.cmd_ctrl = jz_nand_cmd_ctrl; + chip->legacy.select_chip = jz_nand_select_chip; + chip->legacy.dummy_controller.ops = &jz_nand_controller_ops; + + if (nand->busy_gpio) + chip->legacy.dev_ready = jz_nand_dev_ready; + + platform_set_drvdata(pdev, nand); + + /* We are going to autodetect NAND chips in the banks specified in the + * platform data. Although nand_scan_ident() can detect multiple chips, + * it requires those chips to be numbered consecuitively, which is not + * always the case for external memory banks. And a fixed chip-to-bank + * mapping is not practical either, since for example Dingoo units + * produced at different times have NAND chips in different banks. + */ + chipnr = 0; + for (bank_idx = 0; bank_idx < JZ_NAND_NUM_BANKS; bank_idx++) { + unsigned char bank; + + /* If there is no platform data, look for NAND in bank 1, + * which is the most likely bank since it is the only one + * that can be booted from. + */ + bank = pdata ? pdata->banks[bank_idx] : bank_idx ^ 1; + if (bank == 0) + break; + if (bank > JZ_NAND_NUM_BANKS) { + dev_warn(&pdev->dev, + "Skipping non-existing bank: %d\n", bank); + continue; + } + /* The detection routine will directly or indirectly call + * jz_nand_select_chip(), so nand->banks has to contain the + * bank we're checking. + */ + nand->banks[chipnr] = bank; + if (jz_nand_detect_bank(pdev, nand, bank, chipnr, + &nand_maf_id, &nand_dev_id) == 0) + chipnr++; + else + nand->banks[chipnr] = 0; + } + if (chipnr == 0) { + dev_err(&pdev->dev, "No NAND chips found\n"); + goto err_iounmap_mmio; + } + + ret = mtd_device_register(mtd, pdata ? pdata->partitions : NULL, + pdata ? pdata->num_partitions : 0); + + if (ret) { + dev_err(&pdev->dev, "Failed to add mtd device\n"); + goto err_cleanup_nand; + } + + dev_info(&pdev->dev, "Successfully registered JZ4740 NAND driver\n"); + + return 0; + +err_cleanup_nand: + nand_cleanup(chip); + while (chipnr--) { + unsigned char bank = nand->banks[chipnr]; + jz_nand_iounmap_resource(nand->bank_mem[bank - 1], + nand->bank_base[bank - 1]); + } + writel(0, nand->base + JZ_REG_NAND_CTRL); +err_iounmap_mmio: + jz_nand_iounmap_resource(nand->mem, nand->base); +err_free: + kfree(nand); + return ret; +} + +static int jz_nand_remove(struct platform_device *pdev) +{ + struct jz_nand *nand = platform_get_drvdata(pdev); + size_t i; + + nand_release(&nand->chip); + + /* Deassert and disable all chips */ + writel(0, nand->base + JZ_REG_NAND_CTRL); + + for (i = 0; i < JZ_NAND_NUM_BANKS; ++i) { + unsigned char bank = nand->banks[i]; + if (bank != 0) { + jz_nand_iounmap_resource(nand->bank_mem[bank - 1], + nand->bank_base[bank - 1]); + } + } + + jz_nand_iounmap_resource(nand->mem, nand->base); + + kfree(nand); + + return 0; +} + +static struct platform_driver jz_nand_driver = { + .probe = jz_nand_probe, + .remove = jz_nand_remove, + .driver = { + .name = "jz4740-nand", + }, +}; + +module_platform_driver(jz_nand_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Lars-Peter Clausen "); +MODULE_DESCRIPTION("NAND controller driver for JZ4740 SoC"); +MODULE_ALIAS("platform:jz4740-nand"); diff --git a/drivers/mtd/nand/raw/ingenic/jz4780_bch.c b/drivers/mtd/nand/raw/ingenic/jz4780_bch.c new file mode 100644 index 000000000000..c5f74ed85862 --- /dev/null +++ b/drivers/mtd/nand/raw/ingenic/jz4780_bch.c @@ -0,0 +1,385 @@ +/* + * JZ4780 BCH controller + * + * Copyright (c) 2015 Imagination Technologies + * Author: Alex Smith + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "jz4780_bch.h" + +#define BCH_BHCR 0x0 +#define BCH_BHCCR 0x8 +#define BCH_BHCNT 0xc +#define BCH_BHDR 0x10 +#define BCH_BHPAR0 0x14 +#define BCH_BHERR0 0x84 +#define BCH_BHINT 0x184 +#define BCH_BHINTES 0x188 +#define BCH_BHINTEC 0x18c +#define BCH_BHINTE 0x190 + +#define BCH_BHCR_BSEL_SHIFT 4 +#define BCH_BHCR_BSEL_MASK (0x7f << BCH_BHCR_BSEL_SHIFT) +#define BCH_BHCR_ENCE BIT(2) +#define BCH_BHCR_INIT BIT(1) +#define BCH_BHCR_BCHE BIT(0) + +#define BCH_BHCNT_PARITYSIZE_SHIFT 16 +#define BCH_BHCNT_PARITYSIZE_MASK (0x7f << BCH_BHCNT_PARITYSIZE_SHIFT) +#define BCH_BHCNT_BLOCKSIZE_SHIFT 0 +#define BCH_BHCNT_BLOCKSIZE_MASK (0x7ff << BCH_BHCNT_BLOCKSIZE_SHIFT) + +#define BCH_BHERR_MASK_SHIFT 16 +#define BCH_BHERR_MASK_MASK (0xffff << BCH_BHERR_MASK_SHIFT) +#define BCH_BHERR_INDEX_SHIFT 0 +#define BCH_BHERR_INDEX_MASK (0x7ff << BCH_BHERR_INDEX_SHIFT) + +#define BCH_BHINT_ERRC_SHIFT 24 +#define BCH_BHINT_ERRC_MASK (0x7f << BCH_BHINT_ERRC_SHIFT) +#define BCH_BHINT_TERRC_SHIFT 16 +#define BCH_BHINT_TERRC_MASK (0x7f << BCH_BHINT_TERRC_SHIFT) +#define BCH_BHINT_DECF BIT(3) +#define BCH_BHINT_ENCF BIT(2) +#define BCH_BHINT_UNCOR BIT(1) +#define BCH_BHINT_ERR BIT(0) + +#define BCH_CLK_RATE (200 * 1000 * 1000) + +/* Timeout for BCH calculation/correction. */ +#define BCH_TIMEOUT_US 100000 + +struct jz4780_bch { + struct device *dev; + void __iomem *base; + struct clk *clk; + struct mutex lock; +}; + +static void jz4780_bch_init(struct jz4780_bch *bch, + struct jz4780_bch_params *params, bool encode) +{ + u32 reg; + + /* Clear interrupt status. */ + writel(readl(bch->base + BCH_BHINT), bch->base + BCH_BHINT); + + /* Set up BCH count register. */ + reg = params->size << BCH_BHCNT_BLOCKSIZE_SHIFT; + reg |= params->bytes << BCH_BHCNT_PARITYSIZE_SHIFT; + writel(reg, bch->base + BCH_BHCNT); + + /* Initialise and enable BCH. */ + reg = BCH_BHCR_BCHE | BCH_BHCR_INIT; + reg |= params->strength << BCH_BHCR_BSEL_SHIFT; + if (encode) + reg |= BCH_BHCR_ENCE; + writel(reg, bch->base + BCH_BHCR); +} + +static void jz4780_bch_disable(struct jz4780_bch *bch) +{ + writel(readl(bch->base + BCH_BHINT), bch->base + BCH_BHINT); + writel(BCH_BHCR_BCHE, bch->base + BCH_BHCCR); +} + +static void jz4780_bch_write_data(struct jz4780_bch *bch, const void *buf, + size_t size) +{ + size_t size32 = size / sizeof(u32); + size_t size8 = size % sizeof(u32); + const u32 *src32; + const u8 *src8; + + src32 = (const u32 *)buf; + while (size32--) + writel(*src32++, bch->base + BCH_BHDR); + + src8 = (const u8 *)src32; + while (size8--) + writeb(*src8++, bch->base + BCH_BHDR); +} + +static void jz4780_bch_read_parity(struct jz4780_bch *bch, void *buf, + size_t size) +{ + size_t size32 = size / sizeof(u32); + size_t size8 = size % sizeof(u32); + u32 *dest32; + u8 *dest8; + u32 val, offset = 0; + + dest32 = (u32 *)buf; + while (size32--) { + *dest32++ = readl(bch->base + BCH_BHPAR0 + offset); + offset += sizeof(u32); + } + + dest8 = (u8 *)dest32; + val = readl(bch->base + BCH_BHPAR0 + offset); + switch (size8) { + case 3: + dest8[2] = (val >> 16) & 0xff; + /* fall through */ + case 2: + dest8[1] = (val >> 8) & 0xff; + /* fall through */ + case 1: + dest8[0] = val & 0xff; + break; + } +} + +static bool jz4780_bch_wait_complete(struct jz4780_bch *bch, unsigned int irq, + u32 *status) +{ + u32 reg; + int ret; + + /* + * While we could use interrupts here and sleep until the operation + * completes, the controller works fairly quickly (usually a few + * microseconds) and so the overhead of sleeping until we get an + * interrupt quite noticeably decreases performance. + */ + ret = readl_poll_timeout(bch->base + BCH_BHINT, reg, + (reg & irq) == irq, 0, BCH_TIMEOUT_US); + if (ret) + return false; + + if (status) + *status = reg; + + writel(reg, bch->base + BCH_BHINT); + return true; +} + +/** + * jz4780_bch_calculate() - calculate ECC for a data buffer + * @bch: BCH device. + * @params: BCH parameters. + * @buf: input buffer with raw data. + * @ecc_code: output buffer with ECC. + * + * Return: 0 on success, -ETIMEDOUT if timed out while waiting for BCH + * controller. + */ +int jz4780_bch_calculate(struct jz4780_bch *bch, struct jz4780_bch_params *params, + const u8 *buf, u8 *ecc_code) +{ + int ret = 0; + + mutex_lock(&bch->lock); + jz4780_bch_init(bch, params, true); + jz4780_bch_write_data(bch, buf, params->size); + + if (jz4780_bch_wait_complete(bch, BCH_BHINT_ENCF, NULL)) { + jz4780_bch_read_parity(bch, ecc_code, params->bytes); + } else { + dev_err(bch->dev, "timed out while calculating ECC\n"); + ret = -ETIMEDOUT; + } + + jz4780_bch_disable(bch); + mutex_unlock(&bch->lock); + return ret; +} +EXPORT_SYMBOL(jz4780_bch_calculate); + +/** + * jz4780_bch_correct() - detect and correct bit errors + * @bch: BCH device. + * @params: BCH parameters. + * @buf: raw data read from the chip. + * @ecc_code: ECC read from the chip. + * + * Given the raw data and the ECC read from the NAND device, detects and + * corrects errors in the data. + * + * Return: the number of bit errors corrected, -EBADMSG if there are too many + * errors to correct or -ETIMEDOUT if we timed out waiting for the controller. + */ +int jz4780_bch_correct(struct jz4780_bch *bch, struct jz4780_bch_params *params, + u8 *buf, u8 *ecc_code) +{ + u32 reg, mask, index; + int i, ret, count; + + mutex_lock(&bch->lock); + + jz4780_bch_init(bch, params, false); + jz4780_bch_write_data(bch, buf, params->size); + jz4780_bch_write_data(bch, ecc_code, params->bytes); + + if (!jz4780_bch_wait_complete(bch, BCH_BHINT_DECF, ®)) { + dev_err(bch->dev, "timed out while correcting data\n"); + ret = -ETIMEDOUT; + goto out; + } + + if (reg & BCH_BHINT_UNCOR) { + dev_warn(bch->dev, "uncorrectable ECC error\n"); + ret = -EBADMSG; + goto out; + } + + /* Correct any detected errors. */ + if (reg & BCH_BHINT_ERR) { + count = (reg & BCH_BHINT_ERRC_MASK) >> BCH_BHINT_ERRC_SHIFT; + ret = (reg & BCH_BHINT_TERRC_MASK) >> BCH_BHINT_TERRC_SHIFT; + + for (i = 0; i < count; i++) { + reg = readl(bch->base + BCH_BHERR0 + (i * 4)); + mask = (reg & BCH_BHERR_MASK_MASK) >> + BCH_BHERR_MASK_SHIFT; + index = (reg & BCH_BHERR_INDEX_MASK) >> + BCH_BHERR_INDEX_SHIFT; + buf[(index * 2) + 0] ^= mask; + buf[(index * 2) + 1] ^= mask >> 8; + } + } else { + ret = 0; + } + +out: + jz4780_bch_disable(bch); + mutex_unlock(&bch->lock); + return ret; +} +EXPORT_SYMBOL(jz4780_bch_correct); + +/** + * jz4780_bch_get() - get the BCH controller device + * @np: BCH device tree node. + * + * Gets the BCH controller device from the specified device tree node. The + * device must be released with jz4780_bch_release() when it is no longer being + * used. + * + * Return: a pointer to jz4780_bch, errors are encoded into the pointer. + * PTR_ERR(-EPROBE_DEFER) if the device hasn't been initialised yet. + */ +static struct jz4780_bch *jz4780_bch_get(struct device_node *np) +{ + struct platform_device *pdev; + struct jz4780_bch *bch; + + pdev = of_find_device_by_node(np); + if (!pdev) + return ERR_PTR(-EPROBE_DEFER); + + bch = platform_get_drvdata(pdev); + if (!bch) { + put_device(&pdev->dev); + return ERR_PTR(-EPROBE_DEFER); + } + + clk_prepare_enable(bch->clk); + + return bch; +} + +/** + * of_jz4780_bch_get() - get the BCH controller from a DT node + * @of_node: the node that contains a bch-controller property. + * + * Get the bch-controller property from the given device tree + * node and pass it to jz4780_bch_get to do the work. + * + * Return: a pointer to jz4780_bch, errors are encoded into the pointer. + * PTR_ERR(-EPROBE_DEFER) if the device hasn't been initialised yet. + */ +struct jz4780_bch *of_jz4780_bch_get(struct device_node *of_node) +{ + struct jz4780_bch *bch = NULL; + struct device_node *np; + + np = of_parse_phandle(of_node, "ingenic,bch-controller", 0); + + if (np) { + bch = jz4780_bch_get(np); + of_node_put(np); + } + return bch; +} +EXPORT_SYMBOL(of_jz4780_bch_get); + +/** + * jz4780_bch_release() - release the BCH controller device + * @bch: BCH device. + */ +void jz4780_bch_release(struct jz4780_bch *bch) +{ + clk_disable_unprepare(bch->clk); + put_device(bch->dev); +} +EXPORT_SYMBOL(jz4780_bch_release); + +static int jz4780_bch_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct jz4780_bch *bch; + struct resource *res; + + bch = devm_kzalloc(dev, sizeof(*bch), GFP_KERNEL); + if (!bch) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + bch->base = devm_ioremap_resource(dev, res); + if (IS_ERR(bch->base)) + return PTR_ERR(bch->base); + + jz4780_bch_disable(bch); + + bch->clk = devm_clk_get(dev, NULL); + if (IS_ERR(bch->clk)) { + dev_err(dev, "failed to get clock: %ld\n", PTR_ERR(bch->clk)); + return PTR_ERR(bch->clk); + } + + clk_set_rate(bch->clk, BCH_CLK_RATE); + + mutex_init(&bch->lock); + + bch->dev = dev; + platform_set_drvdata(pdev, bch); + + return 0; +} + +static const struct of_device_id jz4780_bch_dt_match[] = { + { .compatible = "ingenic,jz4780-bch" }, + {}, +}; +MODULE_DEVICE_TABLE(of, jz4780_bch_dt_match); + +static struct platform_driver jz4780_bch_driver = { + .probe = jz4780_bch_probe, + .driver = { + .name = "jz4780-bch", + .of_match_table = of_match_ptr(jz4780_bch_dt_match), + }, +}; +module_platform_driver(jz4780_bch_driver); + +MODULE_AUTHOR("Alex Smith "); +MODULE_AUTHOR("Harvey Hunt "); +MODULE_DESCRIPTION("Ingenic JZ4780 BCH error correction driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/mtd/nand/raw/ingenic/jz4780_bch.h b/drivers/mtd/nand/raw/ingenic/jz4780_bch.h new file mode 100644 index 000000000000..bf4718088a3a --- /dev/null +++ b/drivers/mtd/nand/raw/ingenic/jz4780_bch.h @@ -0,0 +1,43 @@ +/* + * JZ4780 BCH controller + * + * Copyright (c) 2015 Imagination Technologies + * Author: Alex Smith + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + */ + +#ifndef __DRIVERS_MTD_NAND_JZ4780_BCH_H__ +#define __DRIVERS_MTD_NAND_JZ4780_BCH_H__ + +#include + +struct device; +struct device_node; +struct jz4780_bch; + +/** + * struct jz4780_bch_params - BCH parameters + * @size: data bytes per ECC step. + * @bytes: ECC bytes per step. + * @strength: number of correctable bits per ECC step. + */ +struct jz4780_bch_params { + int size; + int bytes; + int strength; +}; + +int jz4780_bch_calculate(struct jz4780_bch *bch, + struct jz4780_bch_params *params, + const u8 *buf, u8 *ecc_code); +int jz4780_bch_correct(struct jz4780_bch *bch, + struct jz4780_bch_params *params, u8 *buf, + u8 *ecc_code); + +void jz4780_bch_release(struct jz4780_bch *bch); +struct jz4780_bch *of_jz4780_bch_get(struct device_node *np); + +#endif /* __DRIVERS_MTD_NAND_JZ4780_BCH_H__ */ diff --git a/drivers/mtd/nand/raw/ingenic/jz4780_nand.c b/drivers/mtd/nand/raw/ingenic/jz4780_nand.c new file mode 100644 index 000000000000..22e58975f0d5 --- /dev/null +++ b/drivers/mtd/nand/raw/ingenic/jz4780_nand.c @@ -0,0 +1,415 @@ +/* + * JZ4780 NAND driver + * + * Copyright (c) 2015 Imagination Technologies + * Author: Alex Smith + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "jz4780_bch.h" + +#define DRV_NAME "jz4780-nand" + +#define OFFSET_DATA 0x00000000 +#define OFFSET_CMD 0x00400000 +#define OFFSET_ADDR 0x00800000 + +/* Command delay when there is no R/B pin. */ +#define RB_DELAY_US 100 + +struct jz4780_nand_cs { + unsigned int bank; + void __iomem *base; +}; + +struct jz4780_nand_controller { + struct device *dev; + struct jz4780_bch *bch; + struct nand_controller controller; + unsigned int num_banks; + struct list_head chips; + int selected; + struct jz4780_nand_cs cs[]; +}; + +struct jz4780_nand_chip { + struct nand_chip chip; + struct list_head chip_list; + + struct gpio_desc *busy_gpio; + struct gpio_desc *wp_gpio; + unsigned int reading: 1; +}; + +static inline struct jz4780_nand_chip *to_jz4780_nand_chip(struct mtd_info *mtd) +{ + return container_of(mtd_to_nand(mtd), struct jz4780_nand_chip, chip); +} + +static inline struct jz4780_nand_controller +*to_jz4780_nand_controller(struct nand_controller *ctrl) +{ + return container_of(ctrl, struct jz4780_nand_controller, controller); +} + +static void jz4780_nand_select_chip(struct nand_chip *chip, int chipnr) +{ + struct jz4780_nand_chip *nand = to_jz4780_nand_chip(nand_to_mtd(chip)); + struct jz4780_nand_controller *nfc = to_jz4780_nand_controller(nand->chip.controller); + struct jz4780_nand_cs *cs; + + /* Ensure the currently selected chip is deasserted. */ + if (chipnr == -1 && nfc->selected >= 0) { + cs = &nfc->cs[nfc->selected]; + jz4780_nemc_assert(nfc->dev, cs->bank, false); + } + + nfc->selected = chipnr; +} + +static void jz4780_nand_cmd_ctrl(struct nand_chip *chip, int cmd, + unsigned int ctrl) +{ + struct jz4780_nand_chip *nand = to_jz4780_nand_chip(nand_to_mtd(chip)); + struct jz4780_nand_controller *nfc = to_jz4780_nand_controller(nand->chip.controller); + struct jz4780_nand_cs *cs; + + if (WARN_ON(nfc->selected < 0)) + return; + + cs = &nfc->cs[nfc->selected]; + + jz4780_nemc_assert(nfc->dev, cs->bank, ctrl & NAND_NCE); + + if (cmd == NAND_CMD_NONE) + return; + + if (ctrl & NAND_ALE) + writeb(cmd, cs->base + OFFSET_ADDR); + else if (ctrl & NAND_CLE) + writeb(cmd, cs->base + OFFSET_CMD); +} + +static int jz4780_nand_dev_ready(struct nand_chip *chip) +{ + struct jz4780_nand_chip *nand = to_jz4780_nand_chip(nand_to_mtd(chip)); + + return !gpiod_get_value_cansleep(nand->busy_gpio); +} + +static void jz4780_nand_ecc_hwctl(struct nand_chip *chip, int mode) +{ + struct jz4780_nand_chip *nand = to_jz4780_nand_chip(nand_to_mtd(chip)); + + nand->reading = (mode == NAND_ECC_READ); +} + +static int jz4780_nand_ecc_calculate(struct nand_chip *chip, const u8 *dat, + u8 *ecc_code) +{ + struct jz4780_nand_chip *nand = to_jz4780_nand_chip(nand_to_mtd(chip)); + struct jz4780_nand_controller *nfc = to_jz4780_nand_controller(nand->chip.controller); + struct jz4780_bch_params params; + + /* + * Don't need to generate the ECC when reading, BCH does it for us as + * part of decoding/correction. + */ + if (nand->reading) + return 0; + + params.size = nand->chip.ecc.size; + params.bytes = nand->chip.ecc.bytes; + params.strength = nand->chip.ecc.strength; + + return jz4780_bch_calculate(nfc->bch, ¶ms, dat, ecc_code); +} + +static int jz4780_nand_ecc_correct(struct nand_chip *chip, u8 *dat, + u8 *read_ecc, u8 *calc_ecc) +{ + struct jz4780_nand_chip *nand = to_jz4780_nand_chip(nand_to_mtd(chip)); + struct jz4780_nand_controller *nfc = to_jz4780_nand_controller(nand->chip.controller); + struct jz4780_bch_params params; + + params.size = nand->chip.ecc.size; + params.bytes = nand->chip.ecc.bytes; + params.strength = nand->chip.ecc.strength; + + return jz4780_bch_correct(nfc->bch, ¶ms, dat, read_ecc); +} + +static int jz4780_nand_attach_chip(struct nand_chip *chip) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + struct jz4780_nand_controller *nfc = to_jz4780_nand_controller(chip->controller); + int eccbytes; + + chip->ecc.bytes = fls((1 + 8) * chip->ecc.size) * + (chip->ecc.strength / 8); + + switch (chip->ecc.mode) { + case NAND_ECC_HW: + if (!nfc->bch) { + dev_err(nfc->dev, + "HW BCH selected, but BCH controller not found\n"); + return -ENODEV; + } + + chip->ecc.hwctl = jz4780_nand_ecc_hwctl; + chip->ecc.calculate = jz4780_nand_ecc_calculate; + chip->ecc.correct = jz4780_nand_ecc_correct; + /* fall through */ + case NAND_ECC_SOFT: + dev_info(nfc->dev, "using %s (strength %d, size %d, bytes %d)\n", + (nfc->bch) ? "hardware BCH" : "software ECC", + chip->ecc.strength, chip->ecc.size, chip->ecc.bytes); + break; + case NAND_ECC_NONE: + dev_info(nfc->dev, "not using ECC\n"); + break; + default: + dev_err(nfc->dev, "ECC mode %d not supported\n", + chip->ecc.mode); + return -EINVAL; + } + + /* The NAND core will generate the ECC layout for SW ECC */ + if (chip->ecc.mode != NAND_ECC_HW) + return 0; + + /* Generate ECC layout. ECC codes are right aligned in the OOB area. */ + eccbytes = mtd->writesize / chip->ecc.size * chip->ecc.bytes; + + if (eccbytes > mtd->oobsize - 2) { + dev_err(nfc->dev, + "invalid ECC config: required %d ECC bytes, but only %d are available", + eccbytes, mtd->oobsize - 2); + return -EINVAL; + } + + mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops); + + return 0; +} + +static const struct nand_controller_ops jz4780_nand_controller_ops = { + .attach_chip = jz4780_nand_attach_chip, +}; + +static int jz4780_nand_init_chip(struct platform_device *pdev, + struct jz4780_nand_controller *nfc, + struct device_node *np, + unsigned int chipnr) +{ + struct device *dev = &pdev->dev; + struct jz4780_nand_chip *nand; + struct jz4780_nand_cs *cs; + struct resource *res; + struct nand_chip *chip; + struct mtd_info *mtd; + const __be32 *reg; + int ret = 0; + + cs = &nfc->cs[chipnr]; + + reg = of_get_property(np, "reg", NULL); + if (!reg) + return -EINVAL; + + cs->bank = be32_to_cpu(*reg); + + jz4780_nemc_set_type(nfc->dev, cs->bank, JZ4780_NEMC_BANK_NAND); + + res = platform_get_resource(pdev, IORESOURCE_MEM, chipnr); + cs->base = devm_ioremap_resource(dev, res); + if (IS_ERR(cs->base)) + return PTR_ERR(cs->base); + + nand = devm_kzalloc(dev, sizeof(*nand), GFP_KERNEL); + if (!nand) + return -ENOMEM; + + nand->busy_gpio = devm_gpiod_get_optional(dev, "rb", GPIOD_IN); + + if (IS_ERR(nand->busy_gpio)) { + ret = PTR_ERR(nand->busy_gpio); + dev_err(dev, "failed to request busy GPIO: %d\n", ret); + return ret; + } else if (nand->busy_gpio) { + nand->chip.legacy.dev_ready = jz4780_nand_dev_ready; + } + + nand->wp_gpio = devm_gpiod_get_optional(dev, "wp", GPIOD_OUT_LOW); + + if (IS_ERR(nand->wp_gpio)) { + ret = PTR_ERR(nand->wp_gpio); + dev_err(dev, "failed to request WP GPIO: %d\n", ret); + return ret; + } + + chip = &nand->chip; + mtd = nand_to_mtd(chip); + mtd->name = devm_kasprintf(dev, GFP_KERNEL, "%s.%d", dev_name(dev), + cs->bank); + if (!mtd->name) + return -ENOMEM; + mtd->dev.parent = dev; + + chip->legacy.IO_ADDR_R = cs->base + OFFSET_DATA; + chip->legacy.IO_ADDR_W = cs->base + OFFSET_DATA; + chip->legacy.chip_delay = RB_DELAY_US; + chip->options = NAND_NO_SUBPAGE_WRITE; + chip->legacy.select_chip = jz4780_nand_select_chip; + chip->legacy.cmd_ctrl = jz4780_nand_cmd_ctrl; + chip->ecc.mode = NAND_ECC_HW; + chip->controller = &nfc->controller; + nand_set_flash_node(chip, np); + + chip->controller->ops = &jz4780_nand_controller_ops; + ret = nand_scan(chip, 1); + if (ret) + return ret; + + ret = mtd_device_register(mtd, NULL, 0); + if (ret) { + nand_release(chip); + return ret; + } + + list_add_tail(&nand->chip_list, &nfc->chips); + + return 0; +} + +static void jz4780_nand_cleanup_chips(struct jz4780_nand_controller *nfc) +{ + struct jz4780_nand_chip *chip; + + while (!list_empty(&nfc->chips)) { + chip = list_first_entry(&nfc->chips, struct jz4780_nand_chip, chip_list); + nand_release(&chip->chip); + list_del(&chip->chip_list); + } +} + +static int jz4780_nand_init_chips(struct jz4780_nand_controller *nfc, + struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np; + int i = 0; + int ret; + int num_chips = of_get_child_count(dev->of_node); + + if (num_chips > nfc->num_banks) { + dev_err(dev, "found %d chips but only %d banks\n", num_chips, nfc->num_banks); + return -EINVAL; + } + + for_each_child_of_node(dev->of_node, np) { + ret = jz4780_nand_init_chip(pdev, nfc, np, i); + if (ret) { + jz4780_nand_cleanup_chips(nfc); + return ret; + } + + i++; + } + + return 0; +} + +static int jz4780_nand_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + unsigned int num_banks; + struct jz4780_nand_controller *nfc; + int ret; + + num_banks = jz4780_nemc_num_banks(dev); + if (num_banks == 0) { + dev_err(dev, "no banks found\n"); + return -ENODEV; + } + + nfc = devm_kzalloc(dev, struct_size(nfc, cs, num_banks), GFP_KERNEL); + if (!nfc) + return -ENOMEM; + + /* + * Check for BCH HW before we call nand_scan_ident, to prevent us from + * having to call it again if the BCH driver returns -EPROBE_DEFER. + */ + nfc->bch = of_jz4780_bch_get(dev->of_node); + if (IS_ERR(nfc->bch)) + return PTR_ERR(nfc->bch); + + nfc->dev = dev; + nfc->num_banks = num_banks; + + nand_controller_init(&nfc->controller); + INIT_LIST_HEAD(&nfc->chips); + + ret = jz4780_nand_init_chips(nfc, pdev); + if (ret) { + if (nfc->bch) + jz4780_bch_release(nfc->bch); + return ret; + } + + platform_set_drvdata(pdev, nfc); + return 0; +} + +static int jz4780_nand_remove(struct platform_device *pdev) +{ + struct jz4780_nand_controller *nfc = platform_get_drvdata(pdev); + + if (nfc->bch) + jz4780_bch_release(nfc->bch); + + jz4780_nand_cleanup_chips(nfc); + + return 0; +} + +static const struct of_device_id jz4780_nand_dt_match[] = { + { .compatible = "ingenic,jz4780-nand" }, + {}, +}; +MODULE_DEVICE_TABLE(of, jz4780_nand_dt_match); + +static struct platform_driver jz4780_nand_driver = { + .probe = jz4780_nand_probe, + .remove = jz4780_nand_remove, + .driver = { + .name = DRV_NAME, + .of_match_table = of_match_ptr(jz4780_nand_dt_match), + }, +}; +module_platform_driver(jz4780_nand_driver); + +MODULE_AUTHOR("Alex Smith "); +MODULE_AUTHOR("Harvey Hunt "); +MODULE_DESCRIPTION("Ingenic JZ4780 NAND driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/mtd/nand/raw/jz4740_nand.c b/drivers/mtd/nand/raw/jz4740_nand.c deleted file mode 100644 index 9526d5b23c80..000000000000 --- a/drivers/mtd/nand/raw/jz4740_nand.c +++ /dev/null @@ -1,542 +0,0 @@ -/* - * Copyright (C) 2009-2010, Lars-Peter Clausen - * JZ4740 SoC NAND controller driver - * - * 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. - * - * 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., - * 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include - -#include - -#define JZ_REG_NAND_CTRL 0x50 -#define JZ_REG_NAND_ECC_CTRL 0x100 -#define JZ_REG_NAND_DATA 0x104 -#define JZ_REG_NAND_PAR0 0x108 -#define JZ_REG_NAND_PAR1 0x10C -#define JZ_REG_NAND_PAR2 0x110 -#define JZ_REG_NAND_IRQ_STAT 0x114 -#define JZ_REG_NAND_IRQ_CTRL 0x118 -#define JZ_REG_NAND_ERR(x) (0x11C + ((x) << 2)) - -#define JZ_NAND_ECC_CTRL_PAR_READY BIT(4) -#define JZ_NAND_ECC_CTRL_ENCODING BIT(3) -#define JZ_NAND_ECC_CTRL_RS BIT(2) -#define JZ_NAND_ECC_CTRL_RESET BIT(1) -#define JZ_NAND_ECC_CTRL_ENABLE BIT(0) - -#define JZ_NAND_STATUS_ERR_COUNT (BIT(31) | BIT(30) | BIT(29)) -#define JZ_NAND_STATUS_PAD_FINISH BIT(4) -#define JZ_NAND_STATUS_DEC_FINISH BIT(3) -#define JZ_NAND_STATUS_ENC_FINISH BIT(2) -#define JZ_NAND_STATUS_UNCOR_ERROR BIT(1) -#define JZ_NAND_STATUS_ERROR BIT(0) - -#define JZ_NAND_CTRL_ENABLE_CHIP(x) BIT((x) << 1) -#define JZ_NAND_CTRL_ASSERT_CHIP(x) BIT(((x) << 1) + 1) -#define JZ_NAND_CTRL_ASSERT_CHIP_MASK 0xaa - -#define JZ_NAND_MEM_CMD_OFFSET 0x08000 -#define JZ_NAND_MEM_ADDR_OFFSET 0x10000 - -struct jz_nand { - struct nand_chip chip; - void __iomem *base; - struct resource *mem; - - unsigned char banks[JZ_NAND_NUM_BANKS]; - void __iomem *bank_base[JZ_NAND_NUM_BANKS]; - struct resource *bank_mem[JZ_NAND_NUM_BANKS]; - - int selected_bank; - - struct gpio_desc *busy_gpio; - bool is_reading; -}; - -static inline struct jz_nand *mtd_to_jz_nand(struct mtd_info *mtd) -{ - return container_of(mtd_to_nand(mtd), struct jz_nand, chip); -} - -static void jz_nand_select_chip(struct nand_chip *chip, int chipnr) -{ - struct jz_nand *nand = mtd_to_jz_nand(nand_to_mtd(chip)); - uint32_t ctrl; - int banknr; - - ctrl = readl(nand->base + JZ_REG_NAND_CTRL); - ctrl &= ~JZ_NAND_CTRL_ASSERT_CHIP_MASK; - - if (chipnr == -1) { - banknr = -1; - } else { - banknr = nand->banks[chipnr] - 1; - chip->legacy.IO_ADDR_R = nand->bank_base[banknr]; - chip->legacy.IO_ADDR_W = nand->bank_base[banknr]; - } - writel(ctrl, nand->base + JZ_REG_NAND_CTRL); - - nand->selected_bank = banknr; -} - -static void jz_nand_cmd_ctrl(struct nand_chip *chip, int dat, - unsigned int ctrl) -{ - struct jz_nand *nand = mtd_to_jz_nand(nand_to_mtd(chip)); - uint32_t reg; - void __iomem *bank_base = nand->bank_base[nand->selected_bank]; - - BUG_ON(nand->selected_bank < 0); - - if (ctrl & NAND_CTRL_CHANGE) { - BUG_ON((ctrl & NAND_ALE) && (ctrl & NAND_CLE)); - if (ctrl & NAND_ALE) - bank_base += JZ_NAND_MEM_ADDR_OFFSET; - else if (ctrl & NAND_CLE) - bank_base += JZ_NAND_MEM_CMD_OFFSET; - chip->legacy.IO_ADDR_W = bank_base; - - reg = readl(nand->base + JZ_REG_NAND_CTRL); - if (ctrl & NAND_NCE) - reg |= JZ_NAND_CTRL_ASSERT_CHIP(nand->selected_bank); - else - reg &= ~JZ_NAND_CTRL_ASSERT_CHIP(nand->selected_bank); - writel(reg, nand->base + JZ_REG_NAND_CTRL); - } - if (dat != NAND_CMD_NONE) - writeb(dat, chip->legacy.IO_ADDR_W); -} - -static int jz_nand_dev_ready(struct nand_chip *chip) -{ - struct jz_nand *nand = mtd_to_jz_nand(nand_to_mtd(chip)); - return gpiod_get_value_cansleep(nand->busy_gpio); -} - -static void jz_nand_hwctl(struct nand_chip *chip, int mode) -{ - struct jz_nand *nand = mtd_to_jz_nand(nand_to_mtd(chip)); - uint32_t reg; - - writel(0, nand->base + JZ_REG_NAND_IRQ_STAT); - reg = readl(nand->base + JZ_REG_NAND_ECC_CTRL); - - reg |= JZ_NAND_ECC_CTRL_RESET; - reg |= JZ_NAND_ECC_CTRL_ENABLE; - reg |= JZ_NAND_ECC_CTRL_RS; - - switch (mode) { - case NAND_ECC_READ: - reg &= ~JZ_NAND_ECC_CTRL_ENCODING; - nand->is_reading = true; - break; - case NAND_ECC_WRITE: - reg |= JZ_NAND_ECC_CTRL_ENCODING; - nand->is_reading = false; - break; - default: - break; - } - - writel(reg, nand->base + JZ_REG_NAND_ECC_CTRL); -} - -static int jz_nand_calculate_ecc_rs(struct nand_chip *chip, const uint8_t *dat, - uint8_t *ecc_code) -{ - struct jz_nand *nand = mtd_to_jz_nand(nand_to_mtd(chip)); - uint32_t reg, status; - int i; - unsigned int timeout = 1000; - static uint8_t empty_block_ecc[] = {0xcd, 0x9d, 0x90, 0x58, 0xf4, - 0x8b, 0xff, 0xb7, 0x6f}; - - if (nand->is_reading) - return 0; - - do { - status = readl(nand->base + JZ_REG_NAND_IRQ_STAT); - } while (!(status & JZ_NAND_STATUS_ENC_FINISH) && --timeout); - - if (timeout == 0) - return -1; - - reg = readl(nand->base + JZ_REG_NAND_ECC_CTRL); - reg &= ~JZ_NAND_ECC_CTRL_ENABLE; - writel(reg, nand->base + JZ_REG_NAND_ECC_CTRL); - - for (i = 0; i < 9; ++i) - ecc_code[i] = readb(nand->base + JZ_REG_NAND_PAR0 + i); - - /* If the written data is completly 0xff, we also want to write 0xff as - * ecc, otherwise we will get in trouble when doing subpage writes. */ - if (memcmp(ecc_code, empty_block_ecc, 9) == 0) - memset(ecc_code, 0xff, 9); - - return 0; -} - -static void jz_nand_correct_data(uint8_t *dat, int index, int mask) -{ - int offset = index & 0x7; - uint16_t data; - - index += (index >> 3); - - data = dat[index]; - data |= dat[index+1] << 8; - - mask ^= (data >> offset) & 0x1ff; - data &= ~(0x1ff << offset); - data |= (mask << offset); - - dat[index] = data & 0xff; - dat[index+1] = (data >> 8) & 0xff; -} - -static int jz_nand_correct_ecc_rs(struct nand_chip *chip, uint8_t *dat, - uint8_t *read_ecc, uint8_t *calc_ecc) -{ - struct jz_nand *nand = mtd_to_jz_nand(nand_to_mtd(chip)); - int i, error_count, index; - uint32_t reg, status, error; - unsigned int timeout = 1000; - - for (i = 0; i < 9; ++i) - writeb(read_ecc[i], nand->base + JZ_REG_NAND_PAR0 + i); - - reg = readl(nand->base + JZ_REG_NAND_ECC_CTRL); - reg |= JZ_NAND_ECC_CTRL_PAR_READY; - writel(reg, nand->base + JZ_REG_NAND_ECC_CTRL); - - do { - status = readl(nand->base + JZ_REG_NAND_IRQ_STAT); - } while (!(status & JZ_NAND_STATUS_DEC_FINISH) && --timeout); - - if (timeout == 0) - return -ETIMEDOUT; - - reg = readl(nand->base + JZ_REG_NAND_ECC_CTRL); - reg &= ~JZ_NAND_ECC_CTRL_ENABLE; - writel(reg, nand->base + JZ_REG_NAND_ECC_CTRL); - - if (status & JZ_NAND_STATUS_ERROR) { - if (status & JZ_NAND_STATUS_UNCOR_ERROR) - return -EBADMSG; - - error_count = (status & JZ_NAND_STATUS_ERR_COUNT) >> 29; - - for (i = 0; i < error_count; ++i) { - error = readl(nand->base + JZ_REG_NAND_ERR(i)); - index = ((error >> 16) & 0x1ff) - 1; - if (index >= 0 && index < 512) - jz_nand_correct_data(dat, index, error & 0x1ff); - } - - return error_count; - } - - return 0; -} - -static int jz_nand_ioremap_resource(struct platform_device *pdev, - const char *name, struct resource **res, void __iomem **base) -{ - int ret; - - *res = platform_get_resource_byname(pdev, IORESOURCE_MEM, name); - if (!*res) { - dev_err(&pdev->dev, "Failed to get platform %s memory\n", name); - ret = -ENXIO; - goto err; - } - - *res = request_mem_region((*res)->start, resource_size(*res), - pdev->name); - if (!*res) { - dev_err(&pdev->dev, "Failed to request %s memory region\n", name); - ret = -EBUSY; - goto err; - } - - *base = ioremap((*res)->start, resource_size(*res)); - if (!*base) { - dev_err(&pdev->dev, "Failed to ioremap %s memory region\n", name); - ret = -EBUSY; - goto err_release_mem; - } - - return 0; - -err_release_mem: - release_mem_region((*res)->start, resource_size(*res)); -err: - *res = NULL; - *base = NULL; - return ret; -} - -static inline void jz_nand_iounmap_resource(struct resource *res, - void __iomem *base) -{ - iounmap(base); - release_mem_region(res->start, resource_size(res)); -} - -static int jz_nand_detect_bank(struct platform_device *pdev, - struct jz_nand *nand, unsigned char bank, - size_t chipnr, uint8_t *nand_maf_id, - uint8_t *nand_dev_id) -{ - int ret; - char res_name[6]; - uint32_t ctrl; - struct nand_chip *chip = &nand->chip; - struct mtd_info *mtd = nand_to_mtd(chip); - u8 id[2]; - - /* Request I/O resource. */ - sprintf(res_name, "bank%d", bank); - ret = jz_nand_ioremap_resource(pdev, res_name, - &nand->bank_mem[bank - 1], - &nand->bank_base[bank - 1]); - if (ret) - return ret; - - /* Enable chip in bank. */ - ctrl = readl(nand->base + JZ_REG_NAND_CTRL); - ctrl |= JZ_NAND_CTRL_ENABLE_CHIP(bank - 1); - writel(ctrl, nand->base + JZ_REG_NAND_CTRL); - - if (chipnr == 0) { - /* Detect first chip. */ - ret = nand_scan(chip, 1); - if (ret) - goto notfound_id; - - /* Retrieve the IDs from the first chip. */ - nand_select_target(chip, 0); - nand_reset_op(chip); - nand_readid_op(chip, 0, id, sizeof(id)); - *nand_maf_id = id[0]; - *nand_dev_id = id[1]; - } else { - /* Detect additional chip. */ - nand_select_target(chip, chipnr); - nand_reset_op(chip); - nand_readid_op(chip, 0, id, sizeof(id)); - if (*nand_maf_id != id[0] || *nand_dev_id != id[1]) { - ret = -ENODEV; - goto notfound_id; - } - - /* Update size of the MTD. */ - chip->numchips++; - mtd->size += chip->chipsize; - } - - dev_info(&pdev->dev, "Found chip %zu on bank %i\n", chipnr, bank); - return 0; - -notfound_id: - dev_info(&pdev->dev, "No chip found on bank %i\n", bank); - ctrl &= ~(JZ_NAND_CTRL_ENABLE_CHIP(bank - 1)); - writel(ctrl, nand->base + JZ_REG_NAND_CTRL); - jz_nand_iounmap_resource(nand->bank_mem[bank - 1], - nand->bank_base[bank - 1]); - return ret; -} - -static int jz_nand_attach_chip(struct nand_chip *chip) -{ - struct mtd_info *mtd = nand_to_mtd(chip); - struct device *dev = mtd->dev.parent; - struct jz_nand_platform_data *pdata = dev_get_platdata(dev); - struct platform_device *pdev = to_platform_device(dev); - - if (pdata && pdata->ident_callback) - pdata->ident_callback(pdev, mtd, &pdata->partitions, - &pdata->num_partitions); - - return 0; -} - -static const struct nand_controller_ops jz_nand_controller_ops = { - .attach_chip = jz_nand_attach_chip, -}; - -static int jz_nand_probe(struct platform_device *pdev) -{ - int ret; - struct jz_nand *nand; - struct nand_chip *chip; - struct mtd_info *mtd; - struct jz_nand_platform_data *pdata = dev_get_platdata(&pdev->dev); - size_t chipnr, bank_idx; - uint8_t nand_maf_id = 0, nand_dev_id = 0; - - nand = kzalloc(sizeof(*nand), GFP_KERNEL); - if (!nand) - return -ENOMEM; - - ret = jz_nand_ioremap_resource(pdev, "mmio", &nand->mem, &nand->base); - if (ret) - goto err_free; - - nand->busy_gpio = devm_gpiod_get_optional(&pdev->dev, "busy", GPIOD_IN); - if (IS_ERR(nand->busy_gpio)) { - ret = PTR_ERR(nand->busy_gpio); - dev_err(&pdev->dev, "Failed to request busy gpio %d\n", - ret); - goto err_iounmap_mmio; - } - - chip = &nand->chip; - mtd = nand_to_mtd(chip); - mtd->dev.parent = &pdev->dev; - mtd->name = "jz4740-nand"; - - chip->ecc.hwctl = jz_nand_hwctl; - chip->ecc.calculate = jz_nand_calculate_ecc_rs; - chip->ecc.correct = jz_nand_correct_ecc_rs; - chip->ecc.mode = NAND_ECC_HW_OOB_FIRST; - chip->ecc.size = 512; - chip->ecc.bytes = 9; - chip->ecc.strength = 4; - chip->ecc.options = NAND_ECC_GENERIC_ERASED_CHECK; - - chip->legacy.chip_delay = 50; - chip->legacy.cmd_ctrl = jz_nand_cmd_ctrl; - chip->legacy.select_chip = jz_nand_select_chip; - chip->legacy.dummy_controller.ops = &jz_nand_controller_ops; - - if (nand->busy_gpio) - chip->legacy.dev_ready = jz_nand_dev_ready; - - platform_set_drvdata(pdev, nand); - - /* We are going to autodetect NAND chips in the banks specified in the - * platform data. Although nand_scan_ident() can detect multiple chips, - * it requires those chips to be numbered consecuitively, which is not - * always the case for external memory banks. And a fixed chip-to-bank - * mapping is not practical either, since for example Dingoo units - * produced at different times have NAND chips in different banks. - */ - chipnr = 0; - for (bank_idx = 0; bank_idx < JZ_NAND_NUM_BANKS; bank_idx++) { - unsigned char bank; - - /* If there is no platform data, look for NAND in bank 1, - * which is the most likely bank since it is the only one - * that can be booted from. - */ - bank = pdata ? pdata->banks[bank_idx] : bank_idx ^ 1; - if (bank == 0) - break; - if (bank > JZ_NAND_NUM_BANKS) { - dev_warn(&pdev->dev, - "Skipping non-existing bank: %d\n", bank); - continue; - } - /* The detection routine will directly or indirectly call - * jz_nand_select_chip(), so nand->banks has to contain the - * bank we're checking. - */ - nand->banks[chipnr] = bank; - if (jz_nand_detect_bank(pdev, nand, bank, chipnr, - &nand_maf_id, &nand_dev_id) == 0) - chipnr++; - else - nand->banks[chipnr] = 0; - } - if (chipnr == 0) { - dev_err(&pdev->dev, "No NAND chips found\n"); - goto err_iounmap_mmio; - } - - ret = mtd_device_register(mtd, pdata ? pdata->partitions : NULL, - pdata ? pdata->num_partitions : 0); - - if (ret) { - dev_err(&pdev->dev, "Failed to add mtd device\n"); - goto err_cleanup_nand; - } - - dev_info(&pdev->dev, "Successfully registered JZ4740 NAND driver\n"); - - return 0; - -err_cleanup_nand: - nand_cleanup(chip); - while (chipnr--) { - unsigned char bank = nand->banks[chipnr]; - jz_nand_iounmap_resource(nand->bank_mem[bank - 1], - nand->bank_base[bank - 1]); - } - writel(0, nand->base + JZ_REG_NAND_CTRL); -err_iounmap_mmio: - jz_nand_iounmap_resource(nand->mem, nand->base); -err_free: - kfree(nand); - return ret; -} - -static int jz_nand_remove(struct platform_device *pdev) -{ - struct jz_nand *nand = platform_get_drvdata(pdev); - size_t i; - - nand_release(&nand->chip); - - /* Deassert and disable all chips */ - writel(0, nand->base + JZ_REG_NAND_CTRL); - - for (i = 0; i < JZ_NAND_NUM_BANKS; ++i) { - unsigned char bank = nand->banks[i]; - if (bank != 0) { - jz_nand_iounmap_resource(nand->bank_mem[bank - 1], - nand->bank_base[bank - 1]); - } - } - - jz_nand_iounmap_resource(nand->mem, nand->base); - - kfree(nand); - - return 0; -} - -static struct platform_driver jz_nand_driver = { - .probe = jz_nand_probe, - .remove = jz_nand_remove, - .driver = { - .name = "jz4740-nand", - }, -}; - -module_platform_driver(jz_nand_driver); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Lars-Peter Clausen "); -MODULE_DESCRIPTION("NAND controller driver for JZ4740 SoC"); -MODULE_ALIAS("platform:jz4740-nand"); diff --git a/drivers/mtd/nand/raw/jz4780_bch.c b/drivers/mtd/nand/raw/jz4780_bch.c deleted file mode 100644 index c5f74ed85862..000000000000 --- a/drivers/mtd/nand/raw/jz4780_bch.c +++ /dev/null @@ -1,385 +0,0 @@ -/* - * JZ4780 BCH controller - * - * Copyright (c) 2015 Imagination Technologies - * Author: Alex Smith - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "jz4780_bch.h" - -#define BCH_BHCR 0x0 -#define BCH_BHCCR 0x8 -#define BCH_BHCNT 0xc -#define BCH_BHDR 0x10 -#define BCH_BHPAR0 0x14 -#define BCH_BHERR0 0x84 -#define BCH_BHINT 0x184 -#define BCH_BHINTES 0x188 -#define BCH_BHINTEC 0x18c -#define BCH_BHINTE 0x190 - -#define BCH_BHCR_BSEL_SHIFT 4 -#define BCH_BHCR_BSEL_MASK (0x7f << BCH_BHCR_BSEL_SHIFT) -#define BCH_BHCR_ENCE BIT(2) -#define BCH_BHCR_INIT BIT(1) -#define BCH_BHCR_BCHE BIT(0) - -#define BCH_BHCNT_PARITYSIZE_SHIFT 16 -#define BCH_BHCNT_PARITYSIZE_MASK (0x7f << BCH_BHCNT_PARITYSIZE_SHIFT) -#define BCH_BHCNT_BLOCKSIZE_SHIFT 0 -#define BCH_BHCNT_BLOCKSIZE_MASK (0x7ff << BCH_BHCNT_BLOCKSIZE_SHIFT) - -#define BCH_BHERR_MASK_SHIFT 16 -#define BCH_BHERR_MASK_MASK (0xffff << BCH_BHERR_MASK_SHIFT) -#define BCH_BHERR_INDEX_SHIFT 0 -#define BCH_BHERR_INDEX_MASK (0x7ff << BCH_BHERR_INDEX_SHIFT) - -#define BCH_BHINT_ERRC_SHIFT 24 -#define BCH_BHINT_ERRC_MASK (0x7f << BCH_BHINT_ERRC_SHIFT) -#define BCH_BHINT_TERRC_SHIFT 16 -#define BCH_BHINT_TERRC_MASK (0x7f << BCH_BHINT_TERRC_SHIFT) -#define BCH_BHINT_DECF BIT(3) -#define BCH_BHINT_ENCF BIT(2) -#define BCH_BHINT_UNCOR BIT(1) -#define BCH_BHINT_ERR BIT(0) - -#define BCH_CLK_RATE (200 * 1000 * 1000) - -/* Timeout for BCH calculation/correction. */ -#define BCH_TIMEOUT_US 100000 - -struct jz4780_bch { - struct device *dev; - void __iomem *base; - struct clk *clk; - struct mutex lock; -}; - -static void jz4780_bch_init(struct jz4780_bch *bch, - struct jz4780_bch_params *params, bool encode) -{ - u32 reg; - - /* Clear interrupt status. */ - writel(readl(bch->base + BCH_BHINT), bch->base + BCH_BHINT); - - /* Set up BCH count register. */ - reg = params->size << BCH_BHCNT_BLOCKSIZE_SHIFT; - reg |= params->bytes << BCH_BHCNT_PARITYSIZE_SHIFT; - writel(reg, bch->base + BCH_BHCNT); - - /* Initialise and enable BCH. */ - reg = BCH_BHCR_BCHE | BCH_BHCR_INIT; - reg |= params->strength << BCH_BHCR_BSEL_SHIFT; - if (encode) - reg |= BCH_BHCR_ENCE; - writel(reg, bch->base + BCH_BHCR); -} - -static void jz4780_bch_disable(struct jz4780_bch *bch) -{ - writel(readl(bch->base + BCH_BHINT), bch->base + BCH_BHINT); - writel(BCH_BHCR_BCHE, bch->base + BCH_BHCCR); -} - -static void jz4780_bch_write_data(struct jz4780_bch *bch, const void *buf, - size_t size) -{ - size_t size32 = size / sizeof(u32); - size_t size8 = size % sizeof(u32); - const u32 *src32; - const u8 *src8; - - src32 = (const u32 *)buf; - while (size32--) - writel(*src32++, bch->base + BCH_BHDR); - - src8 = (const u8 *)src32; - while (size8--) - writeb(*src8++, bch->base + BCH_BHDR); -} - -static void jz4780_bch_read_parity(struct jz4780_bch *bch, void *buf, - size_t size) -{ - size_t size32 = size / sizeof(u32); - size_t size8 = size % sizeof(u32); - u32 *dest32; - u8 *dest8; - u32 val, offset = 0; - - dest32 = (u32 *)buf; - while (size32--) { - *dest32++ = readl(bch->base + BCH_BHPAR0 + offset); - offset += sizeof(u32); - } - - dest8 = (u8 *)dest32; - val = readl(bch->base + BCH_BHPAR0 + offset); - switch (size8) { - case 3: - dest8[2] = (val >> 16) & 0xff; - /* fall through */ - case 2: - dest8[1] = (val >> 8) & 0xff; - /* fall through */ - case 1: - dest8[0] = val & 0xff; - break; - } -} - -static bool jz4780_bch_wait_complete(struct jz4780_bch *bch, unsigned int irq, - u32 *status) -{ - u32 reg; - int ret; - - /* - * While we could use interrupts here and sleep until the operation - * completes, the controller works fairly quickly (usually a few - * microseconds) and so the overhead of sleeping until we get an - * interrupt quite noticeably decreases performance. - */ - ret = readl_poll_timeout(bch->base + BCH_BHINT, reg, - (reg & irq) == irq, 0, BCH_TIMEOUT_US); - if (ret) - return false; - - if (status) - *status = reg; - - writel(reg, bch->base + BCH_BHINT); - return true; -} - -/** - * jz4780_bch_calculate() - calculate ECC for a data buffer - * @bch: BCH device. - * @params: BCH parameters. - * @buf: input buffer with raw data. - * @ecc_code: output buffer with ECC. - * - * Return: 0 on success, -ETIMEDOUT if timed out while waiting for BCH - * controller. - */ -int jz4780_bch_calculate(struct jz4780_bch *bch, struct jz4780_bch_params *params, - const u8 *buf, u8 *ecc_code) -{ - int ret = 0; - - mutex_lock(&bch->lock); - jz4780_bch_init(bch, params, true); - jz4780_bch_write_data(bch, buf, params->size); - - if (jz4780_bch_wait_complete(bch, BCH_BHINT_ENCF, NULL)) { - jz4780_bch_read_parity(bch, ecc_code, params->bytes); - } else { - dev_err(bch->dev, "timed out while calculating ECC\n"); - ret = -ETIMEDOUT; - } - - jz4780_bch_disable(bch); - mutex_unlock(&bch->lock); - return ret; -} -EXPORT_SYMBOL(jz4780_bch_calculate); - -/** - * jz4780_bch_correct() - detect and correct bit errors - * @bch: BCH device. - * @params: BCH parameters. - * @buf: raw data read from the chip. - * @ecc_code: ECC read from the chip. - * - * Given the raw data and the ECC read from the NAND device, detects and - * corrects errors in the data. - * - * Return: the number of bit errors corrected, -EBADMSG if there are too many - * errors to correct or -ETIMEDOUT if we timed out waiting for the controller. - */ -int jz4780_bch_correct(struct jz4780_bch *bch, struct jz4780_bch_params *params, - u8 *buf, u8 *ecc_code) -{ - u32 reg, mask, index; - int i, ret, count; - - mutex_lock(&bch->lock); - - jz4780_bch_init(bch, params, false); - jz4780_bch_write_data(bch, buf, params->size); - jz4780_bch_write_data(bch, ecc_code, params->bytes); - - if (!jz4780_bch_wait_complete(bch, BCH_BHINT_DECF, ®)) { - dev_err(bch->dev, "timed out while correcting data\n"); - ret = -ETIMEDOUT; - goto out; - } - - if (reg & BCH_BHINT_UNCOR) { - dev_warn(bch->dev, "uncorrectable ECC error\n"); - ret = -EBADMSG; - goto out; - } - - /* Correct any detected errors. */ - if (reg & BCH_BHINT_ERR) { - count = (reg & BCH_BHINT_ERRC_MASK) >> BCH_BHINT_ERRC_SHIFT; - ret = (reg & BCH_BHINT_TERRC_MASK) >> BCH_BHINT_TERRC_SHIFT; - - for (i = 0; i < count; i++) { - reg = readl(bch->base + BCH_BHERR0 + (i * 4)); - mask = (reg & BCH_BHERR_MASK_MASK) >> - BCH_BHERR_MASK_SHIFT; - index = (reg & BCH_BHERR_INDEX_MASK) >> - BCH_BHERR_INDEX_SHIFT; - buf[(index * 2) + 0] ^= mask; - buf[(index * 2) + 1] ^= mask >> 8; - } - } else { - ret = 0; - } - -out: - jz4780_bch_disable(bch); - mutex_unlock(&bch->lock); - return ret; -} -EXPORT_SYMBOL(jz4780_bch_correct); - -/** - * jz4780_bch_get() - get the BCH controller device - * @np: BCH device tree node. - * - * Gets the BCH controller device from the specified device tree node. The - * device must be released with jz4780_bch_release() when it is no longer being - * used. - * - * Return: a pointer to jz4780_bch, errors are encoded into the pointer. - * PTR_ERR(-EPROBE_DEFER) if the device hasn't been initialised yet. - */ -static struct jz4780_bch *jz4780_bch_get(struct device_node *np) -{ - struct platform_device *pdev; - struct jz4780_bch *bch; - - pdev = of_find_device_by_node(np); - if (!pdev) - return ERR_PTR(-EPROBE_DEFER); - - bch = platform_get_drvdata(pdev); - if (!bch) { - put_device(&pdev->dev); - return ERR_PTR(-EPROBE_DEFER); - } - - clk_prepare_enable(bch->clk); - - return bch; -} - -/** - * of_jz4780_bch_get() - get the BCH controller from a DT node - * @of_node: the node that contains a bch-controller property. - * - * Get the bch-controller property from the given device tree - * node and pass it to jz4780_bch_get to do the work. - * - * Return: a pointer to jz4780_bch, errors are encoded into the pointer. - * PTR_ERR(-EPROBE_DEFER) if the device hasn't been initialised yet. - */ -struct jz4780_bch *of_jz4780_bch_get(struct device_node *of_node) -{ - struct jz4780_bch *bch = NULL; - struct device_node *np; - - np = of_parse_phandle(of_node, "ingenic,bch-controller", 0); - - if (np) { - bch = jz4780_bch_get(np); - of_node_put(np); - } - return bch; -} -EXPORT_SYMBOL(of_jz4780_bch_get); - -/** - * jz4780_bch_release() - release the BCH controller device - * @bch: BCH device. - */ -void jz4780_bch_release(struct jz4780_bch *bch) -{ - clk_disable_unprepare(bch->clk); - put_device(bch->dev); -} -EXPORT_SYMBOL(jz4780_bch_release); - -static int jz4780_bch_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct jz4780_bch *bch; - struct resource *res; - - bch = devm_kzalloc(dev, sizeof(*bch), GFP_KERNEL); - if (!bch) - return -ENOMEM; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - bch->base = devm_ioremap_resource(dev, res); - if (IS_ERR(bch->base)) - return PTR_ERR(bch->base); - - jz4780_bch_disable(bch); - - bch->clk = devm_clk_get(dev, NULL); - if (IS_ERR(bch->clk)) { - dev_err(dev, "failed to get clock: %ld\n", PTR_ERR(bch->clk)); - return PTR_ERR(bch->clk); - } - - clk_set_rate(bch->clk, BCH_CLK_RATE); - - mutex_init(&bch->lock); - - bch->dev = dev; - platform_set_drvdata(pdev, bch); - - return 0; -} - -static const struct of_device_id jz4780_bch_dt_match[] = { - { .compatible = "ingenic,jz4780-bch" }, - {}, -}; -MODULE_DEVICE_TABLE(of, jz4780_bch_dt_match); - -static struct platform_driver jz4780_bch_driver = { - .probe = jz4780_bch_probe, - .driver = { - .name = "jz4780-bch", - .of_match_table = of_match_ptr(jz4780_bch_dt_match), - }, -}; -module_platform_driver(jz4780_bch_driver); - -MODULE_AUTHOR("Alex Smith "); -MODULE_AUTHOR("Harvey Hunt "); -MODULE_DESCRIPTION("Ingenic JZ4780 BCH error correction driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/mtd/nand/raw/jz4780_bch.h b/drivers/mtd/nand/raw/jz4780_bch.h deleted file mode 100644 index bf4718088a3a..000000000000 --- a/drivers/mtd/nand/raw/jz4780_bch.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * JZ4780 BCH controller - * - * Copyright (c) 2015 Imagination Technologies - * Author: Alex Smith - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. - */ - -#ifndef __DRIVERS_MTD_NAND_JZ4780_BCH_H__ -#define __DRIVERS_MTD_NAND_JZ4780_BCH_H__ - -#include - -struct device; -struct device_node; -struct jz4780_bch; - -/** - * struct jz4780_bch_params - BCH parameters - * @size: data bytes per ECC step. - * @bytes: ECC bytes per step. - * @strength: number of correctable bits per ECC step. - */ -struct jz4780_bch_params { - int size; - int bytes; - int strength; -}; - -int jz4780_bch_calculate(struct jz4780_bch *bch, - struct jz4780_bch_params *params, - const u8 *buf, u8 *ecc_code); -int jz4780_bch_correct(struct jz4780_bch *bch, - struct jz4780_bch_params *params, u8 *buf, - u8 *ecc_code); - -void jz4780_bch_release(struct jz4780_bch *bch); -struct jz4780_bch *of_jz4780_bch_get(struct device_node *np); - -#endif /* __DRIVERS_MTD_NAND_JZ4780_BCH_H__ */ diff --git a/drivers/mtd/nand/raw/jz4780_nand.c b/drivers/mtd/nand/raw/jz4780_nand.c deleted file mode 100644 index 22e58975f0d5..000000000000 --- a/drivers/mtd/nand/raw/jz4780_nand.c +++ /dev/null @@ -1,415 +0,0 @@ -/* - * JZ4780 NAND driver - * - * Copyright (c) 2015 Imagination Technologies - * Author: Alex Smith - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "jz4780_bch.h" - -#define DRV_NAME "jz4780-nand" - -#define OFFSET_DATA 0x00000000 -#define OFFSET_CMD 0x00400000 -#define OFFSET_ADDR 0x00800000 - -/* Command delay when there is no R/B pin. */ -#define RB_DELAY_US 100 - -struct jz4780_nand_cs { - unsigned int bank; - void __iomem *base; -}; - -struct jz4780_nand_controller { - struct device *dev; - struct jz4780_bch *bch; - struct nand_controller controller; - unsigned int num_banks; - struct list_head chips; - int selected; - struct jz4780_nand_cs cs[]; -}; - -struct jz4780_nand_chip { - struct nand_chip chip; - struct list_head chip_list; - - struct gpio_desc *busy_gpio; - struct gpio_desc *wp_gpio; - unsigned int reading: 1; -}; - -static inline struct jz4780_nand_chip *to_jz4780_nand_chip(struct mtd_info *mtd) -{ - return container_of(mtd_to_nand(mtd), struct jz4780_nand_chip, chip); -} - -static inline struct jz4780_nand_controller -*to_jz4780_nand_controller(struct nand_controller *ctrl) -{ - return container_of(ctrl, struct jz4780_nand_controller, controller); -} - -static void jz4780_nand_select_chip(struct nand_chip *chip, int chipnr) -{ - struct jz4780_nand_chip *nand = to_jz4780_nand_chip(nand_to_mtd(chip)); - struct jz4780_nand_controller *nfc = to_jz4780_nand_controller(nand->chip.controller); - struct jz4780_nand_cs *cs; - - /* Ensure the currently selected chip is deasserted. */ - if (chipnr == -1 && nfc->selected >= 0) { - cs = &nfc->cs[nfc->selected]; - jz4780_nemc_assert(nfc->dev, cs->bank, false); - } - - nfc->selected = chipnr; -} - -static void jz4780_nand_cmd_ctrl(struct nand_chip *chip, int cmd, - unsigned int ctrl) -{ - struct jz4780_nand_chip *nand = to_jz4780_nand_chip(nand_to_mtd(chip)); - struct jz4780_nand_controller *nfc = to_jz4780_nand_controller(nand->chip.controller); - struct jz4780_nand_cs *cs; - - if (WARN_ON(nfc->selected < 0)) - return; - - cs = &nfc->cs[nfc->selected]; - - jz4780_nemc_assert(nfc->dev, cs->bank, ctrl & NAND_NCE); - - if (cmd == NAND_CMD_NONE) - return; - - if (ctrl & NAND_ALE) - writeb(cmd, cs->base + OFFSET_ADDR); - else if (ctrl & NAND_CLE) - writeb(cmd, cs->base + OFFSET_CMD); -} - -static int jz4780_nand_dev_ready(struct nand_chip *chip) -{ - struct jz4780_nand_chip *nand = to_jz4780_nand_chip(nand_to_mtd(chip)); - - return !gpiod_get_value_cansleep(nand->busy_gpio); -} - -static void jz4780_nand_ecc_hwctl(struct nand_chip *chip, int mode) -{ - struct jz4780_nand_chip *nand = to_jz4780_nand_chip(nand_to_mtd(chip)); - - nand->reading = (mode == NAND_ECC_READ); -} - -static int jz4780_nand_ecc_calculate(struct nand_chip *chip, const u8 *dat, - u8 *ecc_code) -{ - struct jz4780_nand_chip *nand = to_jz4780_nand_chip(nand_to_mtd(chip)); - struct jz4780_nand_controller *nfc = to_jz4780_nand_controller(nand->chip.controller); - struct jz4780_bch_params params; - - /* - * Don't need to generate the ECC when reading, BCH does it for us as - * part of decoding/correction. - */ - if (nand->reading) - return 0; - - params.size = nand->chip.ecc.size; - params.bytes = nand->chip.ecc.bytes; - params.strength = nand->chip.ecc.strength; - - return jz4780_bch_calculate(nfc->bch, ¶ms, dat, ecc_code); -} - -static int jz4780_nand_ecc_correct(struct nand_chip *chip, u8 *dat, - u8 *read_ecc, u8 *calc_ecc) -{ - struct jz4780_nand_chip *nand = to_jz4780_nand_chip(nand_to_mtd(chip)); - struct jz4780_nand_controller *nfc = to_jz4780_nand_controller(nand->chip.controller); - struct jz4780_bch_params params; - - params.size = nand->chip.ecc.size; - params.bytes = nand->chip.ecc.bytes; - params.strength = nand->chip.ecc.strength; - - return jz4780_bch_correct(nfc->bch, ¶ms, dat, read_ecc); -} - -static int jz4780_nand_attach_chip(struct nand_chip *chip) -{ - struct mtd_info *mtd = nand_to_mtd(chip); - struct jz4780_nand_controller *nfc = to_jz4780_nand_controller(chip->controller); - int eccbytes; - - chip->ecc.bytes = fls((1 + 8) * chip->ecc.size) * - (chip->ecc.strength / 8); - - switch (chip->ecc.mode) { - case NAND_ECC_HW: - if (!nfc->bch) { - dev_err(nfc->dev, - "HW BCH selected, but BCH controller not found\n"); - return -ENODEV; - } - - chip->ecc.hwctl = jz4780_nand_ecc_hwctl; - chip->ecc.calculate = jz4780_nand_ecc_calculate; - chip->ecc.correct = jz4780_nand_ecc_correct; - /* fall through */ - case NAND_ECC_SOFT: - dev_info(nfc->dev, "using %s (strength %d, size %d, bytes %d)\n", - (nfc->bch) ? "hardware BCH" : "software ECC", - chip->ecc.strength, chip->ecc.size, chip->ecc.bytes); - break; - case NAND_ECC_NONE: - dev_info(nfc->dev, "not using ECC\n"); - break; - default: - dev_err(nfc->dev, "ECC mode %d not supported\n", - chip->ecc.mode); - return -EINVAL; - } - - /* The NAND core will generate the ECC layout for SW ECC */ - if (chip->ecc.mode != NAND_ECC_HW) - return 0; - - /* Generate ECC layout. ECC codes are right aligned in the OOB area. */ - eccbytes = mtd->writesize / chip->ecc.size * chip->ecc.bytes; - - if (eccbytes > mtd->oobsize - 2) { - dev_err(nfc->dev, - "invalid ECC config: required %d ECC bytes, but only %d are available", - eccbytes, mtd->oobsize - 2); - return -EINVAL; - } - - mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops); - - return 0; -} - -static const struct nand_controller_ops jz4780_nand_controller_ops = { - .attach_chip = jz4780_nand_attach_chip, -}; - -static int jz4780_nand_init_chip(struct platform_device *pdev, - struct jz4780_nand_controller *nfc, - struct device_node *np, - unsigned int chipnr) -{ - struct device *dev = &pdev->dev; - struct jz4780_nand_chip *nand; - struct jz4780_nand_cs *cs; - struct resource *res; - struct nand_chip *chip; - struct mtd_info *mtd; - const __be32 *reg; - int ret = 0; - - cs = &nfc->cs[chipnr]; - - reg = of_get_property(np, "reg", NULL); - if (!reg) - return -EINVAL; - - cs->bank = be32_to_cpu(*reg); - - jz4780_nemc_set_type(nfc->dev, cs->bank, JZ4780_NEMC_BANK_NAND); - - res = platform_get_resource(pdev, IORESOURCE_MEM, chipnr); - cs->base = devm_ioremap_resource(dev, res); - if (IS_ERR(cs->base)) - return PTR_ERR(cs->base); - - nand = devm_kzalloc(dev, sizeof(*nand), GFP_KERNEL); - if (!nand) - return -ENOMEM; - - nand->busy_gpio = devm_gpiod_get_optional(dev, "rb", GPIOD_IN); - - if (IS_ERR(nand->busy_gpio)) { - ret = PTR_ERR(nand->busy_gpio); - dev_err(dev, "failed to request busy GPIO: %d\n", ret); - return ret; - } else if (nand->busy_gpio) { - nand->chip.legacy.dev_ready = jz4780_nand_dev_ready; - } - - nand->wp_gpio = devm_gpiod_get_optional(dev, "wp", GPIOD_OUT_LOW); - - if (IS_ERR(nand->wp_gpio)) { - ret = PTR_ERR(nand->wp_gpio); - dev_err(dev, "failed to request WP GPIO: %d\n", ret); - return ret; - } - - chip = &nand->chip; - mtd = nand_to_mtd(chip); - mtd->name = devm_kasprintf(dev, GFP_KERNEL, "%s.%d", dev_name(dev), - cs->bank); - if (!mtd->name) - return -ENOMEM; - mtd->dev.parent = dev; - - chip->legacy.IO_ADDR_R = cs->base + OFFSET_DATA; - chip->legacy.IO_ADDR_W = cs->base + OFFSET_DATA; - chip->legacy.chip_delay = RB_DELAY_US; - chip->options = NAND_NO_SUBPAGE_WRITE; - chip->legacy.select_chip = jz4780_nand_select_chip; - chip->legacy.cmd_ctrl = jz4780_nand_cmd_ctrl; - chip->ecc.mode = NAND_ECC_HW; - chip->controller = &nfc->controller; - nand_set_flash_node(chip, np); - - chip->controller->ops = &jz4780_nand_controller_ops; - ret = nand_scan(chip, 1); - if (ret) - return ret; - - ret = mtd_device_register(mtd, NULL, 0); - if (ret) { - nand_release(chip); - return ret; - } - - list_add_tail(&nand->chip_list, &nfc->chips); - - return 0; -} - -static void jz4780_nand_cleanup_chips(struct jz4780_nand_controller *nfc) -{ - struct jz4780_nand_chip *chip; - - while (!list_empty(&nfc->chips)) { - chip = list_first_entry(&nfc->chips, struct jz4780_nand_chip, chip_list); - nand_release(&chip->chip); - list_del(&chip->chip_list); - } -} - -static int jz4780_nand_init_chips(struct jz4780_nand_controller *nfc, - struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct device_node *np; - int i = 0; - int ret; - int num_chips = of_get_child_count(dev->of_node); - - if (num_chips > nfc->num_banks) { - dev_err(dev, "found %d chips but only %d banks\n", num_chips, nfc->num_banks); - return -EINVAL; - } - - for_each_child_of_node(dev->of_node, np) { - ret = jz4780_nand_init_chip(pdev, nfc, np, i); - if (ret) { - jz4780_nand_cleanup_chips(nfc); - return ret; - } - - i++; - } - - return 0; -} - -static int jz4780_nand_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - unsigned int num_banks; - struct jz4780_nand_controller *nfc; - int ret; - - num_banks = jz4780_nemc_num_banks(dev); - if (num_banks == 0) { - dev_err(dev, "no banks found\n"); - return -ENODEV; - } - - nfc = devm_kzalloc(dev, struct_size(nfc, cs, num_banks), GFP_KERNEL); - if (!nfc) - return -ENOMEM; - - /* - * Check for BCH HW before we call nand_scan_ident, to prevent us from - * having to call it again if the BCH driver returns -EPROBE_DEFER. - */ - nfc->bch = of_jz4780_bch_get(dev->of_node); - if (IS_ERR(nfc->bch)) - return PTR_ERR(nfc->bch); - - nfc->dev = dev; - nfc->num_banks = num_banks; - - nand_controller_init(&nfc->controller); - INIT_LIST_HEAD(&nfc->chips); - - ret = jz4780_nand_init_chips(nfc, pdev); - if (ret) { - if (nfc->bch) - jz4780_bch_release(nfc->bch); - return ret; - } - - platform_set_drvdata(pdev, nfc); - return 0; -} - -static int jz4780_nand_remove(struct platform_device *pdev) -{ - struct jz4780_nand_controller *nfc = platform_get_drvdata(pdev); - - if (nfc->bch) - jz4780_bch_release(nfc->bch); - - jz4780_nand_cleanup_chips(nfc); - - return 0; -} - -static const struct of_device_id jz4780_nand_dt_match[] = { - { .compatible = "ingenic,jz4780-nand" }, - {}, -}; -MODULE_DEVICE_TABLE(of, jz4780_nand_dt_match); - -static struct platform_driver jz4780_nand_driver = { - .probe = jz4780_nand_probe, - .remove = jz4780_nand_remove, - .driver = { - .name = DRV_NAME, - .of_match_table = of_match_ptr(jz4780_nand_dt_match), - }, -}; -module_platform_driver(jz4780_nand_driver); - -MODULE_AUTHOR("Alex Smith "); -MODULE_AUTHOR("Harvey Hunt "); -MODULE_DESCRIPTION("Ingenic JZ4780 NAND driver"); -MODULE_LICENSE("GPL v2"); -- cgit From 65bba52d3250aadcc55ff189154befd23e4dba79 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Tue, 19 Mar 2019 15:53:55 +0100 Subject: mtd: rawnand: ingenic: Use SPDX license notifiers Use SPDX license notifiers instead of GPLv2 license text in the headers. Signed-off-by: Paul Cercueil Reviewed-by: Boris Brezillon Signed-off-by: Miquel Raynal --- drivers/mtd/nand/raw/ingenic/jz4780_bch.c | 5 +---- drivers/mtd/nand/raw/ingenic/jz4780_bch.h | 5 +---- drivers/mtd/nand/raw/ingenic/jz4780_nand.c | 5 +---- 3 files changed, 3 insertions(+), 12 deletions(-) diff --git a/drivers/mtd/nand/raw/ingenic/jz4780_bch.c b/drivers/mtd/nand/raw/ingenic/jz4780_bch.c index c5f74ed85862..fdf483a49f7b 100644 --- a/drivers/mtd/nand/raw/ingenic/jz4780_bch.c +++ b/drivers/mtd/nand/raw/ingenic/jz4780_bch.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* * JZ4780 BCH controller * * Copyright (c) 2015 Imagination Technologies * Author: Alex Smith - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. */ #include diff --git a/drivers/mtd/nand/raw/ingenic/jz4780_bch.h b/drivers/mtd/nand/raw/ingenic/jz4780_bch.h index bf4718088a3a..451e0c770160 100644 --- a/drivers/mtd/nand/raw/ingenic/jz4780_bch.h +++ b/drivers/mtd/nand/raw/ingenic/jz4780_bch.h @@ -1,12 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * JZ4780 BCH controller * * Copyright (c) 2015 Imagination Technologies * Author: Alex Smith - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. */ #ifndef __DRIVERS_MTD_NAND_JZ4780_BCH_H__ diff --git a/drivers/mtd/nand/raw/ingenic/jz4780_nand.c b/drivers/mtd/nand/raw/ingenic/jz4780_nand.c index 22e58975f0d5..7f55358b860f 100644 --- a/drivers/mtd/nand/raw/ingenic/jz4780_nand.c +++ b/drivers/mtd/nand/raw/ingenic/jz4780_nand.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* * JZ4780 NAND driver * * Copyright (c) 2015 Imagination Technologies * Author: Alex Smith - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. */ #include -- cgit From a919619e9a2530c5eaa011edc2a154d770daa2ad Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Tue, 19 Mar 2019 15:53:56 +0100 Subject: mtd: rawnand: ingenic: Rename jz4780_nand driver to ingenic_nand The jz4780_nand driver will be modified to handle all the Ingenic JZ47xx SoCs that the upstream Linux kernel supports (JZ4740, JZ4725B, JZ4770, JZ4780), so it makes sense to rename it. Signed-off-by: Paul Cercueil Signed-off-by: Miquel Raynal --- drivers/mtd/nand/raw/ingenic/Makefile | 2 +- drivers/mtd/nand/raw/ingenic/ingenic_nand.c | 412 ++++++++++++++++++++++++++++ drivers/mtd/nand/raw/ingenic/jz4780_nand.c | 412 ---------------------------- 3 files changed, 413 insertions(+), 413 deletions(-) create mode 100644 drivers/mtd/nand/raw/ingenic/ingenic_nand.c delete mode 100644 drivers/mtd/nand/raw/ingenic/jz4780_nand.c diff --git a/drivers/mtd/nand/raw/ingenic/Makefile b/drivers/mtd/nand/raw/ingenic/Makefile index 44c2ca053d24..af2d5de21f60 100644 --- a/drivers/mtd/nand/raw/ingenic/Makefile +++ b/drivers/mtd/nand/raw/ingenic/Makefile @@ -1,2 +1,2 @@ obj-$(CONFIG_MTD_NAND_JZ4740) += jz4740_nand.o -obj-$(CONFIG_MTD_NAND_JZ4780) += jz4780_nand.o jz4780_bch.o +obj-$(CONFIG_MTD_NAND_JZ4780) += ingenic_nand.o jz4780_bch.o diff --git a/drivers/mtd/nand/raw/ingenic/ingenic_nand.c b/drivers/mtd/nand/raw/ingenic/ingenic_nand.c new file mode 100644 index 000000000000..8c73f7c5be9a --- /dev/null +++ b/drivers/mtd/nand/raw/ingenic/ingenic_nand.c @@ -0,0 +1,412 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Ingenic JZ47xx NAND driver + * + * Copyright (c) 2015 Imagination Technologies + * Author: Alex Smith + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "jz4780_bch.h" + +#define DRV_NAME "ingenic-nand" + +#define OFFSET_DATA 0x00000000 +#define OFFSET_CMD 0x00400000 +#define OFFSET_ADDR 0x00800000 + +/* Command delay when there is no R/B pin. */ +#define RB_DELAY_US 100 + +struct ingenic_nand_cs { + unsigned int bank; + void __iomem *base; +}; + +struct ingenic_nfc { + struct device *dev; + struct jz4780_bch *bch; + struct nand_controller controller; + unsigned int num_banks; + struct list_head chips; + int selected; + struct ingenic_nand_cs cs[]; +}; + +struct ingenic_nand { + struct nand_chip chip; + struct list_head chip_list; + + struct gpio_desc *busy_gpio; + struct gpio_desc *wp_gpio; + unsigned int reading: 1; +}; + +static inline struct ingenic_nand *to_ingenic_nand(struct mtd_info *mtd) +{ + return container_of(mtd_to_nand(mtd), struct ingenic_nand, chip); +} + +static inline struct ingenic_nfc *to_ingenic_nfc(struct nand_controller *ctrl) +{ + return container_of(ctrl, struct ingenic_nfc, controller); +} + +static void ingenic_nand_select_chip(struct nand_chip *chip, int chipnr) +{ + struct ingenic_nand *nand = to_ingenic_nand(nand_to_mtd(chip)); + struct ingenic_nfc *nfc = to_ingenic_nfc(nand->chip.controller); + struct ingenic_nand_cs *cs; + + /* Ensure the currently selected chip is deasserted. */ + if (chipnr == -1 && nfc->selected >= 0) { + cs = &nfc->cs[nfc->selected]; + jz4780_nemc_assert(nfc->dev, cs->bank, false); + } + + nfc->selected = chipnr; +} + +static void ingenic_nand_cmd_ctrl(struct nand_chip *chip, int cmd, + unsigned int ctrl) +{ + struct ingenic_nand *nand = to_ingenic_nand(nand_to_mtd(chip)); + struct ingenic_nfc *nfc = to_ingenic_nfc(nand->chip.controller); + struct ingenic_nand_cs *cs; + + if (WARN_ON(nfc->selected < 0)) + return; + + cs = &nfc->cs[nfc->selected]; + + jz4780_nemc_assert(nfc->dev, cs->bank, ctrl & NAND_NCE); + + if (cmd == NAND_CMD_NONE) + return; + + if (ctrl & NAND_ALE) + writeb(cmd, cs->base + OFFSET_ADDR); + else if (ctrl & NAND_CLE) + writeb(cmd, cs->base + OFFSET_CMD); +} + +static int ingenic_nand_dev_ready(struct nand_chip *chip) +{ + struct ingenic_nand *nand = to_ingenic_nand(nand_to_mtd(chip)); + + return !gpiod_get_value_cansleep(nand->busy_gpio); +} + +static void ingenic_nand_ecc_hwctl(struct nand_chip *chip, int mode) +{ + struct ingenic_nand *nand = to_ingenic_nand(nand_to_mtd(chip)); + + nand->reading = (mode == NAND_ECC_READ); +} + +static int ingenic_nand_ecc_calculate(struct nand_chip *chip, const u8 *dat, + u8 *ecc_code) +{ + struct ingenic_nand *nand = to_ingenic_nand(nand_to_mtd(chip)); + struct ingenic_nfc *nfc = to_ingenic_nfc(nand->chip.controller); + struct jz4780_bch_params params; + + /* + * Don't need to generate the ECC when reading, BCH does it for us as + * part of decoding/correction. + */ + if (nand->reading) + return 0; + + params.size = nand->chip.ecc.size; + params.bytes = nand->chip.ecc.bytes; + params.strength = nand->chip.ecc.strength; + + return jz4780_bch_calculate(nfc->bch, ¶ms, dat, ecc_code); +} + +static int ingenic_nand_ecc_correct(struct nand_chip *chip, u8 *dat, + u8 *read_ecc, u8 *calc_ecc) +{ + struct ingenic_nand *nand = to_ingenic_nand(nand_to_mtd(chip)); + struct ingenic_nfc *nfc = to_ingenic_nfc(nand->chip.controller); + struct jz4780_bch_params params; + + params.size = nand->chip.ecc.size; + params.bytes = nand->chip.ecc.bytes; + params.strength = nand->chip.ecc.strength; + + return jz4780_bch_correct(nfc->bch, ¶ms, dat, read_ecc); +} + +static int ingenic_nand_attach_chip(struct nand_chip *chip) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + struct ingenic_nfc *nfc = to_ingenic_nfc(chip->controller); + int eccbytes; + + chip->ecc.bytes = fls((1 + 8) * chip->ecc.size) * + (chip->ecc.strength / 8); + + switch (chip->ecc.mode) { + case NAND_ECC_HW: + if (!nfc->bch) { + dev_err(nfc->dev, "HW BCH selected, but BCH controller not found\n"); + return -ENODEV; + } + + chip->ecc.hwctl = ingenic_nand_ecc_hwctl; + chip->ecc.calculate = ingenic_nand_ecc_calculate; + chip->ecc.correct = ingenic_nand_ecc_correct; + /* fall through */ + case NAND_ECC_SOFT: + dev_info(nfc->dev, "using %s (strength %d, size %d, bytes %d)\n", + (nfc->bch) ? "hardware BCH" : "software ECC", + chip->ecc.strength, chip->ecc.size, chip->ecc.bytes); + break; + case NAND_ECC_NONE: + dev_info(nfc->dev, "not using ECC\n"); + break; + default: + dev_err(nfc->dev, "ECC mode %d not supported\n", + chip->ecc.mode); + return -EINVAL; + } + + /* The NAND core will generate the ECC layout for SW ECC */ + if (chip->ecc.mode != NAND_ECC_HW) + return 0; + + /* Generate ECC layout. ECC codes are right aligned in the OOB area. */ + eccbytes = mtd->writesize / chip->ecc.size * chip->ecc.bytes; + + if (eccbytes > mtd->oobsize - 2) { + dev_err(nfc->dev, + "invalid ECC config: required %d ECC bytes, but only %d are available", + eccbytes, mtd->oobsize - 2); + return -EINVAL; + } + + mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops); + + return 0; +} + +static const struct nand_controller_ops ingenic_nand_controller_ops = { + .attach_chip = ingenic_nand_attach_chip, +}; + +static int ingenic_nand_init_chip(struct platform_device *pdev, + struct ingenic_nfc *nfc, + struct device_node *np, + unsigned int chipnr) +{ + struct device *dev = &pdev->dev; + struct ingenic_nand *nand; + struct ingenic_nand_cs *cs; + struct resource *res; + struct nand_chip *chip; + struct mtd_info *mtd; + const __be32 *reg; + int ret = 0; + + cs = &nfc->cs[chipnr]; + + reg = of_get_property(np, "reg", NULL); + if (!reg) + return -EINVAL; + + cs->bank = be32_to_cpu(*reg); + + jz4780_nemc_set_type(nfc->dev, cs->bank, JZ4780_NEMC_BANK_NAND); + + res = platform_get_resource(pdev, IORESOURCE_MEM, chipnr); + cs->base = devm_ioremap_resource(dev, res); + if (IS_ERR(cs->base)) + return PTR_ERR(cs->base); + + nand = devm_kzalloc(dev, sizeof(*nand), GFP_KERNEL); + if (!nand) + return -ENOMEM; + + nand->busy_gpio = devm_gpiod_get_optional(dev, "rb", GPIOD_IN); + + if (IS_ERR(nand->busy_gpio)) { + ret = PTR_ERR(nand->busy_gpio); + dev_err(dev, "failed to request busy GPIO: %d\n", ret); + return ret; + } else if (nand->busy_gpio) { + nand->chip.legacy.dev_ready = ingenic_nand_dev_ready; + } + + nand->wp_gpio = devm_gpiod_get_optional(dev, "wp", GPIOD_OUT_LOW); + + if (IS_ERR(nand->wp_gpio)) { + ret = PTR_ERR(nand->wp_gpio); + dev_err(dev, "failed to request WP GPIO: %d\n", ret); + return ret; + } + + chip = &nand->chip; + mtd = nand_to_mtd(chip); + mtd->name = devm_kasprintf(dev, GFP_KERNEL, "%s.%d", dev_name(dev), + cs->bank); + if (!mtd->name) + return -ENOMEM; + mtd->dev.parent = dev; + + chip->legacy.IO_ADDR_R = cs->base + OFFSET_DATA; + chip->legacy.IO_ADDR_W = cs->base + OFFSET_DATA; + chip->legacy.chip_delay = RB_DELAY_US; + chip->options = NAND_NO_SUBPAGE_WRITE; + chip->legacy.select_chip = ingenic_nand_select_chip; + chip->legacy.cmd_ctrl = ingenic_nand_cmd_ctrl; + chip->ecc.mode = NAND_ECC_HW; + chip->controller = &nfc->controller; + nand_set_flash_node(chip, np); + + chip->controller->ops = &ingenic_nand_controller_ops; + ret = nand_scan(chip, 1); + if (ret) + return ret; + + ret = mtd_device_register(mtd, NULL, 0); + if (ret) { + nand_release(chip); + return ret; + } + + list_add_tail(&nand->chip_list, &nfc->chips); + + return 0; +} + +static void ingenic_nand_cleanup_chips(struct ingenic_nfc *nfc) +{ + struct ingenic_nand *chip; + + while (!list_empty(&nfc->chips)) { + chip = list_first_entry(&nfc->chips, + struct ingenic_nand, chip_list); + nand_release(&chip->chip); + list_del(&chip->chip_list); + } +} + +static int ingenic_nand_init_chips(struct ingenic_nfc *nfc, + struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np; + int i = 0; + int ret; + int num_chips = of_get_child_count(dev->of_node); + + if (num_chips > nfc->num_banks) { + dev_err(dev, "found %d chips but only %d banks\n", + num_chips, nfc->num_banks); + return -EINVAL; + } + + for_each_child_of_node(dev->of_node, np) { + ret = ingenic_nand_init_chip(pdev, nfc, np, i); + if (ret) { + ingenic_nand_cleanup_chips(nfc); + return ret; + } + + i++; + } + + return 0; +} + +static int ingenic_nand_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + unsigned int num_banks; + struct ingenic_nfc *nfc; + int ret; + + num_banks = jz4780_nemc_num_banks(dev); + if (num_banks == 0) { + dev_err(dev, "no banks found\n"); + return -ENODEV; + } + + nfc = devm_kzalloc(dev, struct_size(nfc, cs, num_banks), GFP_KERNEL); + if (!nfc) + return -ENOMEM; + + /* + * Check for BCH HW before we call nand_scan_ident, to prevent us from + * having to call it again if the BCH driver returns -EPROBE_DEFER. + */ + nfc->bch = of_jz4780_bch_get(dev->of_node); + if (IS_ERR(nfc->bch)) + return PTR_ERR(nfc->bch); + + nfc->dev = dev; + nfc->num_banks = num_banks; + + nand_controller_init(&nfc->controller); + INIT_LIST_HEAD(&nfc->chips); + + ret = ingenic_nand_init_chips(nfc, pdev); + if (ret) { + if (nfc->bch) + jz4780_bch_release(nfc->bch); + return ret; + } + + platform_set_drvdata(pdev, nfc); + return 0; +} + +static int ingenic_nand_remove(struct platform_device *pdev) +{ + struct ingenic_nfc *nfc = platform_get_drvdata(pdev); + + if (nfc->bch) + jz4780_bch_release(nfc->bch); + + ingenic_nand_cleanup_chips(nfc); + + return 0; +} + +static const struct of_device_id ingenic_nand_dt_match[] = { + { .compatible = "ingenic,jz4780-nand" }, + {}, +}; +MODULE_DEVICE_TABLE(of, ingenic_nand_dt_match); + +static struct platform_driver ingenic_nand_driver = { + .probe = ingenic_nand_probe, + .remove = ingenic_nand_remove, + .driver = { + .name = DRV_NAME, + .of_match_table = of_match_ptr(ingenic_nand_dt_match), + }, +}; +module_platform_driver(ingenic_nand_driver); + +MODULE_AUTHOR("Alex Smith "); +MODULE_AUTHOR("Harvey Hunt "); +MODULE_DESCRIPTION("Ingenic JZ47xx NAND driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/mtd/nand/raw/ingenic/jz4780_nand.c b/drivers/mtd/nand/raw/ingenic/jz4780_nand.c deleted file mode 100644 index 7f55358b860f..000000000000 --- a/drivers/mtd/nand/raw/ingenic/jz4780_nand.c +++ /dev/null @@ -1,412 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * JZ4780 NAND driver - * - * Copyright (c) 2015 Imagination Technologies - * Author: Alex Smith - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "jz4780_bch.h" - -#define DRV_NAME "jz4780-nand" - -#define OFFSET_DATA 0x00000000 -#define OFFSET_CMD 0x00400000 -#define OFFSET_ADDR 0x00800000 - -/* Command delay when there is no R/B pin. */ -#define RB_DELAY_US 100 - -struct jz4780_nand_cs { - unsigned int bank; - void __iomem *base; -}; - -struct jz4780_nand_controller { - struct device *dev; - struct jz4780_bch *bch; - struct nand_controller controller; - unsigned int num_banks; - struct list_head chips; - int selected; - struct jz4780_nand_cs cs[]; -}; - -struct jz4780_nand_chip { - struct nand_chip chip; - struct list_head chip_list; - - struct gpio_desc *busy_gpio; - struct gpio_desc *wp_gpio; - unsigned int reading: 1; -}; - -static inline struct jz4780_nand_chip *to_jz4780_nand_chip(struct mtd_info *mtd) -{ - return container_of(mtd_to_nand(mtd), struct jz4780_nand_chip, chip); -} - -static inline struct jz4780_nand_controller -*to_jz4780_nand_controller(struct nand_controller *ctrl) -{ - return container_of(ctrl, struct jz4780_nand_controller, controller); -} - -static void jz4780_nand_select_chip(struct nand_chip *chip, int chipnr) -{ - struct jz4780_nand_chip *nand = to_jz4780_nand_chip(nand_to_mtd(chip)); - struct jz4780_nand_controller *nfc = to_jz4780_nand_controller(nand->chip.controller); - struct jz4780_nand_cs *cs; - - /* Ensure the currently selected chip is deasserted. */ - if (chipnr == -1 && nfc->selected >= 0) { - cs = &nfc->cs[nfc->selected]; - jz4780_nemc_assert(nfc->dev, cs->bank, false); - } - - nfc->selected = chipnr; -} - -static void jz4780_nand_cmd_ctrl(struct nand_chip *chip, int cmd, - unsigned int ctrl) -{ - struct jz4780_nand_chip *nand = to_jz4780_nand_chip(nand_to_mtd(chip)); - struct jz4780_nand_controller *nfc = to_jz4780_nand_controller(nand->chip.controller); - struct jz4780_nand_cs *cs; - - if (WARN_ON(nfc->selected < 0)) - return; - - cs = &nfc->cs[nfc->selected]; - - jz4780_nemc_assert(nfc->dev, cs->bank, ctrl & NAND_NCE); - - if (cmd == NAND_CMD_NONE) - return; - - if (ctrl & NAND_ALE) - writeb(cmd, cs->base + OFFSET_ADDR); - else if (ctrl & NAND_CLE) - writeb(cmd, cs->base + OFFSET_CMD); -} - -static int jz4780_nand_dev_ready(struct nand_chip *chip) -{ - struct jz4780_nand_chip *nand = to_jz4780_nand_chip(nand_to_mtd(chip)); - - return !gpiod_get_value_cansleep(nand->busy_gpio); -} - -static void jz4780_nand_ecc_hwctl(struct nand_chip *chip, int mode) -{ - struct jz4780_nand_chip *nand = to_jz4780_nand_chip(nand_to_mtd(chip)); - - nand->reading = (mode == NAND_ECC_READ); -} - -static int jz4780_nand_ecc_calculate(struct nand_chip *chip, const u8 *dat, - u8 *ecc_code) -{ - struct jz4780_nand_chip *nand = to_jz4780_nand_chip(nand_to_mtd(chip)); - struct jz4780_nand_controller *nfc = to_jz4780_nand_controller(nand->chip.controller); - struct jz4780_bch_params params; - - /* - * Don't need to generate the ECC when reading, BCH does it for us as - * part of decoding/correction. - */ - if (nand->reading) - return 0; - - params.size = nand->chip.ecc.size; - params.bytes = nand->chip.ecc.bytes; - params.strength = nand->chip.ecc.strength; - - return jz4780_bch_calculate(nfc->bch, ¶ms, dat, ecc_code); -} - -static int jz4780_nand_ecc_correct(struct nand_chip *chip, u8 *dat, - u8 *read_ecc, u8 *calc_ecc) -{ - struct jz4780_nand_chip *nand = to_jz4780_nand_chip(nand_to_mtd(chip)); - struct jz4780_nand_controller *nfc = to_jz4780_nand_controller(nand->chip.controller); - struct jz4780_bch_params params; - - params.size = nand->chip.ecc.size; - params.bytes = nand->chip.ecc.bytes; - params.strength = nand->chip.ecc.strength; - - return jz4780_bch_correct(nfc->bch, ¶ms, dat, read_ecc); -} - -static int jz4780_nand_attach_chip(struct nand_chip *chip) -{ - struct mtd_info *mtd = nand_to_mtd(chip); - struct jz4780_nand_controller *nfc = to_jz4780_nand_controller(chip->controller); - int eccbytes; - - chip->ecc.bytes = fls((1 + 8) * chip->ecc.size) * - (chip->ecc.strength / 8); - - switch (chip->ecc.mode) { - case NAND_ECC_HW: - if (!nfc->bch) { - dev_err(nfc->dev, - "HW BCH selected, but BCH controller not found\n"); - return -ENODEV; - } - - chip->ecc.hwctl = jz4780_nand_ecc_hwctl; - chip->ecc.calculate = jz4780_nand_ecc_calculate; - chip->ecc.correct = jz4780_nand_ecc_correct; - /* fall through */ - case NAND_ECC_SOFT: - dev_info(nfc->dev, "using %s (strength %d, size %d, bytes %d)\n", - (nfc->bch) ? "hardware BCH" : "software ECC", - chip->ecc.strength, chip->ecc.size, chip->ecc.bytes); - break; - case NAND_ECC_NONE: - dev_info(nfc->dev, "not using ECC\n"); - break; - default: - dev_err(nfc->dev, "ECC mode %d not supported\n", - chip->ecc.mode); - return -EINVAL; - } - - /* The NAND core will generate the ECC layout for SW ECC */ - if (chip->ecc.mode != NAND_ECC_HW) - return 0; - - /* Generate ECC layout. ECC codes are right aligned in the OOB area. */ - eccbytes = mtd->writesize / chip->ecc.size * chip->ecc.bytes; - - if (eccbytes > mtd->oobsize - 2) { - dev_err(nfc->dev, - "invalid ECC config: required %d ECC bytes, but only %d are available", - eccbytes, mtd->oobsize - 2); - return -EINVAL; - } - - mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops); - - return 0; -} - -static const struct nand_controller_ops jz4780_nand_controller_ops = { - .attach_chip = jz4780_nand_attach_chip, -}; - -static int jz4780_nand_init_chip(struct platform_device *pdev, - struct jz4780_nand_controller *nfc, - struct device_node *np, - unsigned int chipnr) -{ - struct device *dev = &pdev->dev; - struct jz4780_nand_chip *nand; - struct jz4780_nand_cs *cs; - struct resource *res; - struct nand_chip *chip; - struct mtd_info *mtd; - const __be32 *reg; - int ret = 0; - - cs = &nfc->cs[chipnr]; - - reg = of_get_property(np, "reg", NULL); - if (!reg) - return -EINVAL; - - cs->bank = be32_to_cpu(*reg); - - jz4780_nemc_set_type(nfc->dev, cs->bank, JZ4780_NEMC_BANK_NAND); - - res = platform_get_resource(pdev, IORESOURCE_MEM, chipnr); - cs->base = devm_ioremap_resource(dev, res); - if (IS_ERR(cs->base)) - return PTR_ERR(cs->base); - - nand = devm_kzalloc(dev, sizeof(*nand), GFP_KERNEL); - if (!nand) - return -ENOMEM; - - nand->busy_gpio = devm_gpiod_get_optional(dev, "rb", GPIOD_IN); - - if (IS_ERR(nand->busy_gpio)) { - ret = PTR_ERR(nand->busy_gpio); - dev_err(dev, "failed to request busy GPIO: %d\n", ret); - return ret; - } else if (nand->busy_gpio) { - nand->chip.legacy.dev_ready = jz4780_nand_dev_ready; - } - - nand->wp_gpio = devm_gpiod_get_optional(dev, "wp", GPIOD_OUT_LOW); - - if (IS_ERR(nand->wp_gpio)) { - ret = PTR_ERR(nand->wp_gpio); - dev_err(dev, "failed to request WP GPIO: %d\n", ret); - return ret; - } - - chip = &nand->chip; - mtd = nand_to_mtd(chip); - mtd->name = devm_kasprintf(dev, GFP_KERNEL, "%s.%d", dev_name(dev), - cs->bank); - if (!mtd->name) - return -ENOMEM; - mtd->dev.parent = dev; - - chip->legacy.IO_ADDR_R = cs->base + OFFSET_DATA; - chip->legacy.IO_ADDR_W = cs->base + OFFSET_DATA; - chip->legacy.chip_delay = RB_DELAY_US; - chip->options = NAND_NO_SUBPAGE_WRITE; - chip->legacy.select_chip = jz4780_nand_select_chip; - chip->legacy.cmd_ctrl = jz4780_nand_cmd_ctrl; - chip->ecc.mode = NAND_ECC_HW; - chip->controller = &nfc->controller; - nand_set_flash_node(chip, np); - - chip->controller->ops = &jz4780_nand_controller_ops; - ret = nand_scan(chip, 1); - if (ret) - return ret; - - ret = mtd_device_register(mtd, NULL, 0); - if (ret) { - nand_release(chip); - return ret; - } - - list_add_tail(&nand->chip_list, &nfc->chips); - - return 0; -} - -static void jz4780_nand_cleanup_chips(struct jz4780_nand_controller *nfc) -{ - struct jz4780_nand_chip *chip; - - while (!list_empty(&nfc->chips)) { - chip = list_first_entry(&nfc->chips, struct jz4780_nand_chip, chip_list); - nand_release(&chip->chip); - list_del(&chip->chip_list); - } -} - -static int jz4780_nand_init_chips(struct jz4780_nand_controller *nfc, - struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct device_node *np; - int i = 0; - int ret; - int num_chips = of_get_child_count(dev->of_node); - - if (num_chips > nfc->num_banks) { - dev_err(dev, "found %d chips but only %d banks\n", num_chips, nfc->num_banks); - return -EINVAL; - } - - for_each_child_of_node(dev->of_node, np) { - ret = jz4780_nand_init_chip(pdev, nfc, np, i); - if (ret) { - jz4780_nand_cleanup_chips(nfc); - return ret; - } - - i++; - } - - return 0; -} - -static int jz4780_nand_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - unsigned int num_banks; - struct jz4780_nand_controller *nfc; - int ret; - - num_banks = jz4780_nemc_num_banks(dev); - if (num_banks == 0) { - dev_err(dev, "no banks found\n"); - return -ENODEV; - } - - nfc = devm_kzalloc(dev, struct_size(nfc, cs, num_banks), GFP_KERNEL); - if (!nfc) - return -ENOMEM; - - /* - * Check for BCH HW before we call nand_scan_ident, to prevent us from - * having to call it again if the BCH driver returns -EPROBE_DEFER. - */ - nfc->bch = of_jz4780_bch_get(dev->of_node); - if (IS_ERR(nfc->bch)) - return PTR_ERR(nfc->bch); - - nfc->dev = dev; - nfc->num_banks = num_banks; - - nand_controller_init(&nfc->controller); - INIT_LIST_HEAD(&nfc->chips); - - ret = jz4780_nand_init_chips(nfc, pdev); - if (ret) { - if (nfc->bch) - jz4780_bch_release(nfc->bch); - return ret; - } - - platform_set_drvdata(pdev, nfc); - return 0; -} - -static int jz4780_nand_remove(struct platform_device *pdev) -{ - struct jz4780_nand_controller *nfc = platform_get_drvdata(pdev); - - if (nfc->bch) - jz4780_bch_release(nfc->bch); - - jz4780_nand_cleanup_chips(nfc); - - return 0; -} - -static const struct of_device_id jz4780_nand_dt_match[] = { - { .compatible = "ingenic,jz4780-nand" }, - {}, -}; -MODULE_DEVICE_TABLE(of, jz4780_nand_dt_match); - -static struct platform_driver jz4780_nand_driver = { - .probe = jz4780_nand_probe, - .remove = jz4780_nand_remove, - .driver = { - .name = DRV_NAME, - .of_match_table = of_match_ptr(jz4780_nand_dt_match), - }, -}; -module_platform_driver(jz4780_nand_driver); - -MODULE_AUTHOR("Alex Smith "); -MODULE_AUTHOR("Harvey Hunt "); -MODULE_DESCRIPTION("Ingenic JZ4780 NAND driver"); -MODULE_LICENSE("GPL v2"); -- cgit From d74fd06f44108832c7d879419fe8de976519e522 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Tue, 19 Mar 2019 15:53:57 +0100 Subject: mtd: rawnand: ingenic: Rename jz4780_bch_init to jz4780_bch_reset The jz4780_bch_init name was confusing, as it suggested that its content should be executed once at init time, whereas what the function really does is reset the hardware for a new ECC operation. Signed-off-by: Paul Cercueil Signed-off-by: Miquel Raynal --- drivers/mtd/nand/raw/ingenic/jz4780_bch.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/mtd/nand/raw/ingenic/jz4780_bch.c b/drivers/mtd/nand/raw/ingenic/jz4780_bch.c index fdf483a49f7b..7635753bd7ea 100644 --- a/drivers/mtd/nand/raw/ingenic/jz4780_bch.c +++ b/drivers/mtd/nand/raw/ingenic/jz4780_bch.c @@ -69,8 +69,8 @@ struct jz4780_bch { struct mutex lock; }; -static void jz4780_bch_init(struct jz4780_bch *bch, - struct jz4780_bch_params *params, bool encode) +static void jz4780_bch_reset(struct jz4780_bch *bch, + struct jz4780_bch_params *params, bool encode) { u32 reg; @@ -183,7 +183,8 @@ int jz4780_bch_calculate(struct jz4780_bch *bch, struct jz4780_bch_params *param int ret = 0; mutex_lock(&bch->lock); - jz4780_bch_init(bch, params, true); + + jz4780_bch_reset(bch, params, true); jz4780_bch_write_data(bch, buf, params->size); if (jz4780_bch_wait_complete(bch, BCH_BHINT_ENCF, NULL)) { @@ -220,7 +221,7 @@ int jz4780_bch_correct(struct jz4780_bch *bch, struct jz4780_bch_params *params, mutex_lock(&bch->lock); - jz4780_bch_init(bch, params, false); + jz4780_bch_reset(bch, params, false); jz4780_bch_write_data(bch, buf, params->size); jz4780_bch_write_data(bch, ecc_code, params->bytes); -- cgit From 3ddc8adbbc76832e96b8500ff50f4b20b9060128 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 12 Mar 2019 11:45:49 +0100 Subject: mtd: spi-nor: Print all JEDEC ID bytes on error If identification of an SPI NOR FLASH fails, the JEDEC ID is printed, which is stored in the first 3 bytes of the ID read from the FLASH. However, the extended JEDEC ID, which is stored in the remaining bytes, also matters, as it is used for identification of some FLASH types. Print all (currently 6) ID bytes read to ease failure analysis and debugging. Suggested-by: Tudor Ambarus Signed-off-by: Geert Uytterhoeven Reviewed-by: Tudor Ambarus Signed-off-by: Miquel Raynal --- drivers/mtd/spi-nor/spi-nor.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index fae147452aff..028b21abee0d 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -2071,8 +2071,8 @@ static const struct flash_info *spi_nor_read_id(struct spi_nor *nor) return &spi_nor_ids[tmp]; } } - dev_err(nor->dev, "unrecognized JEDEC id bytes: %02x, %02x, %02x\n", - id[0], id[1], id[2]); + dev_err(nor->dev, "unrecognized JEDEC id bytes: %*ph\n", + SPI_NOR_MAX_ID_LEN, id); return ERR_PTR(-ENODEV); } -- cgit From 706707341bef5b076e7c271a2dab7e6cd6af7902 Mon Sep 17 00:00:00 2001 From: Alexander Sverdlin Date: Tue, 19 Mar 2019 16:57:13 +0000 Subject: mtd: spi-nor: Fix comment of spi_nor_find_best_erase_type() Erase types are sorted *smallest* type first, refer to spi_nor_sort_erase_mask(). Signed-off-by: Alexander Sverdlin Reviewed-by: Tudor Ambarus Signed-off-by: Miquel Raynal --- drivers/mtd/spi-nor/spi-nor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index 028b21abee0d..cbb0965f85ca 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -744,7 +744,7 @@ spi_nor_find_best_erase_type(const struct spi_nor_erase_map *map, u8 erase_mask = region->offset & SNOR_ERASE_TYPE_MASK; /* - * Erase types are ordered by size, with the biggest erase type at + * Erase types are ordered by size, with the smallest erase type at * index 0. */ for (i = SNOR_ERASE_TYPE_MAX - 1; i >= 0; i--) { -- cgit From 2b75ebeea6f4937d4d05ec4982c471cef9a29b7f Mon Sep 17 00:00:00 2001 From: Alexander Sverdlin Date: Tue, 19 Mar 2019 17:18:07 +0000 Subject: mtd: spi-nor: intel-spi: Avoid crossing 4K address boundary on read/write It was observed that reads crossing 4K address boundary are failing. This limitation is mentioned in Intel documents: Intel(R) 9 Series Chipset Family Platform Controller Hub (PCH) Datasheet: "5.26.3 Flash Access Program Register Access: * Program Register Accesses are not allowed to cross a 4 KB boundary..." Enhanced Serial Peripheral Interface (eSPI) Interface Base Specification (for Client and Server Platforms): "5.1.4 Address For other memory transactions, the address may start or end at any byte boundary. However, the address and payload length combination must not cross the naturally aligned address boundary of the corresponding Maximum Payload Size. It must not cross a 4 KB address boundary." Avoid this by splitting an operation crossing the boundary into two operations. Fixes: 8afda8b26d01 ("spi-nor: Add support for Intel SPI serial flash controller") Cc: stable@vger.kernel.org Reported-by: Romain Porte Tested-by: Pascal Fabreges Signed-off-by: Alexander Sverdlin Reviewed-by: Tudor Ambarus Acked-by: Mika Westerberg Signed-off-by: Miquel Raynal --- drivers/mtd/spi-nor/intel-spi.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/mtd/spi-nor/intel-spi.c b/drivers/mtd/spi-nor/intel-spi.c index af0a22019516..d60cbf23d9aa 100644 --- a/drivers/mtd/spi-nor/intel-spi.c +++ b/drivers/mtd/spi-nor/intel-spi.c @@ -632,6 +632,10 @@ static ssize_t intel_spi_read(struct spi_nor *nor, loff_t from, size_t len, while (len > 0) { block_size = min_t(size_t, len, INTEL_SPI_FIFO_SZ); + /* Read cannot cross 4K boundary */ + block_size = min_t(loff_t, from + block_size, + round_up(from + 1, SZ_4K)) - from; + writel(from, ispi->base + FADDR); val = readl(ispi->base + HSFSTS_CTL); @@ -685,6 +689,10 @@ static ssize_t intel_spi_write(struct spi_nor *nor, loff_t to, size_t len, while (len > 0) { block_size = min_t(size_t, len, INTEL_SPI_FIFO_SZ); + /* Write cannot cross 4K boundary */ + block_size = min_t(loff_t, to + block_size, + round_up(to + 1, SZ_4K)) - to; + writel(to, ispi->base + FADDR); val = readl(ispi->base + HSFSTS_CTL); -- cgit From dcb4b22eeaf44f9122721ffc2b14d84363871454 Mon Sep 17 00:00:00 2001 From: Jonas Bonn Date: Wed, 20 Mar 2019 08:16:04 +0100 Subject: spi-nor: s25fl512s supports region locking Both the BP[0-2] bits and the TBPROT bit are supported on this chip. Tested and verified on a Cypress s25fl512s. Signed-off-by: Jonas Bonn Reviewed-by: Tudor Ambarus Signed-off-by: Miquel Raynal --- drivers/mtd/spi-nor/spi-nor.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index cbb0965f85ca..73172d7f512b 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -1905,7 +1905,9 @@ static const struct flash_info spi_nor_ids[] = { SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) }, { "s25fl256s0", INFO(0x010219, 0x4d00, 256 * 1024, 128, USE_CLSR) }, { "s25fl256s1", INFO(0x010219, 0x4d01, 64 * 1024, 512, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) }, - { "s25fl512s", INFO6(0x010220, 0x4d0080, 256 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) }, + { "s25fl512s", INFO6(0x010220, 0x4d0080, 256 * 1024, 256, + SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | + SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | USE_CLSR) }, { "s25fs512s", INFO6(0x010220, 0x4d0081, 256 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) }, { "s70fl01gs", INFO(0x010221, 0x4d00, 256 * 1024, 256, 0) }, { "s25sl12800", INFO(0x012018, 0x0300, 256 * 1024, 64, 0) }, -- cgit From 15de8c6efd0effef3a5226bd5ab7f101c9f4948f Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Tue, 19 Mar 2019 15:53:58 +0100 Subject: mtd: rawnand: ingenic: Separate top-level and SoC specific code The ingenic-nand driver uses an API provided by the jz4780-bch driver. This makes it difficult to support other SoCs in the jz4780-bch driver. To work around this, we separate the API functions from the SoC-specific code, so that these API functions are SoC-agnostic. Signed-off-by: Paul Cercueil Signed-off-by: Miquel Raynal --- drivers/mtd/nand/raw/ingenic/Kconfig | 17 +++ drivers/mtd/nand/raw/ingenic/Makefile | 5 +- drivers/mtd/nand/raw/ingenic/ingenic_ecc.c | 156 +++++++++++++++++++++++++ drivers/mtd/nand/raw/ingenic/ingenic_ecc.h | 83 ++++++++++++++ drivers/mtd/nand/raw/ingenic/ingenic_nand.c | 40 +++---- drivers/mtd/nand/raw/ingenic/jz4780_bch.c | 172 +++++----------------------- drivers/mtd/nand/raw/ingenic/jz4780_bch.h | 40 ------- 7 files changed, 310 insertions(+), 203 deletions(-) create mode 100644 drivers/mtd/nand/raw/ingenic/ingenic_ecc.c create mode 100644 drivers/mtd/nand/raw/ingenic/ingenic_ecc.h delete mode 100644 drivers/mtd/nand/raw/ingenic/jz4780_bch.h diff --git a/drivers/mtd/nand/raw/ingenic/Kconfig b/drivers/mtd/nand/raw/ingenic/Kconfig index 67806c87b2c4..4bf7d7af3b0a 100644 --- a/drivers/mtd/nand/raw/ingenic/Kconfig +++ b/drivers/mtd/nand/raw/ingenic/Kconfig @@ -11,3 +11,20 @@ config MTD_NAND_JZ4780 help Enables support for NAND Flash connected to the NEMC on JZ4780 SoC based boards, using the BCH controller for hardware error correction. + +if MTD_NAND_JZ4780 + +config MTD_NAND_INGENIC_ECC + tristate + +config MTD_NAND_JZ4780_BCH + tristate "Hardware BCH support for JZ4780 SoC" + select MTD_NAND_INGENIC_ECC + help + Enable this driver to support the BCH error-correction hardware + present on the JZ4780 SoC from Ingenic. + + This driver can also be built as a module. If so, the module + will be called jz4780-bch. + +endif # MTD_NAND_JZ4780 diff --git a/drivers/mtd/nand/raw/ingenic/Makefile b/drivers/mtd/nand/raw/ingenic/Makefile index af2d5de21f60..f3c3c0f230b0 100644 --- a/drivers/mtd/nand/raw/ingenic/Makefile +++ b/drivers/mtd/nand/raw/ingenic/Makefile @@ -1,2 +1,5 @@ obj-$(CONFIG_MTD_NAND_JZ4740) += jz4740_nand.o -obj-$(CONFIG_MTD_NAND_JZ4780) += ingenic_nand.o jz4780_bch.o +obj-$(CONFIG_MTD_NAND_JZ4780) += ingenic_nand.o + +obj-$(CONFIG_MTD_NAND_INGENIC_ECC) += ingenic_ecc.o +obj-$(CONFIG_MTD_NAND_JZ4780_BCH) += jz4780_bch.o diff --git a/drivers/mtd/nand/raw/ingenic/ingenic_ecc.c b/drivers/mtd/nand/raw/ingenic/ingenic_ecc.c new file mode 100644 index 000000000000..2aa71595a9e8 --- /dev/null +++ b/drivers/mtd/nand/raw/ingenic/ingenic_ecc.c @@ -0,0 +1,156 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * JZ47xx ECC common code + * + * Copyright (c) 2015 Imagination Technologies + * Author: Alex Smith + */ + +#include +#include +#include +#include +#include + +#include "ingenic_ecc.h" + +/** + * ingenic_ecc_calculate() - calculate ECC for a data buffer + * @ecc: ECC device. + * @params: ECC parameters. + * @buf: input buffer with raw data. + * @ecc_code: output buffer with ECC. + * + * Return: 0 on success, -ETIMEDOUT if timed out while waiting for ECC + * controller. + */ +int ingenic_ecc_calculate(struct ingenic_ecc *ecc, + struct ingenic_ecc_params *params, + const u8 *buf, u8 *ecc_code) +{ + return ecc->ops->calculate(ecc, params, buf, ecc_code); +} +EXPORT_SYMBOL(ingenic_ecc_calculate); + +/** + * ingenic_ecc_correct() - detect and correct bit errors + * @ecc: ECC device. + * @params: ECC parameters. + * @buf: raw data read from the chip. + * @ecc_code: ECC read from the chip. + * + * Given the raw data and the ECC read from the NAND device, detects and + * corrects errors in the data. + * + * Return: the number of bit errors corrected, -EBADMSG if there are too many + * errors to correct or -ETIMEDOUT if we timed out waiting for the controller. + */ +int ingenic_ecc_correct(struct ingenic_ecc *ecc, + struct ingenic_ecc_params *params, + u8 *buf, u8 *ecc_code) +{ + return ecc->ops->correct(ecc, params, buf, ecc_code); +} +EXPORT_SYMBOL(ingenic_ecc_correct); + +/** + * ingenic_ecc_get() - get the ECC controller device + * @np: ECC device tree node. + * + * Gets the ECC controller device from the specified device tree node. The + * device must be released with ingenic_ecc_release() when it is no longer being + * used. + * + * Return: a pointer to ingenic_ecc, errors are encoded into the pointer. + * PTR_ERR(-EPROBE_DEFER) if the device hasn't been initialised yet. + */ +static struct ingenic_ecc *ingenic_ecc_get(struct device_node *np) +{ + struct platform_device *pdev; + struct ingenic_ecc *ecc; + + pdev = of_find_device_by_node(np); + if (!pdev || !platform_get_drvdata(pdev)) + return ERR_PTR(-EPROBE_DEFER); + + get_device(&pdev->dev); + + ecc = platform_get_drvdata(pdev); + clk_prepare_enable(ecc->clk); + + return ecc; +} + +/** + * of_ingenic_ecc_get() - get the ECC controller from a DT node + * @of_node: the node that contains a bch-controller property. + * + * Get the bch-controller property from the given device tree + * node and pass it to ingenic_ecc_get to do the work. + * + * Return: a pointer to ingenic_ecc, errors are encoded into the pointer. + * PTR_ERR(-EPROBE_DEFER) if the device hasn't been initialised yet. + */ +struct ingenic_ecc *of_ingenic_ecc_get(struct device_node *of_node) +{ + struct ingenic_ecc *ecc = NULL; + struct device_node *np; + + np = of_parse_phandle(of_node, "ingenic,bch-controller", 0); + + if (np) { + ecc = ingenic_ecc_get(np); + of_node_put(np); + } + return ecc; +} +EXPORT_SYMBOL(of_ingenic_ecc_get); + +/** + * ingenic_ecc_release() - release the ECC controller device + * @ecc: ECC device. + */ +void ingenic_ecc_release(struct ingenic_ecc *ecc) +{ + clk_disable_unprepare(ecc->clk); + put_device(ecc->dev); +} +EXPORT_SYMBOL(ingenic_ecc_release); + +int ingenic_ecc_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct ingenic_ecc *ecc; + struct resource *res; + + ecc = devm_kzalloc(dev, sizeof(*ecc), GFP_KERNEL); + if (!ecc) + return -ENOMEM; + + ecc->ops = device_get_match_data(dev); + if (!ecc->ops) + return -EINVAL; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + ecc->base = devm_ioremap_resource(dev, res); + if (IS_ERR(ecc->base)) + return PTR_ERR(ecc->base); + + ecc->ops->disable(ecc); + + ecc->clk = devm_clk_get(dev, NULL); + if (IS_ERR(ecc->clk)) { + dev_err(dev, "failed to get clock: %ld\n", PTR_ERR(ecc->clk)); + return PTR_ERR(ecc->clk); + } + + mutex_init(&ecc->lock); + + ecc->dev = dev; + platform_set_drvdata(pdev, ecc); + + return 0; +} +EXPORT_SYMBOL(ingenic_ecc_probe); + +MODULE_LICENSE("GPL v2"); diff --git a/drivers/mtd/nand/raw/ingenic/ingenic_ecc.h b/drivers/mtd/nand/raw/ingenic/ingenic_ecc.h new file mode 100644 index 000000000000..2cda439b5e11 --- /dev/null +++ b/drivers/mtd/nand/raw/ingenic/ingenic_ecc.h @@ -0,0 +1,83 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __DRIVERS_MTD_NAND_INGENIC_ECC_INTERNAL_H__ +#define __DRIVERS_MTD_NAND_INGENIC_ECC_INTERNAL_H__ + +#include +#include +#include +#include +#include + +struct clk; +struct device; +struct ingenic_ecc; +struct platform_device; + +/** + * struct ingenic_ecc_params - ECC parameters + * @size: data bytes per ECC step. + * @bytes: ECC bytes per step. + * @strength: number of correctable bits per ECC step. + */ +struct ingenic_ecc_params { + int size; + int bytes; + int strength; +}; + +#if IS_ENABLED(CONFIG_MTD_NAND_INGENIC_ECC) +int ingenic_ecc_calculate(struct ingenic_ecc *ecc, + struct ingenic_ecc_params *params, + const u8 *buf, u8 *ecc_code); +int ingenic_ecc_correct(struct ingenic_ecc *ecc, + struct ingenic_ecc_params *params, u8 *buf, + u8 *ecc_code); + +void ingenic_ecc_release(struct ingenic_ecc *ecc); +struct ingenic_ecc *of_ingenic_ecc_get(struct device_node *np); +#else /* CONFIG_MTD_NAND_INGENIC_ECC */ +int ingenic_ecc_calculate(struct ingenic_ecc *ecc, + struct ingenic_ecc_params *params, + const u8 *buf, u8 *ecc_code) +{ + return -ENODEV; +} + +int ingenic_ecc_correct(struct ingenic_ecc *ecc, + struct ingenic_ecc_params *params, u8 *buf, + u8 *ecc_code) +{ + return -ENODEV; +} + +void ingenic_ecc_release(struct ingenic_ecc *ecc) +{ +} + +struct ingenic_ecc *of_ingenic_ecc_get(struct device_node *np) +{ + return ERR_PTR(-ENODEV); +} +#endif /* CONFIG_MTD_NAND_INGENIC_ECC */ + +struct ingenic_ecc_ops { + void (*disable)(struct ingenic_ecc *ecc); + int (*calculate)(struct ingenic_ecc *ecc, + struct ingenic_ecc_params *params, + const u8 *buf, u8 *ecc_code); + int (*correct)(struct ingenic_ecc *ecc, + struct ingenic_ecc_params *params, + u8 *buf, u8 *ecc_code); +}; + +struct ingenic_ecc { + struct device *dev; + const struct ingenic_ecc_ops *ops; + void __iomem *base; + struct clk *clk; + struct mutex lock; +}; + +int ingenic_ecc_probe(struct platform_device *pdev); + +#endif /* __DRIVERS_MTD_NAND_INGENIC_ECC_INTERNAL_H__ */ diff --git a/drivers/mtd/nand/raw/ingenic/ingenic_nand.c b/drivers/mtd/nand/raw/ingenic/ingenic_nand.c index 8c73f7c5be9a..a5f2f21c5198 100644 --- a/drivers/mtd/nand/raw/ingenic/ingenic_nand.c +++ b/drivers/mtd/nand/raw/ingenic/ingenic_nand.c @@ -22,7 +22,7 @@ #include -#include "jz4780_bch.h" +#include "ingenic_ecc.h" #define DRV_NAME "ingenic-nand" @@ -40,7 +40,7 @@ struct ingenic_nand_cs { struct ingenic_nfc { struct device *dev; - struct jz4780_bch *bch; + struct ingenic_ecc *ecc; struct nand_controller controller; unsigned int num_banks; struct list_head chips; @@ -124,11 +124,11 @@ static int ingenic_nand_ecc_calculate(struct nand_chip *chip, const u8 *dat, { struct ingenic_nand *nand = to_ingenic_nand(nand_to_mtd(chip)); struct ingenic_nfc *nfc = to_ingenic_nfc(nand->chip.controller); - struct jz4780_bch_params params; + struct ingenic_ecc_params params; /* - * Don't need to generate the ECC when reading, BCH does it for us as - * part of decoding/correction. + * Don't need to generate the ECC when reading, the ECC engine does it + * for us as part of decoding/correction. */ if (nand->reading) return 0; @@ -137,7 +137,7 @@ static int ingenic_nand_ecc_calculate(struct nand_chip *chip, const u8 *dat, params.bytes = nand->chip.ecc.bytes; params.strength = nand->chip.ecc.strength; - return jz4780_bch_calculate(nfc->bch, ¶ms, dat, ecc_code); + return ingenic_ecc_calculate(nfc->ecc, ¶ms, dat, ecc_code); } static int ingenic_nand_ecc_correct(struct nand_chip *chip, u8 *dat, @@ -145,13 +145,13 @@ static int ingenic_nand_ecc_correct(struct nand_chip *chip, u8 *dat, { struct ingenic_nand *nand = to_ingenic_nand(nand_to_mtd(chip)); struct ingenic_nfc *nfc = to_ingenic_nfc(nand->chip.controller); - struct jz4780_bch_params params; + struct ingenic_ecc_params params; params.size = nand->chip.ecc.size; params.bytes = nand->chip.ecc.bytes; params.strength = nand->chip.ecc.strength; - return jz4780_bch_correct(nfc->bch, ¶ms, dat, read_ecc); + return ingenic_ecc_correct(nfc->ecc, ¶ms, dat, read_ecc); } static int ingenic_nand_attach_chip(struct nand_chip *chip) @@ -165,8 +165,8 @@ static int ingenic_nand_attach_chip(struct nand_chip *chip) switch (chip->ecc.mode) { case NAND_ECC_HW: - if (!nfc->bch) { - dev_err(nfc->dev, "HW BCH selected, but BCH controller not found\n"); + if (!nfc->ecc) { + dev_err(nfc->dev, "HW ECC selected, but ECC controller not found\n"); return -ENODEV; } @@ -176,7 +176,7 @@ static int ingenic_nand_attach_chip(struct nand_chip *chip) /* fall through */ case NAND_ECC_SOFT: dev_info(nfc->dev, "using %s (strength %d, size %d, bytes %d)\n", - (nfc->bch) ? "hardware BCH" : "software ECC", + (nfc->ecc) ? "hardware ECC" : "software ECC", chip->ecc.strength, chip->ecc.size, chip->ecc.bytes); break; case NAND_ECC_NONE: @@ -354,12 +354,12 @@ static int ingenic_nand_probe(struct platform_device *pdev) return -ENOMEM; /* - * Check for BCH HW before we call nand_scan_ident, to prevent us from - * having to call it again if the BCH driver returns -EPROBE_DEFER. + * Check for ECC HW before we call nand_scan_ident, to prevent us from + * having to call it again if the ECC driver returns -EPROBE_DEFER. */ - nfc->bch = of_jz4780_bch_get(dev->of_node); - if (IS_ERR(nfc->bch)) - return PTR_ERR(nfc->bch); + nfc->ecc = of_ingenic_ecc_get(dev->of_node); + if (IS_ERR(nfc->ecc)) + return PTR_ERR(nfc->ecc); nfc->dev = dev; nfc->num_banks = num_banks; @@ -369,8 +369,8 @@ static int ingenic_nand_probe(struct platform_device *pdev) ret = ingenic_nand_init_chips(nfc, pdev); if (ret) { - if (nfc->bch) - jz4780_bch_release(nfc->bch); + if (nfc->ecc) + ingenic_ecc_release(nfc->ecc); return ret; } @@ -382,8 +382,8 @@ static int ingenic_nand_remove(struct platform_device *pdev) { struct ingenic_nfc *nfc = platform_get_drvdata(pdev); - if (nfc->bch) - jz4780_bch_release(nfc->bch); + if (nfc->ecc) + ingenic_ecc_release(nfc->ecc); ingenic_nand_cleanup_chips(nfc); diff --git a/drivers/mtd/nand/raw/ingenic/jz4780_bch.c b/drivers/mtd/nand/raw/ingenic/jz4780_bch.c index 7635753bd7ea..079266a0d6cf 100644 --- a/drivers/mtd/nand/raw/ingenic/jz4780_bch.c +++ b/drivers/mtd/nand/raw/ingenic/jz4780_bch.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* - * JZ4780 BCH controller + * JZ4780 BCH controller driver * * Copyright (c) 2015 Imagination Technologies * Author: Alex Smith @@ -8,18 +8,15 @@ #include #include -#include -#include +#include +#include #include #include #include -#include #include #include -#include -#include -#include "jz4780_bch.h" +#include "ingenic_ecc.h" #define BCH_BHCR 0x0 #define BCH_BHCCR 0x8 @@ -62,15 +59,8 @@ /* Timeout for BCH calculation/correction. */ #define BCH_TIMEOUT_US 100000 -struct jz4780_bch { - struct device *dev; - void __iomem *base; - struct clk *clk; - struct mutex lock; -}; - -static void jz4780_bch_reset(struct jz4780_bch *bch, - struct jz4780_bch_params *params, bool encode) +static void jz4780_bch_reset(struct ingenic_ecc *bch, + struct ingenic_ecc_params *params, bool encode) { u32 reg; @@ -90,13 +80,13 @@ static void jz4780_bch_reset(struct jz4780_bch *bch, writel(reg, bch->base + BCH_BHCR); } -static void jz4780_bch_disable(struct jz4780_bch *bch) +static void jz4780_bch_disable(struct ingenic_ecc *bch) { writel(readl(bch->base + BCH_BHINT), bch->base + BCH_BHINT); writel(BCH_BHCR_BCHE, bch->base + BCH_BHCCR); } -static void jz4780_bch_write_data(struct jz4780_bch *bch, const void *buf, +static void jz4780_bch_write_data(struct ingenic_ecc *bch, const void *buf, size_t size) { size_t size32 = size / sizeof(u32); @@ -113,7 +103,7 @@ static void jz4780_bch_write_data(struct jz4780_bch *bch, const void *buf, writeb(*src8++, bch->base + BCH_BHDR); } -static void jz4780_bch_read_parity(struct jz4780_bch *bch, void *buf, +static void jz4780_bch_read_parity(struct ingenic_ecc *bch, void *buf, size_t size) { size_t size32 = size / sizeof(u32); @@ -143,7 +133,7 @@ static void jz4780_bch_read_parity(struct jz4780_bch *bch, void *buf, } } -static bool jz4780_bch_wait_complete(struct jz4780_bch *bch, unsigned int irq, +static bool jz4780_bch_wait_complete(struct ingenic_ecc *bch, unsigned int irq, u32 *status) { u32 reg; @@ -167,18 +157,9 @@ static bool jz4780_bch_wait_complete(struct jz4780_bch *bch, unsigned int irq, return true; } -/** - * jz4780_bch_calculate() - calculate ECC for a data buffer - * @bch: BCH device. - * @params: BCH parameters. - * @buf: input buffer with raw data. - * @ecc_code: output buffer with ECC. - * - * Return: 0 on success, -ETIMEDOUT if timed out while waiting for BCH - * controller. - */ -int jz4780_bch_calculate(struct jz4780_bch *bch, struct jz4780_bch_params *params, - const u8 *buf, u8 *ecc_code) +static int jz4780_calculate(struct ingenic_ecc *bch, + struct ingenic_ecc_params *params, + const u8 *buf, u8 *ecc_code) { int ret = 0; @@ -198,23 +179,10 @@ int jz4780_bch_calculate(struct jz4780_bch *bch, struct jz4780_bch_params *param mutex_unlock(&bch->lock); return ret; } -EXPORT_SYMBOL(jz4780_bch_calculate); - -/** - * jz4780_bch_correct() - detect and correct bit errors - * @bch: BCH device. - * @params: BCH parameters. - * @buf: raw data read from the chip. - * @ecc_code: ECC read from the chip. - * - * Given the raw data and the ECC read from the NAND device, detects and - * corrects errors in the data. - * - * Return: the number of bit errors corrected, -EBADMSG if there are too many - * errors to correct or -ETIMEDOUT if we timed out waiting for the controller. - */ -int jz4780_bch_correct(struct jz4780_bch *bch, struct jz4780_bch_params *params, - u8 *buf, u8 *ecc_code) + +static int jz4780_correct(struct ingenic_ecc *bch, + struct ingenic_ecc_params *params, + u8 *buf, u8 *ecc_code) { u32 reg, mask, index; int i, ret, count; @@ -260,110 +228,30 @@ out: mutex_unlock(&bch->lock); return ret; } -EXPORT_SYMBOL(jz4780_bch_correct); - -/** - * jz4780_bch_get() - get the BCH controller device - * @np: BCH device tree node. - * - * Gets the BCH controller device from the specified device tree node. The - * device must be released with jz4780_bch_release() when it is no longer being - * used. - * - * Return: a pointer to jz4780_bch, errors are encoded into the pointer. - * PTR_ERR(-EPROBE_DEFER) if the device hasn't been initialised yet. - */ -static struct jz4780_bch *jz4780_bch_get(struct device_node *np) -{ - struct platform_device *pdev; - struct jz4780_bch *bch; - - pdev = of_find_device_by_node(np); - if (!pdev) - return ERR_PTR(-EPROBE_DEFER); - - bch = platform_get_drvdata(pdev); - if (!bch) { - put_device(&pdev->dev); - return ERR_PTR(-EPROBE_DEFER); - } - - clk_prepare_enable(bch->clk); - - return bch; -} - -/** - * of_jz4780_bch_get() - get the BCH controller from a DT node - * @of_node: the node that contains a bch-controller property. - * - * Get the bch-controller property from the given device tree - * node and pass it to jz4780_bch_get to do the work. - * - * Return: a pointer to jz4780_bch, errors are encoded into the pointer. - * PTR_ERR(-EPROBE_DEFER) if the device hasn't been initialised yet. - */ -struct jz4780_bch *of_jz4780_bch_get(struct device_node *of_node) -{ - struct jz4780_bch *bch = NULL; - struct device_node *np; - - np = of_parse_phandle(of_node, "ingenic,bch-controller", 0); - - if (np) { - bch = jz4780_bch_get(np); - of_node_put(np); - } - return bch; -} -EXPORT_SYMBOL(of_jz4780_bch_get); - -/** - * jz4780_bch_release() - release the BCH controller device - * @bch: BCH device. - */ -void jz4780_bch_release(struct jz4780_bch *bch) -{ - clk_disable_unprepare(bch->clk); - put_device(bch->dev); -} -EXPORT_SYMBOL(jz4780_bch_release); static int jz4780_bch_probe(struct platform_device *pdev) { - struct device *dev = &pdev->dev; - struct jz4780_bch *bch; - struct resource *res; - - bch = devm_kzalloc(dev, sizeof(*bch), GFP_KERNEL); - if (!bch) - return -ENOMEM; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - bch->base = devm_ioremap_resource(dev, res); - if (IS_ERR(bch->base)) - return PTR_ERR(bch->base); - - jz4780_bch_disable(bch); + struct ingenic_ecc *bch; + int ret; - bch->clk = devm_clk_get(dev, NULL); - if (IS_ERR(bch->clk)) { - dev_err(dev, "failed to get clock: %ld\n", PTR_ERR(bch->clk)); - return PTR_ERR(bch->clk); - } + ret = ingenic_ecc_probe(pdev); + if (ret) + return ret; + bch = platform_get_drvdata(pdev); clk_set_rate(bch->clk, BCH_CLK_RATE); - mutex_init(&bch->lock); - - bch->dev = dev; - platform_set_drvdata(pdev, bch); - return 0; } +static const struct ingenic_ecc_ops jz4780_bch_ops = { + .disable = jz4780_bch_disable, + .calculate = jz4780_calculate, + .correct = jz4780_correct, +}; + static const struct of_device_id jz4780_bch_dt_match[] = { - { .compatible = "ingenic,jz4780-bch" }, + { .compatible = "ingenic,jz4780-bch", .data = &jz4780_bch_ops }, {}, }; MODULE_DEVICE_TABLE(of, jz4780_bch_dt_match); diff --git a/drivers/mtd/nand/raw/ingenic/jz4780_bch.h b/drivers/mtd/nand/raw/ingenic/jz4780_bch.h deleted file mode 100644 index 451e0c770160..000000000000 --- a/drivers/mtd/nand/raw/ingenic/jz4780_bch.h +++ /dev/null @@ -1,40 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * JZ4780 BCH controller - * - * Copyright (c) 2015 Imagination Technologies - * Author: Alex Smith - */ - -#ifndef __DRIVERS_MTD_NAND_JZ4780_BCH_H__ -#define __DRIVERS_MTD_NAND_JZ4780_BCH_H__ - -#include - -struct device; -struct device_node; -struct jz4780_bch; - -/** - * struct jz4780_bch_params - BCH parameters - * @size: data bytes per ECC step. - * @bytes: ECC bytes per step. - * @strength: number of correctable bits per ECC step. - */ -struct jz4780_bch_params { - int size; - int bytes; - int strength; -}; - -int jz4780_bch_calculate(struct jz4780_bch *bch, - struct jz4780_bch_params *params, - const u8 *buf, u8 *ecc_code); -int jz4780_bch_correct(struct jz4780_bch *bch, - struct jz4780_bch_params *params, u8 *buf, - u8 *ecc_code); - -void jz4780_bch_release(struct jz4780_bch *bch); -struct jz4780_bch *of_jz4780_bch_get(struct device_node *np); - -#endif /* __DRIVERS_MTD_NAND_JZ4780_BCH_H__ */ -- cgit From f838154add45b94c553b96f302c181d32aa3440d Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Tue, 19 Mar 2019 15:53:59 +0100 Subject: mtd: rawnand: ingenic: Make use of ecc-engine property Use the 'ecc-engine' standard property instead of the custom 'ingenic,bch-controller' custom property, which is now deprecated. Signed-off-by: Paul Cercueil Signed-off-by: Miquel Raynal --- drivers/mtd/nand/raw/ingenic/ingenic_ecc.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/mtd/nand/raw/ingenic/ingenic_ecc.c b/drivers/mtd/nand/raw/ingenic/ingenic_ecc.c index 2aa71595a9e8..13cc7630a3d8 100644 --- a/drivers/mtd/nand/raw/ingenic/ingenic_ecc.c +++ b/drivers/mtd/nand/raw/ingenic/ingenic_ecc.c @@ -83,9 +83,9 @@ static struct ingenic_ecc *ingenic_ecc_get(struct device_node *np) /** * of_ingenic_ecc_get() - get the ECC controller from a DT node - * @of_node: the node that contains a bch-controller property. + * @of_node: the node that contains an ecc-engine property. * - * Get the bch-controller property from the given device tree + * Get the ecc-engine property from the given device tree * node and pass it to ingenic_ecc_get to do the work. * * Return: a pointer to ingenic_ecc, errors are encoded into the pointer. @@ -96,7 +96,14 @@ struct ingenic_ecc *of_ingenic_ecc_get(struct device_node *of_node) struct ingenic_ecc *ecc = NULL; struct device_node *np; - np = of_parse_phandle(of_node, "ingenic,bch-controller", 0); + np = of_parse_phandle(of_node, "ecc-engine", 0); + + /* + * If the ecc-engine property is not found, check for the deprecated + * ingenic,bch-controller property + */ + if (!np) + np = of_parse_phandle(of_node, "ingenic,bch-controller", 0); if (np) { ecc = ingenic_ecc_get(np); -- cgit From a0ac778eb82c43b74d50cb0e31815bf5f24b295c Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Tue, 19 Mar 2019 15:54:00 +0100 Subject: mtd: rawnand: ingenic: Add support for the JZ4740 Add support for probing the ingenic-nand driver on the JZ4740 SoC from Ingenic, and the jz4740-ecc driver to support the JZ4740-specific ECC hardware. Signed-off-by: Paul Cercueil Signed-off-by: Miquel Raynal --- drivers/mtd/nand/raw/ingenic/Kconfig | 10 ++ drivers/mtd/nand/raw/ingenic/Makefile | 1 + drivers/mtd/nand/raw/ingenic/ingenic_nand.c | 48 +++++-- drivers/mtd/nand/raw/ingenic/jz4740_ecc.c | 197 ++++++++++++++++++++++++++++ 4 files changed, 245 insertions(+), 11 deletions(-) create mode 100644 drivers/mtd/nand/raw/ingenic/jz4740_ecc.c diff --git a/drivers/mtd/nand/raw/ingenic/Kconfig b/drivers/mtd/nand/raw/ingenic/Kconfig index 4bf7d7af3b0a..cc663cc15119 100644 --- a/drivers/mtd/nand/raw/ingenic/Kconfig +++ b/drivers/mtd/nand/raw/ingenic/Kconfig @@ -17,6 +17,16 @@ if MTD_NAND_JZ4780 config MTD_NAND_INGENIC_ECC tristate +config MTD_NAND_JZ4740_ECC + tristate "Hardware BCH support for JZ4740 SoC" + select MTD_NAND_INGENIC_ECC + help + Enable this driver to support the Reed-Solomon error-correction + hardware present on the JZ4740 SoC from Ingenic. + + This driver can also be built as a module. If so, the module + will be called jz4740-ecc. + config MTD_NAND_JZ4780_BCH tristate "Hardware BCH support for JZ4780 SoC" select MTD_NAND_INGENIC_ECC diff --git a/drivers/mtd/nand/raw/ingenic/Makefile b/drivers/mtd/nand/raw/ingenic/Makefile index f3c3c0f230b0..563b7effcf59 100644 --- a/drivers/mtd/nand/raw/ingenic/Makefile +++ b/drivers/mtd/nand/raw/ingenic/Makefile @@ -2,4 +2,5 @@ obj-$(CONFIG_MTD_NAND_JZ4740) += jz4740_nand.o obj-$(CONFIG_MTD_NAND_JZ4780) += ingenic_nand.o obj-$(CONFIG_MTD_NAND_INGENIC_ECC) += ingenic_ecc.o +obj-$(CONFIG_MTD_NAND_JZ4740_ECC) += jz4740_ecc.o obj-$(CONFIG_MTD_NAND_JZ4780_BCH) += jz4780_bch.o diff --git a/drivers/mtd/nand/raw/ingenic/ingenic_nand.c b/drivers/mtd/nand/raw/ingenic/ingenic_nand.c index a5f2f21c5198..1bd1f18d4532 100644 --- a/drivers/mtd/nand/raw/ingenic/ingenic_nand.c +++ b/drivers/mtd/nand/raw/ingenic/ingenic_nand.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -26,13 +27,15 @@ #define DRV_NAME "ingenic-nand" -#define OFFSET_DATA 0x00000000 -#define OFFSET_CMD 0x00400000 -#define OFFSET_ADDR 0x00800000 - /* Command delay when there is no R/B pin. */ #define RB_DELAY_US 100 +struct jz_soc_info { + unsigned long data_offset; + unsigned long addr_offset; + unsigned long cmd_offset; +}; + struct ingenic_nand_cs { unsigned int bank; void __iomem *base; @@ -41,6 +44,7 @@ struct ingenic_nand_cs { struct ingenic_nfc { struct device *dev; struct ingenic_ecc *ecc; + const struct jz_soc_info *soc_info; struct nand_controller controller; unsigned int num_banks; struct list_head chips; @@ -100,9 +104,9 @@ static void ingenic_nand_cmd_ctrl(struct nand_chip *chip, int cmd, return; if (ctrl & NAND_ALE) - writeb(cmd, cs->base + OFFSET_ADDR); + writeb(cmd, cs->base + nfc->soc_info->addr_offset); else if (ctrl & NAND_CLE) - writeb(cmd, cs->base + OFFSET_CMD); + writeb(cmd, cs->base + nfc->soc_info->cmd_offset); } static int ingenic_nand_dev_ready(struct nand_chip *chip) @@ -160,8 +164,13 @@ static int ingenic_nand_attach_chip(struct nand_chip *chip) struct ingenic_nfc *nfc = to_ingenic_nfc(chip->controller); int eccbytes; - chip->ecc.bytes = fls((1 + 8) * chip->ecc.size) * - (chip->ecc.strength / 8); + if (chip->ecc.strength == 4) { + /* JZ4740 uses 9 bytes of ECC to correct maximum 4 errors */ + chip->ecc.bytes = 9; + } else { + chip->ecc.bytes = fls((1 + 8) * chip->ecc.size) * + (chip->ecc.strength / 8); + } switch (chip->ecc.mode) { case NAND_ECC_HW: @@ -270,8 +279,8 @@ static int ingenic_nand_init_chip(struct platform_device *pdev, return -ENOMEM; mtd->dev.parent = dev; - chip->legacy.IO_ADDR_R = cs->base + OFFSET_DATA; - chip->legacy.IO_ADDR_W = cs->base + OFFSET_DATA; + chip->legacy.IO_ADDR_R = cs->base + nfc->soc_info->data_offset; + chip->legacy.IO_ADDR_W = cs->base + nfc->soc_info->data_offset; chip->legacy.chip_delay = RB_DELAY_US; chip->options = NAND_NO_SUBPAGE_WRITE; chip->legacy.select_chip = ingenic_nand_select_chip; @@ -353,6 +362,10 @@ static int ingenic_nand_probe(struct platform_device *pdev) if (!nfc) return -ENOMEM; + nfc->soc_info = device_get_match_data(dev); + if (!nfc->soc_info) + return -EINVAL; + /* * Check for ECC HW before we call nand_scan_ident, to prevent us from * having to call it again if the ECC driver returns -EPROBE_DEFER. @@ -390,8 +403,21 @@ static int ingenic_nand_remove(struct platform_device *pdev) return 0; } +static const struct jz_soc_info jz4740_soc_info = { + .data_offset = 0x00000000, + .cmd_offset = 0x00008000, + .addr_offset = 0x00010000, +}; + +static const struct jz_soc_info jz4780_soc_info = { + .data_offset = 0x00000000, + .cmd_offset = 0x00400000, + .addr_offset = 0x00800000, +}; + static const struct of_device_id ingenic_nand_dt_match[] = { - { .compatible = "ingenic,jz4780-nand" }, + { .compatible = "ingenic,jz4740-nand", .data = &jz4740_soc_info }, + { .compatible = "ingenic,jz4780-nand", .data = &jz4780_soc_info }, {}, }; MODULE_DEVICE_TABLE(of, ingenic_nand_dt_match); diff --git a/drivers/mtd/nand/raw/ingenic/jz4740_ecc.c b/drivers/mtd/nand/raw/ingenic/jz4740_ecc.c new file mode 100644 index 000000000000..13fea645c7f0 --- /dev/null +++ b/drivers/mtd/nand/raw/ingenic/jz4740_ecc.c @@ -0,0 +1,197 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * JZ4740 ECC controller driver + * + * Copyright (c) 2019 Paul Cercueil + * + * based on jz4740-nand.c + */ + +#include +#include +#include +#include +#include +#include + +#include "ingenic_ecc.h" + +#define JZ_REG_NAND_ECC_CTRL 0x00 +#define JZ_REG_NAND_DATA 0x04 +#define JZ_REG_NAND_PAR0 0x08 +#define JZ_REG_NAND_PAR1 0x0C +#define JZ_REG_NAND_PAR2 0x10 +#define JZ_REG_NAND_IRQ_STAT 0x14 +#define JZ_REG_NAND_IRQ_CTRL 0x18 +#define JZ_REG_NAND_ERR(x) (0x1C + ((x) << 2)) + +#define JZ_NAND_ECC_CTRL_PAR_READY BIT(4) +#define JZ_NAND_ECC_CTRL_ENCODING BIT(3) +#define JZ_NAND_ECC_CTRL_RS BIT(2) +#define JZ_NAND_ECC_CTRL_RESET BIT(1) +#define JZ_NAND_ECC_CTRL_ENABLE BIT(0) + +#define JZ_NAND_STATUS_ERR_COUNT (BIT(31) | BIT(30) | BIT(29)) +#define JZ_NAND_STATUS_PAD_FINISH BIT(4) +#define JZ_NAND_STATUS_DEC_FINISH BIT(3) +#define JZ_NAND_STATUS_ENC_FINISH BIT(2) +#define JZ_NAND_STATUS_UNCOR_ERROR BIT(1) +#define JZ_NAND_STATUS_ERROR BIT(0) + +static const uint8_t empty_block_ecc[] = { + 0xcd, 0x9d, 0x90, 0x58, 0xf4, 0x8b, 0xff, 0xb7, 0x6f +}; + +static void jz4740_ecc_reset(struct ingenic_ecc *ecc, bool calc_ecc) +{ + uint32_t reg; + + /* Clear interrupt status */ + writel(0, ecc->base + JZ_REG_NAND_IRQ_STAT); + + /* Initialize and enable ECC hardware */ + reg = readl(ecc->base + JZ_REG_NAND_ECC_CTRL); + reg |= JZ_NAND_ECC_CTRL_RESET; + reg |= JZ_NAND_ECC_CTRL_ENABLE; + reg |= JZ_NAND_ECC_CTRL_RS; + if (calc_ecc) /* calculate ECC from data */ + reg |= JZ_NAND_ECC_CTRL_ENCODING; + else /* correct data from ECC */ + reg &= ~JZ_NAND_ECC_CTRL_ENCODING; + + writel(reg, ecc->base + JZ_REG_NAND_ECC_CTRL); +} + +static int jz4740_ecc_calculate(struct ingenic_ecc *ecc, + struct ingenic_ecc_params *params, + const u8 *buf, u8 *ecc_code) +{ + uint32_t reg, status; + unsigned int timeout = 1000; + int i; + + jz4740_ecc_reset(ecc, true); + + do { + status = readl(ecc->base + JZ_REG_NAND_IRQ_STAT); + } while (!(status & JZ_NAND_STATUS_ENC_FINISH) && --timeout); + + if (timeout == 0) + return -ETIMEDOUT; + + reg = readl(ecc->base + JZ_REG_NAND_ECC_CTRL); + reg &= ~JZ_NAND_ECC_CTRL_ENABLE; + writel(reg, ecc->base + JZ_REG_NAND_ECC_CTRL); + + for (i = 0; i < params->bytes; ++i) + ecc_code[i] = readb(ecc->base + JZ_REG_NAND_PAR0 + i); + + /* + * If the written data is completely 0xff, we also want to write 0xff as + * ECC, otherwise we will get in trouble when doing subpage writes. + */ + if (memcmp(ecc_code, empty_block_ecc, ARRAY_SIZE(empty_block_ecc)) == 0) + memset(ecc_code, 0xff, ARRAY_SIZE(empty_block_ecc)); + + return 0; +} + +static void jz_nand_correct_data(uint8_t *buf, int index, int mask) +{ + int offset = index & 0x7; + uint16_t data; + + index += (index >> 3); + + data = buf[index]; + data |= buf[index + 1] << 8; + + mask ^= (data >> offset) & 0x1ff; + data &= ~(0x1ff << offset); + data |= (mask << offset); + + buf[index] = data & 0xff; + buf[index + 1] = (data >> 8) & 0xff; +} + +static int jz4740_ecc_correct(struct ingenic_ecc *ecc, + struct ingenic_ecc_params *params, + u8 *buf, u8 *ecc_code) +{ + int i, error_count, index; + uint32_t reg, status, error; + unsigned int timeout = 1000; + + jz4740_ecc_reset(ecc, false); + + for (i = 0; i < params->bytes; ++i) + writeb(ecc_code[i], ecc->base + JZ_REG_NAND_PAR0 + i); + + reg = readl(ecc->base + JZ_REG_NAND_ECC_CTRL); + reg |= JZ_NAND_ECC_CTRL_PAR_READY; + writel(reg, ecc->base + JZ_REG_NAND_ECC_CTRL); + + do { + status = readl(ecc->base + JZ_REG_NAND_IRQ_STAT); + } while (!(status & JZ_NAND_STATUS_DEC_FINISH) && --timeout); + + if (timeout == 0) + return -ETIMEDOUT; + + reg = readl(ecc->base + JZ_REG_NAND_ECC_CTRL); + reg &= ~JZ_NAND_ECC_CTRL_ENABLE; + writel(reg, ecc->base + JZ_REG_NAND_ECC_CTRL); + + if (status & JZ_NAND_STATUS_ERROR) { + if (status & JZ_NAND_STATUS_UNCOR_ERROR) + return -EBADMSG; + + error_count = (status & JZ_NAND_STATUS_ERR_COUNT) >> 29; + + for (i = 0; i < error_count; ++i) { + error = readl(ecc->base + JZ_REG_NAND_ERR(i)); + index = ((error >> 16) & 0x1ff) - 1; + if (index >= 0 && index < params->size) + jz_nand_correct_data(buf, index, error & 0x1ff); + } + + return error_count; + } + + return 0; +} + +static void jz4740_ecc_disable(struct ingenic_ecc *ecc) +{ + u32 reg; + + writel(0, ecc->base + JZ_REG_NAND_IRQ_STAT); + reg = readl(ecc->base + JZ_REG_NAND_ECC_CTRL); + reg &= ~JZ_NAND_ECC_CTRL_ENABLE; + writel(reg, ecc->base + JZ_REG_NAND_ECC_CTRL); +} + +static const struct ingenic_ecc_ops jz4740_ecc_ops = { + .disable = jz4740_ecc_disable, + .calculate = jz4740_ecc_calculate, + .correct = jz4740_ecc_correct, +}; + +static const struct of_device_id jz4740_ecc_dt_match[] = { + { .compatible = "ingenic,jz4740-ecc", .data = &jz4740_ecc_ops }, + {}, +}; +MODULE_DEVICE_TABLE(of, jz4740_ecc_dt_match); + +static struct platform_driver jz4740_ecc_driver = { + .probe = ingenic_ecc_probe, + .driver = { + .name = "jz4740-ecc", + .of_match_table = jz4740_ecc_dt_match, + }, +}; +module_platform_driver(jz4740_ecc_driver); + +MODULE_AUTHOR("Paul Cercueil "); +MODULE_DESCRIPTION("Ingenic JZ4740 ECC controller driver"); +MODULE_LICENSE("GPL v2"); -- cgit From 3e6ac2ad90b351f040d9f8b05da40487f0f35cfe Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Tue, 19 Mar 2019 15:54:01 +0100 Subject: mtd: rawnand: ingenic: Add support for the JZ4725B The boot ROM of the JZ4725B SoC expects a specific OOB layout on the NAND, so we use it unconditionally in the ingenic-nand driver. Also add the jz4725b-bch driver to support the JZ4725B-specific BCH hardware. Signed-off-by: Paul Cercueil Signed-off-by: Miquel Raynal --- drivers/mtd/nand/raw/ingenic/Kconfig | 10 + drivers/mtd/nand/raw/ingenic/Makefile | 1 + drivers/mtd/nand/raw/ingenic/ingenic_nand.c | 48 ++++- drivers/mtd/nand/raw/ingenic/jz4725b_bch.c | 295 ++++++++++++++++++++++++++++ 4 files changed, 353 insertions(+), 1 deletion(-) create mode 100644 drivers/mtd/nand/raw/ingenic/jz4725b_bch.c diff --git a/drivers/mtd/nand/raw/ingenic/Kconfig b/drivers/mtd/nand/raw/ingenic/Kconfig index cc663cc15119..497b46b144f2 100644 --- a/drivers/mtd/nand/raw/ingenic/Kconfig +++ b/drivers/mtd/nand/raw/ingenic/Kconfig @@ -27,6 +27,16 @@ config MTD_NAND_JZ4740_ECC This driver can also be built as a module. If so, the module will be called jz4740-ecc. +config MTD_NAND_JZ4725B_BCH + tristate "Hardware BCH support for JZ4725B SoC" + select MTD_NAND_INGENIC_ECC + help + Enable this driver to support the BCH error-correction hardware + present on the JZ4725B SoC from Ingenic. + + This driver can also be built as a module. If so, the module + will be called jz4725b-bch. + config MTD_NAND_JZ4780_BCH tristate "Hardware BCH support for JZ4780 SoC" select MTD_NAND_INGENIC_ECC diff --git a/drivers/mtd/nand/raw/ingenic/Makefile b/drivers/mtd/nand/raw/ingenic/Makefile index 563b7effcf59..ab2c5f47e5b7 100644 --- a/drivers/mtd/nand/raw/ingenic/Makefile +++ b/drivers/mtd/nand/raw/ingenic/Makefile @@ -3,4 +3,5 @@ obj-$(CONFIG_MTD_NAND_JZ4780) += ingenic_nand.o obj-$(CONFIG_MTD_NAND_INGENIC_ECC) += ingenic_ecc.o obj-$(CONFIG_MTD_NAND_JZ4740_ECC) += jz4740_ecc.o +obj-$(CONFIG_MTD_NAND_JZ4725B_BCH) += jz4725b_bch.o obj-$(CONFIG_MTD_NAND_JZ4780_BCH) += jz4780_bch.o diff --git a/drivers/mtd/nand/raw/ingenic/ingenic_nand.c b/drivers/mtd/nand/raw/ingenic/ingenic_nand.c index 1bd1f18d4532..a2450e10932a 100644 --- a/drivers/mtd/nand/raw/ingenic/ingenic_nand.c +++ b/drivers/mtd/nand/raw/ingenic/ingenic_nand.c @@ -34,6 +34,7 @@ struct jz_soc_info { unsigned long data_offset; unsigned long addr_offset; unsigned long cmd_offset; + const struct mtd_ooblayout_ops *oob_layout; }; struct ingenic_nand_cs { @@ -71,6 +72,41 @@ static inline struct ingenic_nfc *to_ingenic_nfc(struct nand_controller *ctrl) return container_of(ctrl, struct ingenic_nfc, controller); } +static int jz4725b_ooblayout_ecc(struct mtd_info *mtd, int section, + struct mtd_oob_region *oobregion) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + struct nand_ecc_ctrl *ecc = &chip->ecc; + + if (section || !ecc->total) + return -ERANGE; + + oobregion->length = ecc->total; + oobregion->offset = 3; + + return 0; +} + +static int jz4725b_ooblayout_free(struct mtd_info *mtd, int section, + struct mtd_oob_region *oobregion) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + struct nand_ecc_ctrl *ecc = &chip->ecc; + + if (section) + return -ERANGE; + + oobregion->length = mtd->oobsize - ecc->total - 3; + oobregion->offset = 3 + ecc->total; + + return 0; +} + +const struct mtd_ooblayout_ops jz4725b_ooblayout_ops = { + .ecc = jz4725b_ooblayout_ecc, + .free = jz4725b_ooblayout_free, +}; + static void ingenic_nand_select_chip(struct nand_chip *chip, int chipnr) { struct ingenic_nand *nand = to_ingenic_nand(nand_to_mtd(chip)); @@ -211,7 +247,7 @@ static int ingenic_nand_attach_chip(struct nand_chip *chip) return -EINVAL; } - mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops); + mtd_set_ooblayout(mtd, nfc->soc_info->oob_layout); return 0; } @@ -407,16 +443,26 @@ static const struct jz_soc_info jz4740_soc_info = { .data_offset = 0x00000000, .cmd_offset = 0x00008000, .addr_offset = 0x00010000, + .oob_layout = &nand_ooblayout_lp_ops, +}; + +static const struct jz_soc_info jz4725b_soc_info = { + .data_offset = 0x00000000, + .cmd_offset = 0x00008000, + .addr_offset = 0x00010000, + .oob_layout = &jz4725b_ooblayout_ops, }; static const struct jz_soc_info jz4780_soc_info = { .data_offset = 0x00000000, .cmd_offset = 0x00400000, .addr_offset = 0x00800000, + .oob_layout = &nand_ooblayout_lp_ops, }; static const struct of_device_id ingenic_nand_dt_match[] = { { .compatible = "ingenic,jz4740-nand", .data = &jz4740_soc_info }, + { .compatible = "ingenic,jz4725b-nand", .data = &jz4725b_soc_info }, { .compatible = "ingenic,jz4780-nand", .data = &jz4780_soc_info }, {}, }; diff --git a/drivers/mtd/nand/raw/ingenic/jz4725b_bch.c b/drivers/mtd/nand/raw/ingenic/jz4725b_bch.c new file mode 100644 index 000000000000..6c852eae09cf --- /dev/null +++ b/drivers/mtd/nand/raw/ingenic/jz4725b_bch.c @@ -0,0 +1,295 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * JZ4725B BCH controller driver + * + * Copyright (C) 2019 Paul Cercueil + * + * Based on jz4780_bch.c + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ingenic_ecc.h" + +#define BCH_BHCR 0x0 +#define BCH_BHCSR 0x4 +#define BCH_BHCCR 0x8 +#define BCH_BHCNT 0xc +#define BCH_BHDR 0x10 +#define BCH_BHPAR0 0x14 +#define BCH_BHERR0 0x28 +#define BCH_BHINT 0x24 +#define BCH_BHINTES 0x3c +#define BCH_BHINTEC 0x40 +#define BCH_BHINTE 0x38 + +#define BCH_BHCR_ENCE BIT(3) +#define BCH_BHCR_BSEL BIT(2) +#define BCH_BHCR_INIT BIT(1) +#define BCH_BHCR_BCHE BIT(0) + +#define BCH_BHCNT_DEC_COUNT_SHIFT 16 +#define BCH_BHCNT_DEC_COUNT_MASK (0x3ff << BCH_BHCNT_DEC_COUNT_SHIFT) +#define BCH_BHCNT_ENC_COUNT_SHIFT 0 +#define BCH_BHCNT_ENC_COUNT_MASK (0x3ff << BCH_BHCNT_ENC_COUNT_SHIFT) + +#define BCH_BHERR_INDEX0_SHIFT 0 +#define BCH_BHERR_INDEX0_MASK (0x1fff << BCH_BHERR_INDEX0_SHIFT) +#define BCH_BHERR_INDEX1_SHIFT 16 +#define BCH_BHERR_INDEX1_MASK (0x1fff << BCH_BHERR_INDEX1_SHIFT) + +#define BCH_BHINT_ERRC_SHIFT 28 +#define BCH_BHINT_ERRC_MASK (0xf << BCH_BHINT_ERRC_SHIFT) +#define BCH_BHINT_TERRC_SHIFT 16 +#define BCH_BHINT_TERRC_MASK (0x7f << BCH_BHINT_TERRC_SHIFT) +#define BCH_BHINT_ALL_0 BIT(5) +#define BCH_BHINT_ALL_F BIT(4) +#define BCH_BHINT_DECF BIT(3) +#define BCH_BHINT_ENCF BIT(2) +#define BCH_BHINT_UNCOR BIT(1) +#define BCH_BHINT_ERR BIT(0) + +/* Timeout for BCH calculation/correction. */ +#define BCH_TIMEOUT_US 100000 + +static inline void jz4725b_bch_config_set(struct ingenic_ecc *bch, u32 cfg) +{ + writel(cfg, bch->base + BCH_BHCSR); +} + +static inline void jz4725b_bch_config_clear(struct ingenic_ecc *bch, u32 cfg) +{ + writel(cfg, bch->base + BCH_BHCCR); +} + +static int jz4725b_bch_reset(struct ingenic_ecc *bch, + struct ingenic_ecc_params *params, bool calc_ecc) +{ + u32 reg, max_value; + + /* Clear interrupt status. */ + writel(readl(bch->base + BCH_BHINT), bch->base + BCH_BHINT); + + /* Initialise and enable BCH. */ + jz4725b_bch_config_clear(bch, 0x1f); + jz4725b_bch_config_set(bch, BCH_BHCR_BCHE); + + if (params->strength == 8) + jz4725b_bch_config_set(bch, BCH_BHCR_BSEL); + else + jz4725b_bch_config_clear(bch, BCH_BHCR_BSEL); + + if (calc_ecc) /* calculate ECC from data */ + jz4725b_bch_config_set(bch, BCH_BHCR_ENCE); + else /* correct data from ECC */ + jz4725b_bch_config_clear(bch, BCH_BHCR_ENCE); + + jz4725b_bch_config_set(bch, BCH_BHCR_INIT); + + max_value = BCH_BHCNT_ENC_COUNT_MASK >> BCH_BHCNT_ENC_COUNT_SHIFT; + if (params->size > max_value) + return -EINVAL; + + max_value = BCH_BHCNT_DEC_COUNT_MASK >> BCH_BHCNT_DEC_COUNT_SHIFT; + if (params->size + params->bytes > max_value) + return -EINVAL; + + /* Set up BCH count register. */ + reg = params->size << BCH_BHCNT_ENC_COUNT_SHIFT; + reg |= (params->size + params->bytes) << BCH_BHCNT_DEC_COUNT_SHIFT; + writel(reg, bch->base + BCH_BHCNT); + + return 0; +} + +static void jz4725b_bch_disable(struct ingenic_ecc *bch) +{ + /* Clear interrupts */ + writel(readl(bch->base + BCH_BHINT), bch->base + BCH_BHINT); + + /* Disable the hardware */ + jz4725b_bch_config_clear(bch, BCH_BHCR_BCHE); +} + +static void jz4725b_bch_write_data(struct ingenic_ecc *bch, const u8 *buf, + size_t size) +{ + while (size--) + writeb(*buf++, bch->base + BCH_BHDR); +} + +static void jz4725b_bch_read_parity(struct ingenic_ecc *bch, u8 *buf, + size_t size) +{ + size_t size32 = size / sizeof(u32); + size_t size8 = size % sizeof(u32); + u32 *dest32; + u8 *dest8; + u32 val, offset = 0; + + dest32 = (u32 *)buf; + while (size32--) { + *dest32++ = readl_relaxed(bch->base + BCH_BHPAR0 + offset); + offset += sizeof(u32); + } + + dest8 = (u8 *)dest32; + val = readl_relaxed(bch->base + BCH_BHPAR0 + offset); + switch (size8) { + case 3: + dest8[2] = (val >> 16) & 0xff; + /* fall-through */ + case 2: + dest8[1] = (val >> 8) & 0xff; + /* fall-through */ + case 1: + dest8[0] = val & 0xff; + break; + } +} + +static int jz4725b_bch_wait_complete(struct ingenic_ecc *bch, unsigned int irq, + u32 *status) +{ + u32 reg; + int ret; + + /* + * While we could use interrupts here and sleep until the operation + * completes, the controller works fairly quickly (usually a few + * microseconds) and so the overhead of sleeping until we get an + * interrupt quite noticeably decreases performance. + */ + ret = readl_relaxed_poll_timeout(bch->base + BCH_BHINT, reg, + reg & irq, 0, BCH_TIMEOUT_US); + if (ret) + return ret; + + if (status) + *status = reg; + + writel(reg, bch->base + BCH_BHINT); + + return 0; +} + +static int jz4725b_calculate(struct ingenic_ecc *bch, + struct ingenic_ecc_params *params, + const u8 *buf, u8 *ecc_code) +{ + int ret; + + mutex_lock(&bch->lock); + + ret = jz4725b_bch_reset(bch, params, true); + if (ret) { + dev_err(bch->dev, "Unable to init BCH with given parameters\n"); + goto out_disable; + } + + jz4725b_bch_write_data(bch, buf, params->size); + + ret = jz4725b_bch_wait_complete(bch, BCH_BHINT_ENCF, NULL); + if (ret) { + dev_err(bch->dev, "timed out while calculating ECC\n"); + goto out_disable; + } + + jz4725b_bch_read_parity(bch, ecc_code, params->bytes); + +out_disable: + jz4725b_bch_disable(bch); + mutex_unlock(&bch->lock); + + return ret; +} + +static int jz4725b_correct(struct ingenic_ecc *bch, + struct ingenic_ecc_params *params, + u8 *buf, u8 *ecc_code) +{ + u32 reg, errors, bit; + unsigned int i; + int ret; + + mutex_lock(&bch->lock); + + ret = jz4725b_bch_reset(bch, params, false); + if (ret) { + dev_err(bch->dev, "Unable to init BCH with given parameters\n"); + goto out; + } + + jz4725b_bch_write_data(bch, buf, params->size); + jz4725b_bch_write_data(bch, ecc_code, params->bytes); + + ret = jz4725b_bch_wait_complete(bch, BCH_BHINT_DECF, ®); + if (ret) { + dev_err(bch->dev, "timed out while correcting data\n"); + goto out; + } + + if (reg & (BCH_BHINT_ALL_F | BCH_BHINT_ALL_0)) { + /* Data and ECC is all 0xff or 0x00 - nothing to correct */ + ret = 0; + goto out; + } + + if (reg & BCH_BHINT_UNCOR) { + /* Uncorrectable ECC error */ + ret = -EBADMSG; + goto out; + } + + errors = (reg & BCH_BHINT_ERRC_MASK) >> BCH_BHINT_ERRC_SHIFT; + + /* Correct any detected errors. */ + for (i = 0; i < errors; i++) { + if (i & 1) { + bit = (reg & BCH_BHERR_INDEX1_MASK) >> BCH_BHERR_INDEX1_SHIFT; + } else { + reg = readl(bch->base + BCH_BHERR0 + (i * 4)); + bit = (reg & BCH_BHERR_INDEX0_MASK) >> BCH_BHERR_INDEX0_SHIFT; + } + + buf[(bit >> 3)] ^= BIT(bit & 0x7); + } + +out: + jz4725b_bch_disable(bch); + mutex_unlock(&bch->lock); + + return ret; +} + +static const struct ingenic_ecc_ops jz4725b_bch_ops = { + .disable = jz4725b_bch_disable, + .calculate = jz4725b_calculate, + .correct = jz4725b_correct, +}; + +static const struct of_device_id jz4725b_bch_dt_match[] = { + { .compatible = "ingenic,jz4725b-bch", .data = &jz4725b_bch_ops }, + {}, +}; +MODULE_DEVICE_TABLE(of, jz4725b_bch_dt_match); + +static struct platform_driver jz4725b_bch_driver = { + .probe = ingenic_ecc_probe, + .driver = { + .name = "jz4725b-bch", + .of_match_table = jz4725b_bch_dt_match, + }, +}; +module_platform_driver(jz4725b_bch_driver); + +MODULE_AUTHOR("Paul Cercueil "); +MODULE_DESCRIPTION("Ingenic JZ4725B BCH controller driver"); +MODULE_LICENSE("GPL v2"); -- cgit From 2a73858364aae7103d0ad786634303a69d28471b Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Tue, 19 Mar 2019 15:54:02 +0100 Subject: mtd: rawnand: ingenic: Add ooblayout for the Qi Ben Nanonote The Ben Nanonote from Qi Hardware expects a specific OOB layout on its NAND. Signed-off-by: Paul Cercueil Signed-off-by: Miquel Raynal --- drivers/mtd/nand/raw/ingenic/ingenic_nand.c | 41 ++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/nand/raw/ingenic/ingenic_nand.c b/drivers/mtd/nand/raw/ingenic/ingenic_nand.c index a2450e10932a..d32d68ef0dc7 100644 --- a/drivers/mtd/nand/raw/ingenic/ingenic_nand.c +++ b/drivers/mtd/nand/raw/ingenic/ingenic_nand.c @@ -72,6 +72,41 @@ static inline struct ingenic_nfc *to_ingenic_nfc(struct nand_controller *ctrl) return container_of(ctrl, struct ingenic_nfc, controller); } +static int qi_lb60_ooblayout_ecc(struct mtd_info *mtd, int section, + struct mtd_oob_region *oobregion) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + struct nand_ecc_ctrl *ecc = &chip->ecc; + + if (section || !ecc->total) + return -ERANGE; + + oobregion->length = ecc->total; + oobregion->offset = 12; + + return 0; +} + +static int qi_lb60_ooblayout_free(struct mtd_info *mtd, int section, + struct mtd_oob_region *oobregion) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + struct nand_ecc_ctrl *ecc = &chip->ecc; + + if (section) + return -ERANGE; + + oobregion->length = mtd->oobsize - ecc->total - 12; + oobregion->offset = 12 + ecc->total; + + return 0; +} + +const struct mtd_ooblayout_ops qi_lb60_ooblayout_ops = { + .ecc = qi_lb60_ooblayout_ecc, + .free = qi_lb60_ooblayout_free, +}; + static int jz4725b_ooblayout_ecc(struct mtd_info *mtd, int section, struct mtd_oob_region *oobregion) { @@ -247,7 +282,11 @@ static int ingenic_nand_attach_chip(struct nand_chip *chip) return -EINVAL; } - mtd_set_ooblayout(mtd, nfc->soc_info->oob_layout); + /* For legacy reasons we use a different layout on the qi,lb60 board. */ + if (of_machine_is_compatible("qi,lb60")) + mtd_set_ooblayout(mtd, &qi_lb60_ooblayout_ops); + else + mtd_set_ooblayout(mtd, nfc->soc_info->oob_layout); return 0; } -- cgit From e84950691bf7aec716ae671a8b6e82322df6d54a Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Tue, 19 Mar 2019 15:54:03 +0100 Subject: mtd: rawnand: ingenic: Move BBTs out of ECC area The generic layout for BBT markers will most likely overlap with our ECC bytes in the OOB, so move the BBT markers outside the OOB area. Signed-off-by: Paul Cercueil Signed-off-by: Miquel Raynal --- drivers/mtd/nand/raw/ingenic/ingenic_nand.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/mtd/nand/raw/ingenic/ingenic_nand.c b/drivers/mtd/nand/raw/ingenic/ingenic_nand.c index d32d68ef0dc7..ad0c905a03ba 100644 --- a/drivers/mtd/nand/raw/ingenic/ingenic_nand.c +++ b/drivers/mtd/nand/raw/ingenic/ingenic_nand.c @@ -282,6 +282,13 @@ static int ingenic_nand_attach_chip(struct nand_chip *chip) return -EINVAL; } + /* + * The generic layout for BBT markers will most likely overlap with our + * ECC bytes in the OOB, so move the BBT markers outside the OOB area. + */ + if (chip->bbt_options & NAND_BBT_USE_FLASH) + chip->bbt_options |= NAND_BBT_NO_OOB; + /* For legacy reasons we use a different layout on the qi,lb60 board. */ if (of_machine_is_compatible("qi,lb60")) mtd_set_ooblayout(mtd, &qi_lb60_ooblayout_ops); -- cgit From 6f0ce4dfc5a35bcb21f26d5347f4797fdde52810 Mon Sep 17 00:00:00 2001 From: Aditya Pakki Date: Mon, 18 Mar 2019 18:24:34 -0500 Subject: mtd: rawnand: vf610: Avoid a potential NULL pointer dereference of_match_device can return NULL if there is no matching device. Avoid a potential NULL pointer dereference by checking for the return value and passing the error upstream. Signed-off-by: Aditya Pakki Signed-off-by: Miquel Raynal --- drivers/mtd/nand/raw/vf610_nfc.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/mtd/nand/raw/vf610_nfc.c b/drivers/mtd/nand/raw/vf610_nfc.c index a662ca1970e5..6d43ddb3332f 100644 --- a/drivers/mtd/nand/raw/vf610_nfc.c +++ b/drivers/mtd/nand/raw/vf610_nfc.c @@ -850,6 +850,9 @@ static int vf610_nfc_probe(struct platform_device *pdev) } of_id = of_match_device(vf610_nfc_dt_ids, &pdev->dev); + if (!of_id) + return -ENODEV; + nfc->variant = (enum vf610_nfc_variant)of_id->data; for_each_available_child_of_node(nfc->dev->of_node, child) { -- cgit From d090c25028e9df186bb0d31379f7d5605c57fa79 Mon Sep 17 00:00:00 2001 From: Liang Yang Date: Thu, 21 Mar 2019 20:14:01 +0800 Subject: mtd: rawnand: meson: set oob layout ops Specify the oob layout operation to avoid no oob scheme defined for some nand flash. Fixes: 8fae856c5350 ("mtd: rawnand: meson: add support for Amlogic NAND flash controller") Signed-off-by: Liang Yang Tested-by: Martin Blumenstingl Signed-off-by: Miquel Raynal --- drivers/mtd/nand/raw/meson_nand.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/mtd/nand/raw/meson_nand.c b/drivers/mtd/nand/raw/meson_nand.c index 38db4fd61459..cb0b03e36a35 100644 --- a/drivers/mtd/nand/raw/meson_nand.c +++ b/drivers/mtd/nand/raw/meson_nand.c @@ -1188,6 +1188,8 @@ static int meson_nand_attach_chip(struct nand_chip *nand) return -EINVAL; } + mtd_set_ooblayout(mtd, &meson_ooblayout_ops); + ret = meson_nand_bch_mode(nand); if (ret) return -EINVAL; -- cgit From 377e517b5fa53590418a7b4c2206082d92434fa3 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Sun, 4 Nov 2018 14:43:37 +0100 Subject: mtd: nand: Add max_bad_eraseblocks_per_lun info to memorg NAND datasheets usually give the maximum number of bad blocks per LUN and this number can be used to help upper layers decide how much blocks they should reserve for bad block handling. Add a max_bad_eraseblocks_per_lun to the nand_memory_organization struct and update the NAND_MEMORG() macro (and its users) accordingly. We also provide a default mtd->_max_bad_blocks() implementation. Signed-off-by: Boris Brezillon Signed-off-by: Miquel Raynal Reviewed-by: Frieder Schrempf --- drivers/mtd/nand/core.c | 34 ++++++++++++++++++++++++++++++++++ drivers/mtd/nand/spi/gigadevice.c | 8 ++++---- drivers/mtd/nand/spi/macronix.c | 4 ++-- drivers/mtd/nand/spi/micron.c | 2 +- drivers/mtd/nand/spi/toshiba.c | 12 ++++++------ drivers/mtd/nand/spi/winbond.c | 4 ++-- include/linux/mtd/nand.h | 6 +++++- 7 files changed, 54 insertions(+), 16 deletions(-) diff --git a/drivers/mtd/nand/core.c b/drivers/mtd/nand/core.c index 9c9f8936b63b..b6de955ac8bf 100644 --- a/drivers/mtd/nand/core.c +++ b/drivers/mtd/nand/core.c @@ -173,6 +173,40 @@ int nanddev_mtd_erase(struct mtd_info *mtd, struct erase_info *einfo) } EXPORT_SYMBOL_GPL(nanddev_mtd_erase); +/** + * nanddev_mtd_max_bad_blocks() - Get the maximum number of bad eraseblock on + * a specific region of the NAND device + * @mtd: MTD device + * @offs: offset of the NAND region + * @len: length of the NAND region + * + * Default implementation for mtd->_max_bad_blocks(). Only works if + * nand->memorg.max_bad_eraseblocks_per_lun is > 0. + * + * Return: a positive number encoding the maximum number of eraseblocks on a + * portion of memory, a negative error code otherwise. + */ +int nanddev_mtd_max_bad_blocks(struct mtd_info *mtd, loff_t offs, size_t len) +{ + struct nand_device *nand = mtd_to_nanddev(mtd); + struct nand_pos pos, end; + unsigned int max_bb = 0; + + if (!nand->memorg.max_bad_eraseblocks_per_lun) + return -ENOTSUPP; + + nanddev_offs_to_pos(nand, offs, &pos); + nanddev_offs_to_pos(nand, offs + len, &end); + + for (nanddev_offs_to_pos(nand, offs, &pos); + nanddev_pos_cmp(&pos, &end) < 0; + nanddev_pos_next_lun(nand, &pos)) + max_bb += nand->memorg.max_bad_eraseblocks_per_lun; + + return max_bb; +} +EXPORT_SYMBOL_GPL(nanddev_mtd_max_bad_blocks); + /** * nanddev_init() - Initialize a NAND device * @nand: NAND device diff --git a/drivers/mtd/nand/spi/gigadevice.c b/drivers/mtd/nand/spi/gigadevice.c index 0b49d8264bef..e5586390026a 100644 --- a/drivers/mtd/nand/spi/gigadevice.c +++ b/drivers/mtd/nand/spi/gigadevice.c @@ -162,7 +162,7 @@ static const struct mtd_ooblayout_ops gd5fxgq4uexxg_ooblayout = { static const struct spinand_info gigadevice_spinand_table[] = { SPINAND_INFO("GD5F1GQ4xA", 0xF1, - NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1), + NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1), NAND_ECCREQ(8, 512), SPINAND_INFO_OP_VARIANTS(&read_cache_variants, &write_cache_variants, @@ -171,7 +171,7 @@ static const struct spinand_info gigadevice_spinand_table[] = { SPINAND_ECCINFO(&gd5fxgq4xa_ooblayout, gd5fxgq4xa_ecc_get_status)), SPINAND_INFO("GD5F2GQ4xA", 0xF2, - NAND_MEMORG(1, 2048, 64, 64, 2048, 1, 1, 1), + NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 1, 1, 1), NAND_ECCREQ(8, 512), SPINAND_INFO_OP_VARIANTS(&read_cache_variants, &write_cache_variants, @@ -180,7 +180,7 @@ static const struct spinand_info gigadevice_spinand_table[] = { SPINAND_ECCINFO(&gd5fxgq4xa_ooblayout, gd5fxgq4xa_ecc_get_status)), SPINAND_INFO("GD5F4GQ4xA", 0xF4, - NAND_MEMORG(1, 2048, 64, 64, 4096, 1, 1, 1), + NAND_MEMORG(1, 2048, 64, 64, 4096, 40, 1, 1, 1), NAND_ECCREQ(8, 512), SPINAND_INFO_OP_VARIANTS(&read_cache_variants, &write_cache_variants, @@ -189,7 +189,7 @@ static const struct spinand_info gigadevice_spinand_table[] = { SPINAND_ECCINFO(&gd5fxgq4xa_ooblayout, gd5fxgq4xa_ecc_get_status)), SPINAND_INFO("GD5F1GQ4UExxG", 0xd1, - NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1), + NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1), NAND_ECCREQ(8, 512), SPINAND_INFO_OP_VARIANTS(&read_cache_variants, &write_cache_variants, diff --git a/drivers/mtd/nand/spi/macronix.c b/drivers/mtd/nand/spi/macronix.c index d16b57081c95..6502727049a8 100644 --- a/drivers/mtd/nand/spi/macronix.c +++ b/drivers/mtd/nand/spi/macronix.c @@ -100,7 +100,7 @@ static int mx35lf1ge4ab_ecc_get_status(struct spinand_device *spinand, static const struct spinand_info macronix_spinand_table[] = { SPINAND_INFO("MX35LF1GE4AB", 0x12, - NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1), + NAND_MEMORG(1, 2048, 64, 64, 1024, 40, 1, 1, 1), NAND_ECCREQ(4, 512), SPINAND_INFO_OP_VARIANTS(&read_cache_variants, &write_cache_variants, @@ -109,7 +109,7 @@ static const struct spinand_info macronix_spinand_table[] = { SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, mx35lf1ge4ab_ecc_get_status)), SPINAND_INFO("MX35LF2GE4AB", 0x22, - NAND_MEMORG(1, 2048, 64, 64, 2048, 2, 1, 1), + NAND_MEMORG(1, 2048, 64, 64, 2048, 20, 2, 1, 1), NAND_ECCREQ(4, 512), SPINAND_INFO_OP_VARIANTS(&read_cache_variants, &write_cache_variants, diff --git a/drivers/mtd/nand/spi/micron.c b/drivers/mtd/nand/spi/micron.c index 9c4381d6847b..7d7b1f7fcf71 100644 --- a/drivers/mtd/nand/spi/micron.c +++ b/drivers/mtd/nand/spi/micron.c @@ -92,7 +92,7 @@ static int mt29f2g01abagd_ecc_get_status(struct spinand_device *spinand, static const struct spinand_info micron_spinand_table[] = { SPINAND_INFO("MT29F2G01ABAGD", 0x24, - NAND_MEMORG(1, 2048, 128, 64, 2048, 2, 1, 1), + NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 2, 1, 1), NAND_ECCREQ(8, 512), SPINAND_INFO_OP_VARIANTS(&read_cache_variants, &write_cache_variants, diff --git a/drivers/mtd/nand/spi/toshiba.c b/drivers/mtd/nand/spi/toshiba.c index db8021da45b5..1cb3760ff779 100644 --- a/drivers/mtd/nand/spi/toshiba.c +++ b/drivers/mtd/nand/spi/toshiba.c @@ -96,7 +96,7 @@ static int tc58cxgxsx_ecc_get_status(struct spinand_device *spinand, static const struct spinand_info toshiba_spinand_table[] = { /* 3.3V 1Gb */ SPINAND_INFO("TC58CVG0S3", 0xC2, - NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1), + NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1), NAND_ECCREQ(8, 512), SPINAND_INFO_OP_VARIANTS(&read_cache_variants, &write_cache_variants, @@ -106,7 +106,7 @@ static const struct spinand_info toshiba_spinand_table[] = { tc58cxgxsx_ecc_get_status)), /* 3.3V 2Gb */ SPINAND_INFO("TC58CVG1S3", 0xCB, - NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1), + NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1), NAND_ECCREQ(8, 512), SPINAND_INFO_OP_VARIANTS(&read_cache_variants, &write_cache_variants, @@ -116,7 +116,7 @@ static const struct spinand_info toshiba_spinand_table[] = { tc58cxgxsx_ecc_get_status)), /* 3.3V 4Gb */ SPINAND_INFO("TC58CVG2S0", 0xCD, - NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 1), + NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1), NAND_ECCREQ(8, 512), SPINAND_INFO_OP_VARIANTS(&read_cache_variants, &write_cache_variants, @@ -126,7 +126,7 @@ static const struct spinand_info toshiba_spinand_table[] = { tc58cxgxsx_ecc_get_status)), /* 1.8V 1Gb */ SPINAND_INFO("TC58CYG0S3", 0xB2, - NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1), + NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1), NAND_ECCREQ(8, 512), SPINAND_INFO_OP_VARIANTS(&read_cache_variants, &write_cache_variants, @@ -136,7 +136,7 @@ static const struct spinand_info toshiba_spinand_table[] = { tc58cxgxsx_ecc_get_status)), /* 1.8V 2Gb */ SPINAND_INFO("TC58CYG1S3", 0xBB, - NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1), + NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1), NAND_ECCREQ(8, 512), SPINAND_INFO_OP_VARIANTS(&read_cache_variants, &write_cache_variants, @@ -146,7 +146,7 @@ static const struct spinand_info toshiba_spinand_table[] = { tc58cxgxsx_ecc_get_status)), /* 1.8V 4Gb */ SPINAND_INFO("TC58CYG2S0", 0xBD, - NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 1), + NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1), NAND_ECCREQ(8, 512), SPINAND_INFO_OP_VARIANTS(&read_cache_variants, &write_cache_variants, diff --git a/drivers/mtd/nand/spi/winbond.c b/drivers/mtd/nand/spi/winbond.c index 5d944580b898..a6c17e0cace8 100644 --- a/drivers/mtd/nand/spi/winbond.c +++ b/drivers/mtd/nand/spi/winbond.c @@ -76,7 +76,7 @@ static int w25m02gv_select_target(struct spinand_device *spinand, static const struct spinand_info winbond_spinand_table[] = { SPINAND_INFO("W25M02GV", 0xAB, - NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 2), + NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 2), NAND_ECCREQ(1, 512), SPINAND_INFO_OP_VARIANTS(&read_cache_variants, &write_cache_variants, @@ -85,7 +85,7 @@ static const struct spinand_info winbond_spinand_table[] = { SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL), SPINAND_SELECT_TARGET(w25m02gv_select_target)), SPINAND_INFO("W25N01GV", 0xAA, - NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1), + NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1), NAND_ECCREQ(1, 512), SPINAND_INFO_OP_VARIANTS(&read_cache_variants, &write_cache_variants, diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 7f53ece2c039..d32bb623d532 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -19,6 +19,7 @@ * @oobsize: OOB area size * @pages_per_eraseblock: number of pages per eraseblock * @eraseblocks_per_lun: number of eraseblocks per LUN (Logical Unit Number) + * @max_bad_eraseblocks_per_lun: maximum number of eraseblocks per LUN * @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 @@ -29,18 +30,20 @@ struct nand_memory_organization { unsigned int oobsize; unsigned int pages_per_eraseblock; unsigned int eraseblocks_per_lun; + unsigned int max_bad_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) \ +#define NAND_MEMORG(bpc, ps, os, ppe, epl, mbb, ppl, lpt, nt) \ { \ .bits_per_cell = (bpc), \ .pagesize = (ps), \ .oobsize = (os), \ .pages_per_eraseblock = (ppe), \ .eraseblocks_per_lun = (epl), \ + .max_bad_eraseblocks_per_lun = (mbb), \ .planes_per_lun = (ppl), \ .luns_per_target = (lpt), \ .ntargets = (nt), \ @@ -729,5 +732,6 @@ static inline bool nanddev_bbt_is_initialized(struct nand_device *nand) /* MTD -> NAND helper functions. */ int nanddev_mtd_erase(struct mtd_info *mtd, struct erase_info *einfo); +int nanddev_mtd_max_bad_blocks(struct mtd_info *mtd, loff_t offs, size_t len); #endif /* __LINUX_MTD_NAND_H */ -- cgit From 7c4ecca103b3d70c50adc693c9f5d39d292e13e0 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Mon, 29 Oct 2018 10:29:48 +0100 Subject: mtd: nand: Add a helper returning the number of eraseblocks per target Some drivers in the raw NAND framework seems to need this helper, so let's just add it instead of open-coding the logic. Signed-off-by: Boris Brezillon Signed-off-by: Miquel Raynal Reviewed-by: Frieder Schrempf --- include/linux/mtd/nand.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index d32bb623d532..12d75402472a 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -294,6 +294,18 @@ nanddev_eraseblocks_per_lun(const struct nand_device *nand) return nand->memorg.eraseblocks_per_lun; } +/** + * nanddev_eraseblocks_per_target() - Get the number of eraseblocks per target + * @nand: NAND device + * + * Return: the number of eraseblocks per target. + */ +static inline unsigned int +nanddev_eraseblocks_per_target(const struct nand_device *nand) +{ + return nand->memorg.eraseblocks_per_lun * nand->memorg.luns_per_target; +} + /** * nanddev_target_size() - Get the total size provided by a single target/die * @nand: NAND device -- cgit From 46b01d7efda29356d4dff88825e5ef51dd9f6bae Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Mon, 29 Oct 2018 17:18:39 +0100 Subject: mtd: nand: Add a helper to retrieve the number of pages per target Will be used by the raw NAND framework. Signed-off-by: Boris Brezillon Signed-off-by: Miquel Raynal Reviewed-by: Frieder Schrempf --- include/linux/mtd/nand.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 12d75402472a..cebc38b6d6f5 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -271,6 +271,20 @@ nanddev_pages_per_eraseblock(const struct nand_device *nand) return nand->memorg.pages_per_eraseblock; } +/** + * nanddev_pages_per_target() - Get the number of pages per target + * @nand: NAND device + * + * Return: the number of pages per target. + */ +static inline unsigned int +nanddev_pages_per_target(const struct nand_device *nand) +{ + return nand->memorg.pages_per_eraseblock * + nand->memorg.eraseblocks_per_lun * + nand->memorg.luns_per_target; +} + /** * nanddev_per_page_oobsize() - Get NAND erase block size * @nand: NAND device -- cgit From 509198485bf2600f4104fdf391b8632cf69f2dd8 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Sun, 4 Nov 2018 14:45:57 +0100 Subject: mtd: spinand: Implement mtd->_max_bad_blocks We just have to use nanddev_mtd_max_bad_blocks(). Signed-off-by: Boris Brezillon Signed-off-by: Miquel Raynal Reviewed-by: Frieder Schrempf --- drivers/mtd/nand/spi/core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c index fa54fe446b2d..4c15bb58c623 100644 --- a/drivers/mtd/nand/spi/core.c +++ b/drivers/mtd/nand/spi/core.c @@ -1037,6 +1037,7 @@ static int spinand_init(struct spinand_device *spinand) mtd->_block_markbad = spinand_mtd_block_markbad; mtd->_block_isreserved = spinand_mtd_block_isreserved; mtd->_erase = spinand_mtd_erase; + mtd->_max_bad_blocks = nanddev_mtd_max_bad_blocks; if (spinand->eccinfo.ooblayout) mtd_set_ooblayout(mtd, spinand->eccinfo.ooblayout); -- cgit From 080d66e94d69a5b1d197ac411db6c27700868af8 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Thu, 25 Oct 2018 15:05:39 +0200 Subject: mtd: rawnand: Use nand_to_mtd() in nand_{set,get}_flash_node() Use the nand_to_mtd() helper to access chip->mtd as done everywhere else. Signed-off-by: Boris Brezillon Signed-off-by: Miquel Raynal Reviewed-by: Frieder Schrempf --- include/linux/mtd/rawnand.h | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h index b7445a44a814..d5c7741c0901 100644 --- a/include/linux/mtd/rawnand.h +++ b/include/linux/mtd/rawnand.h @@ -1105,17 +1105,6 @@ struct nand_chip { extern const struct mtd_ooblayout_ops nand_ooblayout_sp_ops; extern const struct mtd_ooblayout_ops nand_ooblayout_lp_ops; -static inline void nand_set_flash_node(struct nand_chip *chip, - struct device_node *np) -{ - mtd_set_of_node(&chip->mtd, np); -} - -static inline struct device_node *nand_get_flash_node(struct nand_chip *chip) -{ - return mtd_get_of_node(&chip->mtd); -} - static inline struct nand_chip *mtd_to_nand(struct mtd_info *mtd) { return container_of(mtd, struct nand_chip, mtd); @@ -1147,6 +1136,17 @@ static inline void *nand_get_manufacturer_data(struct nand_chip *chip) return chip->manufacturer.priv; } +static inline void nand_set_flash_node(struct nand_chip *chip, + struct device_node *np) +{ + mtd_set_of_node(nand_to_mtd(chip), np); +} + +static inline struct device_node *nand_get_flash_node(struct nand_chip *chip) +{ + return mtd_get_of_node(nand_to_mtd(chip)); +} + /* * A helper for defining older NAND chips where the second ID byte fully * defined the chip, including the geometry (chip size, eraseblock size, page -- cgit From 3020e30af6f81beedfeb4cf4eecc693bba55a6c2 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Thu, 25 Oct 2018 15:21:08 +0200 Subject: mtd: rawnand: Prepare things to reuse the generic NAND layer The generic NAND layer provides abstraction of NAND devices no matter the bus that is used to communicate with the chip. Basing the raw NAND core on this generic layer should avoid duplication of common operations, like iterating over all pages/blocks for MTD IO/erase operations. In order to re-use this layer, we must first inherit from nand_device and then initialize the nand_device struct appropriately. This patch is taking care of the former. Signed-off-by: Boris Brezillon Signed-off-by: Miquel Raynal Reviewed-by: Frieder Schrempf --- include/linux/mtd/rawnand.h | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h index d5c7741c0901..58887cb2c7ea 100644 --- a/include/linux/mtd/rawnand.h +++ b/include/linux/mtd/rawnand.h @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -860,6 +861,7 @@ struct nand_operation { int nand_op_parser_exec_op(struct nand_chip *chip, const struct nand_op_parser *parser, const struct nand_operation *op, bool check_only); + /** * struct nand_controller_ops - Controller operations * @@ -962,7 +964,7 @@ struct nand_legacy { /** * struct nand_chip - NAND Private Flash Chip Data - * @mtd: MTD device registered to the MTD framework + * @base: Inherit from the generic NAND device * @legacy: All legacy fields/hooks. If you develop a new driver, * don't even try to use any of these fields/hooks, and if * you're modifying an existing driver that is using those @@ -1041,7 +1043,7 @@ struct nand_legacy { */ struct nand_chip { - struct mtd_info mtd; + struct nand_device base; struct nand_legacy legacy; @@ -1107,12 +1109,12 @@ extern const struct mtd_ooblayout_ops nand_ooblayout_lp_ops; static inline struct nand_chip *mtd_to_nand(struct mtd_info *mtd) { - return container_of(mtd, struct nand_chip, mtd); + return container_of(mtd, struct nand_chip, base.mtd); } static inline struct mtd_info *nand_to_mtd(struct nand_chip *chip) { - return &chip->mtd; + return &chip->base.mtd; } static inline void *nand_get_controller_data(struct nand_chip *chip) -- cgit From 629a442cad5facbebc204ff81e1974f8febab636 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Thu, 25 Oct 2018 17:10:37 +0200 Subject: mtd: rawnand: Fill memorg during detection If we want to use the generic NAND layer, we need to have the memorg struct appropriately filled. Patch the detection code to fill this struct. Signed-off-by: Boris Brezillon Reviewed-by: Frieder Schrempf Signed-off-by: Miquel Raynal --- drivers/mtd/nand/raw/denali.c | 5 +++ drivers/mtd/nand/raw/diskonchip.c | 4 ++ drivers/mtd/nand/raw/ingenic/jz4740_nand.c | 4 ++ drivers/mtd/nand/raw/nand_amd.c | 11 +++-- drivers/mtd/nand/raw/nand_base.c | 64 +++++++++++++++++++++++++++--- drivers/mtd/nand/raw/nand_hynix.c | 48 ++++++++++++++-------- drivers/mtd/nand/raw/nand_jedec.c | 22 +++++++--- drivers/mtd/nand/raw/nand_onfi.c | 23 ++++++++--- drivers/mtd/nand/raw/nand_samsung.c | 24 +++++++---- drivers/mtd/nand/raw/nand_toshiba.c | 9 ++++- drivers/mtd/nand/raw/nandsim.c | 5 +++ 11 files changed, 175 insertions(+), 44 deletions(-) diff --git a/drivers/mtd/nand/raw/denali.c b/drivers/mtd/nand/raw/denali.c index 24aeafc67cd4..e99d59d85197 100644 --- a/drivers/mtd/nand/raw/denali.c +++ b/drivers/mtd/nand/raw/denali.c @@ -1096,6 +1096,9 @@ static int denali_multidev_fixup(struct denali_nand_info *denali) { struct nand_chip *chip = &denali->nand; struct mtd_info *mtd = nand_to_mtd(chip); + struct nand_memory_organization *memorg; + + memorg = nanddev_get_memorg(&chip->base); /* * Support for multi device: @@ -1125,6 +1128,8 @@ static int denali_multidev_fixup(struct denali_nand_info *denali) } /* 2 chips in parallel */ + memorg->pagesize <<= 1; + memorg->oobsize <<= 1; mtd->size <<= 1; mtd->erasesize <<= 1; mtd->writesize <<= 1; diff --git a/drivers/mtd/nand/raw/diskonchip.c b/drivers/mtd/nand/raw/diskonchip.c index ead54c90f2d1..2e0da6a24bfd 100644 --- a/drivers/mtd/nand/raw/diskonchip.c +++ b/drivers/mtd/nand/raw/diskonchip.c @@ -1028,6 +1028,7 @@ static inline int __init nftl_partscan(struct mtd_info *mtd, struct mtd_partitio { struct nand_chip *this = mtd_to_nand(mtd); struct doc_priv *doc = nand_get_controller_data(this); + struct nand_memory_organization *memorg; int ret = 0; u_char *buf; struct NFTLMediaHeader *mh; @@ -1036,6 +1037,8 @@ static inline int __init nftl_partscan(struct mtd_info *mtd, struct mtd_partitio unsigned blocks, maxblocks; int offs, numheaders; + memorg = nanddev_get_memorg(&this->base); + buf = kmalloc(mtd->writesize, GFP_KERNEL); if (!buf) { return 0; @@ -1082,6 +1085,7 @@ static inline int __init nftl_partscan(struct mtd_info *mtd, struct mtd_partitio implementation of the NAND layer. */ if (mh->UnitSizeFactor != 0xff) { this->bbt_erase_shift += (0xff - mh->UnitSizeFactor); + memorg->pages_per_eraseblock <<= (0xff - mh->UnitSizeFactor); mtd->erasesize <<= (0xff - mh->UnitSizeFactor); pr_info("Setting virtual erase size to %d\n", mtd->erasesize); blocks = mtd->size >> this->bbt_erase_shift; diff --git a/drivers/mtd/nand/raw/ingenic/jz4740_nand.c b/drivers/mtd/nand/raw/ingenic/jz4740_nand.c index 9526d5b23c80..d5715dde4237 100644 --- a/drivers/mtd/nand/raw/ingenic/jz4740_nand.c +++ b/drivers/mtd/nand/raw/ingenic/jz4740_nand.c @@ -313,8 +313,11 @@ static int jz_nand_detect_bank(struct platform_device *pdev, uint32_t ctrl; struct nand_chip *chip = &nand->chip; struct mtd_info *mtd = nand_to_mtd(chip); + struct nand_memory_organization *memorg; u8 id[2]; + memorg = nanddev_get_memorg(&chip->base); + /* Request I/O resource. */ sprintf(res_name, "bank%d", bank); ret = jz_nand_ioremap_resource(pdev, res_name, @@ -352,6 +355,7 @@ static int jz_nand_detect_bank(struct platform_device *pdev, /* Update size of the MTD. */ chip->numchips++; + memorg->ntargets++; mtd->size += chip->chipsize; } diff --git a/drivers/mtd/nand/raw/nand_amd.c b/drivers/mtd/nand/raw/nand_amd.c index 890c5b43e03c..e008fd662ee6 100644 --- a/drivers/mtd/nand/raw/nand_amd.c +++ b/drivers/mtd/nand/raw/nand_amd.c @@ -20,6 +20,9 @@ static void amd_nand_decode_id(struct nand_chip *chip) { struct mtd_info *mtd = nand_to_mtd(chip); + struct nand_memory_organization *memorg; + + memorg = nanddev_get_memorg(&chip->base); nand_decode_ext_id(chip); @@ -31,9 +34,11 @@ static void amd_nand_decode_id(struct nand_chip *chip) */ if (chip->id.data[4] != 0x00 && chip->id.data[5] == 0x00 && chip->id.data[6] == 0x00 && chip->id.data[7] == 0x00 && - mtd->writesize == 512) { - mtd->erasesize = 128 * 1024; - mtd->erasesize <<= ((chip->id.data[3] & 0x03) << 1); + memorg->pagesize == 512) { + memorg->pages_per_eraseblock = 256; + memorg->pages_per_eraseblock <<= ((chip->id.data[3] & 0x03) << 1); + mtd->erasesize = memorg->pages_per_eraseblock * + memorg->pagesize; } } diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c index ddd396e93e32..dbe3d96b74da 100644 --- a/drivers/mtd/nand/raw/nand_base.c +++ b/drivers/mtd/nand/raw/nand_base.c @@ -4485,21 +4485,30 @@ static int nand_get_bits_per_cell(u8 cellinfo) */ void nand_decode_ext_id(struct nand_chip *chip) { + struct nand_memory_organization *memorg; struct mtd_info *mtd = nand_to_mtd(chip); int extid; u8 *id_data = chip->id.data; + + memorg = nanddev_get_memorg(&chip->base); + /* The 3rd id byte holds MLC / multichip data */ + memorg->bits_per_cell = nand_get_bits_per_cell(id_data[2]); chip->bits_per_cell = nand_get_bits_per_cell(id_data[2]); /* The 4th id byte is the important one */ extid = id_data[3]; /* Calc pagesize */ - mtd->writesize = 1024 << (extid & 0x03); + memorg->pagesize = 1024 << (extid & 0x03); + mtd->writesize = memorg->pagesize; extid >>= 2; /* Calc oobsize */ - mtd->oobsize = (8 << (extid & 0x01)) * (mtd->writesize >> 9); + memorg->oobsize = (8 << (extid & 0x01)) * (mtd->writesize >> 9); + mtd->oobsize = memorg->oobsize; extid >>= 2; /* Calc blocksize. Blocksize is multiples of 64KiB */ + memorg->pages_per_eraseblock = ((64 * 1024) << (extid & 0x03)) / + memorg->pagesize; mtd->erasesize = (64 * 1024) << (extid & 0x03); extid >>= 2; /* Get buswidth information */ @@ -4516,12 +4525,19 @@ EXPORT_SYMBOL_GPL(nand_decode_ext_id); static void nand_decode_id(struct nand_chip *chip, struct nand_flash_dev *type) { struct mtd_info *mtd = nand_to_mtd(chip); + struct nand_memory_organization *memorg; + + memorg = nanddev_get_memorg(&chip->base); + memorg->pages_per_eraseblock = type->erasesize / type->pagesize; mtd->erasesize = type->erasesize; - mtd->writesize = type->pagesize; - mtd->oobsize = mtd->writesize / 32; + memorg->pagesize = type->pagesize; + mtd->writesize = memorg->pagesize; + memorg->oobsize = memorg->pagesize / 32; + mtd->oobsize = memorg->oobsize; /* All legacy ID NAND are small-page, SLC */ + memorg->bits_per_cell = 1; chip->bits_per_cell = 1; } @@ -4550,15 +4566,27 @@ static bool find_full_id_nand(struct nand_chip *chip, struct nand_flash_dev *type) { struct mtd_info *mtd = nand_to_mtd(chip); + struct nand_memory_organization *memorg; u8 *id_data = chip->id.data; + memorg = nanddev_get_memorg(&chip->base); + if (!strncmp(type->id, id_data, type->id_len)) { - mtd->writesize = type->pagesize; + memorg->pagesize = type->pagesize; + mtd->writesize = memorg->pagesize; + memorg->pages_per_eraseblock = type->erasesize / + type->pagesize; mtd->erasesize = type->erasesize; - mtd->oobsize = type->oobsize; + memorg->oobsize = type->oobsize; + mtd->oobsize = memorg->oobsize; + memorg->bits_per_cell = nand_get_bits_per_cell(id_data[2]); chip->bits_per_cell = nand_get_bits_per_cell(id_data[2]); chip->chipsize = (uint64_t)type->chipsize << 20; + memorg->eraseblocks_per_lun = + DIV_ROUND_DOWN_ULL((u64)type->chipsize << 20, + memorg->pagesize * + memorg->pages_per_eraseblock); chip->options |= type->options; chip->ecc_strength_ds = NAND_ECC_STRENGTH(type); chip->ecc_step_ds = NAND_ECC_STEP(type); @@ -4587,7 +4615,12 @@ static void nand_manufacturer_detect(struct nand_chip *chip) */ if (chip->manufacturer.desc && chip->manufacturer.desc->ops && chip->manufacturer.desc->ops->detect) { + struct nand_memory_organization *memorg; + + memorg = nanddev_get_memorg(&chip->base); + /* The 3rd id byte holds MLC / multichip data */ + memorg->bits_per_cell = nand_get_bits_per_cell(chip->id.data[2]); chip->bits_per_cell = nand_get_bits_per_cell(chip->id.data[2]); chip->manufacturer.desc->ops->detect(chip); } else { @@ -4637,10 +4670,20 @@ static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type) { const struct nand_manufacturer *manufacturer; struct mtd_info *mtd = nand_to_mtd(chip); + struct nand_memory_organization *memorg; int busw, ret; u8 *id_data = chip->id.data; u8 maf_id, dev_id; + /* + * Let's start by initializing memorg fields that might be left + * unassigned by the ID-based detection logic. + */ + memorg = nanddev_get_memorg(&chip->base); + memorg->planes_per_lun = 1; + memorg->luns_per_target = 1; + memorg->ntargets = 1; + /* * Reset the chip, required by some chips (e.g. Micron MT29FxGxxxxx) * after power-up. @@ -4745,6 +4788,11 @@ static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type) /* Get chip options */ chip->options |= type->options; + memorg->eraseblocks_per_lun = + DIV_ROUND_DOWN_ULL((u64)type->chipsize << 20, + memorg->pagesize * + memorg->pages_per_eraseblock); + ident_done: if (!mtd->name) mtd->name = chip->parameters.model; @@ -4971,10 +5019,13 @@ static int nand_scan_ident(struct nand_chip *chip, unsigned int maxchips, struct nand_flash_dev *table) { struct mtd_info *mtd = nand_to_mtd(chip); + struct nand_memory_organization *memorg; int nand_maf_id, nand_dev_id; unsigned int i; int ret; + memorg = nanddev_get_memorg(&chip->base); + /* Assume all dies are deselected when we enter nand_scan_ident(). */ chip->cur_cs = -1; @@ -5042,6 +5093,7 @@ static int nand_scan_ident(struct nand_chip *chip, unsigned int maxchips, pr_info("%d chips detected\n", i); /* Store the number of chips and calc total size for mtd */ + memorg->ntargets = i; chip->numchips = i; mtd->size = i * chip->chipsize; diff --git a/drivers/mtd/nand/raw/nand_hynix.c b/drivers/mtd/nand/raw/nand_hynix.c index 343f477362d1..94ea8c593589 100644 --- a/drivers/mtd/nand/raw/nand_hynix.c +++ b/drivers/mtd/nand/raw/nand_hynix.c @@ -418,24 +418,27 @@ static void hynix_nand_extract_oobsize(struct nand_chip *chip, bool valid_jedecid) { struct mtd_info *mtd = nand_to_mtd(chip); + struct nand_memory_organization *memorg; u8 oobsize; + memorg = nanddev_get_memorg(&chip->base); + oobsize = ((chip->id.data[3] >> 2) & 0x3) | ((chip->id.data[3] >> 4) & 0x4); if (valid_jedecid) { switch (oobsize) { case 0: - mtd->oobsize = 2048; + memorg->oobsize = 2048; break; case 1: - mtd->oobsize = 1664; + memorg->oobsize = 1664; break; case 2: - mtd->oobsize = 1024; + memorg->oobsize = 1024; break; case 3: - mtd->oobsize = 640; + memorg->oobsize = 640; break; default: /* @@ -450,25 +453,25 @@ static void hynix_nand_extract_oobsize(struct nand_chip *chip, } else { switch (oobsize) { case 0: - mtd->oobsize = 128; + memorg->oobsize = 128; break; case 1: - mtd->oobsize = 224; + memorg->oobsize = 224; break; case 2: - mtd->oobsize = 448; + memorg->oobsize = 448; break; case 3: - mtd->oobsize = 64; + memorg->oobsize = 64; break; case 4: - mtd->oobsize = 32; + memorg->oobsize = 32; break; case 5: - mtd->oobsize = 16; + memorg->oobsize = 16; break; case 6: - mtd->oobsize = 640; + memorg->oobsize = 640; break; default: /* @@ -492,8 +495,10 @@ static void hynix_nand_extract_oobsize(struct nand_chip *chip, * the actual OOB size for this chip is: 640 * 16k / 8k). */ if (chip->id.data[1] == 0xde) - mtd->oobsize *= mtd->writesize / SZ_8K; + memorg->oobsize *= memorg->pagesize / SZ_8K; } + + mtd->oobsize = memorg->oobsize; } static void hynix_nand_extract_ecc_requirements(struct nand_chip *chip, @@ -609,9 +614,12 @@ static void hynix_nand_extract_scrambling_requirements(struct nand_chip *chip, static void hynix_nand_decode_id(struct nand_chip *chip) { struct mtd_info *mtd = nand_to_mtd(chip); + struct nand_memory_organization *memorg; bool valid_jedecid; u8 tmp; + memorg = nanddev_get_memorg(&chip->base); + /* * Exclude all SLC NANDs from this advanced detection scheme. * According to the ranges defined in several datasheets, it might @@ -625,7 +633,8 @@ static void hynix_nand_decode_id(struct nand_chip *chip) } /* Extract pagesize */ - mtd->writesize = 2048 << (chip->id.data[3] & 0x03); + memorg->pagesize = 2048 << (chip->id.data[3] & 0x03); + mtd->writesize = memorg->pagesize; tmp = (chip->id.data[3] >> 4) & 0x3; /* @@ -635,12 +644,19 @@ static void hynix_nand_decode_id(struct nand_chip *chip) * The only exception is when ID[3][4:5] == 3 and ID[3][7] == 0, in * this case the erasesize is set to 768KiB. */ - if (chip->id.data[3] & 0x80) + if (chip->id.data[3] & 0x80) { + memorg->pages_per_eraseblock = (SZ_1M << tmp) / + memorg->pagesize; mtd->erasesize = SZ_1M << tmp; - else if (tmp == 3) + } else if (tmp == 3) { + memorg->pages_per_eraseblock = (SZ_512K + SZ_256K) / + memorg->pagesize; mtd->erasesize = SZ_512K + SZ_256K; - else + } else { + memorg->pages_per_eraseblock = (SZ_128K << tmp) / + memorg->pagesize; mtd->erasesize = SZ_128K << tmp; + } /* * Modern Toggle DDR NANDs have a valid JEDECID even though they are diff --git a/drivers/mtd/nand/raw/nand_jedec.c b/drivers/mtd/nand/raw/nand_jedec.c index 38b5dc22cb30..61e33ee7ee19 100644 --- a/drivers/mtd/nand/raw/nand_jedec.c +++ b/drivers/mtd/nand/raw/nand_jedec.c @@ -22,12 +22,15 @@ int nand_jedec_detect(struct nand_chip *chip) { struct mtd_info *mtd = nand_to_mtd(chip); + struct nand_memory_organization *memorg; struct nand_jedec_params *p; struct jedec_ecc_info *ecc; int jedec_version = 0; char id[5]; int i, val, ret; + memorg = nanddev_get_memorg(&chip->base); + /* Try JEDEC for unknown chip or LP */ ret = nand_readid_op(chip, 0x40, id, sizeof(id)); if (ret || strncmp(id, "JEDEC", sizeof(id))) @@ -81,17 +84,26 @@ int nand_jedec_detect(struct nand_chip *chip) goto free_jedec_param_page; } - mtd->writesize = le32_to_cpu(p->byte_per_page); + memorg->pagesize = le32_to_cpu(p->byte_per_page); + mtd->writesize = memorg->pagesize; /* Please reference to the comment for nand_flash_detect_onfi. */ - mtd->erasesize = 1 << (fls(le32_to_cpu(p->pages_per_block)) - 1); - mtd->erasesize *= mtd->writesize; + memorg->pages_per_eraseblock = + 1 << (fls(le32_to_cpu(p->pages_per_block)) - 1); + mtd->erasesize = memorg->pages_per_eraseblock * memorg->pagesize; + + memorg->oobsize = le16_to_cpu(p->spare_bytes_per_page); + mtd->oobsize = memorg->oobsize; - mtd->oobsize = le16_to_cpu(p->spare_bytes_per_page); + memorg->luns_per_target = p->lun_count; + memorg->planes_per_lun = 1 << p->multi_plane_addr; /* Please reference to the comment for nand_flash_detect_onfi. */ - chip->chipsize = 1 << (fls(le32_to_cpu(p->blocks_per_lun)) - 1); + memorg->eraseblocks_per_lun = + 1 << (fls(le32_to_cpu(p->blocks_per_lun)) - 1); + chip->chipsize = memorg->eraseblocks_per_lun; chip->chipsize *= (uint64_t)mtd->erasesize * p->lun_count; + memorg->bits_per_cell = p->bits_per_cell; chip->bits_per_cell = p->bits_per_cell; if (le16_to_cpu(p->features) & JEDEC_FEATURE_16_BIT_BUS) diff --git a/drivers/mtd/nand/raw/nand_onfi.c b/drivers/mtd/nand/raw/nand_onfi.c index d8184cf591ad..f3f59cf37d7f 100644 --- a/drivers/mtd/nand/raw/nand_onfi.c +++ b/drivers/mtd/nand/raw/nand_onfi.c @@ -140,12 +140,15 @@ static void nand_bit_wise_majority(const void **srcbufs, int nand_onfi_detect(struct nand_chip *chip) { struct mtd_info *mtd = nand_to_mtd(chip); + struct nand_memory_organization *memorg; struct nand_onfi_params *p; struct onfi_params *onfi; int onfi_version = 0; char id[4]; int i, ret, val; + memorg = nanddev_get_memorg(&chip->base); + /* Try ONFI for unknown chip or LP */ ret = nand_readid_op(chip, 0x20, id, sizeof(id)); if (ret || strncmp(id, "ONFI", 4)) @@ -221,21 +224,31 @@ int nand_onfi_detect(struct nand_chip *chip) goto free_onfi_param_page; } - mtd->writesize = le32_to_cpu(p->byte_per_page); + memorg->pagesize = le32_to_cpu(p->byte_per_page); + mtd->writesize = memorg->pagesize; /* * pages_per_block and blocks_per_lun may not be a power-of-2 size * (don't ask me who thought of this...). MTD assumes that these * dimensions will be power-of-2, so just truncate the remaining area. */ - mtd->erasesize = 1 << (fls(le32_to_cpu(p->pages_per_block)) - 1); - mtd->erasesize *= mtd->writesize; + memorg->pages_per_eraseblock = + 1 << (fls(le32_to_cpu(p->pages_per_block)) - 1); + mtd->erasesize = memorg->pages_per_eraseblock * memorg->pagesize; + + memorg->oobsize = le16_to_cpu(p->spare_bytes_per_page); + mtd->oobsize = memorg->oobsize; - mtd->oobsize = le16_to_cpu(p->spare_bytes_per_page); + memorg->luns_per_target = p->lun_count; + memorg->planes_per_lun = 1 << p->interleaved_bits; /* See erasesize comment */ - chip->chipsize = 1 << (fls(le32_to_cpu(p->blocks_per_lun)) - 1); + memorg->eraseblocks_per_lun = + 1 << (fls(le32_to_cpu(p->blocks_per_lun)) - 1); + memorg->max_bad_eraseblocks_per_lun = le32_to_cpu(p->blocks_per_lun); + chip->chipsize = memorg->eraseblocks_per_lun; chip->chipsize *= (uint64_t)mtd->erasesize * p->lun_count; + memorg->bits_per_cell = p->bits_per_cell; chip->bits_per_cell = p->bits_per_cell; chip->max_bb_per_die = le16_to_cpu(p->bb_per_lun); diff --git a/drivers/mtd/nand/raw/nand_samsung.c b/drivers/mtd/nand/raw/nand_samsung.c index e46d4c492ad8..9a9ad43cc97d 100644 --- a/drivers/mtd/nand/raw/nand_samsung.c +++ b/drivers/mtd/nand/raw/nand_samsung.c @@ -20,6 +20,9 @@ static void samsung_nand_decode_id(struct nand_chip *chip) { struct mtd_info *mtd = nand_to_mtd(chip); + struct nand_memory_organization *memorg; + + memorg = nanddev_get_memorg(&chip->base); /* New Samsung (6 byte ID): Samsung K9GAG08U0F (p.44) */ if (chip->id.len == 6 && !nand_is_slc(chip) && @@ -27,29 +30,30 @@ static void samsung_nand_decode_id(struct nand_chip *chip) u8 extid = chip->id.data[3]; /* Get pagesize */ - mtd->writesize = 2048 << (extid & 0x03); + memorg->pagesize = 2048 << (extid & 0x03); + mtd->writesize = memorg->pagesize; extid >>= 2; /* Get oobsize */ switch (((extid >> 2) & 0x4) | (extid & 0x3)) { case 1: - mtd->oobsize = 128; + memorg->oobsize = 128; break; case 2: - mtd->oobsize = 218; + memorg->oobsize = 218; break; case 3: - mtd->oobsize = 400; + memorg->oobsize = 400; break; case 4: - mtd->oobsize = 436; + memorg->oobsize = 436; break; case 5: - mtd->oobsize = 512; + memorg->oobsize = 512; break; case 6: - mtd->oobsize = 640; + memorg->oobsize = 640; break; default: /* @@ -62,8 +66,14 @@ static void samsung_nand_decode_id(struct nand_chip *chip) break; } + mtd->oobsize = memorg->oobsize; + /* Get blocksize */ extid >>= 2; + memorg->pages_per_eraseblock = (128 * 1024) << + (((extid >> 1) & 0x04) | + (extid & 0x03)) / + memorg->pagesize; mtd->erasesize = (128 * 1024) << (((extid >> 1) & 0x04) | (extid & 0x03)); diff --git a/drivers/mtd/nand/raw/nand_toshiba.c b/drivers/mtd/nand/raw/nand_toshiba.c index d068163b64b3..d8465049dfd6 100644 --- a/drivers/mtd/nand/raw/nand_toshiba.c +++ b/drivers/mtd/nand/raw/nand_toshiba.c @@ -101,6 +101,9 @@ static void toshiba_nand_benand_init(struct nand_chip *chip) static void toshiba_nand_decode_id(struct nand_chip *chip) { struct mtd_info *mtd = nand_to_mtd(chip); + struct nand_memory_organization *memorg; + + memorg = nanddev_get_memorg(&chip->base); nand_decode_ext_id(chip); @@ -114,8 +117,10 @@ static void toshiba_nand_decode_id(struct nand_chip *chip) */ if (chip->id.len >= 6 && nand_is_slc(chip) && (chip->id.data[5] & 0x7) == 0x6 /* 24nm */ && - !(chip->id.data[4] & 0x80) /* !BENAND */) - mtd->oobsize = 32 * mtd->writesize >> 9; + !(chip->id.data[4] & 0x80) /* !BENAND */) { + memorg->oobsize = 32 * memorg->pagesize >> 9; + mtd->oobsize = memorg->oobsize; + } /* * Extract ECC requirements from 6th id byte. diff --git a/drivers/mtd/nand/raw/nandsim.c b/drivers/mtd/nand/raw/nandsim.c index edf5fd3d5f07..bf54733f8b5b 100644 --- a/drivers/mtd/nand/raw/nandsim.c +++ b/drivers/mtd/nand/raw/nandsim.c @@ -2304,6 +2304,10 @@ static int __init ns_init_module(void) if (overridesize) { uint64_t new_size = (uint64_t)nsmtd->erasesize << overridesize; + struct nand_memory_organization *memorg; + + memorg = nanddev_get_memorg(&chip->base); + if (new_size >> overridesize != nsmtd->erasesize) { NS_ERR("overridesize is too big\n"); retval = -EINVAL; @@ -2311,6 +2315,7 @@ static int __init ns_init_module(void) } /* N.B. This relies on nand_scan not doing anything with the size before we change it */ nsmtd->size = new_size; + memorg->eraseblocks_per_lun = 1 << overridesize; chip->chipsize = new_size; chip->chip_shift = ffs(nsmtd->erasesize) + overridesize - 1; chip->pagemask = (chip->chipsize >> chip->page_shift) - 1; -- cgit From a7ab085d7c16a7367a0c93ee39d0750d23b537f9 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Thu, 25 Oct 2018 22:10:36 +0200 Subject: mtd: rawnand: Initialize the nand_device object In order to use some of the nanddev_xxx() helpers, we need to initialize the nand_device object embedded in nand_chip using nanddev_init(). This requires implementing nand_ops. We also drop useless mtd->xxx initialization when they're already taken case of by nanddev_init(). Signed-off-by: Boris Brezillon Signed-off-by: Miquel Raynal Reviewed-by: Frieder Schrempf --- drivers/mtd/nand/raw/Kconfig | 1 + drivers/mtd/nand/raw/nand_base.c | 65 +++++++++++++++++++++++++++++++++++----- 2 files changed, 59 insertions(+), 7 deletions(-) diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig index 705863c6709a..80b5fec1f75a 100644 --- a/drivers/mtd/nand/raw/Kconfig +++ b/drivers/mtd/nand/raw/Kconfig @@ -14,6 +14,7 @@ menuconfig MTD_NAND tristate "Raw/Parallel NAND Device Support" depends on MTD select MTD_NAND_ECC + select MTD_NAND_CORE help This enables support for accessing all type of raw/parallel NAND flash devices. For further information see diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c index dbe3d96b74da..071a0c658bfe 100644 --- a/drivers/mtd/nand/raw/nand_base.c +++ b/drivers/mtd/nand/raw/nand_base.c @@ -5484,6 +5484,50 @@ static bool nand_ecc_strength_good(struct nand_chip *chip) return corr >= ds_corr && ecc->strength >= chip->ecc_strength_ds; } +static int rawnand_erase(struct nand_device *nand, const struct nand_pos *pos) +{ + struct nand_chip *chip = container_of(nand, struct nand_chip, + base); + unsigned int eb = nanddev_pos_to_row(nand, pos); + int ret; + + eb >>= nand->rowconv.eraseblock_addr_shift; + + nand_select_target(chip, pos->target); + ret = nand_erase_op(chip, eb); + nand_deselect_target(chip); + + return ret; +} + +static int rawnand_markbad(struct nand_device *nand, + const struct nand_pos *pos) +{ + struct nand_chip *chip = container_of(nand, struct nand_chip, + base); + + return nand_markbad_bbm(chip, nanddev_pos_to_offs(nand, pos)); +} + +static bool rawnand_isbad(struct nand_device *nand, const struct nand_pos *pos) +{ + struct nand_chip *chip = container_of(nand, struct nand_chip, + base); + int ret; + + nand_select_target(chip, pos->target); + ret = nand_isbad_bbm(chip, nanddev_pos_to_offs(nand, pos)); + nand_deselect_target(chip); + + return ret; +} + +static const struct nand_ops rawnand_ops = { + .erase = rawnand_erase, + .markbad = rawnand_markbad, + .isbad = rawnand_isbad, +}; + /** * nand_scan_tail - Scan for the NAND device * @chip: NAND chip object @@ -5752,10 +5796,15 @@ static int nand_scan_tail(struct nand_chip *chip) break; } + ret = nanddev_init(&chip->base, &rawnand_ops, mtd->owner); + if (ret) + goto err_nand_manuf_cleanup; + + /* Adjust the MTD_CAP_ flags when NAND_ROM is set. */ + if (chip->options & NAND_ROM) + mtd->flags = MTD_CAP_ROM; + /* Fill in remaining MTD driver data */ - mtd->type = nand_is_slc(chip) ? MTD_NANDFLASH : MTD_MLCNANDFLASH; - mtd->flags = (chip->options & NAND_ROM) ? MTD_CAP_ROM : - MTD_CAP_NANDFLASH; mtd->_erase = nand_erase; mtd->_point = NULL; mtd->_unpoint = NULL; @@ -5772,7 +5821,6 @@ static int nand_scan_tail(struct nand_chip *chip) mtd->_block_isbad = nand_block_isbad; mtd->_block_markbad = nand_block_markbad; mtd->_max_bad_blocks = nand_max_bad_blocks; - mtd->writebufsize = mtd->writesize; /* * Initialize bitflip_threshold to its default prior scan_bbt() call. @@ -5785,13 +5833,13 @@ static int nand_scan_tail(struct nand_chip *chip) /* Initialize the ->data_interface field. */ ret = nand_init_data_interface(chip); if (ret) - goto err_nand_manuf_cleanup; + goto err_nanddev_cleanup; /* Enter fastest possible mode on all dies. */ for (i = 0; i < chip->numchips; i++) { ret = nand_setup_data_interface(chip, i); if (ret) - goto err_nand_manuf_cleanup; + goto err_nanddev_cleanup; } /* Check, if we should skip the bad block table scan */ @@ -5801,11 +5849,14 @@ static int nand_scan_tail(struct nand_chip *chip) /* Build bad block table */ ret = nand_create_bbt(chip); if (ret) - goto err_nand_manuf_cleanup; + goto err_nanddev_cleanup; return 0; +err_nanddev_cleanup: + nanddev_cleanup(&chip->base); + err_nand_manuf_cleanup: nand_manufacturer_cleanup(chip); -- cgit From eeab717483e5fb529c8001d36fbda14011905e5f Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Sun, 28 Oct 2018 15:27:55 +0100 Subject: mtd: rawnand: Provide a helper to get chip->data_buf We plan to move cache related fields to a pagecache struct in nand_chip but some drivers access ->pagebuf directly to invalidate the cache before they start using ->data_buf. Let's provide an helper that returns a pointer to ->data_buf after invalidating the cache. Signed-off-by: Boris Brezillon Signed-off-by: Miquel Raynal Reviewed-by: Frieder Schrempf --- drivers/mtd/nand/raw/brcmnand/brcmnand.c | 7 ++--- drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c | 4 +-- drivers/mtd/nand/raw/marvell_nand.c | 43 ++++++++++++------------------ drivers/mtd/nand/raw/nand_base.c | 7 +++-- drivers/mtd/nand/raw/nand_bbt.c | 4 ++- drivers/mtd/nand/raw/qcom_nandc.c | 8 +++--- drivers/mtd/nand/raw/sunxi_nand.c | 11 ++++---- include/linux/mtd/rawnand.h | 21 +++++++++++++++ 8 files changed, 56 insertions(+), 49 deletions(-) diff --git a/drivers/mtd/nand/raw/brcmnand/brcmnand.c b/drivers/mtd/nand/raw/brcmnand/brcmnand.c index 482c6f093f99..ce0b8ffc7812 100644 --- a/drivers/mtd/nand/raw/brcmnand/brcmnand.c +++ b/drivers/mtd/nand/raw/brcmnand/brcmnand.c @@ -1676,11 +1676,8 @@ static int brcmstb_nand_verify_erased_page(struct mtd_info *mtd, int page = addr >> chip->page_shift; int ret; - if (!buf) { - buf = chip->data_buf; - /* Invalidate page cache */ - chip->pagebuf = -1; - } + if (!buf) + buf = nand_get_data_buf(chip); sas = mtd->oobsize / chip->ecc.steps; diff --git a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c index bcf5328cf239..df7071e6da5b 100644 --- a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c +++ b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c @@ -1602,7 +1602,7 @@ static int mx23_check_transcription_stamp(struct gpmi_nand_data *this) unsigned int search_area_size_in_strides; unsigned int stride; unsigned int page; - uint8_t *buffer = chip->data_buf; + u8 *buffer = nand_get_data_buf(chip); int saved_chip_number; int found_an_ncb_fingerprint = false; @@ -1664,7 +1664,7 @@ static int mx23_write_transcription_stamp(struct gpmi_nand_data *this) unsigned int block; unsigned int stride; unsigned int page; - uint8_t *buffer = chip->data_buf; + u8 *buffer = nand_get_data_buf(chip); int saved_chip_number; int status; diff --git a/drivers/mtd/nand/raw/marvell_nand.c b/drivers/mtd/nand/raw/marvell_nand.c index f38e5c1b87e4..e81d401ee16c 100644 --- a/drivers/mtd/nand/raw/marvell_nand.c +++ b/drivers/mtd/nand/raw/marvell_nand.c @@ -1083,12 +1083,11 @@ static int marvell_nfc_hw_ecc_hmg_read_page(struct nand_chip *chip, u8 *buf, */ static int marvell_nfc_hw_ecc_hmg_read_oob_raw(struct nand_chip *chip, int page) { - /* Invalidate page cache */ - chip->pagebuf = -1; + u8 *buf = nand_get_data_buf(chip); marvell_nfc_select_target(chip, chip->cur_cs); - return marvell_nfc_hw_ecc_hmg_do_read_page(chip, chip->data_buf, - chip->oob_poi, true, page); + return marvell_nfc_hw_ecc_hmg_do_read_page(chip, buf, chip->oob_poi, + true, page); } /* Hamming write helpers */ @@ -1179,15 +1178,13 @@ static int marvell_nfc_hw_ecc_hmg_write_oob_raw(struct nand_chip *chip, int page) { struct mtd_info *mtd = nand_to_mtd(chip); + u8 *buf = nand_get_data_buf(chip); - /* Invalidate page cache */ - chip->pagebuf = -1; - - memset(chip->data_buf, 0xFF, mtd->writesize); + memset(buf, 0xFF, mtd->writesize); marvell_nfc_select_target(chip, chip->cur_cs); - return marvell_nfc_hw_ecc_hmg_do_write_page(chip, chip->data_buf, - chip->oob_poi, true, page); + return marvell_nfc_hw_ecc_hmg_do_write_page(chip, buf, chip->oob_poi, + true, page); } /* BCH read helpers */ @@ -1434,18 +1431,16 @@ static int marvell_nfc_hw_ecc_bch_read_page(struct nand_chip *chip, static int marvell_nfc_hw_ecc_bch_read_oob_raw(struct nand_chip *chip, int page) { - /* Invalidate page cache */ - chip->pagebuf = -1; + u8 *buf = nand_get_data_buf(chip); - return chip->ecc.read_page_raw(chip, chip->data_buf, true, page); + return chip->ecc.read_page_raw(chip, buf, true, page); } static int marvell_nfc_hw_ecc_bch_read_oob(struct nand_chip *chip, int page) { - /* Invalidate page cache */ - chip->pagebuf = -1; + u8 *buf = nand_get_data_buf(chip); - return chip->ecc.read_page(chip, chip->data_buf, true, page); + return chip->ecc.read_page(chip, buf, true, page); } /* BCH write helpers */ @@ -1619,25 +1614,21 @@ static int marvell_nfc_hw_ecc_bch_write_oob_raw(struct nand_chip *chip, int page) { struct mtd_info *mtd = nand_to_mtd(chip); + u8 *buf = nand_get_data_buf(chip); - /* Invalidate page cache */ - chip->pagebuf = -1; - - memset(chip->data_buf, 0xFF, mtd->writesize); + memset(buf, 0xFF, mtd->writesize); - return chip->ecc.write_page_raw(chip, chip->data_buf, true, page); + return chip->ecc.write_page_raw(chip, buf, true, page); } static int marvell_nfc_hw_ecc_bch_write_oob(struct nand_chip *chip, int page) { struct mtd_info *mtd = nand_to_mtd(chip); + u8 *buf = nand_get_data_buf(chip); - /* Invalidate page cache */ - chip->pagebuf = -1; - - memset(chip->data_buf, 0xFF, mtd->writesize); + memset(buf, 0xFF, mtd->writesize); - return chip->ecc.write_page(chip, chip->data_buf, true, page); + return chip->ecc.write_page(chip, buf, true, page); } /* NAND framework ->exec_op() hooks and related helpers */ diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c index 071a0c658bfe..fe8119c6cd61 100644 --- a/drivers/mtd/nand/raw/nand_base.c +++ b/drivers/mtd/nand/raw/nand_base.c @@ -4004,10 +4004,9 @@ static int nand_do_write_ops(struct nand_chip *chip, loff_t to, __func__, buf); if (part_pagewr) bytes = min_t(int, bytes - column, writelen); - chip->pagebuf = -1; - memset(chip->data_buf, 0xff, mtd->writesize); - memcpy(&chip->data_buf[column], buf, bytes); - wbuf = chip->data_buf; + wbuf = nand_get_data_buf(chip); + memset(wbuf, 0xff, mtd->writesize); + memcpy(&wbuf[column], buf, bytes); } if (unlikely(oob)) { diff --git a/drivers/mtd/nand/raw/nand_bbt.c b/drivers/mtd/nand/raw/nand_bbt.c index 19a2b563acdf..fff803695b2d 100644 --- a/drivers/mtd/nand/raw/nand_bbt.c +++ b/drivers/mtd/nand/raw/nand_bbt.c @@ -901,7 +901,9 @@ static int write_bbt(struct nand_chip *this, uint8_t *buf, static inline int nand_memory_bbt(struct nand_chip *this, struct nand_bbt_descr *bd) { - return create_bbt(this, this->data_buf, bd, -1); + u8 *pagebuf = nand_get_data_buf(this); + + return create_bbt(this, pagebuf, bd, -1); } /** diff --git a/drivers/mtd/nand/raw/qcom_nandc.c b/drivers/mtd/nand/raw/qcom_nandc.c index 920e7375084f..6ead55e05b80 100644 --- a/drivers/mtd/nand/raw/qcom_nandc.c +++ b/drivers/mtd/nand/raw/qcom_nandc.c @@ -1680,14 +1680,12 @@ check_for_erased_page(struct qcom_nand_host *host, u8 *data_buf, u8 *cw_data_buf, *cw_oob_buf; int cw, data_size, oob_size, ret = 0; - if (!data_buf) { - data_buf = chip->data_buf; - chip->pagebuf = -1; - } + if (!data_buf) + data_buf = nand_get_data_buf(chip); if (!oob_buf) { + nand_get_data_buf(chip); oob_buf = chip->oob_poi; - chip->pagebuf = -1; } for_each_set_bit(cw, &uncorrectable_cws, ecc->steps) { diff --git a/drivers/mtd/nand/raw/sunxi_nand.c b/drivers/mtd/nand/raw/sunxi_nand.c index 4282bc477761..d206819c962a 100644 --- a/drivers/mtd/nand/raw/sunxi_nand.c +++ b/drivers/mtd/nand/raw/sunxi_nand.c @@ -1313,20 +1313,19 @@ pio_fallback: static int sunxi_nfc_hw_ecc_read_oob(struct nand_chip *nand, int page) { - nand->pagebuf = -1; + u8 *buf = nand_get_data_buf(nand); - return nand->ecc.read_page(nand, nand->data_buf, 1, page); + return nand->ecc.read_page(nand, buf, 1, page); } static int sunxi_nfc_hw_ecc_write_oob(struct nand_chip *nand, int page) { struct mtd_info *mtd = nand_to_mtd(nand); + u8 *buf = nand_get_data_buf(nand); int ret; - nand->pagebuf = -1; - - memset(nand->data_buf, 0xff, mtd->writesize); - ret = nand->ecc.write_page(nand, nand->data_buf, 1, page); + memset(buf, 0xff, mtd->writesize); + ret = nand->ecc.write_page(nand, buf, 1, page); if (ret) return ret; diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h index 58887cb2c7ea..253f9942a919 100644 --- a/include/linux/mtd/rawnand.h +++ b/include/linux/mtd/rawnand.h @@ -1350,4 +1350,25 @@ int nand_gpio_waitrdy(struct nand_chip *chip, struct gpio_desc *gpiod, void nand_select_target(struct nand_chip *chip, unsigned int cs); void nand_deselect_target(struct nand_chip *chip); +/** + * nand_get_data_buf() - Get the internal page buffer + * @chip: NAND chip object + * + * Returns the pre-allocated page buffer after invalidating the cache. This + * function should be used by drivers that do not want to allocate their own + * bounce buffer and still need such a buffer for specific operations (most + * commonly when reading OOB data only). + * + * Be careful to never call this function in the write/write_oob path, because + * the core may have placed the data to be written out in this buffer. + * + * Return: pointer to the page cache buffer + */ +static inline void *nand_get_data_buf(struct nand_chip *chip) +{ + chip->pagebuf = -1; + + return chip->data_buf; +} + #endif /* __LINUX_MTD_RAWNAND_H */ -- cgit From d974541e23791e189c5faa0462223d29352cecc6 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Sun, 28 Oct 2018 16:12:45 +0100 Subject: mtd: rawnand: Move all page cache related fields to a sub-struct Looking at the field names it's hard to tell what ->data_buf, ->pagebuf and ->pagebuf_bitflips are for. Clarify that by moving those fields in a sub-struct named pagecache. Signed-off-by: Boris Brezillon Signed-off-by: Miquel Raynal Reviewed-by: Frieder Schrempf --- drivers/mtd/nand/raw/nand_base.c | 28 ++++++++++++++-------------- include/linux/mtd/rawnand.h | 18 +++++++++++------- 2 files changed, 25 insertions(+), 21 deletions(-) diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c index fe8119c6cd61..26aeea06035b 100644 --- a/drivers/mtd/nand/raw/nand_base.c +++ b/drivers/mtd/nand/raw/nand_base.c @@ -459,8 +459,8 @@ static int nand_do_write_oob(struct nand_chip *chip, loff_t to, } /* Invalidate the page cache, if we write to the cached page */ - if (page == chip->pagebuf) - chip->pagebuf = -1; + if (page == chip->pagecache.page) + chip->pagecache.page = -1; nand_fill_oob(chip, ops->oobbuf, ops->ooblen, ops); @@ -3173,7 +3173,7 @@ static int nand_do_read_ops(struct nand_chip *chip, loff_t from, use_bufpoi = 0; /* Is the current page in the buffer? */ - if (realpage != chip->pagebuf || oob) { + if (realpage != chip->pagecache.page || oob) { bufpoi = use_bufpoi ? chip->data_buf : buf; if (use_bufpoi && aligned) @@ -3199,7 +3199,7 @@ read_retry: if (ret < 0) { if (use_bufpoi) /* Invalidate page cache */ - chip->pagebuf = -1; + chip->pagecache.page = -1; break; } @@ -3208,11 +3208,11 @@ read_retry: if (!NAND_HAS_SUBPAGE_READ(chip) && !oob && !(mtd->ecc_stats.failed - ecc_failures) && (ops->mode != MTD_OPS_RAW)) { - chip->pagebuf = realpage; - chip->pagebuf_bitflips = ret; + chip->pagecache.page = realpage; + chip->pagecache.bitflips = ret; } else { /* Invalidate page cache */ - chip->pagebuf = -1; + chip->pagecache.page = -1; } memcpy(buf, chip->data_buf + col, bytes); } @@ -3252,7 +3252,7 @@ read_retry: memcpy(buf, chip->data_buf + col, bytes); buf += bytes; max_bitflips = max_t(unsigned int, max_bitflips, - chip->pagebuf_bitflips); + chip->pagecache.bitflips); } readlen -= bytes; @@ -3973,9 +3973,9 @@ static int nand_do_write_ops(struct nand_chip *chip, loff_t to, page = realpage & chip->pagemask; /* Invalidate the page cache, when we write to the cached page */ - if (to <= ((loff_t)chip->pagebuf << chip->page_shift) && - ((loff_t)chip->pagebuf << chip->page_shift) < (to + ops->len)) - chip->pagebuf = -1; + if (to <= ((loff_t)chip->pagecache.page << chip->page_shift) && + ((loff_t)chip->pagecache.page << chip->page_shift) < (to + ops->len)) + chip->pagecache.page = -1; /* Don't allow multipage oob writes with offset */ if (oob && ops->ooboffs && (ops->ooboffs + ops->ooblen > oobmaxlen)) { @@ -4196,9 +4196,9 @@ int nand_erase_nand(struct nand_chip *chip, struct erase_info *instr, * Invalidate the page cache, if we erase the block which * contains the current cached page. */ - if (page <= chip->pagebuf && chip->pagebuf < + if (page <= chip->pagecache.page && chip->pagecache.page < (page + pages_per_block)) - chip->pagebuf = -1; + chip->pagecache.page = -1; ret = nand_erase_op(chip, (page & chip->pagemask) >> (chip->phys_erase_shift - chip->page_shift)); @@ -5782,7 +5782,7 @@ static int nand_scan_tail(struct nand_chip *chip) chip->subpagesize = mtd->writesize >> mtd->subpage_sft; /* Invalidate the pagebuffer reference */ - chip->pagebuf = -1; + chip->pagecache.page = -1; /* Large page NAND with SOFT_ECC should support subpage reads */ switch (ecc->mode) { diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h index 253f9942a919..99250dc848e8 100644 --- a/include/linux/mtd/rawnand.h +++ b/include/linux/mtd/rawnand.h @@ -1007,10 +1007,10 @@ struct nand_legacy { * @chipsize: [INTERN] the size of one chip for multichip arrays * @pagemask: [INTERN] page number mask = number of (pages / chip) - 1 * @data_buf: [INTERN] buffer for data, size is (page size + oobsize). - * @pagebuf: [INTERN] holds the pagenumber which is currently in - * data_buf. - * @pagebuf_bitflips: [INTERN] holds the bitflip count for the page which is - * currently in data_buf. + * @pagecache: Structure containing page cache related fields + * @pagecache.bitflips: Number of bitflips of the cached page + * @pagecache.page: Page number currently in the cache. -1 means no page is + * currently cached * @subpagesize: [INTERN] holds the subpagesize * @id: [INTERN] holds NAND ID * @parameters: [INTERN] holds generic parameters under an easily @@ -1060,8 +1060,12 @@ struct nand_chip { uint64_t chipsize; int pagemask; u8 *data_buf; - int pagebuf; - unsigned int pagebuf_bitflips; + + struct { + unsigned int bitflips; + int page; + } pagecache; + int subpagesize; uint8_t bits_per_cell; uint16_t ecc_strength_ds; @@ -1366,7 +1370,7 @@ void nand_deselect_target(struct nand_chip *chip); */ static inline void *nand_get_data_buf(struct nand_chip *chip) { - chip->pagebuf = -1; + chip->pagecache.page = -1; return chip->data_buf; } -- cgit From 7beb37e5f0d29d7d23aec0e47900ff4dfa8c2e55 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Sun, 4 Nov 2018 14:50:28 +0100 Subject: mtd: rawnand: Use nanddev_mtd_max_bad_blocks() nanddev_mtd_max_bad_blocks() is implemented by the generic NAND layer and is already doing what we need. Reuse this function instead of having our own implementation. While at it, get rid of the ->max_bb_per_die and ->blocks_per_die fields which are now unused. Signed-off-by: Boris Brezillon Signed-off-by: Miquel Raynal Reviewed-by: Frieder Schrempf --- drivers/mtd/nand/raw/nand_base.c | 38 +------------------------------------- drivers/mtd/nand/raw/nand_onfi.c | 3 --- include/linux/mtd/rawnand.h | 5 ----- 3 files changed, 1 insertion(+), 45 deletions(-) diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c index 26aeea06035b..035b9cf327a6 100644 --- a/drivers/mtd/nand/raw/nand_base.c +++ b/drivers/mtd/nand/raw/nand_base.c @@ -4297,42 +4297,6 @@ static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs) return nand_block_markbad_lowlevel(mtd_to_nand(mtd), ofs); } -/** - * nand_max_bad_blocks - [MTD Interface] Max number of bad blocks for an mtd - * @mtd: MTD device structure - * @ofs: offset relative to mtd start - * @len: length of mtd - */ -static int nand_max_bad_blocks(struct mtd_info *mtd, loff_t ofs, size_t len) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - u32 part_start_block; - u32 part_end_block; - u32 part_start_die; - u32 part_end_die; - - /* - * max_bb_per_die and blocks_per_die used to determine - * the maximum bad block count. - */ - if (!chip->max_bb_per_die || !chip->blocks_per_die) - return -ENOTSUPP; - - /* Get the start and end of the partition in erase blocks. */ - part_start_block = mtd_div_by_eb(ofs, mtd); - part_end_block = mtd_div_by_eb(len, mtd) + part_start_block - 1; - - /* Get the start and end LUNs of the partition. */ - part_start_die = part_start_block / chip->blocks_per_die; - part_end_die = part_end_block / chip->blocks_per_die; - - /* - * Look up the bad blocks per unit and multiply by the number of units - * that the partition spans. - */ - return chip->max_bb_per_die * (part_end_die - part_start_die + 1); -} - /** * nand_suspend - [MTD Interface] Suspend the NAND flash * @mtd: MTD device structure @@ -5819,7 +5783,7 @@ static int nand_scan_tail(struct nand_chip *chip) mtd->_block_isreserved = nand_block_isreserved; mtd->_block_isbad = nand_block_isbad; mtd->_block_markbad = nand_block_markbad; - mtd->_max_bad_blocks = nand_max_bad_blocks; + mtd->_max_bad_blocks = nanddev_mtd_max_bad_blocks; /* * Initialize bitflip_threshold to its default prior scan_bbt() call. diff --git a/drivers/mtd/nand/raw/nand_onfi.c b/drivers/mtd/nand/raw/nand_onfi.c index f3f59cf37d7f..3ca9c8923a30 100644 --- a/drivers/mtd/nand/raw/nand_onfi.c +++ b/drivers/mtd/nand/raw/nand_onfi.c @@ -251,9 +251,6 @@ int nand_onfi_detect(struct nand_chip *chip) memorg->bits_per_cell = p->bits_per_cell; chip->bits_per_cell = p->bits_per_cell; - chip->max_bb_per_die = le16_to_cpu(p->bb_per_lun); - chip->blocks_per_die = le32_to_cpu(p->blocks_per_lun); - if (le16_to_cpu(p->features) & ONFI_FEATURE_16_BIT_BUS) chip->options |= NAND_BUSWIDTH_16; diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h index 99250dc848e8..9d0cdae4e204 100644 --- a/include/linux/mtd/rawnand.h +++ b/include/linux/mtd/rawnand.h @@ -1015,9 +1015,6 @@ struct nand_legacy { * @id: [INTERN] holds NAND ID * @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 * @data_interface: [INTERN] NAND interface timing information * @cur_cs: currently selected target. -1 means no target selected, * otherwise we should always have cur_cs >= 0 && @@ -1076,8 +1073,6 @@ struct nand_chip { struct nand_id id; struct nand_parameters parameters; - u16 max_bb_per_die; - u32 blocks_per_die; struct nand_data_interface data_interface; -- cgit From 298151689b33e04eaf09cf22e1d42396f7723690 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Thu, 25 Oct 2018 17:16:47 +0200 Subject: mtd: rawnand: Get rid of chip->bits_per_cell Now that we inherit from nand_device, we can use nand_device->memorg.bits_per_cell instead of having our own field at the nand_chip level. Signed-off-by: Boris Brezillon Signed-off-by: Miquel Raynal Reviewed-by: Frieder Schrempf --- drivers/mtd/nand/raw/nand_base.c | 4 ---- drivers/mtd/nand/raw/nand_hynix.c | 2 +- drivers/mtd/nand/raw/nand_jedec.c | 1 - drivers/mtd/nand/raw/nand_micron.c | 2 +- drivers/mtd/nand/raw/nand_onfi.c | 1 - include/linux/mtd/rawnand.h | 6 ++---- 6 files changed, 4 insertions(+), 12 deletions(-) diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c index 035b9cf327a6..77c0e0ef61b1 100644 --- a/drivers/mtd/nand/raw/nand_base.c +++ b/drivers/mtd/nand/raw/nand_base.c @@ -4457,7 +4457,6 @@ void nand_decode_ext_id(struct nand_chip *chip) /* The 3rd id byte holds MLC / multichip data */ memorg->bits_per_cell = nand_get_bits_per_cell(id_data[2]); - chip->bits_per_cell = nand_get_bits_per_cell(id_data[2]); /* The 4th id byte is the important one */ extid = id_data[3]; @@ -4501,7 +4500,6 @@ static void nand_decode_id(struct nand_chip *chip, struct nand_flash_dev *type) /* All legacy ID NAND are small-page, SLC */ memorg->bits_per_cell = 1; - chip->bits_per_cell = 1; } /* @@ -4544,7 +4542,6 @@ static bool find_full_id_nand(struct nand_chip *chip, mtd->oobsize = memorg->oobsize; memorg->bits_per_cell = nand_get_bits_per_cell(id_data[2]); - chip->bits_per_cell = nand_get_bits_per_cell(id_data[2]); chip->chipsize = (uint64_t)type->chipsize << 20; memorg->eraseblocks_per_lun = DIV_ROUND_DOWN_ULL((u64)type->chipsize << 20, @@ -4584,7 +4581,6 @@ static void nand_manufacturer_detect(struct nand_chip *chip) /* The 3rd id byte holds MLC / multichip data */ memorg->bits_per_cell = nand_get_bits_per_cell(chip->id.data[2]); - chip->bits_per_cell = nand_get_bits_per_cell(chip->id.data[2]); chip->manufacturer.desc->ops->detect(chip); } else { nand_decode_ext_id(chip); diff --git a/drivers/mtd/nand/raw/nand_hynix.c b/drivers/mtd/nand/raw/nand_hynix.c index 94ea8c593589..272b934dffb7 100644 --- a/drivers/mtd/nand/raw/nand_hynix.c +++ b/drivers/mtd/nand/raw/nand_hynix.c @@ -592,7 +592,7 @@ static void hynix_nand_extract_scrambling_requirements(struct nand_chip *chip, u8 nand_tech; /* We need scrambling on all TLC NANDs*/ - if (chip->bits_per_cell > 2) + if (nanddev_bits_per_cell(&chip->base) > 2) chip->options |= NAND_NEED_SCRAMBLING; /* And on MLC NANDs with sub-3xnm process */ diff --git a/drivers/mtd/nand/raw/nand_jedec.c b/drivers/mtd/nand/raw/nand_jedec.c index 61e33ee7ee19..030f178c7a97 100644 --- a/drivers/mtd/nand/raw/nand_jedec.c +++ b/drivers/mtd/nand/raw/nand_jedec.c @@ -104,7 +104,6 @@ int nand_jedec_detect(struct nand_chip *chip) chip->chipsize = memorg->eraseblocks_per_lun; chip->chipsize *= (uint64_t)mtd->erasesize * p->lun_count; memorg->bits_per_cell = p->bits_per_cell; - chip->bits_per_cell = p->bits_per_cell; if (le16_to_cpu(p->features) & JEDEC_FEATURE_16_BIT_BUS) chip->options |= NAND_BUSWIDTH_16; diff --git a/drivers/mtd/nand/raw/nand_micron.c b/drivers/mtd/nand/raw/nand_micron.c index b85e1c13b79e..98ce6575aa64 100644 --- a/drivers/mtd/nand/raw/nand_micron.c +++ b/drivers/mtd/nand/raw/nand_micron.c @@ -385,7 +385,7 @@ static int micron_supports_on_die_ecc(struct nand_chip *chip) if (!chip->parameters.onfi) return MICRON_ON_DIE_UNSUPPORTED; - if (chip->bits_per_cell != 1) + if (nanddev_bits_per_cell(&chip->base) != 1) return MICRON_ON_DIE_UNSUPPORTED; /* diff --git a/drivers/mtd/nand/raw/nand_onfi.c b/drivers/mtd/nand/raw/nand_onfi.c index 3ca9c8923a30..a6b9fc9a335b 100644 --- a/drivers/mtd/nand/raw/nand_onfi.c +++ b/drivers/mtd/nand/raw/nand_onfi.c @@ -249,7 +249,6 @@ int nand_onfi_detect(struct nand_chip *chip) chip->chipsize = memorg->eraseblocks_per_lun; chip->chipsize *= (uint64_t)mtd->erasesize * p->lun_count; memorg->bits_per_cell = p->bits_per_cell; - chip->bits_per_cell = p->bits_per_cell; if (le16_to_cpu(p->features) & ONFI_FEATURE_16_BIT_BUS) chip->options |= NAND_BUSWIDTH_16; diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h index 9d0cdae4e204..b2570adab911 100644 --- a/include/linux/mtd/rawnand.h +++ b/include/linux/mtd/rawnand.h @@ -992,7 +992,6 @@ struct nand_legacy { * @badblockbits: [INTERN] minimum number of set bits in a good block's * bad block marker position; i.e., BBM == 11110111b is * not bad when badblockbits == 7 - * @bits_per_cell: [INTERN] number of bits per cell. i.e., 1 means SLC. * @ecc_strength_ds: [INTERN] ECC correctability from the datasheet. * Minimum amount of bit errors per @ecc_step_ds guaranteed * to be correctable. If unknown, set to zero. @@ -1064,7 +1063,6 @@ struct nand_chip { } pagecache; int subpagesize; - uint8_t bits_per_cell; uint16_t ecc_strength_ds; uint16_t ecc_step_ds; int onfi_timing_mode_default; @@ -1236,9 +1234,9 @@ int nand_create_bbt(struct nand_chip *chip); */ static inline bool nand_is_slc(struct nand_chip *chip) { - WARN(chip->bits_per_cell == 0, + WARN(nanddev_bits_per_cell(&chip->base) == 0, "chip->bits_per_cell is used uninitialized\n"); - return chip->bits_per_cell == 1; + return nanddev_bits_per_cell(&chip->base) == 1; } /** -- cgit From 6c836d515ff85e333488692c67969f714654a1c6 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Mon, 29 Oct 2018 11:22:16 +0100 Subject: mtd: rawnand: Get rid of chip->chipsize The target size can now be returned by nanddev_get_targetsize(). Get rid of the chip->chipsize field and use this helper instead. Signed-off-by: Boris Brezillon Reviewed-by: Frieder Schrempf Signed-off-by: Miquel Raynal --- drivers/mtd/nand/raw/bcm47xxnflash/ops_bcm4706.c | 2 +- drivers/mtd/nand/raw/denali.c | 1 - drivers/mtd/nand/raw/fsl_elbc_nand.c | 2 +- drivers/mtd/nand/raw/fsl_ifc_nand.c | 2 +- drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c | 2 +- drivers/mtd/nand/raw/ingenic/jz4740_nand.c | 2 +- drivers/mtd/nand/raw/nand_base.c | 17 ++++++++-------- drivers/mtd/nand/raw/nand_bbt.c | 25 +++++++++++++++--------- drivers/mtd/nand/raw/nand_jedec.c | 2 -- drivers/mtd/nand/raw/nand_onfi.c | 2 -- drivers/mtd/nand/raw/nandsim.c | 6 ++++-- drivers/mtd/nand/raw/sh_flctl.c | 9 +++++---- include/linux/mtd/rawnand.h | 2 -- 13 files changed, 38 insertions(+), 36 deletions(-) diff --git a/drivers/mtd/nand/raw/bcm47xxnflash/ops_bcm4706.c b/drivers/mtd/nand/raw/bcm47xxnflash/ops_bcm4706.c index a37cbfe56567..a53ffb3d64b0 100644 --- a/drivers/mtd/nand/raw/bcm47xxnflash/ops_bcm4706.c +++ b/drivers/mtd/nand/raw/bcm47xxnflash/ops_bcm4706.c @@ -428,7 +428,7 @@ int bcm47xxnflash_ops_bcm4706_init(struct bcm47xxnflash *b47n) } /* Configure FLASH */ - chipsize = b47n->nand_chip.chipsize >> 20; + chipsize = nanddev_target_size(&b47n->nand_chip.base) >> 20; tbits = ffs(chipsize); /* find first bit set */ if (!tbits || tbits != fls(chipsize)) { pr_err("Invalid flash size: 0x%lX\n", chipsize); diff --git a/drivers/mtd/nand/raw/denali.c b/drivers/mtd/nand/raw/denali.c index e99d59d85197..be1cc064bdb4 100644 --- a/drivers/mtd/nand/raw/denali.c +++ b/drivers/mtd/nand/raw/denali.c @@ -1134,7 +1134,6 @@ static int denali_multidev_fixup(struct denali_nand_info *denali) mtd->erasesize <<= 1; mtd->writesize <<= 1; mtd->oobsize <<= 1; - chip->chipsize <<= 1; chip->page_shift += 1; chip->phys_erase_shift += 1; chip->bbt_erase_shift += 1; diff --git a/drivers/mtd/nand/raw/fsl_elbc_nand.c b/drivers/mtd/nand/raw/fsl_elbc_nand.c index 70f0d2b450ea..1d960a6cd691 100644 --- a/drivers/mtd/nand/raw/fsl_elbc_nand.c +++ b/drivers/mtd/nand/raw/fsl_elbc_nand.c @@ -655,7 +655,7 @@ static int fsl_elbc_attach_chip(struct nand_chip *chip) dev_dbg(priv->dev, "fsl_elbc_init: nand->numchips = %d\n", chip->numchips); dev_dbg(priv->dev, "fsl_elbc_init: nand->chipsize = %lld\n", - chip->chipsize); + nanddev_target_size(&chip->base)); dev_dbg(priv->dev, "fsl_elbc_init: nand->pagemask = %8x\n", chip->pagemask); dev_dbg(priv->dev, "fsl_elbc_init: nand->legacy.chip_delay = %d\n", diff --git a/drivers/mtd/nand/raw/fsl_ifc_nand.c b/drivers/mtd/nand/raw/fsl_ifc_nand.c index e65d274399f9..a9e8f89aeebd 100644 --- a/drivers/mtd/nand/raw/fsl_ifc_nand.c +++ b/drivers/mtd/nand/raw/fsl_ifc_nand.c @@ -724,7 +724,7 @@ static int fsl_ifc_attach_chip(struct nand_chip *chip) dev_dbg(priv->dev, "%s: nand->numchips = %d\n", __func__, chip->numchips); dev_dbg(priv->dev, "%s: nand->chipsize = %lld\n", __func__, - chip->chipsize); + nanddev_target_size(&chip->base)); dev_dbg(priv->dev, "%s: nand->pagemask = %8x\n", __func__, chip->pagemask); dev_dbg(priv->dev, "%s: nand->legacy.chip_delay = %d\n", __func__, diff --git a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c index df7071e6da5b..eec39615bc6f 100644 --- a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c +++ b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c @@ -1753,7 +1753,7 @@ static int mx23_boot_init(struct gpmi_nand_data *this) dev_dbg(dev, "Transcribing bad block marks...\n"); /* Compute the number of blocks in the entire medium. */ - block_count = chip->chipsize >> chip->phys_erase_shift; + block_count = nanddev_eraseblocks_per_target(&chip->base); /* * Loop over all the blocks in the medium, transcribing block marks as diff --git a/drivers/mtd/nand/raw/ingenic/jz4740_nand.c b/drivers/mtd/nand/raw/ingenic/jz4740_nand.c index d5715dde4237..27e16c44a94d 100644 --- a/drivers/mtd/nand/raw/ingenic/jz4740_nand.c +++ b/drivers/mtd/nand/raw/ingenic/jz4740_nand.c @@ -356,7 +356,7 @@ static int jz_nand_detect_bank(struct platform_device *pdev, /* Update size of the MTD. */ chip->numchips++; memorg->ntargets++; - mtd->size += chip->chipsize; + mtd->size += nanddev_target_size(&chip->base); } dev_info(&pdev->dev, "Found chip %zu on bank %i\n", chipnr, bank); diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c index 77c0e0ef61b1..f89cc8be5ce4 100644 --- a/drivers/mtd/nand/raw/nand_base.c +++ b/drivers/mtd/nand/raw/nand_base.c @@ -4542,7 +4542,6 @@ static bool find_full_id_nand(struct nand_chip *chip, mtd->oobsize = memorg->oobsize; memorg->bits_per_cell = nand_get_bits_per_cell(id_data[2]); - chip->chipsize = (uint64_t)type->chipsize << 20; memorg->eraseblocks_per_lun = DIV_ROUND_DOWN_ULL((u64)type->chipsize << 20, memorg->pagesize * @@ -4633,6 +4632,7 @@ static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type) int busw, ret; u8 *id_data = chip->id.data; u8 maf_id, dev_id; + u64 targetsize; /* * Let's start by initializing memorg fields that might be left @@ -4737,8 +4737,6 @@ static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type) if (!chip->parameters.model) return -ENOMEM; - chip->chipsize = (uint64_t)type->chipsize << 20; - if (!type->pagesize) nand_manufacturer_detect(chip); else @@ -4780,14 +4778,15 @@ ident_done: /* Calculate the address shift from the page size */ chip->page_shift = ffs(mtd->writesize) - 1; /* Convert chipsize to number of pages per chip -1 */ - chip->pagemask = (chip->chipsize >> chip->page_shift) - 1; + targetsize = nanddev_target_size(&chip->base); + chip->pagemask = (targetsize >> chip->page_shift) - 1; chip->bbt_erase_shift = chip->phys_erase_shift = ffs(mtd->erasesize) - 1; - if (chip->chipsize & 0xffffffff) - chip->chip_shift = ffs((unsigned)chip->chipsize) - 1; + if (targetsize & 0xffffffff) + chip->chip_shift = ffs((unsigned)targetsize) - 1; else { - chip->chip_shift = ffs((unsigned)(chip->chipsize >> 32)); + chip->chip_shift = ffs((unsigned)(targetsize >> 32)); chip->chip_shift += 32 - 1; } @@ -4803,7 +4802,7 @@ ident_done: 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", + (int)(targetsize >> 20), nand_is_slc(chip) ? "SLC" : "MLC", mtd->erasesize >> 10, mtd->writesize, mtd->oobsize); return 0; @@ -5054,7 +5053,7 @@ static int nand_scan_ident(struct nand_chip *chip, unsigned int maxchips, /* Store the number of chips and calc total size for mtd */ memorg->ntargets = i; chip->numchips = i; - mtd->size = i * chip->chipsize; + mtd->size = i * nanddev_target_size(&chip->base); return 0; } diff --git a/drivers/mtd/nand/raw/nand_bbt.c b/drivers/mtd/nand/raw/nand_bbt.c index fff803695b2d..42399a32d34a 100644 --- a/drivers/mtd/nand/raw/nand_bbt.c +++ b/drivers/mtd/nand/raw/nand_bbt.c @@ -264,6 +264,7 @@ static int read_abs_bbt(struct nand_chip *this, uint8_t *buf, struct nand_bbt_descr *td, int chip) { struct mtd_info *mtd = nand_to_mtd(this); + u64 targetsize = nanddev_target_size(&this->base); int res = 0, i; if (td->options & NAND_BBT_PERCHIP) { @@ -271,11 +272,11 @@ static int read_abs_bbt(struct nand_chip *this, uint8_t *buf, for (i = 0; i < this->numchips; i++) { if (chip == -1 || chip == i) res = read_bbt(this, buf, td->pages[i], - this->chipsize >> this->bbt_erase_shift, + targetsize >> this->bbt_erase_shift, td, offs); if (res) return res; - offs += this->chipsize >> this->bbt_erase_shift; + offs += targetsize >> this->bbt_erase_shift; } } else { res = read_bbt(this, buf, td->pages[0], @@ -459,6 +460,7 @@ static int scan_block_fast(struct nand_chip *this, struct nand_bbt_descr *bd, static int create_bbt(struct nand_chip *this, uint8_t *buf, struct nand_bbt_descr *bd, int chip) { + u64 targetsize = nanddev_target_size(&this->base); struct mtd_info *mtd = nand_to_mtd(this); int i, numblocks, numpages; int startblock; @@ -481,7 +483,7 @@ static int create_bbt(struct nand_chip *this, uint8_t *buf, chip + 1, this->numchips); return -EINVAL; } - numblocks = this->chipsize >> this->bbt_erase_shift; + numblocks = targetsize >> this->bbt_erase_shift; startblock = chip * numblocks; numblocks += startblock; from = (loff_t)startblock << this->bbt_erase_shift; @@ -529,6 +531,7 @@ static int create_bbt(struct nand_chip *this, uint8_t *buf, static int search_bbt(struct nand_chip *this, uint8_t *buf, struct nand_bbt_descr *td) { + u64 targetsize = nanddev_target_size(&this->base); struct mtd_info *mtd = nand_to_mtd(this); int i, chips; int startblock, block, dir; @@ -548,7 +551,7 @@ static int search_bbt(struct nand_chip *this, uint8_t *buf, /* Do we have a bbt per chip? */ if (td->options & NAND_BBT_PERCHIP) { chips = this->numchips; - bbtblocks = this->chipsize >> this->bbt_erase_shift; + bbtblocks = targetsize >> this->bbt_erase_shift; startblock &= bbtblocks - 1; } else { chips = 1; @@ -576,7 +579,7 @@ static int search_bbt(struct nand_chip *this, uint8_t *buf, break; } } - startblock += this->chipsize >> this->bbt_erase_shift; + startblock += targetsize >> this->bbt_erase_shift; } /* Check, if we found a bbt for each requested chip */ for (i = 0; i < chips; i++) { @@ -626,6 +629,7 @@ static void search_read_bbts(struct nand_chip *this, uint8_t *buf, static int get_bbt_block(struct nand_chip *this, struct nand_bbt_descr *td, struct nand_bbt_descr *md, int chip) { + u64 targetsize = nanddev_target_size(&this->base); int startblock, dir, page, numblocks, i; /* @@ -637,7 +641,7 @@ static int get_bbt_block(struct nand_chip *this, struct nand_bbt_descr *td, return td->pages[chip] >> (this->bbt_erase_shift - this->page_shift); - numblocks = (int)(this->chipsize >> this->bbt_erase_shift); + numblocks = (int)(targetsize >> this->bbt_erase_shift); if (!(td->options & NAND_BBT_PERCHIP)) numblocks *= this->numchips; @@ -717,6 +721,7 @@ static int write_bbt(struct nand_chip *this, uint8_t *buf, struct nand_bbt_descr *td, struct nand_bbt_descr *md, int chipsel) { + u64 targetsize = nanddev_target_size(&this->base); struct mtd_info *mtd = nand_to_mtd(this); struct erase_info einfo; int i, res, chip = 0; @@ -737,7 +742,7 @@ static int write_bbt(struct nand_chip *this, uint8_t *buf, rcode = 0xff; /* Write bad block table per chip rather than per device? */ if (td->options & NAND_BBT_PERCHIP) { - numblocks = (int)(this->chipsize >> this->bbt_erase_shift); + numblocks = (int)(targetsize >> this->bbt_erase_shift); /* Full device write or specific chip? */ if (chipsel == -1) { nrchips = this->numchips; @@ -1099,6 +1104,7 @@ static int nand_update_bbt(struct nand_chip *this, loff_t offs) */ static void mark_bbt_region(struct nand_chip *this, struct nand_bbt_descr *td) { + u64 targetsize = nanddev_target_size(&this->base); struct mtd_info *mtd = nand_to_mtd(this); int i, j, chips, block, nrblocks, update; uint8_t oldval; @@ -1106,7 +1112,7 @@ static void mark_bbt_region(struct nand_chip *this, struct nand_bbt_descr *td) /* Do we have a bbt per chip? */ if (td->options & NAND_BBT_PERCHIP) { chips = this->numchips; - nrblocks = (int)(this->chipsize >> this->bbt_erase_shift); + nrblocks = (int)(targetsize >> this->bbt_erase_shift); } else { chips = 1; nrblocks = (int)(mtd->size >> this->bbt_erase_shift); @@ -1159,6 +1165,7 @@ static void mark_bbt_region(struct nand_chip *this, struct nand_bbt_descr *td) */ static void verify_bbt_descr(struct nand_chip *this, struct nand_bbt_descr *bd) { + u64 targetsize = nanddev_target_size(&this->base); struct mtd_info *mtd = nand_to_mtd(this); u32 pattern_len; u32 bits; @@ -1187,7 +1194,7 @@ static void verify_bbt_descr(struct nand_chip *this, struct nand_bbt_descr *bd) } if (bd->options & NAND_BBT_PERCHIP) - table_size = this->chipsize >> this->bbt_erase_shift; + table_size = targetsize >> this->bbt_erase_shift; else table_size = mtd->size >> this->bbt_erase_shift; table_size >>= 3; diff --git a/drivers/mtd/nand/raw/nand_jedec.c b/drivers/mtd/nand/raw/nand_jedec.c index 030f178c7a97..99e2f017c79b 100644 --- a/drivers/mtd/nand/raw/nand_jedec.c +++ b/drivers/mtd/nand/raw/nand_jedec.c @@ -101,8 +101,6 @@ int nand_jedec_detect(struct nand_chip *chip) /* Please reference to the comment for nand_flash_detect_onfi. */ memorg->eraseblocks_per_lun = 1 << (fls(le32_to_cpu(p->blocks_per_lun)) - 1); - chip->chipsize = memorg->eraseblocks_per_lun; - chip->chipsize *= (uint64_t)mtd->erasesize * p->lun_count; memorg->bits_per_cell = p->bits_per_cell; if (le16_to_cpu(p->features) & JEDEC_FEATURE_16_BIT_BUS) diff --git a/drivers/mtd/nand/raw/nand_onfi.c b/drivers/mtd/nand/raw/nand_onfi.c index a6b9fc9a335b..7b468e7214c7 100644 --- a/drivers/mtd/nand/raw/nand_onfi.c +++ b/drivers/mtd/nand/raw/nand_onfi.c @@ -246,8 +246,6 @@ int nand_onfi_detect(struct nand_chip *chip) memorg->eraseblocks_per_lun = 1 << (fls(le32_to_cpu(p->blocks_per_lun)) - 1); memorg->max_bad_eraseblocks_per_lun = le32_to_cpu(p->blocks_per_lun); - chip->chipsize = memorg->eraseblocks_per_lun; - chip->chipsize *= (uint64_t)mtd->erasesize * p->lun_count; memorg->bits_per_cell = p->bits_per_cell; if (le16_to_cpu(p->features) & ONFI_FEATURE_16_BIT_BUS) diff --git a/drivers/mtd/nand/raw/nandsim.c b/drivers/mtd/nand/raw/nandsim.c index bf54733f8b5b..0f86dd283769 100644 --- a/drivers/mtd/nand/raw/nandsim.c +++ b/drivers/mtd/nand/raw/nandsim.c @@ -2305,6 +2305,7 @@ static int __init ns_init_module(void) if (overridesize) { uint64_t new_size = (uint64_t)nsmtd->erasesize << overridesize; struct nand_memory_organization *memorg; + u64 targetsize; memorg = nanddev_get_memorg(&chip->base); @@ -2313,12 +2314,13 @@ static int __init ns_init_module(void) retval = -EINVAL; goto err_exit; } + /* N.B. This relies on nand_scan not doing anything with the size before we change it */ nsmtd->size = new_size; memorg->eraseblocks_per_lun = 1 << overridesize; - chip->chipsize = new_size; + targetsize = nanddev_target_size(&chip->base); chip->chip_shift = ffs(nsmtd->erasesize) + overridesize - 1; - chip->pagemask = (chip->chipsize >> chip->page_shift) - 1; + chip->pagemask = (targetsize >> chip->page_shift) - 1; } if ((retval = setup_wear_reporting(nsmtd)) != 0) diff --git a/drivers/mtd/nand/raw/sh_flctl.c b/drivers/mtd/nand/raw/sh_flctl.c index cf6b1be1cf9c..3f610040f0c3 100644 --- a/drivers/mtd/nand/raw/sh_flctl.c +++ b/drivers/mtd/nand/raw/sh_flctl.c @@ -986,6 +986,7 @@ static void flctl_read_buf(struct nand_chip *chip, uint8_t *buf, int len) static int flctl_chip_attach_chip(struct nand_chip *chip) { + u64 targetsize = nanddev_target_size(&chip->base); struct mtd_info *mtd = nand_to_mtd(chip); struct sh_flctl *flctl = mtd_to_flctl(mtd); @@ -998,11 +999,11 @@ static int flctl_chip_attach_chip(struct nand_chip *chip) if (mtd->writesize == 512) { flctl->page_size = 0; - if (chip->chipsize > (32 << 20)) { + if (targetsize > (32 << 20)) { /* big than 32MB */ flctl->rw_ADRCNT = ADRCNT_4; flctl->erase_ADRCNT = ADRCNT_3; - } else if (chip->chipsize > (2 << 16)) { + } else if (targetsize > (2 << 16)) { /* big than 128KB */ flctl->rw_ADRCNT = ADRCNT_3; flctl->erase_ADRCNT = ADRCNT_2; @@ -1012,11 +1013,11 @@ static int flctl_chip_attach_chip(struct nand_chip *chip) } } else { flctl->page_size = 1; - if (chip->chipsize > (128 << 20)) { + if (targetsize > (128 << 20)) { /* big than 128MB */ flctl->rw_ADRCNT = ADRCNT2_E; flctl->erase_ADRCNT = ADRCNT_3; - } else if (chip->chipsize > (8 << 16)) { + } else if (targetsize > (8 << 16)) { /* big than 512KB */ flctl->rw_ADRCNT = ADRCNT_4; flctl->erase_ADRCNT = ADRCNT_2; diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h index b2570adab911..02657591c3fc 100644 --- a/include/linux/mtd/rawnand.h +++ b/include/linux/mtd/rawnand.h @@ -1003,7 +1003,6 @@ struct nand_legacy { * ONFI compliant or deduced from the datasheet if * the NAND chip is not ONFI compliant. * @numchips: [INTERN] number of physical chips - * @chipsize: [INTERN] the size of one chip for multichip arrays * @pagemask: [INTERN] page number mask = number of (pages / chip) - 1 * @data_buf: [INTERN] buffer for data, size is (page size + oobsize). * @pagecache: Structure containing page cache related fields @@ -1053,7 +1052,6 @@ struct nand_chip { int bbt_erase_shift; int chip_shift; int numchips; - uint64_t chipsize; int pagemask; u8 *data_buf; -- cgit From 32813e288414fecce18f37f8f0d0414a64b45c56 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Mon, 29 Oct 2018 11:58:29 +0100 Subject: mtd: rawnand: Get rid of chip->numchips The same information is provided by nanddev_ntargets(). Signed-off-by: Boris Brezillon Signed-off-by: Miquel Raynal Reviewed-by: Frieder Schrempf --- drivers/mtd/nand/raw/diskonchip.c | 2 +- drivers/mtd/nand/raw/fsl_elbc_nand.c | 2 +- drivers/mtd/nand/raw/fsl_ifc_nand.c | 2 +- drivers/mtd/nand/raw/hisi504_nand.c | 2 +- drivers/mtd/nand/raw/ingenic/jz4740_nand.c | 1 - drivers/mtd/nand/raw/internals.h | 2 +- drivers/mtd/nand/raw/nand_base.c | 15 ++++----------- drivers/mtd/nand/raw/nand_bbt.c | 16 ++++++++-------- include/linux/mtd/rawnand.h | 7 +++---- 9 files changed, 20 insertions(+), 29 deletions(-) diff --git a/drivers/mtd/nand/raw/diskonchip.c b/drivers/mtd/nand/raw/diskonchip.c index 2e0da6a24bfd..f430c4bf0323 100644 --- a/drivers/mtd/nand/raw/diskonchip.c +++ b/drivers/mtd/nand/raw/diskonchip.c @@ -1291,7 +1291,7 @@ static int __init inftl_scan_bbt(struct mtd_info *mtd) struct doc_priv *doc = nand_get_controller_data(this); struct mtd_partition parts[5]; - if (this->numchips > doc->chips_per_floor) { + if (nanddev_ntargets(&this->base) > doc->chips_per_floor) { pr_err("Multi-floor INFTL devices not yet supported.\n"); return -EIO; } diff --git a/drivers/mtd/nand/raw/fsl_elbc_nand.c b/drivers/mtd/nand/raw/fsl_elbc_nand.c index 1d960a6cd691..293a5b71833a 100644 --- a/drivers/mtd/nand/raw/fsl_elbc_nand.c +++ b/drivers/mtd/nand/raw/fsl_elbc_nand.c @@ -653,7 +653,7 @@ static int fsl_elbc_attach_chip(struct nand_chip *chip) priv->fmr |= al << FMR_AL_SHIFT; dev_dbg(priv->dev, "fsl_elbc_init: nand->numchips = %d\n", - chip->numchips); + nanddev_ntargets(&chip->base)); dev_dbg(priv->dev, "fsl_elbc_init: nand->chipsize = %lld\n", nanddev_target_size(&chip->base)); dev_dbg(priv->dev, "fsl_elbc_init: nand->pagemask = %8x\n", diff --git a/drivers/mtd/nand/raw/fsl_ifc_nand.c b/drivers/mtd/nand/raw/fsl_ifc_nand.c index a9e8f89aeebd..04a3dcd675bf 100644 --- a/drivers/mtd/nand/raw/fsl_ifc_nand.c +++ b/drivers/mtd/nand/raw/fsl_ifc_nand.c @@ -722,7 +722,7 @@ static int fsl_ifc_attach_chip(struct nand_chip *chip) struct fsl_ifc_mtd *priv = nand_get_controller_data(chip); dev_dbg(priv->dev, "%s: nand->numchips = %d\n", __func__, - chip->numchips); + nanddev_ntargets(&chip->base)); dev_dbg(priv->dev, "%s: nand->chipsize = %lld\n", __func__, nanddev_target_size(&chip->base)); dev_dbg(priv->dev, "%s: nand->pagemask = %8x\n", __func__, diff --git a/drivers/mtd/nand/raw/hisi504_nand.c b/drivers/mtd/nand/raw/hisi504_nand.c index f3f9aa160cff..e4526fff9da4 100644 --- a/drivers/mtd/nand/raw/hisi504_nand.c +++ b/drivers/mtd/nand/raw/hisi504_nand.c @@ -849,7 +849,7 @@ static int hisi_nfc_resume(struct device *dev) struct hinfc_host *host = dev_get_drvdata(dev); struct nand_chip *chip = &host->chip; - for (cs = 0; cs < chip->numchips; cs++) + for (cs = 0; cs < nanddev_ntargets(&chip->base); cs++) hisi_nfc_send_cmd_reset(host, cs); hinfc_write(host, SET_HINFC504_PWIDTH(HINFC504_W_LATCH, HINFC504_R_LATCH, HINFC504_RW_LATCH), HINFC504_PWIDTH); diff --git a/drivers/mtd/nand/raw/ingenic/jz4740_nand.c b/drivers/mtd/nand/raw/ingenic/jz4740_nand.c index 27e16c44a94d..f759f1672855 100644 --- a/drivers/mtd/nand/raw/ingenic/jz4740_nand.c +++ b/drivers/mtd/nand/raw/ingenic/jz4740_nand.c @@ -354,7 +354,6 @@ static int jz_nand_detect_bank(struct platform_device *pdev, } /* Update size of the MTD. */ - chip->numchips++; memorg->ntargets++; mtd->size += nanddev_target_size(&chip->base); } diff --git a/drivers/mtd/nand/raw/internals.h b/drivers/mtd/nand/raw/internals.h index fbf6ca015cd7..a204f9d7e123 100644 --- a/drivers/mtd/nand/raw/internals.h +++ b/drivers/mtd/nand/raw/internals.h @@ -110,7 +110,7 @@ static inline int nand_exec_op(struct nand_chip *chip, if (!nand_has_exec_op(chip)) return -ENOTSUPP; - if (WARN_ON(op->cs >= chip->numchips)) + if (WARN_ON(op->cs >= nanddev_ntargets(&chip->base))) return -EINVAL; return chip->controller->ops->exec_op(chip, op, false); diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c index f89cc8be5ce4..73eb23b5cdad 100644 --- a/drivers/mtd/nand/raw/nand_base.c +++ b/drivers/mtd/nand/raw/nand_base.c @@ -240,10 +240,10 @@ static int check_offs_len(struct nand_chip *chip, loff_t ofs, uint64_t len) void nand_select_target(struct nand_chip *chip, unsigned int cs) { /* - * cs should always lie between 0 and chip->numchips, when that's not - * the case it's a bug and the caller should be fixed. + * cs should always lie between 0 and nanddev_ntargets(), when that's + * not the case it's a bug and the caller should be fixed. */ - if (WARN_ON(cs > chip->numchips)) + if (WARN_ON(cs > nanddev_ntargets(&chip->base))) return; chip->cur_cs = cs; @@ -4999,12 +4999,6 @@ static int nand_scan_ident(struct nand_chip *chip, unsigned int maxchips, if (!mtd->name && mtd->dev.parent) mtd->name = dev_name(mtd->dev.parent); - /* - * Start with chips->numchips = maxchips to let nand_select_target() do - * its job. chip->numchips will be adjusted after. - */ - chip->numchips = maxchips; - /* Set the default functions */ nand_set_defaults(chip); @@ -5052,7 +5046,6 @@ static int nand_scan_ident(struct nand_chip *chip, unsigned int maxchips, /* Store the number of chips and calc total size for mtd */ memorg->ntargets = i; - chip->numchips = i; mtd->size = i * nanddev_target_size(&chip->base); return 0; @@ -5794,7 +5787,7 @@ static int nand_scan_tail(struct nand_chip *chip) goto err_nanddev_cleanup; /* Enter fastest possible mode on all dies. */ - for (i = 0; i < chip->numchips; i++) { + for (i = 0; i < nanddev_ntargets(&chip->base); i++) { ret = nand_setup_data_interface(chip, i); if (ret) goto err_nanddev_cleanup; diff --git a/drivers/mtd/nand/raw/nand_bbt.c b/drivers/mtd/nand/raw/nand_bbt.c index 42399a32d34a..9a7855839f81 100644 --- a/drivers/mtd/nand/raw/nand_bbt.c +++ b/drivers/mtd/nand/raw/nand_bbt.c @@ -269,7 +269,7 @@ static int read_abs_bbt(struct nand_chip *this, uint8_t *buf, if (td->options & NAND_BBT_PERCHIP) { int offs = 0; - for (i = 0; i < this->numchips; i++) { + for (i = 0; i < nanddev_ntargets(&this->base); i++) { if (chip == -1 || chip == i) res = read_bbt(this, buf, td->pages[i], targetsize >> this->bbt_erase_shift, @@ -478,9 +478,9 @@ static int create_bbt(struct nand_chip *this, uint8_t *buf, startblock = 0; from = 0; } else { - if (chip >= this->numchips) { + if (chip >= nanddev_ntargets(&this->base)) { pr_warn("create_bbt(): chipnr (%d) > available chips (%d)\n", - chip + 1, this->numchips); + chip + 1, nanddev_ntargets(&this->base)); return -EINVAL; } numblocks = targetsize >> this->bbt_erase_shift; @@ -550,7 +550,7 @@ static int search_bbt(struct nand_chip *this, uint8_t *buf, /* Do we have a bbt per chip? */ if (td->options & NAND_BBT_PERCHIP) { - chips = this->numchips; + chips = nanddev_ntargets(&this->base); bbtblocks = targetsize >> this->bbt_erase_shift; startblock &= bbtblocks - 1; } else { @@ -643,7 +643,7 @@ static int get_bbt_block(struct nand_chip *this, struct nand_bbt_descr *td, numblocks = (int)(targetsize >> this->bbt_erase_shift); if (!(td->options & NAND_BBT_PERCHIP)) - numblocks *= this->numchips; + numblocks *= nanddev_ntargets(&this->base); /* * Automatic placement of the bad block table. Search direction @@ -745,7 +745,7 @@ static int write_bbt(struct nand_chip *this, uint8_t *buf, numblocks = (int)(targetsize >> this->bbt_erase_shift); /* Full device write or specific chip? */ if (chipsel == -1) { - nrchips = this->numchips; + nrchips = nanddev_ntargets(&this->base); } else { nrchips = chipsel + 1; chip = chipsel; @@ -932,7 +932,7 @@ static int check_create(struct nand_chip *this, uint8_t *buf, /* Do we have a bbt per chip? */ if (td->options & NAND_BBT_PERCHIP) - chips = this->numchips; + chips = nanddev_ntargets(&this->base); else chips = 1; @@ -1111,7 +1111,7 @@ static void mark_bbt_region(struct nand_chip *this, struct nand_bbt_descr *td) /* Do we have a bbt per chip? */ if (td->options & NAND_BBT_PERCHIP) { - chips = this->numchips; + chips = nanddev_ntargets(&this->base); nrblocks = (int)(targetsize >> this->bbt_erase_shift); } else { chips = 1; diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h index 02657591c3fc..27c968d370bf 100644 --- a/include/linux/mtd/rawnand.h +++ b/include/linux/mtd/rawnand.h @@ -1002,7 +1002,6 @@ struct nand_legacy { * set to the actually used ONFI mode if the chip is * ONFI compliant or deduced from the datasheet if * the NAND chip is not ONFI compliant. - * @numchips: [INTERN] number of physical chips * @pagemask: [INTERN] page number mask = number of (pages / chip) - 1 * @data_buf: [INTERN] buffer for data, size is (page size + oobsize). * @pagecache: Structure containing page cache related fields @@ -1016,8 +1015,9 @@ struct nand_legacy { * @data_interface: [INTERN] NAND interface timing information * @cur_cs: currently selected target. -1 means no target selected, * otherwise we should always have cur_cs >= 0 && - * cur_cs < numchips. NAND Controller drivers should not - * modify this value, but they're allowed to read it. + * cur_cs < nanddev_ntargets(). NAND Controller drivers + * should not modify this value, but they're allowed to + * read it. * @read_retries: [INTERN] the number of read retry modes supported * @lock: lock protecting the suspended field. Also used to * serialize accesses to the NAND device. @@ -1051,7 +1051,6 @@ struct nand_chip { int phys_erase_shift; int bbt_erase_shift; int chip_shift; - int numchips; int pagemask; u8 *data_buf; -- cgit From 6a1b66d6c8d691b1395d5c3b660ac4469c25bc28 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Sun, 4 Nov 2018 16:09:42 +0100 Subject: mtd: rawnand: Get rid of chip->ecc_{strength,step}_ds nand_device embeds a nand_ecc_req object which contains the minimum strength and step-size required by the NAND device. Drop the chip->ecc_{strength,step}_ds fields and use chip->base.eccreq.{strength,step_size} instead. Signed-off-by: Boris Brezillon Signed-off-by: Miquel Raynal Reviewed-by: Frieder Schrempf --- drivers/mtd/nand/raw/atmel/nand-controller.c | 8 +++--- drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c | 11 +++++--- drivers/mtd/nand/raw/marvell_nand.c | 6 ++--- drivers/mtd/nand/raw/mtk_nand.c | 4 +-- drivers/mtd/nand/raw/nand_base.c | 15 ++++++----- drivers/mtd/nand/raw/nand_esmt.c | 10 +++---- drivers/mtd/nand/raw/nand_hynix.c | 40 ++++++++++++++-------------- drivers/mtd/nand/raw/nand_jedec.c | 4 +-- drivers/mtd/nand/raw/nand_micron.c | 12 ++++----- drivers/mtd/nand/raw/nand_onfi.c | 8 +++--- drivers/mtd/nand/raw/nand_samsung.c | 18 ++++++------- drivers/mtd/nand/raw/nand_toshiba.c | 10 +++---- drivers/mtd/nand/raw/sunxi_nand.c | 4 +-- drivers/mtd/nand/raw/tegra_nand.c | 8 +++--- include/linux/mtd/rawnand.h | 8 ------ 15 files changed, 81 insertions(+), 85 deletions(-) diff --git a/drivers/mtd/nand/raw/atmel/nand-controller.c b/drivers/mtd/nand/raw/atmel/nand-controller.c index 3205b705d734..80d14ba06245 100644 --- a/drivers/mtd/nand/raw/atmel/nand-controller.c +++ b/drivers/mtd/nand/raw/atmel/nand-controller.c @@ -1072,15 +1072,15 @@ static int atmel_nand_pmecc_init(struct nand_chip *chip) req.ecc.strength = ATMEL_PMECC_MAXIMIZE_ECC_STRENGTH; else if (chip->ecc.strength) req.ecc.strength = chip->ecc.strength; - else if (chip->ecc_strength_ds) - req.ecc.strength = chip->ecc_strength_ds; + else if (chip->base.eccreq.strength) + req.ecc.strength = chip->base.eccreq.strength; else req.ecc.strength = ATMEL_PMECC_MAXIMIZE_ECC_STRENGTH; if (chip->ecc.size) req.ecc.sectorsize = chip->ecc.size; - else if (chip->ecc_step_ds) - req.ecc.sectorsize = chip->ecc_step_ds; + else if (chip->base.eccreq.step_size) + req.ecc.sectorsize = chip->base.eccreq.step_size; else req.ecc.sectorsize = ATMEL_PMECC_SECTOR_SIZE_AUTO; diff --git a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c index eec39615bc6f..40df20d1adf5 100644 --- a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c +++ b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c @@ -204,7 +204,8 @@ static int set_geometry_by_ecc_info(struct gpmi_nand_data *this, default: dev_err(this->dev, "unsupported nand chip. ecc bits : %d, ecc size : %d\n", - chip->ecc_strength_ds, chip->ecc_step_ds); + chip->base.eccreq.strength, + chip->base.eccreq.step_size); return -EINVAL; } geo->ecc_chunk_size = ecc_step; @@ -417,11 +418,13 @@ int common_nfc_set_geometry(struct gpmi_nand_data *this) if ((of_property_read_bool(this->dev->of_node, "fsl,use-minimum-ecc")) || legacy_set_geometry(this)) { - if (!(chip->ecc_strength_ds > 0 && chip->ecc_step_ds > 0)) + if (!(chip->base.eccreq.strength > 0 && + chip->base.eccreq.step_size > 0)) return -EINVAL; - return set_geometry_by_ecc_info(this, chip->ecc_strength_ds, - chip->ecc_step_ds); + return set_geometry_by_ecc_info(this, + chip->base.eccreq.strength, + chip->base.eccreq.step_size); } return 0; diff --git a/drivers/mtd/nand/raw/marvell_nand.c b/drivers/mtd/nand/raw/marvell_nand.c index e81d401ee16c..825c47b3fa0d 100644 --- a/drivers/mtd/nand/raw/marvell_nand.c +++ b/drivers/mtd/nand/raw/marvell_nand.c @@ -2248,9 +2248,9 @@ static int marvell_nand_ecc_init(struct mtd_info *mtd, int ret; if (ecc->mode != NAND_ECC_NONE && (!ecc->size || !ecc->strength)) { - if (chip->ecc_step_ds && chip->ecc_strength_ds) { - ecc->size = chip->ecc_step_ds; - ecc->strength = chip->ecc_strength_ds; + if (chip->base.eccreq.step_size && chip->base.eccreq.strength) { + ecc->size = chip->base.eccreq.step_size; + ecc->strength = chip->base.eccreq.strength; } else { dev_info(nfc->dev, "No minimum ECC strength, using 1b/512B\n"); diff --git a/drivers/mtd/nand/raw/mtk_nand.c b/drivers/mtd/nand/raw/mtk_nand.c index 2c0e09187773..b17619f30b1b 100644 --- a/drivers/mtd/nand/raw/mtk_nand.c +++ b/drivers/mtd/nand/raw/mtk_nand.c @@ -1197,8 +1197,8 @@ static int mtk_nfc_ecc_init(struct device *dev, struct mtd_info *mtd) /* if optional dt settings not present */ if (!nand->ecc.size || !nand->ecc.strength) { /* use datasheet requirements */ - nand->ecc.strength = nand->ecc_strength_ds; - nand->ecc.size = nand->ecc_step_ds; + nand->ecc.strength = nand->base.eccreq.strength; + nand->ecc.size = nand->base.eccreq.step_size; /* * align eccstrength and eccsize diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c index 73eb23b5cdad..4646add22114 100644 --- a/drivers/mtd/nand/raw/nand_base.c +++ b/drivers/mtd/nand/raw/nand_base.c @@ -4547,8 +4547,8 @@ static bool find_full_id_nand(struct nand_chip *chip, memorg->pagesize * memorg->pages_per_eraseblock); chip->options |= type->options; - chip->ecc_strength_ds = NAND_ECC_STRENGTH(type); - chip->ecc_step_ds = NAND_ECC_STEP(type); + chip->base.eccreq.strength = NAND_ECC_STRENGTH(type); + chip->base.eccreq.step_size = NAND_ECC_STEP(type); chip->onfi_timing_mode_default = type->onfi_timing_mode_default; @@ -5227,8 +5227,8 @@ nand_match_ecc_req(struct nand_chip *chip, { struct mtd_info *mtd = nand_to_mtd(chip); const struct nand_ecc_step_info *stepinfo; - int req_step = chip->ecc_step_ds; - int req_strength = chip->ecc_strength_ds; + int req_step = chip->base.eccreq.step_size; + int req_strength = chip->base.eccreq.strength; int req_corr, step_size, strength, nsteps, ecc_bytes, ecc_bytes_total; int best_step, best_strength, best_ecc_bytes; int best_ecc_bytes_total = INT_MAX; @@ -5421,7 +5421,7 @@ static bool nand_ecc_strength_good(struct nand_chip *chip) struct nand_ecc_ctrl *ecc = &chip->ecc; int corr, ds_corr; - if (ecc->size == 0 || chip->ecc_step_ds == 0) + if (ecc->size == 0 || chip->base.eccreq.step_size == 0) /* Not enough information */ return true; @@ -5430,9 +5430,10 @@ static bool nand_ecc_strength_good(struct nand_chip *chip) * the correction density. */ corr = (mtd->writesize * ecc->strength) / ecc->size; - ds_corr = (mtd->writesize * chip->ecc_strength_ds) / chip->ecc_step_ds; + ds_corr = (mtd->writesize * chip->base.eccreq.strength) / + chip->base.eccreq.step_size; - return corr >= ds_corr && ecc->strength >= chip->ecc_strength_ds; + return corr >= ds_corr && ecc->strength >= chip->base.eccreq.strength; } static int rawnand_erase(struct nand_device *nand, const struct nand_pos *pos) diff --git a/drivers/mtd/nand/raw/nand_esmt.c b/drivers/mtd/nand/raw/nand_esmt.c index 96f039a83bc8..3de5e89482f5 100644 --- a/drivers/mtd/nand/raw/nand_esmt.c +++ b/drivers/mtd/nand/raw/nand_esmt.c @@ -14,20 +14,20 @@ static void esmt_nand_decode_id(struct nand_chip *chip) /* Extract ECC requirements from 5th id byte. */ if (chip->id.len >= 5 && nand_is_slc(chip)) { - chip->ecc_step_ds = 512; + chip->base.eccreq.step_size = 512; switch (chip->id.data[4] & 0x3) { case 0x0: - chip->ecc_strength_ds = 4; + chip->base.eccreq.strength = 4; break; case 0x1: - chip->ecc_strength_ds = 2; + chip->base.eccreq.strength = 2; break; case 0x2: - chip->ecc_strength_ds = 1; + chip->base.eccreq.strength = 1; break; default: WARN(1, "Could not get ECC info"); - chip->ecc_step_ds = 0; + chip->base.eccreq.step_size = 0; break; } } diff --git a/drivers/mtd/nand/raw/nand_hynix.c b/drivers/mtd/nand/raw/nand_hynix.c index 272b934dffb7..821d221b83eb 100644 --- a/drivers/mtd/nand/raw/nand_hynix.c +++ b/drivers/mtd/nand/raw/nand_hynix.c @@ -508,30 +508,30 @@ static void hynix_nand_extract_ecc_requirements(struct nand_chip *chip, if (valid_jedecid) { /* Reference: H27UCG8T2E datasheet */ - chip->ecc_step_ds = 1024; + chip->base.eccreq.step_size = 1024; switch (ecc_level) { case 0: - chip->ecc_step_ds = 0; - chip->ecc_strength_ds = 0; + chip->base.eccreq.step_size = 0; + chip->base.eccreq.strength = 0; break; case 1: - chip->ecc_strength_ds = 4; + chip->base.eccreq.strength = 4; break; case 2: - chip->ecc_strength_ds = 24; + chip->base.eccreq.strength = 24; break; case 3: - chip->ecc_strength_ds = 32; + chip->base.eccreq.strength = 32; break; case 4: - chip->ecc_strength_ds = 40; + chip->base.eccreq.strength = 40; break; case 5: - chip->ecc_strength_ds = 50; + chip->base.eccreq.strength = 50; break; case 6: - chip->ecc_strength_ds = 60; + chip->base.eccreq.strength = 60; break; default: /* @@ -552,14 +552,14 @@ static void hynix_nand_extract_ecc_requirements(struct nand_chip *chip, if (nand_tech < 3) { /* > 26nm, reference: H27UBG8T2A datasheet */ if (ecc_level < 5) { - chip->ecc_step_ds = 512; - chip->ecc_strength_ds = 1 << ecc_level; + chip->base.eccreq.step_size = 512; + chip->base.eccreq.strength = 1 << ecc_level; } else if (ecc_level < 7) { if (ecc_level == 5) - chip->ecc_step_ds = 2048; + chip->base.eccreq.step_size = 2048; else - chip->ecc_step_ds = 1024; - chip->ecc_strength_ds = 24; + chip->base.eccreq.step_size = 1024; + chip->base.eccreq.strength = 24; } else { /* * We should never reach this case, but if that @@ -572,14 +572,14 @@ static void hynix_nand_extract_ecc_requirements(struct nand_chip *chip, } else { /* <= 26nm, reference: H27UBG8T2B datasheet */ if (!ecc_level) { - chip->ecc_step_ds = 0; - chip->ecc_strength_ds = 0; + chip->base.eccreq.step_size = 0; + chip->base.eccreq.strength = 0; } else if (ecc_level < 5) { - chip->ecc_step_ds = 512; - chip->ecc_strength_ds = 1 << (ecc_level - 1); + chip->base.eccreq.step_size = 512; + chip->base.eccreq.strength = 1 << (ecc_level - 1); } else { - chip->ecc_step_ds = 1024; - chip->ecc_strength_ds = 24 + + chip->base.eccreq.step_size = 1024; + chip->base.eccreq.strength = 24 + (8 * (ecc_level - 5)); } } diff --git a/drivers/mtd/nand/raw/nand_jedec.c b/drivers/mtd/nand/raw/nand_jedec.c index 99e2f017c79b..9b540e76f84f 100644 --- a/drivers/mtd/nand/raw/nand_jedec.c +++ b/drivers/mtd/nand/raw/nand_jedec.c @@ -110,8 +110,8 @@ int nand_jedec_detect(struct nand_chip *chip) ecc = &p->ecc_info[0]; if (ecc->codeword_size >= 9) { - chip->ecc_strength_ds = ecc->ecc_bits; - chip->ecc_step_ds = 1 << ecc->codeword_size; + chip->base.eccreq.strength = ecc->ecc_bits; + chip->base.eccreq.step_size = 1 << ecc->codeword_size; } else { pr_warn("Invalid codeword size\n"); } diff --git a/drivers/mtd/nand/raw/nand_micron.c b/drivers/mtd/nand/raw/nand_micron.c index 98ce6575aa64..7a2cef02eacd 100644 --- a/drivers/mtd/nand/raw/nand_micron.c +++ b/drivers/mtd/nand/raw/nand_micron.c @@ -391,7 +391,7 @@ static int micron_supports_on_die_ecc(struct nand_chip *chip) /* * We only support on-die ECC of 4/512 or 8/512 */ - if (chip->ecc_strength_ds != 4 && chip->ecc_strength_ds != 8) + if (chip->base.eccreq.strength != 4 && chip->base.eccreq.strength != 8) return MICRON_ON_DIE_UNSUPPORTED; /* 0x2 means on-die ECC is available. */ @@ -424,7 +424,7 @@ static int micron_supports_on_die_ecc(struct nand_chip *chip) /* * We only support on-die ECC of 4/512 or 8/512 */ - if (chip->ecc_strength_ds != 4 && chip->ecc_strength_ds != 8) + if (chip->base.eccreq.strength != 4 && chip->base.eccreq.strength != 8) return MICRON_ON_DIE_UNSUPPORTED; return MICRON_ON_DIE_SUPPORTED; @@ -479,7 +479,7 @@ static int micron_nand_init(struct nand_chip *chip) * That's not needed for 8-bit ECC, because the status expose * a better approximation of the number of bitflips in a page. */ - if (chip->ecc_strength_ds == 4) { + if (chip->base.eccreq.strength == 4) { micron->ecc.rawbuf = kmalloc(mtd->writesize + mtd->oobsize, GFP_KERNEL); @@ -489,16 +489,16 @@ static int micron_nand_init(struct nand_chip *chip) } } - if (chip->ecc_strength_ds == 4) + if (chip->base.eccreq.strength == 4) mtd_set_ooblayout(mtd, µn_nand_on_die_4_ooblayout_ops); else mtd_set_ooblayout(mtd, µn_nand_on_die_8_ooblayout_ops); - chip->ecc.bytes = chip->ecc_strength_ds * 2; + chip->ecc.bytes = chip->base.eccreq.strength * 2; chip->ecc.size = 512; - chip->ecc.strength = chip->ecc_strength_ds; + chip->ecc.strength = chip->base.eccreq.strength; chip->ecc.algo = NAND_ECC_BCH; chip->ecc.read_page = micron_nand_read_page_on_die_ecc; chip->ecc.write_page = micron_nand_write_page_on_die_ecc; diff --git a/drivers/mtd/nand/raw/nand_onfi.c b/drivers/mtd/nand/raw/nand_onfi.c index 7b468e7214c7..0b879bd0a68c 100644 --- a/drivers/mtd/nand/raw/nand_onfi.c +++ b/drivers/mtd/nand/raw/nand_onfi.c @@ -94,8 +94,8 @@ static int nand_flash_detect_ext_param_page(struct nand_chip *chip, goto ext_out; } - chip->ecc_strength_ds = ecc->ecc_bits; - chip->ecc_step_ds = 1 << ecc->codeword_size; + chip->base.eccreq.strength = ecc->ecc_bits; + chip->base.eccreq.step_size = 1 << ecc->codeword_size; ret = 0; ext_out: @@ -252,8 +252,8 @@ int nand_onfi_detect(struct nand_chip *chip) chip->options |= NAND_BUSWIDTH_16; if (p->ecc_bits != 0xff) { - chip->ecc_strength_ds = p->ecc_bits; - chip->ecc_step_ds = 512; + chip->base.eccreq.strength = p->ecc_bits; + chip->base.eccreq.step_size = 512; } else if (onfi_version >= 21 && (le16_to_cpu(p->features) & ONFI_FEATURE_EXT_PARAM_PAGE)) { diff --git a/drivers/mtd/nand/raw/nand_samsung.c b/drivers/mtd/nand/raw/nand_samsung.c index 9a9ad43cc97d..f7d7041b6213 100644 --- a/drivers/mtd/nand/raw/nand_samsung.c +++ b/drivers/mtd/nand/raw/nand_samsung.c @@ -80,23 +80,23 @@ static void samsung_nand_decode_id(struct nand_chip *chip) /* Extract ECC requirements from 5th id byte*/ extid = (chip->id.data[4] >> 4) & 0x07; if (extid < 5) { - chip->ecc_step_ds = 512; - chip->ecc_strength_ds = 1 << extid; + chip->base.eccreq.step_size = 512; + chip->base.eccreq.strength = 1 << extid; } else { - chip->ecc_step_ds = 1024; + chip->base.eccreq.step_size = 1024; switch (extid) { case 5: - chip->ecc_strength_ds = 24; + chip->base.eccreq.strength = 24; break; case 6: - chip->ecc_strength_ds = 40; + chip->base.eccreq.strength = 40; break; case 7: - chip->ecc_strength_ds = 60; + chip->base.eccreq.strength = 60; break; default: WARN(1, "Could not decode ECC info"); - chip->ecc_step_ds = 0; + chip->base.eccreq.step_size = 0; } } } else { @@ -106,8 +106,8 @@ static void samsung_nand_decode_id(struct nand_chip *chip) switch (chip->id.data[1]) { /* K9F4G08U0D-S[I|C]B0(T00) */ case 0xDC: - chip->ecc_step_ds = 512; - chip->ecc_strength_ds = 1; + chip->base.eccreq.step_size = 512; + chip->base.eccreq.strength = 1; break; /* K9F1G08U0E 21nm chips do not support subpage write */ diff --git a/drivers/mtd/nand/raw/nand_toshiba.c b/drivers/mtd/nand/raw/nand_toshiba.c index d8465049dfd6..13f9632f1cb4 100644 --- a/drivers/mtd/nand/raw/nand_toshiba.c +++ b/drivers/mtd/nand/raw/nand_toshiba.c @@ -130,20 +130,20 @@ static void toshiba_nand_decode_id(struct nand_chip *chip) * - 24nm: 8 bit ECC for each 512Byte is required. */ if (chip->id.len >= 6 && nand_is_slc(chip)) { - chip->ecc_step_ds = 512; + chip->base.eccreq.step_size = 512; switch (chip->id.data[5] & 0x7) { case 0x4: - chip->ecc_strength_ds = 1; + chip->base.eccreq.strength = 1; break; case 0x5: - chip->ecc_strength_ds = 4; + chip->base.eccreq.strength = 4; break; case 0x6: - chip->ecc_strength_ds = 8; + chip->base.eccreq.strength = 8; break; default: WARN(1, "Could not get ECC info"); - chip->ecc_step_ds = 0; + chip->base.eccreq.step_size = 0; break; } } diff --git a/drivers/mtd/nand/raw/sunxi_nand.c b/drivers/mtd/nand/raw/sunxi_nand.c index d206819c962a..13f03324d36a 100644 --- a/drivers/mtd/nand/raw/sunxi_nand.c +++ b/drivers/mtd/nand/raw/sunxi_nand.c @@ -1723,8 +1723,8 @@ static int sunxi_nand_attach_chip(struct nand_chip *nand) nand->options |= NAND_SUBPAGE_READ; if (!ecc->size) { - ecc->size = nand->ecc_step_ds; - ecc->strength = nand->ecc_strength_ds; + ecc->size = nand->base.eccreq.step_size; + ecc->strength = nand->base.eccreq.strength; } if (!ecc->size || !ecc->strength) diff --git a/drivers/mtd/nand/raw/tegra_nand.c b/drivers/mtd/nand/raw/tegra_nand.c index 13be32c38194..3cc9a4c41443 100644 --- a/drivers/mtd/nand/raw/tegra_nand.c +++ b/drivers/mtd/nand/raw/tegra_nand.c @@ -853,7 +853,7 @@ static int tegra_nand_get_strength(struct nand_chip *chip, const int *strength, } else { strength_sel = strength[i]; - if (strength_sel < chip->ecc_strength_ds) + if (strength_sel < chip->base.eccreq.strength) continue; } @@ -917,9 +917,9 @@ static int tegra_nand_attach_chip(struct nand_chip *chip) chip->ecc.mode = NAND_ECC_HW; chip->ecc.size = 512; chip->ecc.steps = mtd->writesize / chip->ecc.size; - if (chip->ecc_step_ds != 512) { + if (chip->base.eccreq.step_size != 512) { dev_err(ctrl->dev, "Unsupported step size %d\n", - chip->ecc_step_ds); + chip->base.eccreq.step_size); return -EINVAL; } @@ -950,7 +950,7 @@ static int tegra_nand_attach_chip(struct nand_chip *chip) if (ret < 0) { dev_err(ctrl->dev, "No valid strength found, minimum %d\n", - chip->ecc_strength_ds); + chip->base.eccreq.strength); return ret; } diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h index 27c968d370bf..c0589f82c1f8 100644 --- a/include/linux/mtd/rawnand.h +++ b/include/linux/mtd/rawnand.h @@ -992,12 +992,6 @@ struct nand_legacy { * @badblockbits: [INTERN] minimum number of set bits in a good block's * bad block marker position; i.e., BBM == 11110111b is * not bad when badblockbits == 7 - * @ecc_strength_ds: [INTERN] ECC correctability from the datasheet. - * Minimum amount of bit errors per @ecc_step_ds guaranteed - * to be correctable. If unknown, set to zero. - * @ecc_step_ds: [INTERN] ECC step required by the @ecc_strength_ds, - * also from the datasheet. It is the recommended ECC step - * size, if known; if unknown, set to zero. * @onfi_timing_mode_default: [INTERN] default ONFI timing mode. This field is * set to the actually used ONFI mode if the chip is * ONFI compliant or deduced from the datasheet if @@ -1060,8 +1054,6 @@ struct nand_chip { } pagecache; int subpagesize; - uint16_t ecc_strength_ds; - uint16_t ecc_step_ds; int onfi_timing_mode_default; int badblockpos; int badblockbits; -- cgit From e90a619fb7e1acb5e18f1ab618c6d10b08f0fc70 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Thu, 7 Feb 2019 15:28:24 +0100 Subject: mtd: nand: omap: Fix comment in platform data using wrong Kconfig symbol The symbol that is being used in the #if/#endif block is not the one which is mentioned at the bottom. Fixes: 93af53b8633c ("nand: omap2: Remove horrible ifdefs to fix module probe") Signed-off-by: Miquel Raynal --- include/linux/platform_data/elm.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/platform_data/elm.h b/include/linux/platform_data/elm.h index b8686c00f15f..fef4b081b736 100644 --- a/include/linux/platform_data/elm.h +++ b/include/linux/platform_data/elm.h @@ -60,6 +60,6 @@ static inline int elm_config(struct device *dev, enum bch_ecc bch_type, { return -ENOSYS; } -#endif /* CONFIG_MTD_NAND_ECC_BCH */ +#endif /* CONFIG_MTD_NAND_OMAP_BCH */ #endif /* __ELM_H */ -- cgit From 714c068228d3275da6d36f29e544f7e5ae648849 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Wed, 6 Feb 2019 15:12:27 +0100 Subject: mtd: nand: Clarify Kconfig entry for software BCH ECC algorithm There is no point in having two distinct entries, merge them and rename the symbol for more clarity: MTD_NAND_ECC_SW_BCH Signed-off-by: Miquel Raynal --- arch/arm/configs/omap2plus_defconfig | 2 +- arch/arm/configs/pxa_defconfig | 2 +- arch/mips/configs/db1xxx_defconfig | 2 +- arch/mips/configs/generic/board-ni169445.config | 2 +- drivers/mtd/devices/Kconfig | 2 +- drivers/mtd/nand/raw/Kconfig | 9 ++------- drivers/mtd/nand/raw/Makefile | 2 +- drivers/mtd/nand/raw/nand_base.c | 2 +- drivers/mtd/nand/raw/omap2.c | 4 ++-- include/linux/mtd/nand_bch.h | 6 +++--- 10 files changed, 14 insertions(+), 19 deletions(-) diff --git a/arch/arm/configs/omap2plus_defconfig b/arch/arm/configs/omap2plus_defconfig index 3f03ec6d2644..7dc2ac9175de 100644 --- a/arch/arm/configs/omap2plus_defconfig +++ b/arch/arm/configs/omap2plus_defconfig @@ -144,7 +144,7 @@ CONFIG_MTD_ONENAND=y CONFIG_MTD_ONENAND_VERIFY_WRITE=y CONFIG_MTD_ONENAND_OMAP2=y CONFIG_MTD_NAND=y -CONFIG_MTD_NAND_ECC_BCH=y +CONFIG_MTD_NAND_ECC_SW_BCH=y CONFIG_MTD_NAND_OMAP2=y CONFIG_MTD_NAND_OMAP_BCH=y CONFIG_MTD_SPI_NOR=m diff --git a/arch/arm/configs/pxa_defconfig b/arch/arm/configs/pxa_defconfig index d4654755b09c..d91adb49ae11 100644 --- a/arch/arm/configs/pxa_defconfig +++ b/arch/arm/configs/pxa_defconfig @@ -186,7 +186,7 @@ CONFIG_MTD_M25P80=m CONFIG_MTD_BLOCK2MTD=y CONFIG_MTD_DOCG3=m CONFIG_MTD_NAND=m -CONFIG_MTD_NAND_ECC_BCH=y +CONFIG_MTD_NAND_ECC_SW_BCH=y CONFIG_MTD_NAND_GPIO=m CONFIG_MTD_NAND_DISKONCHIP=m CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADVANCED=y diff --git a/arch/mips/configs/db1xxx_defconfig b/arch/mips/configs/db1xxx_defconfig index 34633b7611cb..c5a2c6f234d4 100644 --- a/arch/mips/configs/db1xxx_defconfig +++ b/arch/mips/configs/db1xxx_defconfig @@ -96,7 +96,7 @@ CONFIG_MTD_PHYSMAP=y CONFIG_MTD_M25P80=y CONFIG_MTD_SST25L=y CONFIG_MTD_NAND=y -CONFIG_MTD_NAND_ECC_BCH=y +CONFIG_MTD_NAND_ECC_SW_BCH=y CONFIG_MTD_NAND_AU1550=y CONFIG_MTD_NAND_PLATFORM=y CONFIG_MTD_SPI_NOR=y diff --git a/arch/mips/configs/generic/board-ni169445.config b/arch/mips/configs/generic/board-ni169445.config index f72223b366ca..01f6ab0d47d5 100644 --- a/arch/mips/configs/generic/board-ni169445.config +++ b/arch/mips/configs/generic/board-ni169445.config @@ -16,7 +16,7 @@ CONFIG_MTD_BLOCK=y CONFIG_MTD_CMDLINE_PARTS=y CONFIG_MTD_NAND_ECC=y -CONFIG_MTD_NAND_ECC_BCH=y +CONFIG_MTD_NAND_ECC_SW_BCH=y CONFIG_MTD_NAND=y CONFIG_MTD_NAND_GPIO=y CONFIG_MTD_NAND_IDS=y diff --git a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig index aa983422aa97..f9258d666846 100644 --- a/drivers/mtd/devices/Kconfig +++ b/drivers/mtd/devices/Kconfig @@ -207,7 +207,7 @@ comment "Disk-On-Chip Device Drivers" config MTD_DOCG3 tristate "M-Systems Disk-On-Chip G3" select BCH - select BCH_CONST_PARAMS if !MTD_NAND_BCH + select BCH_CONST_PARAMS if !MTD_NAND_ECC_SW_BCH select BITREVERSE help This provides an MTD device driver for the M-Systems DiskOnChip diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig index 80b5fec1f75a..7a1bde4fe9f6 100644 --- a/drivers/mtd/nand/raw/Kconfig +++ b/drivers/mtd/nand/raw/Kconfig @@ -22,14 +22,9 @@ menuconfig MTD_NAND if MTD_NAND -config MTD_NAND_BCH - tristate +config MTD_NAND_ECC_SW_BCH + tristate "Support software BCH ECC" 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 diff --git a/drivers/mtd/nand/raw/Makefile b/drivers/mtd/nand/raw/Makefile index 5552c4a9f2cf..9749ff00f9e4 100644 --- a/drivers/mtd/nand/raw/Makefile +++ b/drivers/mtd/nand/raw/Makefile @@ -2,7 +2,7 @@ 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_NAND_ECC_SW_BCH) += nand_bch.o obj-$(CONFIG_MTD_SM_COMMON) += sm_common.o obj-$(CONFIG_MTD_NAND_CAFE) += cafe_nand.o diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c index 4646add22114..95fac92d6b82 100644 --- a/drivers/mtd/nand/raw/nand_base.c +++ b/drivers/mtd/nand/raw/nand_base.c @@ -5087,7 +5087,7 @@ static int nand_set_ecc_soft_ops(struct nand_chip *chip) return 0; case NAND_ECC_BCH: if (!mtd_nand_has_bch()) { - WARN(1, "CONFIG_MTD_NAND_ECC_BCH not enabled\n"); + WARN(1, "CONFIG_MTD_NAND_ECC_SW_BCH not enabled\n"); return -EINVAL; } ecc->calculate = nand_bch_calculate_ecc; diff --git a/drivers/mtd/nand/raw/omap2.c b/drivers/mtd/nand/raw/omap2.c index 8f280a2962c8..a9a275342a41 100644 --- a/drivers/mtd/nand/raw/omap2.c +++ b/drivers/mtd/nand/raw/omap2.c @@ -1725,9 +1725,9 @@ static bool omap2_nand_ecc_check(struct omap_nand_info *info) break; } - if (ecc_needs_bch && !IS_ENABLED(CONFIG_MTD_NAND_ECC_BCH)) { + if (ecc_needs_bch && !IS_ENABLED(CONFIG_MTD_NAND_ECC_SW_BCH)) { dev_err(&info->pdev->dev, - "CONFIG_MTD_NAND_ECC_BCH not enabled\n"); + "CONFIG_MTD_NAND_ECC_SW_BCH not enabled\n"); return false; } if (ecc_needs_omap_bch && !IS_ENABLED(CONFIG_MTD_NAND_OMAP_BCH)) { diff --git a/include/linux/mtd/nand_bch.h b/include/linux/mtd/nand_bch.h index b8106651f807..a8a6909b594e 100644 --- a/include/linux/mtd/nand_bch.h +++ b/include/linux/mtd/nand_bch.h @@ -15,7 +15,7 @@ struct mtd_info; struct nand_chip; struct nand_bch_control; -#if defined(CONFIG_MTD_NAND_ECC_BCH) +#if IS_ENABLED(CONFIG_MTD_NAND_ECC_SW_BCH) static inline int mtd_nand_has_bch(void) { return 1; } @@ -39,7 +39,7 @@ struct nand_bch_control *nand_bch_init(struct mtd_info *mtd); */ void nand_bch_free(struct nand_bch_control *nbc); -#else /* !CONFIG_MTD_NAND_ECC_BCH */ +#else /* !CONFIG_MTD_NAND_ECC_SW_BCH */ static inline int mtd_nand_has_bch(void) { return 0; } @@ -64,6 +64,6 @@ static inline struct nand_bch_control *nand_bch_init(struct mtd_info *mtd) static inline void nand_bch_free(struct nand_bch_control *nbc) {} -#endif /* CONFIG_MTD_NAND_ECC_BCH */ +#endif /* CONFIG_MTD_NAND_ECC_SW_BCH */ #endif /* __MTD_NAND_BCH_H__ */ -- cgit From 9bb94643b94115990ffec18c8129f1ab970765c1 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Fri, 8 Feb 2019 08:48:37 +0100 Subject: mtd: nand: Clarify Kconfig entry for software Hamming ECC entries The software Hamming ECC correction implementation is referred as MTD_NAND_ECC which is too generic. Rename it MTD_NAND_ECC_SW_HAMMING. Also rename MTD_NAND_ECC_SMC which is an SMC quirk in the Hamming implementation as MTD_NAND_ECC_SW_HAMMING_SMC. Signed-off-by: Miquel Raynal --- arch/arm/configs/nhk8815_defconfig | 2 +- arch/mips/configs/generic/board-ni169445.config | 2 +- arch/powerpc/configs/85xx/tqm8548_defconfig | 2 +- drivers/mtd/Kconfig | 3 +-- drivers/mtd/nand/raw/Kconfig | 11 +++++------ drivers/mtd/nand/raw/Makefile | 2 +- drivers/mtd/nand/raw/nand_base.c | 2 +- drivers/mtd/sm_ftl.c | 12 ++++++------ drivers/mtd/tests/mtd_nandecctest.c | 14 +++++++------- 9 files changed, 24 insertions(+), 26 deletions(-) diff --git a/arch/arm/configs/nhk8815_defconfig b/arch/arm/configs/nhk8815_defconfig index 5f4c6aaa07f6..e0373989b32d 100644 --- a/arch/arm/configs/nhk8815_defconfig +++ b/arch/arm/configs/nhk8815_defconfig @@ -53,7 +53,7 @@ CONFIG_MTD_BLOCK=y CONFIG_MTD_ONENAND=y CONFIG_MTD_ONENAND_VERIFY_WRITE=y CONFIG_MTD_ONENAND_GENERIC=y -CONFIG_MTD_NAND_ECC_SMC=y +CONFIG_MTD_NAND_ECC_SW_HAMMING_SMC=y CONFIG_MTD_NAND=y CONFIG_MTD_NAND_FSMC=y CONFIG_BLK_DEV_LOOP=y diff --git a/arch/mips/configs/generic/board-ni169445.config b/arch/mips/configs/generic/board-ni169445.config index 01f6ab0d47d5..e68da2e9dc7c 100644 --- a/arch/mips/configs/generic/board-ni169445.config +++ b/arch/mips/configs/generic/board-ni169445.config @@ -15,7 +15,7 @@ CONFIG_MTD=y CONFIG_MTD_BLOCK=y CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_NAND_ECC=y +CONFIG_MTD_NAND_ECC_SW_HAMMING=y CONFIG_MTD_NAND_ECC_SW_BCH=y CONFIG_MTD_NAND=y CONFIG_MTD_NAND_GPIO=y diff --git a/arch/powerpc/configs/85xx/tqm8548_defconfig b/arch/powerpc/configs/85xx/tqm8548_defconfig index 2697e4e8a761..464ce192bc14 100644 --- a/arch/powerpc/configs/85xx/tqm8548_defconfig +++ b/arch/powerpc/configs/85xx/tqm8548_defconfig @@ -35,7 +35,7 @@ CONFIG_MTD=y CONFIG_MTD_CFI=y CONFIG_MTD_CFI_AMDSTD=y CONFIG_MTD_PHYSMAP_OF=y -CONFIG_MTD_NAND_ECC_SMC=y +CONFIG_MTD_NAND_ECC_SW_HAMMING_SMC=y CONFIG_MTD_NAND=y CONFIG_MTD_NAND_FSL_UPM=y CONFIG_BLK_DEV_LOOP=y diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig index 79a8ff542883..aa5a27fdfdd1 100644 --- a/drivers/mtd/Kconfig +++ b/drivers/mtd/Kconfig @@ -230,12 +230,11 @@ config SSFDC This enables read only access to SmartMedia formatted NAND flash. You can mount it with FAT file system. - config SM_FTL tristate "SmartMedia/xD new translation layer" depends on BLOCK select MTD_BLKDEVS - select MTD_NAND_ECC + select MTD_NAND_ECC_SW_HAMMING help This enables EXPERIMENTAL R/W support for SmartMedia/xD FTL (Flash translation layer). diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig index 7a1bde4fe9f6..b521e9862e53 100644 --- a/drivers/mtd/nand/raw/Kconfig +++ b/drivers/mtd/nand/raw/Kconfig @@ -1,20 +1,19 @@ -config MTD_NAND_ECC +config MTD_NAND_ECC_SW_HAMMING tristate -config MTD_NAND_ECC_SMC +config MTD_NAND_ECC_SW_HAMMING_SMC bool "NAND ECC Smart Media byte order" - depends on MTD_NAND_ECC + depends on MTD_NAND_ECC_SW_HAMMING 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 "Raw/Parallel NAND Device Support" depends on MTD - select MTD_NAND_ECC select MTD_NAND_CORE + select MTD_NAND_ECC_SW_HAMMING help This enables support for accessing all type of raw/parallel NAND flash devices. For further information see @@ -132,7 +131,7 @@ config MTD_NAND_S3C2410_DEBUG config MTD_NAND_NDFC tristate "NDFC NanD Flash Controller" depends on 4xx - select MTD_NAND_ECC_SMC + select MTD_NAND_ECC_SW_HAMMING_SMC help NDFC Nand Flash Controllers are integrated in IBM/AMCC's 4xx SoCs diff --git a/drivers/mtd/nand/raw/Makefile b/drivers/mtd/nand/raw/Makefile index 9749ff00f9e4..a022931318ac 100644 --- a/drivers/mtd/nand/raw/Makefile +++ b/drivers/mtd/nand/raw/Makefile @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_MTD_NAND) += nand.o -obj-$(CONFIG_MTD_NAND_ECC) += nand_ecc.o +obj-$(CONFIG_MTD_NAND_ECC_SW_HAMMING) += nand_ecc.o obj-$(CONFIG_MTD_NAND_ECC_SW_BCH) += nand_bch.o obj-$(CONFIG_MTD_SM_COMMON) += sm_common.o diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c index 95fac92d6b82..fd7ce5b929c0 100644 --- a/drivers/mtd/nand/raw/nand_base.c +++ b/drivers/mtd/nand/raw/nand_base.c @@ -5081,7 +5081,7 @@ static int nand_set_ecc_soft_ops(struct nand_chip *chip) ecc->bytes = 3; ecc->strength = 1; - if (IS_ENABLED(CONFIG_MTD_NAND_ECC_SMC)) + if (IS_ENABLED(CONFIG_MTD_NAND_ECC_SW_HAMMING_SMC)) ecc->options |= NAND_ECC_SOFT_HAMMING_SM_ORDER; return 0; diff --git a/drivers/mtd/sm_ftl.c b/drivers/mtd/sm_ftl.c index 89227b1d036a..e0955a98a0f4 100644 --- a/drivers/mtd/sm_ftl.c +++ b/drivers/mtd/sm_ftl.c @@ -222,17 +222,17 @@ static int sm_correct_sector(uint8_t *buffer, struct sm_oob *oob) uint8_t ecc[3]; __nand_calculate_ecc(buffer, SM_SMALL_PAGE, ecc, - IS_ENABLED(CONFIG_MTD_NAND_ECC_SMC)); + IS_ENABLED(CONFIG_MTD_NAND_ECC_SW_HAMMING_SMC)); if (__nand_correct_data(buffer, ecc, oob->ecc1, SM_SMALL_PAGE, - IS_ENABLED(CONFIG_MTD_NAND_ECC_SMC)) < 0) + IS_ENABLED(CONFIG_MTD_NAND_ECC_SW_HAMMING_SMC)) < 0) return -EIO; buffer += SM_SMALL_PAGE; __nand_calculate_ecc(buffer, SM_SMALL_PAGE, ecc, - IS_ENABLED(CONFIG_MTD_NAND_ECC_SMC)); + IS_ENABLED(CONFIG_MTD_NAND_ECC_SW_HAMMING_SMC)); if (__nand_correct_data(buffer, ecc, oob->ecc2, SM_SMALL_PAGE, - IS_ENABLED(CONFIG_MTD_NAND_ECC_SMC)) < 0) + IS_ENABLED(CONFIG_MTD_NAND_ECC_SW_HAMMING_SMC)) < 0) return -EIO; return 0; } @@ -399,11 +399,11 @@ restart: if (ftl->smallpagenand) { __nand_calculate_ecc(buf + boffset, SM_SMALL_PAGE, oob.ecc1, - IS_ENABLED(CONFIG_MTD_NAND_ECC_SMC)); + IS_ENABLED(CONFIG_MTD_NAND_ECC_SW_HAMMING_SMC)); __nand_calculate_ecc(buf + boffset + SM_SMALL_PAGE, SM_SMALL_PAGE, oob.ecc2, - IS_ENABLED(CONFIG_MTD_NAND_ECC_SMC)); + IS_ENABLED(CONFIG_MTD_NAND_ECC_SW_HAMMING_SMC)); } if (!sm_write_sector(ftl, zone, block, boffset, buf + boffset, &oob)) diff --git a/drivers/mtd/tests/mtd_nandecctest.c b/drivers/mtd/tests/mtd_nandecctest.c index c71523e94580..0c0091fb3708 100644 --- a/drivers/mtd/tests/mtd_nandecctest.c +++ b/drivers/mtd/tests/mtd_nandecctest.c @@ -122,9 +122,9 @@ static int no_bit_error_verify(void *error_data, void *error_ecc, int ret; __nand_calculate_ecc(error_data, size, calc_ecc, - IS_ENABLED(CONFIG_MTD_NAND_ECC_SMC)); + IS_ENABLED(CONFIG_MTD_NAND_ECC_SW_HAMMING_SMC)); ret = __nand_correct_data(error_data, error_ecc, calc_ecc, size, - IS_ENABLED(CONFIG_MTD_NAND_ECC_SMC)); + IS_ENABLED(CONFIG_MTD_NAND_ECC_SW_HAMMING_SMC)); if (ret == 0 && !memcmp(correct_data, error_data, size)) return 0; @@ -152,9 +152,9 @@ static int single_bit_error_correct(void *error_data, void *error_ecc, int ret; __nand_calculate_ecc(error_data, size, calc_ecc, - IS_ENABLED(CONFIG_MTD_NAND_ECC_SMC)); + IS_ENABLED(CONFIG_MTD_NAND_ECC_SW_HAMMING_SMC)); ret = __nand_correct_data(error_data, error_ecc, calc_ecc, size, - IS_ENABLED(CONFIG_MTD_NAND_ECC_SMC)); + IS_ENABLED(CONFIG_MTD_NAND_ECC_SW_HAMMING_SMC)); if (ret == 1 && !memcmp(correct_data, error_data, size)) return 0; @@ -189,9 +189,9 @@ static int double_bit_error_detect(void *error_data, void *error_ecc, int ret; __nand_calculate_ecc(error_data, size, calc_ecc, - IS_ENABLED(CONFIG_MTD_NAND_ECC_SMC)); + IS_ENABLED(CONFIG_MTD_NAND_ECC_SW_HAMMING_SMC)); ret = __nand_correct_data(error_data, error_ecc, calc_ecc, size, - IS_ENABLED(CONFIG_MTD_NAND_ECC_SMC)); + IS_ENABLED(CONFIG_MTD_NAND_ECC_SW_HAMMING_SMC)); return (ret == -EBADMSG) ? 0 : -EINVAL; } @@ -266,7 +266,7 @@ static int nand_ecc_test_run(const size_t size) prandom_bytes(correct_data, size); __nand_calculate_ecc(correct_data, size, correct_ecc, - IS_ENABLED(CONFIG_MTD_NAND_ECC_SMC)); + IS_ENABLED(CONFIG_MTD_NAND_ECC_SW_HAMMING_SMC)); for (i = 0; i < ARRAY_SIZE(nand_ecc_test); i++) { nand_ecc_test[i].prepare(error_data, error_ecc, -- cgit From e787be1f1d45e190adce91de52053539668f6269 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Wed, 6 Feb 2019 16:29:14 +0100 Subject: mtd: rawnand: Change Kconfig titles and re-order a bit the list This list is a mess, while some items should probably not be in the raw/ sub-directory, others are definitely at the right place but not with the right description. Write uniform titles and group IPs by vendor. NAND controllers will appear under the list named "Raw/parallel NAND flash controllers" while the other drivers will appear under "Misc". Software ECC engines will later be moved out of the raw/ directory. Signed-off-by: Miquel Raynal --- drivers/mtd/nand/raw/Kconfig | 354 ++++++++++++++++++----------------- drivers/mtd/nand/raw/ingenic/Kconfig | 4 +- 2 files changed, 181 insertions(+), 177 deletions(-) diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig index b521e9862e53..c3a898a300e0 100644 --- a/drivers/mtd/nand/raw/Kconfig +++ b/drivers/mtd/nand/raw/Kconfig @@ -31,15 +31,13 @@ config MTD_NAND_ECC_SW_BCH ECC codes. They are used with NAND devices requiring more than 1 bit of error correction. -config MTD_SM_COMMON - tristate - default n +comment "Raw/parallel NAND flash controllers" config MTD_NAND_DENALI tristate config MTD_NAND_DENALI_PCI - tristate "Support Denali NAND controller on Intel Moorestown" + tristate "Denali NAND controller on Intel Moorestown" select MTD_NAND_DENALI depends on PCI help @@ -47,31 +45,22 @@ config MTD_NAND_DENALI_PCI Denali NAND controller core. config MTD_NAND_DENALI_DT - tristate "Support Denali NAND controller as a DT device" + tristate "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" + tristate "Amstrad E3 NAND controller" depends on MACH_AMS_DELTA || COMPILE_TEST 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" + tristate "OMAP2, OMAP3, OMAP4 and Keystone NAND controller" depends on ARCH_OMAP2PLUS || ARCH_KEYSTONE || COMPILE_TEST depends on HAS_IOMEM help @@ -93,18 +82,6 @@ config MTD_NAND_OMAP_BCH 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 @@ -112,8 +89,15 @@ config MTD_NAND_AU1550 This enables the driver for the NAND flash controller on the AMD/Alchemy 1550 SOC. +config MTD_NAND_NDFC + tristate "IBM/MCC 4xx NAND controller" + depends on 4xx + select MTD_NAND_ECC_SW_HAMMING_SMC + help + NDFC Nand Flash Controllers are integrated in IBM/AMCC's 4xx SoCs + config MTD_NAND_S3C2410 - tristate "NAND Flash support for Samsung S3C SoCs" + tristate "Samsung S3C NAND controller" depends on ARCH_S3C24XX || ARCH_S3C64XX help This enables the NAND flash controller on the S3C24xx and S3C64xx @@ -123,18 +107,11 @@ config MTD_NAND_S3C2410 must advertise a platform_device for the driver to attach. config MTD_NAND_S3C2410_DEBUG - bool "Samsung S3C NAND driver debug" + bool "Samsung S3C NAND controller 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_SW_HAMMING_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 @@ -146,89 +123,19 @@ config MTD_NAND_S3C2410_CLKSTOP approximately 5mA of power when there is nothing happening. config MTD_NAND_TANGO - tristate "NAND Flash support for Tango chips" + tristate "Tango NAND controller" depends on ARCH_TANGO || COMPILE_TEST depends on HAS_IOMEM 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_SHARPSL - tristate "Support for NAND Flash on Sharp SL Series (C7xx + others)" + tristate "Sharp SL Series (C7xx + others) NAND controller" depends on ARCH_PXA || COMPILE_TEST depends on HAS_IOMEM config MTD_NAND_CAFE - tristate "NAND support for OLPC CAFÉ chip" + tristate "OLPC CAFÉ NAND controller" depends on PCI select REED_SOLOMON select REED_SOLOMON_DEC16 @@ -237,7 +144,7 @@ config MTD_NAND_CAFE laptop. config MTD_NAND_CS553X - tristate "NAND support for CS5535/CS5536 (AMD Geode companion chip)" + tristate "CS5535/CS5536 (AMD Geode companion) NAND controller" depends on X86_32 depends on !UML && HAS_IOMEM help @@ -251,7 +158,7 @@ config MTD_NAND_CS553X If you say "m", the module will be called cs553x_nand. config MTD_NAND_ATMEL - tristate "Support for NAND Flash / SmartMedia on AT91" + tristate "Atmel AT91 NAND Flash/SmartMedia NAND controller" depends on ARCH_AT91 || COMPILE_TEST depends on HAS_IOMEM select GENERIC_ALLOCATOR @@ -260,8 +167,17 @@ config MTD_NAND_ATMEL Enables support for NAND Flash / Smart Media Card interface on Atmel AT91 processors. +config MTD_NAND_ORION + tristate "Marvell Orion NAND controller" + 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_MARVELL - tristate "NAND controller support on Marvell boards" + tristate "Marvell EBU NAND controller" depends on PXA3xx || ARCH_MMP || PLAT_ORION || ARCH_MVEBU || \ COMPILE_TEST depends on HAS_IOMEM @@ -273,7 +189,7 @@ config MTD_NAND_MARVELL - 64-bit Aramda platforms (7k, 8k) (NFCv2) config MTD_NAND_SLC_LPC32XX - tristate "NXP LPC32xx SLC Controller" + tristate "NXP LPC32xx SLC NAND controller" depends on ARCH_LPC32XX || COMPILE_TEST depends on HAS_IOMEM help @@ -285,7 +201,7 @@ config MTD_NAND_SLC_LPC32XX by the SLC NAND controller. config MTD_NAND_MLC_LPC32XX - tristate "NXP LPC32xx MLC Controller" + tristate "NXP LPC32xx MLC NAND controller" depends on ARCH_LPC32XX || COMPILE_TEST depends on HAS_IOMEM help @@ -297,38 +213,23 @@ config MTD_NAND_MLC_LPC32XX by the MLC NAND controller. config MTD_NAND_CM_X270 - tristate "Support for NAND Flash on CM-X270 modules" + tristate "CM-X270 modules NAND controller" depends on MACH_ARMCORE config MTD_NAND_PASEMI - tristate "NAND support for PA Semi PWRficient" + tristate "PA Semi PWRficient NAND controller" 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" + tristate "Toshiba Mobile IO NAND 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 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 || COMPILE_TEST @@ -339,7 +240,7 @@ config MTD_NAND_BRCMNAND BCM3xxx, BCM63xxx, iProc/Cygnus and more. config MTD_NAND_BCM47XXNFLASH - tristate "Support for NAND flash on BCM4706 BCMA bus" + tristate "BCM4706 BCMA NAND controller" depends on BCMA_NFLASH depends on BCMA help @@ -347,32 +248,31 @@ config MTD_NAND_BCM47XXNFLASH 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" +config MTD_NAND_OXNAS + tristate "Oxford Semiconductor NAND controller" + depends on ARCH_OXNAS || COMPILE_TEST 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. + This enables the NAND flash controller on Oxford Semiconductor SoCs. -config MTD_NAND_ORION - tristate "NAND Flash support for Marvell Orion SoC" - depends on PLAT_ORION +config MTD_NAND_MPC5121_NFC + tristate "MPC5121 NAND controller" + depends on PPC_MPC512x 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. + This enables the driver for the NAND flash controller on the + MPC5121 SoC. -config MTD_NAND_OXNAS - tristate "NAND Flash support for Oxford Semiconductor SoC" - depends on ARCH_OXNAS || COMPILE_TEST - depends on HAS_IOMEM +config MTD_NAND_GPMI_NAND + tristate "Freescale GPMI NAND controller" + depends on MXS_DMA help - This enables the NAND flash controller on Oxford Semiconductor SoCs. + 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_FSL_ELBC - tristate "NAND support for Freescale eLBC controllers" + tristate "Freescale eLBC NAND controller" depends on FSL_SOC select FSL_LBC help @@ -382,7 +282,7 @@ config MTD_NAND_FSL_ELBC external NAND devices. config MTD_NAND_FSL_IFC - tristate "NAND support for Freescale IFC controller" + tristate "Freescale IFC NAND controller" depends on FSL_SOC || ARCH_LAYERSCAPE || SOC_LS1021A || COMPILE_TEST depends on HAS_IOMEM select FSL_IFC @@ -394,22 +294,15 @@ config MTD_NAND_FSL_IFC external NAND devices. config MTD_NAND_FSL_UPM - tristate "Support for NAND on Freescale UPM" + tristate "Freescale UPM NAND controller" 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" + tristate "Freescale VF610/MPC5125 NAND controller" depends on (SOC_VF610 || COMPILE_TEST) depends on HAS_IOMEM help @@ -421,7 +314,7 @@ config MTD_NAND_VF610_NFC device tree. config MTD_NAND_MXC - tristate "MXC NAND support" + tristate "Freescale MXC NAND controller" depends on ARCH_MXC || COMPILE_TEST depends on HAS_IOMEM help @@ -429,7 +322,7 @@ config MTD_NAND_MXC MXC processors. config MTD_NAND_SH_FLCTL - tristate "Support for NAND on Renesas SuperH FLCTL" + tristate "Renesas SuperH FLCTL NAND controller" depends on SUPERH || COMPILE_TEST depends on HAS_IOMEM help @@ -437,7 +330,7 @@ config MTD_NAND_SH_FLCTL for NAND Flash using FLCTL. config MTD_NAND_DAVINCI - tristate "Support NAND on DaVinci/Keystone SoC" + tristate "DaVinci/Keystone NAND controller" depends on ARCH_DAVINCI || (ARCH_KEYSTONE && TI_AEMIF) || COMPILE_TEST depends on HAS_IOMEM help @@ -445,20 +338,20 @@ config MTD_NAND_DAVINCI DaVinci/Keystone processors. config MTD_NAND_TXX9NDFMC - tristate "NAND Flash support for TXx9 SoC" + tristate "TXx9 NAND controller" depends on SOC_TX4938 || SOC_TX4939 || COMPILE_TEST depends on HAS_IOMEM help This enables the NAND flash controller on the TXx9 SoCs. config MTD_NAND_SOCRATES - tristate "Support for NAND on Socrates board" + tristate "Socrates NAND controller" 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." + tristate "Nuvoton NUC9xx/w90p910 NAND controller" depends on ARCH_W90X900 || COMPILE_TEST depends on HAS_IOMEM help @@ -468,7 +361,7 @@ config MTD_NAND_NUC900 source "drivers/mtd/nand/raw/ingenic/Kconfig" config MTD_NAND_FSMC - tristate "Support for NAND on ST Micros FSMC" + tristate "ST Micros FSMC NAND controller" depends on OF && HAS_IOMEM depends on PLAT_SPEAR || ARCH_NOMADIK || ARCH_U8500 || MACH_U300 || \ COMPILE_TEST @@ -477,28 +370,28 @@ config MTD_NAND_FSMC Flexible Static Memory Controller (FSMC) config MTD_NAND_XWAY - bool "Support for NAND on Lantiq XWAY SoC" + bool "Lantiq XWAY NAND controller" 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" + tristate "Allwinner NAND controller" depends on ARCH_SUNXI || COMPILE_TEST depends on HAS_IOMEM help Enables support for NAND Flash chips on Allwinner SoCs. config MTD_NAND_HISI504 - tristate "Support for NAND controller on Hisilicon SoC Hip04" + tristate "Hisilicon Hip04 NAND controller" depends on ARCH_HISI || COMPILE_TEST depends on HAS_IOMEM help Enables support for NAND controller on Hisilicon SoC Hip04. config MTD_NAND_QCOM - tristate "Support for NAND on QCOM SoCs" + tristate "QCOM NAND controller" depends on ARCH_QCOM || COMPILE_TEST depends on HAS_IOMEM help @@ -506,7 +399,7 @@ config MTD_NAND_QCOM controller. This controller is found on IPQ806x SoC. config MTD_NAND_MTK - tristate "Support for NAND controller on MTK SoCs" + tristate "MTK NAND controller" depends on ARCH_MEDIATEK || COMPILE_TEST depends on HAS_IOMEM help @@ -514,7 +407,7 @@ config MTD_NAND_MTK This controller is found on mt27xx, mt81xx, mt65xx SoCs. config MTD_NAND_TEGRA - tristate "Support for NAND controller on NVIDIA Tegra" + tristate "NVIDIA Tegra NAND controller" depends on ARCH_TEGRA || COMPILE_TEST depends on HAS_IOMEM help @@ -541,4 +434,115 @@ config MTD_NAND_MESON Enables support for NAND controller on Amlogic's Meson SoCs. This controller is found on Meson SoCs. +config MTD_NAND_GPIO + tristate "GPIO assisted NAND controller" + 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_PLATFORM + tristate "Generic NAND controller" + 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. + +comment "Misc" + +config MTD_SM_COMMON + tristate + default n + +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_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_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". + endif # MTD_NAND diff --git a/drivers/mtd/nand/raw/ingenic/Kconfig b/drivers/mtd/nand/raw/ingenic/Kconfig index 497b46b144f2..7cfc77021154 100644 --- a/drivers/mtd/nand/raw/ingenic/Kconfig +++ b/drivers/mtd/nand/raw/ingenic/Kconfig @@ -1,12 +1,12 @@ config MTD_NAND_JZ4740 - tristate "Support for JZ4740 SoC NAND controller" + tristate "JZ4740 NAND controller" depends on MACH_JZ4740 || COMPILE_TEST depends on HAS_IOMEM help Enables support for NAND Flash on JZ4740 SoC based boards. config MTD_NAND_JZ4780 - tristate "Support for NAND on JZ4780 SoC" + tristate "JZ4780 NAND controller" depends on JZ4780_NEMC help Enables support for NAND Flash connected to the NEMC on JZ4780 SoC -- cgit From 72c5af00272339af6bbed6fe7275cd731f57be2d Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Wed, 6 Feb 2019 16:47:44 +0100 Subject: mtd: rawnand: Clarify Kconfig entry MTD_NAND MTD_NAND is large and encloses much more than what the symbol is actually used for: raw NAND. Clarify the symbol by naming it MTD_RAW_NAND instead. Signed-off-by: Miquel Raynal --- arch/arm/configs/at91_dt_defconfig | 2 +- arch/arm/configs/clps711x_defconfig | 2 +- arch/arm/configs/cm_x2xx_defconfig | 2 +- arch/arm/configs/cm_x300_defconfig | 2 +- arch/arm/configs/colibri_pxa270_defconfig | 2 +- arch/arm/configs/corgi_defconfig | 2 +- arch/arm/configs/davinci_all_defconfig | 2 +- arch/arm/configs/em_x270_defconfig | 2 +- arch/arm/configs/ep93xx_defconfig | 2 +- arch/arm/configs/eseries_pxa_defconfig | 2 +- arch/arm/configs/imx_v4_v5_defconfig | 2 +- arch/arm/configs/imx_v6_v7_defconfig | 2 +- arch/arm/configs/ixp4xx_defconfig | 2 +- arch/arm/configs/keystone_defconfig | 2 +- arch/arm/configs/lpc32xx_defconfig | 2 +- arch/arm/configs/mini2440_defconfig | 2 +- arch/arm/configs/mmp2_defconfig | 2 +- arch/arm/configs/multi_v4t_defconfig | 2 +- arch/arm/configs/multi_v5_defconfig | 2 +- arch/arm/configs/multi_v7_defconfig | 2 +- arch/arm/configs/mv78xx0_defconfig | 2 +- arch/arm/configs/mvebu_v5_defconfig | 2 +- arch/arm/configs/mvebu_v7_defconfig | 2 +- arch/arm/configs/mxs_defconfig | 2 +- arch/arm/configs/nhk8815_defconfig | 2 +- arch/arm/configs/omap1_defconfig | 2 +- arch/arm/configs/omap2plus_defconfig | 2 +- arch/arm/configs/orion5x_defconfig | 2 +- arch/arm/configs/oxnas_v6_defconfig | 2 +- arch/arm/configs/pxa3xx_defconfig | 2 +- arch/arm/configs/pxa_defconfig | 2 +- arch/arm/configs/qcom_defconfig | 2 +- arch/arm/configs/s3c2410_defconfig | 2 +- arch/arm/configs/s3c6400_defconfig | 2 +- arch/arm/configs/sama5_defconfig | 2 +- arch/arm/configs/socfpga_defconfig | 2 +- arch/arm/configs/spear13xx_defconfig | 2 +- arch/arm/configs/spear3xx_defconfig | 2 +- arch/arm/configs/spear6xx_defconfig | 2 +- arch/arm/configs/spitz_defconfig | 2 +- arch/arm/configs/tango4_defconfig | 2 +- arch/arm/configs/trizeps4_defconfig | 2 +- arch/arm/configs/u300_defconfig | 2 +- arch/arm64/configs/defconfig | 2 +- arch/mips/configs/bcm47xx_defconfig | 2 +- arch/mips/configs/ci20_defconfig | 2 +- arch/mips/configs/db1xxx_defconfig | 2 +- arch/mips/configs/generic/board-ni169445.config | 2 +- arch/mips/configs/generic/board-ocelot.config | 2 +- arch/mips/configs/loongson1b_defconfig | 2 +- arch/mips/configs/loongson1c_defconfig | 2 +- arch/mips/configs/qi_lb60_defconfig | 2 +- arch/mips/configs/rb532_defconfig | 2 +- arch/mips/configs/rbtx49xx_defconfig | 2 +- arch/mips/configs/xway_defconfig | 2 +- arch/powerpc/configs/40x/kilauea_defconfig | 2 +- arch/powerpc/configs/40x/obs600_defconfig | 2 +- arch/powerpc/configs/44x/canyonlands_defconfig | 2 +- arch/powerpc/configs/44x/eiger_defconfig | 2 +- arch/powerpc/configs/44x/sequoia_defconfig | 2 +- arch/powerpc/configs/44x/warp_defconfig | 2 +- arch/powerpc/configs/83xx/mpc8313_rdb_defconfig | 2 +- arch/powerpc/configs/83xx/mpc8315_rdb_defconfig | 2 +- arch/powerpc/configs/85xx-hw.config | 2 +- arch/powerpc/configs/85xx/ge_imp3a_defconfig | 2 +- arch/powerpc/configs/85xx/socrates_defconfig | 2 +- arch/powerpc/configs/85xx/tqm8548_defconfig | 2 +- arch/powerpc/configs/85xx/xes_mpc85xx_defconfig | 2 +- arch/powerpc/configs/86xx-hw.config | 2 +- arch/powerpc/configs/mpc512x_defconfig | 2 +- arch/powerpc/configs/mpc83xx_defconfig | 2 +- arch/powerpc/configs/pasemi_defconfig | 2 +- arch/powerpc/configs/ppc44x_defconfig | 2 +- arch/sh/configs/ap325rxa_defconfig | 2 +- arch/sh/configs/ecovec24_defconfig | 2 +- arch/sh/configs/migor_defconfig | 2 +- arch/sh/configs/sdk7786_defconfig | 2 +- arch/sh/configs/se7724_defconfig | 2 +- arch/sh/configs/titan_defconfig | 2 +- drivers/mtd/nand/raw/Kconfig | 6 +++--- drivers/mtd/nand/raw/Makefile | 2 +- drivers/mtd/tests/mtd_nandecctest.c | 2 +- 82 files changed, 84 insertions(+), 84 deletions(-) diff --git a/arch/arm/configs/at91_dt_defconfig b/arch/arm/configs/at91_dt_defconfig index e4b1be66b3f5..50ef3eb0ab64 100644 --- a/arch/arm/configs/at91_dt_defconfig +++ b/arch/arm/configs/at91_dt_defconfig @@ -56,7 +56,7 @@ CONFIG_MTD=y CONFIG_MTD_CMDLINE_PARTS=y CONFIG_MTD_BLOCK=y CONFIG_MTD_DATAFLASH=y -CONFIG_MTD_NAND=y +CONFIG_MTD_RAW_NAND=y CONFIG_MTD_NAND_ATMEL=y CONFIG_MTD_UBI=y CONFIG_MTD_UBI_GLUEBI=y diff --git a/arch/arm/configs/clps711x_defconfig b/arch/arm/configs/clps711x_defconfig index fc105c9178cc..7968d20673b9 100644 --- a/arch/arm/configs/clps711x_defconfig +++ b/arch/arm/configs/clps711x_defconfig @@ -36,7 +36,7 @@ CONFIG_MTD_CFI_INTELEXT=y CONFIG_MTD_CFI_AMDSTD=y CONFIG_MTD_CFI_STAA=y CONFIG_MTD_PLATRAM=y -CONFIG_MTD_NAND=y +CONFIG_MTD_RAW_NAND=y CONFIG_MTD_NAND_GPIO=y CONFIG_NETDEVICES=y # CONFIG_NET_CADENCE is not set diff --git a/arch/arm/configs/cm_x2xx_defconfig b/arch/arm/configs/cm_x2xx_defconfig index fb45b4983d3c..5344434df652 100644 --- a/arch/arm/configs/cm_x2xx_defconfig +++ b/arch/arm/configs/cm_x2xx_defconfig @@ -58,7 +58,7 @@ CONFIG_MTD_CFI_AMDSTD=y CONFIG_MTD_CFI_STAA=y CONFIG_MTD_PHYSMAP=y CONFIG_MTD_PXA2XX=y -CONFIG_MTD_NAND=y +CONFIG_MTD_RAW_NAND=y CONFIG_MTD_NAND_GPIO=m CONFIG_MTD_NAND_CM_X270=y CONFIG_MTD_NAND_PLATFORM=y diff --git a/arch/arm/configs/cm_x300_defconfig b/arch/arm/configs/cm_x300_defconfig index 5e349c625b71..3707a014cbc4 100644 --- a/arch/arm/configs/cm_x300_defconfig +++ b/arch/arm/configs/cm_x300_defconfig @@ -48,7 +48,7 @@ CONFIG_LIB80211=m CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" CONFIG_MTD=y CONFIG_MTD_BLOCK=y -CONFIG_MTD_NAND=y +CONFIG_MTD_RAW_NAND=y CONFIG_MTD_NAND_MARVELL=y CONFIG_MTD_UBI=y CONFIG_BLK_DEV_LOOP=y diff --git a/arch/arm/configs/colibri_pxa270_defconfig b/arch/arm/configs/colibri_pxa270_defconfig index 8995695fc118..8d484e4d51cc 100644 --- a/arch/arm/configs/colibri_pxa270_defconfig +++ b/arch/arm/configs/colibri_pxa270_defconfig @@ -64,7 +64,7 @@ CONFIG_MTD_COMPLEX_MAPPINGS=y CONFIG_MTD_PHYSMAP=y CONFIG_MTD_PXA2XX=y CONFIG_MTD_BLOCK2MTD=y -CONFIG_MTD_NAND=y +CONFIG_MTD_RAW_NAND=y CONFIG_MTD_NAND_DISKONCHIP=y CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADVANCED=y CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS=0x4000000 diff --git a/arch/arm/configs/corgi_defconfig b/arch/arm/configs/corgi_defconfig index 09e1672777c9..d99725984947 100644 --- a/arch/arm/configs/corgi_defconfig +++ b/arch/arm/configs/corgi_defconfig @@ -87,7 +87,7 @@ CONFIG_MTD_CMDLINE_PARTS=y CONFIG_MTD_BLOCK=y CONFIG_MTD_ROM=y CONFIG_MTD_COMPLEX_MAPPINGS=y -CONFIG_MTD_NAND=y +CONFIG_MTD_RAW_NAND=y CONFIG_MTD_NAND_SHARPSL=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_SD=y diff --git a/arch/arm/configs/davinci_all_defconfig b/arch/arm/configs/davinci_all_defconfig index 207962a656a2..4a8cad4d3707 100644 --- a/arch/arm/configs/davinci_all_defconfig +++ b/arch/arm/configs/davinci_all_defconfig @@ -74,7 +74,7 @@ CONFIG_MTD_CFI_INTELEXT=m CONFIG_MTD_CFI_AMDSTD=m CONFIG_MTD_PHYSMAP=m CONFIG_MTD_M25P80=m -CONFIG_MTD_NAND=m +CONFIG_MTD_RAW_NAND=m CONFIG_MTD_NAND_DAVINCI=m CONFIG_MTD_SPI_NOR=m CONFIG_MTD_UBI=m diff --git a/arch/arm/configs/em_x270_defconfig b/arch/arm/configs/em_x270_defconfig index 30a67523f860..61228a25ba8d 100644 --- a/arch/arm/configs/em_x270_defconfig +++ b/arch/arm/configs/em_x270_defconfig @@ -54,7 +54,7 @@ CONFIG_MTD_CFI_AMDSTD=y CONFIG_MTD_CFI_STAA=y CONFIG_MTD_PHYSMAP=y CONFIG_MTD_PXA2XX=y -CONFIG_MTD_NAND=y +CONFIG_MTD_RAW_NAND=y CONFIG_MTD_NAND_PLATFORM=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y diff --git a/arch/arm/configs/ep93xx_defconfig b/arch/arm/configs/ep93xx_defconfig index 78cd73d1c795..14889a785f07 100644 --- a/arch/arm/configs/ep93xx_defconfig +++ b/arch/arm/configs/ep93xx_defconfig @@ -63,7 +63,7 @@ CONFIG_MTD_CFI_AMDSTD=y CONFIG_MTD_CFI_STAA=y CONFIG_MTD_ROM=y CONFIG_MTD_PHYSMAP=y -CONFIG_MTD_NAND=y +CONFIG_MTD_RAW_NAND=y CONFIG_BLK_DEV_NBD=y CONFIG_EEPROM_LEGACY=y CONFIG_SCSI=y diff --git a/arch/arm/configs/eseries_pxa_defconfig b/arch/arm/configs/eseries_pxa_defconfig index eabb784cf7da..b85575867d21 100644 --- a/arch/arm/configs/eseries_pxa_defconfig +++ b/arch/arm/configs/eseries_pxa_defconfig @@ -43,7 +43,7 @@ CONFIG_MAC80211_RC_PID=y CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" # CONFIG_STANDALONE is not set CONFIG_MTD=m -CONFIG_MTD_NAND=m +CONFIG_MTD_RAW_NAND=m CONFIG_MTD_NAND_TMIO=m CONFIG_BLK_DEV_LOOP=m # CONFIG_SCSI_PROC_FS is not set diff --git a/arch/arm/configs/imx_v4_v5_defconfig b/arch/arm/configs/imx_v4_v5_defconfig index 8661dd9b064a..ffdcfc3edc25 100644 --- a/arch/arm/configs/imx_v4_v5_defconfig +++ b/arch/arm/configs/imx_v4_v5_defconfig @@ -61,7 +61,7 @@ CONFIG_MTD_CFI_GEOMETRY=y # CONFIG_MTD_CFI_I2 is not set CONFIG_MTD_CFI_INTELEXT=y CONFIG_MTD_PHYSMAP=y -CONFIG_MTD_NAND=y +CONFIG_MTD_RAW_NAND=y CONFIG_MTD_NAND_MXC=y CONFIG_MTD_UBI=y CONFIG_EEPROM_AT24=y diff --git a/arch/arm/configs/imx_v6_v7_defconfig b/arch/arm/configs/imx_v6_v7_defconfig index 5586a5074a96..07b796c2f0ee 100644 --- a/arch/arm/configs/imx_v6_v7_defconfig +++ b/arch/arm/configs/imx_v6_v7_defconfig @@ -110,7 +110,7 @@ CONFIG_MTD_PHYSMAP_OF=y CONFIG_MTD_DATAFLASH=y CONFIG_MTD_M25P80=y CONFIG_MTD_SST25L=y -CONFIG_MTD_NAND=y +CONFIG_MTD_RAW_NAND=y CONFIG_MTD_NAND_GPMI_NAND=y CONFIG_MTD_NAND_VF610_NFC=y CONFIG_MTD_NAND_MXC=y diff --git a/arch/arm/configs/ixp4xx_defconfig b/arch/arm/configs/ixp4xx_defconfig index 8c3c99cd6de9..39ebcce3bc2f 100644 --- a/arch/arm/configs/ixp4xx_defconfig +++ b/arch/arm/configs/ixp4xx_defconfig @@ -112,7 +112,7 @@ CONFIG_MTD_CFI=y CONFIG_MTD_CFI_INTELEXT=y CONFIG_MTD_COMPLEX_MAPPINGS=y CONFIG_MTD_IXP4XX=y -CONFIG_MTD_NAND=m +CONFIG_MTD_RAW_NAND=m CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=8192 diff --git a/arch/arm/configs/keystone_defconfig b/arch/arm/configs/keystone_defconfig index 3ded35a07f45..72fee57aad2f 100644 --- a/arch/arm/configs/keystone_defconfig +++ b/arch/arm/configs/keystone_defconfig @@ -124,7 +124,7 @@ CONFIG_MTD_CMDLINE_PARTS=y CONFIG_MTD_BLOCK=y CONFIG_MTD_PLATRAM=y CONFIG_MTD_M25P80=y -CONFIG_MTD_NAND=y +CONFIG_MTD_RAW_NAND=y CONFIG_MTD_NAND_DAVINCI=y CONFIG_MTD_SPI_NOR=y CONFIG_MTD_UBI=y diff --git a/arch/arm/configs/lpc32xx_defconfig b/arch/arm/configs/lpc32xx_defconfig index e752fb704df0..4b3b2c693c29 100644 --- a/arch/arm/configs/lpc32xx_defconfig +++ b/arch/arm/configs/lpc32xx_defconfig @@ -47,7 +47,7 @@ CONFIG_DEVTMPFS_MOUNT=y CONFIG_MTD=y CONFIG_MTD_CMDLINE_PARTS=y CONFIG_MTD_BLOCK=y -CONFIG_MTD_NAND=y +CONFIG_MTD_RAW_NAND=y CONFIG_MTD_NAND_SLC_LPC32XX=y CONFIG_MTD_NAND_MLC_LPC32XX=y CONFIG_MTD_UBI=y diff --git a/arch/arm/configs/mini2440_defconfig b/arch/arm/configs/mini2440_defconfig index d95a8059d30b..8b0f7c4c3f09 100644 --- a/arch/arm/configs/mini2440_defconfig +++ b/arch/arm/configs/mini2440_defconfig @@ -92,7 +92,7 @@ CONFIG_MTD_CFI_AMDSTD=y CONFIG_MTD_CFI_STAA=y CONFIG_MTD_RAM=y CONFIG_MTD_ROM=y -CONFIG_MTD_NAND=y +CONFIG_MTD_RAW_NAND=y CONFIG_MTD_NAND_S3C2410=y CONFIG_MTD_NAND_PLATFORM=y CONFIG_MTD_LPDDR=y diff --git a/arch/arm/configs/mmp2_defconfig b/arch/arm/configs/mmp2_defconfig index 1eeee7f11d91..94deb0ed0541 100644 --- a/arch/arm/configs/mmp2_defconfig +++ b/arch/arm/configs/mmp2_defconfig @@ -28,7 +28,7 @@ CONFIG_IP_PNP=y CONFIG_MTD=y CONFIG_MTD_CMDLINE_PARTS=y CONFIG_MTD_BLOCK=y -CONFIG_MTD_NAND=y +CONFIG_MTD_RAW_NAND=y CONFIG_MTD_ONENAND=y CONFIG_MTD_ONENAND_GENERIC=y # CONFIG_BLK_DEV is not set diff --git a/arch/arm/configs/multi_v4t_defconfig b/arch/arm/configs/multi_v4t_defconfig index 9a6390c172d6..14f3a4a65d01 100644 --- a/arch/arm/configs/multi_v4t_defconfig +++ b/arch/arm/configs/multi_v4t_defconfig @@ -39,7 +39,7 @@ CONFIG_MTD_CFI_INTELEXT=y CONFIG_MTD_CFI_AMDSTD=y CONFIG_MTD_CFI_STAA=y CONFIG_MTD_PLATRAM=y -CONFIG_MTD_NAND=y +CONFIG_MTD_RAW_NAND=y CONFIG_MTD_NAND_GPIO=y # CONFIG_INPUT is not set # CONFIG_SERIO is not set diff --git a/arch/arm/configs/multi_v5_defconfig b/arch/arm/configs/multi_v5_defconfig index 318b76fa26d1..63b5a8824f0f 100644 --- a/arch/arm/configs/multi_v5_defconfig +++ b/arch/arm/configs/multi_v5_defconfig @@ -87,7 +87,7 @@ CONFIG_MTD_CFI_GEOMETRY=y CONFIG_MTD_CFI_INTELEXT=y CONFIG_MTD_CFI_STAA=y CONFIG_MTD_PHYSMAP=y -CONFIG_MTD_NAND=y +CONFIG_MTD_RAW_NAND=y CONFIG_MTD_NAND_ATMEL=y CONFIG_MTD_NAND_ORION=y CONFIG_MTD_SPI_NOR=y diff --git a/arch/arm/configs/multi_v7_defconfig b/arch/arm/configs/multi_v7_defconfig index c75051b9392c..b7b1cd00a294 100644 --- a/arch/arm/configs/multi_v7_defconfig +++ b/arch/arm/configs/multi_v7_defconfig @@ -184,7 +184,7 @@ CONFIG_MTD=y CONFIG_MTD_CMDLINE_PARTS=y CONFIG_MTD_BLOCK=y CONFIG_MTD_M25P80=y -CONFIG_MTD_NAND=y +CONFIG_MTD_RAW_NAND=y CONFIG_MTD_NAND_DENALI_DT=y CONFIG_MTD_NAND_OMAP2=y CONFIG_MTD_NAND_OMAP_BCH=y diff --git a/arch/arm/configs/mv78xx0_defconfig b/arch/arm/configs/mv78xx0_defconfig index 0448bd8075ac..e9567513f068 100644 --- a/arch/arm/configs/mv78xx0_defconfig +++ b/arch/arm/configs/mv78xx0_defconfig @@ -47,7 +47,7 @@ CONFIG_MTD_CFI_GEOMETRY=y CONFIG_MTD_CFI_INTELEXT=y CONFIG_MTD_CFI_AMDSTD=y CONFIG_MTD_PHYSMAP=y -CONFIG_MTD_NAND=y +CONFIG_MTD_RAW_NAND=y CONFIG_MTD_NAND_ORION=y CONFIG_BLK_DEV_LOOP=y # CONFIG_SCSI_PROC_FS is not set diff --git a/arch/arm/configs/mvebu_v5_defconfig b/arch/arm/configs/mvebu_v5_defconfig index 4b598da0d086..0e5577a31851 100644 --- a/arch/arm/configs/mvebu_v5_defconfig +++ b/arch/arm/configs/mvebu_v5_defconfig @@ -77,7 +77,7 @@ CONFIG_MTD_CFI_INTELEXT=y CONFIG_MTD_CFI_STAA=y CONFIG_MTD_PHYSMAP=y CONFIG_MTD_M25P80=y -CONFIG_MTD_NAND=y +CONFIG_MTD_RAW_NAND=y CONFIG_MTD_NAND_ORION=y CONFIG_MTD_SPI_NOR=y CONFIG_BLK_DEV_LOOP=y diff --git a/arch/arm/configs/mvebu_v7_defconfig b/arch/arm/configs/mvebu_v7_defconfig index 55140219ab11..48f7b4277b8d 100644 --- a/arch/arm/configs/mvebu_v7_defconfig +++ b/arch/arm/configs/mvebu_v7_defconfig @@ -52,7 +52,7 @@ CONFIG_MTD_CFI_AMDSTD=y CONFIG_MTD_CFI_STAA=y CONFIG_MTD_PHYSMAP_OF=y CONFIG_MTD_M25P80=y -CONFIG_MTD_NAND=y +CONFIG_MTD_RAW_NAND=y CONFIG_MTD_NAND_MARVELL=y CONFIG_MTD_SPI_NOR=y CONFIG_MTD_UBI=y diff --git a/arch/arm/configs/mxs_defconfig b/arch/arm/configs/mxs_defconfig index 38480596c449..ed570a0d1f2a 100644 --- a/arch/arm/configs/mxs_defconfig +++ b/arch/arm/configs/mxs_defconfig @@ -50,7 +50,7 @@ CONFIG_MTD_BLOCK=y CONFIG_MTD_DATAFLASH=y CONFIG_MTD_M25P80=y CONFIG_MTD_SST25L=y -CONFIG_MTD_NAND=y +CONFIG_MTD_RAW_NAND=y CONFIG_MTD_NAND_GPMI_NAND=y CONFIG_MTD_SPI_NOR=y CONFIG_MTD_UBI=y diff --git a/arch/arm/configs/nhk8815_defconfig b/arch/arm/configs/nhk8815_defconfig index e0373989b32d..cfc094189d09 100644 --- a/arch/arm/configs/nhk8815_defconfig +++ b/arch/arm/configs/nhk8815_defconfig @@ -54,7 +54,7 @@ CONFIG_MTD_ONENAND=y CONFIG_MTD_ONENAND_VERIFY_WRITE=y CONFIG_MTD_ONENAND_GENERIC=y CONFIG_MTD_NAND_ECC_SW_HAMMING_SMC=y -CONFIG_MTD_NAND=y +CONFIG_MTD_RAW_NAND=y CONFIG_MTD_NAND_FSMC=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_CRYPTOLOOP=y diff --git a/arch/arm/configs/omap1_defconfig b/arch/arm/configs/omap1_defconfig index cfc00b0961ec..40fdf890a292 100644 --- a/arch/arm/configs/omap1_defconfig +++ b/arch/arm/configs/omap1_defconfig @@ -90,7 +90,7 @@ CONFIG_MTD_CMDLINE_PARTS=y CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y CONFIG_MTD_CFI_INTELEXT=y -CONFIG_MTD_NAND=y +CONFIG_MTD_RAW_NAND=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_COUNT=2 diff --git a/arch/arm/configs/omap2plus_defconfig b/arch/arm/configs/omap2plus_defconfig index 7dc2ac9175de..c7bf9c493646 100644 --- a/arch/arm/configs/omap2plus_defconfig +++ b/arch/arm/configs/omap2plus_defconfig @@ -143,7 +143,7 @@ CONFIG_MTD_M25P80=m CONFIG_MTD_ONENAND=y CONFIG_MTD_ONENAND_VERIFY_WRITE=y CONFIG_MTD_ONENAND_OMAP2=y -CONFIG_MTD_NAND=y +CONFIG_MTD_RAW_NAND=y CONFIG_MTD_NAND_ECC_SW_BCH=y CONFIG_MTD_NAND_OMAP2=y CONFIG_MTD_NAND_OMAP_BCH=y diff --git a/arch/arm/configs/orion5x_defconfig b/arch/arm/configs/orion5x_defconfig index bf9046331f6e..077e0fde1ff9 100644 --- a/arch/arm/configs/orion5x_defconfig +++ b/arch/arm/configs/orion5x_defconfig @@ -70,7 +70,7 @@ CONFIG_MTD_CFI_GEOMETRY=y CONFIG_MTD_CFI_INTELEXT=y CONFIG_MTD_CFI_AMDSTD=y CONFIG_MTD_PHYSMAP=y -CONFIG_MTD_NAND=y +CONFIG_MTD_RAW_NAND=y CONFIG_MTD_NAND_PLATFORM=y CONFIG_MTD_NAND_ORION=y CONFIG_BLK_DEV_LOOP=y diff --git a/arch/arm/configs/oxnas_v6_defconfig b/arch/arm/configs/oxnas_v6_defconfig index f6ba32c9d173..cae0db6b4eaf 100644 --- a/arch/arm/configs/oxnas_v6_defconfig +++ b/arch/arm/configs/oxnas_v6_defconfig @@ -50,7 +50,7 @@ CONFIG_SIMPLE_PM_BUS=y CONFIG_MTD=y CONFIG_MTD_CMDLINE_PARTS=y CONFIG_MTD_BLOCK=y -CONFIG_MTD_NAND=y +CONFIG_MTD_RAW_NAND=y CONFIG_MTD_NAND_OXNAS=y CONFIG_MTD_UBI=y CONFIG_BLK_DEV_LOOP=y diff --git a/arch/arm/configs/pxa3xx_defconfig b/arch/arm/configs/pxa3xx_defconfig index 3e0de035ab77..7681eea60127 100644 --- a/arch/arm/configs/pxa3xx_defconfig +++ b/arch/arm/configs/pxa3xx_defconfig @@ -31,7 +31,7 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" # CONFIG_PREVENT_FIRMWARE_BUILD is not set CONFIG_MTD=y CONFIG_MTD_BLOCK=y -CONFIG_MTD_NAND=y +CONFIG_MTD_RAW_NAND=y CONFIG_MTD_NAND_MARVELL=y CONFIG_MTD_ONENAND=y CONFIG_MTD_ONENAND_VERIFY_WRITE=y diff --git a/arch/arm/configs/pxa_defconfig b/arch/arm/configs/pxa_defconfig index d91adb49ae11..f6d24d762a7f 100644 --- a/arch/arm/configs/pxa_defconfig +++ b/arch/arm/configs/pxa_defconfig @@ -185,7 +185,7 @@ CONFIG_MTD_PXA2XX=m CONFIG_MTD_M25P80=m CONFIG_MTD_BLOCK2MTD=y CONFIG_MTD_DOCG3=m -CONFIG_MTD_NAND=m +CONFIG_MTD_RAW_NAND=m CONFIG_MTD_NAND_ECC_SW_BCH=y CONFIG_MTD_NAND_GPIO=m CONFIG_MTD_NAND_DISKONCHIP=m diff --git a/arch/arm/configs/qcom_defconfig b/arch/arm/configs/qcom_defconfig index bd6440f23493..4c50b5337cf6 100644 --- a/arch/arm/configs/qcom_defconfig +++ b/arch/arm/configs/qcom_defconfig @@ -57,7 +57,7 @@ CONFIG_DEVTMPFS_MOUNT=y CONFIG_MTD=y CONFIG_MTD_BLOCK=y CONFIG_MTD_M25P80=y -CONFIG_MTD_NAND=y +CONFIG_MTD_RAW_NAND=y CONFIG_MTD_NAND_QCOM=y CONFIG_MTD_SPI_NOR=y CONFIG_BLK_DEV_LOOP=y diff --git a/arch/arm/configs/s3c2410_defconfig b/arch/arm/configs/s3c2410_defconfig index 2afb359f3168..39c648594d93 100644 --- a/arch/arm/configs/s3c2410_defconfig +++ b/arch/arm/configs/s3c2410_defconfig @@ -192,7 +192,7 @@ CONFIG_MTD_JEDECPROBE=y CONFIG_MTD_CFI_INTELEXT=y CONFIG_MTD_CFI_AMDSTD=y CONFIG_MTD_ROM=y -CONFIG_MTD_NAND=y +CONFIG_MTD_RAW_NAND=y CONFIG_MTD_NAND_S3C2410=y CONFIG_PARPORT=y CONFIG_PARPORT_PC=m diff --git a/arch/arm/configs/s3c6400_defconfig b/arch/arm/configs/s3c6400_defconfig index 507d7ad7523a..6e2656567da6 100644 --- a/arch/arm/configs/s3c6400_defconfig +++ b/arch/arm/configs/s3c6400_defconfig @@ -23,7 +23,7 @@ CONFIG_CMDLINE="console=ttySAC0,115200 root=/dev/ram init=/linuxrc initrd=0x5100 CONFIG_VFP=y CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" CONFIG_MTD=y -CONFIG_MTD_NAND=y +CONFIG_MTD_RAW_NAND=y CONFIG_MTD_NAND_S3C2410=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y diff --git a/arch/arm/configs/sama5_defconfig b/arch/arm/configs/sama5_defconfig index b0026f73083d..515cb37eeab6 100644 --- a/arch/arm/configs/sama5_defconfig +++ b/arch/arm/configs/sama5_defconfig @@ -66,7 +66,7 @@ CONFIG_MTD_CMDLINE_PARTS=y CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y CONFIG_MTD_M25P80=y -CONFIG_MTD_NAND=y +CONFIG_MTD_RAW_NAND=y CONFIG_MTD_NAND_ATMEL=y CONFIG_MTD_SPI_NOR=y CONFIG_MTD_UBI=y diff --git a/arch/arm/configs/socfpga_defconfig b/arch/arm/configs/socfpga_defconfig index 08d1b3e11d68..3b42e0d597bd 100644 --- a/arch/arm/configs/socfpga_defconfig +++ b/arch/arm/configs/socfpga_defconfig @@ -51,7 +51,7 @@ CONFIG_DEVTMPFS_MOUNT=y CONFIG_MTD=y CONFIG_MTD_BLOCK=y CONFIG_MTD_M25P80=y -CONFIG_MTD_NAND=y +CONFIG_MTD_RAW_NAND=y CONFIG_MTD_NAND_DENALI_DT=y CONFIG_MTD_SPI_NOR=y # CONFIG_MTD_SPI_NOR_USE_4K_SECTORS is not set diff --git a/arch/arm/configs/spear13xx_defconfig b/arch/arm/configs/spear13xx_defconfig index 7b36eeb928bb..8ee3679ca8b2 100644 --- a/arch/arm/configs/spear13xx_defconfig +++ b/arch/arm/configs/spear13xx_defconfig @@ -32,7 +32,7 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" CONFIG_MTD=y CONFIG_MTD_OF_PARTS=y CONFIG_MTD_BLOCK=y -CONFIG_MTD_NAND=y +CONFIG_MTD_RAW_NAND=y CONFIG_MTD_NAND_FSMC=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=16384 diff --git a/arch/arm/configs/spear3xx_defconfig b/arch/arm/configs/spear3xx_defconfig index f1b52fb3461b..ddd73b25f75e 100644 --- a/arch/arm/configs/spear3xx_defconfig +++ b/arch/arm/configs/spear3xx_defconfig @@ -17,7 +17,7 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" CONFIG_MTD=y CONFIG_MTD_OF_PARTS=y CONFIG_MTD_BLOCK=y -CONFIG_MTD_NAND=y +CONFIG_MTD_RAW_NAND=y CONFIG_MTD_NAND_FSMC=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=16384 diff --git a/arch/arm/configs/spear6xx_defconfig b/arch/arm/configs/spear6xx_defconfig index 124c244d8df1..5b410f0a365b 100644 --- a/arch/arm/configs/spear6xx_defconfig +++ b/arch/arm/configs/spear6xx_defconfig @@ -14,7 +14,7 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" CONFIG_MTD=y CONFIG_MTD_OF_PARTS=y CONFIG_MTD_BLOCK=y -CONFIG_MTD_NAND=y +CONFIG_MTD_RAW_NAND=y CONFIG_MTD_NAND_FSMC=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=16384 diff --git a/arch/arm/configs/spitz_defconfig b/arch/arm/configs/spitz_defconfig index 9ea82c118661..f6d2f674517c 100644 --- a/arch/arm/configs/spitz_defconfig +++ b/arch/arm/configs/spitz_defconfig @@ -84,7 +84,7 @@ CONFIG_MTD_CMDLINE_PARTS=y CONFIG_MTD_BLOCK=y CONFIG_MTD_ROM=y CONFIG_MTD_COMPLEX_MAPPINGS=y -CONFIG_MTD_NAND=y +CONFIG_MTD_RAW_NAND=y CONFIG_MTD_NAND_SHARPSL=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_SD=y diff --git a/arch/arm/configs/tango4_defconfig b/arch/arm/configs/tango4_defconfig index 68725d4eae45..68eb16e583ac 100644 --- a/arch/arm/configs/tango4_defconfig +++ b/arch/arm/configs/tango4_defconfig @@ -39,7 +39,7 @@ CONFIG_DEVTMPFS_MOUNT=y CONFIG_MTD=y CONFIG_MTD_TESTS=m CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_NAND=y +CONFIG_MTD_RAW_NAND=y CONFIG_MTD_NAND_TANGO=y CONFIG_BLK_DEV_LOOP=y CONFIG_SCSI=y diff --git a/arch/arm/configs/trizeps4_defconfig b/arch/arm/configs/trizeps4_defconfig index 2b5a224d2da1..ecad22501b48 100644 --- a/arch/arm/configs/trizeps4_defconfig +++ b/arch/arm/configs/trizeps4_defconfig @@ -76,7 +76,7 @@ CONFIG_MTD_DOC2001PLUS=y CONFIG_MTD_DOCPROBE_ADVANCED=y CONFIG_MTD_DOCPROBE_ADDRESS=0x4000000 CONFIG_MTD_DOCPROBE_HIGH=y -CONFIG_MTD_NAND=y +CONFIG_MTD_RAW_NAND=y CONFIG_MTD_NAND_DISKONCHIP=y CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADVANCED=y CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS=0x4000000 diff --git a/arch/arm/configs/u300_defconfig b/arch/arm/configs/u300_defconfig index 36d77406e31b..cfd3622e2c8a 100644 --- a/arch/arm/configs/u300_defconfig +++ b/arch/arm/configs/u300_defconfig @@ -27,7 +27,7 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" # CONFIG_PREVENT_FIRMWARE_BUILD is not set CONFIG_MTD=y CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_NAND=y +CONFIG_MTD_RAW_NAND=y CONFIG_MTD_NAND_FSMC=y # CONFIG_INPUT_MOUSEDEV is not set CONFIG_INPUT_EVDEV=y diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig index 2d9c39033c1a..9a8718bbf6ba 100644 --- a/arch/arm64/configs/defconfig +++ b/arch/arm64/configs/defconfig @@ -206,7 +206,7 @@ CONFIG_SIMPLE_PM_BUS=y CONFIG_MTD=y CONFIG_MTD_BLOCK=y CONFIG_MTD_M25P80=y -CONFIG_MTD_NAND=y +CONFIG_MTD_RAW_NAND=y CONFIG_MTD_NAND_DENALI_DT=y CONFIG_MTD_NAND_MARVELL=y CONFIG_MTD_NAND_QCOM=y diff --git a/arch/mips/configs/bcm47xx_defconfig b/arch/mips/configs/bcm47xx_defconfig index 249f5285e343..91ce75edbfb4 100644 --- a/arch/mips/configs/bcm47xx_defconfig +++ b/arch/mips/configs/bcm47xx_defconfig @@ -41,7 +41,7 @@ CONFIG_MTD_CFI_AMDSTD=y CONFIG_MTD_COMPLEX_MAPPINGS=y CONFIG_MTD_PHYSMAP=y CONFIG_MTD_BCM47XXSFLASH=y -CONFIG_MTD_NAND=y +CONFIG_MTD_RAW_NAND=y CONFIG_MTD_NAND_BCM47XXNFLASH=y CONFIG_NETDEVICES=y CONFIG_B44=y diff --git a/arch/mips/configs/ci20_defconfig b/arch/mips/configs/ci20_defconfig index 412800d5d7e0..50bebce28500 100644 --- a/arch/mips/configs/ci20_defconfig +++ b/arch/mips/configs/ci20_defconfig @@ -51,7 +51,7 @@ CONFIG_DEVTMPFS=y CONFIG_DMA_CMA=y CONFIG_CMA_SIZE_MBYTES=32 CONFIG_MTD=y -CONFIG_MTD_NAND=y +CONFIG_MTD_RAW_NAND=y CONFIG_MTD_NAND_JZ4780=y CONFIG_MTD_UBI=y CONFIG_MTD_UBI_FASTMAP=y diff --git a/arch/mips/configs/db1xxx_defconfig b/arch/mips/configs/db1xxx_defconfig index c5a2c6f234d4..bc9b6ae046b2 100644 --- a/arch/mips/configs/db1xxx_defconfig +++ b/arch/mips/configs/db1xxx_defconfig @@ -95,7 +95,7 @@ CONFIG_MTD_CFI_AMDSTD=y CONFIG_MTD_PHYSMAP=y CONFIG_MTD_M25P80=y CONFIG_MTD_SST25L=y -CONFIG_MTD_NAND=y +CONFIG_MTD_RAW_NAND=y CONFIG_MTD_NAND_ECC_SW_BCH=y CONFIG_MTD_NAND_AU1550=y CONFIG_MTD_NAND_PLATFORM=y diff --git a/arch/mips/configs/generic/board-ni169445.config b/arch/mips/configs/generic/board-ni169445.config index e68da2e9dc7c..1ed0d3e8715e 100644 --- a/arch/mips/configs/generic/board-ni169445.config +++ b/arch/mips/configs/generic/board-ni169445.config @@ -17,7 +17,7 @@ CONFIG_MTD_CMDLINE_PARTS=y CONFIG_MTD_NAND_ECC_SW_HAMMING=y CONFIG_MTD_NAND_ECC_SW_BCH=y -CONFIG_MTD_NAND=y +CONFIG_MTD_RAW_NAND=y CONFIG_MTD_NAND_GPIO=y CONFIG_MTD_NAND_IDS=y diff --git a/arch/mips/configs/generic/board-ocelot.config b/arch/mips/configs/generic/board-ocelot.config index f607888d2483..2621630f9850 100644 --- a/arch/mips/configs/generic/board-ocelot.config +++ b/arch/mips/configs/generic/board-ocelot.config @@ -6,7 +6,7 @@ CONFIG_MTD=y CONFIG_MTD_CMDLINE_PARTS=y CONFIG_MTD_BLOCK=y CONFIG_MTD_M25P80=y -CONFIG_MTD_NAND=y +CONFIG_MTD_RAW_NAND=y CONFIG_MTD_NAND_PLATFORM=y CONFIG_MTD_SPI_NOR=y CONFIG_MTD_UBI=y diff --git a/arch/mips/configs/loongson1b_defconfig b/arch/mips/configs/loongson1b_defconfig index b064d68a5424..1628e6fcc405 100644 --- a/arch/mips/configs/loongson1b_defconfig +++ b/arch/mips/configs/loongson1b_defconfig @@ -42,7 +42,7 @@ CONFIG_DEVTMPFS_MOUNT=y CONFIG_MTD=y CONFIG_MTD_CMDLINE_PARTS=y CONFIG_MTD_BLOCK=y -CONFIG_MTD_NAND=y +CONFIG_MTD_RAW_NAND=y CONFIG_MTD_UBI=y CONFIG_BLK_DEV_LOOP=y CONFIG_SCSI=m diff --git a/arch/mips/configs/loongson1c_defconfig b/arch/mips/configs/loongson1c_defconfig index 5d76559b56cd..7aa5527e50b1 100644 --- a/arch/mips/configs/loongson1c_defconfig +++ b/arch/mips/configs/loongson1c_defconfig @@ -43,7 +43,7 @@ CONFIG_DEVTMPFS_MOUNT=y CONFIG_MTD=y CONFIG_MTD_CMDLINE_PARTS=y CONFIG_MTD_BLOCK=y -CONFIG_MTD_NAND=y +CONFIG_MTD_RAW_NAND=y CONFIG_MTD_UBI=y CONFIG_BLK_DEV_LOOP=y CONFIG_SCSI=m diff --git a/arch/mips/configs/qi_lb60_defconfig b/arch/mips/configs/qi_lb60_defconfig index 7671fe6a8042..1a0677d04982 100644 --- a/arch/mips/configs/qi_lb60_defconfig +++ b/arch/mips/configs/qi_lb60_defconfig @@ -44,7 +44,7 @@ CONFIG_TCP_CONG_WESTWOOD=y CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" CONFIG_MTD=y CONFIG_MTD_BLOCK=y -CONFIG_MTD_NAND=y +CONFIG_MTD_RAW_NAND=y CONFIG_MTD_NAND_JZ4740=y CONFIG_MTD_UBI=y CONFIG_NETDEVICES=y diff --git a/arch/mips/configs/rb532_defconfig b/arch/mips/configs/rb532_defconfig index 7befe05fd813..4cbcf015a7ed 100644 --- a/arch/mips/configs/rb532_defconfig +++ b/arch/mips/configs/rb532_defconfig @@ -110,7 +110,7 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" CONFIG_MTD=y CONFIG_MTD_BLOCK=y CONFIG_MTD_BLOCK2MTD=y -CONFIG_MTD_NAND=y +CONFIG_MTD_RAW_NAND=y CONFIG_MTD_NAND_PLATFORM=y CONFIG_ATA=y # CONFIG_ATA_VERBOSE_ERROR is not set diff --git a/arch/mips/configs/rbtx49xx_defconfig b/arch/mips/configs/rbtx49xx_defconfig index 50a2c9ad583f..96114ca59016 100644 --- a/arch/mips/configs/rbtx49xx_defconfig +++ b/arch/mips/configs/rbtx49xx_defconfig @@ -40,7 +40,7 @@ CONFIG_MTD_CFI_AMDSTD=y CONFIG_MTD_COMPLEX_MAPPINGS=y CONFIG_MTD_PHYSMAP=y CONFIG_MTD_RBTX4939=y -CONFIG_MTD_NAND=m +CONFIG_MTD_RAW_NAND=m CONFIG_MTD_NAND_TXX9NDFMC=m CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y diff --git a/arch/mips/configs/xway_defconfig b/arch/mips/configs/xway_defconfig index 2bb02ea9fb4e..203db83c3ee9 100644 --- a/arch/mips/configs/xway_defconfig +++ b/arch/mips/configs/xway_defconfig @@ -81,7 +81,7 @@ CONFIG_MTD_COMPLEX_MAPPINGS=y CONFIG_MTD_PHYSMAP=y CONFIG_MTD_PHYSMAP_OF=y CONFIG_MTD_LANTIQ=y -CONFIG_MTD_NAND=y +CONFIG_MTD_RAW_NAND=y CONFIG_MTD_NAND_XWAY=y CONFIG_EEPROM_93CX6=m CONFIG_SCSI=y diff --git a/arch/powerpc/configs/40x/kilauea_defconfig b/arch/powerpc/configs/40x/kilauea_defconfig index b5cc7426c21f..3da091f651d6 100644 --- a/arch/powerpc/configs/40x/kilauea_defconfig +++ b/arch/powerpc/configs/40x/kilauea_defconfig @@ -33,7 +33,7 @@ CONFIG_MTD_CFI=y CONFIG_MTD_JEDECPROBE=y CONFIG_MTD_CFI_AMDSTD=y CONFIG_MTD_PHYSMAP_OF=y -CONFIG_MTD_NAND=y +CONFIG_MTD_RAW_NAND=y CONFIG_MTD_NAND_NDFC=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=35000 diff --git a/arch/powerpc/configs/40x/obs600_defconfig b/arch/powerpc/configs/40x/obs600_defconfig index aac06d2ad01a..38d3d7769a2f 100644 --- a/arch/powerpc/configs/40x/obs600_defconfig +++ b/arch/powerpc/configs/40x/obs600_defconfig @@ -33,7 +33,7 @@ CONFIG_MTD_CFI=y CONFIG_MTD_JEDECPROBE=y CONFIG_MTD_CFI_AMDSTD=y CONFIG_MTD_PHYSMAP_OF=y -CONFIG_MTD_NAND=y +CONFIG_MTD_RAW_NAND=y CONFIG_MTD_NAND_NDFC=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=35000 diff --git a/arch/powerpc/configs/44x/canyonlands_defconfig b/arch/powerpc/configs/44x/canyonlands_defconfig index c8e6f048a122..d427cee027a6 100644 --- a/arch/powerpc/configs/44x/canyonlands_defconfig +++ b/arch/powerpc/configs/44x/canyonlands_defconfig @@ -32,7 +32,7 @@ CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y CONFIG_MTD_CFI_AMDSTD=y CONFIG_MTD_PHYSMAP_OF=y -CONFIG_MTD_NAND=y +CONFIG_MTD_RAW_NAND=y CONFIG_MTD_NAND_NDFC=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=35000 diff --git a/arch/powerpc/configs/44x/eiger_defconfig b/arch/powerpc/configs/44x/eiger_defconfig index f6dc23fef683..f593258806ad 100644 --- a/arch/powerpc/configs/44x/eiger_defconfig +++ b/arch/powerpc/configs/44x/eiger_defconfig @@ -33,7 +33,7 @@ CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y CONFIG_MTD_CFI_AMDSTD=y CONFIG_MTD_PHYSMAP_OF=y -CONFIG_MTD_NAND=y +CONFIG_MTD_RAW_NAND=y CONFIG_MTD_NAND_NDFC=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=35000 diff --git a/arch/powerpc/configs/44x/sequoia_defconfig b/arch/powerpc/configs/44x/sequoia_defconfig index 1e04122912f3..f34fee9464e5 100644 --- a/arch/powerpc/configs/44x/sequoia_defconfig +++ b/arch/powerpc/configs/44x/sequoia_defconfig @@ -33,7 +33,7 @@ CONFIG_MTD_JEDECPROBE=y CONFIG_MTD_CFI_INTELEXT=y CONFIG_MTD_CFI_AMDSTD=y CONFIG_MTD_PHYSMAP_OF=y -CONFIG_MTD_NAND=y +CONFIG_MTD_RAW_NAND=y CONFIG_MTD_NAND_NDFC=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=35000 diff --git a/arch/powerpc/configs/44x/warp_defconfig b/arch/powerpc/configs/44x/warp_defconfig index 6c02f53271cd..6ae88d4879bf 100644 --- a/arch/powerpc/configs/44x/warp_defconfig +++ b/arch/powerpc/configs/44x/warp_defconfig @@ -34,7 +34,7 @@ CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y CONFIG_MTD_CFI_AMDSTD=y CONFIG_MTD_PHYSMAP_OF=y -CONFIG_MTD_NAND=y +CONFIG_MTD_RAW_NAND=y CONFIG_MTD_NAND_NDFC=y CONFIG_MTD_UBI=y CONFIG_BLK_DEV_RAM=y diff --git a/arch/powerpc/configs/83xx/mpc8313_rdb_defconfig b/arch/powerpc/configs/83xx/mpc8313_rdb_defconfig index 1f69f4edf074..9dffb2e7f735 100644 --- a/arch/powerpc/configs/83xx/mpc8313_rdb_defconfig +++ b/arch/powerpc/configs/83xx/mpc8313_rdb_defconfig @@ -31,7 +31,7 @@ CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y CONFIG_MTD_CFI_AMDSTD=y CONFIG_MTD_PHYSMAP_OF=y -CONFIG_MTD_NAND=y +CONFIG_MTD_RAW_NAND=y CONFIG_MTD_NAND_FSL_ELBC=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y diff --git a/arch/powerpc/configs/83xx/mpc8315_rdb_defconfig b/arch/powerpc/configs/83xx/mpc8315_rdb_defconfig index 797fc3ffddee..a42232732c6d 100644 --- a/arch/powerpc/configs/83xx/mpc8315_rdb_defconfig +++ b/arch/powerpc/configs/83xx/mpc8315_rdb_defconfig @@ -31,7 +31,7 @@ CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y CONFIG_MTD_CFI_AMDSTD=y CONFIG_MTD_PHYSMAP_OF=y -CONFIG_MTD_NAND=y +CONFIG_MTD_RAW_NAND=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=32768 diff --git a/arch/powerpc/configs/85xx-hw.config b/arch/powerpc/configs/85xx-hw.config index c03d0fb16665..9575a38c9155 100644 --- a/arch/powerpc/configs/85xx-hw.config +++ b/arch/powerpc/configs/85xx-hw.config @@ -71,7 +71,7 @@ CONFIG_MTD_CMDLINE_PARTS=y CONFIG_MTD_M25P80=y CONFIG_MTD_NAND_FSL_ELBC=y CONFIG_MTD_NAND_FSL_IFC=y -CONFIG_MTD_NAND=y +CONFIG_MTD_RAW_NAND=y CONFIG_MTD_PHYSMAP_OF=y CONFIG_MTD_PHYSMAP=y CONFIG_MTD_PLATRAM=y diff --git a/arch/powerpc/configs/85xx/ge_imp3a_defconfig b/arch/powerpc/configs/85xx/ge_imp3a_defconfig index dd98f43b2fb8..d70b60314dad 100644 --- a/arch/powerpc/configs/85xx/ge_imp3a_defconfig +++ b/arch/powerpc/configs/85xx/ge_imp3a_defconfig @@ -73,7 +73,7 @@ CONFIG_MTD_JEDECPROBE=y CONFIG_MTD_CFI_INTELEXT=y CONFIG_MTD_CFI_AMDSTD=y CONFIG_MTD_PHYSMAP_OF=y -CONFIG_MTD_NAND=y +CONFIG_MTD_RAW_NAND=y CONFIG_MTD_NAND_FSL_ELBC=y CONFIG_BLK_DEV_LOOP=m CONFIG_BLK_DEV_CRYPTOLOOP=m diff --git a/arch/powerpc/configs/85xx/socrates_defconfig b/arch/powerpc/configs/85xx/socrates_defconfig index 6106fadbbd8b..7037a6d8018c 100644 --- a/arch/powerpc/configs/85xx/socrates_defconfig +++ b/arch/powerpc/configs/85xx/socrates_defconfig @@ -31,7 +31,7 @@ CONFIG_MTD_CFI=y CONFIG_MTD_JEDECPROBE=y CONFIG_MTD_CFI_AMDSTD=y CONFIG_MTD_PHYSMAP_OF=y -CONFIG_MTD_NAND=y +CONFIG_MTD_RAW_NAND=y CONFIG_MTD_NAND_SOCRATES=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y diff --git a/arch/powerpc/configs/85xx/tqm8548_defconfig b/arch/powerpc/configs/85xx/tqm8548_defconfig index 464ce192bc14..1c63cbdc3211 100644 --- a/arch/powerpc/configs/85xx/tqm8548_defconfig +++ b/arch/powerpc/configs/85xx/tqm8548_defconfig @@ -36,7 +36,7 @@ CONFIG_MTD_CFI=y CONFIG_MTD_CFI_AMDSTD=y CONFIG_MTD_PHYSMAP_OF=y CONFIG_MTD_NAND_ECC_SW_HAMMING_SMC=y -CONFIG_MTD_NAND=y +CONFIG_MTD_RAW_NAND=y CONFIG_MTD_NAND_FSL_UPM=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y diff --git a/arch/powerpc/configs/85xx/xes_mpc85xx_defconfig b/arch/powerpc/configs/85xx/xes_mpc85xx_defconfig index 6531139a8a8d..78f5beb2928c 100644 --- a/arch/powerpc/configs/85xx/xes_mpc85xx_defconfig +++ b/arch/powerpc/configs/85xx/xes_mpc85xx_defconfig @@ -65,7 +65,7 @@ CONFIG_MTD_CFI_INTELEXT=y CONFIG_MTD_CFI_AMDSTD=y CONFIG_MTD_CFI_STAA=y CONFIG_MTD_PHYSMAP_OF=y -CONFIG_MTD_NAND=y +CONFIG_MTD_RAW_NAND=y CONFIG_MTD_NAND_FSL_ELBC=y CONFIG_MTD_NAND_FSL_UPM=y CONFIG_BLK_DEV_LOOP=y diff --git a/arch/powerpc/configs/86xx-hw.config b/arch/powerpc/configs/86xx-hw.config index d3dd6b8865c0..151164cf8cb3 100644 --- a/arch/powerpc/configs/86xx-hw.config +++ b/arch/powerpc/configs/86xx-hw.config @@ -47,7 +47,7 @@ CONFIG_MTD_CFI=y CONFIG_MTD_CMDLINE_PARTS=y CONFIG_MTD_JEDECPROBE=y CONFIG_MTD_NAND_FSL_ELBC=y -CONFIG_MTD_NAND=y +CONFIG_MTD_RAW_NAND=y CONFIG_MTD_PHYSMAP_OF=y CONFIG_NETDEVICES=y CONFIG_NET_TULIP=y diff --git a/arch/powerpc/configs/mpc512x_defconfig b/arch/powerpc/configs/mpc512x_defconfig index e4bfb1101c0e..e4bf8aa87e60 100644 --- a/arch/powerpc/configs/mpc512x_defconfig +++ b/arch/powerpc/configs/mpc512x_defconfig @@ -46,7 +46,7 @@ CONFIG_MTD_CFI=y CONFIG_MTD_CFI_AMDSTD=y CONFIG_MTD_ROM=y CONFIG_MTD_PHYSMAP_OF=y -CONFIG_MTD_NAND=y +CONFIG_MTD_RAW_NAND=y CONFIG_MTD_NAND_MPC5121_NFC=y CONFIG_MTD_UBI=y CONFIG_BLK_DEV_RAM=y diff --git a/arch/powerpc/configs/mpc83xx_defconfig b/arch/powerpc/configs/mpc83xx_defconfig index d1b82035d35f..005d00020fb9 100644 --- a/arch/powerpc/configs/mpc83xx_defconfig +++ b/arch/powerpc/configs/mpc83xx_defconfig @@ -46,7 +46,7 @@ CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y CONFIG_MTD_CFI_AMDSTD=y CONFIG_MTD_PHYSMAP_OF=y -CONFIG_MTD_NAND=y +CONFIG_MTD_RAW_NAND=y CONFIG_MTD_NAND_FSL_ELBC=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y diff --git a/arch/powerpc/configs/pasemi_defconfig b/arch/powerpc/configs/pasemi_defconfig index 6daa56f8895c..c0423b2cf7c0 100644 --- a/arch/powerpc/configs/pasemi_defconfig +++ b/arch/powerpc/configs/pasemi_defconfig @@ -51,7 +51,7 @@ CONFIG_MTD=y CONFIG_MTD_BLOCK=y CONFIG_MTD_SLRAM=y CONFIG_MTD_PHRAM=y -CONFIG_MTD_NAND=y +CONFIG_MTD_RAW_NAND=y CONFIG_MTD_NAND_PASEMI=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y diff --git a/arch/powerpc/configs/ppc44x_defconfig b/arch/powerpc/configs/ppc44x_defconfig index 66dd6bf45cde..db48039e0b11 100644 --- a/arch/powerpc/configs/ppc44x_defconfig +++ b/arch/powerpc/configs/ppc44x_defconfig @@ -44,7 +44,7 @@ CONFIG_MTD_CFI=y CONFIG_MTD_JEDECPROBE=y CONFIG_MTD_CFI_AMDSTD=y CONFIG_MTD_PHYSMAP_OF=y -CONFIG_MTD_NAND=m +CONFIG_MTD_RAW_NAND=m CONFIG_MTD_NAND_NDFC=m CONFIG_MTD_UBI=m CONFIG_MTD_UBI_GLUEBI=m diff --git a/arch/sh/configs/ap325rxa_defconfig b/arch/sh/configs/ap325rxa_defconfig index 72b72e50a92e..0ef3f1f9de5c 100644 --- a/arch/sh/configs/ap325rxa_defconfig +++ b/arch/sh/configs/ap325rxa_defconfig @@ -35,7 +35,7 @@ CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y CONFIG_MTD_CFI_AMDSTD=y CONFIG_MTD_PHYSMAP=y -CONFIG_MTD_NAND=y +CONFIG_MTD_RAW_NAND=y CONFIG_MTD_NAND_SH_FLCTL=y CONFIG_MTD_UBI=y CONFIG_BLK_DEV_RAM=y diff --git a/arch/sh/configs/ecovec24_defconfig b/arch/sh/configs/ecovec24_defconfig index 3568310c2c2f..ba67e3752938 100644 --- a/arch/sh/configs/ecovec24_defconfig +++ b/arch/sh/configs/ecovec24_defconfig @@ -38,7 +38,7 @@ CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y CONFIG_MTD_CFI_AMDSTD=y CONFIG_MTD_PHYSMAP=y -CONFIG_MTD_NAND=y +CONFIG_MTD_RAW_NAND=y CONFIG_MTD_UBI=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_COUNT=4 diff --git a/arch/sh/configs/migor_defconfig b/arch/sh/configs/migor_defconfig index e04f21be0756..121a75d65fb4 100644 --- a/arch/sh/configs/migor_defconfig +++ b/arch/sh/configs/migor_defconfig @@ -34,7 +34,7 @@ CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y CONFIG_MTD_CFI_AMDSTD=y CONFIG_MTD_PHYSMAP=y -CONFIG_MTD_NAND=y +CONFIG_MTD_RAW_NAND=y CONFIG_MTD_NAND_PLATFORM=y CONFIG_BLK_DEV_RAM=y CONFIG_SCSI=y diff --git a/arch/sh/configs/sdk7786_defconfig b/arch/sh/configs/sdk7786_defconfig index d16e9334cd98..5209889765ad 100644 --- a/arch/sh/configs/sdk7786_defconfig +++ b/arch/sh/configs/sdk7786_defconfig @@ -108,7 +108,7 @@ CONFIG_MTD_ROM=m CONFIG_MTD_ABSENT=m CONFIG_MTD_PLATRAM=y CONFIG_MTD_PHRAM=y -CONFIG_MTD_NAND=y +CONFIG_MTD_RAW_NAND=y CONFIG_MTD_NAND_PLATFORM=y CONFIG_MTD_NAND_SH_FLCTL=m CONFIG_MTD_UBI=y diff --git a/arch/sh/configs/se7724_defconfig b/arch/sh/configs/se7724_defconfig index aedb3a2d9a10..9f6d46d58554 100644 --- a/arch/sh/configs/se7724_defconfig +++ b/arch/sh/configs/se7724_defconfig @@ -37,7 +37,7 @@ CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y CONFIG_MTD_CFI_AMDSTD=y CONFIG_MTD_PHYSMAP=y -CONFIG_MTD_NAND=y +CONFIG_MTD_RAW_NAND=y CONFIG_MTD_UBI=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_COUNT=4 diff --git a/arch/sh/configs/titan_defconfig b/arch/sh/configs/titan_defconfig index ceb48e9b70f4..822fa9e96f74 100644 --- a/arch/sh/configs/titan_defconfig +++ b/arch/sh/configs/titan_defconfig @@ -155,7 +155,7 @@ CONFIG_INFTL=m CONFIG_RFD_FTL=m CONFIG_MTD_CFI=m CONFIG_MTD_JEDECPROBE=m -CONFIG_MTD_NAND=m +CONFIG_MTD_RAW_NAND=m CONFIG_BLK_DEV_LOOP=m CONFIG_BLK_DEV_CRYPTOLOOP=m CONFIG_BLK_DEV_RAM=y diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig index c3a898a300e0..615d738be411 100644 --- a/drivers/mtd/nand/raw/Kconfig +++ b/drivers/mtd/nand/raw/Kconfig @@ -9,7 +9,7 @@ config MTD_NAND_ECC_SW_HAMMING_SMC Software ECC according to the Smart Media Specification. The original Linux implementation had byte 0 and 1 swapped. -menuconfig MTD_NAND +menuconfig MTD_RAW_NAND tristate "Raw/Parallel NAND Device Support" depends on MTD select MTD_NAND_CORE @@ -19,7 +19,7 @@ menuconfig MTD_NAND NAND flash devices. For further information see . -if MTD_NAND +if MTD_RAW_NAND config MTD_NAND_ECC_SW_BCH tristate "Support software BCH ECC" @@ -545,4 +545,4 @@ config MTD_NAND_DISKONCHIP_BBTWRITE load time (assuming you build diskonchip as a module) with the module parameter "inftl_bbt_write=1". -endif # MTD_NAND +endif # MTD_RAW_NAND diff --git a/drivers/mtd/nand/raw/Makefile b/drivers/mtd/nand/raw/Makefile index a022931318ac..8bc6faaa3bc7 100644 --- a/drivers/mtd/nand/raw/Makefile +++ b/drivers/mtd/nand/raw/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 -obj-$(CONFIG_MTD_NAND) += nand.o +obj-$(CONFIG_MTD_RAW_NAND) += nand.o obj-$(CONFIG_MTD_NAND_ECC_SW_HAMMING) += nand_ecc.o obj-$(CONFIG_MTD_NAND_ECC_SW_BCH) += nand_bch.o obj-$(CONFIG_MTD_SM_COMMON) += sm_common.o diff --git a/drivers/mtd/tests/mtd_nandecctest.c b/drivers/mtd/tests/mtd_nandecctest.c index 0c0091fb3708..73b06304c975 100644 --- a/drivers/mtd/tests/mtd_nandecctest.c +++ b/drivers/mtd/tests/mtd_nandecctest.c @@ -21,7 +21,7 @@ * or detected. */ -#if IS_ENABLED(CONFIG_MTD_NAND) +#if IS_ENABLED(CONFIG_MTD_RAW_NAND) struct nand_ecc_test { const char *name; -- cgit From 31bc36c4550785ae854fc80d001fea76ade48fcf Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Wed, 6 Feb 2019 16:03:13 +0100 Subject: mtd: nand: Remove useless line in Kconfig Prepare changes that will lay in this file to better express what is NAND related and what is not in menuconfig. Signed-off-by: Miquel Raynal --- drivers/mtd/nand/Kconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index 9033215e62ea..495751ed3fd7 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -2,6 +2,5 @@ config MTD_NAND_CORE tristate source "drivers/mtd/nand/onenand/Kconfig" - source "drivers/mtd/nand/raw/Kconfig" source "drivers/mtd/nand/spi/Kconfig" -- cgit From 7019ac5d3bbf1ba98e25c38b0cfb497e0ebdc5f0 Mon Sep 17 00:00:00 2001 From: Anders Roxell Date: Wed, 10 Apr 2019 21:58:52 +0200 Subject: mtd: rawnand: fix build dependency When enabling CONFIG_MTD_NAND_ECC_SW_BCH as a module, the MTD_NAND_ECC_SW_BCH depends on MTD_NAND, but the module controlled by MTD_NAND links against the module controlled by MTD_NAND_ECC_SW_BCH. This leads to the following link failure. aarch64-linux-gnu-ld: drivers/mtd/nand/raw/nand_base.o: in function `nand_cleanup': ../drivers/mtd/nand/raw/nand_base.c:5886: undefined reference to `nand_bch_free' aarch64-linux-gnu-ld: ../drivers/mtd/nand/raw/nand_base.c:5886:(.text+0x9928): relocation truncated to fit: R_AARCH64_CALL26 against undefined symbol `nand_bch_free' aarch64-linux-gnu-ld: drivers/mtd/nand/raw/nand_base.o: in function `nand_set_ecc_soft_ops': ../drivers/mtd/nand/raw/nand_base.c:5093: undefined reference to `nand_bch_calculate_ecc' aarch64-linux-gnu-ld: ../drivers/mtd/nand/raw/nand_base.c:5093:(.text+0xe914): relocation truncated to fit: R_AARCH64_ADR_PREL_PG_HI21 against undefined symbol `nand_bch_calculate_ecc' aarch64-linux-gnu-ld: ../drivers/mtd/nand/raw/nand_base.c:5093: undefined reference to `nand_bch_calculate_ecc' aarch64-linux-gnu-ld: ../drivers/mtd/nand/raw/nand_base.c:5094: undefined reference to `nand_bch_correct_data' aarch64-linux-gnu-ld: ../drivers/mtd/nand/raw/nand_base.c:5094:(.text+0xe934): relocation truncated to fit: R_AARCH64_ADR_PREL_PG_HI21 against undefined symbol `nand_bch_correct_data' aarch64-linux-gnu-ld: ../drivers/mtd/nand/raw/nand_base.c:5094: undefined reference to `nand_bch_correct_data' aarch64-linux-gnu-ld: ../drivers/mtd/nand/raw/nand_base.c:5148: undefined reference to `nand_bch_init' aarch64-linux-gnu-ld: ../drivers/mtd/nand/raw/nand_base.c:5148:(.text+0xebbc): relocation truncated to fit: R_AARCH64_CALL26 against undefined symbol `nand_bch_init' Rework CONFIG_MTD_NAND_ECC_SW_BCH from tristate to bool, and then link the nand_bch.o file into nand.ko if its enabled. Fixes: 51ef1d0b2095 ("mtd: nand: Clarify Kconfig entry for software BCH ECC algorithm") Signed-off-by: Anders Roxell Signed-off-by: Miquel Raynal --- drivers/mtd/nand/raw/Kconfig | 2 +- drivers/mtd/nand/raw/Makefile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig index 615d738be411..0500c42f31cb 100644 --- a/drivers/mtd/nand/raw/Kconfig +++ b/drivers/mtd/nand/raw/Kconfig @@ -22,7 +22,7 @@ menuconfig MTD_RAW_NAND if MTD_RAW_NAND config MTD_NAND_ECC_SW_BCH - tristate "Support software BCH ECC" + bool "Support software BCH ECC" select BCH default n help diff --git a/drivers/mtd/nand/raw/Makefile b/drivers/mtd/nand/raw/Makefile index 8bc6faaa3bc7..efaf5cd25edc 100644 --- a/drivers/mtd/nand/raw/Makefile +++ b/drivers/mtd/nand/raw/Makefile @@ -2,7 +2,7 @@ obj-$(CONFIG_MTD_RAW_NAND) += nand.o obj-$(CONFIG_MTD_NAND_ECC_SW_HAMMING) += nand_ecc.o -obj-$(CONFIG_MTD_NAND_ECC_SW_BCH) += nand_bch.o +nand-$(CONFIG_MTD_NAND_ECC_SW_BCH) += nand_bch.o obj-$(CONFIG_MTD_SM_COMMON) += sm_common.o obj-$(CONFIG_MTD_NAND_CAFE) += cafe_nand.o -- cgit From 7e8afca5cf1aeeec183a221c6fc07faf4cc380df Mon Sep 17 00:00:00 2001 From: Jonathan Neuschäfer Date: Fri, 22 Mar 2019 00:52:41 +0100 Subject: mtd: rawnand: Fix sphinx syntax MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sphinx doesn't handle expressions in identifier references. This fixes the following warnings: ./include/linux/mtd/rawnand.h:1184: WARNING: Inline strong start-string without end-string. ./include/linux/mtd/rawnand.h:1186: WARNING: Inline strong start-string without end-string. Signed-off-by: Jonathan Neuschäfer Signed-off-by: Miquel Raynal --- include/linux/mtd/rawnand.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h index c0589f82c1f8..7c0ccd3a2772 100644 --- a/include/linux/mtd/rawnand.h +++ b/include/linux/mtd/rawnand.h @@ -1168,9 +1168,9 @@ static inline struct device_node *nand_get_flash_node(struct nand_chip *chip) * @name: a human-readable name of the NAND chip * @dev_id: the device ID (the second byte of the full chip ID array) * @mfr_id: manufecturer ID part of the full chip ID array (refers the same - * memory address as @id[0]) + * memory address as ``id[0]``) * @dev_id: device ID part of the full chip ID array (refers the same memory - * address as @id[1]) + * address as ``id[1]``) * @id: full device ID array * @pagesize: size of the NAND page in bytes; if 0, then the real page size (as * well as the eraseblock size) is determined from the extended NAND -- cgit From 9fed311591969cb153eac2ba493875882d29ced6 Mon Sep 17 00:00:00 2001 From: Marek Behún Date: Fri, 22 Mar 2019 14:26:17 +0100 Subject: mtd: rawnand: fsl_elbc: Cosmetic move MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move the fsl_elbc_attach_chip function after the definitions of fsl_elbc_read_page and friends in preparation for the next patch. Signed-off-by: Marek Behún Signed-off-by: Miquel Raynal --- drivers/mtd/nand/raw/fsl_elbc_nand.c | 146 +++++++++++++++++------------------ 1 file changed, 73 insertions(+), 73 deletions(-) diff --git a/drivers/mtd/nand/raw/fsl_elbc_nand.c b/drivers/mtd/nand/raw/fsl_elbc_nand.c index 293a5b71833a..ffcc4241ddc6 100644 --- a/drivers/mtd/nand/raw/fsl_elbc_nand.c +++ b/drivers/mtd/nand/raw/fsl_elbc_nand.c @@ -635,79 +635,6 @@ static int fsl_elbc_wait(struct nand_chip *chip) return (elbc_fcm_ctrl->mdr & 0xff) | NAND_STATUS_WP; } -static int fsl_elbc_attach_chip(struct nand_chip *chip) -{ - struct mtd_info *mtd = nand_to_mtd(chip); - struct fsl_elbc_mtd *priv = nand_get_controller_data(chip); - struct fsl_lbc_ctrl *ctrl = priv->ctrl; - struct fsl_lbc_regs __iomem *lbc = ctrl->regs; - unsigned int al; - - /* calculate FMR Address Length field */ - al = 0; - if (chip->pagemask & 0xffff0000) - al++; - if (chip->pagemask & 0xff000000) - al++; - - priv->fmr |= al << FMR_AL_SHIFT; - - dev_dbg(priv->dev, "fsl_elbc_init: nand->numchips = %d\n", - nanddev_ntargets(&chip->base)); - dev_dbg(priv->dev, "fsl_elbc_init: nand->chipsize = %lld\n", - nanddev_target_size(&chip->base)); - dev_dbg(priv->dev, "fsl_elbc_init: nand->pagemask = %8x\n", - chip->pagemask); - dev_dbg(priv->dev, "fsl_elbc_init: nand->legacy.chip_delay = %d\n", - chip->legacy.chip_delay); - dev_dbg(priv->dev, "fsl_elbc_init: nand->badblockpos = %d\n", - chip->badblockpos); - dev_dbg(priv->dev, "fsl_elbc_init: nand->chip_shift = %d\n", - chip->chip_shift); - dev_dbg(priv->dev, "fsl_elbc_init: nand->page_shift = %d\n", - chip->page_shift); - dev_dbg(priv->dev, "fsl_elbc_init: nand->phys_erase_shift = %d\n", - chip->phys_erase_shift); - dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.mode = %d\n", - chip->ecc.mode); - dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.steps = %d\n", - chip->ecc.steps); - dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.bytes = %d\n", - chip->ecc.bytes); - dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.total = %d\n", - chip->ecc.total); - dev_dbg(priv->dev, "fsl_elbc_init: mtd->ooblayout = %p\n", - mtd->ooblayout); - dev_dbg(priv->dev, "fsl_elbc_init: mtd->flags = %08x\n", mtd->flags); - dev_dbg(priv->dev, "fsl_elbc_init: mtd->size = %lld\n", mtd->size); - dev_dbg(priv->dev, "fsl_elbc_init: mtd->erasesize = %d\n", - mtd->erasesize); - dev_dbg(priv->dev, "fsl_elbc_init: mtd->writesize = %d\n", - mtd->writesize); - dev_dbg(priv->dev, "fsl_elbc_init: mtd->oobsize = %d\n", - mtd->oobsize); - - /* adjust Option Register and ECC to match Flash page size */ - if (mtd->writesize == 512) { - priv->page_size = 0; - clrbits32(&lbc->bank[priv->bank].or, OR_FCM_PGS); - } else if (mtd->writesize == 2048) { - priv->page_size = 1; - setbits32(&lbc->bank[priv->bank].or, OR_FCM_PGS); - } else { - dev_err(priv->dev, - "fsl_elbc_init: page size %d is not supported\n", - mtd->writesize); - return -ENOTSUPP; - } - - return 0; -} - -static const struct nand_controller_ops fsl_elbc_controller_ops = { - .attach_chip = fsl_elbc_attach_chip, -}; - static int fsl_elbc_read_page(struct nand_chip *chip, uint8_t *buf, int oob_required, int page) { @@ -815,6 +742,79 @@ static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv) return 0; } +static int fsl_elbc_attach_chip(struct nand_chip *chip) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + struct fsl_elbc_mtd *priv = nand_get_controller_data(chip); + struct fsl_lbc_ctrl *ctrl = priv->ctrl; + struct fsl_lbc_regs __iomem *lbc = ctrl->regs; + unsigned int al; + + /* calculate FMR Address Length field */ + al = 0; + if (chip->pagemask & 0xffff0000) + al++; + if (chip->pagemask & 0xff000000) + al++; + + priv->fmr |= al << FMR_AL_SHIFT; + + dev_dbg(priv->dev, "fsl_elbc_init: nand->numchips = %d\n", + nanddev_ntargets(&chip->base)); + dev_dbg(priv->dev, "fsl_elbc_init: nand->chipsize = %lld\n", + nanddev_target_size(&chip->base)); + dev_dbg(priv->dev, "fsl_elbc_init: nand->pagemask = %8x\n", + chip->pagemask); + dev_dbg(priv->dev, "fsl_elbc_init: nand->legacy.chip_delay = %d\n", + chip->legacy.chip_delay); + dev_dbg(priv->dev, "fsl_elbc_init: nand->badblockpos = %d\n", + chip->badblockpos); + dev_dbg(priv->dev, "fsl_elbc_init: nand->chip_shift = %d\n", + chip->chip_shift); + dev_dbg(priv->dev, "fsl_elbc_init: nand->page_shift = %d\n", + chip->page_shift); + dev_dbg(priv->dev, "fsl_elbc_init: nand->phys_erase_shift = %d\n", + chip->phys_erase_shift); + dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.mode = %d\n", + chip->ecc.mode); + dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.steps = %d\n", + chip->ecc.steps); + dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.bytes = %d\n", + chip->ecc.bytes); + dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.total = %d\n", + chip->ecc.total); + dev_dbg(priv->dev, "fsl_elbc_init: mtd->ooblayout = %p\n", + mtd->ooblayout); + dev_dbg(priv->dev, "fsl_elbc_init: mtd->flags = %08x\n", mtd->flags); + dev_dbg(priv->dev, "fsl_elbc_init: mtd->size = %lld\n", mtd->size); + dev_dbg(priv->dev, "fsl_elbc_init: mtd->erasesize = %d\n", + mtd->erasesize); + dev_dbg(priv->dev, "fsl_elbc_init: mtd->writesize = %d\n", + mtd->writesize); + dev_dbg(priv->dev, "fsl_elbc_init: mtd->oobsize = %d\n", + mtd->oobsize); + + /* adjust Option Register and ECC to match Flash page size */ + if (mtd->writesize == 512) { + priv->page_size = 0; + clrbits32(&lbc->bank[priv->bank].or, OR_FCM_PGS); + } else if (mtd->writesize == 2048) { + priv->page_size = 1; + setbits32(&lbc->bank[priv->bank].or, OR_FCM_PGS); + } else { + dev_err(priv->dev, + "fsl_elbc_init: page size %d is not supported\n", + mtd->writesize); + return -ENOTSUPP; + } + + return 0; +} + +static const struct nand_controller_ops fsl_elbc_controller_ops = { + .attach_chip = fsl_elbc_attach_chip, +}; + static int fsl_elbc_chip_remove(struct fsl_elbc_mtd *priv) { struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand; -- cgit From 070fb9744d5b7f893da263149a4f3245bb618bdf Mon Sep 17 00:00:00 2001 From: Marek Behún Date: Fri, 22 Mar 2019 14:26:18 +0100 Subject: mtd: rawnand: fsl_elbc: Implement RNDOUT command MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is needed for SW ECC. Signed-off-by: Marek Behún Signed-off-by: Miquel Raynal --- drivers/mtd/nand/raw/fsl_elbc_nand.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/mtd/nand/raw/fsl_elbc_nand.c b/drivers/mtd/nand/raw/fsl_elbc_nand.c index ffcc4241ddc6..513897ce173e 100644 --- a/drivers/mtd/nand/raw/fsl_elbc_nand.c +++ b/drivers/mtd/nand/raw/fsl_elbc_nand.c @@ -355,6 +355,15 @@ static void fsl_elbc_cmdfunc(struct nand_chip *chip, unsigned int command, fsl_elbc_run_command(mtd); return; + /* RNDOUT moves the pointer inside the page */ + case NAND_CMD_RNDOUT: + dev_dbg(priv->dev, + "fsl_elbc_cmdfunc: NAND_CMD_RNDOUT, column: 0x%x.\n", + column); + + elbc_fcm_ctrl->index = column; + return; + /* READOOB reads only the OOB because no ECC is performed. */ case NAND_CMD_READOOB: dev_vdbg(priv->dev, -- cgit From f6424c22aa3673a0313a306be339495c67c41891 Mon Sep 17 00:00:00 2001 From: Marek Behún Date: Fri, 22 Mar 2019 14:26:19 +0100 Subject: mtd: rawnand: fsl_elbc: Make SW ECC work MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move the code that choses ECC into _attach_chip, which is executed only after the chip->ecc.* properties were loaded from device-tree. This way we know which ECC method was chosen by the device-tree and can set methods appropriately. The chip->ecc.*page methods should be set to fsl_elbc_*page only in HW ECC mode. Signed-off-by: Marek Behún Signed-off-by: Miquel Raynal --- drivers/mtd/nand/raw/fsl_elbc_nand.c | 52 +++++++++++++++++++++++------------- 1 file changed, 34 insertions(+), 18 deletions(-) diff --git a/drivers/mtd/nand/raw/fsl_elbc_nand.c b/drivers/mtd/nand/raw/fsl_elbc_nand.c index 513897ce173e..423828ff68e6 100644 --- a/drivers/mtd/nand/raw/fsl_elbc_nand.c +++ b/drivers/mtd/nand/raw/fsl_elbc_nand.c @@ -730,24 +730,6 @@ static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv) chip->controller = &elbc_fcm_ctrl->controller; nand_set_controller_data(chip, priv); - chip->ecc.read_page = fsl_elbc_read_page; - chip->ecc.write_page = fsl_elbc_write_page; - chip->ecc.write_subpage = fsl_elbc_write_subpage; - - /* If CS Base Register selects full hardware ECC then use it */ - if ((in_be32(&lbc->bank[priv->bank].br) & BR_DECC) == - BR_DECC_CHK_GEN) { - chip->ecc.mode = NAND_ECC_HW; - mtd_set_ooblayout(mtd, &fsl_elbc_ooblayout_ops); - chip->ecc.size = 512; - chip->ecc.bytes = 3; - chip->ecc.strength = 1; - } else { - /* otherwise fall back to default software ECC */ - chip->ecc.mode = NAND_ECC_SOFT; - chip->ecc.algo = NAND_ECC_HAMMING; - } - return 0; } @@ -759,6 +741,40 @@ static int fsl_elbc_attach_chip(struct nand_chip *chip) struct fsl_lbc_regs __iomem *lbc = ctrl->regs; unsigned int al; + switch (chip->ecc.mode) { + /* + * if ECC was not chosen in DT, decide whether to use HW or SW ECC from + * CS Base Register + */ + case NAND_ECC_NONE: + /* If CS Base Register selects full hardware ECC then use it */ + if ((in_be32(&lbc->bank[priv->bank].br) & BR_DECC) == + BR_DECC_CHK_GEN) { + chip->ecc.read_page = fsl_elbc_read_page; + chip->ecc.write_page = fsl_elbc_write_page; + chip->ecc.write_subpage = fsl_elbc_write_subpage; + + chip->ecc.mode = NAND_ECC_HW; + mtd_set_ooblayout(mtd, &fsl_elbc_ooblayout_ops); + chip->ecc.size = 512; + chip->ecc.bytes = 3; + chip->ecc.strength = 1; + } else { + /* otherwise fall back to default software ECC */ + chip->ecc.mode = NAND_ECC_SOFT; + chip->ecc.algo = NAND_ECC_HAMMING; + } + break; + + /* if SW ECC was chosen in DT, we do not need to set anything here */ + case NAND_ECC_SOFT: + break; + + /* should we also implement NAND_ECC_HW to do as the code above? */ + default: + return -EINVAL; + } + /* calculate FMR Address Length field */ al = 0; if (chip->pagemask & 0xffff0000) -- cgit From e39bb786816453788836c367caefd72eceea380c Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Mon, 1 Apr 2019 16:49:01 +0200 Subject: mtd: rawnand: atmel: Fix spelling mistake in error message Wrong copy/paste from the previous block, the error message should refer to #size-cells instead of #address-cells. Fixes: f88fc122cc34 ("mtd: nand: Cleanup/rework the atmel_nand driver") Signed-off-by: Miquel Raynal Reviewed-by: Tudor Ambarus --- drivers/mtd/nand/raw/atmel/nand-controller.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/nand/raw/atmel/nand-controller.c b/drivers/mtd/nand/raw/atmel/nand-controller.c index 80d14ba06245..8d6be90a6fe8 100644 --- a/drivers/mtd/nand/raw/atmel/nand-controller.c +++ b/drivers/mtd/nand/raw/atmel/nand-controller.c @@ -1808,7 +1808,7 @@ static int atmel_nand_controller_add_nands(struct atmel_nand_controller *nc) ret = of_property_read_u32(np, "#size-cells", &val); if (ret) { - dev_err(dev, "missing #address-cells property\n"); + dev_err(dev, "missing #size-cells property\n"); return ret; } -- cgit From 750f69b82641603700bf8bc1c70ef6d43bba5cab Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 2 Apr 2019 13:03:01 +0900 Subject: mtd: rawnand: denali: use more nand_chip pointers for internal functions With the recent refactoring, the NAND driver hooks now take a pointer to nand_chip. Add to_denali() in order to convert (struct nand_chip *) to (struct denali_nand_info *) directly. It is more useful than the current mtd_to_denali(). I changed some helper functions to take (struct nand_chip *). This will avoid pointer conversion back and forth, and ease further development. Signed-off-by: Masahiro Yamada Signed-off-by: Miquel Raynal --- drivers/mtd/nand/raw/denali.c | 61 ++++++++++++++++++++++++------------------- 1 file changed, 34 insertions(+), 27 deletions(-) diff --git a/drivers/mtd/nand/raw/denali.c b/drivers/mtd/nand/raw/denali.c index be1cc064bdb4..82a6666fd47b 100644 --- a/drivers/mtd/nand/raw/denali.c +++ b/drivers/mtd/nand/raw/denali.c @@ -47,6 +47,11 @@ static inline struct denali_nand_info *mtd_to_denali(struct mtd_info *mtd) return container_of(mtd_to_nand(mtd), struct denali_nand_info, nand); } +static struct denali_nand_info *to_denali(struct nand_chip *chip) +{ + return container_of(chip, struct denali_nand_info, nand); +} + /* * Direct Addressing - the slave address forms the control information (command * type, bank, block, and page address). The slave data is the actual data to @@ -282,12 +287,12 @@ static void denali_cmd_ctrl(struct nand_chip *chip, int dat, unsigned int ctrl) denali->host_write(denali, DENALI_BANK(denali) | type, dat); } -static int denali_check_erased_page(struct mtd_info *mtd, - struct nand_chip *chip, uint8_t *buf, +static int denali_check_erased_page(struct nand_chip *chip, u8 *buf, unsigned long uncor_ecc_flags, unsigned int max_bitflips) { - struct denali_nand_info *denali = mtd_to_denali(mtd); + struct denali_nand_info *denali = to_denali(chip); + struct mtd_ecc_stats *ecc_stats = &nand_to_mtd(chip)->ecc_stats; uint8_t *ecc_code = chip->oob_poi + denali->oob_skip_bytes; int ecc_steps = chip->ecc.steps; int ecc_size = chip->ecc.size; @@ -303,9 +308,9 @@ static int denali_check_erased_page(struct mtd_info *mtd, NULL, 0, chip->ecc.strength); if (stat < 0) { - mtd->ecc_stats.failed++; + ecc_stats->failed++; } else { - mtd->ecc_stats.corrected += stat; + ecc_stats->corrected += stat; max_bitflips = max_t(unsigned int, max_bitflips, stat); } @@ -316,11 +321,11 @@ static int denali_check_erased_page(struct mtd_info *mtd, return max_bitflips; } -static int denali_hw_ecc_fixup(struct mtd_info *mtd, - struct denali_nand_info *denali, +static int denali_hw_ecc_fixup(struct nand_chip *chip, unsigned long *uncor_ecc_flags) { - struct nand_chip *chip = mtd_to_nand(mtd); + struct denali_nand_info *denali = to_denali(chip); + struct mtd_ecc_stats *ecc_stats = &nand_to_mtd(chip)->ecc_stats; int bank = denali->active_bank; uint32_t ecc_cor; unsigned int max_bitflips; @@ -346,16 +351,17 @@ static int denali_hw_ecc_fixup(struct mtd_info *mtd, * Unfortunately, we can not know the total number of corrected bits in * the page. Increase the stats by max_bitflips. (compromised solution) */ - mtd->ecc_stats.corrected += max_bitflips; + ecc_stats->corrected += max_bitflips; return max_bitflips; } -static int denali_sw_ecc_fixup(struct mtd_info *mtd, - struct denali_nand_info *denali, +static int denali_sw_ecc_fixup(struct nand_chip *chip, unsigned long *uncor_ecc_flags, uint8_t *buf) { - unsigned int ecc_size = denali->nand.ecc.size; + struct denali_nand_info *denali = to_denali(chip); + struct mtd_ecc_stats *ecc_stats = &nand_to_mtd(chip)->ecc_stats; + unsigned int ecc_size = chip->ecc.size; unsigned int bitflips = 0; unsigned int max_bitflips = 0; uint32_t err_addr, err_cor_info; @@ -404,7 +410,7 @@ static int denali_sw_ecc_fixup(struct mtd_info *mtd, /* correct the ECC error */ flips_in_byte = hweight8(buf[offset] ^ err_cor_value); buf[offset] ^= err_cor_value; - mtd->ecc_stats.corrected += flips_in_byte; + ecc_stats->corrected += flips_in_byte; bitflips += flips_in_byte; max_bitflips = max(max_bitflips, bitflips); @@ -587,9 +593,11 @@ static int denali_dma_xfer(struct denali_nand_info *denali, void *buf, return ret; } -static int denali_data_xfer(struct denali_nand_info *denali, void *buf, - size_t size, int page, int raw, int write) +static int denali_data_xfer(struct nand_chip *chip, void *buf, size_t size, + int page, int raw, int write) { + struct denali_nand_info *denali = to_denali(chip); + iowrite32(raw ? 0 : ECC_ENABLE__FLAG, denali->reg + ECC_ENABLE); iowrite32(raw ? TRANSFER_SPARE_REG__FLAG : 0, denali->reg + TRANSFER_SPARE_REG); @@ -678,7 +686,7 @@ static int denali_read_page_raw(struct nand_chip *chip, uint8_t *buf, size_t size = writesize + oobsize; int ret, i, pos, len; - ret = denali_data_xfer(denali, tmp_buf, size, page, 1, 0); + ret = denali_data_xfer(chip, tmp_buf, size, page, 1, 0); if (ret) return ret; @@ -766,14 +774,14 @@ static int denali_read_page(struct nand_chip *chip, uint8_t *buf, int stat = 0; int ret; - ret = denali_data_xfer(denali, buf, mtd->writesize, page, 0, 0); + ret = denali_data_xfer(chip, buf, mtd->writesize, page, 0, 0); if (ret && ret != -EBADMSG) return ret; if (denali->caps & DENALI_CAP_HW_ECC_FIXUP) - stat = denali_hw_ecc_fixup(mtd, denali, &uncor_ecc_flags); + stat = denali_hw_ecc_fixup(chip, &uncor_ecc_flags); else if (ret == -EBADMSG) - stat = denali_sw_ecc_fixup(mtd, denali, &uncor_ecc_flags, buf); + stat = denali_sw_ecc_fixup(chip, &uncor_ecc_flags, buf); if (stat < 0) return stat; @@ -783,7 +791,7 @@ static int denali_read_page(struct nand_chip *chip, uint8_t *buf, if (ret) return ret; - stat = denali_check_erased_page(mtd, chip, buf, + stat = denali_check_erased_page(chip, buf, uncor_ecc_flags, stat); } @@ -866,17 +874,16 @@ static int denali_write_page_raw(struct nand_chip *chip, const uint8_t *buf, memcpy(tmp_buf + size - len, oob, len); } - return denali_data_xfer(denali, tmp_buf, size, page, 1, 1); + return denali_data_xfer(chip, tmp_buf, size, page, 1, 1); } static int denali_write_page(struct nand_chip *chip, const uint8_t *buf, int oob_required, int page) { struct mtd_info *mtd = nand_to_mtd(chip); - struct denali_nand_info *denali = mtd_to_denali(mtd); - return denali_data_xfer(denali, (void *)buf, mtd->writesize, - page, 0, 1); + return denali_data_xfer(chip, (void *)buf, mtd->writesize, page, + 0, 1); } static void denali_select_chip(struct nand_chip *chip, int cs) @@ -1092,9 +1099,9 @@ static const struct mtd_ooblayout_ops denali_ooblayout_ops = { .free = denali_ooblayout_free, }; -static int denali_multidev_fixup(struct denali_nand_info *denali) +static int denali_multidev_fixup(struct nand_chip *chip) { - struct nand_chip *chip = &denali->nand; + struct denali_nand_info *denali = to_denali(chip); struct mtd_info *mtd = nand_to_mtd(chip); struct nand_memory_organization *memorg; @@ -1226,7 +1233,7 @@ static int denali_attach_chip(struct nand_chip *chip) chip->ecc.read_oob = denali_read_oob; chip->ecc.write_oob = denali_write_oob; - ret = denali_multidev_fixup(denali); + ret = denali_multidev_fixup(chip); if (ret) return ret; -- cgit From 0e604fc9cffc7c4e3226280bcb35d9870581afc8 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 2 Apr 2019 13:03:02 +0900 Subject: mtd: rawnand: denali: refactor raw page accessors The Denali IP adopts the syndrome page layout (payload and ECC are interleaved). The *_page_raw() and *_oob() callbacks are complicated because they must hide the underlying layout used by the hardware, and always return contiguous in-band and out-of-band data. The Denali IP cannot reuse nand_{read,write}_page_raw_syndrome() in nand_base.c because its hardware ECC engine skips some of first bytes in OOB. That is why this driver implements specially-crafted *_page_raw() and *_oob() hooks. Currently, similar code is duplicated to reorganize the data layout. For example, denali_read_page_raw() and denali_write_page_raw() look almost the same. The complexity is partly due to the DMA transfer used for better performance of *_page_raw() accessors. On second thought, we do not need to care about their performance because MTD_OPS_RAW is rarely used. Let's focus on code cleanups rather than the performance. This commit removes the internal buffer for DMA, and factors out as much code as possible. Signed-off-by: Masahiro Yamada Signed-off-by: Miquel Raynal --- drivers/mtd/nand/raw/denali.c | 446 +++++++++++++++++------------------------- drivers/mtd/nand/raw/denali.h | 1 - 2 files changed, 182 insertions(+), 265 deletions(-) diff --git a/drivers/mtd/nand/raw/denali.c b/drivers/mtd/nand/raw/denali.c index 82a6666fd47b..3a3f79ce9a72 100644 --- a/drivers/mtd/nand/raw/denali.c +++ b/drivers/mtd/nand/raw/denali.c @@ -287,6 +287,182 @@ static void denali_cmd_ctrl(struct nand_chip *chip, int dat, unsigned int ctrl) denali->host_write(denali, DENALI_BANK(denali) | type, dat); } +static int denali_change_column(struct nand_chip *chip, unsigned int offset, + void *buf, unsigned int len, bool write) +{ + if (write) + return nand_change_write_column_op(chip, offset, buf, len, + false); + else + return nand_change_read_column_op(chip, offset, buf, len, + false); +} + +static int denali_payload_xfer(struct nand_chip *chip, void *buf, bool write) +{ + struct denali_nand_info *denali = to_denali(chip); + struct mtd_info *mtd = nand_to_mtd(chip); + struct nand_ecc_ctrl *ecc = &chip->ecc; + int writesize = mtd->writesize; + int oob_skip = denali->oob_skip_bytes; + int ret, i, pos, len; + + for (i = 0; i < ecc->steps; i++) { + pos = i * (ecc->size + ecc->bytes); + len = ecc->size; + + if (pos >= writesize) { + pos += oob_skip; + } else if (pos + len > writesize) { + /* This chunk overwraps the BBM area. Must be split */ + ret = denali_change_column(chip, pos, buf, + writesize - pos, write); + if (ret) + return ret; + + buf += writesize - pos; + len -= writesize - pos; + pos = writesize + oob_skip; + } + + ret = denali_change_column(chip, pos, buf, len, write); + if (ret) + return ret; + + buf += len; + } + + return 0; +} + +static int denali_oob_xfer(struct nand_chip *chip, void *buf, bool write) +{ + struct denali_nand_info *denali = to_denali(chip); + struct mtd_info *mtd = nand_to_mtd(chip); + struct nand_ecc_ctrl *ecc = &chip->ecc; + int writesize = mtd->writesize; + int oobsize = mtd->oobsize; + int oob_skip = denali->oob_skip_bytes; + int ret, i, pos, len; + + /* BBM at the beginning of the OOB area */ + ret = denali_change_column(chip, writesize, buf, oob_skip, write); + if (ret) + return ret; + + buf += oob_skip; + + for (i = 0; i < ecc->steps; i++) { + pos = ecc->size + i * (ecc->size + ecc->bytes); + + if (i == ecc->steps - 1) + /* The last chunk includes OOB free */ + len = writesize + oobsize - pos - oob_skip; + else + len = ecc->bytes; + + if (pos >= writesize) { + pos += oob_skip; + } else if (pos + len > writesize) { + /* This chunk overwraps the BBM area. Must be split */ + ret = denali_change_column(chip, pos, buf, + writesize - pos, write); + if (ret) + return ret; + + buf += writesize - pos; + len -= writesize - pos; + pos = writesize + oob_skip; + } + + ret = denali_change_column(chip, pos, buf, len, write); + if (ret) + return ret; + + buf += len; + } + + return 0; +} + +static int denali_read_raw(struct nand_chip *chip, void *buf, void *oob_buf, + int page) +{ + int ret; + + if (!buf && !oob_buf) + return -EINVAL; + + ret = nand_read_page_op(chip, page, 0, NULL, 0); + if (ret) + return ret; + + if (buf) { + ret = denali_payload_xfer(chip, buf, false); + if (ret) + return ret; + } + + if (oob_buf) { + ret = denali_oob_xfer(chip, oob_buf, false); + if (ret) + return ret; + } + + return 0; +} + +static int denali_write_raw(struct nand_chip *chip, const void *buf, + const void *oob_buf, int page) +{ + int ret; + + if (!buf && !oob_buf) + return -EINVAL; + + ret = nand_prog_page_begin_op(chip, page, 0, NULL, 0); + if (ret) + return ret; + + if (buf) { + ret = denali_payload_xfer(chip, (void *)buf, true); + if (ret) + return ret; + } + + if (oob_buf) { + ret = denali_oob_xfer(chip, (void *)oob_buf, true); + if (ret) + return ret; + } + + return nand_prog_page_end_op(chip); +} + +static int denali_read_page_raw(struct nand_chip *chip, u8 *buf, + int oob_required, int page) +{ + return denali_read_raw(chip, buf, oob_required ? chip->oob_poi : NULL, + page); +} + +static int denali_write_page_raw(struct nand_chip *chip, const u8 *buf, + int oob_required, int page) +{ + return denali_write_raw(chip, buf, oob_required ? chip->oob_poi : NULL, + page); +} + +static int denali_read_oob(struct nand_chip *chip, int page) +{ + return denali_read_raw(chip, NULL, chip->oob_poi, page); +} + +static int denali_write_oob(struct nand_chip *chip, int page) +{ + return denali_write_raw(chip, NULL, chip->oob_poi, page); +} + static int denali_check_erased_page(struct nand_chip *chip, u8 *buf, unsigned long uncor_ecc_flags, unsigned int max_bitflips) @@ -593,178 +769,17 @@ static int denali_dma_xfer(struct denali_nand_info *denali, void *buf, return ret; } -static int denali_data_xfer(struct nand_chip *chip, void *buf, size_t size, - int page, int raw, int write) +static int denali_page_xfer(struct nand_chip *chip, void *buf, size_t size, + int page, int write) { struct denali_nand_info *denali = to_denali(chip); - iowrite32(raw ? 0 : ECC_ENABLE__FLAG, denali->reg + ECC_ENABLE); - iowrite32(raw ? TRANSFER_SPARE_REG__FLAG : 0, - denali->reg + TRANSFER_SPARE_REG); - if (denali->dma_avail) return denali_dma_xfer(denali, buf, size, page, write); else return denali_pio_xfer(denali, buf, size, page, write); } -static void denali_oob_xfer(struct mtd_info *mtd, struct nand_chip *chip, - int page, int write) -{ - struct denali_nand_info *denali = mtd_to_denali(mtd); - int writesize = mtd->writesize; - int oobsize = mtd->oobsize; - uint8_t *bufpoi = chip->oob_poi; - int ecc_steps = chip->ecc.steps; - int ecc_size = chip->ecc.size; - int ecc_bytes = chip->ecc.bytes; - int oob_skip = denali->oob_skip_bytes; - size_t size = writesize + oobsize; - int i, pos, len; - - /* BBM at the beginning of the OOB area */ - if (write) - nand_prog_page_begin_op(chip, page, writesize, bufpoi, - oob_skip); - else - nand_read_page_op(chip, page, writesize, bufpoi, oob_skip); - bufpoi += oob_skip; - - /* OOB ECC */ - for (i = 0; i < ecc_steps; i++) { - pos = ecc_size + i * (ecc_size + ecc_bytes); - len = ecc_bytes; - - if (pos >= writesize) - pos += oob_skip; - else if (pos + len > writesize) - len = writesize - pos; - - if (write) - nand_change_write_column_op(chip, pos, bufpoi, len, - false); - else - nand_change_read_column_op(chip, pos, bufpoi, len, - false); - bufpoi += len; - if (len < ecc_bytes) { - len = ecc_bytes - len; - if (write) - nand_change_write_column_op(chip, writesize + - oob_skip, bufpoi, - len, false); - else - nand_change_read_column_op(chip, writesize + - oob_skip, bufpoi, - len, false); - bufpoi += len; - } - } - - /* OOB free */ - len = oobsize - (bufpoi - chip->oob_poi); - if (write) - nand_change_write_column_op(chip, size - len, bufpoi, len, - false); - else - nand_change_read_column_op(chip, size - len, bufpoi, len, - false); -} - -static int denali_read_page_raw(struct nand_chip *chip, uint8_t *buf, - int oob_required, int page) -{ - struct mtd_info *mtd = nand_to_mtd(chip); - struct denali_nand_info *denali = mtd_to_denali(mtd); - int writesize = mtd->writesize; - int oobsize = mtd->oobsize; - int ecc_steps = chip->ecc.steps; - int ecc_size = chip->ecc.size; - int ecc_bytes = chip->ecc.bytes; - void *tmp_buf = denali->buf; - int oob_skip = denali->oob_skip_bytes; - size_t size = writesize + oobsize; - int ret, i, pos, len; - - ret = denali_data_xfer(chip, tmp_buf, size, page, 1, 0); - if (ret) - return ret; - - /* Arrange the buffer for syndrome payload/ecc layout */ - if (buf) { - for (i = 0; i < ecc_steps; i++) { - pos = i * (ecc_size + ecc_bytes); - len = ecc_size; - - if (pos >= writesize) - pos += oob_skip; - else if (pos + len > writesize) - len = writesize - pos; - - memcpy(buf, tmp_buf + pos, len); - buf += len; - if (len < ecc_size) { - len = ecc_size - len; - memcpy(buf, tmp_buf + writesize + oob_skip, - len); - buf += len; - } - } - } - - if (oob_required) { - uint8_t *oob = chip->oob_poi; - - /* BBM at the beginning of the OOB area */ - memcpy(oob, tmp_buf + writesize, oob_skip); - oob += oob_skip; - - /* OOB ECC */ - for (i = 0; i < ecc_steps; i++) { - pos = ecc_size + i * (ecc_size + ecc_bytes); - len = ecc_bytes; - - if (pos >= writesize) - pos += oob_skip; - else if (pos + len > writesize) - len = writesize - pos; - - memcpy(oob, tmp_buf + pos, len); - oob += len; - if (len < ecc_bytes) { - len = ecc_bytes - len; - memcpy(oob, tmp_buf + writesize + oob_skip, - len); - oob += len; - } - } - - /* OOB free */ - len = oobsize - (oob - chip->oob_poi); - memcpy(oob, tmp_buf + size - len, len); - } - - return 0; -} - -static int denali_read_oob(struct nand_chip *chip, int page) -{ - struct mtd_info *mtd = nand_to_mtd(chip); - - denali_oob_xfer(mtd, chip, page, 0); - - return 0; -} - -static int denali_write_oob(struct nand_chip *chip, int page) -{ - struct mtd_info *mtd = nand_to_mtd(chip); - - denali_oob_xfer(mtd, chip, page, 1); - - return nand_prog_page_end_op(chip); -} - static int denali_read_page(struct nand_chip *chip, uint8_t *buf, int oob_required, int page) { @@ -774,7 +789,7 @@ static int denali_read_page(struct nand_chip *chip, uint8_t *buf, int stat = 0; int ret; - ret = denali_data_xfer(chip, buf, mtd->writesize, page, 0, 0); + ret = denali_page_xfer(chip, buf, mtd->writesize, page, 0); if (ret && ret != -EBADMSG) return ret; @@ -798,92 +813,12 @@ static int denali_read_page(struct nand_chip *chip, uint8_t *buf, return stat; } -static int denali_write_page_raw(struct nand_chip *chip, const uint8_t *buf, - int oob_required, int page) -{ - struct mtd_info *mtd = nand_to_mtd(chip); - struct denali_nand_info *denali = mtd_to_denali(mtd); - int writesize = mtd->writesize; - int oobsize = mtd->oobsize; - int ecc_steps = chip->ecc.steps; - int ecc_size = chip->ecc.size; - int ecc_bytes = chip->ecc.bytes; - void *tmp_buf = denali->buf; - int oob_skip = denali->oob_skip_bytes; - size_t size = writesize + oobsize; - int i, pos, len; - - /* - * Fill the buffer with 0xff first except the full page transfer. - * This simplifies the logic. - */ - if (!buf || !oob_required) - memset(tmp_buf, 0xff, size); - - /* Arrange the buffer for syndrome payload/ecc layout */ - if (buf) { - for (i = 0; i < ecc_steps; i++) { - pos = i * (ecc_size + ecc_bytes); - len = ecc_size; - - if (pos >= writesize) - pos += oob_skip; - else if (pos + len > writesize) - len = writesize - pos; - - memcpy(tmp_buf + pos, buf, len); - buf += len; - if (len < ecc_size) { - len = ecc_size - len; - memcpy(tmp_buf + writesize + oob_skip, buf, - len); - buf += len; - } - } - } - - if (oob_required) { - const uint8_t *oob = chip->oob_poi; - - /* BBM at the beginning of the OOB area */ - memcpy(tmp_buf + writesize, oob, oob_skip); - oob += oob_skip; - - /* OOB ECC */ - for (i = 0; i < ecc_steps; i++) { - pos = ecc_size + i * (ecc_size + ecc_bytes); - len = ecc_bytes; - - if (pos >= writesize) - pos += oob_skip; - else if (pos + len > writesize) - len = writesize - pos; - - memcpy(tmp_buf + pos, oob, len); - oob += len; - if (len < ecc_bytes) { - len = ecc_bytes - len; - memcpy(tmp_buf + writesize + oob_skip, oob, - len); - oob += len; - } - } - - /* OOB free */ - len = oobsize - (oob - chip->oob_poi); - memcpy(tmp_buf + size - len, oob, len); - } - - return denali_data_xfer(chip, tmp_buf, size, page, 1, 1); -} - static int denali_write_page(struct nand_chip *chip, const uint8_t *buf, int oob_required, int page) { struct mtd_info *mtd = nand_to_mtd(chip); - return denali_data_xfer(chip, (void *)buf, mtd->writesize, page, - 0, 1); + return denali_page_xfer(chip, (void *)buf, mtd->writesize, page, 1); } static void denali_select_chip(struct nand_chip *chip, int cs) @@ -1051,9 +986,10 @@ static void denali_hw_init(struct denali_nand_info *denali) } denali_detect_max_banks(denali); + iowrite32(0, denali->reg + TRANSFER_SPARE_REG); iowrite32(0x0F, denali->reg + RB_PIN_ENABLED); iowrite32(CHIP_EN_DONT_CARE__FLAG, denali->reg + CHIP_ENABLE_DONT_CARE); - + iowrite32(ECC_ENABLE__FLAG, denali->reg + ECC_ENABLE); iowrite32(0xffff, denali->reg + SPARE_AREA_MARKER); } @@ -1237,29 +1173,11 @@ static int denali_attach_chip(struct nand_chip *chip) if (ret) return ret; - /* - * This buffer is DMA-mapped by denali_{read,write}_page_raw. Do not - * use devm_kmalloc() because the memory allocated by devm_ does not - * guarantee DMA-safe alignment. - */ - denali->buf = kmalloc(mtd->writesize + mtd->oobsize, GFP_KERNEL); - if (!denali->buf) - return -ENOMEM; - return 0; } -static void denali_detach_chip(struct nand_chip *chip) -{ - struct mtd_info *mtd = nand_to_mtd(chip); - struct denali_nand_info *denali = mtd_to_denali(mtd); - - kfree(denali->buf); -} - static const struct nand_controller_ops denali_controller_ops = { .attach_chip = denali_attach_chip, - .detach_chip = denali_detach_chip, .setup_data_interface = denali_setup_data_interface, }; diff --git a/drivers/mtd/nand/raw/denali.h b/drivers/mtd/nand/raw/denali.h index c8c2620fc736..44471848647f 100644 --- a/drivers/mtd/nand/raw/denali.h +++ b/drivers/mtd/nand/raw/denali.h @@ -303,7 +303,6 @@ struct denali_nand_info { u32 irq_mask; /* interrupts we are waiting for */ u32 irq_status; /* interrupts that have happened */ int irq; - void *buf; /* for syndrome layout conversion */ int dma_avail; /* can support DMA? */ int devs_per_cs; /* devices connected in parallel */ int oob_skip_bytes; /* number of bytes reserved for BBM */ -- cgit From cf067b5be011dbc0eaf8679c743e0c1bc0b77745 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 2 Apr 2019 13:03:03 +0900 Subject: mtd: rawnand: denali: remove unneeded casts in denali_{read, write}_pio Since (u32 *) can accept an opaque pointer, the explicit casting from (void *) to (u32 *) is redundant. Change the function argument type to remove the casts. Signed-off-by: Masahiro Yamada Signed-off-by: Miquel Raynal --- drivers/mtd/nand/raw/denali.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/mtd/nand/raw/denali.c b/drivers/mtd/nand/raw/denali.c index 3a3f79ce9a72..47557380e6dd 100644 --- a/drivers/mtd/nand/raw/denali.c +++ b/drivers/mtd/nand/raw/denali.c @@ -654,11 +654,10 @@ static void denali_setup_dma32(struct denali_nand_info *denali, denali->host_write(denali, mode | 0x14000, 0x2400); } -static int denali_pio_read(struct denali_nand_info *denali, void *buf, +static int denali_pio_read(struct denali_nand_info *denali, u32 *buf, size_t size, int page) { u32 addr = DENALI_MAP01 | DENALI_BANK(denali) | page; - uint32_t *buf32 = (uint32_t *)buf; uint32_t irq_status, ecc_err_mask; int i; @@ -670,7 +669,7 @@ static int denali_pio_read(struct denali_nand_info *denali, void *buf, denali_reset_irq(denali); for (i = 0; i < size / 4; i++) - *buf32++ = denali->host_read(denali, addr); + buf[i] = denali->host_read(denali, addr); irq_status = denali_wait_for_irq(denali, INTR__PAGE_XFER_INC); if (!(irq_status & INTR__PAGE_XFER_INC)) @@ -682,18 +681,17 @@ static int denali_pio_read(struct denali_nand_info *denali, void *buf, return irq_status & ecc_err_mask ? -EBADMSG : 0; } -static int denali_pio_write(struct denali_nand_info *denali, - const void *buf, size_t size, int page) +static int denali_pio_write(struct denali_nand_info *denali, const u32 *buf, + size_t size, int page) { u32 addr = DENALI_MAP01 | DENALI_BANK(denali) | page; - const uint32_t *buf32 = (uint32_t *)buf; uint32_t irq_status; int i; denali_reset_irq(denali); for (i = 0; i < size / 4; i++) - denali->host_write(denali, addr, *buf32++); + denali->host_write(denali, addr, buf[i]); irq_status = denali_wait_for_irq(denali, INTR__PROGRAM_COMP | INTR__PROGRAM_FAIL); -- cgit From f55411427f1c649c598bf2cfc7653cfbe3f1e603 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 2 Apr 2019 13:03:04 +0900 Subject: mtd: rawnand: denali: switch over to ->exec_op() from legacy hooks Implement ->exec_op(), and remove the deprecated hooks. Signed-off-by: Masahiro Yamada Signed-off-by: Miquel Raynal --- drivers/mtd/nand/raw/denali.c | 251 ++++++++++++++++++++++++------------------ 1 file changed, 143 insertions(+), 108 deletions(-) diff --git a/drivers/mtd/nand/raw/denali.c b/drivers/mtd/nand/raw/denali.c index 47557380e6dd..2e7529ea4e5e 100644 --- a/drivers/mtd/nand/raw/denali.c +++ b/drivers/mtd/nand/raw/denali.c @@ -206,85 +206,11 @@ static uint32_t denali_wait_for_irq(struct denali_nand_info *denali, return denali->irq_status; } -static void denali_read_buf(struct nand_chip *chip, uint8_t *buf, int len) +static void denali_select_target(struct nand_chip *chip, int cs) { - struct mtd_info *mtd = nand_to_mtd(chip); - struct denali_nand_info *denali = mtd_to_denali(mtd); - u32 addr = DENALI_MAP11_DATA | DENALI_BANK(denali); - int i; - - for (i = 0; i < len; i++) - buf[i] = denali->host_read(denali, addr); -} - -static void denali_write_buf(struct nand_chip *chip, const uint8_t *buf, - int len) -{ - struct denali_nand_info *denali = mtd_to_denali(nand_to_mtd(chip)); - u32 addr = DENALI_MAP11_DATA | DENALI_BANK(denali); - int i; - - for (i = 0; i < len; i++) - denali->host_write(denali, addr, buf[i]); -} - -static void denali_read_buf16(struct nand_chip *chip, uint8_t *buf, int len) -{ - struct denali_nand_info *denali = mtd_to_denali(nand_to_mtd(chip)); - u32 addr = DENALI_MAP11_DATA | DENALI_BANK(denali); - uint16_t *buf16 = (uint16_t *)buf; - int i; - - for (i = 0; i < len / 2; i++) - buf16[i] = denali->host_read(denali, addr); -} - -static void denali_write_buf16(struct nand_chip *chip, const uint8_t *buf, - int len) -{ - struct denali_nand_info *denali = mtd_to_denali(nand_to_mtd(chip)); - u32 addr = DENALI_MAP11_DATA | DENALI_BANK(denali); - const uint16_t *buf16 = (const uint16_t *)buf; - int i; - - for (i = 0; i < len / 2; i++) - denali->host_write(denali, addr, buf16[i]); -} - -static uint8_t denali_read_byte(struct nand_chip *chip) -{ - uint8_t byte; - - denali_read_buf(chip, &byte, 1); - - return byte; -} - -static void denali_write_byte(struct nand_chip *chip, uint8_t byte) -{ - denali_write_buf(chip, &byte, 1); -} - -static void denali_cmd_ctrl(struct nand_chip *chip, int dat, unsigned int ctrl) -{ - struct denali_nand_info *denali = mtd_to_denali(nand_to_mtd(chip)); - uint32_t type; - - if (ctrl & NAND_CLE) - type = DENALI_MAP11_CMD; - else if (ctrl & NAND_ALE) - type = DENALI_MAP11_ADDR; - else - return; - - /* - * Some commands are followed by chip->legacy.waitfunc. - * irq_status must be cleared here to catch the R/B# interrupt later. - */ - if (ctrl & NAND_CTRL_CHANGE) - denali_reset_irq(denali); + struct denali_nand_info *denali = to_denali(chip); - denali->host_write(denali, DENALI_BANK(denali) | type, dat); + denali->active_bank = cs; } static int denali_change_column(struct nand_chip *chip, unsigned int offset, @@ -772,6 +698,8 @@ static int denali_page_xfer(struct nand_chip *chip, void *buf, size_t size, { struct denali_nand_info *denali = to_denali(chip); + denali_select_target(chip, chip->cur_cs); + if (denali->dma_avail) return denali_dma_xfer(denali, buf, size, page, write); else @@ -819,24 +747,6 @@ static int denali_write_page(struct nand_chip *chip, const uint8_t *buf, return denali_page_xfer(chip, (void *)buf, mtd->writesize, page, 1); } -static void denali_select_chip(struct nand_chip *chip, int cs) -{ - struct denali_nand_info *denali = mtd_to_denali(nand_to_mtd(chip)); - - denali->active_bank = cs; -} - -static int denali_waitfunc(struct nand_chip *chip) -{ - struct denali_nand_info *denali = mtd_to_denali(nand_to_mtd(chip)); - uint32_t irq_status; - - /* R/B# pin transitioned from low to high? */ - irq_status = denali_wait_for_irq(denali, INTR__INT_ACT); - - return irq_status & INTR__INT_ACT ? 0 : NAND_STATUS_FAIL; -} - static int denali_setup_data_interface(struct nand_chip *chip, int chipnr, const struct nand_data_interface *conf) { @@ -1153,13 +1063,6 @@ static int denali_attach_chip(struct nand_chip *chip) mtd_set_ooblayout(mtd, &denali_ooblayout_ops); - if (chip->options & NAND_BUSWIDTH_16) { - chip->legacy.read_buf = denali_read_buf16; - chip->legacy.write_buf = denali_write_buf16; - } else { - chip->legacy.read_buf = denali_read_buf; - chip->legacy.write_buf = denali_write_buf; - } chip->ecc.read_page = denali_read_page; chip->ecc.read_page_raw = denali_read_page_raw; chip->ecc.write_page = denali_write_page; @@ -1174,8 +1077,146 @@ static int denali_attach_chip(struct nand_chip *chip) return 0; } +static void denali_exec_in8(struct denali_nand_info *denali, u32 type, + u8 *buf, unsigned int len) +{ + int i; + + for (i = 0; i < len; i++) + buf[i] = denali->host_read(denali, type | DENALI_BANK(denali)); +} + +static void denali_exec_in16(struct denali_nand_info *denali, u32 type, + u8 *buf, unsigned int len) +{ + u32 data; + int i; + + for (i = 0; i < len; i += 2) { + data = denali->host_read(denali, type | DENALI_BANK(denali)); + /* bit 31:24 and 15:8 are used for DDR */ + buf[i] = data; + buf[i + 1] = data >> 16; + } +} + +static void denali_exec_in(struct denali_nand_info *denali, u32 type, + u8 *buf, unsigned int len, bool width16) +{ + if (width16) + denali_exec_in16(denali, type, buf, len); + else + denali_exec_in8(denali, type, buf, len); +} + +static void denali_exec_out8(struct denali_nand_info *denali, u32 type, + const u8 *buf, unsigned int len) +{ + int i; + + for (i = 0; i < len; i++) + denali->host_write(denali, type | DENALI_BANK(denali), buf[i]); +} + +static void denali_exec_out16(struct denali_nand_info *denali, u32 type, + const u8 *buf, unsigned int len) +{ + int i; + + for (i = 0; i < len; i += 2) + denali->host_write(denali, type | DENALI_BANK(denali), + buf[i + 1] << 16 | buf[i]); +} + +static void denali_exec_out(struct denali_nand_info *denali, u32 type, + const u8 *buf, unsigned int len, bool width16) +{ + if (width16) + denali_exec_out16(denali, type, buf, len); + else + denali_exec_out8(denali, type, buf, len); +} + +static int denali_exec_waitrdy(struct denali_nand_info *denali) +{ + u32 irq_stat; + + /* R/B# pin transitioned from low to high? */ + irq_stat = denali_wait_for_irq(denali, INTR__INT_ACT); + + /* Just in case nand_operation has multiple NAND_OP_WAITRDY_INSTR. */ + denali_reset_irq(denali); + + return irq_stat & INTR__INT_ACT ? 0 : -EIO; +} + +static int denali_exec_instr(struct nand_chip *chip, + const struct nand_op_instr *instr) +{ + struct denali_nand_info *denali = to_denali(chip); + + switch (instr->type) { + case NAND_OP_CMD_INSTR: + denali_exec_out8(denali, DENALI_MAP11_CMD, + &instr->ctx.cmd.opcode, 1); + return 0; + case NAND_OP_ADDR_INSTR: + denali_exec_out8(denali, DENALI_MAP11_ADDR, + instr->ctx.addr.addrs, + instr->ctx.addr.naddrs); + return 0; + case NAND_OP_DATA_IN_INSTR: + denali_exec_in(denali, DENALI_MAP11_DATA, + instr->ctx.data.buf.in, + instr->ctx.data.len, + !instr->ctx.data.force_8bit && + chip->options & NAND_BUSWIDTH_16); + return 0; + case NAND_OP_DATA_OUT_INSTR: + denali_exec_out(denali, DENALI_MAP11_DATA, + instr->ctx.data.buf.out, + instr->ctx.data.len, + !instr->ctx.data.force_8bit && + chip->options & NAND_BUSWIDTH_16); + return 0; + case NAND_OP_WAITRDY_INSTR: + return denali_exec_waitrdy(denali); + default: + WARN_ONCE(1, "unsupported NAND instruction type: %d\n", + instr->type); + + return -EINVAL; + } +} + +static int denali_exec_op(struct nand_chip *chip, + const struct nand_operation *op, bool check_only) +{ + int i, ret; + + if (check_only) + return 0; + + denali_select_target(chip, op->cs); + + /* + * Some commands contain NAND_OP_WAITRDY_INSTR. + * irq must be cleared here to catch the R/B# interrupt there. + */ + denali_reset_irq(to_denali(chip)); + + for (i = 0; i < op->ninstrs; i++) { + ret = denali_exec_instr(chip, &op->instrs[i]); + if (ret) + return ret; + } + + return 0; +} + static const struct nand_controller_ops denali_controller_ops = { .attach_chip = denali_attach_chip, + .exec_op = denali_exec_op, .setup_data_interface = denali_setup_data_interface, }; @@ -1210,12 +1251,6 @@ int denali_init(struct denali_nand_info *denali) if (!mtd->name) mtd->name = "denali-nand"; - chip->legacy.select_chip = denali_select_chip; - chip->legacy.read_byte = denali_read_byte; - chip->legacy.write_byte = denali_write_byte; - chip->legacy.cmd_ctrl = denali_cmd_ctrl; - chip->legacy.waitfunc = denali_waitfunc; - if (features & FEATURES__INDEX_ADDR) { denali->host_read = denali_indexed_read; denali->host_write = denali_indexed_write; -- cgit From f4f16fd3e7dcee033747b501f281238a65252c75 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 2 Apr 2019 13:03:05 +0900 Subject: mtd: rawnand: denali: use bool type instead of int where appropriate Use 'bool' type for the following boolean parameters. - write (write or read?) - dma_avail (DMA engine available or not?) Signed-off-by: Masahiro Yamada Signed-off-by: Miquel Raynal --- drivers/mtd/nand/raw/denali.c | 23 ++++++++++++----------- drivers/mtd/nand/raw/denali.h | 4 ++-- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/drivers/mtd/nand/raw/denali.c b/drivers/mtd/nand/raw/denali.c index 2e7529ea4e5e..da3fcbaec0e2 100644 --- a/drivers/mtd/nand/raw/denali.c +++ b/drivers/mtd/nand/raw/denali.c @@ -533,7 +533,7 @@ static int denali_sw_ecc_fixup(struct nand_chip *chip, } static void denali_setup_dma64(struct denali_nand_info *denali, - dma_addr_t dma_addr, int page, int write) + dma_addr_t dma_addr, int page, bool write) { uint32_t mode; const int page_count = 1; @@ -547,7 +547,8 @@ static void denali_setup_dma64(struct denali_nand_info *denali, * burst len = 64 bytes, the number of pages */ denali->host_write(denali, mode, - 0x01002000 | (64 << 16) | (write << 8) | page_count); + 0x01002000 | (64 << 16) | + (write ? BIT(8) : 0) | page_count); /* 2. set memory low address */ denali->host_write(denali, mode, lower_32_bits(dma_addr)); @@ -557,7 +558,7 @@ static void denali_setup_dma64(struct denali_nand_info *denali, } static void denali_setup_dma32(struct denali_nand_info *denali, - dma_addr_t dma_addr, int page, int write) + dma_addr_t dma_addr, int page, bool write) { uint32_t mode; const int page_count = 1; @@ -568,7 +569,7 @@ static void denali_setup_dma32(struct denali_nand_info *denali, /* 1. setup transfer type and # of pages */ denali->host_write(denali, mode | page, - 0x2000 | (write << 8) | page_count); + 0x2000 | (write ? BIT(8) : 0) | page_count); /* 2. set memory high address bits 23:8 */ denali->host_write(denali, mode | ((dma_addr >> 16) << 8), 0x2200); @@ -628,7 +629,7 @@ static int denali_pio_write(struct denali_nand_info *denali, const u32 *buf, } static int denali_pio_xfer(struct denali_nand_info *denali, void *buf, - size_t size, int page, int write) + size_t size, int page, bool write) { if (write) return denali_pio_write(denali, buf, size, page); @@ -637,7 +638,7 @@ static int denali_pio_xfer(struct denali_nand_info *denali, void *buf, } static int denali_dma_xfer(struct denali_nand_info *denali, void *buf, - size_t size, int page, int write) + size_t size, int page, bool write) { dma_addr_t dma_addr; uint32_t irq_mask, irq_status, ecc_err_mask; @@ -694,7 +695,7 @@ static int denali_dma_xfer(struct denali_nand_info *denali, void *buf, } static int denali_page_xfer(struct nand_chip *chip, void *buf, size_t size, - int page, int write) + int page, bool write) { struct denali_nand_info *denali = to_denali(chip); @@ -715,7 +716,7 @@ static int denali_read_page(struct nand_chip *chip, uint8_t *buf, int stat = 0; int ret; - ret = denali_page_xfer(chip, buf, mtd->writesize, page, 0); + ret = denali_page_xfer(chip, buf, mtd->writesize, page, false); if (ret && ret != -EBADMSG) return ret; @@ -744,7 +745,7 @@ static int denali_write_page(struct nand_chip *chip, const uint8_t *buf, { struct mtd_info *mtd = nand_to_mtd(chip); - return denali_page_xfer(chip, (void *)buf, mtd->writesize, page, 1); + return denali_page_xfer(chip, (void *)buf, mtd->writesize, page, true); } static int denali_setup_data_interface(struct nand_chip *chip, int chipnr, @@ -1005,7 +1006,7 @@ static int denali_attach_chip(struct nand_chip *chip) int ret; if (ioread32(denali->reg + FEATURES) & FEATURES__DMA) - denali->dma_avail = 1; + denali->dma_avail = true; if (denali->dma_avail) { int dma_bit = denali->caps & DENALI_CAP_DMA_64BIT ? 64 : 32; @@ -1014,7 +1015,7 @@ static int denali_attach_chip(struct nand_chip *chip) if (ret) { dev_info(denali->dev, "Failed to set DMA mask. Disabling DMA.\n"); - denali->dma_avail = 0; + denali->dma_avail = false; } } diff --git a/drivers/mtd/nand/raw/denali.h b/drivers/mtd/nand/raw/denali.h index 44471848647f..d2603c67dd20 100644 --- a/drivers/mtd/nand/raw/denali.h +++ b/drivers/mtd/nand/raw/denali.h @@ -303,7 +303,7 @@ struct denali_nand_info { u32 irq_mask; /* interrupts we are waiting for */ u32 irq_status; /* interrupts that have happened */ int irq; - int dma_avail; /* can support DMA? */ + bool dma_avail; /* can support DMA? */ int devs_per_cs; /* devices connected in parallel */ int oob_skip_bytes; /* number of bytes reserved for BBM */ int max_banks; @@ -313,7 +313,7 @@ struct denali_nand_info { u32 (*host_read)(struct denali_nand_info *denali, u32 addr); void (*host_write)(struct denali_nand_info *denali, u32 addr, u32 data); void (*setup_dma)(struct denali_nand_info *denali, dma_addr_t dma_addr, - int page, int write); + int page, bool write); }; #define DENALI_CAP_HW_ECC_FIXUP BIT(0) -- cgit From 13defd47349edaf894d2b13600220ff2b57c4baf Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 2 Apr 2019 13:03:06 +0900 Subject: mtd: rawnand: denali_pci: rename goto labels As Documentation/process/coding-style.rst says, choose label names which say what the goto does. The out_ label style is already used in denali_dt.c. Rename likewise for denali_pci.c Signed-off-by: Masahiro Yamada Signed-off-by: Miquel Raynal --- drivers/mtd/nand/raw/denali_pci.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/mtd/nand/raw/denali_pci.c b/drivers/mtd/nand/raw/denali_pci.c index 48e9ac54ad53..02eb5990a91e 100644 --- a/drivers/mtd/nand/raw/denali_pci.c +++ b/drivers/mtd/nand/raw/denali_pci.c @@ -84,20 +84,20 @@ static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) if (!denali->host) { dev_err(&dev->dev, "Spectra: ioremap_nocache failed!"); ret = -ENOMEM; - goto failed_remap_reg; + goto out_unmap_reg; } ret = denali_init(denali); if (ret) - goto failed_remap_mem; + goto out_unmap_host; pci_set_drvdata(dev, denali); return 0; -failed_remap_mem: +out_unmap_host: iounmap(denali->host); -failed_remap_reg: +out_unmap_reg: iounmap(denali->reg); return ret; } -- cgit From d8e8fd0ebf8b1b8d26a160c2363479a88c1f72c2 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 2 Apr 2019 13:03:07 +0900 Subject: mtd: rawnand: denali: decouple controller and NAND chips Currently, this driver sticks to the legacy NAND model because it was upstreamed before commit 2d472aba15ff ("mtd: nand: document the NAND controller/NAND chip DT representation"). However, relying on the dummy_controller is already deprecated. Switch over to the new controller/chip representation. The struct denali_nand_info has been split into denali_controller and denali_chip, to contain the controller data, per-chip data, respectively. One problem is, this commit changes the DT binding. So, as always, the backward compatibility must be taken into consideration. In the new binding, the controller node expects #address-cells = <1>; #size-cells = <0>; ... since the child nodes represent NAND chips. In the old binding, the controller node may have subnodes, but they are MTD partitions. The denali_dt_is_legacy_binding() exploits it to distinguish old/new platforms. Going forward, the old binding is only allowed for existing DT files. I updated the binding document. Signed-off-by: Masahiro Yamada Acked-by: Rob Herring Signed-off-by: Miquel Raynal --- .../devicetree/bindings/mtd/denali-nand.txt | 40 +- drivers/mtd/nand/raw/denali.c | 430 ++++++++++++--------- drivers/mtd/nand/raw/denali.h | 114 +++++- drivers/mtd/nand/raw/denali_dt.c | 98 ++++- drivers/mtd/nand/raw/denali_pci.c | 30 +- 5 files changed, 482 insertions(+), 230 deletions(-) diff --git a/Documentation/devicetree/bindings/mtd/denali-nand.txt b/Documentation/devicetree/bindings/mtd/denali-nand.txt index f33da8782741..b14b6751c2f3 100644 --- a/Documentation/devicetree/bindings/mtd/denali-nand.txt +++ b/Documentation/devicetree/bindings/mtd/denali-nand.txt @@ -7,34 +7,48 @@ Required properties: "socionext,uniphier-denali-nand-v5b" - for Socionext UniPhier (v5b) - reg : should contain registers location and length for data and reg. - reg-names: Should contain the reg names "nand_data" and "denali_reg" + - #address-cells: should be 1. The cell encodes the chip select connection. + - #size-cells : should be 0. - interrupts : The interrupt number. - clocks: should contain phandle of the controller core clock, the bus interface clock, and the ECC circuit clock. - clock-names: should contain "nand", "nand_x", "ecc" -Optional properties: - - nand-ecc-step-size: see nand.txt for details. If present, the value must be - 512 for "altr,socfpga-denali-nand" - 1024 for "socionext,uniphier-denali-nand-v5a" - 1024 for "socionext,uniphier-denali-nand-v5b" - - nand-ecc-strength: see nand.txt for details. Valid values are: - 8, 15 for "altr,socfpga-denali-nand" - 8, 16, 24 for "socionext,uniphier-denali-nand-v5a" - 8, 16 for "socionext,uniphier-denali-nand-v5b" - - nand-ecc-maximize: see nand.txt for details - -The device tree may optionally contain sub-nodes describing partitions of the +Sub-nodes: + Sub-nodes represent available NAND chips. + + Required properties: + - reg: should contain the bank ID of the controller to which each chip + select is connected. + + Optional properties: + - nand-ecc-step-size: see nand.txt for details. + If present, the value must be + 512 for "altr,socfpga-denali-nand" + 1024 for "socionext,uniphier-denali-nand-v5a" + 1024 for "socionext,uniphier-denali-nand-v5b" + - nand-ecc-strength: see nand.txt for details. Valid values are: + 8, 15 for "altr,socfpga-denali-nand" + 8, 16, 24 for "socionext,uniphier-denali-nand-v5a" + 8, 16 for "socionext,uniphier-denali-nand-v5b" + - nand-ecc-maximize: see nand.txt for details + +The chip nodes may optionally contain sub-nodes describing partitions of the address space. See partition.txt for more detail. Examples: nand: nand@ff900000 { #address-cells = <1>; - #size-cells = <1>; + #size-cells = <0>; compatible = "altr,socfpga-denali-nand"; reg = <0xff900000 0x20>, <0xffb80000 0x1000>; reg-names = "nand_data", "denali_reg"; clocks = <&nand_clk>, <&nand_x_clk>, <&nand_ecc_clk>; clock-names = "nand", "nand_x", "ecc"; interrupts = <0 144 4>; + + nand@0 { + reg = <0>; + } }; diff --git a/drivers/mtd/nand/raw/denali.c b/drivers/mtd/nand/raw/denali.c index da3fcbaec0e2..d8c10444e284 100644 --- a/drivers/mtd/nand/raw/denali.c +++ b/drivers/mtd/nand/raw/denali.c @@ -3,7 +3,7 @@ * NAND Flash Controller Device Driver * Copyright © 2009-2010, Intel Corporation and its suppliers. * - * Copyright (c) 2017 Socionext Inc. + * Copyright (c) 2017-2019 Socionext Inc. * Reworked by Masahiro Yamada */ @@ -42,14 +42,15 @@ #define DENALI_INVALID_BANK -1 #define DENALI_NR_BANKS 4 -static inline struct denali_nand_info *mtd_to_denali(struct mtd_info *mtd) +static struct denali_chip *to_denali_chip(struct nand_chip *chip) { - return container_of(mtd_to_nand(mtd), struct denali_nand_info, nand); + return container_of(chip, struct denali_chip, chip); } -static struct denali_nand_info *to_denali(struct nand_chip *chip) +static struct denali_controller *to_denali_controller(struct nand_chip *chip) { - return container_of(chip, struct denali_nand_info, nand); + return container_of(chip->controller, struct denali_controller, + controller); } /* @@ -57,12 +58,12 @@ static struct denali_nand_info *to_denali(struct nand_chip *chip) * type, bank, block, and page address). The slave data is the actual data to * be transferred. This mode requires 28 bits of address region allocated. */ -static u32 denali_direct_read(struct denali_nand_info *denali, u32 addr) +static u32 denali_direct_read(struct denali_controller *denali, u32 addr) { return ioread32(denali->host + addr); } -static void denali_direct_write(struct denali_nand_info *denali, u32 addr, +static void denali_direct_write(struct denali_controller *denali, u32 addr, u32 data) { iowrite32(data, denali->host + addr); @@ -74,35 +75,20 @@ static void denali_direct_write(struct denali_nand_info *denali, u32 addr, * control information and transferred data are latched by the registers in * the translation module. */ -static u32 denali_indexed_read(struct denali_nand_info *denali, u32 addr) +static u32 denali_indexed_read(struct denali_controller *denali, u32 addr) { iowrite32(addr, denali->host + DENALI_INDEXED_CTRL); return ioread32(denali->host + DENALI_INDEXED_DATA); } -static void denali_indexed_write(struct denali_nand_info *denali, u32 addr, +static void denali_indexed_write(struct denali_controller *denali, u32 addr, u32 data) { iowrite32(addr, denali->host + DENALI_INDEXED_CTRL); iowrite32(data, denali->host + DENALI_INDEXED_DATA); } -/* - * Use the configuration feature register to determine the maximum number of - * banks that the hardware supports. - */ -static void denali_detect_max_banks(struct denali_nand_info *denali) -{ - uint32_t features = ioread32(denali->reg + FEATURES); - - denali->max_banks = 1 << FIELD_GET(FEATURES__N_BANKS, features); - - /* the encoding changed from rev 5.0 to 5.1 */ - if (denali->revision < 0x0501) - denali->max_banks <<= 1; -} - -static void denali_enable_irq(struct denali_nand_info *denali) +static void denali_enable_irq(struct denali_controller *denali) { int i; @@ -111,7 +97,7 @@ static void denali_enable_irq(struct denali_nand_info *denali) iowrite32(GLOBAL_INT_EN_FLAG, denali->reg + GLOBAL_INT_ENABLE); } -static void denali_disable_irq(struct denali_nand_info *denali) +static void denali_disable_irq(struct denali_controller *denali) { int i; @@ -120,14 +106,14 @@ static void denali_disable_irq(struct denali_nand_info *denali) iowrite32(0, denali->reg + GLOBAL_INT_ENABLE); } -static void denali_clear_irq(struct denali_nand_info *denali, +static void denali_clear_irq(struct denali_controller *denali, int bank, uint32_t irq_status) { /* write one to clear bits */ iowrite32(irq_status, denali->reg + INTR_STATUS(bank)); } -static void denali_clear_irq_all(struct denali_nand_info *denali) +static void denali_clear_irq_all(struct denali_controller *denali) { int i; @@ -137,7 +123,7 @@ static void denali_clear_irq_all(struct denali_nand_info *denali) static irqreturn_t denali_isr(int irq, void *dev_id) { - struct denali_nand_info *denali = dev_id; + struct denali_controller *denali = dev_id; irqreturn_t ret = IRQ_NONE; uint32_t irq_status; int i; @@ -165,7 +151,7 @@ static irqreturn_t denali_isr(int irq, void *dev_id) return ret; } -static void denali_reset_irq(struct denali_nand_info *denali) +static void denali_reset_irq(struct denali_controller *denali) { unsigned long flags; @@ -175,8 +161,7 @@ static void denali_reset_irq(struct denali_nand_info *denali) spin_unlock_irqrestore(&denali->irq_lock, flags); } -static uint32_t denali_wait_for_irq(struct denali_nand_info *denali, - uint32_t irq_mask) +static u32 denali_wait_for_irq(struct denali_controller *denali, u32 irq_mask) { unsigned long time_left, flags; uint32_t irq_status; @@ -208,9 +193,41 @@ static uint32_t denali_wait_for_irq(struct denali_nand_info *denali, static void denali_select_target(struct nand_chip *chip, int cs) { - struct denali_nand_info *denali = to_denali(chip); + struct denali_controller *denali = to_denali_controller(chip); + struct denali_chip_sel *sel = &to_denali_chip(chip)->sels[cs]; + struct mtd_info *mtd = nand_to_mtd(chip); + + denali->active_bank = sel->bank; - denali->active_bank = cs; + iowrite32(1 << (chip->phys_erase_shift - chip->page_shift), + denali->reg + PAGES_PER_BLOCK); + iowrite32(chip->options & NAND_BUSWIDTH_16 ? 1 : 0, + denali->reg + DEVICE_WIDTH); + iowrite32(mtd->writesize, denali->reg + DEVICE_MAIN_AREA_SIZE); + iowrite32(mtd->oobsize, denali->reg + DEVICE_SPARE_AREA_SIZE); + iowrite32(chip->options & NAND_ROW_ADDR_3 ? + 0 : TWO_ROW_ADDR_CYCLES__FLAG, + denali->reg + TWO_ROW_ADDR_CYCLES); + iowrite32(FIELD_PREP(ECC_CORRECTION__ERASE_THRESHOLD, 1) | + FIELD_PREP(ECC_CORRECTION__VALUE, chip->ecc.strength), + denali->reg + ECC_CORRECTION); + iowrite32(chip->ecc.size, denali->reg + CFG_DATA_BLOCK_SIZE); + iowrite32(chip->ecc.size, denali->reg + CFG_LAST_DATA_BLOCK_SIZE); + iowrite32(chip->ecc.steps, denali->reg + CFG_NUM_DATA_BLOCKS); + + if (chip->options & NAND_KEEP_TIMINGS) + return; + + /* update timing registers unless NAND_KEEP_TIMINGS is set */ + iowrite32(sel->hwhr2_and_we_2_re, denali->reg + TWHR2_AND_WE_2_RE); + iowrite32(sel->tcwaw_and_addr_2_data, + denali->reg + TCWAW_AND_ADDR_2_DATA); + iowrite32(sel->re_2_we, denali->reg + RE_2_WE); + iowrite32(sel->acc_clks, denali->reg + ACC_CLKS); + iowrite32(sel->rdwr_en_lo_cnt, denali->reg + RDWR_EN_LO_CNT); + iowrite32(sel->rdwr_en_hi_cnt, denali->reg + RDWR_EN_HI_CNT); + iowrite32(sel->cs_setup_cnt, denali->reg + CS_SETUP_CNT); + iowrite32(sel->re_2_re, denali->reg + RE_2_RE); } static int denali_change_column(struct nand_chip *chip, unsigned int offset, @@ -226,7 +243,7 @@ static int denali_change_column(struct nand_chip *chip, unsigned int offset, static int denali_payload_xfer(struct nand_chip *chip, void *buf, bool write) { - struct denali_nand_info *denali = to_denali(chip); + struct denali_controller *denali = to_denali_controller(chip); struct mtd_info *mtd = nand_to_mtd(chip); struct nand_ecc_ctrl *ecc = &chip->ecc; int writesize = mtd->writesize; @@ -263,7 +280,7 @@ static int denali_payload_xfer(struct nand_chip *chip, void *buf, bool write) static int denali_oob_xfer(struct nand_chip *chip, void *buf, bool write) { - struct denali_nand_info *denali = to_denali(chip); + struct denali_controller *denali = to_denali_controller(chip); struct mtd_info *mtd = nand_to_mtd(chip); struct nand_ecc_ctrl *ecc = &chip->ecc; int writesize = mtd->writesize; @@ -393,7 +410,7 @@ static int denali_check_erased_page(struct nand_chip *chip, u8 *buf, unsigned long uncor_ecc_flags, unsigned int max_bitflips) { - struct denali_nand_info *denali = to_denali(chip); + struct denali_controller *denali = to_denali_controller(chip); struct mtd_ecc_stats *ecc_stats = &nand_to_mtd(chip)->ecc_stats; uint8_t *ecc_code = chip->oob_poi + denali->oob_skip_bytes; int ecc_steps = chip->ecc.steps; @@ -426,7 +443,7 @@ static int denali_check_erased_page(struct nand_chip *chip, u8 *buf, static int denali_hw_ecc_fixup(struct nand_chip *chip, unsigned long *uncor_ecc_flags) { - struct denali_nand_info *denali = to_denali(chip); + struct denali_controller *denali = to_denali_controller(chip); struct mtd_ecc_stats *ecc_stats = &nand_to_mtd(chip)->ecc_stats; int bank = denali->active_bank; uint32_t ecc_cor; @@ -461,7 +478,7 @@ static int denali_hw_ecc_fixup(struct nand_chip *chip, static int denali_sw_ecc_fixup(struct nand_chip *chip, unsigned long *uncor_ecc_flags, uint8_t *buf) { - struct denali_nand_info *denali = to_denali(chip); + struct denali_controller *denali = to_denali_controller(chip); struct mtd_ecc_stats *ecc_stats = &nand_to_mtd(chip)->ecc_stats; unsigned int ecc_size = chip->ecc.size; unsigned int bitflips = 0; @@ -532,7 +549,7 @@ static int denali_sw_ecc_fixup(struct nand_chip *chip, return max_bitflips; } -static void denali_setup_dma64(struct denali_nand_info *denali, +static void denali_setup_dma64(struct denali_controller *denali, dma_addr_t dma_addr, int page, bool write) { uint32_t mode; @@ -557,7 +574,7 @@ static void denali_setup_dma64(struct denali_nand_info *denali, denali->host_write(denali, mode, upper_32_bits(dma_addr)); } -static void denali_setup_dma32(struct denali_nand_info *denali, +static void denali_setup_dma32(struct denali_controller *denali, dma_addr_t dma_addr, int page, bool write) { uint32_t mode; @@ -581,7 +598,7 @@ static void denali_setup_dma32(struct denali_nand_info *denali, denali->host_write(denali, mode | 0x14000, 0x2400); } -static int denali_pio_read(struct denali_nand_info *denali, u32 *buf, +static int denali_pio_read(struct denali_controller *denali, u32 *buf, size_t size, int page) { u32 addr = DENALI_MAP01 | DENALI_BANK(denali) | page; @@ -608,7 +625,7 @@ static int denali_pio_read(struct denali_nand_info *denali, u32 *buf, return irq_status & ecc_err_mask ? -EBADMSG : 0; } -static int denali_pio_write(struct denali_nand_info *denali, const u32 *buf, +static int denali_pio_write(struct denali_controller *denali, const u32 *buf, size_t size, int page) { u32 addr = DENALI_MAP01 | DENALI_BANK(denali) | page; @@ -628,7 +645,7 @@ static int denali_pio_write(struct denali_nand_info *denali, const u32 *buf, return 0; } -static int denali_pio_xfer(struct denali_nand_info *denali, void *buf, +static int denali_pio_xfer(struct denali_controller *denali, void *buf, size_t size, int page, bool write) { if (write) @@ -637,7 +654,7 @@ static int denali_pio_xfer(struct denali_nand_info *denali, void *buf, return denali_pio_read(denali, buf, size, page); } -static int denali_dma_xfer(struct denali_nand_info *denali, void *buf, +static int denali_dma_xfer(struct denali_controller *denali, void *buf, size_t size, int page, bool write) { dma_addr_t dma_addr; @@ -697,7 +714,7 @@ static int denali_dma_xfer(struct denali_nand_info *denali, void *buf, static int denali_page_xfer(struct nand_chip *chip, void *buf, size_t size, int page, bool write) { - struct denali_nand_info *denali = to_denali(chip); + struct denali_controller *denali = to_denali_controller(chip); denali_select_target(chip, chip->cur_cs); @@ -710,8 +727,8 @@ static int denali_page_xfer(struct nand_chip *chip, void *buf, size_t size, static int denali_read_page(struct nand_chip *chip, uint8_t *buf, int oob_required, int page) { + struct denali_controller *denali = to_denali_controller(chip); struct mtd_info *mtd = nand_to_mtd(chip); - struct denali_nand_info *denali = mtd_to_denali(mtd); unsigned long uncor_ecc_flags = 0; int stat = 0; int ret; @@ -751,7 +768,8 @@ static int denali_write_page(struct nand_chip *chip, const uint8_t *buf, static int denali_setup_data_interface(struct nand_chip *chip, int chipnr, const struct nand_data_interface *conf) { - struct denali_nand_info *denali = mtd_to_denali(nand_to_mtd(chip)); + struct denali_controller *denali = to_denali_controller(chip); + struct denali_chip_sel *sel; const struct nand_sdr_timings *timings; unsigned long t_x, mult_x; int acc_clks, re_2_we, re_2_re, we_2_re, addr_2_data; @@ -780,6 +798,8 @@ static int denali_setup_data_interface(struct nand_chip *chip, int chipnr, if (chipnr == NAND_DATA_IFACE_CHECK_ONLY) return 0; + sel = &to_denali_chip(chip)->sels[chipnr]; + /* tREA -> ACC_CLKS */ acc_clks = DIV_ROUND_UP(timings->tREA_max, t_x); acc_clks = min_t(int, acc_clks, ACC_CLKS__VALUE); @@ -787,7 +807,7 @@ static int denali_setup_data_interface(struct nand_chip *chip, int chipnr, tmp = ioread32(denali->reg + ACC_CLKS); tmp &= ~ACC_CLKS__VALUE; tmp |= FIELD_PREP(ACC_CLKS__VALUE, acc_clks); - iowrite32(tmp, denali->reg + ACC_CLKS); + sel->acc_clks = tmp; /* tRWH -> RE_2_WE */ re_2_we = DIV_ROUND_UP(timings->tRHW_min, t_x); @@ -796,7 +816,7 @@ static int denali_setup_data_interface(struct nand_chip *chip, int chipnr, tmp = ioread32(denali->reg + RE_2_WE); tmp &= ~RE_2_WE__VALUE; tmp |= FIELD_PREP(RE_2_WE__VALUE, re_2_we); - iowrite32(tmp, denali->reg + RE_2_WE); + sel->re_2_we = tmp; /* tRHZ -> RE_2_RE */ re_2_re = DIV_ROUND_UP(timings->tRHZ_max, t_x); @@ -805,7 +825,7 @@ static int denali_setup_data_interface(struct nand_chip *chip, int chipnr, tmp = ioread32(denali->reg + RE_2_RE); tmp &= ~RE_2_RE__VALUE; tmp |= FIELD_PREP(RE_2_RE__VALUE, re_2_re); - iowrite32(tmp, denali->reg + RE_2_RE); + sel->re_2_re = tmp; /* * tCCS, tWHR -> WE_2_RE @@ -819,7 +839,7 @@ static int denali_setup_data_interface(struct nand_chip *chip, int chipnr, tmp = ioread32(denali->reg + TWHR2_AND_WE_2_RE); tmp &= ~TWHR2_AND_WE_2_RE__WE_2_RE; tmp |= FIELD_PREP(TWHR2_AND_WE_2_RE__WE_2_RE, we_2_re); - iowrite32(tmp, denali->reg + TWHR2_AND_WE_2_RE); + sel->hwhr2_and_we_2_re = tmp; /* tADL -> ADDR_2_DATA */ @@ -834,7 +854,7 @@ static int denali_setup_data_interface(struct nand_chip *chip, int chipnr, tmp = ioread32(denali->reg + TCWAW_AND_ADDR_2_DATA); tmp &= ~TCWAW_AND_ADDR_2_DATA__ADDR_2_DATA; tmp |= FIELD_PREP(TCWAW_AND_ADDR_2_DATA__ADDR_2_DATA, addr_2_data); - iowrite32(tmp, denali->reg + TCWAW_AND_ADDR_2_DATA); + sel->tcwaw_and_addr_2_data = tmp; /* tREH, tWH -> RDWR_EN_HI_CNT */ rdwr_en_hi = DIV_ROUND_UP(max(timings->tREH_min, timings->tWH_min), @@ -844,7 +864,7 @@ static int denali_setup_data_interface(struct nand_chip *chip, int chipnr, tmp = ioread32(denali->reg + RDWR_EN_HI_CNT); tmp &= ~RDWR_EN_HI_CNT__VALUE; tmp |= FIELD_PREP(RDWR_EN_HI_CNT__VALUE, rdwr_en_hi); - iowrite32(tmp, denali->reg + RDWR_EN_HI_CNT); + sel->rdwr_en_hi_cnt = tmp; /* tRP, tWP -> RDWR_EN_LO_CNT */ rdwr_en_lo = DIV_ROUND_UP(max(timings->tRP_min, timings->tWP_min), t_x); @@ -857,7 +877,7 @@ static int denali_setup_data_interface(struct nand_chip *chip, int chipnr, tmp = ioread32(denali->reg + RDWR_EN_LO_CNT); tmp &= ~RDWR_EN_LO_CNT__VALUE; tmp |= FIELD_PREP(RDWR_EN_LO_CNT__VALUE, rdwr_en_lo); - iowrite32(tmp, denali->reg + RDWR_EN_LO_CNT); + sel->rdwr_en_lo_cnt = tmp; /* tCS, tCEA -> CS_SETUP_CNT */ cs_setup = max3((int)DIV_ROUND_UP(timings->tCS_min, t_x) - rdwr_en_lo, @@ -868,40 +888,11 @@ static int denali_setup_data_interface(struct nand_chip *chip, int chipnr, tmp = ioread32(denali->reg + CS_SETUP_CNT); tmp &= ~CS_SETUP_CNT__VALUE; tmp |= FIELD_PREP(CS_SETUP_CNT__VALUE, cs_setup); - iowrite32(tmp, denali->reg + CS_SETUP_CNT); + sel->cs_setup_cnt = tmp; return 0; } -static void denali_hw_init(struct denali_nand_info *denali) -{ - /* - * The REVISION register may not be reliable. Platforms are allowed to - * override it. - */ - if (!denali->revision) - denali->revision = swab16(ioread32(denali->reg + REVISION)); - - /* - * Set how many bytes should be skipped before writing data in OOB. - * If a non-zero value has already been set (by firmware or something), - * just use it. Otherwise, set the driver default. - */ - denali->oob_skip_bytes = ioread32(denali->reg + SPARE_AREA_SKIP_BYTES); - if (!denali->oob_skip_bytes) { - denali->oob_skip_bytes = DENALI_DEFAULT_OOB_SKIP_BYTES; - iowrite32(denali->oob_skip_bytes, - denali->reg + SPARE_AREA_SKIP_BYTES); - } - - denali_detect_max_banks(denali); - iowrite32(0, denali->reg + TRANSFER_SPARE_REG); - iowrite32(0x0F, denali->reg + RB_PIN_ENABLED); - iowrite32(CHIP_EN_DONT_CARE__FLAG, denali->reg + CHIP_ENABLE_DONT_CARE); - iowrite32(ECC_ENABLE__FLAG, denali->reg + ECC_ENABLE); - iowrite32(0xffff, denali->reg + SPARE_AREA_MARKER); -} - int denali_calc_ecc_bytes(int step_size, int strength) { /* BCH code. Denali requires ecc.bytes to be multiple of 2 */ @@ -912,10 +903,10 @@ EXPORT_SYMBOL(denali_calc_ecc_bytes); static int denali_ooblayout_ecc(struct mtd_info *mtd, int section, struct mtd_oob_region *oobregion) { - struct denali_nand_info *denali = mtd_to_denali(mtd); struct nand_chip *chip = mtd_to_nand(mtd); + struct denali_controller *denali = to_denali_controller(chip); - if (section) + if (section > 0) return -ERANGE; oobregion->offset = denali->oob_skip_bytes; @@ -927,10 +918,10 @@ static int denali_ooblayout_ecc(struct mtd_info *mtd, int section, static int denali_ooblayout_free(struct mtd_info *mtd, int section, struct mtd_oob_region *oobregion) { - struct denali_nand_info *denali = mtd_to_denali(mtd); struct nand_chip *chip = mtd_to_nand(mtd); + struct denali_controller *denali = to_denali_controller(chip); - if (section) + if (section > 0) return -ERANGE; oobregion->offset = chip->ecc.total + denali->oob_skip_bytes; @@ -946,7 +937,7 @@ static const struct mtd_ooblayout_ops denali_ooblayout_ops = { static int denali_multidev_fixup(struct nand_chip *chip) { - struct denali_nand_info *denali = to_denali(chip); + struct denali_controller *denali = to_denali_controller(chip); struct mtd_info *mtd = nand_to_mtd(chip); struct nand_memory_organization *memorg; @@ -1001,38 +992,10 @@ static int denali_multidev_fixup(struct nand_chip *chip) static int denali_attach_chip(struct nand_chip *chip) { + struct denali_controller *denali = to_denali_controller(chip); struct mtd_info *mtd = nand_to_mtd(chip); - struct denali_nand_info *denali = mtd_to_denali(mtd); int ret; - if (ioread32(denali->reg + FEATURES) & FEATURES__DMA) - denali->dma_avail = true; - - if (denali->dma_avail) { - int dma_bit = denali->caps & DENALI_CAP_DMA_64BIT ? 64 : 32; - - ret = dma_set_mask(denali->dev, DMA_BIT_MASK(dma_bit)); - if (ret) { - dev_info(denali->dev, - "Failed to set DMA mask. Disabling DMA.\n"); - denali->dma_avail = false; - } - } - - if (denali->dma_avail) { - chip->options |= NAND_USE_BOUNCE_BUFFER; - chip->buf_align = 16; - if (denali->caps & DENALI_CAP_DMA_64BIT) - denali->setup_dma = denali_setup_dma64; - else - denali->setup_dma = denali_setup_dma32; - } - - chip->bbt_options |= NAND_BBT_USE_FLASH; - chip->bbt_options |= NAND_BBT_NO_OOB; - chip->ecc.mode = NAND_ECC_HW_SYNDROME; - chip->options |= NAND_NO_SUBPAGE_WRITE; - ret = nand_ecc_choose_conf(chip, denali->ecc_caps, mtd->oobsize - denali->oob_skip_bytes); if (ret) { @@ -1044,33 +1007,6 @@ static int denali_attach_chip(struct nand_chip *chip) "chosen ECC settings: step=%d, strength=%d, bytes=%d\n", chip->ecc.size, chip->ecc.strength, chip->ecc.bytes); - iowrite32(FIELD_PREP(ECC_CORRECTION__ERASE_THRESHOLD, 1) | - FIELD_PREP(ECC_CORRECTION__VALUE, chip->ecc.strength), - denali->reg + ECC_CORRECTION); - iowrite32(mtd->erasesize / mtd->writesize, - denali->reg + PAGES_PER_BLOCK); - iowrite32(chip->options & NAND_BUSWIDTH_16 ? 1 : 0, - denali->reg + DEVICE_WIDTH); - iowrite32(chip->options & NAND_ROW_ADDR_3 ? 0 : TWO_ROW_ADDR_CYCLES__FLAG, - denali->reg + TWO_ROW_ADDR_CYCLES); - iowrite32(mtd->writesize, denali->reg + DEVICE_MAIN_AREA_SIZE); - iowrite32(mtd->oobsize, denali->reg + DEVICE_SPARE_AREA_SIZE); - - iowrite32(chip->ecc.size, denali->reg + CFG_DATA_BLOCK_SIZE); - iowrite32(chip->ecc.size, denali->reg + CFG_LAST_DATA_BLOCK_SIZE); - /* chip->ecc.steps is set by nand_scan_tail(); not available here */ - iowrite32(mtd->writesize / chip->ecc.size, - denali->reg + CFG_NUM_DATA_BLOCKS); - - mtd_set_ooblayout(mtd, &denali_ooblayout_ops); - - chip->ecc.read_page = denali_read_page; - chip->ecc.read_page_raw = denali_read_page_raw; - chip->ecc.write_page = denali_write_page; - chip->ecc.write_page_raw = denali_write_page_raw; - chip->ecc.read_oob = denali_read_oob; - chip->ecc.write_oob = denali_write_oob; - ret = denali_multidev_fixup(chip); if (ret) return ret; @@ -1078,7 +1014,7 @@ static int denali_attach_chip(struct nand_chip *chip) return 0; } -static void denali_exec_in8(struct denali_nand_info *denali, u32 type, +static void denali_exec_in8(struct denali_controller *denali, u32 type, u8 *buf, unsigned int len) { int i; @@ -1087,7 +1023,7 @@ static void denali_exec_in8(struct denali_nand_info *denali, u32 type, buf[i] = denali->host_read(denali, type | DENALI_BANK(denali)); } -static void denali_exec_in16(struct denali_nand_info *denali, u32 type, +static void denali_exec_in16(struct denali_controller *denali, u32 type, u8 *buf, unsigned int len) { u32 data; @@ -1101,7 +1037,7 @@ static void denali_exec_in16(struct denali_nand_info *denali, u32 type, } } -static void denali_exec_in(struct denali_nand_info *denali, u32 type, +static void denali_exec_in(struct denali_controller *denali, u32 type, u8 *buf, unsigned int len, bool width16) { if (width16) @@ -1110,7 +1046,7 @@ static void denali_exec_in(struct denali_nand_info *denali, u32 type, denali_exec_in8(denali, type, buf, len); } -static void denali_exec_out8(struct denali_nand_info *denali, u32 type, +static void denali_exec_out8(struct denali_controller *denali, u32 type, const u8 *buf, unsigned int len) { int i; @@ -1119,7 +1055,7 @@ static void denali_exec_out8(struct denali_nand_info *denali, u32 type, denali->host_write(denali, type | DENALI_BANK(denali), buf[i]); } -static void denali_exec_out16(struct denali_nand_info *denali, u32 type, +static void denali_exec_out16(struct denali_controller *denali, u32 type, const u8 *buf, unsigned int len) { int i; @@ -1129,7 +1065,7 @@ static void denali_exec_out16(struct denali_nand_info *denali, u32 type, buf[i + 1] << 16 | buf[i]); } -static void denali_exec_out(struct denali_nand_info *denali, u32 type, +static void denali_exec_out(struct denali_controller *denali, u32 type, const u8 *buf, unsigned int len, bool width16) { if (width16) @@ -1138,7 +1074,7 @@ static void denali_exec_out(struct denali_nand_info *denali, u32 type, denali_exec_out8(denali, type, buf, len); } -static int denali_exec_waitrdy(struct denali_nand_info *denali) +static int denali_exec_waitrdy(struct denali_controller *denali) { u32 irq_stat; @@ -1154,7 +1090,7 @@ static int denali_exec_waitrdy(struct denali_nand_info *denali) static int denali_exec_instr(struct nand_chip *chip, const struct nand_op_instr *instr) { - struct denali_nand_info *denali = to_denali(chip); + struct denali_controller *denali = to_denali_controller(chip); switch (instr->type) { case NAND_OP_CMD_INSTR: @@ -1204,7 +1140,7 @@ static int denali_exec_op(struct nand_chip *chip, * Some commands contain NAND_OP_WAITRDY_INSTR. * irq must be cleared here to catch the R/B# interrupt there. */ - denali_reset_irq(to_denali(chip)); + denali_reset_irq(to_denali_controller(chip)); for (i = 0; i < op->ninstrs; i++) { ret = denali_exec_instr(chip, &op->instrs[i]); @@ -1221,53 +1157,80 @@ static const struct nand_controller_ops denali_controller_ops = { .setup_data_interface = denali_setup_data_interface, }; -int denali_init(struct denali_nand_info *denali) +int denali_chip_init(struct denali_controller *denali, + struct denali_chip *dchip) { - struct nand_chip *chip = &denali->nand; + struct nand_chip *chip = &dchip->chip; struct mtd_info *mtd = nand_to_mtd(chip); - u32 features = ioread32(denali->reg + FEATURES); - int ret; + struct denali_chip *dchip2; + int i, j, ret; - mtd->dev.parent = denali->dev; - denali_hw_init(denali); + chip->controller = &denali->controller; - init_completion(&denali->complete); - spin_lock_init(&denali->irq_lock); + /* sanity checks for bank numbers */ + for (i = 0; i < dchip->nsels; i++) { + unsigned int bank = dchip->sels[i].bank; - denali_clear_irq_all(denali); + if (bank >= denali->nbanks) { + dev_err(denali->dev, "unsupported bank %d\n", bank); + return -EINVAL; + } - ret = devm_request_irq(denali->dev, denali->irq, denali_isr, - IRQF_SHARED, DENALI_NAND_NAME, denali); - if (ret) { - dev_err(denali->dev, "Unable to request IRQ\n"); - return ret; - } + for (j = 0; j < i; j++) { + if (bank == dchip->sels[j].bank) { + dev_err(denali->dev, + "bank %d is assigned twice in the same chip\n", + bank); + return -EINVAL; + } + } - denali_enable_irq(denali); + list_for_each_entry(dchip2, &denali->chips, node) { + for (j = 0; j < dchip2->nsels; j++) { + if (bank == dchip2->sels[j].bank) { + dev_err(denali->dev, + "bank %d is already used\n", + bank); + return -EINVAL; + } + } + } + } - denali->active_bank = DENALI_INVALID_BANK; + mtd->dev.parent = denali->dev; - nand_set_flash_node(chip, denali->dev->of_node); - /* Fallback to the default name if DT did not give "label" property */ - if (!mtd->name) + /* + * Fallback to the default name if DT did not give "label" property. + * Use "label" property if multiple chips are connected. + */ + if (!mtd->name && list_empty(&denali->chips)) mtd->name = "denali-nand"; - if (features & FEATURES__INDEX_ADDR) { - denali->host_read = denali_indexed_read; - denali->host_write = denali_indexed_write; - } else { - denali->host_read = denali_direct_read; - denali->host_write = denali_direct_write; + if (denali->dma_avail) { + chip->options |= NAND_USE_BOUNCE_BUFFER; + chip->buf_align = 16; } /* clk rate info is needed for setup_data_interface */ if (!denali->clk_rate || !denali->clk_x_rate) chip->options |= NAND_KEEP_TIMINGS; - chip->legacy.dummy_controller.ops = &denali_controller_ops; - ret = nand_scan(chip, denali->max_banks); + chip->bbt_options |= NAND_BBT_USE_FLASH; + chip->bbt_options |= NAND_BBT_NO_OOB; + chip->options |= NAND_NO_SUBPAGE_WRITE; + chip->ecc.mode = NAND_ECC_HW_SYNDROME; + chip->ecc.read_page = denali_read_page; + chip->ecc.write_page = denali_write_page; + chip->ecc.read_page_raw = denali_read_page_raw; + chip->ecc.write_page_raw = denali_write_page_raw; + chip->ecc.read_oob = denali_read_oob; + chip->ecc.write_oob = denali_write_oob; + + mtd_set_ooblayout(mtd, &denali_ooblayout_ops); + + ret = nand_scan(chip, dchip->nsels); if (ret) - goto disable_irq; + return ret; ret = mtd_device_register(mtd, NULL, 0); if (ret) { @@ -1275,20 +1238,111 @@ int denali_init(struct denali_nand_info *denali) goto cleanup_nand; } + list_add_tail(&dchip->node, &denali->chips); + return 0; cleanup_nand: nand_cleanup(chip); -disable_irq: - denali_disable_irq(denali); return ret; } +EXPORT_SYMBOL_GPL(denali_chip_init); + +int denali_init(struct denali_controller *denali) +{ + u32 features = ioread32(denali->reg + FEATURES); + int ret; + + nand_controller_init(&denali->controller); + denali->controller.ops = &denali_controller_ops; + init_completion(&denali->complete); + spin_lock_init(&denali->irq_lock); + INIT_LIST_HEAD(&denali->chips); + denali->active_bank = DENALI_INVALID_BANK; + + /* + * The REVISION register may not be reliable. Platforms are allowed to + * override it. + */ + if (!denali->revision) + denali->revision = swab16(ioread32(denali->reg + REVISION)); + + denali->nbanks = 1 << FIELD_GET(FEATURES__N_BANKS, features); + + /* the encoding changed from rev 5.0 to 5.1 */ + if (denali->revision < 0x0501) + denali->nbanks <<= 1; + + if (features & FEATURES__DMA) + denali->dma_avail = true; + + if (denali->dma_avail) { + int dma_bit = denali->caps & DENALI_CAP_DMA_64BIT ? 64 : 32; + + ret = dma_set_mask(denali->dev, DMA_BIT_MASK(dma_bit)); + if (ret) { + dev_info(denali->dev, + "Failed to set DMA mask. Disabling DMA.\n"); + denali->dma_avail = false; + } + } + + if (denali->dma_avail) { + if (denali->caps & DENALI_CAP_DMA_64BIT) + denali->setup_dma = denali_setup_dma64; + else + denali->setup_dma = denali_setup_dma32; + } + + if (features & FEATURES__INDEX_ADDR) { + denali->host_read = denali_indexed_read; + denali->host_write = denali_indexed_write; + } else { + denali->host_read = denali_direct_read; + denali->host_write = denali_direct_write; + } + + /* + * Set how many bytes should be skipped before writing data in OOB. + * If a non-zero value has already been set (by firmware or something), + * just use it. Otherwise, set the driver's default. + */ + denali->oob_skip_bytes = ioread32(denali->reg + SPARE_AREA_SKIP_BYTES); + if (!denali->oob_skip_bytes) { + denali->oob_skip_bytes = DENALI_DEFAULT_OOB_SKIP_BYTES; + iowrite32(denali->oob_skip_bytes, + denali->reg + SPARE_AREA_SKIP_BYTES); + } + + iowrite32(0, denali->reg + TRANSFER_SPARE_REG); + iowrite32(GENMASK(denali->nbanks - 1, 0), denali->reg + RB_PIN_ENABLED); + iowrite32(CHIP_EN_DONT_CARE__FLAG, denali->reg + CHIP_ENABLE_DONT_CARE); + iowrite32(ECC_ENABLE__FLAG, denali->reg + ECC_ENABLE); + iowrite32(0xffff, denali->reg + SPARE_AREA_MARKER); + + denali_clear_irq_all(denali); + + ret = devm_request_irq(denali->dev, denali->irq, denali_isr, + IRQF_SHARED, DENALI_NAND_NAME, denali); + if (ret) { + dev_err(denali->dev, "Unable to request IRQ\n"); + return ret; + } + + denali_enable_irq(denali); + + return 0; +} EXPORT_SYMBOL(denali_init); -void denali_remove(struct denali_nand_info *denali) +void denali_remove(struct denali_controller *denali) { - nand_release(&denali->nand); + struct denali_chip *dchip; + + list_for_each_entry(dchip, &denali->chips, node) + nand_release(&dchip->chip); + denali_disable_irq(denali); } EXPORT_SYMBOL(denali_remove); diff --git a/drivers/mtd/nand/raw/denali.h b/drivers/mtd/nand/raw/denali.h index d2603c67dd20..e5cdcda56d14 100644 --- a/drivers/mtd/nand/raw/denali.h +++ b/drivers/mtd/nand/raw/denali.h @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -290,29 +291,98 @@ #define CHNL_ACTIVE__CHANNEL2 BIT(2) #define CHNL_ACTIVE__CHANNEL3 BIT(3) -struct denali_nand_info { - struct nand_chip nand; - unsigned long clk_rate; /* core clock rate */ - unsigned long clk_x_rate; /* bus interface clock rate */ - int active_bank; /* currently selected bank */ +/** + * struct denali_chip_sel - per-CS data of Denali NAND + * + * @bank: bank id of the controller this CS is connected to + * @hwhr2_and_we_2_re: value of timing register HWHR2_AND_WE_2_RE + * @tcwaw_and_addr_2_data: value of timing register TCWAW_AND_ADDR_2_DATA + * @re_2_we: value of timing register RE_2_WE + * @acc_clks: value of timing register ACC_CLKS + * @rdwr_en_lo_cnt: value of timing register RDWR_EN_LO_CNT + * @rdwr_en_hi_cnt: value of timing register RDWR_EN_HI_CNT + * @cs_setup_cnt: value of timing register CS_SETUP_CNT + * @re_2_re: value of timing register RE_2_RE + */ +struct denali_chip_sel { + int bank; + u32 hwhr2_and_we_2_re; + u32 tcwaw_and_addr_2_data; + u32 re_2_we; + u32 acc_clks; + u32 rdwr_en_lo_cnt; + u32 rdwr_en_hi_cnt; + u32 cs_setup_cnt; + u32 re_2_re; +}; + +/** + * struct denali_chip - per-chip data of Denali NAND + * + * @chip: base NAND chip structure + * @node: node to be used to associate this chip with the controller + * @nsels: the number of CS lines of this chip + * @sels: the array of per-cs data + */ +struct denali_chip { + struct nand_chip chip; + struct list_head node; + unsigned int nsels; + struct denali_chip_sel sels[0]; +}; + +/** + * struct denali_controller - Denali NAND controller data + * + * @controller: base NAND controller structure + * @dev: device + * @chips: the list of chips attached to this controller + * @clk_rate: frequency of core clock + * @clk_x_rate: frequency of bus interface clock + * @reg: base of Register Interface + * @host: base of Host Data/Command interface + * @complete: completion used to wait for interrupts + * @irq: interrupt number + * @irq_mask: interrupt bits the controller is waiting for + * @irq_status: interrupt bits of events that have happened + * @irq_lock: lock to protect @irq_mask and @irq_status + * @dma_avail: set if DMA engine is available + * @devs_per_cs: number of devices connected in parallel + * @oob_skip_bytes: number of bytes in OOB skipped by the ECC engine + * @active_bank: active bank id + * @nbanks: the number of banks supported by this controller + * @revision: IP revision + * @caps: controller capabilities that cannot be detected run-time + * @ecc_caps: ECC engine capabilities + * @host_read: callback for read access of Host Data/Command Interface + * @host_write: callback for write access of Host Data/Command Interface + * @setup_dma: callback for setup of the Data DMA + */ +struct denali_controller { + struct nand_controller controller; struct device *dev; - void __iomem *reg; /* Register Interface */ - void __iomem *host; /* Host Data/Command Interface */ + struct list_head chips; + unsigned long clk_rate; + unsigned long clk_x_rate; + void __iomem *reg; + void __iomem *host; struct completion complete; - spinlock_t irq_lock; /* protect irq_mask and irq_status */ - u32 irq_mask; /* interrupts we are waiting for */ - u32 irq_status; /* interrupts that have happened */ int irq; - bool dma_avail; /* can support DMA? */ - int devs_per_cs; /* devices connected in parallel */ - int oob_skip_bytes; /* number of bytes reserved for BBM */ - int max_banks; - unsigned int revision; /* IP revision */ - unsigned int caps; /* IP capability (or quirk) */ + u32 irq_mask; + u32 irq_status; + spinlock_t irq_lock; + bool dma_avail; + int devs_per_cs; + int oob_skip_bytes; + int active_bank; + int nbanks; + unsigned int revision; + unsigned int caps; const struct nand_ecc_caps *ecc_caps; - u32 (*host_read)(struct denali_nand_info *denali, u32 addr); - void (*host_write)(struct denali_nand_info *denali, u32 addr, u32 data); - void (*setup_dma)(struct denali_nand_info *denali, dma_addr_t dma_addr, + u32 (*host_read)(struct denali_controller *denali, u32 addr); + void (*host_write)(struct denali_controller *denali, u32 addr, + u32 data); + void (*setup_dma)(struct denali_controller *denali, dma_addr_t dma_addr, int page, bool write); }; @@ -320,7 +390,9 @@ struct denali_nand_info { #define DENALI_CAP_DMA_64BIT BIT(1) int denali_calc_ecc_bytes(int step_size, int strength); -int denali_init(struct denali_nand_info *denali); -void denali_remove(struct denali_nand_info *denali); +int denali_chip_init(struct denali_controller *denali, + struct denali_chip *dchip); +int denali_init(struct denali_controller *denali); +void denali_remove(struct denali_controller *denali); #endif /* __DENALI_H__ */ diff --git a/drivers/mtd/nand/raw/denali_dt.c b/drivers/mtd/nand/raw/denali_dt.c index 0b5ae2418815..5e14836f6bd5 100644 --- a/drivers/mtd/nand/raw/denali_dt.c +++ b/drivers/mtd/nand/raw/denali_dt.c @@ -18,7 +18,7 @@ #include "denali.h" struct denali_dt { - struct denali_nand_info denali; + struct denali_controller controller; struct clk *clk; /* core clock */ struct clk *clk_x; /* bus interface clock */ struct clk *clk_ecc; /* ECC circuit clock */ @@ -71,19 +71,92 @@ static const struct of_device_id denali_nand_dt_ids[] = { }; MODULE_DEVICE_TABLE(of, denali_nand_dt_ids); +static int denali_dt_chip_init(struct denali_controller *denali, + struct device_node *chip_np) +{ + struct denali_chip *dchip; + u32 bank; + int nsels, i, ret; + + nsels = of_property_count_u32_elems(chip_np, "reg"); + if (nsels < 0) + return nsels; + + dchip = devm_kzalloc(denali->dev, struct_size(dchip, sels, nsels), + GFP_KERNEL); + if (!dchip) + return -ENOMEM; + + dchip->nsels = nsels; + + for (i = 0; i < nsels; i++) { + ret = of_property_read_u32_index(chip_np, "reg", i, &bank); + if (ret) + return ret; + + dchip->sels[i].bank = bank; + + nand_set_flash_node(&dchip->chip, chip_np); + } + + return denali_chip_init(denali, dchip); +} + +/* Backward compatibility for old platforms */ +static int denali_dt_legacy_chip_init(struct denali_controller *denali) +{ + struct denali_chip *dchip; + int nsels, i; + + nsels = denali->nbanks; + + dchip = devm_kzalloc(denali->dev, struct_size(dchip, sels, nsels), + GFP_KERNEL); + if (!dchip) + return -ENOMEM; + + dchip->nsels = nsels; + + for (i = 0; i < nsels; i++) + dchip->sels[i].bank = i; + + nand_set_flash_node(&dchip->chip, denali->dev->of_node); + + return denali_chip_init(denali, dchip); +} + +/* + * Check the DT binding. + * The new binding expects chip subnodes in the controller node. + * So, #address-cells = <1>; #size-cells = <0>; are required. + * Check the #size-cells to distinguish the binding. + */ +static bool denali_dt_is_legacy_binding(struct device_node *np) +{ + u32 cells; + int ret; + + ret = of_property_read_u32(np, "#size-cells", &cells); + if (ret) + return true; + + return cells != 0; +} + static int denali_dt_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct resource *res; struct denali_dt *dt; const struct denali_dt_data *data; - struct denali_nand_info *denali; + struct denali_controller *denali; + struct device_node *np; int ret; dt = devm_kzalloc(dev, sizeof(*dt), GFP_KERNEL); if (!dt) return -ENOMEM; - denali = &dt->denali; + denali = &dt->controller; data = of_device_get_match_data(dev); if (data) { @@ -140,9 +213,26 @@ static int denali_dt_probe(struct platform_device *pdev) if (ret) goto out_disable_clk_ecc; + if (denali_dt_is_legacy_binding(dev->of_node)) { + ret = denali_dt_legacy_chip_init(denali); + if (ret) + goto out_remove_denali; + } else { + for_each_child_of_node(dev->of_node, np) { + ret = denali_dt_chip_init(denali, np); + if (ret) { + of_node_put(np); + goto out_remove_denali; + } + } + } + platform_set_drvdata(pdev, dt); + return 0; +out_remove_denali: + denali_remove(denali); out_disable_clk_ecc: clk_disable_unprepare(dt->clk_ecc); out_disable_clk_x: @@ -157,7 +247,7 @@ static int denali_dt_remove(struct platform_device *pdev) { struct denali_dt *dt = platform_get_drvdata(pdev); - denali_remove(&dt->denali); + denali_remove(&dt->controller); clk_disable_unprepare(dt->clk_ecc); clk_disable_unprepare(dt->clk_x); clk_disable_unprepare(dt->clk); diff --git a/drivers/mtd/nand/raw/denali_pci.c b/drivers/mtd/nand/raw/denali_pci.c index 02eb5990a91e..d62aa5271753 100644 --- a/drivers/mtd/nand/raw/denali_pci.c +++ b/drivers/mtd/nand/raw/denali_pci.c @@ -29,10 +29,11 @@ NAND_ECC_CAPS_SINGLE(denali_pci_ecc_caps, denali_calc_ecc_bytes, 512, 8, 15); static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) { - int ret; resource_size_t csr_base, mem_base; unsigned long csr_len, mem_len; - struct denali_nand_info *denali; + struct denali_controller *denali; + struct denali_chip *dchip; + int nsels, ret, i; denali = devm_kzalloc(&dev->dev, sizeof(*denali), GFP_KERNEL); if (!denali) @@ -64,7 +65,6 @@ static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) denali->dev = &dev->dev; denali->irq = dev->irq; denali->ecc_caps = &denali_pci_ecc_caps; - denali->nand.ecc.options |= NAND_ECC_MAXIMIZE; denali->clk_rate = 50000000; /* 50 MHz */ denali->clk_x_rate = 200000000; /* 200 MHz */ @@ -91,10 +91,32 @@ static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) if (ret) goto out_unmap_host; + nsels = denali->nbanks; + + dchip = devm_kzalloc(denali->dev, struct_size(dchip, sels, nsels), + GFP_KERNEL); + if (!dchip) { + ret = -ENOMEM; + goto out_remove_denali; + } + + dchip->chip.ecc.options |= NAND_ECC_MAXIMIZE; + + dchip->nsels = nsels; + + for (i = 0; i < nsels; i++) + dchip->sels[i].bank = i; + + ret = denali_chip_init(denali, dchip); + if (ret) + goto out_remove_denali; + pci_set_drvdata(dev, denali); return 0; +out_remove_denali: + denali_remove(denali); out_unmap_host: iounmap(denali->host); out_unmap_reg: @@ -104,7 +126,7 @@ out_unmap_reg: static void denali_pci_remove(struct pci_dev *dev) { - struct denali_nand_info *denali = pci_get_drvdata(dev); + struct denali_controller *denali = pci_get_drvdata(dev); denali_remove(denali); iounmap(denali->reg); -- cgit From 979da35536251504b6c43f9dd568903fcf637162 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 2 Apr 2019 13:03:08 +0900 Subject: mtd: rawnand: denali: remove DENALI_NR_BANKS macro Use the runtime-detected denali->nbanks instead of hard-coded DENALI_NR_BANKS (=4). The actual number of banks depends on the IP configuration, and can be less than DENALI_NR_BANKS. It is pointless to touch registers of unsupported banks. Signed-off-by: Masahiro Yamada Signed-off-by: Miquel Raynal --- drivers/mtd/nand/raw/denali.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/mtd/nand/raw/denali.c b/drivers/mtd/nand/raw/denali.c index d8c10444e284..52b704c58eaf 100644 --- a/drivers/mtd/nand/raw/denali.c +++ b/drivers/mtd/nand/raw/denali.c @@ -40,7 +40,6 @@ #define DENALI_BANK(denali) ((denali)->active_bank << 24) #define DENALI_INVALID_BANK -1 -#define DENALI_NR_BANKS 4 static struct denali_chip *to_denali_chip(struct nand_chip *chip) { @@ -92,7 +91,7 @@ static void denali_enable_irq(struct denali_controller *denali) { int i; - for (i = 0; i < DENALI_NR_BANKS; i++) + for (i = 0; i < denali->nbanks; i++) iowrite32(U32_MAX, denali->reg + INTR_EN(i)); iowrite32(GLOBAL_INT_EN_FLAG, denali->reg + GLOBAL_INT_ENABLE); } @@ -101,7 +100,7 @@ static void denali_disable_irq(struct denali_controller *denali) { int i; - for (i = 0; i < DENALI_NR_BANKS; i++) + for (i = 0; i < denali->nbanks; i++) iowrite32(0, denali->reg + INTR_EN(i)); iowrite32(0, denali->reg + GLOBAL_INT_ENABLE); } @@ -117,7 +116,7 @@ static void denali_clear_irq_all(struct denali_controller *denali) { int i; - for (i = 0; i < DENALI_NR_BANKS; i++) + for (i = 0; i < denali->nbanks; i++) denali_clear_irq(denali, i, U32_MAX); } @@ -130,7 +129,7 @@ static irqreturn_t denali_isr(int irq, void *dev_id) spin_lock(&denali->irq_lock); - for (i = 0; i < DENALI_NR_BANKS; i++) { + for (i = 0; i < denali->nbanks; i++) { irq_status = ioread32(denali->reg + INTR_STATUS(i)); if (irq_status) ret = IRQ_HANDLED; -- cgit From 2dcfc7b3c8992093121056c8dae1b63a652948e4 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 2 Apr 2019 13:03:09 +0900 Subject: mtd: rawnand: denali: clean up coding style Eliminate the following reports from 'scripts/checkpatch.pl --strict'. CHECK: Prefer kernel type 'u8' over 'uint8_t' CHECK: Prefer kernel type 'u32' over 'uint32_t' CHECK: Alignment should match open parenthesis I slightly changed denali_check_erased_page() to shorten it. Signed-off-by: Masahiro Yamada Signed-off-by: Miquel Raynal --- drivers/mtd/nand/raw/denali.c | 54 +++++++++++++++++++++---------------------- 1 file changed, 26 insertions(+), 28 deletions(-) diff --git a/drivers/mtd/nand/raw/denali.c b/drivers/mtd/nand/raw/denali.c index 52b704c58eaf..3102ddbd8abd 100644 --- a/drivers/mtd/nand/raw/denali.c +++ b/drivers/mtd/nand/raw/denali.c @@ -106,7 +106,7 @@ static void denali_disable_irq(struct denali_controller *denali) } static void denali_clear_irq(struct denali_controller *denali, - int bank, uint32_t irq_status) + int bank, u32 irq_status) { /* write one to clear bits */ iowrite32(irq_status, denali->reg + INTR_STATUS(bank)); @@ -124,7 +124,7 @@ static irqreturn_t denali_isr(int irq, void *dev_id) { struct denali_controller *denali = dev_id; irqreturn_t ret = IRQ_NONE; - uint32_t irq_status; + u32 irq_status; int i; spin_lock(&denali->irq_lock); @@ -163,7 +163,7 @@ static void denali_reset_irq(struct denali_controller *denali) static u32 denali_wait_for_irq(struct denali_controller *denali, u32 irq_mask) { unsigned long time_left, flags; - uint32_t irq_status; + u32 irq_status; spin_lock_irqsave(&denali->irq_lock, flags); @@ -411,20 +411,17 @@ static int denali_check_erased_page(struct nand_chip *chip, u8 *buf, { struct denali_controller *denali = to_denali_controller(chip); struct mtd_ecc_stats *ecc_stats = &nand_to_mtd(chip)->ecc_stats; - uint8_t *ecc_code = chip->oob_poi + denali->oob_skip_bytes; - int ecc_steps = chip->ecc.steps; - int ecc_size = chip->ecc.size; - int ecc_bytes = chip->ecc.bytes; + struct nand_ecc_ctrl *ecc = &chip->ecc; + u8 *ecc_code = chip->oob_poi + denali->oob_skip_bytes; int i, stat; - for (i = 0; i < ecc_steps; i++) { + for (i = 0; i < ecc->steps; i++) { if (!(uncor_ecc_flags & BIT(i))) continue; - stat = nand_check_erased_ecc_chunk(buf, ecc_size, - ecc_code, ecc_bytes, - NULL, 0, - chip->ecc.strength); + stat = nand_check_erased_ecc_chunk(buf, ecc->size, ecc_code, + ecc->bytes, NULL, 0, + ecc->strength); if (stat < 0) { ecc_stats->failed++; } else { @@ -432,8 +429,8 @@ static int denali_check_erased_page(struct nand_chip *chip, u8 *buf, max_bitflips = max_t(unsigned int, max_bitflips, stat); } - buf += ecc_size; - ecc_code += ecc_bytes; + buf += ecc->size; + ecc_code += ecc->bytes; } return max_bitflips; @@ -445,7 +442,7 @@ static int denali_hw_ecc_fixup(struct nand_chip *chip, struct denali_controller *denali = to_denali_controller(chip); struct mtd_ecc_stats *ecc_stats = &nand_to_mtd(chip)->ecc_stats; int bank = denali->active_bank; - uint32_t ecc_cor; + u32 ecc_cor; unsigned int max_bitflips; ecc_cor = ioread32(denali->reg + ECC_COR_INFO(bank)); @@ -475,18 +472,18 @@ static int denali_hw_ecc_fixup(struct nand_chip *chip, } static int denali_sw_ecc_fixup(struct nand_chip *chip, - unsigned long *uncor_ecc_flags, uint8_t *buf) + unsigned long *uncor_ecc_flags, u8 *buf) { struct denali_controller *denali = to_denali_controller(chip); struct mtd_ecc_stats *ecc_stats = &nand_to_mtd(chip)->ecc_stats; unsigned int ecc_size = chip->ecc.size; unsigned int bitflips = 0; unsigned int max_bitflips = 0; - uint32_t err_addr, err_cor_info; + u32 err_addr, err_cor_info; unsigned int err_byte, err_sector, err_device; - uint8_t err_cor_value; + u8 err_cor_value; unsigned int prev_sector = 0; - uint32_t irq_status; + u32 irq_status; denali_reset_irq(denali); @@ -551,7 +548,7 @@ static int denali_sw_ecc_fixup(struct nand_chip *chip, static void denali_setup_dma64(struct denali_controller *denali, dma_addr_t dma_addr, int page, bool write) { - uint32_t mode; + u32 mode; const int page_count = 1; mode = DENALI_MAP10 | DENALI_BANK(denali) | page; @@ -576,7 +573,7 @@ static void denali_setup_dma64(struct denali_controller *denali, static void denali_setup_dma32(struct denali_controller *denali, dma_addr_t dma_addr, int page, bool write) { - uint32_t mode; + u32 mode; const int page_count = 1; mode = DENALI_MAP10 | DENALI_BANK(denali); @@ -601,7 +598,7 @@ static int denali_pio_read(struct denali_controller *denali, u32 *buf, size_t size, int page) { u32 addr = DENALI_MAP01 | DENALI_BANK(denali) | page; - uint32_t irq_status, ecc_err_mask; + u32 irq_status, ecc_err_mask; int i; if (denali->caps & DENALI_CAP_HW_ECC_FIXUP) @@ -628,7 +625,7 @@ static int denali_pio_write(struct denali_controller *denali, const u32 *buf, size_t size, int page) { u32 addr = DENALI_MAP01 | DENALI_BANK(denali) | page; - uint32_t irq_status; + u32 irq_status; int i; denali_reset_irq(denali); @@ -637,7 +634,8 @@ static int denali_pio_write(struct denali_controller *denali, const u32 *buf, denali->host_write(denali, addr, buf[i]); irq_status = denali_wait_for_irq(denali, - INTR__PROGRAM_COMP | INTR__PROGRAM_FAIL); + INTR__PROGRAM_COMP | + INTR__PROGRAM_FAIL); if (!(irq_status & INTR__PROGRAM_COMP)) return -EIO; @@ -657,7 +655,7 @@ static int denali_dma_xfer(struct denali_controller *denali, void *buf, size_t size, int page, bool write) { dma_addr_t dma_addr; - uint32_t irq_mask, irq_status, ecc_err_mask; + u32 irq_mask, irq_status, ecc_err_mask; enum dma_data_direction dir = write ? DMA_TO_DEVICE : DMA_FROM_DEVICE; int ret = 0; @@ -723,7 +721,7 @@ static int denali_page_xfer(struct nand_chip *chip, void *buf, size_t size, return denali_pio_xfer(denali, buf, size, page, write); } -static int denali_read_page(struct nand_chip *chip, uint8_t *buf, +static int denali_read_page(struct nand_chip *chip, u8 *buf, int oob_required, int page) { struct denali_controller *denali = to_denali_controller(chip); @@ -756,7 +754,7 @@ static int denali_read_page(struct nand_chip *chip, uint8_t *buf, return stat; } -static int denali_write_page(struct nand_chip *chip, const uint8_t *buf, +static int denali_write_page(struct nand_chip *chip, const u8 *buf, int oob_required, int page) { struct mtd_info *mtd = nand_to_mtd(chip); @@ -774,7 +772,7 @@ static int denali_setup_data_interface(struct nand_chip *chip, int chipnr, int acc_clks, re_2_we, re_2_re, we_2_re, addr_2_data; int rdwr_en_lo, rdwr_en_hi, rdwr_en_lo_hi, cs_setup; int addr_2_data_mask; - uint32_t tmp; + u32 tmp; timings = nand_get_sdr_timings(conf); if (IS_ERR(timings)) -- cgit From 09e030d975490a23f759e44e54520307b8c7e8e2 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Thu, 4 Apr 2019 18:47:11 +0800 Subject: mtd: rawnand: ingenic: Add missing MODULE_* information gcc warning this: WARNING: modpost: missing MODULE_LICENSE() in drivers/mtd/nand/raw/ingenic/ingenic_ecc.o Add MODULE_LICENSE,MODULE_AUTHOR and MODULE_DESCRIPTION. Reported-by: Hulk Robot Fixes: 9df5741a577e ("mtd: rawnand: ingenic: Separate top-level and SoC specific code") Signed-off-by: YueHaibing Signed-off-by: Miquel Raynal --- drivers/mtd/nand/raw/ingenic/ingenic_ecc.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/mtd/nand/raw/ingenic/ingenic_ecc.c b/drivers/mtd/nand/raw/ingenic/ingenic_ecc.c index 13cc7630a3d8..d3e085c5685a 100644 --- a/drivers/mtd/nand/raw/ingenic/ingenic_ecc.c +++ b/drivers/mtd/nand/raw/ingenic/ingenic_ecc.c @@ -160,4 +160,7 @@ int ingenic_ecc_probe(struct platform_device *pdev) } EXPORT_SYMBOL(ingenic_ecc_probe); +MODULE_AUTHOR("Alex Smith "); +MODULE_AUTHOR("Harvey Hunt "); +MODULE_DESCRIPTION("Ingenic ECC common driver"); MODULE_LICENSE("GPL v2"); -- cgit From cf3bbe67be154d9658a7b8644a23a05e6246ea79 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Wed, 10 Apr 2019 22:00:35 +0800 Subject: mtd: rawnand: ingenic: Make jz4725b_ooblayout_ops static Fix sparse warning: drivers/mtd/nand/raw/ingenic/ingenic_nand.c:140:32: warning: symbol 'jz4725b_ooblayout_ops' was not declared. Should it be static? Reported-by: Hulk Robot Signed-off-by: YueHaibing Signed-off-by: Miquel Raynal --- drivers/mtd/nand/raw/ingenic/ingenic_nand.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/nand/raw/ingenic/ingenic_nand.c b/drivers/mtd/nand/raw/ingenic/ingenic_nand.c index ad0c905a03ba..d7b7c0f13909 100644 --- a/drivers/mtd/nand/raw/ingenic/ingenic_nand.c +++ b/drivers/mtd/nand/raw/ingenic/ingenic_nand.c @@ -137,7 +137,7 @@ static int jz4725b_ooblayout_free(struct mtd_info *mtd, int section, return 0; } -const struct mtd_ooblayout_ops jz4725b_ooblayout_ops = { +static const struct mtd_ooblayout_ops jz4725b_ooblayout_ops = { .ecc = jz4725b_ooblayout_ecc, .free = jz4725b_ooblayout_free, }; -- cgit From 212e4969359297e44c8ed879d56ab077f9a52454 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Wed, 3 Apr 2019 09:48:04 +0200 Subject: dt-bindings: mtd: Add YAML schemas for the generic NAND options The NAND chips in MTD have a bunch of generic options that are needed in a device tree. Add a YAML schemas for those. Signed-off-by: Maxime Ripard Reviewed-by: Rob Herring Signed-off-by: Miquel Raynal --- .../devicetree/bindings/mtd/nand-controller.yaml | 143 +++++++++++++++++++++ Documentation/devicetree/bindings/mtd/nand.txt | 75 ----------- 2 files changed, 143 insertions(+), 75 deletions(-) create mode 100644 Documentation/devicetree/bindings/mtd/nand-controller.yaml delete mode 100644 Documentation/devicetree/bindings/mtd/nand.txt diff --git a/Documentation/devicetree/bindings/mtd/nand-controller.yaml b/Documentation/devicetree/bindings/mtd/nand-controller.yaml new file mode 100644 index 000000000000..199ba5ac2a06 --- /dev/null +++ b/Documentation/devicetree/bindings/mtd/nand-controller.yaml @@ -0,0 +1,143 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/mtd/nand-controller.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NAND Chip and NAND Controller Generic Binding + +maintainers: + - Miquel Raynal + - Richard Weinberger + +description: | + The NAND controller should be represented with its own DT node, and + all NAND chips attached to this controller should be defined as + children nodes of the NAND controller. This representation should be + enforced even for simple controllers supporting only one chip. + + The ECC strength and ECC step size properties define the user + desires in terms of correction capability of a controller. Together, + they request the ECC engine to correct {strength} bit errors per + {size} bytes. + + The interpretation of these parameters is implementation-defined, so + not all implementations must support all possible + combinations. However, implementations are encouraged to further + specify the value(s) they support. + +properties: + $nodename: + pattern: "^nand-controller(@.*)?" + + "#address-cells": + const: 1 + + "#size-cells": + const: 0 + + ranges: true + +patternProperties: + "^nand@[a-f0-9]$": + properties: + reg: + description: + Contains the native Ready/Busy IDs. + + nand-ecc-mode: + allOf: + - $ref: /schemas/types.yaml#/definitions/string + - enum: [ none, soft, hw, hw_syndrome, hw_oob_first, on-die ] + description: + Desired ECC engine, either hardware (most of the time + embedded in the NAND controller) or software correction + (Linux will handle the calculations). soft_bch is deprecated + and should be replaced by soft and nand-ecc-algo. + + nand-ecc-algo: + allOf: + - $ref: /schemas/types.yaml#/definitions/string + - enum: [ hamming, bch, rs ] + description: + Desired ECC algorithm. + + nand-bus-width: + allOf: + - $ref: /schemas/types.yaml#/definitions/uint32 + - enum: [ 8, 16 ] + - default: 8 + description: + Bus width to the NAND chip + + nand-on-flash-bbt: + $ref: /schemas/types.yaml#/definitions/flag + description: + With this property, the OS will search the device for a Bad + Block Table (BBT). If not found, it will create one, reserve + a few blocks at the end of the device to store it and update + it as the device ages. Otherwise, the out-of-band area of a + few pages of all the blocks will be scanned at boot time to + find Bad Block Markers (BBM). These markers will help to + build a volatile BBT in RAM. + + nand-ecc-strength: + allOf: + - $ref: /schemas/types.yaml#/definitions/uint32 + - minimum: 1 + description: + Maximum number of bits that can be corrected per ECC step. + + nand-ecc-step-size: + allOf: + - $ref: /schemas/types.yaml#/definitions/uint32 + - minimum: 1 + description: + Number of data bytes covered by a single ECC step. + + nand-ecc-maximize: + $ref: /schemas/types.yaml#/definitions/flag + description: + Whether or not the ECC strength should be maximized. The + maximum ECC strength is both controller and chip + dependent. The ECC engine has to select the ECC config + providing the best strength and taking the OOB area size + constraint into account. This is particularly useful when + only the in-band area is used by the upper layers, and you + want to make your NAND as reliable as possible. + + nand-is-boot-medium: + $ref: /schemas/types.yaml#/definitions/flag + description: + Whether or not the NAND chip is a boot medium. Drivers might + use this information to select ECC algorithms supported by + the boot ROM or similar restrictions. + + nand-rb: + $ref: /schemas/types.yaml#/definitions/uint32-array + description: + Contains the native Ready/Busy IDs. + + required: + - reg + +required: + - "#address-cells" + - "#size-cells" + +examples: + - | + nand-controller { + #address-cells = <1>; + #size-cells = <0>; + + /* controller specific properties */ + + nand@0 { + reg = <0>; + nand-ecc-mode = "soft"; + nand-ecc-algo = "bch"; + + /* controller specific properties */ + }; + }; diff --git a/Documentation/devicetree/bindings/mtd/nand.txt b/Documentation/devicetree/bindings/mtd/nand.txt deleted file mode 100644 index e949c778e983..000000000000 --- a/Documentation/devicetree/bindings/mtd/nand.txt +++ /dev/null @@ -1,75 +0,0 @@ -* NAND chip and NAND controller generic binding - -NAND controller/NAND chip representation: - -The NAND controller should be represented with its own DT node, and all -NAND chips attached to this controller should be defined as children nodes -of the NAND controller. This representation should be enforced even for -simple controllers supporting only one chip. - -Mandatory NAND controller properties: -- #address-cells: depends on your controller. Should at least be 1 to - encode the CS line id. -- #size-cells: depends on your controller. Put zero unless you need a - mapping between CS lines and dedicated memory regions - -Optional NAND controller properties -- ranges: only needed if you need to define a mapping between CS lines and - memory regions - -Optional NAND chip properties: - -- nand-ecc-mode : String, operation mode of the NAND ecc mode. - Supported values are: "none", "soft", "hw", "hw_syndrome", - "hw_oob_first", "on-die". - Deprecated values: - "soft_bch": use "soft" and nand-ecc-algo instead -- nand-ecc-algo: string, algorithm of NAND ECC. - Valid values are: "hamming", "bch", "rs". -- nand-bus-width : 8 or 16 bus width if not present 8 -- nand-on-flash-bbt: boolean to enable on flash bbt option if not present false - -- nand-ecc-strength: integer representing the number of bits to correct - per ECC step. - -- nand-ecc-step-size: integer representing the number of data bytes - that are covered by a single ECC step. - -- nand-ecc-maximize: boolean used to specify that you want to maximize ECC - strength. The maximum ECC strength is both controller and - chip dependent. The controller side has to select the ECC - config providing the best strength and taking the OOB area - size constraint into account. - This is particularly useful when only the in-band area is - used by the upper layers, and you want to make your NAND - as reliable as possible. -- nand-is-boot-medium: Whether the NAND chip is a boot medium. Drivers might use - this information to select ECC algorithms supported by - the boot ROM or similar restrictions. - -- nand-rb: shall contain the native Ready/Busy ids. - -The ECC strength and ECC step size properties define the correction capability -of a controller. Together, they say a controller can correct "{strength} bit -errors per {size} bytes". - -The interpretation of these parameters is implementation-defined, so not all -implementations must support all possible combinations. However, implementations -are encouraged to further specify the value(s) they support. - -Example: - - nand-controller { - #address-cells = <1>; - #size-cells = <0>; - - /* controller specific properties */ - - nand@0 { - reg = <0>; - nand-ecc-mode = "soft"; - nand-ecc-algo = "bch"; - - /* controller specific properties */ - }; - }; -- cgit From a3c5a11dc82255c126a749d1e82d5de6605e9b26 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Wed, 3 Apr 2019 09:48:05 +0200 Subject: dt-bindings: mtd: sunxi-nand: Add YAML schemas Switch the DT binding to a YAML schema to enable the DT validation. Reviewed-by: Rob Herring Signed-off-by: Maxime Ripard Signed-off-by: Miquel Raynal --- .../bindings/mtd/allwinner,sun4i-a10-nand.yaml | 96 ++++++++++++++++++++++ .../devicetree/bindings/mtd/sunxi-nand.txt | 48 ----------- 2 files changed, 96 insertions(+), 48 deletions(-) create mode 100644 Documentation/devicetree/bindings/mtd/allwinner,sun4i-a10-nand.yaml delete mode 100644 Documentation/devicetree/bindings/mtd/sunxi-nand.txt diff --git a/Documentation/devicetree/bindings/mtd/allwinner,sun4i-a10-nand.yaml b/Documentation/devicetree/bindings/mtd/allwinner,sun4i-a10-nand.yaml new file mode 100644 index 000000000000..d5834b197e96 --- /dev/null +++ b/Documentation/devicetree/bindings/mtd/allwinner,sun4i-a10-nand.yaml @@ -0,0 +1,96 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/mtd/allwinner,sun4i-a10-nand.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Allwinner A10 NAND Controller Device Tree Bindings + +allOf: + - $ref: "nand-controller.yaml" + +maintainers: + - Chen-Yu Tsai + - Maxime Ripard + +properties: + "#address-cells": true + "#size-cells": true + + compatible: + const: allwinner,sun4i-a10-nand + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + items: + - description: Bus Clock + - description: Module Clock + + clock-names: + items: + - const: ahb + - const: mod + + resets: + maxItems: 1 + + reset-names: + const: ahb + + dmas: + maxItems: 1 + + dma-names: + const: rxtx + + pinctrl-names: true + +patternProperties: + "^pinctrl-[0-9]+$": true + + "^nand@[a-f0-9]+$": + properties: + reg: + maxItems: 1 + minimum: 0 + maximum: 7 + + nand-ecc-mode: true + + nand-ecc-algo: + const: bch + + nand-ecc-step-size: + enum: [ 512, 1024 ] + + nand-ecc-strength: + maximum: 80 + + allwinner,rb: + description: + Contains the native Ready/Busy IDs. + allOf: + - $ref: /schemas/types.yaml#/definitions/uint32-array + - minItems: 1 + maxItems: 2 + items: + minimum: 0 + maximum: 1 + + additionalProperties: false + +required: + - compatible + - reg + - interrupts + - clocks + - clock-names + +additionalProperties: false + +... diff --git a/Documentation/devicetree/bindings/mtd/sunxi-nand.txt b/Documentation/devicetree/bindings/mtd/sunxi-nand.txt deleted file mode 100644 index dcd5a5d80dc0..000000000000 --- a/Documentation/devicetree/bindings/mtd/sunxi-nand.txt +++ /dev/null @@ -1,48 +0,0 @@ -Allwinner NAND Flash Controller (NFC) - -Required properties: -- compatible : "allwinner,sun4i-a10-nand". -- reg : shall contain registers location and length for data and reg. -- interrupts : shall define the nand controller interrupt. -- #address-cells: shall be set to 1. Encode the nand CS. -- #size-cells : shall be set to 0. -- clocks : shall reference nand controller clocks. -- clock-names : nand controller internal clock names. Shall contain : - * "ahb" : AHB gating clock - * "mod" : nand controller clock - -Optional properties: -- dmas : shall reference DMA channel associated to the NAND controller. -- dma-names : shall be "rxtx". - -Optional children nodes: -Children nodes represent the available nand chips. - -Optional properties: -- reset : phandle + reset specifier pair -- reset-names : must contain "ahb" -- allwinner,rb : shall contain the native Ready/Busy ids. -- 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. - - -Examples: -nfc: nand@1c03000 { - compatible = "allwinner,sun4i-a10-nand"; - reg = <0x01c03000 0x1000>; - interrupts = <0 37 1>; - clocks = <&ahb_gates 13>, <&nand_clk>; - clock-names = "ahb", "mod"; - #address-cells = <1>; - #size-cells = <0>; - pinctrl-names = "default"; - pinctrl-0 = <&nand_pins_a &nand_cs0_pins_a &nand_rb0_pins_a>; - - nand@0 { - reg = <0>; - allwinner,rb = <0>; - nand-ecc-mode = "soft_bch"; - }; -}; -- cgit From aee02f82e19a5df848861e0883a394a4996b5bd4 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Mon, 8 Apr 2019 09:41:44 +0200 Subject: dt-bindings: mtd: sunxi: Add new compatible The A23/A33 NAND controller is slightly different than the A10+ ones, eg. DMA handling is a bit different and a few register offsets changed. Introduce a new compatible to represent this version of the IP. Also append '-controller' to the new compatible (which is required for new compatibles) as this is describing a NAND controller and not a NAND chip. Signed-off-by: Miquel Raynal --- Documentation/devicetree/bindings/mtd/allwinner,sun4i-a10-nand.yaml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/mtd/allwinner,sun4i-a10-nand.yaml b/Documentation/devicetree/bindings/mtd/allwinner,sun4i-a10-nand.yaml index d5834b197e96..fbd4da3684fc 100644 --- a/Documentation/devicetree/bindings/mtd/allwinner,sun4i-a10-nand.yaml +++ b/Documentation/devicetree/bindings/mtd/allwinner,sun4i-a10-nand.yaml @@ -18,8 +18,9 @@ properties: "#size-cells": true compatible: - const: allwinner,sun4i-a10-nand - + enum: + - allwinner,sun4i-a10-nand + - allwinner,sun8i-a23-nand-controller reg: maxItems: 1 -- cgit From a760e77d7598986256305e4770609bbfa9a42520 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Mon, 8 Apr 2019 09:41:45 +0200 Subject: mtd: rawnand: sunxi: Add a platform data structure Before the introduction of A33 NAND DMA support, let's use a platform data structure for parameters that will differ. Right now, there is only one compatible with one data structure. Signed-off-by: Miquel Raynal --- drivers/mtd/nand/raw/sunxi_nand.c | 37 ++++++++++++++++++++++++++++++++----- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/drivers/mtd/nand/raw/sunxi_nand.c b/drivers/mtd/nand/raw/sunxi_nand.c index 13f03324d36a..e93f39bc2bc5 100644 --- a/drivers/mtd/nand/raw/sunxi_nand.c +++ b/drivers/mtd/nand/raw/sunxi_nand.c @@ -42,7 +42,7 @@ #define NFC_REG_CMD 0x0024 #define NFC_REG_RCMD_SET 0x0028 #define NFC_REG_WCMD_SET 0x002C -#define NFC_REG_IO_DATA 0x0030 +#define NFC_REG_A10_IO_DATA 0x0030 #define NFC_REG_ECC_CTL 0x0034 #define NFC_REG_ECC_ST 0x0038 #define NFC_REG_DEBUG 0x003C @@ -200,6 +200,18 @@ static inline struct sunxi_nand_chip *to_sunxi_nand(struct nand_chip *nand) return container_of(nand, struct sunxi_nand_chip, nand); } +/* + * NAND Controller capabilities structure: stores NAND controller capabilities + * for distinction between compatible strings. + * + * @reg_io_data: I/O data register + * @dma_maxburst: DMA maxburst + */ +struct sunxi_nfc_caps { + unsigned int reg_io_data; + unsigned int dma_maxburst; +}; + /** * struct sunxi_nfc - stores sunxi NAND controller information * @@ -228,6 +240,7 @@ struct sunxi_nfc { struct list_head chips; struct completion complete; struct dma_chan *dmac; + const struct sunxi_nfc_caps *caps; }; static inline struct sunxi_nfc *to_sunxi_nfc(struct nand_controller *ctrl) @@ -2087,6 +2100,12 @@ static int sunxi_nfc_probe(struct platform_device *pdev) goto out_mod_clk_unprepare; } + nfc->caps = of_device_get_match_data(&pdev->dev); + if (!nfc->caps) { + ret = -EINVAL; + goto out_ahb_reset_reassert; + } + ret = sunxi_nfc_rst(nfc); if (ret) goto out_ahb_reset_reassert; @@ -2101,12 +2120,12 @@ static int sunxi_nfc_probe(struct platform_device *pdev) if (nfc->dmac) { struct dma_slave_config dmac_cfg = { }; - dmac_cfg.src_addr = r->start + NFC_REG_IO_DATA; + dmac_cfg.src_addr = r->start + nfc->caps->reg_io_data; dmac_cfg.dst_addr = dmac_cfg.src_addr; dmac_cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; dmac_cfg.dst_addr_width = dmac_cfg.src_addr_width; - dmac_cfg.src_maxburst = 4; - dmac_cfg.dst_maxburst = 4; + dmac_cfg.src_maxburst = nfc->caps->dma_maxburst; + dmac_cfg.dst_maxburst = nfc->caps->dma_maxburst; dmaengine_slave_config(nfc->dmac, &dmac_cfg); } else { dev_warn(dev, "failed to request rxtx DMA channel\n"); @@ -2151,8 +2170,16 @@ static int sunxi_nfc_remove(struct platform_device *pdev) return 0; } +static const struct sunxi_nfc_caps sunxi_nfc_a10_caps = { + .reg_io_data = NFC_REG_A10_IO_DATA, + .dma_maxburst = 4, +}; + static const struct of_device_id sunxi_nfc_ids[] = { - { .compatible = "allwinner,sun4i-a10-nand" }, + { + .compatible = "allwinner,sun4i-a10-nand", + .data = &sunxi_nfc_a10_caps, + }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, sunxi_nfc_ids); -- cgit From c49836f05aa15282f7280e06ede3f6f8a6324833 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Mon, 8 Apr 2019 09:41:46 +0200 Subject: mtd: rawnand: sunxi: Add A23/A33 DMA support Allwinner NAND controllers can make use of DMA to enhance the I/O throughput thanks to ECC pipelining. DMA handling with A23/A33 NAND IP is a bit different than with the older SoCs, hence the introduction of a new compatible to handle: * the differences between register offsets, * the burst length change from 4 to minimum 8, * drive SRAM accesses through the AHB bus instead of the MBUS. Signed-off-by: Miquel Raynal --- drivers/mtd/nand/raw/sunxi_nand.c | 38 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/nand/raw/sunxi_nand.c b/drivers/mtd/nand/raw/sunxi_nand.c index e93f39bc2bc5..b021a5720b42 100644 --- a/drivers/mtd/nand/raw/sunxi_nand.c +++ b/drivers/mtd/nand/raw/sunxi_nand.c @@ -43,6 +43,7 @@ #define NFC_REG_RCMD_SET 0x0028 #define NFC_REG_WCMD_SET 0x002C #define NFC_REG_A10_IO_DATA 0x0030 +#define NFC_REG_A23_IO_DATA 0x0300 #define NFC_REG_ECC_CTL 0x0034 #define NFC_REG_ECC_ST 0x0038 #define NFC_REG_DEBUG 0x003C @@ -204,10 +205,14 @@ static inline struct sunxi_nand_chip *to_sunxi_nand(struct nand_chip *nand) * NAND Controller capabilities structure: stores NAND controller capabilities * for distinction between compatible strings. * + * @sram_through_ahb: On A23, we choose to access the internal RAM through AHB + * instead of MBUS (less configuration). A10, A10s, A13 and + * A20 use the MBUS but no extra configuration is needed. * @reg_io_data: I/O data register * @dma_maxburst: DMA maxburst */ struct sunxi_nfc_caps { + bool sram_through_ahb; unsigned int reg_io_data; unsigned int dma_maxburst; }; @@ -363,10 +368,29 @@ static int sunxi_nfc_dma_op_prepare(struct sunxi_nfc *nfc, const void *buf, goto err_unmap_buf; } - writel(readl(nfc->regs + NFC_REG_CTL) | NFC_RAM_METHOD, - nfc->regs + NFC_REG_CTL); + /* + * On A23, we suppose the "internal RAM" (p.12 of the NFC user manual) + * refers to the NAND controller's internal SRAM. This memory is mapped + * and so is accessible from the AHB. It seems that it can also be + * accessed by the MBUS. MBUS accesses are mandatory when using the + * internal DMA instead of the external DMA engine. + * + * During DMA I/O operation, either we access this memory from the AHB + * by clearing the NFC_RAM_METHOD bit, or we set the bit and use the + * MBUS. In this case, we should also configure the MBUS DMA length + * NFC_REG_MDMA_CNT(0xC4) to be chunksize * nchunks. NAND I/O over MBUS + * are also limited to 32kiB pages. + */ + if (nfc->caps->sram_through_ahb) + writel(readl(nfc->regs + NFC_REG_CTL) & ~NFC_RAM_METHOD, + nfc->regs + NFC_REG_CTL); + else + writel(readl(nfc->regs + NFC_REG_CTL) | NFC_RAM_METHOD, + nfc->regs + NFC_REG_CTL); + writel(nchunks, nfc->regs + NFC_REG_SECTOR_NUM); writel(chunksize, nfc->regs + NFC_REG_CNT); + dmat = dmaengine_submit(dmad); ret = dma_submit_error(dmat); @@ -2175,11 +2199,21 @@ static const struct sunxi_nfc_caps sunxi_nfc_a10_caps = { .dma_maxburst = 4, }; +static const struct sunxi_nfc_caps sunxi_nfc_a23_caps = { + .sram_through_ahb = true, + .reg_io_data = NFC_REG_A23_IO_DATA, + .dma_maxburst = 8, +}; + static const struct of_device_id sunxi_nfc_ids[] = { { .compatible = "allwinner,sun4i-a10-nand", .data = &sunxi_nfc_a10_caps, }, + { + .compatible = "allwinner,sun8i-a23-nand-controller", + .data = &sunxi_nfc_a23_caps, + }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, sunxi_nfc_ids); -- cgit From 2e16dc73ae65c106ede04dc42f439457b582fc8d Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Mon, 8 Apr 2019 11:28:49 +0200 Subject: mtd: rawnand: marvell: Fix helper name in comment Since the migration of the driver to stop using the legacy ->select_chip() hook, the marvell_nfc_select_chip() helper has been 'renamed' to marvell_nfc_select_target(). Update a left-over reference to this helper in a comment in the ->resume() path. Fixes: b25251414f6e00 ("mtd: rawnand: marvell: Stop implementing ->select_chip()") Signed-off-by: Miquel Raynal Reviewed-by: Boris Brezillon --- drivers/mtd/nand/raw/marvell_nand.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/nand/raw/marvell_nand.c b/drivers/mtd/nand/raw/marvell_nand.c index 825c47b3fa0d..0d29b5d6bcd5 100644 --- a/drivers/mtd/nand/raw/marvell_nand.c +++ b/drivers/mtd/nand/raw/marvell_nand.c @@ -2980,7 +2980,7 @@ static int __maybe_unused marvell_nfc_resume(struct device *dev) /* * Reset nfc->selected_chip so the next command will cause the timing - * registers to be restored in marvell_nfc_select_chip(). + * registers to be restored in marvell_nfc_select_target(). */ nfc->selected_chip = NULL; -- cgit From f56cad5fd6cd876d0cab9d13d9df7bebf6fddf59 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 9 Apr 2019 13:53:32 +0900 Subject: mtd: rawnand: constify elements of NAND_OP_PARSER(_PATTERN) Currently, drivers are able to constify a nand_op_parser array, but not nand_op_parser_pattern and nand_op_parser_pattern_elem since they are instantiated by using the NAND_OP_PARSER(_PATTERN). Add 'const' to them in order to move more driver data from .data to .rodata section. Signed-off-by: Masahiro Yamada Reviewed-by: Boris Brezillon Signed-off-by: Miquel Raynal --- include/linux/mtd/rawnand.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h index 7c0ccd3a2772..39f6c62b0ede 100644 --- a/include/linux/mtd/rawnand.h +++ b/include/linux/mtd/rawnand.h @@ -806,7 +806,7 @@ struct nand_op_parser_pattern { #define NAND_OP_PARSER_PATTERN(_exec, ...) \ { \ .exec = _exec, \ - .elems = (struct nand_op_parser_pattern_elem[]) { __VA_ARGS__ }, \ + .elems = (const struct nand_op_parser_pattern_elem[]) { __VA_ARGS__ }, \ .nelems = sizeof((struct nand_op_parser_pattern_elem[]) { __VA_ARGS__ }) / \ sizeof(struct nand_op_parser_pattern_elem), \ } @@ -832,7 +832,7 @@ struct nand_op_parser { #define NAND_OP_PARSER(...) \ { \ - .patterns = (struct nand_op_parser_pattern[]) { __VA_ARGS__ }, \ + .patterns = (const struct nand_op_parser_pattern[]) { __VA_ARGS__ }, \ .npatterns = sizeof((struct nand_op_parser_pattern[]) { __VA_ARGS__ }) / \ sizeof(struct nand_op_parser_pattern), \ } -- cgit From 5f73f240a4ffe49f596314312f1d3731d011e195 Mon Sep 17 00:00:00 2001 From: Martin Blumenstingl Date: Fri, 12 Apr 2019 00:00:53 +0200 Subject: mtd: rawnand: meson: use struct_size macro Use the recently introduced struct_size macro instead of open-coding it's logic. No functional changes. Signed-off-by: Martin Blumenstingl Tested-by:Liang Yang Acked-by: Liang Yang Signed-off-by: Miquel Raynal --- drivers/mtd/nand/raw/meson_nand.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/mtd/nand/raw/meson_nand.c b/drivers/mtd/nand/raw/meson_nand.c index cb0b03e36a35..c1a6af57dab5 100644 --- a/drivers/mtd/nand/raw/meson_nand.c +++ b/drivers/mtd/nand/raw/meson_nand.c @@ -1242,8 +1242,7 @@ meson_nfc_nand_chip_init(struct device *dev, return -EINVAL; } - meson_chip = devm_kzalloc(dev, - sizeof(*meson_chip) + (nsels * sizeof(u8)), + meson_chip = devm_kzalloc(dev, struct_size(meson_chip, sels, nsels), GFP_KERNEL); if (!meson_chip) return -ENOMEM; -- cgit From 2d8ffbf569440f72b05a16f12453c25195220000 Mon Sep 17 00:00:00 2001 From: Martin Blumenstingl Date: Fri, 12 Apr 2019 00:00:54 +0200 Subject: mtd: rawnand: meson: use of_property_count_elems_of_size helper Use the of_property_count_elems_of_size() helper instead of open-coding it's logic. As a bonus this will now error out if the "reg" property values use an incorrect size (anything other than sizeof(u32)). Signed-off-by: Martin Blumenstingl Tested-by:Liang Yang Acked-by: Liang Yang Signed-off-by: Miquel Raynal --- drivers/mtd/nand/raw/meson_nand.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/mtd/nand/raw/meson_nand.c b/drivers/mtd/nand/raw/meson_nand.c index c1a6af57dab5..9a6023638101 100644 --- a/drivers/mtd/nand/raw/meson_nand.c +++ b/drivers/mtd/nand/raw/meson_nand.c @@ -1233,10 +1233,7 @@ meson_nfc_nand_chip_init(struct device *dev, int ret, i; u32 tmp, nsels; - if (!of_get_property(np, "reg", &nsels)) - return -EINVAL; - - nsels /= sizeof(u32); + nsels = of_property_count_elems_of_size(np, "reg", sizeof(u32)); if (!nsels || nsels > MAX_CE_NUM) { dev_err(dev, "invalid register property size\n"); return -EINVAL; -- cgit From c96ffedf8a2f91c9124012ec4eef42a3da01d08b Mon Sep 17 00:00:00 2001 From: Martin Blumenstingl Date: Fri, 12 Apr 2019 00:00:55 +0200 Subject: mtd: rawnand: meson: use a void pointer for meson_nfc_dma_buffer_setup This simplifies the code because it gets rid of the casts to an u8-pointer when passing "info_buf" from struct meson_nfc_nand_chip. Also it gets rid of the cast of the u8 databuf pointer to a void pointer. The logic inside meson_nfc_dma_buffer_setup() doesn't care about the pointer types themselves because it only passes them to dma_map_single which accepts a void pointer. No functional changes. Signed-off-by: Martin Blumenstingl Tested-by:Liang Yang Acked-by: Liang Yang Tested-by:Liang Yang Acked-by: Liang Yang Tested-by:Liang Yang Acked-by: Liang Yang Signed-off-by: Miquel Raynal --- drivers/mtd/nand/raw/meson_nand.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/mtd/nand/raw/meson_nand.c b/drivers/mtd/nand/raw/meson_nand.c index 9a6023638101..57cc4bd3f665 100644 --- a/drivers/mtd/nand/raw/meson_nand.c +++ b/drivers/mtd/nand/raw/meson_nand.c @@ -470,15 +470,15 @@ static int meson_nfc_ecc_correct(struct nand_chip *nand, u32 *bitflips, return ret; } -static int meson_nfc_dma_buffer_setup(struct nand_chip *nand, u8 *databuf, - int datalen, u8 *infobuf, int infolen, +static int meson_nfc_dma_buffer_setup(struct nand_chip *nand, void *databuf, + int datalen, void *infobuf, int infolen, enum dma_data_direction dir) { struct meson_nfc *nfc = nand_get_controller_data(nand); u32 cmd; int ret = 0; - nfc->daddr = dma_map_single(nfc->dev, (void *)databuf, datalen, dir); + nfc->daddr = dma_map_single(nfc->dev, databuf, datalen, dir); ret = dma_mapping_error(nfc->dev, nfc->daddr); if (ret) { dev_err(nfc->dev, "DMA mapping error\n"); @@ -645,7 +645,7 @@ static int meson_nfc_write_page_sub(struct nand_chip *nand, return ret; ret = meson_nfc_dma_buffer_setup(nand, meson_chip->data_buf, - data_len, (u8 *)meson_chip->info_buf, + data_len, meson_chip->info_buf, info_len, DMA_TO_DEVICE); if (ret) return ret; @@ -729,7 +729,7 @@ static int meson_nfc_read_page_sub(struct nand_chip *nand, return ret; ret = meson_nfc_dma_buffer_setup(nand, meson_chip->data_buf, - data_len, (u8 *)meson_chip->info_buf, + data_len, meson_chip->info_buf, info_len, DMA_FROM_DEVICE); if (ret) return ret; -- cgit From 39e01956e2f70ff9f0e97db1a69c9847aa1d5d8b Mon Sep 17 00:00:00 2001 From: Martin Blumenstingl Date: Fri, 12 Apr 2019 00:00:56 +0200 Subject: mtd: rawnand: meson: only initialize the RB completion once Documentation/scheduler/completion.txt states: Calling init_completion() on the same completion object twice is most likely a bug as it re-initializes the queue to an empty queue and enqueued tasks could get "lost" - use reinit_completion() in that case, but be aware of other races. Initialize nfc->completion in meson_nfc_probe using init_completion and change the call in meson_nfc_queue_rb to reinit_completion so the logic matches what the documentation suggests. Signed-off-by: Martin Blumenstingl Tested-by:Liang Yang Acked-by: Liang Yang Tested-by:Liang Yang Acked-by: Liang Yang Signed-off-by: Miquel Raynal --- drivers/mtd/nand/raw/meson_nand.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/nand/raw/meson_nand.c b/drivers/mtd/nand/raw/meson_nand.c index 57cc4bd3f665..ea57ddcec41e 100644 --- a/drivers/mtd/nand/raw/meson_nand.c +++ b/drivers/mtd/nand/raw/meson_nand.c @@ -400,7 +400,7 @@ static int meson_nfc_queue_rb(struct meson_nfc *nfc, int timeout_ms) cfg |= NFC_RB_IRQ_EN; writel(cfg, nfc->reg_base + NFC_REG_CFG); - init_completion(&nfc->completion); + reinit_completion(&nfc->completion); /* use the max erase time as the maximum clock for waiting R/B */ cmd = NFC_CMD_RB | NFC_CMD_RB_INT @@ -1380,6 +1380,7 @@ static int meson_nfc_probe(struct platform_device *pdev) nand_controller_init(&nfc->controller); INIT_LIST_HEAD(&nfc->chips); + init_completion(&nfc->completion); nfc->dev = dev; -- cgit From 04649ec1335f2289c230f080e52e09f7b9c95c4a Mon Sep 17 00:00:00 2001 From: Frieder Schrempf Date: Wed, 17 Apr 2019 12:36:34 +0000 Subject: mtd: rawnand: Always store info about bad block markers in chip struct The information about where the manufacturer puts the bad block markers inside the bad block and in the OOB data is stored in different places. Let's move this information to nand_chip.options and nand_chip.badblockpos. As this chip-specific information is not directly related to the bad block table (BBT), we also rename the flags to NAND_BBM_*. Signed-off-by: Frieder Schrempf Reviewed-by: Miquel Raynal Signed-off-by: Miquel Raynal --- drivers/mtd/nand/raw/nand_amd.c | 2 +- drivers/mtd/nand/raw/nand_base.c | 12 ++++++------ drivers/mtd/nand/raw/nand_bbt.c | 4 ++-- drivers/mtd/nand/raw/nand_esmt.c | 2 +- drivers/mtd/nand/raw/nand_hynix.c | 4 ++-- drivers/mtd/nand/raw/nand_macronix.c | 2 +- drivers/mtd/nand/raw/nand_micron.c | 2 +- drivers/mtd/nand/raw/nand_samsung.c | 4 ++-- drivers/mtd/nand/raw/nand_toshiba.c | 2 +- drivers/mtd/nand/raw/sh_flctl.c | 4 ++-- include/linux/mtd/rawnand.h | 16 +++++++++++++++- 11 files changed, 34 insertions(+), 20 deletions(-) diff --git a/drivers/mtd/nand/raw/nand_amd.c b/drivers/mtd/nand/raw/nand_amd.c index e008fd662ee6..9051e4e41eee 100644 --- a/drivers/mtd/nand/raw/nand_amd.c +++ b/drivers/mtd/nand/raw/nand_amd.c @@ -45,7 +45,7 @@ static void amd_nand_decode_id(struct nand_chip *chip) static int amd_nand_init(struct nand_chip *chip) { if (nand_is_slc(chip)) - chip->bbt_options |= NAND_BBT_SCAN2NDPAGE; + chip->options |= NAND_BBM_SECONDPAGE; return 0; } diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c index fd7ce5b929c0..e1111291389a 100644 --- a/drivers/mtd/nand/raw/nand_base.c +++ b/drivers/mtd/nand/raw/nand_base.c @@ -295,11 +295,11 @@ static int nand_block_bad(struct nand_chip *chip, loff_t ofs) int page, page_end, res; u8 bad; - if (chip->bbt_options & NAND_BBT_SCANLASTPAGE) + if (chip->options & NAND_BBM_LASTPAGE) ofs += mtd->erasesize - mtd->writesize; page = (int)(ofs >> chip->page_shift) & chip->pagemask; - page_end = page + (chip->bbt_options & NAND_BBT_SCAN2NDPAGE ? 2 : 1); + page_end = page + ((chip->options & NAND_BBM_SECONDPAGE) ? 2 : 1); for (; page < page_end; page++) { res = chip->ecc.read_oob(chip, page); @@ -507,7 +507,7 @@ static int nand_default_block_markbad(struct nand_chip *chip, loff_t ofs) ops.mode = MTD_OPS_PLACE_OOB; /* Write to first/last page(s) if necessary */ - if (chip->bbt_options & NAND_BBT_SCANLASTPAGE) + if (chip->options & NAND_BBM_LASTPAGE) ofs += mtd->erasesize - mtd->writesize; do { res = nand_do_write_oob(chip, ofs, &ops); @@ -516,7 +516,7 @@ static int nand_default_block_markbad(struct nand_chip *chip, loff_t ofs) i++; ofs += mtd->writesize; - } while ((chip->bbt_options & NAND_BBT_SCAN2NDPAGE) && i < 2); + } while ((chip->options & NAND_BBM_SECONDPAGE) && i < 2); return ret; } @@ -4513,9 +4513,9 @@ static void nand_decode_bbm_options(struct nand_chip *chip) /* Set the bad block position */ if (mtd->writesize > 512 || (chip->options & NAND_BUSWIDTH_16)) - chip->badblockpos = NAND_LARGE_BADBLOCK_POS; + chip->badblockpos = NAND_BBM_POS_LARGE; else - chip->badblockpos = NAND_SMALL_BADBLOCK_POS; + chip->badblockpos = NAND_BBM_POS_SMALL; } static inline bool is_full_id_nand(struct nand_flash_dev *type) diff --git a/drivers/mtd/nand/raw/nand_bbt.c b/drivers/mtd/nand/raw/nand_bbt.c index 9a7855839f81..4915dd7283bb 100644 --- a/drivers/mtd/nand/raw/nand_bbt.c +++ b/drivers/mtd/nand/raw/nand_bbt.c @@ -468,7 +468,7 @@ static int create_bbt(struct nand_chip *this, uint8_t *buf, pr_info("Scanning device for bad blocks\n"); - if (bd->options & NAND_BBT_SCAN2NDPAGE) + if (this->options & NAND_BBM_SECONDPAGE) numpages = 2; else numpages = 1; @@ -489,7 +489,7 @@ static int create_bbt(struct nand_chip *this, uint8_t *buf, from = (loff_t)startblock << this->bbt_erase_shift; } - if (this->bbt_options & NAND_BBT_SCANLASTPAGE) + if (this->options & NAND_BBM_LASTPAGE) from += mtd->erasesize - (mtd->writesize * numpages); for (i = startblock; i < numblocks; i++) { diff --git a/drivers/mtd/nand/raw/nand_esmt.c b/drivers/mtd/nand/raw/nand_esmt.c index 3de5e89482f5..4320d4c6a7cd 100644 --- a/drivers/mtd/nand/raw/nand_esmt.c +++ b/drivers/mtd/nand/raw/nand_esmt.c @@ -36,7 +36,7 @@ static void esmt_nand_decode_id(struct nand_chip *chip) static int esmt_nand_init(struct nand_chip *chip) { if (nand_is_slc(chip)) - chip->bbt_options |= NAND_BBT_SCAN2NDPAGE; + chip->options |= NAND_BBM_SECONDPAGE; return 0; } diff --git a/drivers/mtd/nand/raw/nand_hynix.c b/drivers/mtd/nand/raw/nand_hynix.c index 821d221b83eb..33cb10df65b8 100644 --- a/drivers/mtd/nand/raw/nand_hynix.c +++ b/drivers/mtd/nand/raw/nand_hynix.c @@ -688,9 +688,9 @@ static int hynix_nand_init(struct nand_chip *chip) int ret; if (!nand_is_slc(chip)) - chip->bbt_options |= NAND_BBT_SCANLASTPAGE; + chip->options |= NAND_BBM_LASTPAGE; else - chip->bbt_options |= NAND_BBT_SCAN2NDPAGE; + chip->options |= NAND_BBM_SECONDPAGE; hynix = kzalloc(sizeof(*hynix), GFP_KERNEL); if (!hynix) diff --git a/drivers/mtd/nand/raw/nand_macronix.c b/drivers/mtd/nand/raw/nand_macronix.c index 47d8cda547cf..6db7ced4b96b 100644 --- a/drivers/mtd/nand/raw/nand_macronix.c +++ b/drivers/mtd/nand/raw/nand_macronix.c @@ -62,7 +62,7 @@ static void macronix_nand_fix_broken_get_timings(struct nand_chip *chip) static int macronix_nand_init(struct nand_chip *chip) { if (nand_is_slc(chip)) - chip->bbt_options |= NAND_BBT_SCAN2NDPAGE; + chip->options |= NAND_BBM_SECONDPAGE; macronix_nand_fix_broken_get_timings(chip); diff --git a/drivers/mtd/nand/raw/nand_micron.c b/drivers/mtd/nand/raw/nand_micron.c index 7a2cef02eacd..d43e15772f73 100644 --- a/drivers/mtd/nand/raw/nand_micron.c +++ b/drivers/mtd/nand/raw/nand_micron.c @@ -448,7 +448,7 @@ static int micron_nand_init(struct nand_chip *chip) goto err_free_manuf_data; if (mtd->writesize == 2048) - chip->bbt_options |= NAND_BBT_SCAN2NDPAGE; + chip->options |= NAND_BBM_SECONDPAGE; ondie = micron_supports_on_die_ecc(chip); diff --git a/drivers/mtd/nand/raw/nand_samsung.c b/drivers/mtd/nand/raw/nand_samsung.c index f7d7041b6213..f4db72329b7b 100644 --- a/drivers/mtd/nand/raw/nand_samsung.c +++ b/drivers/mtd/nand/raw/nand_samsung.c @@ -131,9 +131,9 @@ static int samsung_nand_init(struct nand_chip *chip) chip->options |= NAND_SAMSUNG_LP_OPTIONS; if (!nand_is_slc(chip)) - chip->bbt_options |= NAND_BBT_SCANLASTPAGE; + chip->options |= NAND_BBM_LASTPAGE; else - chip->bbt_options |= NAND_BBT_SCAN2NDPAGE; + chip->options |= NAND_BBM_SECONDPAGE; return 0; } diff --git a/drivers/mtd/nand/raw/nand_toshiba.c b/drivers/mtd/nand/raw/nand_toshiba.c index 13f9632f1cb4..67f01cef5651 100644 --- a/drivers/mtd/nand/raw/nand_toshiba.c +++ b/drivers/mtd/nand/raw/nand_toshiba.c @@ -152,7 +152,7 @@ static void toshiba_nand_decode_id(struct nand_chip *chip) static int toshiba_nand_init(struct nand_chip *chip) { if (nand_is_slc(chip)) - chip->bbt_options |= NAND_BBT_SCAN2NDPAGE; + chip->options |= NAND_BBM_SECONDPAGE; /* Check that chip is BENAND and ECC mode is on-die */ if (nand_is_slc(chip) && chip->ecc.mode == NAND_ECC_ON_DIE && diff --git a/drivers/mtd/nand/raw/sh_flctl.c b/drivers/mtd/nand/raw/sh_flctl.c index 3f610040f0c3..02a6768ab13f 100644 --- a/drivers/mtd/nand/raw/sh_flctl.c +++ b/drivers/mtd/nand/raw/sh_flctl.c @@ -101,14 +101,12 @@ static const struct mtd_ooblayout_ops flctl_4secc_oob_largepage_ops = { static uint8_t scan_ff_pattern[] = { 0xff, 0xff }; static struct nand_bbt_descr flctl_4secc_smallpage = { - .options = NAND_BBT_SCAN2NDPAGE, .offs = 11, .len = 1, .pattern = scan_ff_pattern, }; static struct nand_bbt_descr flctl_4secc_largepage = { - .options = NAND_BBT_SCAN2NDPAGE, .offs = 0, .len = 2, .pattern = scan_ff_pattern, @@ -1179,6 +1177,8 @@ static int flctl_probe(struct platform_device *pdev) if (pdata->flcmncr_val & SEL_16BIT) nand->options |= NAND_BUSWIDTH_16; + nand->options |= NAND_BBM_SECONDPAGE; + pm_runtime_enable(&pdev->dev); pm_runtime_resume(&pdev->dev); diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h index 39f6c62b0ede..8b3e28ef75ce 100644 --- a/include/linux/mtd/rawnand.h +++ b/include/linux/mtd/rawnand.h @@ -169,6 +169,20 @@ enum nand_ecc_algo { /* Macros to identify the above */ #define NAND_HAS_SUBPAGE_READ(chip) ((chip->options & NAND_SUBPAGE_READ)) +/* + * There are different places where the manufacturer stores the factory bad + * block markers. + * + * Position within the block: Each of these pages needs to be checked for a + * bad block marking pattern. + */ +#define NAND_BBM_SECONDPAGE 0x02000000 +#define NAND_BBM_LASTPAGE 0x04000000 + +/* Position within the OOB data of the page */ +#define NAND_BBM_POS_SMALL 5 +#define NAND_BBM_POS_LARGE 0 + /* Non chip related options */ /* This option skips the bbt scan during initialization. */ #define NAND_SKIP_BBTSCAN 0x00010000 @@ -1055,7 +1069,7 @@ struct nand_chip { int subpagesize; int onfi_timing_mode_default; - int badblockpos; + unsigned int badblockpos; int badblockbits; struct nand_id id; -- cgit From bfd15c904ac584dfacfafb1e382c158f6db73d2a Mon Sep 17 00:00:00 2001 From: Frieder Schrempf Date: Wed, 17 Apr 2019 12:36:35 +0000 Subject: mtd: onenand: Store bad block marker position in chip struct The information about where the manufacturer puts the bad block markers inside the bad block and in the OOB data is stored in different places. Let's move this information to the chip struct, as we did it for rawnand. Signed-off-by: Frieder Schrempf Reviewed-by: Miquel Raynal Signed-off-by: Miquel Raynal --- drivers/mtd/nand/onenand/onenand_base.c | 5 ++++- drivers/mtd/nand/onenand/onenand_bbt.c | 3 --- include/linux/mtd/onenand.h | 3 +++ 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/mtd/nand/onenand/onenand_base.c b/drivers/mtd/nand/onenand/onenand_base.c index 4ca4b194e7d7..f41d76248550 100644 --- a/drivers/mtd/nand/onenand/onenand_base.c +++ b/drivers/mtd/nand/onenand/onenand_base.c @@ -2458,7 +2458,7 @@ static int onenand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) bbm->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1); /* We write two bytes, so we don't have to mess with 16-bit access */ - ofs += mtd->oobsize + (bbm->badblockpos & ~0x01); + ofs += mtd->oobsize + (this->badblockpos & ~0x01); /* FIXME : What to do when marking SLC block in partition * with MLC erasesize? For now, it is not advisable to * create partitions containing both SLC and MLC regions. @@ -3967,6 +3967,9 @@ int onenand_scan(struct mtd_info *mtd, int maxchips) if (!(this->options & ONENAND_SKIP_INITIAL_UNLOCKING)) this->unlock_all(mtd); + /* Set the bad block marker position */ + this->badblockpos = ONENAND_BADBLOCK_POS; + ret = this->scan_bbt(mtd); if ((!FLEXONENAND(this)) || ret) return ret; diff --git a/drivers/mtd/nand/onenand/onenand_bbt.c b/drivers/mtd/nand/onenand/onenand_bbt.c index dde20487937d..57c31c81be18 100644 --- a/drivers/mtd/nand/onenand/onenand_bbt.c +++ b/drivers/mtd/nand/onenand/onenand_bbt.c @@ -190,9 +190,6 @@ static int onenand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd) if (!bbm->bbt) return -ENOMEM; - /* Set the bad block position */ - bbm->badblockpos = ONENAND_BADBLOCK_POS; - /* Set erase shift */ bbm->bbt_erase_shift = this->erase_shift; diff --git a/include/linux/mtd/onenand.h b/include/linux/mtd/onenand.h index 0aaa98b219a4..bfe9e10fae04 100644 --- a/include/linux/mtd/onenand.h +++ b/include/linux/mtd/onenand.h @@ -94,6 +94,7 @@ struct onenand_chip { unsigned int technology; unsigned int density_mask; unsigned int options; + unsigned int badblockpos; unsigned int erase_shift; unsigned int page_shift; @@ -188,6 +189,8 @@ struct onenand_chip { /* Check byte access in OneNAND */ #define ONENAND_CHECK_BYTE_ACCESS(addr) (addr & 0x1) +#define ONENAND_BADBLOCK_POS 0 + /* * Options bits */ -- cgit From c902467cda2d927dba0d6bd2c2efc1988720b8d6 Mon Sep 17 00:00:00 2001 From: Frieder Schrempf Date: Wed, 17 Apr 2019 12:36:35 +0000 Subject: mtd: nand: Cleanup flags and fields for bad block marker position Now that we have moved the information to the chip level, let's remove all the unused flags and fields. Signed-off-by: Frieder Schrempf Reviewed-by: Miquel Raynal Signed-off-by: Miquel Raynal --- include/linux/mtd/bbm.h | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/include/linux/mtd/bbm.h b/include/linux/mtd/bbm.h index 3102bd754d18..010bc5544c54 100644 --- a/include/linux/mtd/bbm.h +++ b/include/linux/mtd/bbm.h @@ -93,10 +93,7 @@ struct nand_bbt_descr { #define NAND_BBT_WRITE 0x00002000 /* Read and write back block contents when writing bbt */ #define NAND_BBT_SAVECONTENT 0x00004000 -/* Search good / bad pattern on the first and the second page */ -#define NAND_BBT_SCAN2NDPAGE 0x00008000 -/* Search good / bad pattern on the last page of the eraseblock */ -#define NAND_BBT_SCANLASTPAGE 0x00010000 + /* * Use a flash based bad block table. By default, OOB identifier is saved in * OOB area. This option is passed to the default bad block table function. @@ -123,13 +120,6 @@ struct nand_bbt_descr { /* The maximum number of blocks to scan for a bbt */ #define NAND_BBT_SCAN_MAXBLOCKS 4 -/* - * Constants for oob configuration - */ -#define NAND_SMALL_BADBLOCK_POS 5 -#define NAND_LARGE_BADBLOCK_POS 0 -#define ONENAND_BADBLOCK_POS 0 - /* * Bad block scanning errors */ @@ -140,7 +130,6 @@ struct nand_bbt_descr { /** * struct bbm_info - [GENERIC] Bad Block Table data structure * @bbt_erase_shift: [INTERN] number of address bits in a bbt entry - * @badblockpos: [INTERN] position of the bad block marker in the oob area * @options: options for this descriptor * @bbt: [INTERN] bad block table pointer * @isbad_bbt: function to determine if a block is bad @@ -150,7 +139,6 @@ struct nand_bbt_descr { */ struct bbm_info { int bbt_erase_shift; - int badblockpos; int options; uint8_t *bbt; -- cgit From bb5925480b13f52ad2e29ab20695c7f27e10f382 Mon Sep 17 00:00:00 2001 From: Frieder Schrempf Date: Wed, 17 Apr 2019 12:36:36 +0000 Subject: mtd: nand: Make flags for bad block marker position more granular To be able to check and set bad block markers in the first and second page of a block independently of each other, we create separate flags for both cases. Previously NAND_BBM_SECONDPAGE meant, that both, the first and the second page were used. With this patch NAND_BBM_FIRSTPAGE stands for using the first page and NAND_BBM_SECONDPAGE for using the second page. This patch is only for preparation of subsequent changes and does not implement the logic to actually handle both flags separately. Signed-off-by: Frieder Schrempf Reviewed-by: Boris Brezillon Reviewed-by: Miquel Raynal Signed-off-by: Miquel Raynal --- drivers/mtd/nand/raw/nand_amd.c | 2 +- drivers/mtd/nand/raw/nand_base.c | 6 ++++-- drivers/mtd/nand/raw/nand_bbt.c | 3 ++- drivers/mtd/nand/raw/nand_esmt.c | 2 +- drivers/mtd/nand/raw/nand_hynix.c | 2 +- drivers/mtd/nand/raw/nand_macronix.c | 2 +- drivers/mtd/nand/raw/nand_micron.c | 2 +- drivers/mtd/nand/raw/nand_samsung.c | 2 +- drivers/mtd/nand/raw/nand_toshiba.c | 2 +- drivers/mtd/nand/raw/sh_flctl.c | 2 +- include/linux/mtd/rawnand.h | 1 + 11 files changed, 15 insertions(+), 11 deletions(-) diff --git a/drivers/mtd/nand/raw/nand_amd.c b/drivers/mtd/nand/raw/nand_amd.c index 9051e4e41eee..1417559d3057 100644 --- a/drivers/mtd/nand/raw/nand_amd.c +++ b/drivers/mtd/nand/raw/nand_amd.c @@ -45,7 +45,7 @@ static void amd_nand_decode_id(struct nand_chip *chip) static int amd_nand_init(struct nand_chip *chip) { if (nand_is_slc(chip)) - chip->options |= NAND_BBM_SECONDPAGE; + chip->options |= NAND_BBM_FIRSTPAGE | NAND_BBM_SECONDPAGE; return 0; } diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c index e1111291389a..6e2d728d2fd9 100644 --- a/drivers/mtd/nand/raw/nand_base.c +++ b/drivers/mtd/nand/raw/nand_base.c @@ -299,7 +299,8 @@ static int nand_block_bad(struct nand_chip *chip, loff_t ofs) ofs += mtd->erasesize - mtd->writesize; page = (int)(ofs >> chip->page_shift) & chip->pagemask; - page_end = page + ((chip->options & NAND_BBM_SECONDPAGE) ? 2 : 1); + page_end = page + (((chip->options & NAND_BBM_FIRSTPAGE) && + (chip->options & NAND_BBM_SECONDPAGE)) ? 2 : 1); for (; page < page_end; page++) { res = chip->ecc.read_oob(chip, page); @@ -516,7 +517,8 @@ static int nand_default_block_markbad(struct nand_chip *chip, loff_t ofs) i++; ofs += mtd->writesize; - } while ((chip->options & NAND_BBM_SECONDPAGE) && i < 2); + } while ((chip->options & NAND_BBM_FIRSTPAGE) && + (chip->options & NAND_BBM_SECONDPAGE) && i < 2); return ret; } diff --git a/drivers/mtd/nand/raw/nand_bbt.c b/drivers/mtd/nand/raw/nand_bbt.c index 4915dd7283bb..4cb664847ef5 100644 --- a/drivers/mtd/nand/raw/nand_bbt.c +++ b/drivers/mtd/nand/raw/nand_bbt.c @@ -468,7 +468,8 @@ static int create_bbt(struct nand_chip *this, uint8_t *buf, pr_info("Scanning device for bad blocks\n"); - if (this->options & NAND_BBM_SECONDPAGE) + if ((this->options & NAND_BBM_FIRSTPAGE) && + (this->options & NAND_BBM_SECONDPAGE)) numpages = 2; else numpages = 1; diff --git a/drivers/mtd/nand/raw/nand_esmt.c b/drivers/mtd/nand/raw/nand_esmt.c index 4320d4c6a7cd..58646ed663ac 100644 --- a/drivers/mtd/nand/raw/nand_esmt.c +++ b/drivers/mtd/nand/raw/nand_esmt.c @@ -36,7 +36,7 @@ static void esmt_nand_decode_id(struct nand_chip *chip) static int esmt_nand_init(struct nand_chip *chip) { if (nand_is_slc(chip)) - chip->options |= NAND_BBM_SECONDPAGE; + chip->options |= NAND_BBM_FIRSTPAGE | NAND_BBM_SECONDPAGE; return 0; } diff --git a/drivers/mtd/nand/raw/nand_hynix.c b/drivers/mtd/nand/raw/nand_hynix.c index 33cb10df65b8..7c600c4d5ec8 100644 --- a/drivers/mtd/nand/raw/nand_hynix.c +++ b/drivers/mtd/nand/raw/nand_hynix.c @@ -690,7 +690,7 @@ static int hynix_nand_init(struct nand_chip *chip) if (!nand_is_slc(chip)) chip->options |= NAND_BBM_LASTPAGE; else - chip->options |= NAND_BBM_SECONDPAGE; + chip->options |= NAND_BBM_FIRSTPAGE | NAND_BBM_SECONDPAGE; hynix = kzalloc(sizeof(*hynix), GFP_KERNEL); if (!hynix) diff --git a/drivers/mtd/nand/raw/nand_macronix.c b/drivers/mtd/nand/raw/nand_macronix.c index 6db7ced4b96b..e287e71347c5 100644 --- a/drivers/mtd/nand/raw/nand_macronix.c +++ b/drivers/mtd/nand/raw/nand_macronix.c @@ -62,7 +62,7 @@ static void macronix_nand_fix_broken_get_timings(struct nand_chip *chip) static int macronix_nand_init(struct nand_chip *chip) { if (nand_is_slc(chip)) - chip->options |= NAND_BBM_SECONDPAGE; + chip->options |= NAND_BBM_FIRSTPAGE | NAND_BBM_SECONDPAGE; macronix_nand_fix_broken_get_timings(chip); diff --git a/drivers/mtd/nand/raw/nand_micron.c b/drivers/mtd/nand/raw/nand_micron.c index d43e15772f73..cbd4f09ac178 100644 --- a/drivers/mtd/nand/raw/nand_micron.c +++ b/drivers/mtd/nand/raw/nand_micron.c @@ -448,7 +448,7 @@ static int micron_nand_init(struct nand_chip *chip) goto err_free_manuf_data; if (mtd->writesize == 2048) - chip->options |= NAND_BBM_SECONDPAGE; + chip->options |= NAND_BBM_FIRSTPAGE | NAND_BBM_SECONDPAGE; ondie = micron_supports_on_die_ecc(chip); diff --git a/drivers/mtd/nand/raw/nand_samsung.c b/drivers/mtd/nand/raw/nand_samsung.c index f4db72329b7b..5552ce20ede0 100644 --- a/drivers/mtd/nand/raw/nand_samsung.c +++ b/drivers/mtd/nand/raw/nand_samsung.c @@ -133,7 +133,7 @@ static int samsung_nand_init(struct nand_chip *chip) if (!nand_is_slc(chip)) chip->options |= NAND_BBM_LASTPAGE; else - chip->options |= NAND_BBM_SECONDPAGE; + chip->options |= NAND_BBM_FIRSTPAGE | NAND_BBM_SECONDPAGE; return 0; } diff --git a/drivers/mtd/nand/raw/nand_toshiba.c b/drivers/mtd/nand/raw/nand_toshiba.c index 67f01cef5651..74ffcae48726 100644 --- a/drivers/mtd/nand/raw/nand_toshiba.c +++ b/drivers/mtd/nand/raw/nand_toshiba.c @@ -152,7 +152,7 @@ static void toshiba_nand_decode_id(struct nand_chip *chip) static int toshiba_nand_init(struct nand_chip *chip) { if (nand_is_slc(chip)) - chip->options |= NAND_BBM_SECONDPAGE; + chip->options |= NAND_BBM_FIRSTPAGE | NAND_BBM_SECONDPAGE; /* Check that chip is BENAND and ECC mode is on-die */ if (nand_is_slc(chip) && chip->ecc.mode == NAND_ECC_ON_DIE && diff --git a/drivers/mtd/nand/raw/sh_flctl.c b/drivers/mtd/nand/raw/sh_flctl.c index 02a6768ab13f..e509c93737c4 100644 --- a/drivers/mtd/nand/raw/sh_flctl.c +++ b/drivers/mtd/nand/raw/sh_flctl.c @@ -1177,7 +1177,7 @@ static int flctl_probe(struct platform_device *pdev) if (pdata->flcmncr_val & SEL_16BIT) nand->options |= NAND_BUSWIDTH_16; - nand->options |= NAND_BBM_SECONDPAGE; + nand->options |= NAND_BBM_FIRSTPAGE | NAND_BBM_SECONDPAGE; pm_runtime_enable(&pdev->dev); pm_runtime_resume(&pdev->dev); diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h index 8b3e28ef75ce..dbfffa5bec7b 100644 --- a/include/linux/mtd/rawnand.h +++ b/include/linux/mtd/rawnand.h @@ -176,6 +176,7 @@ enum nand_ecc_algo { * Position within the block: Each of these pages needs to be checked for a * bad block marking pattern. */ +#define NAND_BBM_FIRSTPAGE 0x01000000 #define NAND_BBM_SECONDPAGE 0x02000000 #define NAND_BBM_LASTPAGE 0x04000000 -- cgit From f90da7818b141e856b723085328d23b36351849d Mon Sep 17 00:00:00 2001 From: Frieder Schrempf Date: Wed, 17 Apr 2019 12:36:37 +0000 Subject: mtd: rawnand: Support bad block markers in first, second or last page Currently supported bad block marker positions within the block are: * in first page only * in last page only * in first or second page Some ESMT NANDs are known to have been shipped by the manufacturer with bad block markers in the first or last page, instead of the first or second page. Also the datasheets for Cypress/Spansion/AMD NANDs claim that the first, second *and* last page needs to be checked. Therefore we make it possible to set NAND_BBM_FIRSTPAGE, NAND_BBM_SECONDPAGE and NAND_BBM_LASTPAGE independently in any combination. To simplify the code, the logic to evaluate the flags is moved to a a new function nand_bbm_get_next_page(). Signed-off-by: Frieder Schrempf Reviewed-by: Boris Brezillon Signed-off-by: Miquel Raynal --- drivers/mtd/nand/raw/internals.h | 1 + drivers/mtd/nand/raw/nand_base.c | 63 +++++++++++++++++++++++++++------------- drivers/mtd/nand/raw/nand_bbt.c | 29 ++++++++---------- 3 files changed, 56 insertions(+), 37 deletions(-) diff --git a/drivers/mtd/nand/raw/internals.h b/drivers/mtd/nand/raw/internals.h index a204f9d7e123..cba6fe7dd8c4 100644 --- a/drivers/mtd/nand/raw/internals.h +++ b/drivers/mtd/nand/raw/internals.h @@ -76,6 +76,7 @@ extern const struct nand_manufacturer_ops toshiba_nand_manuf_ops; /* Core functions */ const struct nand_manufacturer *nand_get_manufacturer(u8 id); +int nand_bbm_get_next_page(struct nand_chip *chip, int page); int nand_markbad_bbm(struct nand_chip *chip, loff_t ofs); int nand_erase_nand(struct nand_chip *chip, struct erase_info *instr, int allowbbt); diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c index 6e2d728d2fd9..2cf71060d6f8 100644 --- a/drivers/mtd/nand/raw/nand_base.c +++ b/drivers/mtd/nand/raw/nand_base.c @@ -282,6 +282,31 @@ static void nand_release_device(struct nand_chip *chip) mutex_unlock(&chip->lock); } +/** + * nand_bbm_get_next_page - Get the next page for bad block markers + * @chip: NAND chip object + * @page: First page to start checking for bad block marker usage + * + * Returns an integer that corresponds to the page offset within a block, for + * a page that is used to store bad block markers. If no more pages are + * available, -EINVAL is returned. + */ +int nand_bbm_get_next_page(struct nand_chip *chip, int page) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + int last_page = ((mtd->erasesize - mtd->writesize) >> + chip->page_shift) & chip->pagemask; + + if (page == 0 && chip->options & NAND_BBM_FIRSTPAGE) + return 0; + else if (page <= 1 && chip->options & NAND_BBM_SECONDPAGE) + return 1; + else if (page <= last_page && chip->options & NAND_BBM_LASTPAGE) + return last_page; + + return -EINVAL; +} + /** * nand_block_bad - [DEFAULT] Read bad block marker from the chip * @chip: NAND chip object @@ -291,19 +316,15 @@ static void nand_release_device(struct nand_chip *chip) */ static int nand_block_bad(struct nand_chip *chip, loff_t ofs) { - struct mtd_info *mtd = nand_to_mtd(chip); - int page, page_end, res; + int first_page, page_offset; + int res; u8 bad; - if (chip->options & NAND_BBM_LASTPAGE) - ofs += mtd->erasesize - mtd->writesize; + first_page = (int)(ofs >> chip->page_shift) & chip->pagemask; + page_offset = nand_bbm_get_next_page(chip, 0); - page = (int)(ofs >> chip->page_shift) & chip->pagemask; - page_end = page + (((chip->options & NAND_BBM_FIRSTPAGE) && - (chip->options & NAND_BBM_SECONDPAGE)) ? 2 : 1); - - for (; page < page_end; page++) { - res = chip->ecc.read_oob(chip, page); + while (page_offset >= 0) { + res = chip->ecc.read_oob(chip, first_page + page_offset); if (res < 0) return res; @@ -315,6 +336,8 @@ static int nand_block_bad(struct nand_chip *chip, loff_t ofs) res = hweight8(bad) < chip->badblockbits; if (res) return res; + + page_offset = nand_bbm_get_next_page(chip, page_offset + 1); } return 0; @@ -494,7 +517,7 @@ static int nand_default_block_markbad(struct nand_chip *chip, loff_t ofs) struct mtd_info *mtd = nand_to_mtd(chip); struct mtd_oob_ops ops; uint8_t buf[2] = { 0, 0 }; - int ret = 0, res, i = 0; + int ret = 0, res, page_offset; memset(&ops, 0, sizeof(ops)); ops.oobbuf = buf; @@ -507,18 +530,18 @@ static int nand_default_block_markbad(struct nand_chip *chip, loff_t ofs) } ops.mode = MTD_OPS_PLACE_OOB; - /* Write to first/last page(s) if necessary */ - if (chip->options & NAND_BBM_LASTPAGE) - ofs += mtd->erasesize - mtd->writesize; - do { - res = nand_do_write_oob(chip, ofs, &ops); + page_offset = nand_bbm_get_next_page(chip, 0); + + while (page_offset >= 0) { + res = nand_do_write_oob(chip, + ofs + (page_offset * mtd->writesize), + &ops); + if (!ret) ret = res; - i++; - ofs += mtd->writesize; - } while ((chip->options & NAND_BBM_FIRSTPAGE) && - (chip->options & NAND_BBM_SECONDPAGE) && i < 2); + page_offset = nand_bbm_get_next_page(chip, page_offset + 1); + } return ret; } diff --git a/drivers/mtd/nand/raw/nand_bbt.c b/drivers/mtd/nand/raw/nand_bbt.c index 4cb664847ef5..fd3c10216eda 100644 --- a/drivers/mtd/nand/raw/nand_bbt.c +++ b/drivers/mtd/nand/raw/nand_bbt.c @@ -416,11 +416,12 @@ static void read_abs_bbts(struct nand_chip *this, uint8_t *buf, /* Scan a given block partially */ static int scan_block_fast(struct nand_chip *this, struct nand_bbt_descr *bd, - loff_t offs, uint8_t *buf, int numpages) + loff_t offs, uint8_t *buf) { struct mtd_info *mtd = nand_to_mtd(this); + struct mtd_oob_ops ops; - int j, ret; + int ret, page_offset; ops.ooblen = mtd->oobsize; ops.oobbuf = buf; @@ -428,12 +429,15 @@ static int scan_block_fast(struct nand_chip *this, struct nand_bbt_descr *bd, ops.datbuf = NULL; ops.mode = MTD_OPS_PLACE_OOB; - for (j = 0; j < numpages; j++) { + page_offset = nand_bbm_get_next_page(this, 0); + + while (page_offset >= 0) { /* * Read the full oob until read_oob is fixed to handle single * byte reads for 16 bit buswidth. */ - ret = mtd_read_oob(mtd, offs, &ops); + ret = mtd_read_oob(mtd, offs + (page_offset * mtd->writesize), + &ops); /* Ignore ECC errors when checking for BBM */ if (ret && !mtd_is_bitflip_or_eccerr(ret)) return ret; @@ -441,8 +445,9 @@ static int scan_block_fast(struct nand_chip *this, struct nand_bbt_descr *bd, if (check_short_pattern(buf, bd)) return 1; - offs += mtd->writesize; + page_offset = nand_bbm_get_next_page(this, page_offset + 1); } + return 0; } @@ -462,18 +467,11 @@ static int create_bbt(struct nand_chip *this, uint8_t *buf, { u64 targetsize = nanddev_target_size(&this->base); struct mtd_info *mtd = nand_to_mtd(this); - int i, numblocks, numpages; - int startblock; + int i, numblocks, startblock; loff_t from; pr_info("Scanning device for bad blocks\n"); - if ((this->options & NAND_BBM_FIRSTPAGE) && - (this->options & NAND_BBM_SECONDPAGE)) - numpages = 2; - else - numpages = 1; - if (chip == -1) { numblocks = mtd->size >> this->bbt_erase_shift; startblock = 0; @@ -490,15 +488,12 @@ static int create_bbt(struct nand_chip *this, uint8_t *buf, from = (loff_t)startblock << this->bbt_erase_shift; } - if (this->options & NAND_BBM_LASTPAGE) - from += mtd->erasesize - (mtd->writesize * numpages); - for (i = startblock; i < numblocks; i++) { int ret; BUG_ON(bd->options & NAND_BBT_NO_OOB); - ret = scan_block_fast(this, bd, from, buf, numpages); + ret = scan_block_fast(this, bd, from, buf); if (ret < 0) return ret; -- cgit From 7a1894a955cc3bf0be0851421d6603c3b5c78323 Mon Sep 17 00:00:00 2001 From: Frieder Schrempf Date: Wed, 17 Apr 2019 12:36:37 +0000 Subject: mtd: rawnand: ESMT: Also use the last page for bad block markers It is known that some ESMT SLC NANDs have been shipped with the factory bad block markers in the first or last page of the block, instead of the first or second page. To be on the safe side, let's check all three locations. Signed-off-by: Frieder Schrempf Reviewed-by: Boris Brezillon Reviewed-by: Miquel Raynal Signed-off-by: Miquel Raynal --- drivers/mtd/nand/raw/nand_esmt.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/nand/raw/nand_esmt.c b/drivers/mtd/nand/raw/nand_esmt.c index 58646ed663ac..3338c68aaaf1 100644 --- a/drivers/mtd/nand/raw/nand_esmt.c +++ b/drivers/mtd/nand/raw/nand_esmt.c @@ -36,7 +36,14 @@ static void esmt_nand_decode_id(struct nand_chip *chip) static int esmt_nand_init(struct nand_chip *chip) { if (nand_is_slc(chip)) - chip->options |= NAND_BBM_FIRSTPAGE | NAND_BBM_SECONDPAGE; + /* + * It is known that some ESMT SLC NANDs have been shipped + * with the factory bad block markers in the first or last page + * of the block, instead of the first or second page. To be on + * the safe side, let's check all three locations. + */ + chip->options |= NAND_BBM_FIRSTPAGE | NAND_BBM_SECONDPAGE | + NAND_BBM_LASTPAGE; return 0; } -- cgit From 598dce7068179d49b78d116fcb74422beeb3efd7 Mon Sep 17 00:00:00 2001 From: Frieder Schrempf Date: Wed, 17 Apr 2019 12:36:37 +0000 Subject: mtd: rawnand: AMD: Also use the last page for bad block markers According to the datasheet of some Cypress SLC NANDs, the bad block markers can be in the first, second or last page of a block. So let's check all three locations. Signed-off-by: Frieder Schrempf Reviewed-by: Boris Brezillon Reviewed-by: Miquel Raynal Signed-off-by: Miquel Raynal --- drivers/mtd/nand/raw/nand_amd.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/nand/raw/nand_amd.c b/drivers/mtd/nand/raw/nand_amd.c index 1417559d3057..6217555c19a6 100644 --- a/drivers/mtd/nand/raw/nand_amd.c +++ b/drivers/mtd/nand/raw/nand_amd.c @@ -45,7 +45,13 @@ static void amd_nand_decode_id(struct nand_chip *chip) static int amd_nand_init(struct nand_chip *chip) { if (nand_is_slc(chip)) - chip->options |= NAND_BBM_FIRSTPAGE | NAND_BBM_SECONDPAGE; + /* + * According to the datasheet of some Cypress SLC NANDs, + * the bad block markers can be in the first, second or last + * page of a block. So let's check all three locations. + */ + chip->options |= NAND_BBM_FIRSTPAGE | NAND_BBM_SECONDPAGE | + NAND_BBM_LASTPAGE; return 0; } -- cgit From 74aee14c776cd98e87635b7523809db3b3a693eb Mon Sep 17 00:00:00 2001 From: Richard Weinberger Date: Wed, 17 Apr 2019 20:54:32 +0200 Subject: mtd: nandsim: Embed struct nand_chip in struct nandsim We will need struct nand_controller soon, so more stuff need to be parts of struct nandsim. While we are here, rename "nand" to "ns" to use the same naming scheme everywhere in nandsim. Reviewed-by: Boris Brezillon Signed-off-by: Richard Weinberger Signed-off-by: Miquel Raynal --- drivers/mtd/nand/raw/nandsim.c | 49 +++++++++++++++++++++--------------------- 1 file changed, 24 insertions(+), 25 deletions(-) diff --git a/drivers/mtd/nand/raw/nandsim.c b/drivers/mtd/nand/raw/nandsim.c index 0f86dd283769..86ebd24ac421 100644 --- a/drivers/mtd/nand/raw/nandsim.c +++ b/drivers/mtd/nand/raw/nandsim.c @@ -298,6 +298,7 @@ union ns_mem { * The structure which describes all the internal simulator data. */ struct nandsim { + struct nand_chip chip; struct mtd_partition partitions[CONFIG_NANDSIM_MAX_PARTS]; unsigned int nbparts; @@ -2216,7 +2217,7 @@ static const struct nand_controller_ops ns_controller_ops = { static int __init ns_init_module(void) { struct nand_chip *chip; - struct nandsim *nand; + struct nandsim *ns; int retval = -ENOMEM, i; if (bus_width != 8 && bus_width != 16) { @@ -2224,16 +2225,14 @@ static int __init ns_init_module(void) return -EINVAL; } - /* Allocate and initialize mtd_info, nand_chip and nandsim structures */ - chip = kzalloc(sizeof(struct nand_chip) + sizeof(struct nandsim), - GFP_KERNEL); - if (!chip) { + ns = kzalloc(sizeof(struct nandsim), GFP_KERNEL); + if (!ns) { NS_ERR("unable to allocate core structures.\n"); return -ENOMEM; } + chip = &ns->chip; nsmtd = nand_to_mtd(chip); - nand = (struct nandsim *)(chip + 1); - nand_set_controller_data(chip, (void *)nand); + nand_set_controller_data(chip, (void *)ns); /* * Register simulator's callbacks. @@ -2268,19 +2267,19 @@ static int __init ns_init_module(void) * the initial ID read command correctly */ if (id_bytes[6] != 0xFF || id_bytes[7] != 0xFF) - nand->geom.idbytes = 8; + ns->geom.idbytes = 8; else if (id_bytes[4] != 0xFF || id_bytes[5] != 0xFF) - nand->geom.idbytes = 6; + ns->geom.idbytes = 6; else if (id_bytes[2] != 0xFF || id_bytes[3] != 0xFF) - nand->geom.idbytes = 4; + ns->geom.idbytes = 4; else - nand->geom.idbytes = 2; - nand->regs.status = NS_STATUS_OK(nand); - nand->nxstate = STATE_UNKNOWN; - nand->options |= OPT_PAGE512; /* temporary value */ - memcpy(nand->ids, id_bytes, sizeof(nand->ids)); + ns->geom.idbytes = 2; + ns->regs.status = NS_STATUS_OK(ns); + ns->nxstate = STATE_UNKNOWN; + ns->options |= OPT_PAGE512; /* temporary value */ + memcpy(ns->ids, id_bytes, sizeof(ns->ids)); if (bus_width == 16) { - nand->busw = 16; + ns->busw = 16; chip->options |= NAND_BUSWIDTH_16; } @@ -2332,27 +2331,27 @@ static int __init ns_init_module(void) if ((retval = nand_create_bbt(chip)) != 0) goto err_exit; - if ((retval = parse_badblocks(nand, nsmtd)) != 0) + if ((retval = parse_badblocks(ns, nsmtd)) != 0) goto err_exit; /* Register NAND partitions */ - retval = mtd_device_register(nsmtd, &nand->partitions[0], - nand->nbparts); + retval = mtd_device_register(nsmtd, &ns->partitions[0], + ns->nbparts); if (retval != 0) goto err_exit; - if ((retval = nandsim_debugfs_create(nand)) != 0) + if ((retval = nandsim_debugfs_create(ns)) != 0) goto err_exit; return 0; err_exit: - free_nandsim(nand); + free_nandsim(ns); nand_release(chip); - for (i = 0;i < ARRAY_SIZE(nand->partitions); ++i) - kfree(nand->partitions[i].name); + for (i = 0;i < ARRAY_SIZE(ns->partitions); ++i) + kfree(ns->partitions[i].name); error: - kfree(chip); + kfree(ns); free_lists(); return retval; @@ -2373,7 +2372,7 @@ static void __exit ns_cleanup_module(void) nand_release(chip); /* Unregister driver */ for (i = 0;i < ARRAY_SIZE(ns->partitions); ++i) kfree(ns->partitions[i].name); - kfree(mtd_to_nand(nsmtd)); /* Free other structures */ + kfree(ns); /* Free other structures */ free_lists(); } -- cgit From 1c14fe2167ef4294b41949bcc372ea39c0510c00 Mon Sep 17 00:00:00 2001 From: Richard Weinberger Date: Wed, 17 Apr 2019 20:54:33 +0200 Subject: mtd: nandsim: switch to exec_op interface Stop using the legacy interface. Reviewed-by: Boris Brezillon Signed-off-by: Richard Weinberger Signed-off-by: Miquel Raynal --- drivers/mtd/nand/raw/nandsim.c | 78 +++++++++++++++++++++++++----------------- 1 file changed, 47 insertions(+), 31 deletions(-) diff --git a/drivers/mtd/nand/raw/nandsim.c b/drivers/mtd/nand/raw/nandsim.c index 86ebd24ac421..df63fa564082 100644 --- a/drivers/mtd/nand/raw/nandsim.c +++ b/drivers/mtd/nand/raw/nandsim.c @@ -299,6 +299,7 @@ union ns_mem { */ struct nandsim { struct nand_chip chip; + struct nand_controller base; struct mtd_partition partitions[CONFIG_NANDSIM_MAX_PARTS]; unsigned int nbparts; @@ -645,9 +646,6 @@ static int __init init_nandsim(struct mtd_info *mtd) return -EIO; } - /* Force mtd to not do delays */ - chip->legacy.chip_delay = 0; - /* Initialize the NAND flash parameters */ ns->busw = chip->options & NAND_BUSWIDTH_16 ? 16 : 8; ns->geom.totsz = mtd->size; @@ -2077,24 +2075,6 @@ static void ns_nand_write_byte(struct nand_chip *chip, u_char byte) return; } -static void ns_hwcontrol(struct nand_chip *chip, int cmd, unsigned int bitmask) -{ - struct nandsim *ns = nand_get_controller_data(chip); - - ns->lines.cle = bitmask & NAND_CLE ? 1 : 0; - ns->lines.ale = bitmask & NAND_ALE ? 1 : 0; - ns->lines.ce = bitmask & NAND_NCE ? 1 : 0; - - if (cmd != NAND_CMD_NONE) - ns_nand_write_byte(chip, cmd); -} - -static int ns_device_ready(struct nand_chip *chip) -{ - NS_DBG("device_ready\n"); - return 1; -} - static void ns_nand_write_buf(struct nand_chip *chip, const u_char *buf, int len) { @@ -2146,7 +2126,7 @@ static void ns_nand_read_buf(struct nand_chip *chip, u_char *buf, int len) int i; for (i = 0; i < len; i++) - buf[i] = chip->legacy.read_byte(chip); + buf[i] = ns_nand_read_byte(chip); return; } @@ -2169,6 +2149,46 @@ static void ns_nand_read_buf(struct nand_chip *chip, u_char *buf, int len) return; } +static int ns_exec_op(struct nand_chip *chip, const struct nand_operation *op, + bool check_only) +{ + int i; + unsigned int op_id; + const struct nand_op_instr *instr = NULL; + struct nandsim *ns = nand_get_controller_data(chip); + + ns->lines.ce = 1; + + for (op_id = 0; op_id < op->ninstrs; op_id++) { + instr = &op->instrs[op_id]; + ns->lines.cle = 0; + ns->lines.ale = 0; + + switch (instr->type) { + case NAND_OP_CMD_INSTR: + ns->lines.cle = 1; + ns_nand_write_byte(chip, instr->ctx.cmd.opcode); + break; + case NAND_OP_ADDR_INSTR: + ns->lines.ale = 1; + for (i = 0; i < instr->ctx.addr.naddrs; i++) + ns_nand_write_byte(chip, instr->ctx.addr.addrs[i]); + break; + case NAND_OP_DATA_IN_INSTR: + ns_nand_read_buf(chip, instr->ctx.data.buf.in, instr->ctx.data.len); + break; + case NAND_OP_DATA_OUT_INSTR: + ns_nand_write_buf(chip, instr->ctx.data.buf.out, instr->ctx.data.len); + break; + case NAND_OP_WAITRDY_INSTR: + /* we are always ready */ + break; + } + } + + return 0; +} + static int ns_attach_chip(struct nand_chip *chip) { unsigned int eccsteps, eccbytes; @@ -2209,6 +2229,7 @@ static int ns_attach_chip(struct nand_chip *chip) static const struct nand_controller_ops ns_controller_ops = { .attach_chip = ns_attach_chip, + .exec_op = ns_exec_op, }; /* @@ -2234,14 +2255,6 @@ static int __init ns_init_module(void) nsmtd = nand_to_mtd(chip); nand_set_controller_data(chip, (void *)ns); - /* - * Register simulator's callbacks. - */ - chip->legacy.cmd_ctrl = ns_hwcontrol; - chip->legacy.read_byte = ns_nand_read_byte; - chip->legacy.dev_ready = ns_device_ready; - chip->legacy.write_buf = ns_nand_write_buf; - chip->legacy.read_buf = ns_nand_read_buf; chip->ecc.mode = NAND_ECC_SOFT; chip->ecc.algo = NAND_ECC_HAMMING; /* The NAND_SKIP_BBTSCAN option is necessary for 'overridesize' */ @@ -2294,7 +2307,10 @@ static int __init ns_init_module(void) if ((retval = parse_gravepages()) != 0) goto error; - chip->legacy.dummy_controller.ops = &ns_controller_ops; + nand_controller_init(&ns->base); + ns->base.ops = &ns_controller_ops; + chip->controller = &ns->base; + retval = nand_scan(chip, 1); if (retval) { NS_ERR("Could not scan NAND Simulator device\n"); -- cgit From e43f53c22a937d024f070907d02539e413f20c15 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Tue, 16 Apr 2019 12:11:10 +0300 Subject: spi-nor: intel-spi: Add support for Intel Comet Lake SPI serial flash Intel Comet Lake has the same SPI serial flash controller as Ice Lake. Add Comet Lake PCI ID to the driver list of supported devices. Signed-off-by: Mika Westerberg Reviewed-by: Tudor Ambarus Signed-off-by: Tudor Ambarus --- drivers/mtd/spi-nor/intel-spi-pci.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mtd/spi-nor/intel-spi-pci.c b/drivers/mtd/spi-nor/intel-spi-pci.c index 872b40922608..bfbfc17ed6aa 100644 --- a/drivers/mtd/spi-nor/intel-spi-pci.c +++ b/drivers/mtd/spi-nor/intel-spi-pci.c @@ -63,6 +63,7 @@ static void intel_spi_pci_remove(struct pci_dev *pdev) } static const struct pci_device_id intel_spi_pci_ids[] = { + { PCI_VDEVICE(INTEL, 0x02a4), (unsigned long)&bxt_info }, { PCI_VDEVICE(INTEL, 0x18e0), (unsigned long)&bxt_info }, { PCI_VDEVICE(INTEL, 0x19e0), (unsigned long)&bxt_info }, { PCI_VDEVICE(INTEL, 0x34a4), (unsigned long)&bxt_info }, -- cgit From c58b1ff20ffd0f48b1618cb664bc95a98dd2bf85 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 13 Mar 2019 22:18:41 +0100 Subject: mtd: physmap_of_gemini: remove extranous __xipram annotation Marking a local variable as __xipram causes a warning because of the noinline attribute: drivers/mtd/maps/physmap-gemini.c:89:11: error: '__noinline__' attribute only applies to functions [-Werror,-Wignored-attributes] map_word __xipram ret; ^ include/linux/mtd/xip.h:34:18: note: expanded from macro '__xipram' #define __xipram noinline __attribute__ ((__section__ (".xiptext"))) I can't see any reason for the anotation anyway, so just remove it here. Fixes: 9d3b5086f6d4 ("mtd: physmap_of_gemini: Handle pin control") Signed-off-by: Arnd Bergmann Acked-by: Linus Walleij Signed-off-by: Richard Weinberger --- drivers/mtd/maps/physmap-gemini.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/maps/physmap-gemini.c b/drivers/mtd/maps/physmap-gemini.c index 60775b208fc9..a289c8b5cabf 100644 --- a/drivers/mtd/maps/physmap-gemini.c +++ b/drivers/mtd/maps/physmap-gemini.c @@ -86,7 +86,7 @@ static void gemini_flash_disable_pins(void) static map_word __xipram gemini_flash_map_read(struct map_info *map, unsigned long ofs) { - map_word __xipram ret; + map_word ret; gemini_flash_enable_pins(); ret = inline_map_read(map, ofs); -- cgit From 4bc11a2418f2ebb51b977a9807f4fb78b52ed5a8 Mon Sep 17 00:00:00 2001 From: Vignesh Raghavendra Date: Mon, 25 Mar 2019 15:18:46 +0530 Subject: MAINTAINERS: Add myself as co-maintainer for MTD I have been contributing and reviewing MTD patches for a while now and would like to add myself as co-maintainer for MTD to help maintain CFI and SPI NOR parts of the subsystem. Hopefully, this will help in taking some load off current maintainers. Signed-off-by: Vignesh Raghavendra Acked-by: Boris Brezillon Acked-by: Tudor Ambarus Acked-by: Miquel Raynal Signed-off-by: Richard Weinberger --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 5c38f21aee78..ff3821b07176 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -10011,6 +10011,7 @@ M: Brian Norris M: Boris Brezillon M: Marek Vasut M: Richard Weinberger +M: Vignesh Raghavendra L: linux-mtd@lists.infradead.org W: http://www.linux-mtd.infradead.org/ Q: http://patchwork.ozlabs.org/project/linux-mtd/list/ -- cgit From daa82b93f5b0bdc67e5cf594d55c0c8d84a406c9 Mon Sep 17 00:00:00 2001 From: Jonas Gorski Date: Thu, 28 Mar 2019 15:19:06 +0100 Subject: dt-bindings: mtd: describe the simple BCM963XX NOR flash layout Add binding documentation for the standard CFE based BCM963XX flash layout, found in most devices using a BCM63XX SoC with NOR flash. Reviewed-by: Rob Herring Signed-off-by: Jonas Gorski Reviewed-by: Florian Fainelli Signed-off-by: Richard Weinberger --- .../brcm,bcm963xx-cfe-nor-partitions.txt | 24 ++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 Documentation/devicetree/bindings/mtd/partitions/brcm,bcm963xx-cfe-nor-partitions.txt diff --git a/Documentation/devicetree/bindings/mtd/partitions/brcm,bcm963xx-cfe-nor-partitions.txt b/Documentation/devicetree/bindings/mtd/partitions/brcm,bcm963xx-cfe-nor-partitions.txt new file mode 100644 index 000000000000..9f630e95f180 --- /dev/null +++ b/Documentation/devicetree/bindings/mtd/partitions/brcm,bcm963xx-cfe-nor-partitions.txt @@ -0,0 +1,24 @@ +Broadcom BCM963XX CFE Loader NOR Flash Partitions +================================================= + +Most Broadcom BCM63XX SoC based devices follow the Broadcom reference layout for +NOR. The first erase block used for the CFE bootloader, the last for an +NVRAM partition, and the remainder in-between for one to two firmware partitions +at fixed offsets. A valid firmware partition is identified by the ImageTag +header found at beginning of the second erase block, containing the rootfs and +kernel offsets and sizes within the firmware partition. + +Required properties: +- compatible : must be "brcm,bcm963xx-cfe-nor-partitions" + +Example: + +flash@1fc00000 { + compatible = "cfi-flash"; + reg = <0x1fc00000 0x400000>; + bank-width = <2>; + + partitions { + compatible = "brcm,bcm963xx-cfe-nor-partitions"; + }; +}; -- cgit From e651de475a7a919403b51eb93db374d732377b0e Mon Sep 17 00:00:00 2001 From: Jonas Gorski Date: Thu, 28 Mar 2019 15:19:07 +0100 Subject: mtd: bcm63xxpart: add of_match_table support Add of_match_table support to allow using bcm63xxpart as a full flash layout parser from device tree. Reviewed-by: Rob Herring Signed-off-by: Jonas Gorski Reviewed-by: Florian Fainelli Signed-off-by: Richard Weinberger --- drivers/mtd/bcm63xxpart.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/mtd/bcm63xxpart.c b/drivers/mtd/bcm63xxpart.c index 41d1d3149c61..f639b4c960f0 100644 --- a/drivers/mtd/bcm63xxpart.c +++ b/drivers/mtd/bcm63xxpart.c @@ -34,6 +34,7 @@ #include #include #include +#include #define BCM963XX_CFE_BLOCK_SIZE SZ_64K /* always at least 64KiB */ @@ -311,9 +312,16 @@ out: return ret; }; +static const struct of_device_id parse_bcm63xx_cfe_match_table[] = { + { .compatible = "brcm,bcm963xx-cfe-nor-partitions" }, + {}, +}; +MODULE_DEVICE_TABLE(of, parse_bcm63xx_cfe_match_table); + static struct mtd_part_parser bcm63xx_cfe_parser = { .parse_fn = bcm63xx_parse_cfe_partitions, .name = "bcm63xxpart", + .of_match_table = parse_bcm63xx_cfe_match_table, }; module_mtd_part_parser(bcm63xx_cfe_parser); -- cgit From dd84cb022b310674f4c287ac426cb10f1b577140 Mon Sep 17 00:00:00 2001 From: Jonas Gorski Date: Thu, 28 Mar 2019 15:19:08 +0100 Subject: mtd: bcm63xxpart: move imagetag parsing to its own parser Move the bcm963xx Image Tag parsing into its own partition parser. This Allows reusing the parser with different full flash parsers. While moving it, rename it to bcm963* to better reflect it isn't chip, but reference implementation specific. Reviewed-by: Rob Herring Signed-off-by: Jonas Gorski Reviewed-by: Florian Fainelli Signed-off-by: Richard Weinberger --- drivers/mtd/Kconfig | 1 + drivers/mtd/bcm63xxpart.c | 155 ++---------------------- drivers/mtd/parsers/Kconfig | 11 ++ drivers/mtd/parsers/Makefile | 1 + drivers/mtd/parsers/parser_imagetag.c | 214 ++++++++++++++++++++++++++++++++++ 5 files changed, 235 insertions(+), 147 deletions(-) create mode 100644 drivers/mtd/parsers/parser_imagetag.c diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig index aa5a27fdfdd1..0c263df7ded7 100644 --- a/drivers/mtd/Kconfig +++ b/drivers/mtd/Kconfig @@ -94,6 +94,7 @@ config MTD_BCM63XX_PARTS tristate "BCM63XX CFE partitioning support" depends on BCM63XX || BMIPS_GENERIC || COMPILE_TEST select CRC32 + select MTD_PARSER_IMAGETAG help This provides partition parsing for BCM63xx devices with CFE bootloaders. diff --git a/drivers/mtd/bcm63xxpart.c b/drivers/mtd/bcm63xxpart.c index f639b4c960f0..b2bd04764e95 100644 --- a/drivers/mtd/bcm63xxpart.c +++ b/drivers/mtd/bcm63xxpart.c @@ -94,51 +94,19 @@ static int bcm63xx_read_nvram(struct mtd_info *master, return 0; } -static int bcm63xx_read_image_tag(struct mtd_info *master, const char *name, - loff_t tag_offset, struct bcm_tag *buf) -{ - int ret; - size_t retlen; - u32 computed_crc; - - ret = mtd_read(master, tag_offset, sizeof(*buf), &retlen, (void *)buf); - if (ret) - return ret; - - if (retlen != sizeof(*buf)) - return -EIO; - - computed_crc = crc32_le(IMAGETAG_CRC_START, (u8 *)buf, - offsetof(struct bcm_tag, header_crc)); - if (computed_crc == buf->header_crc) { - STR_NULL_TERMINATE(buf->board_id); - STR_NULL_TERMINATE(buf->tag_version); - - pr_info("%s: CFE image tag found at 0x%llx with version %s, board type %s\n", - name, tag_offset, buf->tag_version, buf->board_id); - - return 0; - } - - pr_warn("%s: CFE image tag at 0x%llx CRC invalid (expected %08x, actual %08x)\n", - name, tag_offset, buf->header_crc, computed_crc); - return 1; -} +static const char * const bcm63xx_cfe_part_types[] = { + "bcm963xx-imagetag", + NULL, +}; static int bcm63xx_parse_cfe_nor_partitions(struct mtd_info *master, const struct mtd_partition **pparts, struct bcm963xx_nvram *nvram) { - /* CFE, NVRAM and global Linux are always present */ - int nrparts = 3, curpart = 0; - struct bcm_tag *buf = NULL; struct mtd_partition *parts; - int ret; - unsigned int rootfsaddr, kerneladdr, spareaddr; - unsigned int rootfslen, kernellen, sparelen, totallen; + int nrparts = 3, curpart = 0; unsigned int cfelen, nvramlen; unsigned int cfe_erasesize; int i; - bool rootfs_first = false; cfe_erasesize = max_t(uint32_t, master->erasesize, BCM963XX_CFE_BLOCK_SIZE); @@ -147,83 +115,9 @@ static int bcm63xx_parse_cfe_nor_partitions(struct mtd_info *master, nvramlen = nvram->psi_size * SZ_1K; nvramlen = roundup(nvramlen, cfe_erasesize); - buf = vmalloc(sizeof(struct bcm_tag)); - if (!buf) - return -ENOMEM; - - /* Get the tag */ - ret = bcm63xx_read_image_tag(master, "rootfs", cfelen, buf); - if (!ret) { - STR_NULL_TERMINATE(buf->flash_image_start); - if (kstrtouint(buf->flash_image_start, 10, &rootfsaddr) || - rootfsaddr < BCM963XX_EXTENDED_SIZE) { - pr_err("invalid rootfs address: %*ph\n", - (int)sizeof(buf->flash_image_start), - buf->flash_image_start); - goto invalid_tag; - } - - STR_NULL_TERMINATE(buf->kernel_address); - if (kstrtouint(buf->kernel_address, 10, &kerneladdr) || - kerneladdr < BCM963XX_EXTENDED_SIZE) { - pr_err("invalid kernel address: %*ph\n", - (int)sizeof(buf->kernel_address), - buf->kernel_address); - goto invalid_tag; - } - - STR_NULL_TERMINATE(buf->kernel_length); - if (kstrtouint(buf->kernel_length, 10, &kernellen)) { - pr_err("invalid kernel length: %*ph\n", - (int)sizeof(buf->kernel_length), - buf->kernel_length); - goto invalid_tag; - } - - STR_NULL_TERMINATE(buf->total_length); - if (kstrtouint(buf->total_length, 10, &totallen)) { - pr_err("invalid total length: %*ph\n", - (int)sizeof(buf->total_length), - buf->total_length); - goto invalid_tag; - } - - kerneladdr = kerneladdr - BCM963XX_EXTENDED_SIZE; - rootfsaddr = rootfsaddr - BCM963XX_EXTENDED_SIZE; - spareaddr = roundup(totallen, master->erasesize) + cfelen; - - if (rootfsaddr < kerneladdr) { - /* default Broadcom layout */ - rootfslen = kerneladdr - rootfsaddr; - rootfs_first = true; - } else { - /* OpenWrt layout */ - rootfsaddr = kerneladdr + kernellen; - rootfslen = spareaddr - rootfsaddr; - } - } else if (ret > 0) { -invalid_tag: - kernellen = 0; - rootfslen = 0; - rootfsaddr = 0; - spareaddr = cfelen; - } else { - goto out; - } - sparelen = master->size - spareaddr - nvramlen; - - /* Determine number of partitions */ - if (rootfslen > 0) - nrparts++; - - if (kernellen > 0) - nrparts++; - parts = kzalloc(sizeof(*parts) * nrparts + 10 * nrparts, GFP_KERNEL); - if (!parts) { - ret = -ENOMEM; - goto out; - } + if (!parts) + return -ENOMEM; /* Start building partition list */ parts[curpart].name = "CFE"; @@ -231,30 +125,6 @@ invalid_tag: parts[curpart].size = cfelen; curpart++; - if (kernellen > 0) { - int kernelpart = curpart; - - if (rootfslen > 0 && rootfs_first) - kernelpart++; - parts[kernelpart].name = "kernel"; - parts[kernelpart].offset = kerneladdr; - parts[kernelpart].size = kernellen; - curpart++; - } - - if (rootfslen > 0) { - int rootfspart = curpart; - - if (kernellen > 0 && rootfs_first) - rootfspart--; - parts[rootfspart].name = "rootfs"; - parts[rootfspart].offset = rootfsaddr; - parts[rootfspart].size = rootfslen; - if (sparelen > 0 && !rootfs_first) - parts[rootfspart].size += sparelen; - curpart++; - } - parts[curpart].name = "nvram"; parts[curpart].offset = master->size - nvramlen; parts[curpart].size = nvramlen; @@ -264,22 +134,13 @@ invalid_tag: parts[curpart].name = "linux"; parts[curpart].offset = cfelen; parts[curpart].size = master->size - cfelen - nvramlen; + parts[curpart].types = bcm63xx_cfe_part_types; for (i = 0; i < nrparts; i++) pr_info("Partition %d is %s offset %llx and length %llx\n", i, parts[i].name, parts[i].offset, parts[i].size); - pr_info("Spare partition is offset %x and length %x\n", spareaddr, - sparelen); - *pparts = parts; - ret = 0; - -out: - vfree(buf); - - if (ret) - return ret; return nrparts; } diff --git a/drivers/mtd/parsers/Kconfig b/drivers/mtd/parsers/Kconfig index fccf1950e92d..c8be3f1507ca 100644 --- a/drivers/mtd/parsers/Kconfig +++ b/drivers/mtd/parsers/Kconfig @@ -1,3 +1,14 @@ +config MTD_PARSER_IMAGETAG + tristate "Parser for BCM963XX Image Tag format partitions" + depends on BCM63XX || BMIPS_GENERIC || COMPILE_TEST + select CRC32 + help + Image Tag is the firmware header used by broadcom on their xDSL line + of devices. It is used to describe the offsets and lengths of kernel + and rootfs partitions. + This driver adds support for parsing a partition with an Image Tag + header and creates up to two partitions, kernel and rootfs. + config MTD_PARSER_TRX tristate "Parser for TRX format partitions" depends on MTD && (BCM47XX || ARCH_BCM_5301X || COMPILE_TEST) diff --git a/drivers/mtd/parsers/Makefile b/drivers/mtd/parsers/Makefile index d8418bf6804a..3860c4464c63 100644 --- a/drivers/mtd/parsers/Makefile +++ b/drivers/mtd/parsers/Makefile @@ -1,3 +1,4 @@ +obj-$(CONFIG_MTD_PARSER_IMAGETAG) += parser_imagetag.o obj-$(CONFIG_MTD_PARSER_TRX) += parser_trx.o obj-$(CONFIG_MTD_SHARPSL_PARTS) += sharpslpart.o obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o diff --git a/drivers/mtd/parsers/parser_imagetag.c b/drivers/mtd/parsers/parser_imagetag.c new file mode 100644 index 000000000000..74b66d009b5c --- /dev/null +++ b/drivers/mtd/parsers/parser_imagetag.c @@ -0,0 +1,214 @@ +/* + * BCM63XX CFE image tag parser + * + * Copyright © 2006-2008 Florian Fainelli + * Mike Albon + * Copyright © 2009-2010 Daniel Dickinson + * Copyright © 2011-2013 Jonas Gorski + * + * 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. + * + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Ensure strings read from flash structs are null terminated */ +#define STR_NULL_TERMINATE(x) \ + do { char *_str = (x); _str[sizeof(x) - 1] = 0; } while (0) + +static int bcm963xx_read_imagetag(struct mtd_info *master, const char *name, + loff_t tag_offset, struct bcm_tag *buf) +{ + int ret; + size_t retlen; + u32 computed_crc; + + ret = mtd_read(master, tag_offset, sizeof(*buf), &retlen, (void *)buf); + if (ret) + return ret; + + if (retlen != sizeof(*buf)) + return -EIO; + + computed_crc = crc32_le(IMAGETAG_CRC_START, (u8 *)buf, + offsetof(struct bcm_tag, header_crc)); + if (computed_crc == buf->header_crc) { + STR_NULL_TERMINATE(buf->board_id); + STR_NULL_TERMINATE(buf->tag_version); + + pr_info("%s: CFE image tag found at 0x%llx with version %s, board type %s\n", + name, tag_offset, buf->tag_version, buf->board_id); + + return 0; + } + + pr_warn("%s: CFE image tag at 0x%llx CRC invalid (expected %08x, actual %08x)\n", + name, tag_offset, buf->header_crc, computed_crc); + return -EINVAL; +} + +static int bcm963xx_parse_imagetag_partitions(struct mtd_info *master, + const struct mtd_partition **pparts, + struct mtd_part_parser_data *data) +{ + /* CFE, NVRAM and global Linux are always present */ + int nrparts = 0, curpart = 0; + struct bcm_tag *buf = NULL; + struct mtd_partition *parts; + int ret; + unsigned int rootfsaddr, kerneladdr, spareaddr, offset; + unsigned int rootfslen, kernellen, sparelen, totallen; + int i; + bool rootfs_first = false; + + buf = vmalloc(sizeof(struct bcm_tag)); + if (!buf) + return -ENOMEM; + + /* Get the tag */ + ret = bcm963xx_read_imagetag(master, "rootfs", 0, buf); + if (!ret) { + STR_NULL_TERMINATE(buf->flash_image_start); + if (kstrtouint(buf->flash_image_start, 10, &rootfsaddr) || + rootfsaddr < BCM963XX_EXTENDED_SIZE) { + pr_err("invalid rootfs address: %*ph\n", + (int)sizeof(buf->flash_image_start), + buf->flash_image_start); + goto out; + } + + STR_NULL_TERMINATE(buf->kernel_address); + if (kstrtouint(buf->kernel_address, 10, &kerneladdr) || + kerneladdr < BCM963XX_EXTENDED_SIZE) { + pr_err("invalid kernel address: %*ph\n", + (int)sizeof(buf->kernel_address), + buf->kernel_address); + goto out; + } + + STR_NULL_TERMINATE(buf->kernel_length); + if (kstrtouint(buf->kernel_length, 10, &kernellen)) { + pr_err("invalid kernel length: %*ph\n", + (int)sizeof(buf->kernel_length), + buf->kernel_length); + goto out; + } + + STR_NULL_TERMINATE(buf->total_length); + if (kstrtouint(buf->total_length, 10, &totallen)) { + pr_err("invalid total length: %*ph\n", + (int)sizeof(buf->total_length), + buf->total_length); + goto out; + } + + /* + * Addresses are flash absolute, so convert to partition + * relative addresses. Assume either kernel or rootfs will + * directly follow the image tag. + */ + if (rootfsaddr < kerneladdr) + offset = rootfsaddr - sizeof(struct bcm_tag); + else + offset = kerneladdr - sizeof(struct bcm_tag); + + kerneladdr = kerneladdr - offset; + rootfsaddr = rootfsaddr - offset; + spareaddr = roundup(totallen, master->erasesize); + + if (rootfsaddr < kerneladdr) { + /* default Broadcom layout */ + rootfslen = kerneladdr - rootfsaddr; + rootfs_first = true; + } else { + /* OpenWrt layout */ + rootfsaddr = kerneladdr + kernellen; + rootfslen = spareaddr - rootfsaddr; + } + } else { + goto out; + } + sparelen = master->size - spareaddr; + + /* Determine number of partitions */ + if (rootfslen > 0) + nrparts++; + + if (kernellen > 0) + nrparts++; + + parts = kzalloc(sizeof(*parts) * nrparts + 10 * nrparts, GFP_KERNEL); + if (!parts) { + ret = -ENOMEM; + goto out; + } + + /* Start building partition list */ + if (kernellen > 0) { + int kernelpart = curpart; + + if (rootfslen > 0 && rootfs_first) + kernelpart++; + parts[kernelpart].name = "kernel"; + parts[kernelpart].offset = kerneladdr; + parts[kernelpart].size = kernellen; + curpart++; + } + + if (rootfslen > 0) { + int rootfspart = curpart; + + if (kernellen > 0 && rootfs_first) + rootfspart--; + parts[rootfspart].name = "rootfs"; + parts[rootfspart].offset = rootfsaddr; + parts[rootfspart].size = rootfslen; + if (sparelen > 0 && !rootfs_first) + parts[rootfspart].size += sparelen; + curpart++; + } + + for (i = 0; i < nrparts; i++) + pr_info("Partition %d is %s offset %llx and length %llx\n", i, + parts[i].name, parts[i].offset, parts[i].size); + + pr_info("Spare partition is offset %x and length %x\n", spareaddr, + sparelen); + + *pparts = parts; + ret = 0; + +out: + vfree(buf); + + if (ret) + return ret; + + return nrparts; +} + +static struct mtd_part_parser bcm963xx_imagetag_parser = { + .parse_fn = bcm963xx_parse_imagetag_partitions, + .name = "bcm963xx-imagetag", +}; +module_mtd_part_parser(bcm963xx_imagetag_parser); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Daniel Dickinson "); +MODULE_AUTHOR("Florian Fainelli "); +MODULE_AUTHOR("Mike Albon "); +MODULE_AUTHOR("Jonas Gorski "); +MODULE_DESCRIPTION("MTD parser for BCM963XX CFE Image Tag partitions"); -- cgit From 6744ebb0c798ac3717ceb5da1a479d9314dd641c Mon Sep 17 00:00:00 2001 From: Jonas Gorski Date: Thu, 28 Mar 2019 15:19:09 +0100 Subject: dt-bindings: mtd: describe BCM963XX ImageTag format and usage Describe how to use the BCM963XX ImageTag format in a mixed flash layout environment. Reviewed-by: Rob Herring Signed-off-by: Jonas Gorski Reviewed-by: Florian Fainelli Signed-off-by: Richard Weinberger --- .../mtd/partitions/brcm,bcm963xx-imagetag.txt | 45 ++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 Documentation/devicetree/bindings/mtd/partitions/brcm,bcm963xx-imagetag.txt diff --git a/Documentation/devicetree/bindings/mtd/partitions/brcm,bcm963xx-imagetag.txt b/Documentation/devicetree/bindings/mtd/partitions/brcm,bcm963xx-imagetag.txt new file mode 100644 index 000000000000..f8b7418ed817 --- /dev/null +++ b/Documentation/devicetree/bindings/mtd/partitions/brcm,bcm963xx-imagetag.txt @@ -0,0 +1,45 @@ +Broadcom BCM963XX ImageTag Partition Container +============================================== + +Some Broadcom BCM63XX SoC based devices contain additional, non discoverable +partitions or non standard bootloader partition sizes. For these a mixed layout +needs to be used with an explicit firmware partition. + +The BCM963XX ImageTag is a simple firmware header describing the offsets and +sizes of the rootfs and kernel parts contained in the firmware. + +Required properties: +- compatible : must be "brcm,bcm963xx-imagetag" + +Example: + +flash@1e000000 { + compatible = "cfi-flash"; + reg = <0x1e000000 0x2000000>; + bank-width = <2>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + cfe@0 { + reg = <0x0 0x10000>; + read-only; + }; + + firmware@10000 { + reg = <0x10000 0x7d0000>; + compatible = "brcm,bcm963xx-imagetag"; + }; + + caldata@7e0000 { + reg = <0x7e0000 0x10000>; + read-only; + }; + + nvram@7f0000 { + reg = <0x7f0000 0x10000>; + }; + }; +}; -- cgit From fb899d3b2a622874cbb5daf9eb8c0fba19844648 Mon Sep 17 00:00:00 2001 From: Jonas Gorski Date: Thu, 28 Mar 2019 15:19:10 +0100 Subject: mtd: parser_imagetag: add of_match_table support Allow matching the imagetag parser for fixed partitions defined in the device tree. Reviewed-by: Rob Herring Signed-off-by: Jonas Gorski Reviewed-by: Florian Fainelli Signed-off-by: Richard Weinberger --- drivers/mtd/parsers/parser_imagetag.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/mtd/parsers/parser_imagetag.c b/drivers/mtd/parsers/parser_imagetag.c index 74b66d009b5c..9537c183a3be 100644 --- a/drivers/mtd/parsers/parser_imagetag.c +++ b/drivers/mtd/parsers/parser_imagetag.c @@ -24,6 +24,7 @@ #include #include #include +#include /* Ensure strings read from flash structs are null terminated */ #define STR_NULL_TERMINATE(x) \ @@ -200,9 +201,16 @@ out: return nrparts; } +static const struct of_device_id parse_bcm963xx_imagetag_match_table[] = { + { .compatible = "brcm,bcm963xx-imagetag" }, + {}, +}; +MODULE_DEVICE_TABLE(of, parse_bcm963xx_imagetag_match_table); + static struct mtd_part_parser bcm963xx_imagetag_parser = { .parse_fn = bcm963xx_parse_imagetag_partitions, .name = "bcm963xx-imagetag", + .of_match_table = parse_bcm963xx_imagetag_match_table, }; module_mtd_part_parser(bcm963xx_imagetag_parser); -- cgit From 64d14c6fe040361ff6aecb825e392cf97837cd9e Mon Sep 17 00:00:00 2001 From: Chris Packham Date: Fri, 29 Mar 2019 15:13:21 +1300 Subject: mtd: maps: physmap: Store gpio_values correctly When the gpio-addr-flash.c driver was merged with physmap-core.c the code to store the current gpio_values was lost. This meant that once a gpio was asserted it was never de-asserted. Fix this by storing the current offset in gpio_values like the old driver used to. Fixes: commit ba32ce95cbd9 ("mtd: maps: Merge gpio-addr-flash.c into physmap-core.c") Cc: Signed-off-by: Chris Packham Reviewed-by: Boris Brezillon Signed-off-by: Richard Weinberger --- drivers/mtd/maps/physmap-core.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/mtd/maps/physmap-core.c b/drivers/mtd/maps/physmap-core.c index d9a3e4bebe5d..21b556afc305 100644 --- a/drivers/mtd/maps/physmap-core.c +++ b/drivers/mtd/maps/physmap-core.c @@ -132,6 +132,8 @@ static void physmap_set_addr_gpios(struct physmap_flash_info *info, gpiod_set_value(info->gpios->desc[i], !!(BIT(i) & ofs)); } + + info->gpio_values = ofs; } #define win_mask(order) (BIT(order) - 1) -- cgit From 6e9314dc051f9a5e9120954f2d6de9c8e5d8c522 Mon Sep 17 00:00:00 2001 From: Chris Packham Date: Fri, 29 Mar 2019 15:13:22 +1300 Subject: dt-binding: mtd: physmap: Add example using addr-gpios property Add an example showing how to use the addr-gpios property to deal with a system with limited IO space. Cc: devicetree@vger.kernel.org Signed-off-by: Chris Packham Reviewed-by: Rob Herring Signed-off-by: Richard Weinberger --- Documentation/devicetree/bindings/mtd/mtd-physmap.txt | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Documentation/devicetree/bindings/mtd/mtd-physmap.txt b/Documentation/devicetree/bindings/mtd/mtd-physmap.txt index 7df0dcaccb7d..c69f4f065d23 100644 --- a/Documentation/devicetree/bindings/mtd/mtd-physmap.txt +++ b/Documentation/devicetree/bindings/mtd/mtd-physmap.txt @@ -96,3 +96,19 @@ An example using SRAM: bank-width = <2>; }; +An example using gpio-addrs + + flash@20000000 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "cfi-flash", "jedec-flash"; + reg = <0x20000000 0x02000000>; + ranges = <0 0x00000000 0x02000000 + 1 0x02000000 0x02000000>; + bank-width = <2>; + addr-gpios = <&gpio1 2 GPIO_ACTIVE_HIGH>; + partition@0 { + label = "test-part1"; + reg = <0 0x04000000>; + }; + }; -- cgit From 1a5490cf4d1a690e3728c87b4b689a38e8faaa46 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Sat, 30 Mar 2019 09:29:25 +0100 Subject: MAINTAINERS: Remove my name from the MTD and NAND entries I am less and less active on the MTD/NAND fronts, and I don't think it will get any better in the future. Let's remove my name so that people don't expect me to review/merge their patches. Signed-off-by: Boris Brezillon Signed-off-by: Richard Weinberger --- MAINTAINERS | 2 -- 1 file changed, 2 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index ff3821b07176..f9dee743c6d2 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -10008,7 +10008,6 @@ F: mm/ MEMORY TECHNOLOGY DEVICES (MTD) M: David Woodhouse M: Brian Norris -M: Boris Brezillon M: Marek Vasut M: Richard Weinberger M: Vignesh Raghavendra @@ -10623,7 +10622,6 @@ S: Supported F: drivers/net/ethernet/myricom/myri10ge/ NAND FLASH SUBSYSTEM -M: Boris Brezillon M: Miquel Raynal R: Richard Weinberger L: linux-mtd@lists.infradead.org -- cgit From b6abd06777a89a2579097fffc2b064449a9abf66 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Mon, 1 Apr 2019 17:09:37 +0200 Subject: MAINTAINERS: Add myself as MTD maintainer Help Richard and hopefully Tudor and Vignesh maintaining MTD since Boris is leaving. Signed-off-by: Miquel Raynal Acked-by: Vignesh Raghavendra Acked-by: Boris Brezillon Acked-by: Tudor Ambarus Signed-off-by: Richard Weinberger --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index f9dee743c6d2..897ccdacc0e0 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -10009,6 +10009,7 @@ MEMORY TECHNOLOGY DEVICES (MTD) M: David Woodhouse M: Brian Norris M: Marek Vasut +M: Miquel Raynal M: Richard Weinberger M: Vignesh Raghavendra L: linux-mtd@lists.infradead.org -- cgit From d41970097f10d898cef0eb04bf53d786efd6bbbc Mon Sep 17 00:00:00 2001 From: Chris Packham Date: Wed, 3 Apr 2019 15:02:40 +1300 Subject: mtd: maps: Allow MTD_PHYSMAP with MTD_RAM When the physmap_of_core.c code was merged into physmap-core.c the ability to use MTD_PHYSMAP_OF with only MTD_RAM selected was lost. Restore this by adding MTD_RAM to the dependencies of MTD_PHYSMAP. Fixes: commit 642b1e8dbed7 ("mtd: maps: Merge physmap_of.c into physmap-core.c") Cc: Signed-off-by: Chris Packham Reviewed-by: Hamish Martin Signed-off-by: Richard Weinberger --- drivers/mtd/maps/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig index e0cf869c8544..544ed1931843 100644 --- a/drivers/mtd/maps/Kconfig +++ b/drivers/mtd/maps/Kconfig @@ -10,7 +10,7 @@ config MTD_COMPLEX_MAPPINGS config MTD_PHYSMAP tristate "Flash device in physical memory map" - depends on MTD_CFI || MTD_JEDECPROBE || MTD_ROM || MTD_LPDDR + depends on MTD_CFI || MTD_JEDECPROBE || MTD_ROM || MTD_RAM || MTD_LPDDR help This provides a 'mapping' driver which allows the NOR Flash and ROM driver code to communicate with chips which are mapped -- cgit From 251f26c9e828aa441a603efc32e0308ca76f172c Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Sat, 27 Apr 2019 17:14:57 +0200 Subject: mtd: maps: Make uclinux_ram_map static The blackfin architecture has been removed a while ago, so there is no more need to declare uclinux_ram_map as a global structure. Signed-off-by: Thomas Huth Signed-off-by: Richard Weinberger --- drivers/mtd/maps/uclinux.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/mtd/maps/uclinux.c b/drivers/mtd/maps/uclinux.c index aef030ca8601..de4c46318abb 100644 --- a/drivers/mtd/maps/uclinux.c +++ b/drivers/mtd/maps/uclinux.c @@ -31,13 +31,7 @@ #define MAP_NAME "ram" #endif -/* - * Blackfin uses uclinux_ram_map during startup, so it must not be static. - * Provide a dummy declaration to make sparse happy. - */ -extern struct map_info uclinux_ram_map; - -struct map_info uclinux_ram_map = { +static struct map_info uclinux_ram_map = { .name = MAP_NAME, .size = 0, }; -- cgit From 2aa3b8e1de23aaf9260b2635d467d69c9a2ea3f2 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 2 May 2019 16:30:26 +0200 Subject: mtd: afs: Move AFS partition parser to parsers subdir This moves the AFS (ARM Firmware Suite) partition parser for NOR flash down into the parsers subdirectory. Signed-off-by: Linus Walleij Signed-off-by: Richard Weinberger --- drivers/mtd/Kconfig | 16 --- drivers/mtd/Makefile | 1 - drivers/mtd/afs.c | 266 ------------------------------------------- drivers/mtd/parsers/Kconfig | 16 +++ drivers/mtd/parsers/Makefile | 1 + drivers/mtd/parsers/afs.c | 266 +++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 283 insertions(+), 283 deletions(-) delete mode 100644 drivers/mtd/afs.c create mode 100644 drivers/mtd/parsers/afs.c diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig index 0c263df7ded7..fb31a7f649a3 100644 --- a/drivers/mtd/Kconfig +++ b/drivers/mtd/Kconfig @@ -60,22 +60,6 @@ config MTD_CMDLINE_PARTS If unsure, say 'N'. -config MTD_AFS_PARTS - tristate "ARM Firmware Suite partition parsing" - depends on (ARM || ARM64) - help - The ARM Firmware Suite allows the user to divide flash devices into - multiple 'images'. Each such image has a header containing its name - and offset/size etc. - - If you need code which can detect and parse these tables, and - register MTD 'partitions' corresponding to each image detected, - enable this option. - - You will still need the parsing functions to be called by the driver - for your particular device. It won't happen automatically. The - 'physmap' map driver (CONFIG_MTD_PHYSMAP) does this, for example. - config MTD_OF_PARTS tristate "OpenFirmware partitioning information support" default y diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile index 58fc327a5276..806287e80e84 100644 --- a/drivers/mtd/Makefile +++ b/drivers/mtd/Makefile @@ -9,7 +9,6 @@ mtd-y := mtdcore.o mtdsuper.o mtdconcat.o mtdpart.o mtdchar.o obj-$(CONFIG_MTD_OF_PARTS) += ofpart.o obj-$(CONFIG_MTD_CMDLINE_PARTS) += cmdlinepart.o -obj-$(CONFIG_MTD_AFS_PARTS) += afs.o obj-$(CONFIG_MTD_AR7_PARTS) += ar7part.o obj-$(CONFIG_MTD_BCM63XX_PARTS) += bcm63xxpart.o obj-$(CONFIG_MTD_BCM47XX_PARTS) += bcm47xxpart.o diff --git a/drivers/mtd/afs.c b/drivers/mtd/afs.c deleted file mode 100644 index d61b7edfc938..000000000000 --- a/drivers/mtd/afs.c +++ /dev/null @@ -1,266 +0,0 @@ -/*====================================================================== - - drivers/mtd/afs.c: ARM Flash Layout/Partitioning - - Copyright © 2000 ARM Limited - - 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 - - This is access code for flashes using ARM's flash partitioning - standards. - -======================================================================*/ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#define AFSV1_FOOTER_MAGIC 0xA0FFFF9F - -struct footer_v1 { - u32 image_info_base; /* Address of first word of ImageFooter */ - u32 image_start; /* Start of area reserved by this footer */ - u32 signature; /* 'Magic' number proves it's a footer */ - u32 type; /* Area type: ARM Image, SIB, customer */ - u32 checksum; /* Just this structure */ -}; - -struct image_info_v1 { - u32 bootFlags; /* Boot flags, compression etc. */ - u32 imageNumber; /* Unique number, selects for boot etc. */ - u32 loadAddress; /* Address program should be loaded to */ - u32 length; /* Actual size of image */ - u32 address; /* Image is executed from here */ - char name[16]; /* Null terminated */ - u32 headerBase; /* Flash Address of any stripped header */ - u32 header_length; /* Length of header in memory */ - u32 headerType; /* AIF, RLF, s-record etc. */ - u32 checksum; /* Image checksum (inc. this struct) */ -}; - -static u32 word_sum(void *words, int num) -{ - u32 *p = words; - u32 sum = 0; - - while (num--) - sum += *p++; - - return sum; -} - -static int -afs_read_footer_v1(struct mtd_info *mtd, u_int *img_start, u_int *iis_start, - u_int off, u_int mask) -{ - struct footer_v1 fs; - u_int ptr = off + mtd->erasesize - sizeof(fs); - size_t sz; - int ret; - - ret = mtd_read(mtd, ptr, sizeof(fs), &sz, (u_char *)&fs); - if (ret >= 0 && sz != sizeof(fs)) - ret = -EINVAL; - - if (ret < 0) { - printk(KERN_ERR "AFS: mtd read failed at 0x%x: %d\n", - ptr, ret); - return ret; - } - - /* - * Does it contain the magic number? - */ - if (fs.signature != AFSV1_FOOTER_MAGIC) - return 0; - - /* - * Check the checksum. - */ - if (word_sum(&fs, sizeof(fs) / sizeof(u32)) != 0xffffffff) - return 0; - - /* - * Don't touch the SIB. - */ - if (fs.type == 2) - return 0; - - *iis_start = fs.image_info_base & mask; - *img_start = fs.image_start & mask; - - /* - * Check the image info base. This can not - * be located after the footer structure. - */ - if (*iis_start >= ptr) - return 0; - - /* - * Check the start of this image. The image - * data can not be located after this block. - */ - if (*img_start > off) - return 0; - - return 1; -} - -static int -afs_read_iis_v1(struct mtd_info *mtd, struct image_info_v1 *iis, u_int ptr) -{ - size_t sz; - int ret, i; - - memset(iis, 0, sizeof(*iis)); - ret = mtd_read(mtd, ptr, sizeof(*iis), &sz, (u_char *)iis); - if (ret < 0) - goto failed; - - if (sz != sizeof(*iis)) { - ret = -EINVAL; - goto failed; - } - - ret = 0; - - /* - * Validate the name - it must be NUL terminated. - */ - for (i = 0; i < sizeof(iis->name); i++) - if (iis->name[i] == '\0') - break; - - if (i < sizeof(iis->name)) - ret = 1; - - return ret; - - failed: - printk(KERN_ERR "AFS: mtd read failed at 0x%x: %d\n", - ptr, ret); - return ret; -} - -static int parse_afs_partitions(struct mtd_info *mtd, - const struct mtd_partition **pparts, - struct mtd_part_parser_data *data) -{ - struct mtd_partition *parts; - u_int mask, off, idx, sz; - int ret = 0; - char *str; - - /* - * This is the address mask; we use this to mask off out of - * range address bits. - */ - mask = mtd->size - 1; - - /* - * First, calculate the size of the array we need for the - * partition information. We include in this the size of - * the strings. - */ - for (idx = off = sz = 0; off < mtd->size; off += mtd->erasesize) { - struct image_info_v1 iis; - u_int iis_ptr, img_ptr; - - ret = afs_read_footer_v1(mtd, &img_ptr, &iis_ptr, off, mask); - if (ret < 0) - break; - if (ret) { - ret = afs_read_iis_v1(mtd, &iis, iis_ptr); - if (ret < 0) - break; - if (ret == 0) - continue; - - sz += sizeof(struct mtd_partition); - sz += strlen(iis.name) + 1; - idx += 1; - } - } - - if (!sz) - return ret; - - parts = kzalloc(sz, GFP_KERNEL); - if (!parts) - return -ENOMEM; - - str = (char *)(parts + idx); - - /* - * Identify the partitions - */ - for (idx = off = 0; off < mtd->size; off += mtd->erasesize) { - struct image_info_v1 iis; - u_int iis_ptr, img_ptr; - - /* Read the footer. */ - ret = afs_read_footer_v1(mtd, &img_ptr, &iis_ptr, off, mask); - if (ret < 0) - break; - if (ret == 0) - continue; - - /* Read the image info block */ - ret = afs_read_iis_v1(mtd, &iis, iis_ptr); - if (ret < 0) - break; - if (ret == 0) - continue; - - strcpy(str, iis.name); - - parts[idx].name = str; - parts[idx].size = (iis.length + mtd->erasesize - 1) & ~(mtd->erasesize - 1); - parts[idx].offset = img_ptr; - parts[idx].mask_flags = 0; - - printk(" mtd%d: at 0x%08x, %5lluKiB, %8u, %s\n", - idx, img_ptr, parts[idx].size / 1024, - iis.imageNumber, str); - - idx += 1; - str = str + strlen(iis.name) + 1; - } - - if (!idx) { - kfree(parts); - parts = NULL; - } - - *pparts = parts; - return idx ? idx : ret; -} - -static struct mtd_part_parser afs_parser = { - .parse_fn = parse_afs_partitions, - .name = "afs", -}; -module_mtd_part_parser(afs_parser); - -MODULE_AUTHOR("ARM Ltd"); -MODULE_DESCRIPTION("ARM Firmware Suite partition parser"); -MODULE_LICENSE("GPL"); diff --git a/drivers/mtd/parsers/Kconfig b/drivers/mtd/parsers/Kconfig index c8be3f1507ca..bc201327dda0 100644 --- a/drivers/mtd/parsers/Kconfig +++ b/drivers/mtd/parsers/Kconfig @@ -9,6 +9,22 @@ config MTD_PARSER_IMAGETAG This driver adds support for parsing a partition with an Image Tag header and creates up to two partitions, kernel and rootfs. +config MTD_AFS_PARTS + tristate "ARM Firmware Suite partition parsing" + depends on (ARM || ARM64) + help + The ARM Firmware Suite allows the user to divide flash devices into + multiple 'images'. Each such image has a header containing its name + and offset/size etc. + + If you need code which can detect and parse these tables, and + register MTD 'partitions' corresponding to each image detected, + enable this option. + + You will still need the parsing functions to be called by the driver + for your particular device. It won't happen automatically. The + 'physmap' map driver (CONFIG_MTD_PHYSMAP) does this, for example. + config MTD_PARSER_TRX tristate "Parser for TRX format partitions" depends on MTD && (BCM47XX || ARCH_BCM_5301X || COMPILE_TEST) diff --git a/drivers/mtd/parsers/Makefile b/drivers/mtd/parsers/Makefile index 3860c4464c63..cddc8f35a856 100644 --- a/drivers/mtd/parsers/Makefile +++ b/drivers/mtd/parsers/Makefile @@ -1,4 +1,5 @@ obj-$(CONFIG_MTD_PARSER_IMAGETAG) += parser_imagetag.o +obj-$(CONFIG_MTD_AFS_PARTS) += afs.o obj-$(CONFIG_MTD_PARSER_TRX) += parser_trx.o obj-$(CONFIG_MTD_SHARPSL_PARTS) += sharpslpart.o obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o diff --git a/drivers/mtd/parsers/afs.c b/drivers/mtd/parsers/afs.c new file mode 100644 index 000000000000..d61b7edfc938 --- /dev/null +++ b/drivers/mtd/parsers/afs.c @@ -0,0 +1,266 @@ +/*====================================================================== + + drivers/mtd/afs.c: ARM Flash Layout/Partitioning + + Copyright © 2000 ARM Limited + + 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 + + This is access code for flashes using ARM's flash partitioning + standards. + +======================================================================*/ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define AFSV1_FOOTER_MAGIC 0xA0FFFF9F + +struct footer_v1 { + u32 image_info_base; /* Address of first word of ImageFooter */ + u32 image_start; /* Start of area reserved by this footer */ + u32 signature; /* 'Magic' number proves it's a footer */ + u32 type; /* Area type: ARM Image, SIB, customer */ + u32 checksum; /* Just this structure */ +}; + +struct image_info_v1 { + u32 bootFlags; /* Boot flags, compression etc. */ + u32 imageNumber; /* Unique number, selects for boot etc. */ + u32 loadAddress; /* Address program should be loaded to */ + u32 length; /* Actual size of image */ + u32 address; /* Image is executed from here */ + char name[16]; /* Null terminated */ + u32 headerBase; /* Flash Address of any stripped header */ + u32 header_length; /* Length of header in memory */ + u32 headerType; /* AIF, RLF, s-record etc. */ + u32 checksum; /* Image checksum (inc. this struct) */ +}; + +static u32 word_sum(void *words, int num) +{ + u32 *p = words; + u32 sum = 0; + + while (num--) + sum += *p++; + + return sum; +} + +static int +afs_read_footer_v1(struct mtd_info *mtd, u_int *img_start, u_int *iis_start, + u_int off, u_int mask) +{ + struct footer_v1 fs; + u_int ptr = off + mtd->erasesize - sizeof(fs); + size_t sz; + int ret; + + ret = mtd_read(mtd, ptr, sizeof(fs), &sz, (u_char *)&fs); + if (ret >= 0 && sz != sizeof(fs)) + ret = -EINVAL; + + if (ret < 0) { + printk(KERN_ERR "AFS: mtd read failed at 0x%x: %d\n", + ptr, ret); + return ret; + } + + /* + * Does it contain the magic number? + */ + if (fs.signature != AFSV1_FOOTER_MAGIC) + return 0; + + /* + * Check the checksum. + */ + if (word_sum(&fs, sizeof(fs) / sizeof(u32)) != 0xffffffff) + return 0; + + /* + * Don't touch the SIB. + */ + if (fs.type == 2) + return 0; + + *iis_start = fs.image_info_base & mask; + *img_start = fs.image_start & mask; + + /* + * Check the image info base. This can not + * be located after the footer structure. + */ + if (*iis_start >= ptr) + return 0; + + /* + * Check the start of this image. The image + * data can not be located after this block. + */ + if (*img_start > off) + return 0; + + return 1; +} + +static int +afs_read_iis_v1(struct mtd_info *mtd, struct image_info_v1 *iis, u_int ptr) +{ + size_t sz; + int ret, i; + + memset(iis, 0, sizeof(*iis)); + ret = mtd_read(mtd, ptr, sizeof(*iis), &sz, (u_char *)iis); + if (ret < 0) + goto failed; + + if (sz != sizeof(*iis)) { + ret = -EINVAL; + goto failed; + } + + ret = 0; + + /* + * Validate the name - it must be NUL terminated. + */ + for (i = 0; i < sizeof(iis->name); i++) + if (iis->name[i] == '\0') + break; + + if (i < sizeof(iis->name)) + ret = 1; + + return ret; + + failed: + printk(KERN_ERR "AFS: mtd read failed at 0x%x: %d\n", + ptr, ret); + return ret; +} + +static int parse_afs_partitions(struct mtd_info *mtd, + const struct mtd_partition **pparts, + struct mtd_part_parser_data *data) +{ + struct mtd_partition *parts; + u_int mask, off, idx, sz; + int ret = 0; + char *str; + + /* + * This is the address mask; we use this to mask off out of + * range address bits. + */ + mask = mtd->size - 1; + + /* + * First, calculate the size of the array we need for the + * partition information. We include in this the size of + * the strings. + */ + for (idx = off = sz = 0; off < mtd->size; off += mtd->erasesize) { + struct image_info_v1 iis; + u_int iis_ptr, img_ptr; + + ret = afs_read_footer_v1(mtd, &img_ptr, &iis_ptr, off, mask); + if (ret < 0) + break; + if (ret) { + ret = afs_read_iis_v1(mtd, &iis, iis_ptr); + if (ret < 0) + break; + if (ret == 0) + continue; + + sz += sizeof(struct mtd_partition); + sz += strlen(iis.name) + 1; + idx += 1; + } + } + + if (!sz) + return ret; + + parts = kzalloc(sz, GFP_KERNEL); + if (!parts) + return -ENOMEM; + + str = (char *)(parts + idx); + + /* + * Identify the partitions + */ + for (idx = off = 0; off < mtd->size; off += mtd->erasesize) { + struct image_info_v1 iis; + u_int iis_ptr, img_ptr; + + /* Read the footer. */ + ret = afs_read_footer_v1(mtd, &img_ptr, &iis_ptr, off, mask); + if (ret < 0) + break; + if (ret == 0) + continue; + + /* Read the image info block */ + ret = afs_read_iis_v1(mtd, &iis, iis_ptr); + if (ret < 0) + break; + if (ret == 0) + continue; + + strcpy(str, iis.name); + + parts[idx].name = str; + parts[idx].size = (iis.length + mtd->erasesize - 1) & ~(mtd->erasesize - 1); + parts[idx].offset = img_ptr; + parts[idx].mask_flags = 0; + + printk(" mtd%d: at 0x%08x, %5lluKiB, %8u, %s\n", + idx, img_ptr, parts[idx].size / 1024, + iis.imageNumber, str); + + idx += 1; + str = str + strlen(iis.name) + 1; + } + + if (!idx) { + kfree(parts); + parts = NULL; + } + + *pparts = parts; + return idx ? idx : ret; +} + +static struct mtd_part_parser afs_parser = { + .parse_fn = parse_afs_partitions, + .name = "afs", +}; +module_mtd_part_parser(afs_parser); + +MODULE_AUTHOR("ARM Ltd"); +MODULE_DESCRIPTION("ARM Firmware Suite partition parser"); +MODULE_LICENSE("GPL"); -- cgit From 2485fa5323316968e73a2b46ea0bc554c37b7e83 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 2 May 2019 16:30:27 +0200 Subject: mtd: partitions: Add AFS partitions DT bindings This adds device tree bindings for ARM Firmware Suite flash partitioning used in NOR flashes on ARM reference designs. Cc: devicetree@vger.kernel.org Reviewed-by: Rob Herring Signed-off-by: Linus Walleij Signed-off-by: Richard Weinberger --- .../bindings/mtd/partitions/arm,arm-firmware-suite.txt | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 Documentation/devicetree/bindings/mtd/partitions/arm,arm-firmware-suite.txt diff --git a/Documentation/devicetree/bindings/mtd/partitions/arm,arm-firmware-suite.txt b/Documentation/devicetree/bindings/mtd/partitions/arm,arm-firmware-suite.txt new file mode 100644 index 000000000000..d5c5616f6db5 --- /dev/null +++ b/Documentation/devicetree/bindings/mtd/partitions/arm,arm-firmware-suite.txt @@ -0,0 +1,17 @@ +ARM AFS - ARM Firmware Suite Partitions +======================================= + +The ARM Firmware Suite is a flash partitioning system found on the +ARM reference designs: Integrator AP, Integrator CP, Versatile AB, +Versatile PB, the RealView family, Versatile Express and Juno. + +Required properties: +- compatible : (required) must be "arm,arm-firmware-suite" + +Example: + +flash@0 { + partitions { + compatible = "arm,arm-firmware-suite"; + }; +}; -- cgit From 22749bf549efb000c88d164c9a6a3366468e8e1c Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 2 May 2019 16:30:28 +0200 Subject: mtd: partitions: Add OF support to AFS partitions This adds device tree support for AFS partitioning. Signed-off-by: Linus Walleij Signed-off-by: Richard Weinberger --- drivers/mtd/parsers/afs.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/mtd/parsers/afs.c b/drivers/mtd/parsers/afs.c index d61b7edfc938..3679e1d22595 100644 --- a/drivers/mtd/parsers/afs.c +++ b/drivers/mtd/parsers/afs.c @@ -255,9 +255,16 @@ static int parse_afs_partitions(struct mtd_info *mtd, return idx ? idx : ret; } +static const struct of_device_id mtd_parser_afs_of_match_table[] = { + { .compatible = "arm,arm-firmware-suite" }, + {}, +}; +MODULE_DEVICE_TABLE(of, mtd_parser_afs_of_match_table); + static struct mtd_part_parser afs_parser = { .parse_fn = parse_afs_partitions, .name = "afs", + .of_match_table = mtd_parser_afs_of_match_table, }; module_mtd_part_parser(afs_parser); -- cgit From 1fca1f6abb38a6c2a082c1df01601d0898454d7a Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 2 May 2019 16:30:29 +0200 Subject: mtd: afs: simplify partition parsing This simplifies the AFS partition parsing to make the code more straight-forward and readable. Before this patch the code tried to calculate the memory required to hold the partition info by adding up the sizes of the strings of the names and adding that to a single memory allocation, indexing the name pointers in front of the struct mtd_partition allocations so all allocated data was in one chunk. This is overzealous. Instead use kstrdup and bail out, kfree():ing the memory used for MTD partitions and names alike on the errorpath. In the process rename the index variable from idx to i. Cc: Ryan Harkin Acked-by: Liviu Dudau Signed-off-by: Linus Walleij Signed-off-by: Richard Weinberger --- drivers/mtd/parsers/afs.c | 67 ++++++++++++++++++++++------------------------- 1 file changed, 32 insertions(+), 35 deletions(-) diff --git a/drivers/mtd/parsers/afs.c b/drivers/mtd/parsers/afs.c index 3679e1d22595..c489938cd665 100644 --- a/drivers/mtd/parsers/afs.c +++ b/drivers/mtd/parsers/afs.c @@ -166,9 +166,9 @@ static int parse_afs_partitions(struct mtd_info *mtd, struct mtd_part_parser_data *data) { struct mtd_partition *parts; - u_int mask, off, idx, sz; + u_int mask, off, sz; int ret = 0; - char *str; + int i; /* * This is the address mask; we use this to mask off out of @@ -181,78 +181,75 @@ static int parse_afs_partitions(struct mtd_info *mtd, * partition information. We include in this the size of * the strings. */ - for (idx = off = sz = 0; off < mtd->size; off += mtd->erasesize) { - struct image_info_v1 iis; + for (i = off = sz = 0; off < mtd->size; off += mtd->erasesize) { u_int iis_ptr, img_ptr; ret = afs_read_footer_v1(mtd, &img_ptr, &iis_ptr, off, mask); if (ret < 0) - break; + return ret; if (ret) { - ret = afs_read_iis_v1(mtd, &iis, iis_ptr); - if (ret < 0) - break; - if (ret == 0) - continue; - sz += sizeof(struct mtd_partition); - sz += strlen(iis.name) + 1; - idx += 1; + i += 1; } } - if (!sz) - return ret; + if (!i) + return 0; parts = kzalloc(sz, GFP_KERNEL); if (!parts) return -ENOMEM; - str = (char *)(parts + idx); - /* * Identify the partitions */ - for (idx = off = 0; off < mtd->size; off += mtd->erasesize) { + for (i = off = 0; off < mtd->size; off += mtd->erasesize) { struct image_info_v1 iis; u_int iis_ptr, img_ptr; /* Read the footer. */ ret = afs_read_footer_v1(mtd, &img_ptr, &iis_ptr, off, mask); if (ret < 0) - break; + goto out_free_parts; if (ret == 0) continue; /* Read the image info block */ ret = afs_read_iis_v1(mtd, &iis, iis_ptr); if (ret < 0) - break; + goto out_free_parts; if (ret == 0) continue; - strcpy(str, iis.name); + parts[i].name = kstrdup(iis.name, GFP_KERNEL); + if (!parts[i].name) { + ret = -ENOMEM; + goto out_free_parts; + } - parts[idx].name = str; - parts[idx].size = (iis.length + mtd->erasesize - 1) & ~(mtd->erasesize - 1); - parts[idx].offset = img_ptr; - parts[idx].mask_flags = 0; + parts[i].size = (iis.length + mtd->erasesize - 1) & ~(mtd->erasesize - 1); + parts[i].offset = img_ptr; + parts[i].mask_flags = 0; printk(" mtd%d: at 0x%08x, %5lluKiB, %8u, %s\n", - idx, img_ptr, parts[idx].size / 1024, - iis.imageNumber, str); - - idx += 1; - str = str + strlen(iis.name) + 1; - } + i, img_ptr, parts[i].size / 1024, + iis.imageNumber, parts[i].name); - if (!idx) { - kfree(parts); - parts = NULL; + i += 1; } *pparts = parts; - return idx ? idx : ret; + return i; + +out_free_parts: + while (i >= 0) { + if (parts[i].name) + kfree(parts[i].name); + i--; + } + kfree(parts); + *pparts = NULL; + return ret; } static const struct of_device_id mtd_parser_afs_of_match_table[] = { -- cgit From 20700171929316ed88fdd11b3099518a0bd2f36e Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 2 May 2019 16:30:30 +0200 Subject: mtd: afs: simplify partition detection Instead of reading out the AFS footers twice, create a separate function to just check if there is a footer or not. Rids a few local variables and prepare us to join the actual parser into one function. Cc: Ryan Harkin Acked-by: Liviu Dudau Signed-off-by: Linus Walleij Signed-off-by: Richard Weinberger --- drivers/mtd/parsers/afs.c | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/drivers/mtd/parsers/afs.c b/drivers/mtd/parsers/afs.c index c489938cd665..ccc198818057 100644 --- a/drivers/mtd/parsers/afs.c +++ b/drivers/mtd/parsers/afs.c @@ -68,6 +68,26 @@ static u32 word_sum(void *words, int num) return sum; } +static bool afs_is_v1(struct mtd_info *mtd, u_int off) +{ + /* The magic is 12 bytes from the end of the erase block */ + u_int ptr = off + mtd->erasesize - 12; + u32 magic; + size_t sz; + int ret; + + ret = mtd_read(mtd, ptr, 4, &sz, (u_char *)&magic); + if (ret < 0) { + printk(KERN_ERR "AFS: mtd read failed at 0x%x: %d\n", + ptr, ret); + return false; + } + if (ret >= 0 && sz != 4) + return false; + + return (magic == AFSV1_FOOTER_MAGIC); +} + static int afs_read_footer_v1(struct mtd_info *mtd, u_int *img_start, u_int *iis_start, u_int off, u_int mask) @@ -176,18 +196,9 @@ static int parse_afs_partitions(struct mtd_info *mtd, */ mask = mtd->size - 1; - /* - * First, calculate the size of the array we need for the - * partition information. We include in this the size of - * the strings. - */ + /* Count the partitions by looping over all erase blocks */ for (i = off = sz = 0; off < mtd->size; off += mtd->erasesize) { - u_int iis_ptr, img_ptr; - - ret = afs_read_footer_v1(mtd, &img_ptr, &iis_ptr, off, mask); - if (ret < 0) - return ret; - if (ret) { + if (afs_is_v1(mtd, off)) { sz += sizeof(struct mtd_partition); i += 1; } -- cgit From 4aeb1594796d21f10866b7bd28365024fba347ff Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 2 May 2019 16:30:31 +0200 Subject: mtd: factor out v1 partition parsing This breaks out the parsing of v1 partitions so we can later add a v2 partition parser. Cc: Ryan Harkin Acked-by: Liviu Dudau Signed-off-by: Linus Walleij Signed-off-by: Richard Weinberger --- drivers/mtd/parsers/afs.c | 88 +++++++++++++++++++++++++++-------------------- 1 file changed, 50 insertions(+), 38 deletions(-) diff --git a/drivers/mtd/parsers/afs.c b/drivers/mtd/parsers/afs.c index ccc198818057..32ded91ae66c 100644 --- a/drivers/mtd/parsers/afs.c +++ b/drivers/mtd/parsers/afs.c @@ -181,14 +181,18 @@ afs_read_iis_v1(struct mtd_info *mtd, struct image_info_v1 *iis, u_int ptr) return ret; } -static int parse_afs_partitions(struct mtd_info *mtd, - const struct mtd_partition **pparts, - struct mtd_part_parser_data *data) +static int afs_parse_v1_partition(struct mtd_info *mtd, + u_int off, struct mtd_partition *part) { - struct mtd_partition *parts; - u_int mask, off, sz; - int ret = 0; - int i; + struct image_info_v1 iis; + u_int mask; + /* + * Static checks cannot see that we bail out if we have an error + * reading the footer. + */ + u_int uninitialized_var(iis_ptr); + u_int uninitialized_var(img_ptr); + int ret; /* * This is the address mask; we use this to mask off out of @@ -196,6 +200,39 @@ static int parse_afs_partitions(struct mtd_info *mtd, */ mask = mtd->size - 1; + ret = afs_read_footer_v1(mtd, &img_ptr, &iis_ptr, off, mask); + if (ret < 0) + return ret; + + /* Read the image info block */ + ret = afs_read_iis_v1(mtd, &iis, iis_ptr); + if (ret < 0) + return ret; + + part->name = kstrdup(iis.name, GFP_KERNEL); + if (!part->name) + return -ENOMEM; + + part->size = (iis.length + mtd->erasesize - 1) & ~(mtd->erasesize - 1); + part->offset = img_ptr; + part->mask_flags = 0; + + printk(" mtd: at 0x%08x, %5lluKiB, %8u, %s\n", + img_ptr, part->size / 1024, + iis.imageNumber, part->name); + + return 0; +} + +static int parse_afs_partitions(struct mtd_info *mtd, + const struct mtd_partition **pparts, + struct mtd_part_parser_data *data) +{ + struct mtd_partition *parts; + u_int off, sz; + int ret = 0; + int i; + /* Count the partitions by looping over all erase blocks */ for (i = off = sz = 0; off < mtd->size; off += mtd->erasesize) { if (afs_is_v1(mtd, off)) { @@ -215,38 +252,13 @@ static int parse_afs_partitions(struct mtd_info *mtd, * Identify the partitions */ for (i = off = 0; off < mtd->size; off += mtd->erasesize) { - struct image_info_v1 iis; - u_int iis_ptr, img_ptr; - - /* Read the footer. */ - ret = afs_read_footer_v1(mtd, &img_ptr, &iis_ptr, off, mask); - if (ret < 0) - goto out_free_parts; - if (ret == 0) - continue; - - /* Read the image info block */ - ret = afs_read_iis_v1(mtd, &iis, iis_ptr); - if (ret < 0) - goto out_free_parts; - if (ret == 0) - continue; - - parts[i].name = kstrdup(iis.name, GFP_KERNEL); - if (!parts[i].name) { - ret = -ENOMEM; - goto out_free_parts; - } - parts[i].size = (iis.length + mtd->erasesize - 1) & ~(mtd->erasesize - 1); - parts[i].offset = img_ptr; - parts[i].mask_flags = 0; - - printk(" mtd%d: at 0x%08x, %5lluKiB, %8u, %s\n", - i, img_ptr, parts[i].size / 1024, - iis.imageNumber, parts[i].name); - - i += 1; + if (afs_is_v1(mtd, off)) { + ret = afs_parse_v1_partition(mtd, off, &parts[i]); + if (ret) + goto out_free_parts; + i++; + } } *pparts = parts; -- cgit From ff827b4e8d3606a275b92b159c7e9ae45ad2c361 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 2 May 2019 16:30:32 +0200 Subject: mtd: afs: factor footer parsing into the v1 part parsing This simplifies the code by factoring in the image footer parsing into the single function parsing the AFSv1 partitions. Cc: Ryan Harkin Acked-by: Liviu Dudau Signed-off-by: Linus Walleij Signed-off-by: Richard Weinberger --- drivers/mtd/parsers/afs.c | 98 +++++++++++++++++++---------------------------- 1 file changed, 39 insertions(+), 59 deletions(-) diff --git a/drivers/mtd/parsers/afs.c b/drivers/mtd/parsers/afs.c index 32ded91ae66c..8ff82a548252 100644 --- a/drivers/mtd/parsers/afs.c +++ b/drivers/mtd/parsers/afs.c @@ -88,63 +88,6 @@ static bool afs_is_v1(struct mtd_info *mtd, u_int off) return (magic == AFSV1_FOOTER_MAGIC); } -static int -afs_read_footer_v1(struct mtd_info *mtd, u_int *img_start, u_int *iis_start, - u_int off, u_int mask) -{ - struct footer_v1 fs; - u_int ptr = off + mtd->erasesize - sizeof(fs); - size_t sz; - int ret; - - ret = mtd_read(mtd, ptr, sizeof(fs), &sz, (u_char *)&fs); - if (ret >= 0 && sz != sizeof(fs)) - ret = -EINVAL; - - if (ret < 0) { - printk(KERN_ERR "AFS: mtd read failed at 0x%x: %d\n", - ptr, ret); - return ret; - } - - /* - * Does it contain the magic number? - */ - if (fs.signature != AFSV1_FOOTER_MAGIC) - return 0; - - /* - * Check the checksum. - */ - if (word_sum(&fs, sizeof(fs) / sizeof(u32)) != 0xffffffff) - return 0; - - /* - * Don't touch the SIB. - */ - if (fs.type == 2) - return 0; - - *iis_start = fs.image_info_base & mask; - *img_start = fs.image_start & mask; - - /* - * Check the image info base. This can not - * be located after the footer structure. - */ - if (*iis_start >= ptr) - return 0; - - /* - * Check the start of this image. The image - * data can not be located after this block. - */ - if (*img_start > off) - return 0; - - return 1; -} - static int afs_read_iis_v1(struct mtd_info *mtd, struct image_info_v1 *iis, u_int ptr) { @@ -184,6 +127,7 @@ afs_read_iis_v1(struct mtd_info *mtd, struct image_info_v1 *iis, u_int ptr) static int afs_parse_v1_partition(struct mtd_info *mtd, u_int off, struct mtd_partition *part) { + struct footer_v1 fs; struct image_info_v1 iis; u_int mask; /* @@ -192,6 +136,8 @@ static int afs_parse_v1_partition(struct mtd_info *mtd, */ u_int uninitialized_var(iis_ptr); u_int uninitialized_var(img_ptr); + u_int ptr; + size_t sz; int ret; /* @@ -200,9 +146,43 @@ static int afs_parse_v1_partition(struct mtd_info *mtd, */ mask = mtd->size - 1; - ret = afs_read_footer_v1(mtd, &img_ptr, &iis_ptr, off, mask); - if (ret < 0) + ptr = off + mtd->erasesize - sizeof(fs); + ret = mtd_read(mtd, ptr, sizeof(fs), &sz, (u_char *)&fs); + if (ret >= 0 && sz != sizeof(fs)) + ret = -EINVAL; + if (ret < 0) { + printk(KERN_ERR "AFS: mtd read failed at 0x%x: %d\n", + ptr, ret); return ret; + } + /* + * Check the checksum. + */ + if (word_sum(&fs, sizeof(fs) / sizeof(u32)) != 0xffffffff) + return -EINVAL; + + /* + * Hide the SIB (System Information Block) + */ + if (fs.type == 2) + return 0; + + iis_ptr = fs.image_info_base & mask; + img_ptr = fs.image_start & mask; + + /* + * Check the image info base. This can not + * be located after the footer structure. + */ + if (iis_ptr >= ptr) + return 0; + + /* + * Check the start of this image. The image + * data can not be located after this block. + */ + if (img_ptr > off) + return 0; /* Read the image info block */ ret = afs_read_iis_v1(mtd, &iis, iis_ptr); -- cgit From 32e68bea9338101253b72f594796c76acd68da11 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 2 May 2019 16:30:33 +0200 Subject: mtd: afs: factor the IIS read into partition parser Factor the IIS (Image Information Structure) reading into the partition parser, giving us a single, clean partition parser function. Cc: Ryan Harkin Acked-by: Liviu Dudau Signed-off-by: Linus Walleij Signed-off-by: Richard Weinberger --- drivers/mtd/parsers/afs.c | 59 ++++++++++++++++------------------------------- 1 file changed, 20 insertions(+), 39 deletions(-) diff --git a/drivers/mtd/parsers/afs.c b/drivers/mtd/parsers/afs.c index 8ff82a548252..72c688b8a383 100644 --- a/drivers/mtd/parsers/afs.c +++ b/drivers/mtd/parsers/afs.c @@ -88,42 +88,6 @@ static bool afs_is_v1(struct mtd_info *mtd, u_int off) return (magic == AFSV1_FOOTER_MAGIC); } -static int -afs_read_iis_v1(struct mtd_info *mtd, struct image_info_v1 *iis, u_int ptr) -{ - size_t sz; - int ret, i; - - memset(iis, 0, sizeof(*iis)); - ret = mtd_read(mtd, ptr, sizeof(*iis), &sz, (u_char *)iis); - if (ret < 0) - goto failed; - - if (sz != sizeof(*iis)) { - ret = -EINVAL; - goto failed; - } - - ret = 0; - - /* - * Validate the name - it must be NUL terminated. - */ - for (i = 0; i < sizeof(iis->name); i++) - if (iis->name[i] == '\0') - break; - - if (i < sizeof(iis->name)) - ret = 1; - - return ret; - - failed: - printk(KERN_ERR "AFS: mtd read failed at 0x%x: %d\n", - ptr, ret); - return ret; -} - static int afs_parse_v1_partition(struct mtd_info *mtd, u_int off, struct mtd_partition *part) { @@ -139,6 +103,7 @@ static int afs_parse_v1_partition(struct mtd_info *mtd, u_int ptr; size_t sz; int ret; + int i; /* * This is the address mask; we use this to mask off out of @@ -185,9 +150,25 @@ static int afs_parse_v1_partition(struct mtd_info *mtd, return 0; /* Read the image info block */ - ret = afs_read_iis_v1(mtd, &iis, iis_ptr); - if (ret < 0) - return ret; + memset(&iis, 0, sizeof(iis)); + ret = mtd_read(mtd, iis_ptr, sizeof(iis), &sz, (u_char *)&iis); + if (ret < 0) { + printk(KERN_ERR "AFS: mtd read failed at 0x%x: %d\n", + iis_ptr, ret); + return -EINVAL; + } + + if (sz != sizeof(iis)) + return -EINVAL; + + /* + * Validate the name - it must be NUL terminated. + */ + for (i = 0; i < sizeof(iis.name); i++) + if (iis.name[i] == '\0') + break; + if (i > sizeof(iis.name)) + return -EINVAL; part->name = kstrdup(iis.name, GFP_KERNEL); if (!part->name) -- cgit From b7cf5e2830bbb128699d7635ce8404b7f605bc95 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 6 May 2019 21:55:51 +0200 Subject: mtd: afs: add v2 partition parsing The AFS v2 partition type appear in later ARM reference designs such as RealView, Versatile Express and the 64bit Juno Development Platform. The image informations is padded with a 32bit word (4 bytes) on the 32bit platforms and a 64bit word (8 bytes) on the 64bit platforms. The boot monitor source code gives at hand that this is because the first entry in the struct mapped over the image information is a "next" pointer for a linked list, filled in by firmware after reading in the info block, and always zero in the flash. We adjust padding by checking what padding gives the right checksum. This was tested on: - Integrator/AP (v1 partitions) - RealView PB11MPCore (v2 32bit partitions) - Juno Development System (v2 64bit partitions) All systems display the images in flash very nicely as separate partitions, e.g on Juno: 4 afs partitions found on MTD device 8000000.flash Creating 4 MTD partitions on "8000000.flash": 0x000000040000-0x0000000c0000 : "fip" 0x000000ec0000-0x0000018c0000 : "Image" 0x000000f00000-0x000000f40000 : "juno" 0x000003ec0000-0x000003f00000 : "bl1" Cc: Ryan Harkin Acked-by: Liviu Dudau Signed-off-by: Linus Walleij Signed-off-by: Richard Weinberger --- drivers/mtd/parsers/afs.c | 158 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 157 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/parsers/afs.c b/drivers/mtd/parsers/afs.c index 72c688b8a383..0c730024f806 100644 --- a/drivers/mtd/parsers/afs.c +++ b/drivers/mtd/parsers/afs.c @@ -3,6 +3,7 @@ drivers/mtd/afs.c: ARM Flash Layout/Partitioning Copyright © 2000 ARM Limited + Copyright (C) 2019 Linus Walleij 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 @@ -35,6 +36,8 @@ #include #define AFSV1_FOOTER_MAGIC 0xA0FFFF9F +#define AFSV2_FOOTER_MAGIC1 0x464C5348 /* "FLSH" */ +#define AFSV2_FOOTER_MAGIC2 0x464F4F54 /* "FOOT" */ struct footer_v1 { u32 image_info_base; /* Address of first word of ImageFooter */ @@ -68,6 +71,22 @@ static u32 word_sum(void *words, int num) return sum; } +static u32 word_sum_v2(u32 *p, u32 num) +{ + u32 sum = 0; + int i; + + for (i = 0; i < num; i++) { + u32 val; + + val = p[i]; + if (val > ~sum) + sum++; + sum += val; + } + return ~sum; +} + static bool afs_is_v1(struct mtd_info *mtd, u_int off) { /* The magic is 12 bytes from the end of the erase block */ @@ -88,6 +107,27 @@ static bool afs_is_v1(struct mtd_info *mtd, u_int off) return (magic == AFSV1_FOOTER_MAGIC); } +static bool afs_is_v2(struct mtd_info *mtd, u_int off) +{ + /* The magic is the 8 last bytes of the erase block */ + u_int ptr = off + mtd->erasesize - 8; + u32 foot[2]; + size_t sz; + int ret; + + ret = mtd_read(mtd, ptr, 8, &sz, (u_char *)foot); + if (ret < 0) { + printk(KERN_ERR "AFS: mtd read failed at 0x%x: %d\n", + ptr, ret); + return false; + } + if (ret >= 0 && sz != 8) + return false; + + return (foot[0] == AFSV2_FOOTER_MAGIC1 && + foot[1] == AFSV2_FOOTER_MAGIC2); +} + static int afs_parse_v1_partition(struct mtd_info *mtd, u_int off, struct mtd_partition *part) { @@ -185,6 +225,113 @@ static int afs_parse_v1_partition(struct mtd_info *mtd, return 0; } +static int afs_parse_v2_partition(struct mtd_info *mtd, + u_int off, struct mtd_partition *part) +{ + u_int ptr; + u32 footer[12]; + u32 imginfo[36]; + char *name; + u32 version; + u32 entrypoint; + u32 attributes; + u32 region_count; + u32 block_start; + u32 block_end; + u32 crc; + size_t sz; + int ret; + int i; + int pad = 0; + + pr_debug("Parsing v2 partition @%08x-%08x\n", + off, off + mtd->erasesize); + + /* First read the footer */ + ptr = off + mtd->erasesize - sizeof(footer); + ret = mtd_read(mtd, ptr, sizeof(footer), &sz, (u_char *)footer); + if ((ret < 0) || (ret >= 0 && sz != sizeof(footer))) { + pr_err("AFS: mtd read failed at 0x%x: %d\n", + ptr, ret); + return -EIO; + } + name = (char *) &footer[0]; + version = footer[9]; + ptr = off + mtd->erasesize - sizeof(footer) - footer[8]; + + pr_debug("found image \"%s\", version %08x, info @%08x\n", + name, version, ptr); + + /* Then read the image information */ + ret = mtd_read(mtd, ptr, sizeof(imginfo), &sz, (u_char *)imginfo); + if ((ret < 0) || (ret >= 0 && sz != sizeof(imginfo))) { + pr_err("AFS: mtd read failed at 0x%x: %d\n", + ptr, ret); + return -EIO; + } + + /* 32bit platforms have 4 bytes padding */ + crc = word_sum_v2(&imginfo[1], 34); + if (!crc) { + pr_debug("Padding 1 word (4 bytes)\n"); + pad = 1; + } else { + /* 64bit platforms have 8 bytes padding */ + crc = word_sum_v2(&imginfo[2], 34); + if (!crc) { + pr_debug("Padding 2 words (8 bytes)\n"); + pad = 2; + } + } + if (crc) { + pr_err("AFS: bad checksum on v2 image info: %08x\n", crc); + return -EINVAL; + } + entrypoint = imginfo[pad]; + attributes = imginfo[pad+1]; + region_count = imginfo[pad+2]; + block_start = imginfo[20]; + block_end = imginfo[21]; + + pr_debug("image entry=%08x, attr=%08x, regions=%08x, " + "bs=%08x, be=%08x\n", + entrypoint, attributes, region_count, + block_start, block_end); + + for (i = 0; i < region_count; i++) { + u32 region_load_addr = imginfo[pad + 3 + i*4]; + u32 region_size = imginfo[pad + 4 + i*4]; + u32 region_offset = imginfo[pad + 5 + i*4]; + u32 region_start; + u32 region_end; + + pr_debug(" region %d: address: %08x, size: %08x, " + "offset: %08x\n", + i, + region_load_addr, + region_size, + region_offset); + + region_start = off + region_offset; + region_end = region_start + region_size; + /* Align partition to end of erase block */ + region_end += (mtd->erasesize - 1); + region_end &= ~(mtd->erasesize -1); + pr_debug(" partition start = %08x, partition end = %08x\n", + region_start, region_end); + + /* Create one partition per region */ + part->name = kstrdup(name, GFP_KERNEL); + if (!part->name) + return -ENOMEM; + part->offset = region_start; + part->size = region_end - region_start; + part->mask_flags = 0; + } + + return 0; +} + static int parse_afs_partitions(struct mtd_info *mtd, const struct mtd_partition **pparts, struct mtd_part_parser_data *data) @@ -200,6 +347,10 @@ static int parse_afs_partitions(struct mtd_info *mtd, sz += sizeof(struct mtd_partition); i += 1; } + if (afs_is_v2(mtd, off)) { + sz += sizeof(struct mtd_partition); + i += 1; + } } if (!i) @@ -213,13 +364,18 @@ static int parse_afs_partitions(struct mtd_info *mtd, * Identify the partitions */ for (i = off = 0; off < mtd->size; off += mtd->erasesize) { - if (afs_is_v1(mtd, off)) { ret = afs_parse_v1_partition(mtd, off, &parts[i]); if (ret) goto out_free_parts; i++; } + if (afs_is_v2(mtd, off)) { + ret = afs_parse_v2_partition(mtd, off, &parts[i]); + if (ret) + goto out_free_parts; + i++; + } } *pparts = parts; -- cgit From 8792620886e6a895229beb0386ffcaca4a08593f Mon Sep 17 00:00:00 2001 From: Richard Weinberger Date: Fri, 12 Apr 2019 09:27:31 +0200 Subject: MAINTAINERS: Update jffs2 entry Update the entry to represent the current state of jffs2. I'll carry fixes via the UBIFS tree, David has the last word on anything. New features are not planned. Signed-off-by: Richard Weinberger --- MAINTAINERS | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 897ccdacc0e0..2f5607bf3505 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8317,9 +8317,11 @@ F: drivers/net/ethernet/jme.* JOURNALLING FLASH FILE SYSTEM V2 (JFFS2) M: David Woodhouse +M: Richard Weinberger L: linux-mtd@lists.infradead.org W: http://www.linux-mtd.infradead.org/doc/jffs2.html -S: Maintained +T: git git://git.infradead.org/ubifs-2.6.git +S: Odd Fixes F: fs/jffs2/ F: include/uapi/linux/jffs2.h -- cgit From 553f0459b8082fef847863aa8afcc6ca37fbce05 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Fri, 5 Apr 2019 10:03:42 +0200 Subject: MAINTAINERS: MTD Git repository is hosted on kernel.org Because of the slowness of the infradead.org server, Linus requested that we send him PRs from another domain. We moved our Git repository to kernel.org and maintain the following branches: * Fixes based on the last -rc: mtd/fixes * Next branch based usually on -rc1: mtd/next, nand/next, spi-nor/next. Signed-off-by: Miquel Raynal Acked-by: Richard Weinberger Acked-by: Tudor Ambarus Acked-by: Vignesh Raghavendra Signed-off-by: Richard Weinberger --- MAINTAINERS | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 2f5607bf3505..2c02139d36e6 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -10017,8 +10017,8 @@ M: Vignesh Raghavendra L: linux-mtd@lists.infradead.org W: http://www.linux-mtd.infradead.org/ Q: http://patchwork.ozlabs.org/project/linux-mtd/list/ -T: git git://git.infradead.org/linux-mtd.git master -T: git git://git.infradead.org/linux-mtd.git mtd/next +T: git git://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux.git mtd/fixes +T: git git://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux.git mtd/next S: Maintained F: Documentation/devicetree/bindings/mtd/ F: drivers/mtd/ @@ -10630,8 +10630,7 @@ R: Richard Weinberger L: linux-mtd@lists.infradead.org W: http://www.linux-mtd.infradead.org/ Q: http://patchwork.ozlabs.org/project/linux-mtd/list/ -T: git git://git.infradead.org/linux-mtd.git nand/fixes -T: git git://git.infradead.org/linux-mtd.git nand/next +T: git git://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux.git nand/next S: Maintained F: drivers/mtd/nand/ F: include/linux/mtd/*nand*.h @@ -14616,8 +14615,7 @@ M: Tudor Ambarus L: linux-mtd@lists.infradead.org W: http://www.linux-mtd.infradead.org/ Q: http://patchwork.ozlabs.org/project/linux-mtd/list/ -T: git git://git.infradead.org/linux-mtd.git spi-nor/fixes -T: git git://git.infradead.org/linux-mtd.git spi-nor/next +T: git git://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux.git spi-nor/next S: Maintained F: drivers/mtd/spi-nor/ F: include/linux/mtd/spi-nor.h -- cgit From 660e171675282d82be044fc5e7fe1e444b7aaccc Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Fri, 8 Feb 2019 12:02:02 -0600 Subject: mtd: cfi_util: mark expected switch fall-throughs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In preparation to enabling -Wimplicit-fallthrough, mark switch cases where we are expecting to fall through. This patch fixes the following warnings: drivers/mtd/chips/cfi_util.c: In function ‘cfi_build_cmd’: drivers/mtd/chips/cfi_util.c:110:10: warning: this statement may fall through [-Wimplicit-fallthrough=] onecmd |= (onecmd << (chip_mode * 32)); ~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ drivers/mtd/chips/cfi_util.c:112:2: note: here case 4: ^~~~ drivers/mtd/chips/cfi_util.c:113:10: warning: this statement may fall through [-Wimplicit-fallthrough=] onecmd |= (onecmd << (chip_mode * 16)); ~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ drivers/mtd/chips/cfi_util.c:114:2: note: here case 2: ^~~~ drivers/mtd/chips/cfi_util.c: In function ‘cfi_merge_status’: drivers/mtd/chips/cfi_util.c:163:7: warning: this statement may fall through [-Wimplicit-fallthrough=] res |= (onestat >> (chip_mode * 32)); ~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ drivers/mtd/chips/cfi_util.c:165:2: note: here case 4: ^~~~ drivers/mtd/chips/cfi_util.c:166:7: warning: this statement may fall through [-Wimplicit-fallthrough=] res |= (onestat >> (chip_mode * 16)); ~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ drivers/mtd/chips/cfi_util.c:167:2: note: here case 2: ^~~~ Warning level 3 was used: -Wimplicit-fallthrough=3 This patch is part of the ongoing efforts to enabling -Wimplicit-fallthrough. Signed-off-by: Gustavo A. R. Silva Reviewed-by: Kees Cook Signed-off-by: Richard Weinberger --- drivers/mtd/chips/cfi_util.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/mtd/chips/cfi_util.c b/drivers/mtd/chips/cfi_util.c index 6f16552cd59f..e3b266ee06af 100644 --- a/drivers/mtd/chips/cfi_util.c +++ b/drivers/mtd/chips/cfi_util.c @@ -109,10 +109,13 @@ map_word cfi_build_cmd(u_long cmd, struct map_info *map, struct cfi_private *cfi case 8: onecmd |= (onecmd << (chip_mode * 32)); #endif + /* fall through */ case 4: onecmd |= (onecmd << (chip_mode * 16)); + /* fall through */ case 2: onecmd |= (onecmd << (chip_mode * 8)); + /* fall through */ case 1: ; } @@ -162,10 +165,13 @@ unsigned long cfi_merge_status(map_word val, struct map_info *map, case 8: res |= (onestat >> (chip_mode * 32)); #endif + /* fall through */ case 4: res |= (onestat >> (chip_mode * 16)); + /* fall through */ case 2: res |= (onestat >> (chip_mode * 8)); + /* fall through */ case 1: ; } -- cgit From af5d44b04dad70744a1750c733574436f51fd494 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Fri, 8 Feb 2019 12:06:15 -0600 Subject: mtd: cfi_cmdset_0002: Mark expected switch fall-throughs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In preparation to enabling -Wimplicit-fallthrough, mark switch cases where we are expecting to fall through. This patch fixes the following warnings: drivers/mtd/chips/cfi_cmdset_0002.c: In function ‘get_chip’: drivers/mtd/chips/cfi_cmdset_0002.c:870:6: warning: this statement may fall through [-Wimplicit-fallthrough=] if (mode == FL_READY && chip->oldstate == FL_READY) ^ drivers/mtd/chips/cfi_cmdset_0002.c:873:2: note: here default: ^~~~~~~ drivers/mtd/chips/cfi_cmdset_0002.c: In function ‘cfi_amdstd_sync’: drivers/mtd/chips/cfi_cmdset_0002.c:2745:16: warning: this statement may fall through [-Wimplicit-fallthrough=] chip->state = FL_SYNCING; ~~~~~~~~~~~~^~~~~~~~~~~~ drivers/mtd/chips/cfi_cmdset_0002.c:2750:3: note: here case FL_SYNCING: ^~~~ Warning level 3 was used: -Wimplicit-fallthrough=3 This patch is part of the ongoing efforts to enabling -Wimplicit-fallthrough. Signed-off-by: Gustavo A. R. Silva Reviewed-by: Tokunori Ikegami Signed-off-by: Richard Weinberger --- drivers/mtd/chips/cfi_cmdset_0002.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c index 7b7286b4d81e..c8fa5906bdf9 100644 --- a/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/drivers/mtd/chips/cfi_cmdset_0002.c @@ -869,6 +869,7 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr /* Only if there's no operation suspended... */ if (mode == FL_READY && chip->oldstate == FL_READY) return 0; + /* fall through */ default: sleep: @@ -2751,6 +2752,7 @@ static void cfi_amdstd_sync (struct mtd_info *mtd) * as the whole point is that nobody can do anything * with the chip now anyway. */ + /* fall through */ case FL_SYNCING: mutex_unlock(&chip->mutex); break; -- cgit From 098d74b4eaf63b7ab13ebdac4ad95f6b214b5f62 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Fri, 8 Feb 2019 12:09:11 -0600 Subject: mtd: phram: Mark expected switch fall-throughs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In preparation to enabling -Wimplicit-fallthrough, mark switch cases where we are expecting to fall through. This patch fixes the following warnings: drivers/mtd/devices/phram.c: In function ‘parse_num64’: drivers/mtd/devices/phram.c:149:11: warning: this statement may fall through [-Wimplicit-fallthrough=] shift += 10; ~~~~~~^~~~~ drivers/mtd/devices/phram.c:150:4: note: here case 'M': ^~~~ drivers/mtd/devices/phram.c:151:11: warning: this statement may fall through [-Wimplicit-fallthrough=] shift += 10; ~~~~~~^~~~~ drivers/mtd/devices/phram.c:152:4: note: here case 'k': ^~~~ Warning level 3 was used: -Wimplicit-fallthrough=3 This patch is part of the ongoing efforts to enabling -Wimplicit-fallthrough. Signed-off-by: Gustavo A. R. Silva Reviewed-by: Kees Cook Signed-off-by: Richard Weinberger --- drivers/mtd/devices/phram.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/mtd/devices/phram.c b/drivers/mtd/devices/phram.c index 9ee04b5f9311..8a8627c30aed 100644 --- a/drivers/mtd/devices/phram.c +++ b/drivers/mtd/devices/phram.c @@ -147,8 +147,10 @@ static int parse_num64(uint64_t *num64, char *token) switch (token[len - 2]) { case 'G': shift += 10; + /* fall through */ case 'M': shift += 10; + /* fall through */ case 'k': shift += 10; token[len - 2] = 0; -- cgit From fae4973c9a58858bc63a842cdaf7810955503399 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Fri, 8 Feb 2019 12:12:10 -0600 Subject: mtd: lpddr_cmds: Mark expected switch fall-through MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In preparation to enabling -Wimplicit-fallthrough, mark switch cases where we are expecting to fall through. This patch fixes the following warnings: drivers/mtd/lpddr/lpddr_cmds.c: In function ‘chip_ready’: drivers/mtd/lpddr/lpddr_cmds.c:319:6: warning: this statement may fall through [-Wimplicit-fallthrough=] if (mode == FL_READY && chip->oldstate == FL_READY) ^ drivers/mtd/lpddr/lpddr_cmds.c:322:2: note: here default: ^~~~~~~ Warning level 3 was used: -Wimplicit-fallthrough=3 This patch is part of the ongoing efforts to enabling -Wimplicit-fallthrough. Signed-off-by: Gustavo A. R. Silva Reviewed-by: Kees Cook Signed-off-by: Richard Weinberger --- drivers/mtd/lpddr/lpddr_cmds.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mtd/lpddr/lpddr_cmds.c b/drivers/mtd/lpddr/lpddr_cmds.c index b13557fe52bd..76a4c73e100e 100644 --- a/drivers/mtd/lpddr/lpddr_cmds.c +++ b/drivers/mtd/lpddr/lpddr_cmds.c @@ -318,6 +318,7 @@ static int chip_ready(struct map_info *map, struct flchip *chip, int mode) /* Only if there's no operation suspended... */ if (mode == FL_READY && chip->oldstate == FL_READY) return 0; + /* fall through */ default: sleep: -- cgit From 3008ba87093852f3756c5d33f584602e5e2a4aa4 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 31 Jan 2019 14:08:20 +0000 Subject: mtd: part: fix incorrect format specifier for an unsigned long long An unsigned long long is being formatted with %lld instead of the unsigned version %llu. Fix this. Clean up cppcheck warning: %lld in format string (no. 1) requires 'long long' but the argument type is 'unsigned long long'. Fixes: a62c24d75529 ("mtd: part: Add sysfs variable for offset of partition") Signed-off-by: Colin Ian King Signed-off-by: Richard Weinberger --- drivers/mtd/mtdpart.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index 37f174ccbcec..dfa241ad018b 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c @@ -572,7 +572,7 @@ static ssize_t mtd_partition_offset_show(struct device *dev, { struct mtd_info *mtd = dev_get_drvdata(dev); struct mtd_part *part = mtd_to_part(mtd); - return snprintf(buf, PAGE_SIZE, "%lld\n", part->offset); + return snprintf(buf, PAGE_SIZE, "%llu\n", part->offset); } static DEVICE_ATTR(offset, S_IRUGO, mtd_partition_offset_show, NULL); -- cgit