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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 me