From 5197360f9e09449ac7249a98fbde36a3608e059c Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Mon, 18 May 2020 19:03:21 +0200 Subject: mtd: rawnand: mtk: Convert the driver to exec_op() Let's convert the driver to exec_op() to have one less driver relying on the legacy interface. Signed-off-by: Boris Brezillon Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20200518170321.321697-1-boris.brezillon@collabora.com --- drivers/mtd/nand/raw/mtk_nand.c | 116 ++++++++++++++++++++++++---------------- 1 file changed, 71 insertions(+), 45 deletions(-) diff --git a/drivers/mtd/nand/raw/mtk_nand.c b/drivers/mtd/nand/raw/mtk_nand.c index c1a6e31aabb8..ca8457626d53 100644 --- a/drivers/mtd/nand/raw/mtk_nand.c +++ b/drivers/mtd/nand/raw/mtk_nand.c @@ -387,44 +387,6 @@ static int mtk_nfc_hw_runtime_config(struct mtd_info *mtd) return 0; } -static void mtk_nfc_select_chip(struct nand_chip *nand, int chip) -{ - struct mtk_nfc *nfc = nand_get_controller_data(nand); - struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(nand); - - if (chip < 0) - return; - - mtk_nfc_hw_runtime_config(nand_to_mtd(nand)); - - nfi_writel(nfc, mtk_nand->sels[chip], NFI_CSEL); -} - -static int mtk_nfc_dev_ready(struct nand_chip *nand) -{ - struct mtk_nfc *nfc = nand_get_controller_data(nand); - - if (nfi_readl(nfc, NFI_STA) & STA_BUSY) - return 0; - - return 1; -} - -static void mtk_nfc_cmd_ctrl(struct nand_chip *chip, int dat, - unsigned int ctrl) -{ - struct mtk_nfc *nfc = nand_get_controller_data(chip); - - if (ctrl & NAND_ALE) { - mtk_nfc_send_address(nfc, dat); - } else if (ctrl & NAND_CLE) { - mtk_nfc_hw_reset(nfc); - - nfi_writew(nfc, CNFG_OP_CUST, NFI_CNFG); - mtk_nfc_send_command(nfc, dat); - } -} - static inline void mtk_nfc_wait_ioready(struct mtk_nfc *nfc) { int rc; @@ -501,6 +463,74 @@ static void mtk_nfc_write_buf(struct nand_chip *chip, const u8 *buf, int len) mtk_nfc_write_byte(chip, buf[i]); } +static int mtk_nfc_exec_instr(struct nand_chip *chip, + const struct nand_op_instr *instr) +{ + struct mtk_nfc *nfc = nand_get_controller_data(chip); + unsigned int i; + u32 status; + + switch (instr->type) { + case NAND_OP_CMD_INSTR: + mtk_nfc_send_command(nfc, instr->ctx.cmd.opcode); + return 0; + case NAND_OP_ADDR_INSTR: + for (i = 0; i < instr->ctx.addr.naddrs; i++) + mtk_nfc_send_address(nfc, instr->ctx.addr.addrs[i]); + return 0; + case NAND_OP_DATA_IN_INSTR: + mtk_nfc_read_buf(chip, instr->ctx.data.buf.in, + instr->ctx.data.len); + return 0; + case NAND_OP_DATA_OUT_INSTR: + mtk_nfc_write_buf(chip, instr->ctx.data.buf.out, + instr->ctx.data.len); + return 0; + case NAND_OP_WAITRDY_INSTR: + return readl_poll_timeout(nfc->regs + NFI_STA, status, + status & STA_BUSY, 20, + instr->ctx.waitrdy.timeout_ms); + default: + break; + } + + return -EINVAL; +} + +static void mtk_nfc_select_target(struct nand_chip *nand, unsigned int cs) +{ + struct mtk_nfc *nfc = nand_get_controller_data(nand); + struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(nand); + + mtk_nfc_hw_runtime_config(nand_to_mtd(nand)); + + nfi_writel(nfc, mtk_nand->sels[cs], NFI_CSEL); +} + +static int mtk_nfc_exec_op(struct nand_chip *chip, + const struct nand_operation *op, + bool check_only) +{ + struct mtk_nfc *nfc = nand_get_controller_data(chip); + unsigned int i; + int ret = 0; + + if (check_only) + return 0; + + mtk_nfc_hw_reset(nfc); + nfi_writew(nfc, CNFG_OP_CUST, NFI_CNFG); + mtk_nfc_select_target(chip, op->cs); + + for (i = 0; i < op->ninstrs; i++) { + ret = mtk_nfc_exec_instr(chip, &op->instrs[i]); + if (ret) + break; + } + + return ret; +} + static int mtk_nfc_setup_data_interface(struct nand_chip *chip, int csline, const struct nand_data_interface *conf) { @@ -803,6 +833,7 @@ static int mtk_nfc_write_page(struct mtd_info *mtd, struct nand_chip *chip, u32 reg; int ret; + mtk_nfc_select_target(chip, chip->cur_cs); nand_prog_page_begin_op(chip, page, 0, NULL, 0); if (!raw) { @@ -920,6 +951,7 @@ static int mtk_nfc_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, u8 *buf; int rc; + mtk_nfc_select_target(chip, chip->cur_cs); start = data_offs / chip->ecc.size; end = DIV_ROUND_UP(data_offs + readlen, chip->ecc.size); @@ -1326,6 +1358,7 @@ static int mtk_nfc_attach_chip(struct nand_chip *chip) static const struct nand_controller_ops mtk_nfc_controller_ops = { .attach_chip = mtk_nfc_attach_chip, .setup_data_interface = mtk_nfc_setup_data_interface, + .exec_op = mtk_nfc_exec_op, }; static int mtk_nfc_nand_chip_init(struct device *dev, struct mtk_nfc *nfc, @@ -1381,13 +1414,6 @@ static int mtk_nfc_nand_chip_init(struct device *dev, struct mtk_nfc *nfc, nand_set_controller_data(nand, nfc); nand->options |= NAND_USES_DMA | NAND_SUBPAGE_READ; - nand->legacy.dev_ready = mtk_nfc_dev_ready; - nand->legacy.select_chip = mtk_nfc_select_chip; - nand->legacy.write_byte = mtk_nfc_write_byte; - nand->legacy.write_buf = mtk_nfc_write_buf; - nand->legacy.read_byte = mtk_nfc_read_byte; - nand->legacy.read_buf = mtk_nfc_read_buf; - nand->legacy.cmd_ctrl = mtk_nfc_cmd_ctrl; /* set default mode in case dt entry is missing */ nand->ecc.mode = NAND_ECC_HW; -- cgit v1.2.3 From 90d6bf481a5d0c32112925f3ecc640b9145f77d8 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Mon, 18 May 2020 19:09:12 +0200 Subject: mtd: rawnand: tango: Convert the driver to exec_op() Let's convert the driver to exec_op() to have one less driver relying on the legacy interface. Signed-off-by: Boris Brezillon Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20200518170912.328988-1-boris.brezillon@collabora.com --- drivers/mtd/nand/raw/tango_nand.c | 125 ++++++++++++++++++++++++-------------- 1 file changed, 79 insertions(+), 46 deletions(-) diff --git a/drivers/mtd/nand/raw/tango_nand.c b/drivers/mtd/nand/raw/tango_nand.c index 246871e01027..b3a0d08f1733 100644 --- a/drivers/mtd/nand/raw/tango_nand.c +++ b/drivers/mtd/nand/raw/tango_nand.c @@ -113,59 +113,80 @@ struct tango_chip { #define TIMING(t0, t1, t2, t3) ((t0) << 24 | (t1) << 16 | (t2) << 8 | (t3)) -static void tango_cmd_ctrl(struct nand_chip *chip, int dat, unsigned int ctrl) +static void tango_select_target(struct nand_chip *chip, unsigned int cs) { + struct tango_nfc *nfc = to_tango_nfc(chip->controller); struct tango_chip *tchip = to_tango_chip(chip); - if (ctrl & NAND_CLE) - writeb_relaxed(dat, tchip->base + PBUS_CMD); - - if (ctrl & NAND_ALE) - writeb_relaxed(dat, tchip->base + PBUS_ADDR); + writel_relaxed(tchip->timing1, nfc->reg_base + NFC_TIMING1); + writel_relaxed(tchip->timing2, nfc->reg_base + NFC_TIMING2); + writel_relaxed(tchip->xfer_cfg, nfc->reg_base + NFC_XFER_CFG); + writel_relaxed(tchip->pkt_0_cfg, nfc->reg_base + NFC_PKT_0_CFG); + writel_relaxed(tchip->pkt_n_cfg, nfc->reg_base + NFC_PKT_N_CFG); + writel_relaxed(tchip->bb_cfg, nfc->reg_base + NFC_BB_CFG); } -static int tango_dev_ready(struct nand_chip *chip) +static int tango_waitrdy(struct nand_chip *chip, unsigned int timeout_ms) { struct tango_nfc *nfc = to_tango_nfc(chip->controller); + u32 status; - return readl_relaxed(nfc->pbus_base + PBUS_CS_CTRL) & PBUS_IORDY; + return readl_relaxed_poll_timeout(nfc->pbus_base + PBUS_CS_CTRL, + status, status & PBUS_IORDY, 20, + timeout_ms); } -static u8 tango_read_byte(struct nand_chip *chip) +static int tango_exec_instr(struct nand_chip *chip, + const struct nand_op_instr *instr) { struct tango_chip *tchip = to_tango_chip(chip); + unsigned int i; - return readb_relaxed(tchip->base + PBUS_DATA); -} - -static void tango_read_buf(struct nand_chip *chip, u8 *buf, int len) -{ - struct tango_chip *tchip = to_tango_chip(chip); + switch (instr->type) { + case NAND_OP_CMD_INSTR: + writeb_relaxed(instr->ctx.cmd.opcode, tchip->base + PBUS_CMD); + return 0; + case NAND_OP_ADDR_INSTR: + for (i = 0; i < instr->ctx.addr.naddrs; i++) + writeb_relaxed(instr->ctx.addr.addrs[i], + tchip->base + PBUS_ADDR); + return 0; + case NAND_OP_DATA_IN_INSTR: + ioread8_rep(tchip->base + PBUS_DATA, instr->ctx.data.buf.in, + instr->ctx.data.len); + return 0; + case NAND_OP_DATA_OUT_INSTR: + iowrite8_rep(tchip->base + PBUS_DATA, instr->ctx.data.buf.out, + instr->ctx.data.len); + return 0; + case NAND_OP_WAITRDY_INSTR: + return tango_waitrdy(chip, + instr->ctx.waitrdy.timeout_ms); + default: + break; + } - ioread8_rep(tchip->base + PBUS_DATA, buf, len); + return -EINVAL; } -static void tango_write_buf(struct nand_chip *chip, const u8 *buf, int len) +static int tango_exec_op(struct nand_chip *chip, + const struct nand_operation *op, + bool check_only) { - struct tango_chip *tchip = to_tango_chip(chip); - - iowrite8_rep(tchip->base + PBUS_DATA, buf, len); -} + unsigned int i; + int ret = 0; -static void tango_select_chip(struct nand_chip *chip, int idx) -{ - struct tango_nfc *nfc = to_tango_nfc(chip->controller); - struct tango_chip *tchip = to_tango_chip(chip); + if (check_only) + return 0; - if (idx < 0) - return; /* No "chip unselect" function */ + tango_select_target(chip, op->cs); + for (i = 0; i < op->ninstrs; i++) { + ret = tango_exec_instr(chip, &op->instrs[i]); + if (ret) + break; + } - writel_relaxed(tchip->timing1, nfc->reg_base + NFC_TIMING1); - writel_relaxed(tchip->timing2, nfc->reg_base + NFC_TIMING2); - writel_relaxed(tchip->xfer_cfg, nfc->reg_base + NFC_XFER_CFG); - writel_relaxed(tchip->pkt_0_cfg, nfc->reg_base + NFC_PKT_0_CFG); - writel_relaxed(tchip->pkt_n_cfg, nfc->reg_base + NFC_PKT_N_CFG); - writel_relaxed(tchip->bb_cfg, nfc->reg_base + NFC_BB_CFG); + return ret; } /* @@ -279,6 +300,7 @@ static int tango_read_page(struct nand_chip *chip, u8 *buf, struct tango_nfc *nfc = to_tango_nfc(chip->controller); int err, res, len = mtd->writesize; + tango_select_target(chip, chip->cur_cs); if (oob_required) chip->ecc.read_oob(chip, page); @@ -300,22 +322,30 @@ static int tango_write_page(struct nand_chip *chip, const u8 *buf, { struct mtd_info *mtd = nand_to_mtd(chip); struct tango_nfc *nfc = to_tango_nfc(chip->controller); - int err, status, len = mtd->writesize; + const struct nand_sdr_timings *timings; + int err, len = mtd->writesize; + u8 status; /* Calling tango_write_oob() would send PAGEPROG twice */ if (oob_required) return -ENOTSUPP; + tango_select_target(chip, chip->cur_cs); writel_relaxed(0xffffffff, nfc->mem_base + METADATA); err = do_dma(nfc, DMA_TO_DEVICE, NFC_WRITE, buf, len, page); if (err) return err; - status = chip->legacy.waitfunc(chip); - if (status & NAND_STATUS_FAIL) - return -EIO; + timings = nand_get_sdr_timings(&chip->data_interface); + err = tango_waitrdy(chip, PSEC_TO_MSEC(timings->tR_max)); + if (err) + return err; - return 0; + err = nand_status_op(chip, &status); + if (err) + return err; + + return (status & NAND_STATUS_FAIL) ? -EIO : 0; } static void aux_read(struct nand_chip *chip, u8 **buf, int len, int *pos) @@ -326,7 +356,9 @@ static void aux_read(struct nand_chip *chip, u8 **buf, int len, int *pos) /* skip over "len" bytes */ nand_change_read_column_op(chip, *pos, NULL, 0, false); } else { - tango_read_buf(chip, *buf, len); + struct tango_chip *tchip = to_tango_chip(chip); + + ioread8_rep(tchip->base + PBUS_DATA, *buf, len); *buf += len; } } @@ -339,7 +371,9 @@ static void aux_write(struct nand_chip *chip, const u8 **buf, int len, int *pos) /* skip over "len" bytes */ nand_change_write_column_op(chip, *pos, NULL, 0, false); } else { - tango_write_buf(chip, *buf, len); + struct tango_chip *tchip = to_tango_chip(chip); + + iowrite8_rep(tchip->base + PBUS_DATA, *buf, len); *buf += len; } } @@ -420,6 +454,7 @@ static void raw_write(struct nand_chip *chip, const u8 *buf, const u8 *oob) static int tango_read_page_raw(struct nand_chip *chip, u8 *buf, int oob_required, int page) { + tango_select_target(chip, chip->cur_cs); nand_read_page_op(chip, page, 0, NULL, 0); raw_read(chip, buf, chip->oob_poi); return 0; @@ -428,6 +463,7 @@ static int tango_read_page_raw(struct nand_chip *chip, u8 *buf, static int tango_write_page_raw(struct nand_chip *chip, const u8 *buf, int oob_required, int page) { + tango_select_target(chip, chip->cur_cs); nand_prog_page_begin_op(chip, page, 0, NULL, 0); raw_write(chip, buf, chip->oob_poi); return nand_prog_page_end_op(chip); @@ -435,6 +471,7 @@ static int tango_write_page_raw(struct nand_chip *chip, const u8 *buf, static int tango_read_oob(struct nand_chip *chip, int page) { + tango_select_target(chip, chip->cur_cs); nand_read_page_op(chip, page, 0, NULL, 0); raw_read(chip, NULL, chip->oob_poi); return 0; @@ -442,6 +479,7 @@ static int tango_read_oob(struct nand_chip *chip, int page) static int tango_write_oob(struct nand_chip *chip, int page) { + tango_select_target(chip, chip->cur_cs); nand_prog_page_begin_op(chip, page, 0, NULL, 0); raw_write(chip, NULL, chip->oob_poi); return nand_prog_page_end_op(chip); @@ -528,6 +566,7 @@ static int tango_attach_chip(struct nand_chip *chip) static const struct nand_controller_ops tango_controller_ops = { .attach_chip = tango_attach_chip, .setup_data_interface = tango_set_timings, + .exec_op = tango_exec_op, }; static int chip_init(struct device *dev, struct device_node *np) @@ -562,12 +601,6 @@ static int chip_init(struct device *dev, struct device_node *np) ecc = &chip->ecc; mtd = nand_to_mtd(chip); - chip->legacy.read_byte = tango_read_byte; - chip->legacy.write_buf = tango_write_buf; - chip->legacy.read_buf = tango_read_buf; - chip->legacy.select_chip = tango_select_chip; - chip->legacy.cmd_ctrl = tango_cmd_ctrl; - chip->legacy.dev_ready = tango_dev_ready; chip->options = NAND_USES_DMA | NAND_NO_SUBPAGE_WRITE | NAND_WAIT_TCCS; -- cgit v1.2.3 From ba9f316986502471b160470e5e27a5e5a2ccadaf Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Wed, 20 May 2020 01:24:52 +0200 Subject: dt-bindings: mtd: nand: Document the generic rb-gpios property A few drivers use this property to describe GPIO pins used to sample the NAND Ready/Busy state. Let's make it part of the generic binding doc. Signed-off-by: Boris Brezillon Reviewed-by: Rob Herring Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20200519232454.374081-2-boris.brezillon@collabora.com --- Documentation/devicetree/bindings/mtd/nand-controller.yaml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Documentation/devicetree/bindings/mtd/nand-controller.yaml b/Documentation/devicetree/bindings/mtd/nand-controller.yaml index cde7c4d79efe..40fc5b0b2b8c 100644 --- a/Documentation/devicetree/bindings/mtd/nand-controller.yaml +++ b/Documentation/devicetree/bindings/mtd/nand-controller.yaml @@ -114,6 +114,13 @@ patternProperties: description: Contains the native Ready/Busy IDs. + rb-gpios: + description: + Contains one or more GPIO descriptor (the numper of descriptor + depends on the number of R/B pins exposed by the flash) for the + Ready/Busy pins. Active state refers to the NAND ready state and + should be set to GPIOD_ACTIVE_HIGH unless the signal is inverted. + required: - reg -- cgit v1.2.3 From 33d226f504ed72cba3a2b42bbe2a993b3d6d9548 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Fri, 29 May 2020 02:25:06 +0200 Subject: mtd: nand: Move nand_device forward declaration to the top This structure might be used earlier in this file, let's move the forward declaration at the top. Signed-off-by: Miquel Raynal Reviewed-by: Boris Brezillon Link: https://lore.kernel.org/linux-mtd/20200529002517.3546-10-miquel.raynal@bootlin.com --- include/linux/mtd/nand.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 0c7483843a32..a1f38c778d0e 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -12,6 +12,8 @@ #include +struct nand_device; + /** * struct nand_memory_organization - Memory organization structure * @bits_per_cell: number of bits per NAND cell @@ -133,8 +135,6 @@ struct nand_bbt { unsigned long *cache; }; -struct nand_device; - /** * struct nand_ops - NAND operations * @erase: erase a specific block. No need to check if the block is bad before -- cgit v1.2.3 From deedeb60e812b464c18a9902984eb3f643efcae9 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Fri, 29 May 2020 02:25:07 +0200 Subject: mtd: nand: Add an extra level in the Kconfig hierarchy Use an extra level in Kconfig for all NAND related entries. Signed-off-by: Miquel Raynal Reviewed-by: Boris Brezillon Link: https://lore.kernel.org/linux-mtd/20200529002517.3546-11-miquel.raynal@bootlin.com --- drivers/mtd/nand/Kconfig | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index a5d8a211cb8a..c1a45b071165 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -1,7 +1,12 @@ # SPDX-License-Identifier: GPL-2.0-only + +menu "NAND" + config MTD_NAND_CORE tristate source "drivers/mtd/nand/onenand/Kconfig" source "drivers/mtd/nand/raw/Kconfig" source "drivers/mtd/nand/spi/Kconfig" + +endmenu -- cgit v1.2.3 From 6232095cc57cd096f126fa23c227a20a1669cc4f Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Fri, 29 May 2020 02:25:08 +0200 Subject: mtd: nand: Drop useless 'depends on' in Kconfig Both OneNAND and raw NAND bits can't be compiled if MTD is disabled because of the if/endif logic in drivers/mtd/Kconfig. There is no need for an extra "depends on MTD" in their respective Kconfig files. Signed-off-by: Miquel Raynal Reviewed-by: Boris Brezillon Link: https://lore.kernel.org/linux-mtd/20200529002517.3546-12-miquel.raynal@bootlin.com --- drivers/mtd/nand/onenand/Kconfig | 1 - drivers/mtd/nand/raw/Kconfig | 1 - 2 files changed, 2 deletions(-) diff --git a/drivers/mtd/nand/onenand/Kconfig b/drivers/mtd/nand/onenand/Kconfig index 572b8fe69abb..1a0e65bc246e 100644 --- a/drivers/mtd/nand/onenand/Kconfig +++ b/drivers/mtd/nand/onenand/Kconfig @@ -1,7 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only menuconfig MTD_ONENAND tristate "OneNAND Device Support" - depends on MTD depends on HAS_IOMEM help This enables support for accessing all type of OneNAND flash diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig index 113f61052269..85280e327bfe 100644 --- a/drivers/mtd/nand/raw/Kconfig +++ b/drivers/mtd/nand/raw/Kconfig @@ -12,7 +12,6 @@ config MTD_NAND_ECC_SW_HAMMING_SMC menuconfig MTD_RAW_NAND tristate "Raw/Parallel NAND Device Support" - depends on MTD select MTD_NAND_CORE select MTD_NAND_ECC_SW_HAMMING help -- cgit v1.2.3 From 85f54c5588885cc3b5be4a07498dd0755de9f5cf Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Fri, 29 May 2020 02:25:10 +0200 Subject: mtd: nand: Rename a core structure Prepare the migration to a generic ECC engine by renaming the nand_ecc_req structure into nand_ecc_props. This structure will be the base of a wider 'nand_ecc' structure. In nand_device, these properties are still named "eccreq" even if "eccprops" might be more descriptive. This is just a transition step, this field is being replaced very soon by a much wider structure. The impact of renaming this field would be huge compared to its interest. Signed-off-by: Miquel Raynal Reviewed-by: Boris Brezillon Link: https://lore.kernel.org/linux-mtd/20200529002517.3546-14-miquel.raynal@bootlin.com --- include/linux/mtd/nand.h | 8 ++++---- include/linux/mtd/spinand.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index a1f38c778d0e..af99041ceaa9 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -116,11 +116,11 @@ struct nand_page_io_req { }; /** - * struct nand_ecc_req - NAND ECC requirements + * struct nand_ecc_props - NAND ECC properties * @strength: ECC strength - * @step_size: ECC step/block size + * @step_size: Number of bytes per step */ -struct nand_ecc_req { +struct nand_ecc_props { unsigned int strength; unsigned int step_size; }; @@ -179,7 +179,7 @@ struct nand_ops { struct nand_device { struct mtd_info mtd; struct nand_memory_organization memorg; - struct nand_ecc_req eccreq; + struct nand_ecc_props eccreq; struct nand_row_converter rowconv; struct nand_bbt bbt; const struct nand_ops *ops; diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h index 1077c45721ff..7b78c4ba9b3e 100644 --- a/include/linux/mtd/spinand.h +++ b/include/linux/mtd/spinand.h @@ -309,7 +309,7 @@ struct spinand_info { struct spinand_devid devid; u32 flags; struct nand_memory_organization memorg; - struct nand_ecc_req eccreq; + struct nand_ecc_props eccreq; struct spinand_ecc_info eccinfo; struct { const struct spinand_op_variants *read_cache; -- cgit v1.2.3 From c4cabc08d09e4b107b685e08bdec8a38a91089d8 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Fri, 29 May 2020 13:12:55 +0200 Subject: mtd: rawnand: Use unsigned types for nand_chip unsigned values page_shift, phys_erase_shift, bbt_erase_shift, chip_shift, pagemask, subpagesize and badblockbits are all positive values, so declare them as unsigned. Signed-off-by: Miquel Raynal Reviewed-by: Boris Brezillon Link: https://lore.kernel.org/linux-mtd/20200529111322.7184-2-miquel.raynal@bootlin.com --- include/linux/mtd/rawnand.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h index 65b1c1c18b41..830f2d08937f 100644 --- a/include/linux/mtd/rawnand.h +++ b/include/linux/mtd/rawnand.h @@ -1110,11 +1110,11 @@ struct nand_chip { unsigned int options; unsigned int bbt_options; - int page_shift; - int phys_erase_shift; - int bbt_erase_shift; - int chip_shift; - int pagemask; + unsigned int page_shift; + unsigned int phys_erase_shift; + unsigned int bbt_erase_shift; + unsigned int chip_shift; + unsigned int pagemask; u8 *data_buf; struct { @@ -1122,10 +1122,10 @@ struct nand_chip { int page; } pagecache; - int subpagesize; + unsigned int subpagesize; int onfi_timing_mode_default; unsigned int badblockpos; - int badblockbits; + unsigned int badblockbits; struct nand_id id; struct nand_parameters parameters; -- cgit v1.2.3 From d1f3837a507d73746f9e2118fad20ee5e57e86cc Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Fri, 29 May 2020 13:12:56 +0200 Subject: mtd: rawnand: Only use u8 instead of uint8_t in nand_chip structure Mechanical change to avoid using old types. Signed-off-by: Miquel Raynal Reviewed-by: Boris Brezillon Link: https://lore.kernel.org/linux-mtd/20200529111322.7184-3-miquel.raynal@bootlin.com --- 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 830f2d08937f..cea137778224 100644 --- a/include/linux/mtd/rawnand.h +++ b/include/linux/mtd/rawnand.h @@ -1141,13 +1141,13 @@ struct nand_chip { int (*suspend)(struct nand_chip *chip); void (*resume)(struct nand_chip *chip); - uint8_t *oob_poi; + u8 *oob_poi; struct nand_controller *controller; struct nand_ecc_ctrl ecc; unsigned long buf_align; - uint8_t *bbt; + u8 *bbt; struct nand_bbt_descr *bbt_td; struct nand_bbt_descr *bbt_md; -- cgit v1.2.3 From 8e8b2706e15d16443b1ea61a6f994c08ec5b9486 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Fri, 29 May 2020 13:12:57 +0200 Subject: mtd: rawnand: Create a nand_chip operations structure And move nand_chip hooks there. While moving entries from one structure to the other, adapt the documentation style. Signed-off-by: Miquel Raynal Reviewed-by: Boris Brezillon Link: https://lore.kernel.org/linux-mtd/20200529111322.7184-4-miquel.raynal@bootlin.com --- drivers/mtd/nand/raw/nand_base.c | 20 ++++++++++---------- drivers/mtd/nand/raw/nand_hynix.c | 2 +- drivers/mtd/nand/raw/nand_macronix.c | 10 +++++----- drivers/mtd/nand/raw/nand_micron.c | 2 +- include/linux/mtd/rawnand.h | 32 ++++++++++++++++++-------------- 5 files changed, 35 insertions(+), 31 deletions(-) diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c index 45124dbb1835..d9cb71e7c0ed 100644 --- a/drivers/mtd/nand/raw/nand_base.c +++ b/drivers/mtd/nand/raw/nand_base.c @@ -3215,10 +3215,10 @@ static int nand_setup_read_retry(struct nand_chip *chip, int retry_mode) if (retry_mode >= chip->read_retries) return -EINVAL; - if (!chip->setup_read_retry) + if (!chip->ops.setup_read_retry) return -EOPNOTSUPP; - return chip->setup_read_retry(chip, retry_mode); + return chip->ops.setup_read_retry(chip, retry_mode); } static void nand_wait_readrdy(struct nand_chip *chip) @@ -4462,8 +4462,8 @@ static int nand_suspend(struct mtd_info *mtd) int ret = 0; mutex_lock(&chip->lock); - if (chip->suspend) - ret = chip->suspend(chip); + if (chip->ops.suspend) + ret = chip->ops.suspend(chip); if (!ret) chip->suspended = 1; mutex_unlock(&chip->lock); @@ -4481,8 +4481,8 @@ static void nand_resume(struct mtd_info *mtd) mutex_lock(&chip->lock); if (chip->suspended) { - if (chip->resume) - chip->resume(chip); + if (chip->ops.resume) + chip->ops.resume(chip); chip->suspended = 0; } else { pr_err("%s called for a chip which is not in suspended state\n", @@ -4511,10 +4511,10 @@ static int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) { struct nand_chip *chip = mtd_to_nand(mtd); - if (!chip->lock_area) + if (!chip->ops.lock_area) return -ENOTSUPP; - return chip->lock_area(chip, ofs, len); + return chip->ops.lock_area(chip, ofs, len); } /** @@ -4527,10 +4527,10 @@ static int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) { struct nand_chip *chip = mtd_to_nand(mtd); - if (!chip->unlock_area) + if (!chip->ops.unlock_area) return -ENOTSUPP; - return chip->unlock_area(chip, ofs, len); + return chip->ops.unlock_area(chip, ofs, len); } /* Set default functions */ diff --git a/drivers/mtd/nand/raw/nand_hynix.c b/drivers/mtd/nand/raw/nand_hynix.c index 7caedaa5b9e5..7d1be53f27f3 100644 --- a/drivers/mtd/nand/raw/nand_hynix.c +++ b/drivers/mtd/nand/raw/nand_hynix.c @@ -337,7 +337,7 @@ static int hynix_mlc_1xnm_rr_init(struct nand_chip *chip, rr->nregs = nregs; rr->regs = hynix_1xnm_mlc_read_retry_regs; hynix->read_retry = rr; - chip->setup_read_retry = hynix_nand_setup_read_retry; + chip->ops.setup_read_retry = hynix_nand_setup_read_retry; chip->read_retries = nmodes; out: diff --git a/drivers/mtd/nand/raw/nand_macronix.c b/drivers/mtd/nand/raw/nand_macronix.c index 09c254c97b5c..1472f925f386 100644 --- a/drivers/mtd/nand/raw/nand_macronix.c +++ b/drivers/mtd/nand/raw/nand_macronix.c @@ -130,7 +130,7 @@ static void macronix_nand_onfi_init(struct nand_chip *chip) return; chip->read_retries = MACRONIX_NUM_READ_RETRY_MODES; - chip->setup_read_retry = macronix_nand_setup_read_retry; + chip->ops.setup_read_retry = macronix_nand_setup_read_retry; if (p->supports_set_get_features) { bitmap_set(p->set_feature_list, @@ -242,8 +242,8 @@ static void macronix_nand_block_protection_support(struct nand_chip *chip) bitmap_set(chip->parameters.set_feature_list, ONFI_FEATURE_ADDR_MXIC_PROTECTION, 1); - chip->lock_area = mxic_nand_lock; - chip->unlock_area = mxic_nand_unlock; + chip->ops.lock_area = mxic_nand_lock; + chip->ops.unlock_area = mxic_nand_unlock; } static int nand_power_down_op(struct nand_chip *chip) @@ -312,8 +312,8 @@ static void macronix_nand_deep_power_down_support(struct nand_chip *chip) if (i < 0) return; - chip->suspend = mxic_nand_suspend; - chip->resume = mxic_nand_resume; + chip->ops.suspend = mxic_nand_suspend; + chip->ops.resume = mxic_nand_resume; } static int macronix_nand_init(struct nand_chip *chip) diff --git a/drivers/mtd/nand/raw/nand_micron.c b/drivers/mtd/nand/raw/nand_micron.c index 3589b4fce0d4..4385092a9325 100644 --- a/drivers/mtd/nand/raw/nand_micron.c +++ b/drivers/mtd/nand/raw/nand_micron.c @@ -84,7 +84,7 @@ static int micron_nand_onfi_init(struct nand_chip *chip) struct nand_onfi_vendor_micron *micron = (void *)p->onfi->vendor; chip->read_retries = micron->read_retry_options; - chip->setup_read_retry = micron_nand_setup_read_retry; + chip->ops.setup_read_retry = micron_nand_setup_read_retry; } if (p->supports_set_get_features) { diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h index cea137778224..7f9be95ca8dc 100644 --- a/include/linux/mtd/rawnand.h +++ b/include/linux/mtd/rawnand.h @@ -1027,16 +1027,31 @@ struct nand_legacy { struct nand_controller dummy_controller; }; +/** + * struct nand_chip_ops - NAND chip operations + * @suspend: Suspend operation + * @resume: Resume operation + * @lock_area: Lock operation + * @unlock_area: Unlock operation + * @setup_read_retry: Set the read-retry mode (mostly needed for MLC NANDs) + */ +struct nand_chip_ops { + int (*suspend)(struct nand_chip *chip); + void (*resume)(struct nand_chip *chip); + int (*lock_area)(struct nand_chip *chip, loff_t ofs, uint64_t len); + int (*unlock_area)(struct nand_chip *chip, loff_t ofs, uint64_t len); + int (*setup_read_retry)(struct nand_chip *chip, int retry_mode); +}; + /** * struct nand_chip - NAND Private Flash Chip Data * @base: Inherit from the generic NAND device + * @ops: NAND chip operations * @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 * fields/hooks, you should consider reworking the driver * avoid using them. - * @setup_read_retry: [FLASHSPECIFIC] flash (vendor) specific function for - * setting the read-retry mode. Mostly needed for MLC NAND. * @ecc: [BOARDSPECIFIC] ECC control structure * @buf_align: minimum buffer alignment required by a platform * @oob_poi: "poison value buffer," used for laying out OOB data @@ -1081,8 +1096,6 @@ struct nand_legacy { * @lock: lock protecting the suspended field. Also used to * serialize accesses to the NAND device. * @suspended: set to 1 when the device is suspended, 0 when it's not. - * @suspend: [REPLACEABLE] specific NAND device suspend operation - * @resume: [REPLACEABLE] specific NAND device resume operation * @bbt: [INTERN] bad block table pointer * @bbt_td: [REPLACEABLE] bad block table descriptor for flash * lookup. @@ -1096,17 +1109,13 @@ struct nand_legacy { * @manufacturer: [INTERN] Contains manufacturer information * @manufacturer.desc: [INTERN] Contains manufacturer's description * @manufacturer.priv: [INTERN] Contains manufacturer private information - * @lock_area: [REPLACEABLE] specific NAND chip lock operation - * @unlock_area: [REPLACEABLE] specific NAND chip unlock operation */ struct nand_chip { struct nand_device base; - + struct nand_chip_ops ops; struct nand_legacy legacy; - int (*setup_read_retry)(struct nand_chip *chip, int retry_mode); - unsigned int options; unsigned int bbt_options; @@ -1138,8 +1147,6 @@ struct nand_chip { struct mutex lock; unsigned int suspended : 1; - int (*suspend)(struct nand_chip *chip); - void (*resume)(struct nand_chip *chip); u8 *oob_poi; struct nand_controller *controller; @@ -1159,9 +1166,6 @@ struct nand_chip { const struct nand_manufacturer *desc; void *priv; } manufacturer; - - int (*lock_area)(struct nand_chip *chip, loff_t ofs, uint64_t len); - int (*unlock_area)(struct nand_chip *chip, loff_t ofs, uint64_t len); }; extern const struct mtd_ooblayout_ops nand_ooblayout_sp_ops; -- cgit v1.2.3 From 271de009b7c0c1c15f63491a352ab08835462977 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Fri, 29 May 2020 13:12:58 +0200 Subject: mtd: rawnand: Rename the manufacturer structure It is currently called nand_manufacturer but could actually be called nand_manufacturer_desc, like its instances, so that the former name is left unused for now. Signed-off-by: Miquel Raynal Reviewed-by: Boris Brezillon Link: https://lore.kernel.org/linux-mtd/20200529111322.7184-5-miquel.raynal@bootlin.com --- drivers/mtd/nand/raw/internals.h | 6 +++--- drivers/mtd/nand/raw/nand_base.c | 14 +++++++------- drivers/mtd/nand/raw/nand_ids.c | 16 ++++++++-------- include/linux/mtd/rawnand.h | 2 +- 4 files changed, 19 insertions(+), 19 deletions(-) diff --git a/drivers/mtd/nand/raw/internals.h b/drivers/mtd/nand/raw/internals.h index 03866b0aadea..a518acfd9b3f 100644 --- a/drivers/mtd/nand/raw/internals.h +++ b/drivers/mtd/nand/raw/internals.h @@ -53,12 +53,12 @@ struct nand_manufacturer_ops { }; /** - * struct nand_manufacturer - NAND Flash Manufacturer structure + * struct nand_manufacturer_desc - NAND Flash Manufacturer descriptor * @name: Manufacturer name * @id: manufacturer ID code of device. * @ops: manufacturer operations */ -struct nand_manufacturer { +struct nand_manufacturer_desc { int id; char *name; const struct nand_manufacturer_ops *ops; @@ -79,7 +79,7 @@ extern const struct nand_manufacturer_ops toshiba_nand_manuf_ops; extern const struct mtd_pairing_scheme dist3_pairing_scheme; /* Core functions */ -const struct nand_manufacturer *nand_get_manufacturer(u8 id); +const struct nand_manufacturer_desc *nand_get_manufacturer_desc(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, diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c index d9cb71e7c0ed..534ee75d0f2b 100644 --- a/drivers/mtd/nand/raw/nand_base.c +++ b/drivers/mtd/nand/raw/nand_base.c @@ -4810,9 +4810,9 @@ static void nand_manufacturer_cleanup(struct nand_chip *chip) } static const char * -nand_manufacturer_name(const struct nand_manufacturer *manufacturer) +nand_manufacturer_name(const struct nand_manufacturer_desc *manufacturer_desc) { - return manufacturer ? manufacturer->name : "Unknown"; + return manufacturer_desc ? manufacturer_desc->name : "Unknown"; } /* @@ -4820,7 +4820,7 @@ nand_manufacturer_name(const struct nand_manufacturer *manufacturer) */ static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type) { - const struct nand_manufacturer *manufacturer; + const struct nand_manufacturer_desc *manufacturer_desc; struct mtd_info *mtd = nand_to_mtd(chip); struct nand_memory_organization *memorg; int busw, ret; @@ -4877,8 +4877,8 @@ static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type) chip->id.len = nand_id_len(id_data, ARRAY_SIZE(chip->id.data)); /* Try to identify manufacturer */ - manufacturer = nand_get_manufacturer(maf_id); - chip->manufacturer.desc = manufacturer; + manufacturer_desc = nand_get_manufacturer_desc(maf_id); + chip->manufacturer.desc = manufacturer_desc; if (!type) type = nand_flash_ids; @@ -4957,7 +4957,7 @@ ident_done: */ pr_info("device found, Manufacturer ID: 0x%02x, Chip ID: 0x%02x\n", maf_id, dev_id); - pr_info("%s %s\n", nand_manufacturer_name(manufacturer), + pr_info("%s %s\n", nand_manufacturer_name(manufacturer_desc), mtd->name); pr_warn("bus width %d instead of %d bits\n", busw ? 16 : 8, (chip->options & NAND_BUSWIDTH_16) ? 16 : 8); @@ -4992,7 +4992,7 @@ ident_done: pr_info("device found, Manufacturer ID: 0x%02x, Chip ID: 0x%02x\n", maf_id, dev_id); - pr_info("%s %s\n", nand_manufacturer_name(manufacturer), + pr_info("%s %s\n", nand_manufacturer_name(manufacturer_desc), chip->parameters.model); pr_info("%d MiB, %s, erase size: %d KiB, page size: %d, OOB size: %d\n", (int)(targetsize >> 20), nand_is_slc(chip) ? "SLC" : "MLC", diff --git a/drivers/mtd/nand/raw/nand_ids.c b/drivers/mtd/nand/raw/nand_ids.c index ba27902fc54b..e0dbc2e316c7 100644 --- a/drivers/mtd/nand/raw/nand_ids.c +++ b/drivers/mtd/nand/raw/nand_ids.c @@ -166,7 +166,7 @@ struct nand_flash_dev nand_flash_ids[] = { }; /* Manufacturer IDs */ -static const struct nand_manufacturer nand_manufacturers[] = { +static const struct nand_manufacturer_desc nand_manufacturer_descs[] = { {NAND_MFR_AMD, "AMD/Spansion", &amd_nand_manuf_ops}, {NAND_MFR_ATO, "ATO"}, {NAND_MFR_EON, "Eon"}, @@ -186,20 +186,20 @@ static const struct nand_manufacturer nand_manufacturers[] = { }; /** - * nand_get_manufacturer - Get manufacturer information from the manufacturer - * ID + * nand_get_manufacturer_desc - Get manufacturer information from the + * manufacturer ID * @id: manufacturer ID * - * Returns a pointer a nand_manufacturer object if the manufacturer is defined + * Returns a nand_manufacturer_desc object if the manufacturer is defined * in the NAND manufacturers database, NULL otherwise. */ -const struct nand_manufacturer *nand_get_manufacturer(u8 id) +const struct nand_manufacturer_desc *nand_get_manufacturer_desc(u8 id) { int i; - for (i = 0; i < ARRAY_SIZE(nand_manufacturers); i++) - if (nand_manufacturers[i].id == id) - return &nand_manufacturers[i]; + for (i = 0; i < ARRAY_SIZE(nand_manufacturer_descs); i++) + if (nand_manufacturer_descs[i].id == id) + return &nand_manufacturer_descs[i]; return NULL; } diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h index 7f9be95ca8dc..860d3c1020ef 100644 --- a/include/linux/mtd/rawnand.h +++ b/include/linux/mtd/rawnand.h @@ -1163,7 +1163,7 @@ struct nand_chip { void *priv; struct { - const struct nand_manufacturer *desc; + const struct nand_manufacturer_desc *desc; void *priv; } manufacturer; }; -- cgit v1.2.3 From 36017af430e6b2fad0b2ee5476103706160f1379 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Fri, 29 May 2020 13:12:59 +0200 Subject: mtd: rawnand: Declare the nand_manufacturer structure out of nand_chip Now that struct nand_manufacturer type is free, use it to store the nand_manufacturer_desc and the manufacturer's private data. Signed-off-by: Miquel Raynal Reviewed-by: Boris Brezillon Link: https://lore.kernel.org/linux-mtd/20200529111322.7184-6-miquel.raynal@bootlin.com --- include/linux/mtd/rawnand.h | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h index 860d3c1020ef..a3dfa36a9fd5 100644 --- a/include/linux/mtd/rawnand.h +++ b/include/linux/mtd/rawnand.h @@ -1043,10 +1043,21 @@ struct nand_chip_ops { int (*setup_read_retry)(struct nand_chip *chip, int retry_mode); }; +/** + * struct nand_manufacturer - NAND manufacturer structure + * @desc: The manufacturer description + * @priv: Private information for the manufacturer driver + */ +struct nand_manufacturer { + const struct nand_manufacturer_desc *desc; + void *priv; +}; + /** * struct nand_chip - NAND Private Flash Chip Data * @base: Inherit from the generic NAND device * @ops: NAND chip operations + * @manufacturer: Manufacturer information * @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 @@ -1106,13 +1117,11 @@ struct nand_chip_ops { * structure which is shared among multiple independent * devices. * @priv: [OPTIONAL] pointer to private chip data - * @manufacturer: [INTERN] Contains manufacturer information - * @manufacturer.desc: [INTERN] Contains manufacturer's description - * @manufacturer.priv: [INTERN] Contains manufacturer private information */ struct nand_chip { struct nand_device base; + struct nand_manufacturer manufacturer; struct nand_chip_ops ops; struct nand_legacy legacy; @@ -1161,11 +1170,6 @@ struct nand_chip { struct nand_bbt_descr *badblock_pattern; void *priv; - - struct { - const struct nand_manufacturer_desc *desc; - void *priv; - } manufacturer; }; extern const struct mtd_ooblayout_ops nand_ooblayout_sp_ops; -- cgit v1.2.3 From a63674c7cfe62221e05ba73107d9e15d73ff8bbd Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Fri, 29 May 2020 13:13:00 +0200 Subject: mtd: rawnand: Reorganize the nand_chip structure Reorder fields in this structure and pack entries by theme: * The main descriptive structures * The data interface details * Bad block information * The device layout * Extra buffers matching the device layout * Internal values * External objects like the ECC controller, the ECC engine and a private data pointer. While at it, adapt the documentation style. I changed on purpose the description of @oob_poi which was weird. Signed-off-by: Miquel Raynal Reviewed-by: Boris Brezillon Link: https://lore.kernel.org/linux-mtd/20200529111322.7184-7-miquel.raynal@bootlin.com --- include/linux/mtd/rawnand.h | 166 ++++++++++++++++++++------------------------ 1 file changed, 76 insertions(+), 90 deletions(-) diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h index a3dfa36a9fd5..544ec8736793 100644 --- a/include/linux/mtd/rawnand.h +++ b/include/linux/mtd/rawnand.h @@ -1055,120 +1055,106 @@ struct nand_manufacturer { /** * struct nand_chip - NAND Private Flash Chip Data - * @base: Inherit from the generic NAND device - * @ops: NAND chip operations - * @manufacturer: Manufacturer information - * @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 - * fields/hooks, you should consider reworking the driver - * avoid using them. - * @ecc: [BOARDSPECIFIC] ECC control structure - * @buf_align: minimum buffer alignment required by a platform - * @oob_poi: "poison value buffer," used for laying out OOB data - * before writing - * @page_shift: [INTERN] number of address bits in a page (column - * address bits). - * @phys_erase_shift: [INTERN] number of address bits in a physical eraseblock - * @bbt_erase_shift: [INTERN] number of address bits in a bbt entry - * @chip_shift: [INTERN] number of address bits in one chip - * @options: [BOARDSPECIFIC] various chip options. They can partly - * be set to inform nand_scan about special functionality. - * See the defines for further explanation. - * @bbt_options: [INTERN] bad block specific options. All options used - * here must come from bbm.h. By default, these options - * will be copied to the appropriate nand_bbt_descr's. - * @badblockpos: [INTERN] position of the bad block marker in the oob - * area. - * @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 - * @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 - * the NAND chip is not ONFI compliant. - * @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 - * @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 - * readable form. - * @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 < 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. - * @suspended: set to 1 when the device is suspended, 0 when it's not. - * @bbt: [INTERN] bad block table pointer - * @bbt_td: [REPLACEABLE] bad block table descriptor for flash - * lookup. - * @bbt_md: [REPLACEABLE] bad block table mirror descriptor - * @badblock_pattern: [REPLACEABLE] bad block scan pattern used for initial - * bad block scan. - * @controller: [REPLACEABLE] a pointer to a hardware controller - * structure which is shared among multiple independent - * devices. - * @priv: [OPTIONAL] pointer to private chip data + * @base: Inherit from the generic NAND device + * @id: Holds NAND ID + * @parameters: Holds generic parameters under an easily readable form + * @manufacturer: Manufacturer information + * @ops: NAND chip operations + * @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 fields/hooks, you should + * consider reworking the driver and avoid using them. + * @options: Various chip options. They can partly be set to inform nand_scan + * about special functionality. See the defines for further + * explanation. + * @onfi_timing_mode_default: 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 otherwise + * @data_interface: NAND interface timing information + * @bbt_erase_shift: Number of address bits in a bbt entry + * @bbt_options: Bad block table specific options. All options used here must + * come from bbm.h. By default, these options will be copied to + * the appropriate nand_bbt_descr's. + * @badblockpos: Bad block marker position in the oob area + * @badblockbits: Minimum number of set bits in a good block's bad block marker + * position; i.e., BBM = 11110111b is good when badblockbits = 7 + * @bbt_td: Bad block table descriptor for flash lookup + * @bbt_md: Bad block table mirror descriptor + * @badblock_pattern: Bad block scan pattern used for initial bad block scan + * @bbt: Bad block table pointer + * @page_shift: Number of address bits in a page (column address bits) + * @phys_erase_shift: Number of address bits in a physical eraseblock + * @chip_shift: Number of address bits in one chip + * @pagemask: Page number mask = number of (pages / chip) - 1 + * @subpagesize: Holds the subpagesize + * @data_buf: Buffer for data, size is (page size + oobsize) + * @oob_poi: pointer on the OOB area covered by 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 + * @buf_align: Minimum buffer alignment required by a platform + * @lock: Lock protecting the suspended field. Also used to serialize accesses + * to the NAND device + * @suspended: Set to 1 when the device is suspended, 0 when it's not + * @cur_cs: Currently selected target. -1 means no target selected, otherwise we + * should always have cur_cs >= 0 && cur_cs < nanddev_ntargets(). + * NAND Controller drivers should not modify this value, but they're + * allowed to read it. + * @read_retries: The number of read retry modes supported + * @controller: The hardware controller structure which is shared among multiple + * independent devices + * @ecc: The ECC controller structure + * @priv: Chip private data */ - struct nand_chip { struct nand_device base; + struct nand_id id; + struct nand_parameters parameters; struct nand_manufacturer manufacturer; struct nand_chip_ops ops; struct nand_legacy legacy; - unsigned int options; + + /* Data interface */ + int onfi_timing_mode_default; + struct nand_data_interface data_interface; + + /* Bad block information */ + unsigned int bbt_erase_shift; unsigned int bbt_options; + unsigned int badblockpos; + unsigned int badblockbits; + struct nand_bbt_descr *bbt_td; + struct nand_bbt_descr *bbt_md; + struct nand_bbt_descr *badblock_pattern; + u8 *bbt; + /* Device internal layout */ unsigned int page_shift; unsigned int phys_erase_shift; - unsigned int bbt_erase_shift; unsigned int chip_shift; unsigned int pagemask; - u8 *data_buf; + unsigned int subpagesize; + /* Buffers */ + u8 *data_buf; + u8 *oob_poi; struct { unsigned int bitflips; int page; } pagecache; + unsigned long buf_align; - unsigned int subpagesize; - int onfi_timing_mode_default; - unsigned int badblockpos; - unsigned int badblockbits; - - struct nand_id id; - struct nand_parameters parameters; - - struct nand_data_interface data_interface; - - int cur_cs; - - int read_retries; - + /* Internals */ struct mutex lock; unsigned int suspended : 1; + int cur_cs; + int read_retries; - u8 *oob_poi; + /* Externals */ struct nand_controller *controller; - struct nand_ecc_ctrl ecc; - unsigned long buf_align; - - u8 *bbt; - struct nand_bbt_descr *bbt_td; - struct nand_bbt_descr *bbt_md; - - struct nand_bbt_descr *badblock_pattern; - void *priv; }; -- cgit v1.2.3 From 6ef10df37e7dd99a5a16228fabcc3a5141585b66 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Fri, 29 May 2020 13:13:01 +0200 Subject: mtd: rawnand: Compare the actual timing values Avoid relying just on the default timing mode to discriminate if the data interface must be restored. This field should only be used at initialization time by legacy chips statically defined. Do a memcmp() instead. Signed-off-by: Miquel Raynal Reviewed-by: Boris Brezillon Link: https://lore.kernel.org/linux-mtd/20200529111322.7184-8-miquel.raynal@bootlin.com --- drivers/mtd/nand/raw/nand_base.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c index 534ee75d0f2b..3526c2a50bbe 100644 --- a/drivers/mtd/nand/raw/nand_base.c +++ b/drivers/mtd/nand/raw/nand_base.c @@ -2512,7 +2512,8 @@ int nand_reset(struct nand_chip *chip, int chipnr) * nand_setup_data_interface() uses ->set/get_features() which would * fail anyway as the parameter page is not available yet. */ - if (!chip->onfi_timing_mode_default) + if (!memcmp(&chip->data_interface, &saved_data_intf, + sizeof(saved_data_intf))) return 0; chip->data_interface = saved_data_intf; -- cgit v1.2.3 From fe7f7b0846bdcc53a3d3e83fea67f988ab5145d8 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Fri, 29 May 2020 13:13:02 +0200 Subject: mtd: rawnand: Use the data interface mode entry when relevant The data interface setup does not care about the default timing mode but cares about the actual timing mode at the time of the call of this helper. Use this entry instead and let chip->default_timing_mode only be used at initialization time. Signed-off-by: Miquel Raynal Reviewed-by: Boris Brezillon Link: https://lore.kernel.org/linux-mtd/20200529111322.7184-9-miquel.raynal@bootlin.com --- drivers/mtd/nand/raw/nand_base.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c index 3526c2a50bbe..6e06ccf61aeb 100644 --- a/drivers/mtd/nand/raw/nand_base.c +++ b/drivers/mtd/nand/raw/nand_base.c @@ -951,9 +951,8 @@ static int nand_reset_data_interface(struct nand_chip *chip, int chipnr) */ static int nand_setup_data_interface(struct nand_chip *chip, int chipnr) { - u8 tmode_param[ONFI_SUBFEATURE_PARAM_LEN] = { - chip->onfi_timing_mode_default, - }; + u8 mode = chip->data_interface.timings.mode; + u8 tmode_param[ONFI_SUBFEATURE_PARAM_LEN] = { mode, }; int ret; if (!nand_has_setup_data_iface(chip)) @@ -987,9 +986,9 @@ static int nand_setup_data_interface(struct nand_chip *chip, int chipnr) if (ret) goto err_reset_chip; - if (tmode_param[0] != chip->onfi_timing_mode_default) { + if (tmode_param[0] != mode) { pr_warn("timing mode %d not acknowledged by the NAND chip\n", - chip->onfi_timing_mode_default); + mode); goto err_reset_chip; } -- cgit v1.2.3 From adcf98b2d87429dfbc114666a8be6f2b36f5d898 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Fri, 29 May 2020 13:13:03 +0200 Subject: mtd: rawnand: Rename nand_has_setup_data_iface() This is really a NAND controller hook so call it nand_controller_can_setup_data_iface(), which makes much more sense. Signed-off-by: Miquel Raynal Reviewed-by: Boris Brezillon Link: https://lore.kernel.org/linux-mtd/20200529111322.7184-10-miquel.raynal@bootlin.com --- drivers/mtd/nand/raw/internals.h | 2 +- drivers/mtd/nand/raw/nand_base.c | 6 +++--- drivers/mtd/nand/raw/nand_legacy.c | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/mtd/nand/raw/internals.h b/drivers/mtd/nand/raw/internals.h index a518acfd9b3f..a5e2cec7e301 100644 --- a/drivers/mtd/nand/raw/internals.h +++ b/drivers/mtd/nand/raw/internals.h @@ -130,7 +130,7 @@ static inline int nand_exec_op(struct nand_chip *chip, return chip->controller->ops->exec_op(chip, op, false); } -static inline bool nand_has_setup_data_iface(struct nand_chip *chip) +static inline bool nand_controller_can_setup_data_iface(struct nand_chip *chip) { if (!chip->controller || !chip->controller->ops || !chip->controller->ops->setup_data_interface) diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c index 6e06ccf61aeb..2a477ce81165 100644 --- a/drivers/mtd/nand/raw/nand_base.c +++ b/drivers/mtd/nand/raw/nand_base.c @@ -910,7 +910,7 @@ static int nand_reset_data_interface(struct nand_chip *chip, int chipnr) { int ret; - if (!nand_has_setup_data_iface(chip)) + if (!nand_controller_can_setup_data_iface(chip)) return 0; /* @@ -955,7 +955,7 @@ static int nand_setup_data_interface(struct nand_chip *chip, int chipnr) u8 tmode_param[ONFI_SUBFEATURE_PARAM_LEN] = { mode, }; int ret; - if (!nand_has_setup_data_iface(chip)) + if (!nand_controller_can_setup_data_iface(chip)) return 0; /* Change the mode on the chip side (if supported by the NAND chip) */ @@ -1025,7 +1025,7 @@ static int nand_init_data_interface(struct nand_chip *chip) { int modes, mode, ret; - if (!nand_has_setup_data_iface(chip)) + if (!nand_controller_can_setup_data_iface(chip)) return 0; /* diff --git a/drivers/mtd/nand/raw/nand_legacy.c b/drivers/mtd/nand/raw/nand_legacy.c index d64791c06a97..848403dcae03 100644 --- a/drivers/mtd/nand/raw/nand_legacy.c +++ b/drivers/mtd/nand/raw/nand_legacy.c @@ -365,7 +365,7 @@ static void nand_ccs_delay(struct nand_chip *chip) * Wait tCCS_min if it is correctly defined, otherwise wait 500ns * (which should be safe for all NANDs). */ - if (nand_has_setup_data_iface(chip)) + if (nand_controller_can_setup_data_iface(chip)) ndelay(chip->data_interface.timings.sdr.tCCS_min / 1000); else ndelay(500); -- cgit v1.2.3 From 8d69a80f541db0f58ebe92801bedbf17199738bd Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Fri, 29 May 2020 13:13:04 +0200 Subject: mtd: rawnand: Fix nand_setup_data_interface() description This is a copy/paste error and belongs to nand_init_data_interface() description. Signed-off-by: Miquel Raynal Reviewed-by: Boris Brezillon Link: https://lore.kernel.org/linux-mtd/20200529111322.7184-11-miquel.raynal@bootlin.com --- drivers/mtd/nand/raw/nand_base.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c index 2a477ce81165..01e788e0d010 100644 --- a/drivers/mtd/nand/raw/nand_base.c +++ b/drivers/mtd/nand/raw/nand_base.c @@ -941,11 +941,8 @@ static int nand_reset_data_interface(struct nand_chip *chip, int chipnr) * @chip: The NAND chip * @chipnr: Internal die id * - * Find and configure the best data interface and NAND timings supported by - * the chip and the driver. - * First tries to retrieve supported timing modes from ONFI information, - * and if the NAND chip does not support ONFI, relies on the - * ->onfi_timing_mode_default specified in the nand_ids table. + * Configure what has been reported to be the best data interface and NAND + * timings supported by the chip and the driver. * * Returns 0 for success or negative error code otherwise. */ -- cgit v1.2.3 From 5e179a532a9954883685748b60081e75b33f0d32 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Fri, 29 May 2020 13:13:05 +0200 Subject: mtd: rawnand: Rename nand_init_data_interface() This name is a bit misleading, what we do in this helper is trying to find the best SDR timings supported by the controller and the chip. Signed-off-by: Miquel Raynal Reviewed-by: Boris Brezillon Link: https://lore.kernel.org/linux-mtd/20200529111322.7184-12-miquel.raynal@bootlin.com --- drivers/mtd/nand/raw/nand_base.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c index 01e788e0d010..1d9cf02d164b 100644 --- a/drivers/mtd/nand/raw/nand_base.c +++ b/drivers/mtd/nand/raw/nand_base.c @@ -1005,7 +1005,7 @@ err_reset_chip: } /** - * nand_init_data_interface - find the best data interface and timings + * nand_choose_data_interface - find the best data interface and timings * @chip: The NAND chip * * Find the best data interface and NAND timings supported by the chip @@ -1018,7 +1018,7 @@ err_reset_chip: * * Returns 0 for success or negative error code otherwise. */ -static int nand_init_data_interface(struct nand_chip *chip) +static int nand_choose_data_interface(struct nand_chip *chip) { int modes, mode, ret; @@ -5969,8 +5969,8 @@ static int nand_scan_tail(struct nand_chip *chip) if (!mtd->bitflip_threshold) mtd->bitflip_threshold = DIV_ROUND_UP(mtd->ecc_strength * 3, 4); - /* Initialize the ->data_interface field. */ - ret = nand_init_data_interface(chip); + /* Find the fastest data interface for this chip */ + ret = nand_choose_data_interface(chip); if (ret) goto err_nanddev_cleanup; -- cgit v1.2.3 From 844cc46460095023365345bfe61a0f195f9cb66e Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Fri, 29 May 2020 13:13:06 +0200 Subject: mtd: rawnand: timings: Update onfi_fill_data_interface() kernel doc Describe all parameters and drop the legacy [NAND Interface] prefix. Signed-off-by: Miquel Raynal Reviewed-by: Boris Brezillon Link: https://lore.kernel.org/linux-mtd/20200529111322.7184-13-miquel.raynal@bootlin.com --- drivers/mtd/nand/raw/nand_timings.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/mtd/nand/raw/nand_timings.c b/drivers/mtd/nand/raw/nand_timings.c index 36d21be3dfe5..a73d934e86f9 100644 --- a/drivers/mtd/nand/raw/nand_timings.c +++ b/drivers/mtd/nand/raw/nand_timings.c @@ -274,9 +274,10 @@ static const struct nand_data_interface onfi_sdr_timings[] = { }; /** - * onfi_fill_data_interface - [NAND Interface] Initialize a data interface from - * given ONFI mode - * @mode: The ONFI timing mode + * onfi_fill_data_interface - Initialize a data interface from a given ONFI mode + * @chip: The NAND chip + * @type: The data interface type + * @timing_mode: The ONFI timing mode */ int onfi_fill_data_interface(struct nand_chip *chip, enum nand_data_interface_type type, -- cgit v1.2.3 From 623c0141f560800c4fc7a7502654994633791d36 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Fri, 29 May 2020 13:13:07 +0200 Subject: mtd: rawnand: timings: Provide onfi_fill_data_interface() with a data interface Right now the core uses onfi_fill_data_interface() to initialize the nand_data_interface object embedded in nand_chip, but we are about to allocate this object dynamically and let manufacturer drivers provide their own interface config. Let's patch the onfi_fill_data_interface() so it can initialize an interface config that's not the one currently attached to the nand_chip. Signed-off-by: Miquel Raynal Reviewed-by: Boris Brezillon Link: https://lore.kernel.org/linux-mtd/20200529111322.7184-14-miquel.raynal@bootlin.com --- drivers/mtd/nand/raw/internals.h | 1 + drivers/mtd/nand/raw/nand_base.c | 7 ++++--- drivers/mtd/nand/raw/nand_timings.c | 3 ++- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/mtd/nand/raw/internals.h b/drivers/mtd/nand/raw/internals.h index a5e2cec7e301..0f74509abc4c 100644 --- a/drivers/mtd/nand/raw/internals.h +++ b/drivers/mtd/nand/raw/internals.h @@ -85,6 +85,7 @@ 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); int onfi_fill_data_interface(struct nand_chip *chip, + struct nand_data_interface *iface, enum nand_data_interface_type type, int timing_mode); int nand_get_features(struct nand_chip *chip, int addr, u8 *subfeature_param); diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c index 1d9cf02d164b..b4de85794e07 100644 --- a/drivers/mtd/nand/raw/nand_base.c +++ b/drivers/mtd/nand/raw/nand_base.c @@ -927,7 +927,7 @@ static int nand_reset_data_interface(struct nand_chip *chip, int chipnr) * timings to timing mode 0. */ - onfi_fill_data_interface(chip, NAND_SDR_IFACE, 0); + onfi_fill_data_interface(chip, &chip->data_interface, NAND_SDR_IFACE, 0); ret = chip->controller->ops->setup_data_interface(chip, chipnr, &chip->data_interface); if (ret) @@ -1040,7 +1040,8 @@ static int nand_choose_data_interface(struct nand_chip *chip) } for (mode = fls(modes) - 1; mode >= 0; mode--) { - ret = onfi_fill_data_interface(chip, NAND_SDR_IFACE, mode); + ret = onfi_fill_data_interface(chip, &chip->data_interface, + NAND_SDR_IFACE, mode); if (ret) continue; @@ -5182,7 +5183,7 @@ static int nand_scan_ident(struct nand_chip *chip, unsigned int maxchips, mutex_init(&chip->lock); /* Enforce the right timings for reset/detection */ - onfi_fill_data_interface(chip, NAND_SDR_IFACE, 0); + onfi_fill_data_interface(chip, &chip->data_interface, NAND_SDR_IFACE, 0); ret = nand_dt_init(chip); if (ret) diff --git a/drivers/mtd/nand/raw/nand_timings.c b/drivers/mtd/nand/raw/nand_timings.c index a73d934e86f9..ce6bb87db2e8 100644 --- a/drivers/mtd/nand/raw/nand_timings.c +++ b/drivers/mtd/nand/raw/nand_timings.c @@ -276,14 +276,15 @@ static const struct nand_data_interface onfi_sdr_timings[] = { /** * onfi_fill_data_interface - Initialize a data interface from a given ONFI mode * @chip: The NAND chip + * @iface: The data interface to fill * @type: The data interface type * @timing_mode: The ONFI timing mode */ int onfi_fill_data_interface(struct nand_chip *chip, + struct nand_data_interface *iface, enum nand_data_interface_type type, int timing_mode) { - struct nand_data_interface *iface = &chip->data_interface; struct onfi_params *onfi = chip->parameters.onfi; if (type != NAND_SDR_IFACE) -- cgit v1.2.3 From fcaab3b26d2534ec9f227810975ad220823ac578 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Fri, 29 May 2020 13:13:08 +0200 Subject: mtd: rawnand: timings: onfi_fill_data_interface timing mode is unsigned Turn this argument into an unsigned int, as it cannot be signed. This also spares a check. Signed-off-by: Miquel Raynal Reviewed-by: Boris Brezillon Link: https://lore.kernel.org/linux-mtd/20200529111322.7184-15-miquel.raynal@bootlin.com --- drivers/mtd/nand/raw/internals.h | 2 +- drivers/mtd/nand/raw/nand_timings.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/mtd/nand/raw/internals.h b/drivers/mtd/nand/raw/internals.h index 0f74509abc4c..bd10ec92f04a 100644 --- a/drivers/mtd/nand/raw/internals.h +++ b/drivers/mtd/nand/raw/internals.h @@ -87,7 +87,7 @@ int nand_erase_nand(struct nand_chip *chip, struct erase_info *instr, int onfi_fill_data_interface(struct nand_chip *chip, struct nand_data_interface *iface, enum nand_data_interface_type type, - int timing_mode); + unsigned int timing_mode); int nand_get_features(struct nand_chip *chip, int addr, u8 *subfeature_param); int nand_set_features(struct nand_chip *chip, int addr, u8 *subfeature_param); int nand_read_page_raw_notsupp(struct nand_chip *chip, u8 *buf, diff --git a/drivers/mtd/nand/raw/nand_timings.c b/drivers/mtd/nand/raw/nand_timings.c index ce6bb87db2e8..08dc381349fa 100644 --- a/drivers/mtd/nand/raw/nand_timings.c +++ b/drivers/mtd/nand/raw/nand_timings.c @@ -283,14 +283,14 @@ static const struct nand_data_interface onfi_sdr_timings[] = { int onfi_fill_data_interface(struct nand_chip *chip, struct nand_data_interface *iface, enum nand_data_interface_type type, - int timing_mode) + unsigned int timing_mode) { struct onfi_params *onfi = chip->parameters.onfi; if (type != NAND_SDR_IFACE) return -EINVAL; - if (timing_mode < 0 || timing_mode >= ARRAY_SIZE(onfi_sdr_timings)) + if (timing_mode >= ARRAY_SIZE(onfi_sdr_timings)) return -EINVAL; *iface = onfi_sdr_timings[timing_mode]; -- cgit v1.2.3 From 98d6979aa898239ec2faa10467c338a808e1287e Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Fri, 29 May 2020 13:13:09 +0200 Subject: mtd: rawnand: timings: Add a helper to find the closest ONFI mode Vendors are allowed to provide their own set of timings. In this case, we provide a way to derive the "closest" timing mode so that, if the NAND controller does not support tweaking these parameters, it will be able to configure itself anyway. Signed-off-by: Miquel Raynal Reviewed-by: Boris Brezillon Link: https://lore.kernel.org/linux-mtd/20200529111322.7184-16-miquel.raynal@bootlin.com --- drivers/mtd/nand/raw/internals.h | 2 ++ drivers/mtd/nand/raw/nand_timings.c | 47 +++++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/drivers/mtd/nand/raw/internals.h b/drivers/mtd/nand/raw/internals.h index bd10ec92f04a..f851ed210d70 100644 --- a/drivers/mtd/nand/raw/internals.h +++ b/drivers/mtd/nand/raw/internals.h @@ -88,6 +88,8 @@ int onfi_fill_data_interface(struct nand_chip *chip, struct nand_data_interface *iface, enum nand_data_interface_type type, unsigned int timing_mode); +unsigned int +onfi_find_closest_sdr_mode(const struct nand_sdr_timings *spec_timings); int nand_get_features(struct nand_chip *chip, int addr, u8 *subfeature_param); int nand_set_features(struct nand_chip *chip, int addr, u8 *subfeature_param); int nand_read_page_raw_notsupp(struct nand_chip *chip, u8 *buf, diff --git a/drivers/mtd/nand/raw/nand_timings.c b/drivers/mtd/nand/raw/nand_timings.c index 08dc381349fa..b089f2dc5f23 100644 --- a/drivers/mtd/nand/raw/nand_timings.c +++ b/drivers/mtd/nand/raw/nand_timings.c @@ -273,6 +273,53 @@ static const struct nand_data_interface onfi_sdr_timings[] = { }, }; +/** + * onfi_find_closest_sdr_mode - Derive the closest ONFI SDR timing mode given a + * set of timings + * @spec_timings: the timings to challenge + */ +unsigned int +onfi_find_closest_sdr_mode(const struct nand_sdr_timings *spec_timings) +{ + const struct nand_sdr_timings *onfi_timings; + int mode; + + for (mode = ARRAY_SIZE(onfi_sdr_timings) - 1; mode > 0; mode--) { + onfi_timings = &onfi_sdr_timings[mode].timings.sdr; + + if (spec_timings->tCCS_min <= onfi_timings->tCCS_min && + spec_timings->tADL_min <= onfi_timings->tADL_min && + spec_timings->tALH_min <= onfi_timings->tALH_min && + spec_timings->tALS_min <= onfi_timings->tALS_min && + spec_timings->tAR_min <= onfi_timings->tAR_min && + spec_timings->tCEH_min <= onfi_timings->tCEH_min && + spec_timings->tCH_min <= onfi_timings->tCH_min && + spec_timings->tCLH_min <= onfi_timings->tCLH_min && + spec_timings->tCLR_min <= onfi_timings->tCLR_min && + spec_timings->tCLS_min <= onfi_timings->tCLS_min && + spec_timings->tCOH_min <= onfi_timings->tCOH_min && + spec_timings->tCS_min <= onfi_timings->tCS_min && + spec_timings->tDH_min <= onfi_timings->tDH_min && + spec_timings->tDS_min <= onfi_timings->tDS_min && + spec_timings->tIR_min <= onfi_timings->tIR_min && + spec_timings->tRC_min <= onfi_timings->tRC_min && + spec_timings->tREH_min <= onfi_timings->tREH_min && + spec_timings->tRHOH_min <= onfi_timings->tRHOH_min && + spec_timings->tRHW_min <= onfi_timings->tRHW_min && + spec_timings->tRLOH_min <= onfi_timings->tRLOH_min && + spec_timings->tRP_min <= onfi_timings->tRP_min && + spec_timings->tRR_min <= onfi_timings->tRR_min && + spec_timings->tWC_min <= onfi_timings->tWC_min && + spec_timings->tWH_min <= onfi_timings->tWH_min && + spec_timings->tWHR_min <= onfi_timings->tWHR_min && + spec_timings->tWP_min <= onfi_timings->tWP_min && + spec_timings->tWW_min <= onfi_timings->tWW_min) + return mode; + } + + return 0; +} + /** * onfi_fill_data_interface - Initialize a data interface from a given ONFI mode * @chip: The NAND chip -- cgit v1.2.3 From 173d548b64e14d3d1f22191cc0092c47631a18db Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Fri, 29 May 2020 13:13:10 +0200 Subject: mtd: rawnand: timings: Avoid redefining tR_max and tCCS_min These two values are already hardcoded in the default ONFI timing structure, no need to redefine them here. Plus, we want to be able to reference timing mode 0 easily and reliably, without extra computation, so we get rid of the extra assignations. Signed-off-by: Miquel Raynal Reviewed-by: Boris Brezillon Link: https://lore.kernel.org/linux-mtd/20200529111322.7184-17-miquel.raynal@bootlin.com --- drivers/mtd/nand/raw/nand_timings.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/mtd/nand/raw/nand_timings.c b/drivers/mtd/nand/raw/nand_timings.c index b089f2dc5f23..54c7a1a8b038 100644 --- a/drivers/mtd/nand/raw/nand_timings.c +++ b/drivers/mtd/nand/raw/nand_timings.c @@ -369,9 +369,6 @@ int onfi_fill_data_interface(struct nand_chip *chip, /* microseconds -> picoseconds */ timings->tPROG_max = 1000000ULL * ONFI_DYN_TIMING_MAX; timings->tBERS_max = 1000000ULL * ONFI_DYN_TIMING_MAX; - - timings->tR_max = 200000000; - timings->tCCS_min = 500000; } return 0; -- cgit v1.2.3 From d1bfe1e31932822ee90fc6b4cdeae785f70b3650 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Fri, 29 May 2020 13:13:11 +0200 Subject: mtd: rawnand: timings: Use default values for tPROG_max and tBERS_max The ONFI parameter page of a chip might define more fine grained tPROG_max and tBERS_max. When we do not have this information, we default to the highest possible values (they are maxima anyway). There is no point setting these fields at runtime, so explicitly move these defaults to the main ONFI SDR timings structure. This way, we will also be able to return a pointer to mode 0 directly when we will create a default reset configuration. Signed-off-by: Miquel Raynal Reviewed-by: Boris Brezillon Link: https://lore.kernel.org/linux-mtd/20200529111322.7184-18-miquel.raynal@bootlin.com --- drivers/mtd/nand/raw/nand_timings.c | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/drivers/mtd/nand/raw/nand_timings.c b/drivers/mtd/nand/raw/nand_timings.c index 54c7a1a8b038..efff3583c549 100644 --- a/drivers/mtd/nand/raw/nand_timings.c +++ b/drivers/mtd/nand/raw/nand_timings.c @@ -12,6 +12,13 @@ #define ONFI_DYN_TIMING_MAX U16_MAX +/* + * For non-ONFI chips we use the highest possible value for tPROG and tBERS. + * tR and tCCS will take the default values precised in the ONFI specification + * for timing mode 0, respectively 200us and 500ns. + * + * These four values are tweaked to be more accurate in the case of ONFI chips. + */ static const struct nand_data_interface onfi_sdr_timings[] = { /* Mode 0 */ { @@ -20,6 +27,8 @@ static const struct nand_data_interface onfi_sdr_timings[] = { .timings.sdr = { .tCCS_min = 500000, .tR_max = 200000000, + .tPROG_max = 1000000ULL * ONFI_DYN_TIMING_MAX, + .tBERS_max = 1000000ULL * ONFI_DYN_TIMING_MAX, .tADL_min = 400000, .tALH_min = 20000, .tALS_min = 50000, @@ -63,6 +72,8 @@ static const struct nand_data_interface onfi_sdr_timings[] = { .timings.sdr = { .tCCS_min = 500000, .tR_max = 200000000, + .tPROG_max = 1000000ULL * ONFI_DYN_TIMING_MAX, + .tBERS_max = 1000000ULL * ONFI_DYN_TIMING_MAX, .tADL_min = 400000, .tALH_min = 10000, .tALS_min = 25000, @@ -106,6 +117,8 @@ static const struct nand_data_interface onfi_sdr_timings[] = { .timings.sdr = { .tCCS_min = 500000, .tR_max = 200000000, + .tPROG_max = 1000000ULL * ONFI_DYN_TIMING_MAX, + .tBERS_max = 1000000ULL * ONFI_DYN_TIMING_MAX, .tADL_min = 400000, .tALH_min = 10000, .tALS_min = 15000, @@ -149,6 +162,8 @@ static const struct nand_data_interface onfi_sdr_timings[] = { .timings.sdr = { .tCCS_min = 500000, .tR_max = 200000000, + .tPROG_max = 1000000ULL * ONFI_DYN_TIMING_MAX, + .tBERS_max = 1000000ULL * ONFI_DYN_TIMING_MAX, .tADL_min = 400000, .tALH_min = 5000, .tALS_min = 10000, @@ -192,6 +207,8 @@ static const struct nand_data_interface onfi_sdr_timings[] = { .timings.sdr = { .tCCS_min = 500000, .tR_max = 200000000, + .tPROG_max = 1000000ULL * ONFI_DYN_TIMING_MAX, + .tBERS_max = 1000000ULL * ONFI_DYN_TIMING_MAX, .tADL_min = 400000, .tALH_min = 5000, .tALS_min = 10000, @@ -235,6 +252,8 @@ static const struct nand_data_interface onfi_sdr_timings[] = { .timings.sdr = { .tCCS_min = 500000, .tR_max = 200000000, + .tPROG_max = 1000000ULL * ONFI_DYN_TIMING_MAX, + .tBERS_max = 1000000ULL * ONFI_DYN_TIMING_MAX, .tADL_min = 400000, .tALH_min = 5000, .tALS_min = 10000, @@ -357,18 +376,6 @@ int onfi_fill_data_interface(struct nand_chip *chip, /* nanoseconds -> picoseconds */ timings->tCCS_min = 1000UL * onfi->tCCS; - } else { - struct nand_sdr_timings *timings = &iface->timings.sdr; - /* - * For non-ONFI chips we use the highest possible value for - * tPROG and tBERS. tR and tCCS will take the default values - * precised in the ONFI specification for timing mode 0, - * respectively 200us and 500ns. - */ - - /* microseconds -> picoseconds */ - timings->tPROG_max = 1000000ULL * ONFI_DYN_TIMING_MAX; - timings->tBERS_max = 1000000ULL * ONFI_DYN_TIMING_MAX; } return 0; -- cgit v1.2.3 From e0160cd41fb81fde9ee4612a7ea2dfd631de2638 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Fri, 29 May 2020 13:13:12 +0200 Subject: mtd: rawnand: Hide the chip->data_interface indirection As a preparation for allocating the data interface structure dynamically (and rename it), let's avoid accessing chip->data_interface directly. Instead, we introduce a helper, nand_get_interface_config(), and use it to retrieve the current data interface configuration out of a nand_chip object. Signed-off-by: Miquel Raynal Reviewed-by: Boris Brezillon Link: https://lore.kernel.org/linux-mtd/20200529111322.7184-19-miquel.raynal@bootlin.com --- drivers/mtd/nand/raw/marvell_nand.c | 9 ++++++--- drivers/mtd/nand/raw/meson_nand.c | 8 ++++---- drivers/mtd/nand/raw/nand_base.c | 34 +++++++++++++++++----------------- drivers/mtd/nand/raw/nand_legacy.c | 5 ++++- drivers/mtd/nand/raw/nand_toshiba.c | 2 +- drivers/mtd/nand/raw/stm32_fmc2_nand.c | 2 +- drivers/mtd/nand/raw/tango_nand.c | 2 +- include/linux/mtd/rawnand.h | 11 +++++++++++ 8 files changed, 45 insertions(+), 28 deletions(-) diff --git a/drivers/mtd/nand/raw/marvell_nand.c b/drivers/mtd/nand/raw/marvell_nand.c index 260a0430313e..df859889e4eb 100644 --- a/drivers/mtd/nand/raw/marvell_nand.c +++ b/drivers/mtd/nand/raw/marvell_nand.c @@ -1096,6 +1096,8 @@ static int marvell_nfc_hw_ecc_hmg_do_write_page(struct nand_chip *chip, const u8 *oob_buf, bool raw, int page) { + const struct nand_sdr_timings *sdr = + nand_get_sdr_timings(nand_get_interface_config(chip)); struct marvell_nand_chip *marvell_nand = to_marvell_nand(chip); struct marvell_nfc *nfc = to_marvell_nfc(chip->controller); const struct marvell_hw_ecc_layout *lt = to_marvell_nand(chip)->layout; @@ -1141,7 +1143,7 @@ static int marvell_nfc_hw_ecc_hmg_do_write_page(struct nand_chip *chip, return ret; ret = marvell_nfc_wait_op(chip, - PSEC_TO_MSEC(chip->data_interface.timings.sdr.tPROG_max)); + PSEC_TO_MSEC(sdr->tPROG_max)); return ret; } @@ -1562,6 +1564,8 @@ static int marvell_nfc_hw_ecc_bch_write_page(struct nand_chip *chip, const u8 *buf, int oob_required, int page) { + const struct nand_sdr_timings *sdr = + nand_get_sdr_timings(nand_get_interface_config(chip)); struct mtd_info *mtd = nand_to_mtd(chip); const struct marvell_hw_ecc_layout *lt = to_marvell_nand(chip)->layout; const u8 *data = buf; @@ -1598,8 +1602,7 @@ static int marvell_nfc_hw_ecc_bch_write_page(struct nand_chip *chip, marvell_nfc_wait_ndrun(chip); } - ret = marvell_nfc_wait_op(chip, - PSEC_TO_MSEC(chip->data_interface.timings.sdr.tPROG_max)); + ret = marvell_nfc_wait_op(chip, PSEC_TO_MSEC(sdr->tPROG_max)); marvell_nfc_disable_hw_ecc(chip); diff --git a/drivers/mtd/nand/raw/meson_nand.c b/drivers/mtd/nand/raw/meson_nand.c index 3f376471f3f7..580b7be0719f 100644 --- a/drivers/mtd/nand/raw/meson_nand.c +++ b/drivers/mtd/nand/raw/meson_nand.c @@ -573,10 +573,10 @@ static int meson_nfc_write_buf(struct nand_chip *nand, u8 *buf, int len) static int meson_nfc_rw_cmd_prepare_and_execute(struct nand_chip *nand, int page, bool in) { + const struct nand_sdr_timings *sdr = + nand_get_sdr_timings(nand_get_interface_config(nand)); struct mtd_info *mtd = nand_to_mtd(nand); struct meson_nfc *nfc = nand_get_controller_data(nand); - const struct nand_sdr_timings *sdr = - nand_get_sdr_timings(&nand->data_interface); u32 *addrs = nfc->cmdfifo.rw.addrs; u32 cs = nfc->param.chip_select; u32 cmd0, cmd_num, row_start; @@ -626,9 +626,9 @@ static int meson_nfc_rw_cmd_prepare_and_execute(struct nand_chip *nand, static int meson_nfc_write_page_sub(struct nand_chip *nand, int page, int raw) { - struct mtd_info *mtd = nand_to_mtd(nand); const struct nand_sdr_timings *sdr = - nand_get_sdr_timings(&nand->data_interface); + nand_get_sdr_timings(nand_get_interface_config(nand)); + struct mtd_info *mtd = nand_to_mtd(nand); struct meson_nfc_nand_chip *meson_chip = to_meson_nand(nand); struct meson_nfc *nfc = nand_get_controller_data(nand); int data_len, info_len; diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c index b4de85794e07..7d393e1d0252 100644 --- a/drivers/mtd/nand/raw/nand_base.c +++ b/drivers/mtd/nand/raw/nand_base.c @@ -773,7 +773,7 @@ int nand_soft_waitrdy(struct nand_chip *chip, unsigned long timeout_ms) return -ENOTSUPP; /* Wait tWB before polling the STATUS reg. */ - timings = nand_get_sdr_timings(&chip->data_interface); + timings = nand_get_sdr_timings(nand_get_interface_config(chip)); ndelay(PSEC_TO_NSEC(timings->tWB_max)); ret = nand_status_op(chip, NULL); @@ -1119,9 +1119,9 @@ static int nand_sp_exec_read_page_op(struct nand_chip *chip, unsigned int page, unsigned int offset_in_page, void *buf, unsigned int len) { - struct mtd_info *mtd = nand_to_mtd(chip); const struct nand_sdr_timings *sdr = - nand_get_sdr_timings(&chip->data_interface); + nand_get_sdr_timings(nand_get_interface_config(chip)); + struct mtd_info *mtd = nand_to_mtd(chip); u8 addrs[4]; struct nand_op_instr instrs[] = { NAND_OP_CMD(NAND_CMD_READ0, 0), @@ -1163,7 +1163,7 @@ static int nand_lp_exec_read_page_op(struct nand_chip *chip, unsigned int page, unsigned int len) { const struct nand_sdr_timings *sdr = - nand_get_sdr_timings(&chip->data_interface); + nand_get_sdr_timings(nand_get_interface_config(chip)); u8 addrs[5]; struct nand_op_instr instrs[] = { NAND_OP_CMD(NAND_CMD_READ0, 0), @@ -1260,7 +1260,7 @@ int nand_read_param_page_op(struct nand_chip *chip, u8 page, void *buf, if (nand_has_exec_op(chip)) { const struct nand_sdr_timings *sdr = - nand_get_sdr_timings(&chip->data_interface); + nand_get_sdr_timings(nand_get_interface_config(chip)); struct nand_op_instr instrs[] = { NAND_OP_CMD(NAND_CMD_PARAM, 0), NAND_OP_ADDR(1, &page, PSEC_TO_NSEC(sdr->tWB_max)), @@ -1315,7 +1315,7 @@ int nand_change_read_column_op(struct nand_chip *chip, if (nand_has_exec_op(chip)) { const struct nand_sdr_timings *sdr = - nand_get_sdr_timings(&chip->data_interface); + nand_get_sdr_timings(nand_get_interface_config(chip)); u8 addrs[2] = {}; struct nand_op_instr instrs[] = { NAND_OP_CMD(NAND_CMD_RNDOUT, 0), @@ -1389,9 +1389,9 @@ static int nand_exec_prog_page_op(struct nand_chip *chip, unsigned int page, unsigned int offset_in_page, const void *buf, unsigned int len, bool prog) { - struct mtd_info *mtd = nand_to_mtd(chip); const struct nand_sdr_timings *sdr = - nand_get_sdr_timings(&chip->data_interface); + nand_get_sdr_timings(nand_get_interface_config(chip)); + struct mtd_info *mtd = nand_to_mtd(chip); u8 addrs[5] = {}; struct nand_op_instr instrs[] = { /* @@ -1514,7 +1514,7 @@ int nand_prog_page_end_op(struct nand_chip *chip) if (nand_has_exec_op(chip)) { const struct nand_sdr_timings *sdr = - nand_get_sdr_timings(&chip->data_interface); + nand_get_sdr_timings(nand_get_interface_config(chip)); struct nand_op_instr instrs[] = { NAND_OP_CMD(NAND_CMD_PAGEPROG, PSEC_TO_NSEC(sdr->tWB_max)), @@ -1621,7 +1621,7 @@ int nand_change_write_column_op(struct nand_chip *chip, if (nand_has_exec_op(chip)) { const struct nand_sdr_timings *sdr = - nand_get_sdr_timings(&chip->data_interface); + nand_get_sdr_timings(nand_get_interface_config(chip)); u8 addrs[2]; struct nand_op_instr instrs[] = { NAND_OP_CMD(NAND_CMD_RNDIN, 0), @@ -1676,7 +1676,7 @@ int nand_readid_op(struct nand_chip *chip, u8 addr, void *buf, if (nand_has_exec_op(chip)) { const struct nand_sdr_timings *sdr = - nand_get_sdr_timings(&chip->data_interface); + nand_get_sdr_timings(nand_get_interface_config(chip)); struct nand_op_instr instrs[] = { NAND_OP_CMD(NAND_CMD_READID, 0), NAND_OP_ADDR(1, &addr, PSEC_TO_NSEC(sdr->tADL_min)), @@ -1715,7 +1715,7 @@ int nand_status_op(struct nand_chip *chip, u8 *status) { if (nand_has_exec_op(chip)) { const struct nand_sdr_timings *sdr = - nand_get_sdr_timings(&chip->data_interface); + nand_get_sdr_timings(nand_get_interface_config(chip)); struct nand_op_instr instrs[] = { NAND_OP_CMD(NAND_CMD_STATUS, PSEC_TO_NSEC(sdr->tADL_min)), @@ -1784,7 +1784,7 @@ int nand_erase_op(struct nand_chip *chip, unsigned int eraseblock) if (nand_has_exec_op(chip)) { const struct nand_sdr_timings *sdr = - nand_get_sdr_timings(&chip->data_interface); + nand_get_sdr_timings(nand_get_interface_config(chip)); u8 addrs[3] = { page, page >> 8, page >> 16 }; struct nand_op_instr instrs[] = { NAND_OP_CMD(NAND_CMD_ERASE1, 0), @@ -1843,7 +1843,7 @@ static int nand_set_features_op(struct nand_chip *chip, u8 feature, if (nand_has_exec_op(chip)) { const struct nand_sdr_timings *sdr = - nand_get_sdr_timings(&chip->data_interface); + nand_get_sdr_timings(nand_get_interface_config(chip)); struct nand_op_instr instrs[] = { NAND_OP_CMD(NAND_CMD_SET_FEATURES, 0), NAND_OP_ADDR(1, &feature, PSEC_TO_NSEC(sdr->tADL_min)), @@ -1890,7 +1890,7 @@ static int nand_get_features_op(struct nand_chip *chip, u8 feature, if (nand_has_exec_op(chip)) { const struct nand_sdr_timings *sdr = - nand_get_sdr_timings(&chip->data_interface); + nand_get_sdr_timings(nand_get_interface_config(chip)); struct nand_op_instr instrs[] = { NAND_OP_CMD(NAND_CMD_GET_FEATURES, 0), NAND_OP_ADDR(1, &feature, PSEC_TO_NSEC(sdr->tWB_max)), @@ -1947,7 +1947,7 @@ int nand_reset_op(struct nand_chip *chip) { if (nand_has_exec_op(chip)) { const struct nand_sdr_timings *sdr = - nand_get_sdr_timings(&chip->data_interface); + nand_get_sdr_timings(nand_get_interface_config(chip)); struct nand_op_instr instrs[] = { NAND_OP_CMD(NAND_CMD_RESET, PSEC_TO_NSEC(sdr->tWB_max)), NAND_OP_WAIT_RDY(PSEC_TO_MSEC(sdr->tRST_max), 0), @@ -3226,7 +3226,7 @@ static void nand_wait_readrdy(struct nand_chip *chip) if (!(chip->options & NAND_NEED_READRDY)) return; - sdr = nand_get_sdr_timings(&chip->data_interface); + sdr = nand_get_sdr_timings(nand_get_interface_config(chip)); WARN_ON(nand_wait_rdy_op(chip, PSEC_TO_MSEC(sdr->tR_max), 0)); } diff --git a/drivers/mtd/nand/raw/nand_legacy.c b/drivers/mtd/nand/raw/nand_legacy.c index 848403dcae03..fe769762e1d8 100644 --- a/drivers/mtd/nand/raw/nand_legacy.c +++ b/drivers/mtd/nand/raw/nand_legacy.c @@ -354,6 +354,9 @@ static void nand_command(struct nand_chip *chip, unsigned int command, static void nand_ccs_delay(struct nand_chip *chip) { + const struct nand_sdr_timings *sdr = + nand_get_sdr_timings(nand_get_interface_config(chip)); + /* * The controller already takes care of waiting for tCCS when the RNDIN * or RNDOUT command is sent, return directly. @@ -366,7 +369,7 @@ static void nand_ccs_delay(struct nand_chip *chip) * (which should be safe for all NANDs). */ if (nand_controller_can_setup_data_iface(chip)) - ndelay(chip->data_interface.timings.sdr.tCCS_min / 1000); + ndelay(sdr->tCCS_min / 1000); else ndelay(500); } diff --git a/drivers/mtd/nand/raw/nand_toshiba.c b/drivers/mtd/nand/raw/nand_toshiba.c index ae069905d7e4..333037bdca41 100644 --- a/drivers/mtd/nand/raw/nand_toshiba.c +++ b/drivers/mtd/nand/raw/nand_toshiba.c @@ -33,7 +33,7 @@ static int toshiba_nand_benand_read_eccstatus_op(struct nand_chip *chip, if (nand_has_exec_op(chip)) { const struct nand_sdr_timings *sdr = - nand_get_sdr_timings(&chip->data_interface); + nand_get_sdr_timings(nand_get_interface_config(chip)); struct nand_op_instr instrs[] = { NAND_OP_CMD(TOSHIBA_NAND_CMD_ECC_STATUS_READ, PSEC_TO_NSEC(sdr->tADL_min)), diff --git a/drivers/mtd/nand/raw/stm32_fmc2_nand.c b/drivers/mtd/nand/raw/stm32_fmc2_nand.c index 65c9d17b25a3..7320c0fc19ec 100644 --- a/drivers/mtd/nand/raw/stm32_fmc2_nand.c +++ b/drivers/mtd/nand/raw/stm32_fmc2_nand.c @@ -1308,7 +1308,7 @@ static int stm32_fmc2_nfc_waitrdy(struct nand_chip *chip, dev_warn(nfc->dev, "Waitrdy timeout\n"); /* Wait tWB before R/B# signal is low */ - timings = nand_get_sdr_timings(&chip->data_interface); + timings = nand_get_sdr_timings(nand_get_interface_config(chip)); ndelay(PSEC_TO_NSEC(timings->tWB_max)); /* R/B# signal is low, clear high level flag */ diff --git a/drivers/mtd/nand/raw/tango_nand.c b/drivers/mtd/nand/raw/tango_nand.c index b3a0d08f1733..648dc7e77f6a 100644 --- a/drivers/mtd/nand/raw/tango_nand.c +++ b/drivers/mtd/nand/raw/tango_nand.c @@ -336,7 +336,7 @@ static int tango_write_page(struct nand_chip *chip, const u8 *buf, if (err) return err; - timings = nand_get_sdr_timings(&chip->data_interface); + timings = nand_get_sdr_timings(nand_get_interface_config(chip)); err = tango_waitrdy(chip, PSEC_TO_MSEC(timings->tR_max)); if (err) return err; diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h index 544ec8736793..0852df941130 100644 --- a/include/linux/mtd/rawnand.h +++ b/include/linux/mtd/rawnand.h @@ -1203,6 +1203,17 @@ static inline struct device_node *nand_get_flash_node(struct nand_chip *chip) return mtd_get_of_node(nand_to_mtd(chip)); } +/** + * nand_get_interface_config - Retrieve the current interface configuration + * of a NAND chip + * @chip: The NAND chip + */ +static inline const struct nand_data_interface * +nand_get_interface_config(struct nand_chip *chip) +{ + return &chip->data_interface; +} + /* * 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 v1.2.3 From 4c46667b3d67253604ee42840917844548c86657 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Fri, 29 May 2020 13:13:13 +0200 Subject: mtd: rawnand: s/data_interface/interface_config/ The name/suffix data_interface is a bit misleading in that the field or functions actually represent a configuration that can be applied by the controller/chip. Let's rename all fields/functions/hooks that are worth renaming. Signed-off-by: Boris Brezillon Signed-off-by: Miquel Raynal --- drivers/mtd/nand/raw/ams-delta.c | 6 +-- drivers/mtd/nand/raw/arasan-nand-controller.c | 6 +-- drivers/mtd/nand/raw/atmel/nand-controller.c | 34 ++++++------- drivers/mtd/nand/raw/cadence-nand-controller.c | 6 +-- drivers/mtd/nand/raw/denali.c | 8 +-- drivers/mtd/nand/raw/fsmc_nand.c | 6 +-- drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c | 6 +-- drivers/mtd/nand/raw/internals.h | 12 ++--- drivers/mtd/nand/raw/marvell_nand.c | 9 ++-- drivers/mtd/nand/raw/meson_nand.c | 6 +-- drivers/mtd/nand/raw/mtk_nand.c | 6 +-- drivers/mtd/nand/raw/mxc_nand.c | 20 ++++---- drivers/mtd/nand/raw/mxic_nand.c | 6 +-- drivers/mtd/nand/raw/nand_base.c | 69 +++++++++++++------------- drivers/mtd/nand/raw/nand_legacy.c | 2 +- drivers/mtd/nand/raw/nand_timings.c | 17 ++++--- drivers/mtd/nand/raw/s3c2410.c | 6 +-- drivers/mtd/nand/raw/stm32_fmc2_nand.c | 4 +- drivers/mtd/nand/raw/sunxi_nand.c | 6 +-- drivers/mtd/nand/raw/tango_nand.c | 4 +- drivers/mtd/nand/raw/tegra_nand.c | 6 +-- include/linux/mtd/rawnand.h | 33 ++++++------ 22 files changed, 139 insertions(+), 139 deletions(-) diff --git a/drivers/mtd/nand/raw/ams-delta.c b/drivers/mtd/nand/raw/ams-delta.c index 3711e7a0436c..fdba155416d2 100644 --- a/drivers/mtd/nand/raw/ams-delta.c +++ b/drivers/mtd/nand/raw/ams-delta.c @@ -191,8 +191,8 @@ static int gpio_nand_exec_op(struct nand_chip *this, return ret; } -static int gpio_nand_setup_data_interface(struct nand_chip *this, int csline, - const struct nand_data_interface *cf) +static int gpio_nand_setup_interface(struct nand_chip *this, int csline, + const struct nand_interface_config *cf) { struct gpio_nand *priv = nand_get_controller_data(this); const struct nand_sdr_timings *sdr = nand_get_sdr_timings(cf); @@ -217,7 +217,7 @@ static int gpio_nand_setup_data_interface(struct nand_chip *this, int csline, static const struct nand_controller_ops gpio_nand_ops = { .exec_op = gpio_nand_exec_op, - .setup_data_interface = gpio_nand_setup_data_interface, + .setup_interface = gpio_nand_setup_interface, }; /* diff --git a/drivers/mtd/nand/raw/arasan-nand-controller.c b/drivers/mtd/nand/raw/arasan-nand-controller.c index 7141dcccba3c..12c643e97c85 100644 --- a/drivers/mtd/nand/raw/arasan-nand-controller.c +++ b/drivers/mtd/nand/raw/arasan-nand-controller.c @@ -854,8 +854,8 @@ static int anfc_exec_op(struct nand_chip *chip, return nand_op_parser_exec_op(chip, &anfc_op_parser, op, check_only); } -static int anfc_setup_data_interface(struct nand_chip *chip, int target, - const struct nand_data_interface *conf) +static int anfc_setup_interface(struct nand_chip *chip, int target, + const struct nand_interface_config *conf) { struct anand *anand = to_anand(chip); struct arasan_nfc *nfc = to_anfc(chip->controller); @@ -1083,7 +1083,7 @@ static void anfc_detach_chip(struct nand_chip *chip) static const struct nand_controller_ops anfc_ops = { .exec_op = anfc_exec_op, - .setup_data_interface = anfc_setup_data_interface, + .setup_interface = anfc_setup_interface, .attach_chip = anfc_attach_chip, .detach_chip = anfc_detach_chip, }; diff --git a/drivers/mtd/nand/raw/atmel/nand-controller.c b/drivers/mtd/nand/raw/atmel/nand-controller.c index 46a3724a788e..c9818f548d07 100644 --- a/drivers/mtd/nand/raw/atmel/nand-controller.c +++ b/drivers/mtd/nand/raw/atmel/nand-controller.c @@ -200,8 +200,8 @@ struct atmel_nand_controller_ops { void (*nand_init)(struct atmel_nand_controller *nc, struct atmel_nand *nand); int (*ecc_init)(struct nand_chip *chip); - int (*setup_data_interface)(struct atmel_nand *nand, int csline, - const struct nand_data_interface *conf); + int (*setup_interface)(struct atmel_nand *nand, int csline, + const struct nand_interface_config *conf); }; struct atmel_nand_controller_caps { @@ -1168,7 +1168,7 @@ static int atmel_hsmc_nand_ecc_init(struct nand_chip *chip) } static int atmel_smc_nand_prepare_smcconf(struct atmel_nand *nand, - const struct nand_data_interface *conf, + const struct nand_interface_config *conf, struct atmel_smc_cs_conf *smcconf) { u32 ncycles, totalcycles, timeps, mckperiodps; @@ -1397,9 +1397,9 @@ static int atmel_smc_nand_prepare_smcconf(struct atmel_nand *nand, return 0; } -static int atmel_smc_nand_setup_data_interface(struct atmel_nand *nand, +static int atmel_smc_nand_setup_interface(struct atmel_nand *nand, int csline, - const struct nand_data_interface *conf) + const struct nand_interface_config *conf) { struct atmel_nand_controller *nc; struct atmel_smc_cs_conf smcconf; @@ -1422,9 +1422,9 @@ static int atmel_smc_nand_setup_data_interface(struct atmel_nand *nand, return 0; } -static int atmel_hsmc_nand_setup_data_interface(struct atmel_nand *nand, +static int atmel_hsmc_nand_setup_interface(struct atmel_nand *nand, int csline, - const struct nand_data_interface *conf) + const struct nand_interface_config *conf) { struct atmel_hsmc_nand_controller *nc; struct atmel_smc_cs_conf smcconf; @@ -1452,8 +1452,8 @@ static int atmel_hsmc_nand_setup_data_interface(struct atmel_nand *nand, return 0; } -static int atmel_nand_setup_data_interface(struct nand_chip *chip, int csline, - const struct nand_data_interface *conf) +static int atmel_nand_setup_interface(struct nand_chip *chip, int csline, + const struct nand_interface_config *conf) { struct atmel_nand *nand = to_atmel_nand(chip); struct atmel_nand_controller *nc; @@ -1464,7 +1464,7 @@ static int atmel_nand_setup_data_interface(struct nand_chip *chip, int csline, (csline < 0 && csline != NAND_DATA_IFACE_CHECK_ONLY)) return -EINVAL; - return nc->caps->ops->setup_data_interface(nand, csline, conf); + return nc->caps->ops->setup_interface(nand, csline, conf); } static void atmel_nand_init(struct atmel_nand_controller *nc, @@ -1483,7 +1483,7 @@ static void atmel_nand_init(struct atmel_nand_controller *nc, chip->legacy.write_buf = atmel_nand_write_buf; chip->legacy.select_chip = atmel_nand_select_chip; - if (!nc->mck || !nc->caps->ops->setup_data_interface) + if (!nc->mck || !nc->caps->ops->setup_interface) chip->options |= NAND_KEEP_TIMINGS; /* Some NANDs require a longer delay than the default one (20us). */ @@ -1956,7 +1956,7 @@ static int atmel_nand_attach_chip(struct nand_chip *chip) static const struct nand_controller_ops atmel_nand_controller_ops = { .attach_chip = atmel_nand_attach_chip, - .setup_data_interface = atmel_nand_setup_data_interface, + .setup_interface = atmel_nand_setup_interface, }; static int atmel_nand_controller_init(struct atmel_nand_controller *nc, @@ -2318,7 +2318,7 @@ static const struct atmel_nand_controller_ops atmel_hsmc_nc_ops = { .remove = atmel_hsmc_nand_controller_remove, .ecc_init = atmel_hsmc_nand_ecc_init, .nand_init = atmel_hsmc_nand_init, - .setup_data_interface = atmel_hsmc_nand_setup_data_interface, + .setup_interface = atmel_hsmc_nand_setup_interface, }; static const struct atmel_nand_controller_caps atmel_sama5_nc_caps = { @@ -2375,10 +2375,10 @@ atmel_smc_nand_controller_remove(struct atmel_nand_controller *nc) /* * The SMC reg layout of at91rm9200 is completely different which prevents us - * from re-using atmel_smc_nand_setup_data_interface() for the - * ->setup_data_interface() hook. + * from re-using atmel_smc_nand_setup_interface() for the + * ->setup_interface() hook. * At this point, there's no support for the at91rm9200 SMC IP, so we leave - * ->setup_data_interface() unassigned. + * ->setup_interface() unassigned. */ static const struct atmel_nand_controller_ops at91rm9200_nc_ops = { .probe = atmel_smc_nand_controller_probe, @@ -2399,7 +2399,7 @@ static const struct atmel_nand_controller_ops atmel_smc_nc_ops = { .remove = atmel_smc_nand_controller_remove, .ecc_init = atmel_nand_ecc_init, .nand_init = atmel_smc_nand_init, - .setup_data_interface = atmel_smc_nand_setup_data_interface, + .setup_interface = atmel_smc_nand_setup_interface, }; static const struct atmel_nand_controller_caps atmel_sam9260_nc_caps = { diff --git a/drivers/mtd/nand/raw/cadence-nand-controller.c b/drivers/mtd/nand/raw/cadence-nand-controller.c index c405722adfe1..574cbd3446e5 100644 --- a/drivers/mtd/nand/raw/cadence-nand-controller.c +++ b/drivers/mtd/nand/raw/cadence-nand-controller.c @@ -2303,8 +2303,8 @@ static inline u32 calc_tdvw(u32 trp_cnt, u32 clk_period, u32 trhoh_min, } static int -cadence_nand_setup_data_interface(struct nand_chip *chip, int chipnr, - const struct nand_data_interface *conf) +cadence_nand_setup_interface(struct nand_chip *chip, int chipnr, + const struct nand_interface_config *conf) { const struct nand_sdr_timings *sdr; struct cdns_nand_ctrl *cdns_ctrl = to_cdns_nand_ctrl(chip->controller); @@ -2690,7 +2690,7 @@ static int cadence_nand_attach_chip(struct nand_chip *chip) static const struct nand_controller_ops cadence_nand_controller_ops = { .attach_chip = cadence_nand_attach_chip, .exec_op = cadence_nand_exec_op, - .setup_data_interface = cadence_nand_setup_data_interface, + .setup_interface = cadence_nand_setup_interface, }; static int cadence_nand_chip_init(struct cdns_nand_ctrl *cdns_ctrl, diff --git a/drivers/mtd/nand/raw/denali.c b/drivers/mtd/nand/raw/denali.c index 4e6e1578aa2d..9d99dade95ce 100644 --- a/drivers/mtd/nand/raw/denali.c +++ b/drivers/mtd/nand/raw/denali.c @@ -761,8 +761,8 @@ static int denali_write_page(struct nand_chip *chip, const u8 *buf, return denali_page_xfer(chip, (void *)buf, mtd->writesize, page, true); } -static int denali_setup_data_interface(struct nand_chip *chip, int chipnr, - const struct nand_data_interface *conf) +static int denali_setup_interface(struct nand_chip *chip, int chipnr, + const struct nand_interface_config *conf) { static const unsigned int data_setup_on_host = 10000; struct denali_controller *denali = to_denali_controller(chip); @@ -1173,7 +1173,7 @@ static int denali_exec_op(struct nand_chip *chip, 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, + .setup_interface = denali_setup_interface, }; int denali_chip_init(struct denali_controller *denali, @@ -1230,7 +1230,7 @@ int denali_chip_init(struct denali_controller *denali, chip->buf_align = 16; } - /* clk rate info is needed for setup_data_interface */ + /* clk rate info is needed for setup_interface */ if (!denali->clk_rate || !denali->clk_x_rate) chip->options |= NAND_KEEP_TIMINGS; diff --git a/drivers/mtd/nand/raw/fsmc_nand.c b/drivers/mtd/nand/raw/fsmc_nand.c index 3909752b14c5..92ddc41d0ff0 100644 --- a/drivers/mtd/nand/raw/fsmc_nand.c +++ b/drivers/mtd/nand/raw/fsmc_nand.c @@ -327,8 +327,8 @@ static int fsmc_calc_timings(struct fsmc_nand_data *host, return 0; } -static int fsmc_setup_data_interface(struct nand_chip *nand, int csline, - const struct nand_data_interface *conf) +static int fsmc_setup_interface(struct nand_chip *nand, int csline, + const struct nand_interface_config *conf) { struct fsmc_nand_data *host = nand_to_fsmc(nand); struct fsmc_nand_timings tims; @@ -951,7 +951,7 @@ static int fsmc_nand_attach_chip(struct nand_chip *nand) static const struct nand_controller_ops fsmc_nand_controller_ops = { .attach_chip = fsmc_nand_attach_chip, .exec_op = fsmc_exec_op, - .setup_data_interface = fsmc_setup_data_interface, + .setup_interface = fsmc_setup_interface, }; /** diff --git a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c index 061a8ddda275..5d4aee46cc55 100644 --- a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c +++ b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c @@ -736,8 +736,8 @@ static void gpmi_nfc_apply_timings(struct gpmi_nand_data *this) udelay(dll_wait_time_us); } -static int gpmi_setup_data_interface(struct nand_chip *chip, int chipnr, - const struct nand_data_interface *conf) +static int gpmi_setup_interface(struct nand_chip *chip, int chipnr, + const struct nand_interface_config *conf) { struct gpmi_nand_data *this = nand_get_controller_data(chip); const struct nand_sdr_timings *sdr; @@ -2400,7 +2400,7 @@ unmap: static const struct nand_controller_ops gpmi_nand_controller_ops = { .attach_chip = gpmi_nand_attach_chip, - .setup_data_interface = gpmi_setup_data_interface, + .setup_interface = gpmi_setup_interface, .exec_op = gpmi_nfc_exec_op, }; diff --git a/drivers/mtd/nand/raw/internals.h b/drivers/mtd/nand/raw/internals.h index f851ed210d70..114c63a6a349 100644 --- a/drivers/mtd/nand/raw/internals.h +++ b/drivers/mtd/nand/raw/internals.h @@ -84,10 +84,10 @@ 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); -int onfi_fill_data_interface(struct nand_chip *chip, - struct nand_data_interface *iface, - enum nand_data_interface_type type, - unsigned int timing_mode); +int onfi_fill_interface_config(struct nand_chip *chip, + struct nand_interface_config *iface, + enum nand_interface_type type, + unsigned int timing_mode); unsigned int onfi_find_closest_sdr_mode(const struct nand_sdr_timings *spec_timings); int nand_get_features(struct nand_chip *chip, int addr, u8 *subfeature_param); @@ -133,10 +133,10 @@ static inline int nand_exec_op(struct nand_chip *chip, return chip->controller->ops->exec_op(chip, op, false); } -static inline bool nand_controller_can_setup_data_iface(struct nand_chip *chip) +static inline bool nand_controller_can_setup_interface(struct nand_chip *chip) { if (!chip->controller || !chip->controller->ops || - !chip->controller->ops->setup_data_interface) + !chip->controller->ops->setup_interface) return false; if (chip->options & NAND_KEEP_TIMINGS) diff --git a/drivers/mtd/nand/raw/marvell_nand.c b/drivers/mtd/nand/raw/marvell_nand.c index df859889e4eb..8482d3bd8b1f 100644 --- a/drivers/mtd/nand/raw/marvell_nand.c +++ b/drivers/mtd/nand/raw/marvell_nand.c @@ -2308,9 +2308,8 @@ static struct nand_bbt_descr bbt_mirror_descr = { .pattern = bbt_mirror_pattern }; -static int marvell_nfc_setup_data_interface(struct nand_chip *chip, int chipnr, - const struct nand_data_interface - *conf) +static int marvell_nfc_setup_interface(struct nand_chip *chip, int chipnr, + const struct nand_interface_config *conf) { struct marvell_nand_chip *marvell_nand = to_marvell_nand(chip); struct marvell_nfc *nfc = to_marvell_nfc(chip->controller); @@ -2511,7 +2510,7 @@ static int marvell_nand_attach_chip(struct nand_chip *chip) static const struct nand_controller_ops marvell_nand_controller_ops = { .attach_chip = marvell_nand_attach_chip, .exec_op = marvell_nfc_exec_op, - .setup_data_interface = marvell_nfc_setup_data_interface, + .setup_interface = marvell_nfc_setup_interface, }; static int marvell_nand_chip_init(struct device *dev, struct marvell_nfc *nfc, @@ -2647,7 +2646,7 @@ static int marvell_nand_chip_init(struct device *dev, struct marvell_nfc *nfc, /* * Save a reference value for timing registers before - * ->setup_data_interface() is called. + * ->setup_interface() is called. */ marvell_nand->ndtr0 = readl_relaxed(nfc->regs + NDTR0); marvell_nand->ndtr1 = readl_relaxed(nfc->regs + NDTR1); diff --git a/drivers/mtd/nand/raw/meson_nand.c b/drivers/mtd/nand/raw/meson_nand.c index 580b7be0719f..0e5829a2b54f 100644 --- a/drivers/mtd/nand/raw/meson_nand.c +++ b/drivers/mtd/nand/raw/meson_nand.c @@ -1097,8 +1097,8 @@ static int meson_chip_buffer_init(struct nand_chip *nand) } static -int meson_nfc_setup_data_interface(struct nand_chip *nand, int csline, - const struct nand_data_interface *conf) +int meson_nfc_setup_interface(struct nand_chip *nand, int csline, + const struct nand_interface_config *conf) { struct meson_nfc_nand_chip *meson_chip = to_meson_nand(nand); const struct nand_sdr_timings *timings; @@ -1222,7 +1222,7 @@ static int meson_nand_attach_chip(struct nand_chip *nand) static const struct nand_controller_ops meson_nand_controller_ops = { .attach_chip = meson_nand_attach_chip, .detach_chip = meson_nand_detach_chip, - .setup_data_interface = meson_nfc_setup_data_interface, + .setup_interface = meson_nfc_setup_interface, .exec_op = meson_nfc_exec_op, }; diff --git a/drivers/mtd/nand/raw/mtk_nand.c b/drivers/mtd/nand/raw/mtk_nand.c index ca8457626d53..ad1b55dab211 100644 --- a/drivers/mtd/nand/raw/mtk_nand.c +++ b/drivers/mtd/nand/raw/mtk_nand.c @@ -531,8 +531,8 @@ static int mtk_nfc_exec_op(struct nand_chip *chip, return ret; } -static int mtk_nfc_setup_data_interface(struct nand_chip *chip, int csline, - const struct nand_data_interface *conf) +static int mtk_nfc_setup_interface(struct nand_chip *chip, int csline, + const struct nand_interface_config *conf) { struct mtk_nfc *nfc = nand_get_controller_data(chip); const struct nand_sdr_timings *timings; @@ -1357,7 +1357,7 @@ static int mtk_nfc_attach_chip(struct nand_chip *chip) static const struct nand_controller_ops mtk_nfc_controller_ops = { .attach_chip = mtk_nfc_attach_chip, - .setup_data_interface = mtk_nfc_setup_data_interface, + .setup_interface = mtk_nfc_setup_interface, .exec_op = mtk_nfc_exec_op, }; diff --git a/drivers/mtd/nand/raw/mxc_nand.c b/drivers/mtd/nand/raw/mxc_nand.c index 09dacb83cb5a..07c41e8bae2d 100644 --- a/drivers/mtd/nand/raw/mxc_nand.c +++ b/drivers/mtd/nand/raw/mxc_nand.c @@ -137,8 +137,8 @@ struct mxc_nand_devtype_data { u32 (*get_ecc_status)(struct mxc_nand_host *); const struct mtd_ooblayout_ops *ooblayout; void (*select_chip)(struct nand_chip *chip, int cs); - int (*setup_data_interface)(struct nand_chip *chip, int csline, - const struct nand_data_interface *conf); + int (*setup_interface)(struct nand_chip *chip, int csline, + const struct nand_interface_config *conf); void (*enable_hwecc)(struct nand_chip *chip, bool enable); /* @@ -1139,8 +1139,8 @@ static void preset_v1(struct mtd_info *mtd) writew(0x4, NFC_V1_V2_WRPROT); } -static int mxc_nand_v2_setup_data_interface(struct nand_chip *chip, int csline, - const struct nand_data_interface *conf) +static int mxc_nand_v2_setup_interface(struct nand_chip *chip, int csline, + const struct nand_interface_config *conf) { struct mxc_nand_host *host = nand_get_controller_data(chip); int tRC_min_ns, tRC_ps, ret; @@ -1521,7 +1521,7 @@ static const struct mxc_nand_devtype_data imx25_nand_devtype_data = { .get_ecc_status = get_ecc_status_v2, .ooblayout = &mxc_v2_ooblayout_ops, .select_chip = mxc_nand_select_chip_v2, - .setup_data_interface = mxc_nand_v2_setup_data_interface, + .setup_interface = mxc_nand_v2_setup_interface, .enable_hwecc = mxc_nand_enable_hwecc_v1_v2, .irqpending_quirk = 0, .needs_ip = 0, @@ -1738,17 +1738,17 @@ static int mxcnd_attach_chip(struct nand_chip *chip) return 0; } -static int mxcnd_setup_data_interface(struct nand_chip *chip, int chipnr, - const struct nand_data_interface *conf) +static int mxcnd_setup_interface(struct nand_chip *chip, int chipnr, + const struct nand_interface_config *conf) { struct mxc_nand_host *host = nand_get_controller_data(chip); - return host->devtype_data->setup_data_interface(chip, chipnr, conf); + return host->devtype_data->setup_interface(chip, chipnr, conf); } static const struct nand_controller_ops mxcnd_controller_ops = { .attach_chip = mxcnd_attach_chip, - .setup_data_interface = mxcnd_setup_data_interface, + .setup_interface = mxcnd_setup_interface, }; static int mxcnd_probe(struct platform_device *pdev) @@ -1809,7 +1809,7 @@ static int mxcnd_probe(struct platform_device *pdev) if (err < 0) return err; - if (!host->devtype_data->setup_data_interface) + if (!host->devtype_data->setup_interface) this->options |= NAND_KEEP_TIMINGS; if (host->devtype_data->needs_ip) { diff --git a/drivers/mtd/nand/raw/mxic_nand.c b/drivers/mtd/nand/raw/mxic_nand.c index 57f36721f4c6..d66b5b0971fa 100644 --- a/drivers/mtd/nand/raw/mxic_nand.c +++ b/drivers/mtd/nand/raw/mxic_nand.c @@ -451,8 +451,8 @@ static int mxic_nfc_exec_op(struct nand_chip *chip, return ret; } -static int mxic_nfc_setup_data_interface(struct nand_chip *chip, int chipnr, - const struct nand_data_interface *conf) +static int mxic_nfc_setup_interface(struct nand_chip *chip, int chipnr, + const struct nand_interface_config *conf) { struct mxic_nand_ctlr *nfc = nand_get_controller_data(chip); const struct nand_sdr_timings *sdr; @@ -480,7 +480,7 @@ static int mxic_nfc_setup_data_interface(struct nand_chip *chip, int chipnr, static const struct nand_controller_ops mxic_nand_controller_ops = { .exec_op = mxic_nfc_exec_op, - .setup_data_interface = mxic_nfc_setup_data_interface, + .setup_interface = mxic_nfc_setup_interface, }; static int mxic_nfc_probe(struct platform_device *pdev) diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c index 7d393e1d0252..4fa18fb68d62 100644 --- a/drivers/mtd/nand/raw/nand_base.c +++ b/drivers/mtd/nand/raw/nand_base.c @@ -898,7 +898,7 @@ static bool nand_supports_set_features(struct nand_chip *chip, int addr) } /** - * nand_reset_data_interface - Reset data interface and timings + * nand_reset_interface - Reset data interface and timings * @chip: The NAND chip * @chipnr: Internal die id * @@ -906,11 +906,12 @@ static bool nand_supports_set_features(struct nand_chip *chip, int addr) * * Returns 0 for success or negative error code otherwise. */ -static int nand_reset_data_interface(struct nand_chip *chip, int chipnr) +static int nand_reset_interface(struct nand_chip *chip, int chipnr) { + const struct nand_controller_ops *ops = chip->controller->ops; int ret; - if (!nand_controller_can_setup_data_iface(chip)) + if (!nand_controller_can_setup_interface(chip)) return 0; /* @@ -927,9 +928,9 @@ static int nand_reset_data_interface(struct nand_chip *chip, int chipnr) * timings to timing mode 0. */ - onfi_fill_data_interface(chip, &chip->data_interface, NAND_SDR_IFACE, 0); - ret = chip->controller->ops->setup_data_interface(chip, chipnr, - &chip->data_interface); + onfi_fill_interface_config(chip, &chip->interface_config, + NAND_SDR_IFACE, 0); + ret = ops->setup_interface(chip, chipnr, &chip->interface_config); if (ret) pr_err("Failed to configure data interface to SDR timing mode 0\n"); @@ -937,7 +938,7 @@ static int nand_reset_data_interface(struct nand_chip *chip, int chipnr) } /** - * nand_setup_data_interface - Setup the best data interface and timings + * nand_setup_interface - Setup the best data interface and timings * @chip: The NAND chip * @chipnr: Internal die id * @@ -946,13 +947,13 @@ static int nand_reset_data_interface(struct nand_chip *chip, int chipnr) * * Returns 0 for success or negative error code otherwise. */ -static int nand_setup_data_interface(struct nand_chip *chip, int chipnr) +static int nand_setup_interface(struct nand_chip *chip, int chipnr) { - u8 mode = chip->data_interface.timings.mode; + u8 mode = chip->interface_config.timings.mode; u8 tmode_param[ONFI_SUBFEATURE_PARAM_LEN] = { mode, }; int ret; - if (!nand_controller_can_setup_data_iface(chip)) + if (!nand_controller_can_setup_interface(chip)) return 0; /* Change the mode on the chip side (if supported by the NAND chip) */ @@ -966,8 +967,8 @@ static int nand_setup_data_interface(struct nand_chip *chip, int chipnr) } /* Change the mode on the controller side */ - ret = chip->controller->ops->setup_data_interface(chip, chipnr, - &chip->data_interface); + ret = chip->controller->ops->setup_interface(chip, chipnr, + &chip->interface_config); if (ret) return ret; @@ -996,7 +997,7 @@ err_reset_chip: * Fallback to mode 0 if the chip explicitly did not ack the chosen * timing mode. */ - nand_reset_data_interface(chip, chipnr); + nand_reset_interface(chip, chipnr); nand_select_target(chip, chipnr); nand_reset_op(chip); nand_deselect_target(chip); @@ -1005,7 +1006,7 @@ err_reset_chip: } /** - * nand_choose_data_interface - find the best data interface and timings + * nand_choose_interface_config - find the best data interface and timings * @chip: The NAND chip * * Find the best data interface and NAND timings supported by the chip @@ -1013,16 +1014,16 @@ err_reset_chip: * First tries to retrieve supported timing modes from ONFI information, * and if the NAND chip does not support ONFI, relies on the * ->onfi_timing_mode_default specified in the nand_ids table. After this - * function nand_chip->data_interface is initialized with the best timing mode + * function nand_chip->interface_ is initialized with the best timing mode * available. * * Returns 0 for success or negative error code otherwise. */ -static int nand_choose_data_interface(struct nand_chip *chip) +static int nand_choose_interface_config(struct nand_chip *chip) { int modes, mode, ret; - if (!nand_controller_can_setup_data_iface(chip)) + if (!nand_controller_can_setup_interface(chip)) return 0; /* @@ -1040,8 +1041,8 @@ static int nand_choose_data_interface(struct nand_chip *chip) } for (mode = fls(modes) - 1; mode >= 0; mode--) { - ret = onfi_fill_data_interface(chip, &chip->data_interface, - NAND_SDR_IFACE, mode); + ret = onfi_fill_interface_config(chip, &chip->interface_config, + NAND_SDR_IFACE, mode); if (ret) continue; @@ -1049,9 +1050,9 @@ static int nand_choose_data_interface(struct nand_chip *chip) * Pass NAND_DATA_IFACE_CHECK_ONLY to only check if the * controller supports the requested timings. */ - ret = chip->controller->ops->setup_data_interface(chip, + ret = chip->controller->ops->setup_interface(chip, NAND_DATA_IFACE_CHECK_ONLY, - &chip->data_interface); + &chip->interface_config); if (!ret) { chip->onfi_timing_mode_default = mode; break; @@ -2477,17 +2478,17 @@ EXPORT_SYMBOL_GPL(nand_subop_get_data_len); * @chipnr: Internal die id * * Save the timings data structure, then apply SDR timings mode 0 (see - * nand_reset_data_interface for details), do the reset operation, and - * apply back the previous timings. + * nand_reset_interface for details), do the reset operation, and apply + * back the previous timings. * * Returns 0 on success, a negative error code otherwise. */ int nand_reset(struct nand_chip *chip, int chipnr) { - struct nand_data_interface saved_data_intf = chip->data_interface; + struct nand_interface_config saved_intf_config = chip->interface_config; int ret; - ret = nand_reset_data_interface(chip, chipnr); + ret = nand_reset_interface(chip, chipnr); if (ret) return ret; @@ -2503,18 +2504,18 @@ int nand_reset(struct nand_chip *chip, int chipnr) return ret; /* - * A nand_reset_data_interface() put both the NAND chip and the NAND + * A nand_reset_interface() put both the NAND chip and the NAND * controller in timings mode 0. If the default mode for this chip is * also 0, no need to proceed to the change again. Plus, at probe time, - * nand_setup_data_interface() uses ->set/get_features() which would + * nand_setup_interface() uses ->set/get_features() which would * fail anyway as the parameter page is not available yet. */ - if (!memcmp(&chip->data_interface, &saved_data_intf, - sizeof(saved_data_intf))) + if (!memcmp(&chip->interface_config, &saved_intf_config, + sizeof(saved_intf_config))) return 0; - chip->data_interface = saved_data_intf; - ret = nand_setup_data_interface(chip, chipnr); + chip->interface_config = saved_intf_config; + ret = nand_setup_interface(chip, chipnr); if (ret) return ret; @@ -5183,7 +5184,7 @@ static int nand_scan_ident(struct nand_chip *chip, unsigned int maxchips, mutex_init(&chip->lock); /* Enforce the right timings for reset/detection */ - onfi_fill_data_interface(chip, &chip->data_interface, NAND_SDR_IFACE, 0); + onfi_fill_interface_config(chip, &chip->interface_config, NAND_SDR_IFACE, 0); ret = nand_dt_init(chip); if (ret) @@ -5971,13 +5972,13 @@ static int nand_scan_tail(struct nand_chip *chip) mtd->bitflip_threshold = DIV_ROUND_UP(mtd->ecc_strength * 3, 4); /* Find the fastest data interface for this chip */ - ret = nand_choose_data_interface(chip); + ret = nand_choose_interface_config(chip); if (ret) goto err_nanddev_cleanup; /* Enter fastest possible mode on all dies. */ for (i = 0; i < nanddev_ntargets(&chip->base); i++) { - ret = nand_setup_data_interface(chip, i); + ret = nand_setup_interface(chip, i); if (ret) goto err_nanddev_cleanup; } diff --git a/drivers/mtd/nand/raw/nand_legacy.c b/drivers/mtd/nand/raw/nand_legacy.c index fe769762e1d8..2bcc03714432 100644 --- a/drivers/mtd/nand/raw/nand_legacy.c +++ b/drivers/mtd/nand/raw/nand_legacy.c @@ -368,7 +368,7 @@ static void nand_ccs_delay(struct nand_chip *chip) * Wait tCCS_min if it is correctly defined, otherwise wait 500ns * (which should be safe for all NANDs). */ - if (nand_controller_can_setup_data_iface(chip)) + if (nand_controller_can_setup_interface(chip)) ndelay(sdr->tCCS_min / 1000); else ndelay(500); diff --git a/drivers/mtd/nand/raw/nand_timings.c b/drivers/mtd/nand/raw/nand_timings.c index efff3583c549..bf05b4bceaa0 100644 --- a/drivers/mtd/nand/raw/nand_timings.c +++ b/drivers/mtd/nand/raw/nand_timings.c @@ -19,7 +19,7 @@ * * These four values are tweaked to be more accurate in the case of ONFI chips. */ -static const struct nand_data_interface onfi_sdr_timings[] = { +static const struct nand_interface_config onfi_sdr_timings[] = { /* Mode 0 */ { .type = NAND_SDR_IFACE, @@ -340,16 +340,17 @@ onfi_find_closest_sdr_mode(const struct nand_sdr_timings *spec_timings) } /** - * onfi_fill_data_interface - Initialize a data interface from a given ONFI mode + * onfi_fill_interface_config - Initialize an interface config from a given + * ONFI mode * @chip: The NAND chip - * @iface: The data interface to fill - * @type: The data interface type + * @iface: The interface configuration to fill + * @type: The interface type * @timing_mode: The ONFI timing mode */ -int onfi_fill_data_interface(struct nand_chip *chip, - struct nand_data_interface *iface, - enum nand_data_interface_type type, - unsigned int timing_mode) +int onfi_fill_interface_config(struct nand_chip *chip, + struct nand_interface_config *iface, + enum nand_interface_type type, + unsigned int timing_mode) { struct onfi_params *onfi = chip->parameters.onfi; diff --git a/drivers/mtd/nand/raw/s3c2410.c b/drivers/mtd/nand/raw/s3c2410.c index f86dff311464..f121a3ae294c 100644 --- a/drivers/mtd/nand/raw/s3c2410.c +++ b/drivers/mtd/nand/raw/s3c2410.c @@ -808,8 +808,8 @@ static int s3c2410_nand_add_partition(struct s3c2410_nand_info *info, return -ENODEV; } -static int s3c2410_nand_setup_data_interface(struct nand_chip *chip, int csline, - const struct nand_data_interface *conf) +static int s3c2410_nand_setup_interface(struct nand_chip *chip, int csline, + const struct nand_interface_config *conf) { struct mtd_info *mtd = nand_to_mtd(chip); struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); @@ -999,7 +999,7 @@ static int s3c2410_nand_attach_chip(struct nand_chip *chip) static const struct nand_controller_ops s3c24xx_nand_controller_ops = { .attach_chip = s3c2410_nand_attach_chip, - .setup_data_interface = s3c2410_nand_setup_data_interface, + .setup_interface = s3c2410_nand_setup_interface, }; static const struct of_device_id s3c24xx_nand_dt_ids[] = { diff --git a/drivers/mtd/nand/raw/stm32_fmc2_nand.c b/drivers/mtd/nand/raw/stm32_fmc2_nand.c index 7320c0fc19ec..a4140af43ed4 100644 --- a/drivers/mtd/nand/raw/stm32_fmc2_nand.c +++ b/drivers/mtd/nand/raw/stm32_fmc2_nand.c @@ -1546,7 +1546,7 @@ static void stm32_fmc2_nfc_calc_timings(struct nand_chip *chip, } static int stm32_fmc2_nfc_setup_interface(struct nand_chip *chip, int chipnr, - const struct nand_data_interface *conf) + const struct nand_interface_config *conf) { const struct nand_sdr_timings *sdrt; @@ -1764,7 +1764,7 @@ static int stm32_fmc2_nfc_attach_chip(struct nand_chip *chip) static const struct nand_controller_ops stm32_fmc2_nfc_controller_ops = { .attach_chip = stm32_fmc2_nfc_attach_chip, .exec_op = stm32_fmc2_nfc_exec_op, - .setup_data_interface = stm32_fmc2_nfc_setup_interface, + .setup_interface = stm32_fmc2_nfc_setup_interface, }; static int stm32_fmc2_nfc_parse_child(struct stm32_fmc2_nfc *nfc, diff --git a/drivers/mtd/nand/raw/sunxi_nand.c b/drivers/mtd/nand/raw/sunxi_nand.c index ffbc1651fadc..9c50c2b965e1 100644 --- a/drivers/mtd/nand/raw/sunxi_nand.c +++ b/drivers/mtd/nand/raw/sunxi_nand.c @@ -1376,8 +1376,8 @@ static int _sunxi_nand_lookup_timing(const s32 *lut, int lut_size, u32 duration, #define sunxi_nand_lookup_timing(l, p, c) \ _sunxi_nand_lookup_timing(l, ARRAY_SIZE(l), p, c) -static int sunxi_nfc_setup_data_interface(struct nand_chip *nand, int csline, - const struct nand_data_interface *conf) +static int sunxi_nfc_setup_interface(struct nand_chip *nand, int csline, + const struct nand_interface_config *conf) { struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand); struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller); @@ -1920,7 +1920,7 @@ static int sunxi_nfc_exec_op(struct nand_chip *nand, static const struct nand_controller_ops sunxi_nand_controller_ops = { .attach_chip = sunxi_nand_attach_chip, - .setup_data_interface = sunxi_nfc_setup_data_interface, + .setup_interface = sunxi_nfc_setup_interface, .exec_op = sunxi_nfc_exec_op, }; diff --git a/drivers/mtd/nand/raw/tango_nand.c b/drivers/mtd/nand/raw/tango_nand.c index 648dc7e77f6a..bdb965ae7a4a 100644 --- a/drivers/mtd/nand/raw/tango_nand.c +++ b/drivers/mtd/nand/raw/tango_nand.c @@ -515,7 +515,7 @@ static u32 to_ticks(int kHz, int ps) } static int tango_set_timings(struct nand_chip *chip, int csline, - const struct nand_data_interface *conf) + const struct nand_interface_config *conf) { const struct nand_sdr_timings *sdr = nand_get_sdr_timings(conf); struct tango_nfc *nfc = to_tango_nfc(chip->controller); @@ -565,7 +565,7 @@ static int tango_attach_chip(struct nand_chip *chip) static const struct nand_controller_ops tango_controller_ops = { .attach_chip = tango_attach_chip, - .setup_data_interface = tango_set_timings, + .setup_interface = tango_set_timings, .exec_op = tango_exec_op, }; diff --git a/drivers/mtd/nand/raw/tegra_nand.c b/drivers/mtd/nand/raw/tegra_nand.c index f9d046b2cd3b..6b6212ffa01c 100644 --- a/drivers/mtd/nand/raw/tegra_nand.c +++ b/drivers/mtd/nand/raw/tegra_nand.c @@ -813,8 +813,8 @@ static void tegra_nand_setup_timing(struct tegra_nand_controller *ctrl, writel_relaxed(reg, ctrl->regs + TIMING_2); } -static int tegra_nand_setup_data_interface(struct nand_chip *chip, int csline, - const struct nand_data_interface *conf) +static int tegra_nand_setup_interface(struct nand_chip *chip, int csline, + const struct nand_interface_config *conf) { struct tegra_nand_controller *ctrl = to_tegra_ctrl(chip->controller); const struct nand_sdr_timings *timings; @@ -1053,7 +1053,7 @@ static int tegra_nand_attach_chip(struct nand_chip *chip) static const struct nand_controller_ops tegra_nand_controller_ops = { .attach_chip = &tegra_nand_attach_chip, .exec_op = tegra_nand_exec_op, - .setup_data_interface = tegra_nand_setup_data_interface, + .setup_interface = tegra_nand_setup_interface, }; static int tegra_nand_chips_init(struct device *dev, diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h index 0852df941130..2ca56eef0f07 100644 --- a/include/linux/mtd/rawnand.h +++ b/include/linux/mtd/rawnand.h @@ -492,22 +492,22 @@ struct nand_sdr_timings { }; /** - * enum nand_data_interface_type - NAND interface timing type + * enum nand_interface_type - NAND interface type * @NAND_SDR_IFACE: Single Data Rate interface */ -enum nand_data_interface_type { +enum nand_interface_type { NAND_SDR_IFACE, }; /** - * struct nand_data_interface - NAND interface timing + * struct nand_interface_config - NAND interface timing * @type: type of the timing * @timings: The timing information * @timings.mode: Timing mode as defined in the specification * @timings.sdr: Use it when @type is %NAND_SDR_IFACE. */ -struct nand_data_interface { - enum nand_data_interface_type type; +struct nand_interface_config { + enum nand_interface_type type; struct nand_timings { unsigned int mode; union { @@ -521,7 +521,7 @@ struct nand_data_interface { * @conf: The data interface */ static inline const struct nand_sdr_timings * -nand_get_sdr_timings(const struct nand_data_interface *conf) +nand_get_sdr_timings(const struct nand_interface_config *conf) { if (conf->type != NAND_SDR_IFACE) return ERR_PTR(-EINVAL); @@ -944,11 +944,10 @@ static inline void nand_op_trace(const char *prefix, * This method replaces chip->legacy.cmdfunc(), * chip->legacy.{read,write}_{buf,byte,word}(), * chip->legacy.dev_ready() and chip->legacy.waifunc(). - * @setup_data_interface: setup the data interface and timing. If - * chipnr is set to %NAND_DATA_IFACE_CHECK_ONLY this - * means the configuration should not be applied but - * only checked. - * This hook is optional. + * @setup_interface: setup the data interface and timing. If chipnr is set to + * %NAND_DATA_IFACE_CHECK_ONLY this means the configuration + * should not be applied but only checked. + * This hook is optional. */ struct nand_controller_ops { int (*attach_chip)(struct nand_chip *chip); @@ -956,8 +955,8 @@ struct nand_controller_ops { int (*exec_op)(struct nand_chip *chip, const struct nand_operation *op, bool check_only); - int (*setup_data_interface)(struct nand_chip *chip, int chipnr, - const struct nand_data_interface *conf); + int (*setup_interface)(struct nand_chip *chip, int chipnr, + const struct nand_interface_config *conf); }; /** @@ -1070,7 +1069,7 @@ struct nand_manufacturer { * @onfi_timing_mode_default: 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 otherwise - * @data_interface: NAND interface timing information + * @interface_config: NAND interface timing information * @bbt_erase_shift: Number of address bits in a bbt entry * @bbt_options: Bad block table specific options. All options used here must * come from bbm.h. By default, these options will be copied to @@ -1118,7 +1117,7 @@ struct nand_chip { /* Data interface */ int onfi_timing_mode_default; - struct nand_data_interface data_interface; + struct nand_interface_config interface_config; /* Bad block information */ unsigned int bbt_erase_shift; @@ -1208,10 +1207,10 @@ static inline struct device_node *nand_get_flash_node(struct nand_chip *chip) * of a NAND chip * @chip: The NAND chip */ -static inline const struct nand_data_interface * +static inline const struct nand_interface_config * nand_get_interface_config(struct nand_chip *chip) { - return &chip->data_interface; + return &chip->interface_config; } /* -- cgit v1.2.3 From 42a9ad050e6f1f6e909e2117e7a99f54f5336939 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Fri, 29 May 2020 13:13:14 +0200 Subject: mtd: rawnand: timings: Make onfi_fill_interface_config() a void helper Warn the user if the parameters are wrong but basically it would mean there is a serious issue in the NAND core. So no need to ever check its output, let's make this helper return void. Signed-off-by: Miquel Raynal Reviewed-by: Boris Brezillon Link: https://lore.kernel.org/linux-mtd/20200529111322.7184-21-miquel.raynal@bootlin.com --- drivers/mtd/nand/raw/internals.h | 8 ++++---- drivers/mtd/nand/raw/nand_base.c | 6 ++---- drivers/mtd/nand/raw/nand_timings.c | 18 ++++++++---------- 3 files changed, 14 insertions(+), 18 deletions(-) diff --git a/drivers/mtd/nand/raw/internals.h b/drivers/mtd/nand/raw/internals.h index 114c63a6a349..63c5af436901 100644 --- a/drivers/mtd/nand/raw/internals.h +++ b/drivers/mtd/nand/raw/internals.h @@ -84,10 +84,10 @@ 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); -int onfi_fill_interface_config(struct nand_chip *chip, - struct nand_interface_config *iface, - enum nand_interface_type type, - unsigned int timing_mode); +void onfi_fill_interface_config(struct nand_chip *chip, + struct nand_interface_config *iface, + enum nand_interface_type type, + unsigned int timing_mode); unsigned int onfi_find_closest_sdr_mode(const struct nand_sdr_timings *spec_timings); int nand_get_features(struct nand_chip *chip, int addr, u8 *subfeature_param); diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c index 4fa18fb68d62..3bfd71d589cf 100644 --- a/drivers/mtd/nand/raw/nand_base.c +++ b/drivers/mtd/nand/raw/nand_base.c @@ -1041,10 +1041,8 @@ static int nand_choose_interface_config(struct nand_chip *chip) } for (mode = fls(modes) - 1; mode >= 0; mode--) { - ret = onfi_fill_interface_config(chip, &chip->interface_config, - NAND_SDR_IFACE, mode); - if (ret) - continue; + onfi_fill_interface_config(chip, &chip->interface_config, + NAND_SDR_IFACE, mode); /* * Pass NAND_DATA_IFACE_CHECK_ONLY to only check if the diff --git a/drivers/mtd/nand/raw/nand_timings.c b/drivers/mtd/nand/raw/nand_timings.c index bf05b4bceaa0..1e22006c79ba 100644 --- a/drivers/mtd/nand/raw/nand_timings.c +++ b/drivers/mtd/nand/raw/nand_timings.c @@ -347,18 +347,18 @@ onfi_find_closest_sdr_mode(const struct nand_sdr_timings *spec_timings) * @type: The interface type * @timing_mode: The ONFI timing mode */ -int onfi_fill_interface_config(struct nand_chip *chip, - struct nand_interface_config *iface, - enum nand_interface_type type, - unsigned int timing_mode) +void onfi_fill_interface_config(struct nand_chip *chip, + struct nand_interface_config *iface, + enum nand_interface_type type, + unsigned int timing_mode) { struct onfi_params *onfi = chip->parameters.onfi; - if (type != NAND_SDR_IFACE) - return -EINVAL; + if (WARN_ON(type != NAND_SDR_IFACE)) + return; - if (timing_mode >= ARRAY_SIZE(onfi_sdr_timings)) - return -EINVAL; + if (WARN_ON(timing_mode >= ARRAY_SIZE(onfi_sdr_timings))) + return; *iface = onfi_sdr_timings[timing_mode]; @@ -378,6 +378,4 @@ int onfi_fill_interface_config(struct nand_chip *chip, /* nanoseconds -> picoseconds */ timings->tCCS_min = 1000UL * onfi->tCCS; } - - return 0; } -- cgit v1.2.3 From b5b39f640c1f5621ed4ff6418e74ee35ff5d988e Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Fri, 29 May 2020 13:13:15 +0200 Subject: mtd: rawnand: Introduce nand_choose_best_sdr_timings() Extract the logic out of nand_choose_interface_config() to create a public helper that can be reused by manufacturer drivers. Add the possibility to provide a specific set of timings. Signed-off-by: Miquel Raynal Reviewed-by: Boris Brezillon Link: https://lore.kernel.org/linux-mtd/20200529111322.7184-22-miquel.raynal@bootlin.com --- drivers/mtd/nand/raw/internals.h | 3 ++ drivers/mtd/nand/raw/nand_base.c | 94 +++++++++++++++++++++++++--------------- 2 files changed, 61 insertions(+), 36 deletions(-) diff --git a/drivers/mtd/nand/raw/internals.h b/drivers/mtd/nand/raw/internals.h index 63c5af436901..5ebfbb89e572 100644 --- a/drivers/mtd/nand/raw/internals.h +++ b/drivers/mtd/nand/raw/internals.h @@ -90,6 +90,9 @@ void onfi_fill_interface_config(struct nand_chip *chip, unsigned int timing_mode); unsigned int onfi_find_closest_sdr_mode(const struct nand_sdr_timings *spec_timings); +int nand_choose_best_sdr_timings(struct nand_chip *chip, + struct nand_interface_config *iface, + struct nand_sdr_timings *spec_timings); int nand_get_features(struct nand_chip *chip, int addr, u8 *subfeature_param); int nand_set_features(struct nand_chip *chip, int addr, u8 *subfeature_param); int nand_read_page_raw_notsupp(struct nand_chip *chip, u8 *buf, diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c index 3bfd71d589cf..742d099df5c6 100644 --- a/drivers/mtd/nand/raw/nand_base.c +++ b/drivers/mtd/nand/raw/nand_base.c @@ -1005,6 +1005,62 @@ err_reset_chip: return ret; } +/** + * nand_choose_best_sdr_timings - Pick up the best SDR timings that both the + * NAND controller and the NAND chip support + * @chip: the NAND chip + * @iface: the interface configuration (can eventually be updated) + * @spec_timings: specific timings, when not fitting the ONFI specification + * + * If specific timings are provided, use them. Otherwise, try to retrieve + * supported timing modes from ONFI information. Finally, if the NAND chip does + * not follow the ONFI specification, rely on the ->default_timing_mode + * specified in the nand_ids table. + */ +int nand_choose_best_sdr_timings(struct nand_chip *chip, + struct nand_interface_config *iface, + struct nand_sdr_timings *spec_timings) +{ + const struct nand_controller_ops *ops = chip->controller->ops; + int best_mode = 0, mode, ret; + + iface->type = NAND_SDR_IFACE; + + if (spec_timings) { + iface->timings.sdr = *spec_timings; + iface->timings.mode = onfi_find_closest_sdr_mode(spec_timings); + + /* Verify the controller supports the requested interface */ + ret = ops->setup_interface(chip, NAND_DATA_IFACE_CHECK_ONLY, + iface); + if (!ret) + return ret; + + /* Fallback to slower modes */ + best_mode = iface->timings.mode; + } else { + if (chip->parameters.onfi) { + unsigned int onfi_modes; + + onfi_modes = chip->parameters.onfi->async_timing_mode; + best_mode = fls(onfi_modes) - 1; + } else { + best_mode = chip->onfi_timing_mode_default; + } + } + + for (mode = best_mode; mode >= 0; mode--) { + onfi_fill_interface_config(chip, iface, NAND_SDR_IFACE, mode); + + ret = ops->setup_interface(chip, NAND_DATA_IFACE_CHECK_ONLY, + iface); + if (!ret) + return 0; + } + + return 0; +} + /** * nand_choose_interface_config - find the best data interface and timings * @chip: The NAND chip @@ -1016,48 +1072,14 @@ err_reset_chip: * ->onfi_timing_mode_default specified in the nand_ids table. After this * function nand_chip->interface_ is initialized with the best timing mode * available. - * - * Returns 0 for success or negative error code otherwise. */ static int nand_choose_interface_config(struct nand_chip *chip) { - int modes, mode, ret; - if (!nand_controller_can_setup_interface(chip)) return 0; - /* - * First try to identify the best timings from ONFI parameters and - * if the NAND does not support ONFI, fallback to the default ONFI - * timing mode. - */ - if (chip->parameters.onfi) { - modes = chip->parameters.onfi->async_timing_mode; - } else { - if (!chip->onfi_timing_mode_default) - return 0; - - modes = GENMASK(chip->onfi_timing_mode_default, 0); - } - - for (mode = fls(modes) - 1; mode >= 0; mode--) { - onfi_fill_interface_config(chip, &chip->interface_config, - NAND_SDR_IFACE, mode); - - /* - * Pass NAND_DATA_IFACE_CHECK_ONLY to only check if the - * controller supports the requested timings. - */ - ret = chip->controller->ops->setup_interface(chip, - NAND_DATA_IFACE_CHECK_ONLY, - &chip->interface_config); - if (!ret) { - chip->onfi_timing_mode_default = mode; - break; - } - } - - return 0; + return nand_choose_best_sdr_timings(chip, &chip->interface_config, + NULL); } /** -- cgit v1.2.3 From 26d014f0400e5ff54cc80c8329e3adbd74db1e04 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Fri, 29 May 2020 13:13:16 +0200 Subject: mtd: rawnand: Add the ->choose_interface_config() hook This hook can be overloaded by NAND manufacturer drivers to propose alternative timings when not following the main standards. In this case, the manufacturer drivers is responsible for choosing the best interface configuration that fits both the controller and chip capabilities. Signed-off-by: Miquel Raynal Reviewed-by: Boris Brezillon Link: https://lore.kernel.org/linux-mtd/20200529111322.7184-23-miquel.raynal@bootlin.com --- drivers/mtd/nand/raw/nand_base.c | 17 +++++++++++------ include/linux/mtd/rawnand.h | 3 +++ 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c index 742d099df5c6..2f4eba1a1082 100644 --- a/drivers/mtd/nand/raw/nand_base.c +++ b/drivers/mtd/nand/raw/nand_base.c @@ -1066,18 +1066,23 @@ int nand_choose_best_sdr_timings(struct nand_chip *chip, * @chip: The NAND chip * * Find the best data interface and NAND timings supported by the chip - * and the driver. - * First tries to retrieve supported timing modes from ONFI information, - * and if the NAND chip does not support ONFI, relies on the - * ->onfi_timing_mode_default specified in the nand_ids table. After this - * function nand_chip->interface_ is initialized with the best timing mode - * available. + * and the driver. Eventually let the NAND manufacturer driver propose his own + * set of timings. + * + * After this function nand_chip->interface_config is initialized with the best + * timing mode available. + * + * Returns 0 for success or negative error code otherwise. */ static int nand_choose_interface_config(struct nand_chip *chip) { if (!nand_controller_can_setup_interface(chip)) return 0; + if (chip->ops.choose_interface_config) + return chip->ops.choose_interface_config(chip, + &chip->interface_config); + return nand_choose_best_sdr_timings(chip, &chip->interface_config, NULL); } diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h index 2ca56eef0f07..316a02189da1 100644 --- a/include/linux/mtd/rawnand.h +++ b/include/linux/mtd/rawnand.h @@ -1033,6 +1033,7 @@ struct nand_legacy { * @lock_area: Lock operation * @unlock_area: Unlock operation * @setup_read_retry: Set the read-retry mode (mostly needed for MLC NANDs) + * @choose_interface_config: Choose the best interface configuration */ struct nand_chip_ops { int (*suspend)(struct nand_chip *chip); @@ -1040,6 +1041,8 @@ struct nand_chip_ops { int (*lock_area)(struct nand_chip *chip, loff_t ofs, uint64_t len); int (*unlock_area)(struct nand_chip *chip, loff_t ofs, uint64_t len); int (*setup_read_retry)(struct nand_chip *chip, int retry_mode); + int (*choose_interface_config)(struct nand_chip *chip, + struct nand_interface_config *iface); }; /** -- cgit v1.2.3 From 2f36bae11234b5a9ca018bc44fff0e847cacc33c Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Fri, 29 May 2020 13:13:17 +0200 Subject: mtd: rawnand: toshiba: Implement ->choose_interface_config() for TC58TEG5DCLTA00 Implement this hook for the tc58teg5dclta00 NAND chip and stop setting ->default_timing_mode. Signed-off-by: Miquel Raynal Reviewed-by: Boris Brezillon Link: https://lore.kernel.org/linux-mtd/20200529111322.7184-24-miquel.raynal@bootlin.com --- drivers/mtd/nand/raw/nand_toshiba.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/nand/raw/nand_toshiba.c b/drivers/mtd/nand/raw/nand_toshiba.c index 333037bdca41..d23bb4322062 100644 --- a/drivers/mtd/nand/raw/nand_toshiba.c +++ b/drivers/mtd/nand/raw/nand_toshiba.c @@ -194,11 +194,21 @@ static void toshiba_nand_decode_id(struct nand_chip *chip) } } +static int +tc58teg5dclta00_choose_interface_config(struct nand_chip *chip, + struct nand_interface_config *iface) +{ + onfi_fill_interface_config(chip, iface, NAND_SDR_IFACE, 5); + + return nand_choose_best_sdr_timings(chip, iface, NULL); +} + static int tc58teg5dclta00_init(struct nand_chip *chip) { struct mtd_info *mtd = nand_to_mtd(chip); - chip->onfi_timing_mode_default = 5; + chip->ops.choose_interface_config = + &tc58teg5dclta00_choose_interface_config; chip->options |= NAND_NEED_SCRAMBLING; mtd_set_pairing_scheme(mtd, &dist3_pairing_scheme); -- cgit v1.2.3 From 0d0245b99552aa8c5c67d34ab7b4f0fd4d174444 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Fri, 29 May 2020 13:13:18 +0200 Subject: mtd: rawnand: toshiba: Implement ->choose_interface_config() for TC58NVG0S3E This chip supports ONFI SDR timing mode 2, implement the new hook to advertize it. Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20200529111322.7184-25-miquel.raynal@bootlin.com --- drivers/mtd/nand/raw/nand_ids.c | 3 +-- drivers/mtd/nand/raw/nand_toshiba.c | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/nand/raw/nand_ids.c b/drivers/mtd/nand/raw/nand_ids.c index e0dbc2e316c7..c729a8bc895d 100644 --- a/drivers/mtd/nand/raw/nand_ids.c +++ b/drivers/mtd/nand/raw/nand_ids.c @@ -28,8 +28,7 @@ struct nand_flash_dev nand_flash_ids[] = { */ {"TC58NVG0S3E 1G 3.3V 8-bit", { .id = {0x98, 0xd1, 0x90, 0x15, 0x76, 0x14, 0x01, 0x00} }, - SZ_2K, SZ_128, SZ_128K, 0, 8, 64, NAND_ECC_INFO(1, SZ_512), - 2 }, + SZ_2K, SZ_128, SZ_128K, 0, 8, 64, NAND_ECC_INFO(1, SZ_512), }, {"TC58NVG2S0F 4G 3.3V 8-bit", { .id = {0x98, 0xdc, 0x90, 0x26, 0x76, 0x15, 0x01, 0x08} }, SZ_4K, SZ_512, SZ_256K, 0, 8, 224, NAND_ECC_INFO(4, SZ_512) }, diff --git a/drivers/mtd/nand/raw/nand_toshiba.c b/drivers/mtd/nand/raw/nand_toshiba.c index d23bb4322062..6d53f9b7a817 100644 --- a/drivers/mtd/nand/raw/nand_toshiba.c +++ b/drivers/mtd/nand/raw/nand_toshiba.c @@ -203,6 +203,15 @@ tc58teg5dclta00_choose_interface_config(struct nand_chip *chip, return nand_choose_best_sdr_timings(chip, iface, NULL); } +static int +tc58nvg0s3e_choose_interface_config(struct nand_chip *chip, + struct nand_interface_config *iface) +{ + onfi_fill_interface_config(chip, iface, NAND_SDR_IFACE, 2); + + return nand_choose_best_sdr_timings(chip, iface, NULL); +} + static int tc58teg5dclta00_init(struct nand_chip *chip) { struct mtd_info *mtd = nand_to_mtd(chip); @@ -215,6 +224,14 @@ static int tc58teg5dclta00_init(struct nand_chip *chip) return 0; } +static int tc58nvg0s3e_init(struct nand_chip *chip) +{ + chip->ops.choose_interface_config = + &tc58nvg0s3e_choose_interface_config; + + return 0; +} + static int toshiba_nand_init(struct nand_chip *chip) { if (nand_is_slc(chip)) @@ -227,6 +244,9 @@ static int toshiba_nand_init(struct nand_chip *chip) if (!strcmp("TC58TEG5DCLTA00", chip->parameters.model)) tc58teg5dclta00_init(chip); + if (!strncmp("TC58NVG0S3E", chip->parameters.model, + sizeof("TC58NVG0S3E") - 1)) + tc58nvg0s3e_init(chip); return 0; } -- cgit v1.2.3 From 246a06ff13277349a09ea4dd46f516185e13d01d Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Fri, 29 May 2020 13:13:19 +0200 Subject: mtd: rawnand: hynix: Implement ->choose_interface_config() for H27UCG8T2ATR-BC This chip supports ONFI SDR timing mode 4, implement the new hook to advertize it. Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20200529111322.7184-26-miquel.raynal@bootlin.com --- drivers/mtd/nand/raw/nand_hynix.c | 14 ++++++++++++++ drivers/mtd/nand/raw/nand_ids.c | 2 +- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/nand/raw/nand_hynix.c b/drivers/mtd/nand/raw/nand_hynix.c index 7d1be53f27f3..6d08eb834456 100644 --- a/drivers/mtd/nand/raw/nand_hynix.c +++ b/drivers/mtd/nand/raw/nand_hynix.c @@ -673,6 +673,15 @@ static void hynix_nand_cleanup(struct nand_chip *chip) nand_set_manufacturer_data(chip, NULL); } +static int +h27ucg8t2atrbc_choose_interface_config(struct nand_chip *chip, + struct nand_interface_config *iface) +{ + onfi_fill_interface_config(chip, iface, NAND_SDR_IFACE, 4); + + return nand_choose_best_sdr_timings(chip, iface, NULL); +} + static int hynix_nand_init(struct nand_chip *chip) { struct hynix_nand *hynix; @@ -689,6 +698,11 @@ static int hynix_nand_init(struct nand_chip *chip) nand_set_manufacturer_data(chip, hynix); + if (!strncmp("H27UCG8T2ATR-BC", chip->parameters.model, + sizeof("H27UCG8T2ATR-BC") - 1)) + chip->ops.choose_interface_config = + h27ucg8t2atrbc_choose_interface_config; + ret = hynix_nand_rr_init(chip); if (ret) hynix_nand_cleanup(chip); diff --git a/drivers/mtd/nand/raw/nand_ids.c b/drivers/mtd/nand/raw/nand_ids.c index c729a8bc895d..3b890d55703d 100644 --- a/drivers/mtd/nand/raw/nand_ids.c +++ b/drivers/mtd/nand/raw/nand_ids.c @@ -50,7 +50,7 @@ struct nand_flash_dev nand_flash_ids[] = { {"H27UCG8T2ATR-BC 64G 3.3V 8-bit", { .id = {0xad, 0xde, 0x94, 0xda, 0x74, 0xc4} }, SZ_8K, SZ_8K, SZ_2M, NAND_NEED_SCRAMBLING, 6, 640, - NAND_ECC_INFO(40, SZ_1K), 4 }, + NAND_ECC_INFO(40, SZ_1K) }, LEGACY_ID_NAND("NAND 4MiB 5V 8-bit", 0x6B, 4, SZ_8K, SP_OPTIONS), LEGACY_ID_NAND("NAND 4MiB 3,3V 8-bit", 0xE3, 4, SZ_8K, SP_OPTIONS), -- cgit v1.2.3 From 6d469f863772946e9ebd26068f7c9a609ab128d3 Mon Sep 17 00:00:00 2001 From: Rickard x Andersson Date: Fri, 29 May 2020 13:13:20 +0200 Subject: mtd: rawnand: toshiba: Choose the interface configuration for TH58NVG2S3HBAI4 The Kioxia/Toshiba TH58NVG2S3HBAI4 NAND memory is not ONFI compliant. The timings of the NAND chip memory are quite close to ONFI mode 4 but is breaking that spec. By providing our own set of timings, erase block read speed is increased from 6910 kiB/s to 13490 kiB/s and erase block write speed is increased from 3350 kiB/s to 4410 kiB/s. Tested on IMX6SX which has a NAND controller supporting EDO mode. Signed-off-by: Rickard x Andersson Signed-off-by: Miquel Raynal Reviewed-by: Boris Brezillon Link: https://lore.kernel.org/linux-mtd/20200529111322.7184-27-miquel.raynal@bootlin.com --- drivers/mtd/nand/raw/nand_ids.c | 3 +++ drivers/mtd/nand/raw/nand_toshiba.c | 38 +++++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/drivers/mtd/nand/raw/nand_ids.c b/drivers/mtd/nand/raw/nand_ids.c index 3b890d55703d..b9945791a9d7 100644 --- a/drivers/mtd/nand/raw/nand_ids.c +++ b/drivers/mtd/nand/raw/nand_ids.c @@ -51,6 +51,9 @@ struct nand_flash_dev nand_flash_ids[] = { { .id = {0xad, 0xde, 0x94, 0xda, 0x74, 0xc4} }, SZ_8K, SZ_8K, SZ_2M, NAND_NEED_SCRAMBLING, 6, 640, NAND_ECC_INFO(40, SZ_1K) }, + {"TH58NVG2S3HBAI4 4G 3.3V 8-bit", + { .id = {0x98, 0xdc, 0x91, 0x15, 0x76} }, + SZ_2K, SZ_512, SZ_128K, 0, 5, 128, NAND_ECC_INFO(8, SZ_512) }, LEGACY_ID_NAND("NAND 4MiB 5V 8-bit", 0x6B, 4, SZ_8K, SP_OPTIONS), LEGACY_ID_NAND("NAND 4MiB 3,3V 8-bit", 0xE3, 4, SZ_8K, SP_OPTIONS), diff --git a/drivers/mtd/nand/raw/nand_toshiba.c b/drivers/mtd/nand/raw/nand_toshiba.c index 6d53f9b7a817..f746c19f3b2c 100644 --- a/drivers/mtd/nand/raw/nand_toshiba.c +++ b/drivers/mtd/nand/raw/nand_toshiba.c @@ -212,6 +212,33 @@ tc58nvg0s3e_choose_interface_config(struct nand_chip *chip, return nand_choose_best_sdr_timings(chip, iface, NULL); } +static int +th58nvg2s3hbai4_choose_interface_config(struct nand_chip *chip, + struct nand_interface_config *iface) +{ + struct nand_sdr_timings *sdr = &iface->timings.sdr; + + /* Start with timings from the closest timing mode, mode 4. */ + onfi_fill_interface_config(chip, iface, NAND_SDR_IFACE, 4); + + /* Patch timings that differ from mode 4. */ + sdr->tALS_min = 12000; + sdr->tCHZ_max = 20000; + sdr->tCLS_min = 12000; + sdr->tCOH_min = 0; + sdr->tDS_min = 12000; + sdr->tRHOH_min = 25000; + sdr->tRHW_min = 30000; + sdr->tRHZ_max = 60000; + sdr->tWHR_min = 60000; + + /* Patch timings not part of onfi timing mode. */ + sdr->tPROG_max = 700000000; + sdr->tBERS_max = 5000000000; + + return nand_choose_best_sdr_timings(chip, iface, sdr); +} + static int tc58teg5dclta00_init(struct nand_chip *chip) { struct mtd_info *mtd = nand_to_mtd(chip); @@ -232,6 +259,14 @@ static int tc58nvg0s3e_init(struct nand_chip *chip) return 0; } +static int th58nvg2s3hbai4_init(struct nand_chip *chip) +{ + chip->ops.choose_interface_config = + &th58nvg2s3hbai4_choose_interface_config; + + return 0; +} + static int toshiba_nand_init(struct nand_chip *chip) { if (nand_is_slc(chip)) @@ -247,6 +282,9 @@ static int toshiba_nand_init(struct nand_chip *chip) if (!strncmp("TC58NVG0S3E", chip->parameters.model, sizeof("TC58NVG0S3E") - 1)) tc58nvg0s3e_init(chip); + if (!strncmp("TH58NVG2S3HBAI4", chip->parameters.model, + sizeof("TH58NVG2S3HBAI4") - 1)) + th58nvg2s3hbai4_init(chip); return 0; } -- cgit v1.2.3 From a69ad11168dca68b3f0adc6882422f4a2e2cb050 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Fri, 29 May 2020 13:13:21 +0200 Subject: mtd: rawnand: Get rid of the default ONFI timing mode The ->choose_interface() hook is here for manufacturer drivers to provide a better timing interface than the default one, this field is not needed anymore. Signed-off-by: Miquel Raynal Reviewed-by: Boris Brezillon Link: https://lore.kernel.org/linux-mtd/20200529111322.7184-28-miquel.raynal@bootlin.com --- drivers/mtd/nand/raw/nand_base.c | 19 ++++--------------- include/linux/mtd/rawnand.h | 9 --------- 2 files changed, 4 insertions(+), 24 deletions(-) diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c index 2f4eba1a1082..753328f106c1 100644 --- a/drivers/mtd/nand/raw/nand_base.c +++ b/drivers/mtd/nand/raw/nand_base.c @@ -1012,10 +1012,8 @@ err_reset_chip: * @iface: the interface configuration (can eventually be updated) * @spec_timings: specific timings, when not fitting the ONFI specification * - * If specific timings are provided, use them. Otherwise, try to retrieve - * supported timing modes from ONFI information. Finally, if the NAND chip does - * not follow the ONFI specification, rely on the ->default_timing_mode - * specified in the nand_ids table. + * If specific timings are provided, use them. Otherwise, retrieve supported + * timing modes from ONFI information. */ int nand_choose_best_sdr_timings(struct nand_chip *chip, struct nand_interface_config *iface, @@ -1038,15 +1036,8 @@ int nand_choose_best_sdr_timings(struct nand_chip *chip, /* Fallback to slower modes */ best_mode = iface->timings.mode; - } else { - if (chip->parameters.onfi) { - unsigned int onfi_modes; - - onfi_modes = chip->parameters.onfi->async_timing_mode; - best_mode = fls(onfi_modes) - 1; - } else { - best_mode = chip->onfi_timing_mode_default; - } + } else if (chip->parameters.onfi) { + best_mode = fls(chip->parameters.onfi->async_timing_mode) - 1; } for (mode = best_mode; mode >= 0; mode--) { @@ -4767,8 +4758,6 @@ static bool find_full_id_nand(struct nand_chip *chip, chip->options |= type->options; 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; chip->parameters.model = kstrdup(type->name, GFP_KERNEL); if (!chip->parameters.model) diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h index 316a02189da1..a2427c67d38b 100644 --- a/include/linux/mtd/rawnand.h +++ b/include/linux/mtd/rawnand.h @@ -1069,9 +1069,6 @@ struct nand_manufacturer { * @options: Various chip options. They can partly be set to inform nand_scan * about special functionality. See the defines for further * explanation. - * @onfi_timing_mode_default: 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 otherwise * @interface_config: NAND interface timing information * @bbt_erase_shift: Number of address bits in a bbt entry * @bbt_options: Bad block table specific options. All options used here must @@ -1119,7 +1116,6 @@ struct nand_chip { unsigned int options; /* Data interface */ - int onfi_timing_mode_default; struct nand_interface_config interface_config; /* Bad block information */ @@ -1268,10 +1264,6 @@ nand_get_interface_config(struct nand_chip *chip) * @ecc_step_ds in nand_chip{}, also from the datasheet. * For example, the "4bit ECC for each 512Byte" can be set with * NAND_ECC_INFO(4, 512). - * @onfi_timing_mode_default: the default ONFI timing mode entered after a NAND - * reset. Should be deduced from timings described - * in the datasheet. - * */ struct nand_flash_dev { char *name; @@ -1292,7 +1284,6 @@ struct nand_flash_dev { uint16_t strength_ds; uint16_t step_ds; } ecc; - int onfi_timing_mode_default; }; int nand_create_bbt(struct nand_chip *chip); -- cgit v1.2.3 From 35b6bcc970f759d4a86d6221d09ca28ea20467c8 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Fri, 29 May 2020 13:13:22 +0200 Subject: mtd: rawnand: Allocate the interface configurations dynamically Instead of manipulating the statically allocated structure and copy timings around, allocate one at identification time and save it in the nand_chip structure once it has been initialized. All NAND chips using the same interface configuration during reset and startup, we define a helper to retrieve a single reset interface configuration object, shared across all NAND chips. We use a second pointer to always have a reference on the currently applied interface configuration, which may either point to the "best interface configuration" or to the "default reset interface configuration". Signed-off-by: Miquel Raynal Reviewed-by: Boris Brezillon Link: https://lore.kernel.org/linux-mtd/20200529111322.7184-29-miquel.raynal@bootlin.com --- drivers/mtd/nand/raw/internals.h | 1 + drivers/mtd/nand/raw/nand_base.c | 84 +++++++++++++++++++++++-------------- drivers/mtd/nand/raw/nand_timings.c | 6 +++ include/linux/mtd/rawnand.h | 11 +++-- 4 files changed, 67 insertions(+), 35 deletions(-) diff --git a/drivers/mtd/nand/raw/internals.h b/drivers/mtd/nand/raw/internals.h index 5ebfbb89e572..012876e14317 100644 --- a/drivers/mtd/nand/raw/internals.h +++ b/drivers/mtd/nand/raw/internals.h @@ -93,6 +93,7 @@ onfi_find_closest_sdr_mode(const struct nand_sdr_timings *spec_timings); int nand_choose_best_sdr_timings(struct nand_chip *chip, struct nand_interface_config *iface, struct nand_sdr_timings *spec_timings); +const struct nand_interface_config *nand_get_reset_interface_config(void); int nand_get_features(struct nand_chip *chip, int addr, u8 *subfeature_param); int nand_set_features(struct nand_chip *chip, int addr, u8 *subfeature_param); int nand_read_page_raw_notsupp(struct nand_chip *chip, u8 *buf, diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c index 753328f106c1..0c768cb88f96 100644 --- a/drivers/mtd/nand/raw/nand_base.c +++ b/drivers/mtd/nand/raw/nand_base.c @@ -928,9 +928,9 @@ static int nand_reset_interface(struct nand_chip *chip, int chipnr) * timings to timing mode 0. */ - onfi_fill_interface_config(chip, &chip->interface_config, - NAND_SDR_IFACE, 0); - ret = ops->setup_interface(chip, chipnr, &chip->interface_config); + chip->current_interface_config = nand_get_reset_interface_config(); + ret = ops->setup_interface(chip, chipnr, + chip->current_interface_config); if (ret) pr_err("Failed to configure data interface to SDR timing mode 0\n"); @@ -949,13 +949,25 @@ static int nand_reset_interface(struct nand_chip *chip, int chipnr) */ static int nand_setup_interface(struct nand_chip *chip, int chipnr) { - u8 mode = chip->interface_config.timings.mode; - u8 tmode_param[ONFI_SUBFEATURE_PARAM_LEN] = { mode, }; + const struct nand_controller_ops *ops = chip->controller->ops; + u8 tmode_param[ONFI_SUBFEATURE_PARAM_LEN] = { }; int ret; if (!nand_controller_can_setup_interface(chip)) return 0; + /* + * A nand_reset_interface() put both the NAND chip and the NAND + * controller in timings mode 0. If the default mode for this chip is + * also 0, no need to proceed to the change again. Plus, at probe time, + * nand_setup_interface() uses ->set/get_features() which would + * fail anyway as the parameter page is not available yet. + */ + if (!chip->best_interface_config) + return 0; + + tmode_param[0] = chip->best_interface_config->timings.mode; + /* Change the mode on the chip side (if supported by the NAND chip) */ if (nand_supports_set_features(chip, ONFI_FEATURE_ADDR_TIMING_MODE)) { nand_select_target(chip, chipnr); @@ -967,14 +979,13 @@ static int nand_setup_interface(struct nand_chip *chip, int chipnr) } /* Change the mode on the controller side */ - ret = chip->controller->ops->setup_interface(chip, chipnr, - &chip->interface_config); + ret = ops->setup_interface(chip, chipnr, chip->best_interface_config); if (ret) return ret; /* Check the mode has been accepted by the chip, if supported */ if (!nand_supports_get_features(chip, ONFI_FEATURE_ADDR_TIMING_MODE)) - return 0; + goto update_interface_config; memset(tmode_param, 0, ONFI_SUBFEATURE_PARAM_LEN); nand_select_target(chip, chipnr); @@ -984,12 +995,15 @@ static int nand_setup_interface(struct nand_chip *chip, int chipnr) if (ret) goto err_reset_chip; - if (tmode_param[0] != mode) { + if (tmode_param[0] != chip->best_interface_config->timings.mode) { pr_warn("timing mode %d not acknowledged by the NAND chip\n", - mode); + chip->best_interface_config->timings.mode); goto err_reset_chip; } +update_interface_config: + chip->current_interface_config = chip->best_interface_config; + return 0; err_reset_chip: @@ -1031,8 +1045,10 @@ int nand_choose_best_sdr_timings(struct nand_chip *chip, /* Verify the controller supports the requested interface */ ret = ops->setup_interface(chip, NAND_DATA_IFACE_CHECK_ONLY, iface); - if (!ret) + if (!ret) { + chip->best_interface_config = iface; return ret; + } /* Fallback to slower modes */ best_mode = iface->timings.mode; @@ -1046,9 +1062,11 @@ int nand_choose_best_sdr_timings(struct nand_chip *chip, ret = ops->setup_interface(chip, NAND_DATA_IFACE_CHECK_ONLY, iface); if (!ret) - return 0; + break; } + chip->best_interface_config = iface; + return 0; } @@ -1067,15 +1085,25 @@ int nand_choose_best_sdr_timings(struct nand_chip *chip, */ static int nand_choose_interface_config(struct nand_chip *chip) { + struct nand_interface_config *iface; + int ret; + if (!nand_controller_can_setup_interface(chip)) return 0; + iface = kzalloc(sizeof(*iface), GFP_KERNEL); + if (!iface) + return -ENOMEM; + if (chip->ops.choose_interface_config) - return chip->ops.choose_interface_config(chip, - &chip->interface_config); + ret = chip->ops.choose_interface_config(chip, iface); + else + ret = nand_choose_best_sdr_timings(chip, iface, NULL); - return nand_choose_best_sdr_timings(chip, &chip->interface_config, - NULL); + if (ret) + kfree(iface); + + return ret; } /** @@ -2501,7 +2529,6 @@ EXPORT_SYMBOL_GPL(nand_subop_get_data_len); */ int nand_reset(struct nand_chip *chip, int chipnr) { - struct nand_interface_config saved_intf_config = chip->interface_config; int ret; ret = nand_reset_interface(chip, chipnr); @@ -2519,18 +2546,6 @@ int nand_reset(struct nand_chip *chip, int chipnr) if (ret) return ret; - /* - * A nand_reset_interface() put both the NAND chip and the NAND - * controller in timings mode 0. If the default mode for this chip is - * also 0, no need to proceed to the change again. Plus, at probe time, - * nand_setup_interface() uses ->set/get_features() which would - * fail anyway as the parameter page is not available yet. - */ - if (!memcmp(&chip->interface_config, &saved_intf_config, - sizeof(saved_intf_config))) - return 0; - - chip->interface_config = saved_intf_config; ret = nand_setup_interface(chip, chipnr); if (ret) return ret; @@ -5198,7 +5213,7 @@ static int nand_scan_ident(struct nand_chip *chip, unsigned int maxchips, mutex_init(&chip->lock); /* Enforce the right timings for reset/detection */ - onfi_fill_interface_config(chip, &chip->interface_config, NAND_SDR_IFACE, 0); + chip->current_interface_config = nand_get_reset_interface_config(); ret = nand_dt_init(chip); if (ret) @@ -5994,7 +6009,7 @@ static int nand_scan_tail(struct nand_chip *chip) for (i = 0; i < nanddev_ntargets(&chip->base); i++) { ret = nand_setup_interface(chip, i); if (ret) - goto err_nanddev_cleanup; + goto err_free_interface_config; } /* Check, if we should skip the bad block table scan */ @@ -6004,10 +6019,12 @@ static int nand_scan_tail(struct nand_chip *chip) /* Build bad block table */ ret = nand_create_bbt(chip); if (ret) - goto err_nanddev_cleanup; + goto err_free_interface_config; return 0; +err_free_interface_config: + kfree(chip->best_interface_config); err_nanddev_cleanup: nanddev_cleanup(&chip->base); @@ -6101,6 +6118,9 @@ void nand_cleanup(struct nand_chip *chip) & NAND_BBT_DYNAMICSTRUCT) kfree(chip->badblock_pattern); + /* Free the data interface */ + kfree(chip->best_interface_config); + /* Free manufacturer priv data. */ nand_manufacturer_cleanup(chip); diff --git a/drivers/mtd/nand/raw/nand_timings.c b/drivers/mtd/nand/raw/nand_timings.c index 1e22006c79ba..94d832646487 100644 --- a/drivers/mtd/nand/raw/nand_timings.c +++ b/drivers/mtd/nand/raw/nand_timings.c @@ -292,6 +292,12 @@ static const struct nand_interface_config onfi_sdr_timings[] = { }, }; +/* All NAND chips share the same reset data interface: SDR mode 0 */ +const struct nand_interface_config *nand_get_reset_interface_config(void) +{ + return &onfi_sdr_timings[0]; +} + /** * onfi_find_closest_sdr_mode - Derive the closest ONFI SDR timing mode given a * set of timings diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h index a2427c67d38b..a725b620aca2 100644 --- a/include/linux/mtd/rawnand.h +++ b/include/linux/mtd/rawnand.h @@ -1069,7 +1069,11 @@ struct nand_manufacturer { * @options: Various chip options. They can partly be set to inform nand_scan * about special functionality. See the defines for further * explanation. - * @interface_config: NAND interface timing information + * @current_interface_config: The currently used NAND interface configuration + * @best_interface_config: The best NAND interface configuration which fits both + * the NAND chip and NAND controller constraints. If + * unset, the default reset interface configuration must + * be used. * @bbt_erase_shift: Number of address bits in a bbt entry * @bbt_options: Bad block table specific options. All options used here must * come from bbm.h. By default, these options will be copied to @@ -1116,7 +1120,8 @@ struct nand_chip { unsigned int options; /* Data interface */ - struct nand_interface_config interface_config; + const struct nand_interface_config *current_interface_config; + struct nand_interface_config *best_interface_config; /* Bad block information */ unsigned int bbt_erase_shift; @@ -1209,7 +1214,7 @@ static inline struct device_node *nand_get_flash_node(struct nand_chip *chip) static inline const struct nand_interface_config * nand_get_interface_config(struct nand_chip *chip) { - return &chip->interface_config; + return chip->current_interface_config; } /* -- cgit v1.2.3 From ccc49eff77bee2885447a032948959a134029fe3 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Wed, 3 Jun 2020 15:49:13 +0200 Subject: mtd: rawnand: fsl_upm: Remove unused mtd var The mtd var in fun_wait_rnb() is now unused, let's get rid of it and fix the warning resulting from this unused var. Fixes: 50a487e7719c ("mtd: rawnand: Pass a nand_chip object to chip->dev_ready()") Signed-off-by: Boris Brezillon Reviewed-by: Miquel Raynal Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20200603134922.1352340-2-boris.brezillon@collabora.com --- drivers/mtd/nand/raw/fsl_upm.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/mtd/nand/raw/fsl_upm.c b/drivers/mtd/nand/raw/fsl_upm.c index 627deb26db51..76d1032cd35e 100644 --- a/drivers/mtd/nand/raw/fsl_upm.c +++ b/drivers/mtd/nand/raw/fsl_upm.c @@ -62,7 +62,6 @@ static int fun_chip_ready(struct nand_chip *chip) static void fun_wait_rnb(struct fsl_upm_nand *fun) { if (fun->rnb_gpio[fun->mchip_number] >= 0) { - struct mtd_info *mtd = nand_to_mtd(&fun->chip); int cnt = 1000000; while (--cnt && !fun_chip_ready(&fun->chip)) -- cgit v1.2.3 From 5290833c10b9f997de16f5bd158efcde3f96db54 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Wed, 3 Jun 2020 15:49:14 +0200 Subject: mtd: rawnand: fsl_upm: Get rid of the unused fsl_upm_nand.parts field fsl_upm_nand.parts is unused, let's get rid of it. Signed-off-by: Boris Brezillon Reviewed-by: Miquel Raynal Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20200603134922.1352340-3-boris.brezillon@collabora.com --- drivers/mtd/nand/raw/fsl_upm.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/mtd/nand/raw/fsl_upm.c b/drivers/mtd/nand/raw/fsl_upm.c index 76d1032cd35e..6eba2f4a2f5a 100644 --- a/drivers/mtd/nand/raw/fsl_upm.c +++ b/drivers/mtd/nand/raw/fsl_upm.c @@ -29,7 +29,6 @@ struct fsl_upm_nand { struct device *dev; struct nand_chip chip; int last_ctrl; - struct mtd_partition *parts; struct fsl_upm upm; uint8_t upm_addr_offset; uint8_t upm_cmd_offset; -- cgit v1.2.3 From f760bf29f8676b67fda766d3cf1dbc2fe79829e6 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Wed, 3 Jun 2020 15:49:15 +0200 Subject: mtd: rawnand: fsl_upm: Allocate the fsl_upm_nand object using devm_kzalloc() This simplifies the init error path and remove function. Signed-off-by: Boris Brezillon Reviewed-by: Miquel Raynal Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20200603134922.1352340-4-boris.brezillon@collabora.com --- drivers/mtd/nand/raw/fsl_upm.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/drivers/mtd/nand/raw/fsl_upm.c b/drivers/mtd/nand/raw/fsl_upm.c index 6eba2f4a2f5a..9cf79c62ef22 100644 --- a/drivers/mtd/nand/raw/fsl_upm.c +++ b/drivers/mtd/nand/raw/fsl_upm.c @@ -205,36 +205,34 @@ static int fun_probe(struct platform_device *ofdev) int size; int i; - fun = kzalloc(sizeof(*fun), GFP_KERNEL); + fun = devm_kzalloc(&ofdev->dev, sizeof(*fun), GFP_KERNEL); if (!fun) return -ENOMEM; ret = of_address_to_resource(ofdev->dev.of_node, 0, &io_res); if (ret) { dev_err(&ofdev->dev, "can't get IO base\n"); - goto err1; + return ret; } ret = fsl_upm_find(io_res.start, &fun->upm); if (ret) { dev_err(&ofdev->dev, "can't find UPM\n"); - goto err1; + return ret; } prop = of_get_property(ofdev->dev.of_node, "fsl,upm-addr-offset", &size); if (!prop || size != sizeof(uint32_t)) { dev_err(&ofdev->dev, "can't get UPM address offset\n"); - ret = -EINVAL; - goto err1; + return -EINVAL; } fun->upm_addr_offset = *prop; prop = of_get_property(ofdev->dev.of_node, "fsl,upm-cmd-offset", &size); if (!prop || size != sizeof(uint32_t)) { dev_err(&ofdev->dev, "can't get UPM command offset\n"); - ret = -EINVAL; - goto err1; + return -EINVAL; } fun->upm_cmd_offset = *prop; @@ -244,7 +242,7 @@ static int fun_probe(struct platform_device *ofdev) fun->mchip_count = size / sizeof(uint32_t); if (fun->mchip_count >= NAND_MAX_CHIPS) { dev_err(&ofdev->dev, "too much multiple chips\n"); - goto err1; + return -EINVAL; } for (i = 0; i < fun->mchip_count; i++) fun->mchip_offsets[i] = be32_to_cpu(prop[i]); @@ -306,8 +304,6 @@ err2: break; gpio_free(fun->rnb_gpio[i]); } -err1: - kfree(fun); return ret; } @@ -330,8 +326,6 @@ static int fun_remove(struct platform_device *ofdev) gpio_free(fun->rnb_gpio[i]); } - kfree(fun); - return 0; } -- cgit v1.2.3 From 0016648cdc45eea00bd585ccb4b2596784f60615 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Wed, 3 Jun 2020 15:49:16 +0200 Subject: mtd: rawnand: fsl_upm: Use devm_kasprintf() to allocate the MTD name This simplifies the init() error path and the remove() handler. Signed-off-by: Boris Brezillon Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20200603134922.1352340-5-boris.brezillon@collabora.com --- drivers/mtd/nand/raw/fsl_upm.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/mtd/nand/raw/fsl_upm.c b/drivers/mtd/nand/raw/fsl_upm.c index 9cf79c62ef22..a3e3a968891d 100644 --- a/drivers/mtd/nand/raw/fsl_upm.c +++ b/drivers/mtd/nand/raw/fsl_upm.c @@ -176,8 +176,9 @@ static int fun_chip_init(struct fsl_upm_nand *fun, return -ENODEV; nand_set_flash_node(&fun->chip, flash_np); - mtd->name = kasprintf(GFP_KERNEL, "0x%llx.%pOFn", (u64)io_res->start, - flash_np); + mtd->name = devm_kasprintf(fun->dev, GFP_KERNEL, "0x%llx.%pOFn", + (u64)io_res->start, + flash_np); if (!mtd->name) { ret = -ENOMEM; goto err; @@ -190,8 +191,6 @@ static int fun_chip_init(struct fsl_upm_nand *fun, ret = mtd_device_register(mtd, NULL, 0); err: of_node_put(flash_np); - if (ret) - kfree(mtd->name); return ret; } @@ -318,7 +317,6 @@ static int fun_remove(struct platform_device *ofdev) ret = mtd_device_unregister(mtd); WARN_ON(ret); nand_cleanup(chip); - kfree(mtd->name); for (i = 0; i < fun->mchip_count; i++) { if (fun->rnb_gpio[i] < 0) -- cgit v1.2.3 From 58c5a0e04dfceb1c64c84553bc909d1aa39a3bd5 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Wed, 3 Jun 2020 15:49:17 +0200 Subject: mtd: rawnand: fsl_upm: Use platform_get_resource() + devm_ioremap_resource() Replace the of_address_to_resource() + devm_ioremap() calls by platform_get_resource() + devm_ioremap_resource() ones which allows us to get rid of one error message since devm_ioremap_resource() already takes care of that. Signed-off-by: Boris Brezillon Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20200603134922.1352340-6-boris.brezillon@collabora.com --- drivers/mtd/nand/raw/fsl_upm.c | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/drivers/mtd/nand/raw/fsl_upm.c b/drivers/mtd/nand/raw/fsl_upm.c index a3e3a968891d..54851e9ea784 100644 --- a/drivers/mtd/nand/raw/fsl_upm.c +++ b/drivers/mtd/nand/raw/fsl_upm.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include @@ -197,7 +196,7 @@ err: static int fun_probe(struct platform_device *ofdev) { struct fsl_upm_nand *fun; - struct resource io_res; + struct resource *io_res; const __be32 *prop; int rnb_gpio; int ret; @@ -208,13 +207,12 @@ static int fun_probe(struct platform_device *ofdev) if (!fun) return -ENOMEM; - ret = of_address_to_resource(ofdev->dev.of_node, 0, &io_res); - if (ret) { - dev_err(&ofdev->dev, "can't get IO base\n"); - return ret; - } + io_res = platform_get_resource(ofdev, IORESOURCE_MEM, 0); + fun->io_base = devm_ioremap_resource(&ofdev->dev, io_res); + if (IS_ERR(fun->io_base)) + return PTR_ERR(fun->io_base); - ret = fsl_upm_find(io_res.start, &fun->upm); + ret = fsl_upm_find(io_res->start, &fun->upm); if (ret) { dev_err(&ofdev->dev, "can't find UPM\n"); return ret; @@ -280,17 +278,10 @@ static int fun_probe(struct platform_device *ofdev) fun->wait_flags = FSL_UPM_WAIT_RUN_PATTERN | FSL_UPM_WAIT_WRITE_BYTE; - fun->io_base = devm_ioremap(&ofdev->dev, io_res.start, - resource_size(&io_res)); - if (!fun->io_base) { - ret = -ENOMEM; - goto err2; - } - fun->dev = &ofdev->dev; fun->last_ctrl = NAND_CLE; - ret = fun_chip_init(fun, ofdev->dev.of_node, &io_res); + ret = fun_chip_init(fun, ofdev->dev.of_node, io_res); if (ret) goto err2; -- cgit v1.2.3 From a50895bbdbd433173c698c4a2321b0f02ff19ba1 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Wed, 3 Jun 2020 15:49:18 +0200 Subject: mtd: rawnand: fsl_upm: Use gpio descriptors The integer-based GPIO ids are now deprecated in favor of the GPIO desc API. The PPC platforms have already been converted to GPIOLIB, so let's use gpio descs in the NAND driver too. While at it, we use devm_gpiod_get_index_optional() so we can get rid of the manual gpio desc release done in the init error path and in the remove function. Signed-off-by: Boris Brezillon Reviewed-by: Miquel Raynal Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20200603134922.1352340-7-boris.brezillon@collabora.com --- drivers/mtd/nand/raw/fsl_upm.c | 44 ++++++++++-------------------------------- 1 file changed, 10 insertions(+), 34 deletions(-) diff --git a/drivers/mtd/nand/raw/fsl_upm.c b/drivers/mtd/nand/raw/fsl_upm.c index 54851e9ea784..977b7aad419b 100644 --- a/drivers/mtd/nand/raw/fsl_upm.c +++ b/drivers/mtd/nand/raw/fsl_upm.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include @@ -32,7 +31,7 @@ struct fsl_upm_nand { uint8_t upm_addr_offset; uint8_t upm_cmd_offset; void __iomem *io_base; - int rnb_gpio[NAND_MAX_CHIPS]; + struct gpio_desc *rnb_gpio[NAND_MAX_CHIPS]; uint32_t mchip_offsets[NAND_MAX_CHIPS]; uint32_t mchip_count; uint32_t mchip_number; @@ -50,7 +49,7 @@ static int fun_chip_ready(struct nand_chip *chip) { struct fsl_upm_nand *fun = to_fsl_upm_nand(nand_to_mtd(chip)); - if (gpio_get_value(fun->rnb_gpio[fun->mchip_number])) + if (gpiod_get_value(fun->rnb_gpio[fun->mchip_number])) return 1; dev_vdbg(fun->dev, "busy\n"); @@ -165,7 +164,7 @@ static int fun_chip_init(struct fsl_upm_nand *fun, if (fun->mchip_count > 1) fun->chip.legacy.select_chip = fun_select_chip; - if (fun->rnb_gpio[0] >= 0) + if (!fun->rnb_gpio[0]) fun->chip.legacy.dev_ready = fun_chip_ready; mtd->dev.parent = fun->dev; @@ -198,7 +197,6 @@ static int fun_probe(struct platform_device *ofdev) struct fsl_upm_nand *fun; struct resource *io_res; const __be32 *prop; - int rnb_gpio; int ret; int size; int i; @@ -248,20 +246,12 @@ static int fun_probe(struct platform_device *ofdev) } for (i = 0; i < fun->mchip_count; i++) { - fun->rnb_gpio[i] = -1; - rnb_gpio = of_get_gpio(ofdev->dev.of_node, i); - if (rnb_gpio >= 0) { - ret = gpio_request(rnb_gpio, dev_name(&ofdev->dev)); - if (ret) { - dev_err(&ofdev->dev, - "can't request RNB gpio #%d\n", i); - goto err2; - } - gpio_direction_input(rnb_gpio); - fun->rnb_gpio[i] = rnb_gpio; - } else if (rnb_gpio == -EINVAL) { + fun->rnb_gpio[i] = devm_gpiod_get_index_optional(&ofdev->dev, + NULL, i, + GPIOD_IN); + if (IS_ERR(fun->rnb_gpio[i])) { dev_err(&ofdev->dev, "RNB gpio #%d is invalid\n", i); - goto err2; + return PTR_ERR(fun->rnb_gpio[i]); } } @@ -283,19 +273,11 @@ static int fun_probe(struct platform_device *ofdev) ret = fun_chip_init(fun, ofdev->dev.of_node, io_res); if (ret) - goto err2; + return ret; dev_set_drvdata(&ofdev->dev, fun); return 0; -err2: - for (i = 0; i < fun->mchip_count; i++) { - if (fun->rnb_gpio[i] < 0) - break; - gpio_free(fun->rnb_gpio[i]); - } - - return ret; } static int fun_remove(struct platform_device *ofdev) @@ -303,18 +285,12 @@ static int fun_remove(struct platform_device *ofdev) struct fsl_upm_nand *fun = dev_get_drvdata(&ofdev->dev); struct nand_chip *chip = &fun->chip; struct mtd_info *mtd = nand_to_mtd(chip); - int ret, i; + int ret; ret = mtd_device_unregister(mtd); WARN_ON(ret); nand_cleanup(chip); - for (i = 0; i < fun->mchip_count; i++) { - if (fun->rnb_gpio[i] < 0) - break; - gpio_free(fun->rnb_gpio[i]); - } - return 0; } -- cgit v1.2.3 From abc846afda664b7f229f32b40bbef738c3511801 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Wed, 3 Jun 2020 15:49:19 +0200 Subject: mtd: rawnand: fsl_upm: Inherit from nand_controller Explicitly inherit from nand_controller instead of relying on the nand_chip.legacy.dummy_controller field. Signed-off-by: Boris Brezillon Reviewed-by: Miquel Raynal Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20200603134922.1352340-8-boris.brezillon@collabora.com --- drivers/mtd/nand/raw/fsl_upm.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/mtd/nand/raw/fsl_upm.c b/drivers/mtd/nand/raw/fsl_upm.c index 977b7aad419b..9a63e36825d8 100644 --- a/drivers/mtd/nand/raw/fsl_upm.c +++ b/drivers/mtd/nand/raw/fsl_upm.c @@ -24,6 +24,7 @@ #define FSL_UPM_WAIT_WRITE_BUFFER 0x4 struct fsl_upm_nand { + struct nand_controller base; struct device *dev; struct nand_chip chip; int last_ctrl; @@ -167,6 +168,7 @@ static int fun_chip_init(struct fsl_upm_nand *fun, if (!fun->rnb_gpio[0]) fun->chip.legacy.dev_ready = fun_chip_ready; + fun->chip.controller = &fun->base; mtd->dev.parent = fun->dev; flash_np = of_get_next_child(upm_np, NULL); @@ -268,6 +270,7 @@ static int fun_probe(struct platform_device *ofdev) fun->wait_flags = FSL_UPM_WAIT_RUN_PATTERN | FSL_UPM_WAIT_WRITE_BYTE; + nand_controller_init(&fun->base); fun->dev = &ofdev->dev; fun->last_ctrl = NAND_CLE; -- cgit v1.2.3 From 54309d65776755bcdb9dcf3744cd764fc1e254ea Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Wed, 3 Jun 2020 15:49:20 +0200 Subject: mtd: rawnand: fsl_upm: Implement exec_op() Implement exec_op() so we can get rid of the legacy interface implementation. Signed-off-by: Boris Brezillon Reviewed-by: Miquel Raynal Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20200603134922.1352340-9-boris.brezillon@collabora.com --- drivers/mtd/nand/raw/fsl_upm.c | 86 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) diff --git a/drivers/mtd/nand/raw/fsl_upm.c b/drivers/mtd/nand/raw/fsl_upm.c index 9a63e36825d8..03ca20930274 100644 --- a/drivers/mtd/nand/raw/fsl_upm.c +++ b/drivers/mtd/nand/raw/fsl_upm.c @@ -194,6 +194,91 @@ err: return ret; } +static int func_exec_instr(struct nand_chip *chip, + const struct nand_op_instr *instr) +{ + struct fsl_upm_nand *fun = to_fsl_upm_nand(nand_to_mtd(chip)); + u32 mar, reg_offs = fun->mchip_offsets[fun->mchip_number]; + unsigned int i; + const u8 *out; + u8 *in; + + switch (instr->type) { + case NAND_OP_CMD_INSTR: + fsl_upm_start_pattern(&fun->upm, fun->upm_cmd_offset); + mar = (instr->ctx.cmd.opcode << (32 - fun->upm.width)) | + reg_offs; + fsl_upm_run_pattern(&fun->upm, fun->io_base + reg_offs, mar); + fsl_upm_end_pattern(&fun->upm); + return 0; + + case NAND_OP_ADDR_INSTR: + fsl_upm_start_pattern(&fun->upm, fun->upm_addr_offset); + for (i = 0; i < instr->ctx.addr.naddrs; i++) { + mar = (instr->ctx.addr.addrs[i] << (32 - fun->upm.width)) | + reg_offs; + fsl_upm_run_pattern(&fun->upm, fun->io_base + reg_offs, mar); + } + fsl_upm_end_pattern(&fun->upm); + return 0; + + case NAND_OP_DATA_IN_INSTR: + in = instr->ctx.data.buf.in; + for (i = 0; i < instr->ctx.data.len; i++) + in[i] = in_8(fun->io_base + reg_offs); + return 0; + + case NAND_OP_DATA_OUT_INSTR: + out = instr->ctx.data.buf.out; + for (i = 0; i < instr->ctx.data.len; i++) + out_8(fun->io_base + reg_offs, out[i]); + return 0; + + case NAND_OP_WAITRDY_INSTR: + if (!fun->rnb_gpio[fun->mchip_number]) + return nand_soft_waitrdy(chip, instr->ctx.waitrdy.timeout_ms); + + return nand_gpio_waitrdy(chip, fun->rnb_gpio[fun->mchip_number], + instr->ctx.waitrdy.timeout_ms); + + default: + return -EINVAL; + } + + return 0; +} + +static int fun_exec_op(struct nand_chip *chip, const struct nand_operation *op, + bool check_only) +{ + struct fsl_upm_nand *fun = to_fsl_upm_nand(nand_to_mtd(chip)); + unsigned int i; + int ret; + + if (op->cs > NAND_MAX_CHIPS) + return -EINVAL; + + if (check_only) + return 0; + + fun->mchip_number = op->cs; + + for (i = 0; i < op->ninstrs; i++) { + ret = func_exec_instr(chip, &op->instrs[i]); + if (ret) + return ret; + + if (op->instrs[i].delay_ns) + ndelay(op->instrs[i].delay_ns); + } + + return 0; +} + +static const struct nand_controller_ops fun_ops = { + .exec_op = fun_exec_op, +}; + static int fun_probe(struct platform_device *ofdev) { struct fsl_upm_nand *fun; @@ -271,6 +356,7 @@ static int fun_probe(struct platform_device *ofdev) FSL_UPM_WAIT_WRITE_BYTE; nand_controller_init(&fun->base); + fun->base.ops = &fun_ops; fun->dev = &ofdev->dev; fun->last_ctrl = NAND_CLE; -- cgit v1.2.3 From 8fac41ebe2895fccf4bc40347f1638fe845d4936 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Wed, 3 Jun 2020 15:49:21 +0200 Subject: mtd: rawnand: fsl_upm: Get rid of the legacy interface implementation Now that the driver implements exec_op(), we can get rid of the legacy interface implementation. Signed-off-by: Boris Brezillon Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20200603134922.1352340-10-boris.brezillon@collabora.com --- drivers/mtd/nand/raw/fsl_upm.c | 133 ----------------------------------------- 1 file changed, 133 deletions(-) diff --git a/drivers/mtd/nand/raw/fsl_upm.c b/drivers/mtd/nand/raw/fsl_upm.c index 03ca20930274..197850aeb261 100644 --- a/drivers/mtd/nand/raw/fsl_upm.c +++ b/drivers/mtd/nand/raw/fsl_upm.c @@ -19,15 +19,10 @@ #include #include -#define FSL_UPM_WAIT_RUN_PATTERN 0x1 -#define FSL_UPM_WAIT_WRITE_BYTE 0x2 -#define FSL_UPM_WAIT_WRITE_BUFFER 0x4 - struct fsl_upm_nand { struct nand_controller base; struct device *dev; struct nand_chip chip; - int last_ctrl; struct fsl_upm upm; uint8_t upm_addr_offset; uint8_t upm_cmd_offset; @@ -36,8 +31,6 @@ struct fsl_upm_nand { uint32_t mchip_offsets[NAND_MAX_CHIPS]; uint32_t mchip_count; uint32_t mchip_number; - int chip_delay; - uint32_t wait_flags; }; static inline struct fsl_upm_nand *to_fsl_upm_nand(struct mtd_info *mtdinfo) @@ -46,105 +39,6 @@ static inline struct fsl_upm_nand *to_fsl_upm_nand(struct mtd_info *mtdinfo) chip); } -static int fun_chip_ready(struct nand_chip *chip) -{ - struct fsl_upm_nand *fun = to_fsl_upm_nand(nand_to_mtd(chip)); - - if (gpiod_get_value(fun->rnb_gpio[fun->mchip_number])) - return 1; - - dev_vdbg(fun->dev, "busy\n"); - return 0; -} - -static void fun_wait_rnb(struct fsl_upm_nand *fun) -{ - if (fun->rnb_gpio[fun->mchip_number] >= 0) { - int cnt = 1000000; - - while (--cnt && !fun_chip_ready(&fun->chip)) - cpu_relax(); - if (!cnt) - dev_err(fun->dev, "tired waiting for RNB\n"); - } else { - ndelay(100); - } -} - -static void fun_cmd_ctrl(struct nand_chip *chip, int cmd, unsigned int ctrl) -{ - struct fsl_upm_nand *fun = to_fsl_upm_nand(nand_to_mtd(chip)); - u32 mar; - - if (!(ctrl & fun->last_ctrl)) { - fsl_upm_end_pattern(&fun->upm); - - if (cmd == NAND_CMD_NONE) - return; - - fun->last_ctrl = ctrl & (NAND_ALE | NAND_CLE); - } - - if (ctrl & NAND_CTRL_CHANGE) { - if (ctrl & NAND_ALE) - fsl_upm_start_pattern(&fun->upm, fun->upm_addr_offset); - else if (ctrl & NAND_CLE) - fsl_upm_start_pattern(&fun->upm, fun->upm_cmd_offset); - } - - mar = (cmd << (32 - fun->upm.width)) | - fun->mchip_offsets[fun->mchip_number]; - fsl_upm_run_pattern(&fun->upm, chip->legacy.IO_ADDR_R, mar); - - if (fun->wait_flags & FSL_UPM_WAIT_RUN_PATTERN) - fun_wait_rnb(fun); -} - -static void fun_select_chip(struct nand_chip *chip, int mchip_nr) -{ - struct fsl_upm_nand *fun = to_fsl_upm_nand(nand_to_mtd(chip)); - - if (mchip_nr == -1) { - chip->legacy.cmd_ctrl(chip, NAND_CMD_NONE, 0 | NAND_CTRL_CHANGE); - } else if (mchip_nr >= 0 && mchip_nr < NAND_MAX_CHIPS) { - fun->mchip_number = mchip_nr; - chip->legacy.IO_ADDR_R = fun->io_base + fun->mchip_offsets[mchip_nr]; - chip->legacy.IO_ADDR_W = chip->legacy.IO_ADDR_R; - } else { - BUG(); - } -} - -static uint8_t fun_read_byte(struct nand_chip *chip) -{ - struct fsl_upm_nand *fun = to_fsl_upm_nand(nand_to_mtd(chip)); - - return in_8(fun->chip.legacy.IO_ADDR_R); -} - -static void fun_read_buf(struct nand_chip *chip, uint8_t *buf, int len) -{ - struct fsl_upm_nand *fun = to_fsl_upm_nand(nand_to_mtd(chip)); - int i; - - for (i = 0; i < len; i++) - buf[i] = in_8(fun->chip.legacy.IO_ADDR_R); -} - -static void fun_write_buf(struct nand_chip *chip, const uint8_t *buf, int len) -{ - struct fsl_upm_nand *fun = to_fsl_upm_nand(nand_to_mtd(chip)); - int i; - - for (i = 0; i < len; i++) { - out_8(fun->chip.legacy.IO_ADDR_W, buf[i]); - if (fun->wait_flags & FSL_UPM_WAIT_WRITE_BYTE) - fun_wait_rnb(fun); - } - if (fun->wait_flags & FSL_UPM_WAIT_WRITE_BUFFER) - fun_wait_rnb(fun); -} - static int fun_chip_init(struct fsl_upm_nand *fun, const struct device_node *upm_np, const struct resource *io_res) @@ -153,21 +47,8 @@ static int fun_chip_init(struct fsl_upm_nand *fun, int ret; struct device_node *flash_np; - fun->chip.legacy.IO_ADDR_R = fun->io_base; - fun->chip.legacy.IO_ADDR_W = fun->io_base; - fun->chip.legacy.cmd_ctrl = fun_cmd_ctrl; - fun->chip.legacy.chip_delay = fun->chip_delay; - fun->chip.legacy.read_byte = fun_read_byte; - fun->chip.legacy.read_buf = fun_read_buf; - fun->chip.legacy.write_buf = fun_write_buf; fun->chip.ecc.mode = NAND_ECC_SOFT; fun->chip.ecc.algo = NAND_ECC_HAMMING; - if (fun->mchip_count > 1) - fun->chip.legacy.select_chip = fun_select_chip; - - if (!fun->rnb_gpio[0]) - fun->chip.legacy.dev_ready = fun_chip_ready; - fun->chip.controller = &fun->base; mtd->dev.parent = fun->dev; @@ -342,23 +223,9 @@ static int fun_probe(struct platform_device *ofdev) } } - prop = of_get_property(ofdev->dev.of_node, "chip-delay", NULL); - if (prop) - fun->chip_delay = be32_to_cpup(prop); - else - fun->chip_delay = 50; - - prop = of_get_property(ofdev->dev.of_node, "fsl,upm-wait-flags", &size); - if (prop && size == sizeof(uint32_t)) - fun->wait_flags = be32_to_cpup(prop); - else - fun->wait_flags = FSL_UPM_WAIT_RUN_PATTERN | - FSL_UPM_WAIT_WRITE_BYTE; - nand_controller_init(&fun->base); fun->base.ops = &fun_ops; fun->dev = &ofdev->dev; - fun->last_ctrl = NAND_CLE; ret = fun_chip_init(fun, ofdev->dev.of_node, io_res); if (ret) -- cgit v1.2.3 From b4c719685491983628155c5c8b677332709c4c6f Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Wed, 3 Jun 2020 17:07:44 +0200 Subject: mtd: rawnand: gpio: Inherit from nand_controller Inherit from nand_controller so we don't rely on the nand_chip.legacy.dummy_controller field. Signed-off-by: Boris Brezillon Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20200603150746.1423257-2-boris.brezillon@collabora.com --- drivers/mtd/nand/raw/gpio.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/mtd/nand/raw/gpio.c b/drivers/mtd/nand/raw/gpio.c index 938077e5c6a9..33828fb20a13 100644 --- a/drivers/mtd/nand/raw/gpio.c +++ b/drivers/mtd/nand/raw/gpio.c @@ -27,6 +27,7 @@ #include struct gpiomtd { + struct nand_controller base; void __iomem *io_sync; struct nand_chip nand_chip; struct gpio_nand_platdata plat; @@ -273,6 +274,7 @@ static int gpio_nand_probe(struct platform_device *pdev) if (gpiomtd->rdy) chip->legacy.dev_ready = gpio_nand_devready; + nand_controller_init(&gpiomtd->base); nand_set_flash_node(chip, pdev->dev.of_node); chip->legacy.IO_ADDR_W = chip->legacy.IO_ADDR_R; chip->ecc.mode = NAND_ECC_SOFT; @@ -280,6 +282,7 @@ static int gpio_nand_probe(struct platform_device *pdev) chip->options = gpiomtd->plat.options; chip->legacy.chip_delay = gpiomtd->plat.chip_delay; chip->legacy.cmd_ctrl = gpio_nand_cmd_ctrl; + chip->controller = &gpiomtd->base; mtd = nand_to_mtd(chip); mtd->dev.parent = dev; -- cgit v1.2.3 From 22b27a675d714499848d4f389082eb0d959a7b34 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Wed, 3 Jun 2020 17:07:45 +0200 Subject: mtd: rawnand: gpio: Implement exec_op() Implement exec_op() so we can get rid of the legacy interface implementation. Signed-off-by: Boris Brezillon Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20200603150746.1423257-3-boris.brezillon@collabora.com --- drivers/mtd/nand/raw/gpio.c | 104 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 101 insertions(+), 3 deletions(-) diff --git a/drivers/mtd/nand/raw/gpio.c b/drivers/mtd/nand/raw/gpio.c index 33828fb20a13..115998011192 100644 --- a/drivers/mtd/nand/raw/gpio.c +++ b/drivers/mtd/nand/raw/gpio.c @@ -25,9 +25,11 @@ #include #include #include +#include struct gpiomtd { struct nand_controller base; + void __iomem *io; void __iomem *io_sync; struct nand_chip nand_chip; struct gpio_nand_platdata plat; @@ -98,6 +100,99 @@ static int gpio_nand_devready(struct nand_chip *chip) return gpiod_get_value(gpiomtd->rdy); } +static int gpio_nand_exec_instr(struct nand_chip *chip, + const struct nand_op_instr *instr) +{ + struct gpiomtd *gpiomtd = gpio_nand_getpriv(nand_to_mtd(chip)); + unsigned int i; + + switch (instr->type) { + case NAND_OP_CMD_INSTR: + gpio_nand_dosync(gpiomtd); + gpiod_set_value(gpiomtd->cle, 1); + gpio_nand_dosync(gpiomtd); + writeb(instr->ctx.cmd.opcode, gpiomtd->io); + gpio_nand_dosync(gpiomtd); + gpiod_set_value(gpiomtd->cle, 0); + return 0; + + case NAND_OP_ADDR_INSTR: + gpio_nand_dosync(gpiomtd); + gpiod_set_value(gpiomtd->ale, 1); + gpio_nand_dosync(gpiomtd); + for (i = 0; i < instr->ctx.addr.naddrs; i++) + writeb(instr->ctx.addr.addrs[i], gpiomtd->io); + gpio_nand_dosync(gpiomtd); + gpiod_set_value(gpiomtd->ale, 0); + return 0; + + case NAND_OP_DATA_IN_INSTR: + gpio_nand_dosync(gpiomtd); + if ((chip->options & NAND_BUSWIDTH_16) && + !instr->ctx.data.force_8bit) + ioread16_rep(gpiomtd->io, instr->ctx.data.buf.in, + instr->ctx.data.len / 2); + else + ioread8_rep(gpiomtd->io, instr->ctx.data.buf.in, + instr->ctx.data.len); + return 0; + + case NAND_OP_DATA_OUT_INSTR: + gpio_nand_dosync(gpiomtd); + if ((chip->options & NAND_BUSWIDTH_16) && + !instr->ctx.data.force_8bit) + iowrite16_rep(gpiomtd->io, instr->ctx.data.buf.out, + instr->ctx.data.len / 2); + else + iowrite8_rep(gpiomtd->io, instr->ctx.data.buf.out, + instr->ctx.data.len); + return 0; + + case NAND_OP_WAITRDY_INSTR: + if (!gpiomtd->rdy) + return nand_soft_waitrdy(chip, instr->ctx.waitrdy.timeout_ms); + + return nand_gpio_waitrdy(chip, gpiomtd->rdy, + instr->ctx.waitrdy.timeout_ms); + + default: + return -EINVAL; + } + + return 0; +} + +static int gpio_nand_exec_op(struct nand_chip *chip, + const struct nand_operation *op, + bool check_only) +{ + struct gpiomtd *gpiomtd = gpio_nand_getpriv(nand_to_mtd(chip)); + unsigned int i; + int ret = 0; + + if (check_only) + return 0; + + gpio_nand_dosync(gpiomtd); + gpiod_set_value(gpiomtd->nce, 0); + for (i = 0; i < op->ninstrs; i++) { + ret = gpio_nand_exec_instr(chip, &op->instrs[i]); + if (ret) + break; + + if (op->instrs[i].delay_ns) + ndelay(op->instrs[i].delay_ns); + } + gpio_nand_dosync(gpiomtd); + gpiod_set_value(gpiomtd->nce, 1); + + return ret; +} + +static const struct nand_controller_ops gpio_nand_ops = { + .exec_op = gpio_nand_exec_op, +}; + #ifdef CONFIG_OF static const struct of_device_id gpio_nand_id_table[] = { { .compatible = "gpio-control-nand" }, @@ -226,9 +321,9 @@ static int gpio_nand_probe(struct platform_device *pdev) chip = &gpiomtd->nand_chip; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - chip->legacy.IO_ADDR_R = devm_ioremap_resource(dev, res); - if (IS_ERR(chip->legacy.IO_ADDR_R)) - return PTR_ERR(chip->legacy.IO_ADDR_R); + gpiomtd->io = devm_ioremap_resource(dev, res); + if (IS_ERR(gpiomtd->io)) + return PTR_ERR(gpiomtd->io); res = gpio_nand_get_io_sync(pdev); if (res) { @@ -275,7 +370,10 @@ static int gpio_nand_probe(struct platform_device *pdev) chip->legacy.dev_ready = gpio_nand_devready; nand_controller_init(&gpiomtd->base); + gpiomtd->base.ops = &gpio_nand_ops; + nand_set_flash_node(chip, pdev->dev.of_node); + chip->legacy.IO_ADDR_R = gpiomtd->io; chip->legacy.IO_ADDR_W = chip->legacy.IO_ADDR_R; chip->ecc.mode = NAND_ECC_SOFT; chip->ecc.algo = NAND_ECC_HAMMING; -- cgit v1.2.3 From df66c27101ff279dc2e8cc2ced7191029495f194 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Wed, 3 Jun 2020 17:07:46 +0200 Subject: mtd: rawnand: gpio: Get rid of the legacy interface implementation Now that exec_op() is implemented, we can get rid of the legacy interface implementation. Signed-off-by: Boris Brezillon Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20200603150746.1423257-4-boris.brezillon@collabora.com --- drivers/mtd/nand/raw/gpio.c | 35 ----------------------------------- 1 file changed, 35 deletions(-) diff --git a/drivers/mtd/nand/raw/gpio.c b/drivers/mtd/nand/raw/gpio.c index 115998011192..3bd847ccc3f3 100644 --- a/drivers/mtd/nand/raw/gpio.c +++ b/drivers/mtd/nand/raw/gpio.c @@ -72,34 +72,6 @@ static void gpio_nand_dosync(struct gpiomtd *gpiomtd) static inline void gpio_nand_dosync(struct gpiomtd *gpiomtd) {} #endif -static void gpio_nand_cmd_ctrl(struct nand_chip *chip, int cmd, - unsigned int ctrl) -{ - struct gpiomtd *gpiomtd = gpio_nand_getpriv(nand_to_mtd(chip)); - - gpio_nand_dosync(gpiomtd); - - if (ctrl & NAND_CTRL_CHANGE) { - if (gpiomtd->nce) - gpiod_set_value(gpiomtd->nce, !(ctrl & NAND_NCE)); - gpiod_set_value(gpiomtd->cle, !!(ctrl & NAND_CLE)); - gpiod_set_value(gpiomtd->ale, !!(ctrl & NAND_ALE)); - gpio_nand_dosync(gpiomtd); - } - if (cmd == NAND_CMD_NONE) - return; - - writeb(cmd, gpiomtd->nand_chip.legacy.IO_ADDR_W); - gpio_nand_dosync(gpiomtd); -} - -static int gpio_nand_devready(struct nand_chip *chip) -{ - struct gpiomtd *gpiomtd = gpio_nand_getpriv(nand_to_mtd(chip)); - - return gpiod_get_value(gpiomtd->rdy); -} - static int gpio_nand_exec_instr(struct nand_chip *chip, const struct nand_op_instr *instr) { @@ -365,21 +337,14 @@ static int gpio_nand_probe(struct platform_device *pdev) ret = PTR_ERR(gpiomtd->rdy); goto out_ce; } - /* Using RDY pin */ - if (gpiomtd->rdy) - chip->legacy.dev_ready = gpio_nand_devready; nand_controller_init(&gpiomtd->base); gpiomtd->base.ops = &gpio_nand_ops; nand_set_flash_node(chip, pdev->dev.of_node); - chip->legacy.IO_ADDR_R = gpiomtd->io; - chip->legacy.IO_ADDR_W = chip->legacy.IO_ADDR_R; chip->ecc.mode = NAND_ECC_SOFT; chip->ecc.algo = NAND_ECC_HAMMING; chip->options = gpiomtd->plat.options; - chip->legacy.chip_delay = gpiomtd->plat.chip_delay; - chip->legacy.cmd_ctrl = gpio_nand_cmd_ctrl; chip->controller = &gpiomtd->base; mtd = nand_to_mtd(chip); -- cgit v1.2.3 From 735bf220b11fe003d4236d430db0c7131babf468 Mon Sep 17 00:00:00 2001 From: Kieran Bingham Date: Tue, 9 Jun 2020 13:45:57 +0100 Subject: mtd: rawnand: trivial spelling The word 'descriptor' is misspelled throughout the tree. Fix it up accordingly: decriptors -> descriptors Signed-off-by: Kieran Bingham Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20200609124610.3445662-5-kieran.bingham+renesas@ideasonboard.com --- drivers/mtd/nand/raw/mxc_nand.c | 2 +- drivers/mtd/nand/raw/nand_bbt.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/nand/raw/mxc_nand.c b/drivers/mtd/nand/raw/mxc_nand.c index 07c41e8bae2d..a043d76b48cb 100644 --- a/drivers/mtd/nand/raw/mxc_nand.c +++ b/drivers/mtd/nand/raw/mxc_nand.c @@ -1432,7 +1432,7 @@ static int mxc_nand_get_features(struct nand_chip *chip, int addr, } /* - * The generic flash bbt decriptors overlap with our ecc + * The generic flash bbt descriptors overlap with our ecc * hardware, so define some i.MX specific ones. */ static uint8_t bbt_pattern[] = { 'B', 'b', 't', '0' }; diff --git a/drivers/mtd/nand/raw/nand_bbt.c b/drivers/mtd/nand/raw/nand_bbt.c index 96045d60471e..344a24fd2ca8 100644 --- a/drivers/mtd/nand/raw/nand_bbt.c +++ b/drivers/mtd/nand/raw/nand_bbt.c @@ -1226,7 +1226,7 @@ static int nand_scan_bbt(struct nand_chip *this, struct nand_bbt_descr *bd) return -ENOMEM; /* - * If no primary table decriptor is given, scan the device to build a + * If no primary table descriptor is given, scan the device to build a * memory based bad block table. */ if (!td) { -- cgit v1.2.3 From 443440cc4a901af462239d286cd10721aa1c7dfc Mon Sep 17 00:00:00 2001 From: Sivaprakash Murugesan Date: Fri, 12 Jun 2020 13:28:15 +0530 Subject: mtd: rawnand: qcom: avoid write to unavailable register SFLASHC_BURST_CFG is only available on older ipq NAND platforms, this register has been removed when the NAND controller got implemented in the qpic controller. Avoid writing this register on devices which are based on qpic NAND controller. Fixes: dce84760b09f ("mtd: nand: qcom: Support for IPQ8074 QPIC NAND controller") Cc: stable@vger.kernel.org Signed-off-by: Sivaprakash Murugesan Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/1591948696-16015-2-git-send-email-sivaprak@codeaurora.org --- drivers/mtd/nand/raw/qcom_nandc.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/nand/raw/qcom_nandc.c b/drivers/mtd/nand/raw/qcom_nandc.c index f1daf330951b..78b5f211598c 100644 --- a/drivers/mtd/nand/raw/qcom_nandc.c +++ b/drivers/mtd/nand/raw/qcom_nandc.c @@ -459,11 +459,13 @@ struct qcom_nand_host { * among different NAND controllers. * @ecc_modes - ecc mode for NAND * @is_bam - whether NAND controller is using BAM + * @is_qpic - whether NAND CTRL is part of qpic IP * @dev_cmd_reg_start - NAND_DEV_CMD_* registers starting offset */ struct qcom_nandc_props { u32 ecc_modes; bool is_bam; + bool is_qpic; u32 dev_cmd_reg_start; }; @@ -2774,7 +2776,8 @@ static int qcom_nandc_setup(struct qcom_nand_controller *nandc) u32 nand_ctrl; /* kill onenand */ - nandc_write(nandc, SFLASHC_BURST_CFG, 0); + if (!nandc->props->is_qpic) + nandc_write(nandc, SFLASHC_BURST_CFG, 0); nandc_write(nandc, dev_cmd_reg_addr(nandc, NAND_DEV_CMD_VLD), NAND_DEV_CMD_VLD_VAL); @@ -3035,12 +3038,14 @@ static const struct qcom_nandc_props ipq806x_nandc_props = { static const struct qcom_nandc_props ipq4019_nandc_props = { .ecc_modes = (ECC_BCH_4BIT | ECC_BCH_8BIT), .is_bam = true, + .is_qpic = true, .dev_cmd_reg_start = 0x0, }; static const struct qcom_nandc_props ipq8074_nandc_props = { .ecc_modes = (ECC_BCH_4BIT | ECC_BCH_8BIT), .is_bam = true, + .is_qpic = true, .dev_cmd_reg_start = 0x7000, }; -- cgit v1.2.3 From cb272395dceef1652247dad08a50ed4153ffbd43 Mon Sep 17 00:00:00 2001 From: Sivaprakash Murugesan Date: Fri, 12 Jun 2020 13:28:16 +0530 Subject: mtd: rawnand: qcom: set BAM mode only if not set already BAM is DMA controller on QCOM ipq platforms, BAM mode on NAND driver is set by writing BAM_MODE_EN bit on NAND_CTRL register. NAND_CTRL is an operational register and in BAM mode operational registers are read only. So, before enabling BAM mode by writing the NAND_CTRL register, check if BAM mode was already enabled by the bootloader, and enable BAM mode only if it is not enabled already. Signed-off-by: Sivaprakash Murugesan Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/1591948696-16015-3-git-send-email-sivaprak@codeaurora.org --- drivers/mtd/nand/raw/qcom_nandc.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/nand/raw/qcom_nandc.c b/drivers/mtd/nand/raw/qcom_nandc.c index 78b5f211598c..bd7a7251429b 100644 --- a/drivers/mtd/nand/raw/qcom_nandc.c +++ b/drivers/mtd/nand/raw/qcom_nandc.c @@ -2784,7 +2784,16 @@ static int qcom_nandc_setup(struct qcom_nand_controller *nandc) /* enable ADM or BAM DMA */ if (nandc->props->is_bam) { nand_ctrl = nandc_read(nandc, NAND_CTRL); - nandc_write(nandc, NAND_CTRL, nand_ctrl | BAM_MODE_EN); + + /* + *NAND_CTRL is an operational registers, and CPU + * access to operational registers are read only + * in BAM mode. So update the NAND_CTRL register + * only if it is not in BAM mode. In most cases BAM + * mode will be enabled in bootloader + */ + if (!(nand_ctrl & BAM_MODE_EN)) + nandc_write(nandc, NAND_CTRL, nand_ctrl | BAM_MODE_EN); } else { nandc_write(nandc, NAND_FLASH_CHIP_SELECT, DM_EN); } -- cgit v1.2.3 From bee3ab8bdd3b13faf08e5b6e0218f59b0a49fcc3 Mon Sep 17 00:00:00 2001 From: Kamal Dasu Date: Fri, 12 Jun 2020 17:29:01 -0400 Subject: mtd: rawnand: brcmnand: Don't default to edu transfer When flash-dma is absent do not default to using flash-edu. Make sure flash-edu is enabled before setting EDU transfer function. Fixes: a5d53ad26a8b ("mtd: rawnand: brcmnand: Add support for flash-edu for dma transfers") Signed-off-by: Kamal Dasu Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20200612212902.21347-2-kdasu.kdev@gmail.com --- drivers/mtd/nand/raw/brcmnand/brcmnand.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/nand/raw/brcmnand/brcmnand.c b/drivers/mtd/nand/raw/brcmnand/brcmnand.c index 44068e9eea03..ac934a715a19 100644 --- a/drivers/mtd/nand/raw/brcmnand/brcmnand.c +++ b/drivers/mtd/nand/raw/brcmnand/brcmnand.c @@ -3023,8 +3023,9 @@ int brcmnand_probe(struct platform_device *pdev, struct brcmnand_soc *soc) if (ret < 0) goto err; - /* set edu transfer function to call */ - ctrl->dma_trans = brcmnand_edu_trans; + if (has_edu(ctrl)) + /* set edu transfer function to call */ + ctrl->dma_trans = brcmnand_edu_trans; } /* Disable automatic device ID config, direct addressing */ -- cgit v1.2.3 From 4551e78ad98add1f16b70cf286d5aad3ce7bcd4c Mon Sep 17 00:00:00 2001 From: Kamal Dasu Date: Fri, 12 Jun 2020 17:29:02 -0400 Subject: mtd: rawnand: brcmnand: ECC error handling on EDU transfers Implement ECC correctable and uncorrectable error handling for EDU reads. If ECC correctable bitflips are encountered on EDU transfer, read page again using PIO. This is needed due to a NAND controller limitation where corrected data is not transferred to the DMA buffer on ECC error. This applies to ECC correctable errors that are reported by the controller hardware based on set number of bitflips threshold in the controller threshold register, bitflips below the threshold are corrected silently and are not reported by the controller hardware. Fixes: a5d53ad26a8b ("mtd: rawnand: brcmnand: Add support for flash-edu for dma transfers") Signed-off-by: Kamal Dasu Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20200612212902.21347-3-kdasu.kdev@gmail.com --- drivers/mtd/nand/raw/brcmnand/brcmnand.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/drivers/mtd/nand/raw/brcmnand/brcmnand.c b/drivers/mtd/nand/raw/brcmnand/brcmnand.c index ac934a715a19..a4033d32a710 100644 --- a/drivers/mtd/nand/raw/brcmnand/brcmnand.c +++ b/drivers/mtd/nand/raw/brcmnand/brcmnand.c @@ -1918,6 +1918,22 @@ static int brcmnand_edu_trans(struct brcmnand_host *host, u64 addr, u32 *buf, edu_writel(ctrl, EDU_STOP, 0); /* force stop */ edu_readl(ctrl, EDU_STOP); + if (!ret && edu_cmd == EDU_CMD_READ) { + u64 err_addr = 0; + + /* + * check for ECC errors here, subpage ECC errors are + * retained in ECC error address register + */ + err_addr = brcmnand_get_uncorrecc_addr(ctrl); + if (!err_addr) { + err_addr = brcmnand_get_correcc_addr(ctrl); + if (err_addr) + ret = -EUCLEAN; + } else + ret = -EBADMSG; + } + return ret; } @@ -2124,6 +2140,7 @@ static int brcmnand_read(struct mtd_info *mtd, struct nand_chip *chip, u64 err_addr = 0; int err; bool retry = true; + bool edu_err = false; dev_dbg(ctrl->dev, "read %llx -> %p\n", (unsigned long long)addr, buf); @@ -2141,6 +2158,10 @@ try_dmaread: else return -EIO; } + + if (has_edu(ctrl) && err_addr) + edu_err = true; + } else { if (oob) memset(oob, 0x99, mtd->oobsize); @@ -2188,6 +2209,11 @@ try_dmaread: if (mtd_is_bitflip(err)) { unsigned int corrected = brcmnand_count_corrected(ctrl); + /* in case of EDU correctable error we read again using PIO */ + if (edu_err) + err = brcmnand_read_by_pio(mtd, chip, addr, trans, buf, + oob, &err_addr); + dev_dbg(ctrl->dev, "corrected error at 0x%llx\n", (unsigned long long)err_addr); mtd->ecc_stats.corrected += corrected; -- cgit v1.2.3 From 91e81150d38842b58133ce1a5d70c88e8f1cf7c1 Mon Sep 17 00:00:00 2001 From: Álvaro Fernández Rojas Date: Mon, 15 Jun 2020 11:17:40 +0200 Subject: mtd: parsers: bcm63xx: simplify CFE detection MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of trying to parse CFE version string, which is customized by some vendors, let's just check that "CFE1" was passed on argument 3. Signed-off-by: Álvaro Fernández Rojas Signed-off-by: Jonas Gorski Reviewed-by: Florian Fainelli Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20200615091740.2958303-1-noltari@gmail.com --- drivers/mtd/parsers/bcm63xxpart.c | 32 ++++++++++++-------------------- 1 file changed, 12 insertions(+), 20 deletions(-) diff --git a/drivers/mtd/parsers/bcm63xxpart.c b/drivers/mtd/parsers/bcm63xxpart.c index 78f90c6c18fd..b15bdadaedb5 100644 --- a/drivers/mtd/parsers/bcm63xxpart.c +++ b/drivers/mtd/parsers/bcm63xxpart.c @@ -22,6 +22,11 @@ #include #include +#ifdef CONFIG_MIPS +#include +#include +#endif /* CONFIG_MIPS */ + #define BCM963XX_CFE_BLOCK_SIZE SZ_64K /* always at least 64KiB */ #define BCM963XX_CFE_MAGIC_OFFSET 0x4e0 @@ -32,28 +37,15 @@ #define STR_NULL_TERMINATE(x) \ do { char *_str = (x); _str[sizeof(x) - 1] = 0; } while (0) -static int bcm63xx_detect_cfe(struct mtd_info *master) +static inline int bcm63xx_detect_cfe(void) { - char buf[9]; - int ret; - size_t retlen; + int ret = 0; - ret = mtd_read(master, BCM963XX_CFE_VERSION_OFFSET, 5, &retlen, - (void *)buf); - buf[retlen] = 0; +#ifdef CONFIG_MIPS + ret = (fw_arg3 == CFE_EPTSEAL); +#endif /* CONFIG_MIPS */ - if (ret) - return ret; - - if (strncmp("cfe-v", buf, 5) == 0) - return 0; - - /* very old CFE's do not have the cfe-v string, so check for magic */ - ret = mtd_read(master, BCM963XX_CFE_MAGIC_OFFSET, 8, &retlen, - (void *)buf); - buf[retlen] = 0; - - return strncmp("CFE1CFE1", buf, 8); + return ret; } static int bcm63xx_read_nvram(struct mtd_info *master, @@ -138,7 +130,7 @@ static int bcm63xx_parse_cfe_partitions(struct mtd_info *master, struct bcm963xx_nvram *nvram = NULL; int ret; - if (bcm63xx_detect_cfe(master)) + if (!bcm63xx_detect_cfe()) return -EINVAL; nvram = vzalloc(sizeof(*nvram)); -- cgit v1.2.3 From fef95b7211deb80c19ebfcdd5208ec7b80b40cbf Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Mon, 15 Jun 2020 18:57:48 +0300 Subject: mtd: spi-nor: intel-spi: Add support for Intel Emmitsburg SPI serial flash Intel Emmitsburg has the same SPI serial flash controller as Lewisburg. Add Emmitsburg PCI ID to the driver list of supported devices. Signed-off-by: Mika Westerberg Signed-off-by: Tudor Ambarus Link: https://lore.kernel.org/r/20200615155748.920-1-mika.westerberg@linux.intel.com --- drivers/mtd/spi-nor/controllers/intel-spi-pci.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mtd/spi-nor/controllers/intel-spi-pci.c b/drivers/mtd/spi-nor/controllers/intel-spi-pci.c index 81329f680bec..c19f1035cc02 100644 --- a/drivers/mtd/spi-nor/controllers/intel-spi-pci.c +++ b/drivers/mtd/spi-nor/controllers/intel-spi-pci.c @@ -68,6 +68,7 @@ static const struct pci_device_id intel_spi_pci_ids[] = { { PCI_VDEVICE(INTEL, 0x06a4), (unsigned long)&bxt_info }, { PCI_VDEVICE(INTEL, 0x18e0), (unsigned long)&bxt_info }, { PCI_VDEVICE(INTEL, 0x19e0), (unsigned long)&bxt_info }, + { PCI_VDEVICE(INTEL, 0x1bca), (unsigned long)&bxt_info }, { PCI_VDEVICE(INTEL, 0x34a4), (unsigned long)&bxt_info }, { PCI_VDEVICE(INTEL, 0x4b24), (unsigned long)&bxt_info }, { PCI_VDEVICE(INTEL, 0x4da4), (unsigned long)&bxt_info }, -- cgit v1.2.3 From a0eec15673222ef52655fc6a5da0008c501aebdc Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Wed, 24 Jun 2020 22:21:03 +0300 Subject: mtd: spi-nor: intel-spi: Add support for Intel Tiger Lake-H SPI serial flash Intel Tiger Lake-H has the same SPI serial flash controller as Cannon Lake. Add Tiger Lake-H PCI ID to the driver list of supported devices. Signed-off-by: Mika Westerberg Signed-off-by: Tudor Ambarus Link: https://lore.kernel.org/r/20200624192103.78770-1-mika.westerberg@linux.intel.com --- drivers/mtd/spi-nor/controllers/intel-spi-pci.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mtd/spi-nor/controllers/intel-spi-pci.c b/drivers/mtd/spi-nor/controllers/intel-spi-pci.c index c19f1035cc02..c72aa1ab71ad 100644 --- a/drivers/mtd/spi-nor/controllers/intel-spi-pci.c +++ b/drivers/mtd/spi-nor/controllers/intel-spi-pci.c @@ -70,6 +70,7 @@ static const struct pci_device_id intel_spi_pci_ids[] = { { PCI_VDEVICE(INTEL, 0x19e0), (unsigned long)&bxt_info }, { PCI_VDEVICE(INTEL, 0x1bca), (unsigned long)&bxt_info }, { PCI_VDEVICE(INTEL, 0x34a4), (unsigned long)&bxt_info }, + { PCI_VDEVICE(INTEL, 0x43a4), (unsigned long)&cnl_info }, { PCI_VDEVICE(INTEL, 0x4b24), (unsigned long)&bxt_info }, { PCI_VDEVICE(INTEL, 0x4da4), (unsigned long)&bxt_info }, { PCI_VDEVICE(INTEL, 0xa0a4), (unsigned long)&bxt_info }, -- cgit v1.2.3 From 482dcb2a04fdf6d4306e40f2b0537a313a466558 Mon Sep 17 00:00:00 2001 From: Frieder Schrempf Date: Thu, 2 Jul 2020 14:05:50 +0000 Subject: mtd: spi-nor: macronix: Add support for MX25R1635F The MX25R1635F is the smaller sibling of the MX25R3235F that is already supported. It's only half the size (16Mb). It was tested on the Kontron Electronics i.MX8MM SoM (N8010) using raw read and write from and to the mtd device and the 'flash_erase' command. Signed-off-by: Frieder Schrempf [tudor.ambarus@microchip.com: update subject] Signed-off-by: Tudor Ambarus Link: https://lore.kernel.org/r/20200702140523.6811-1-frieder.schrempf@kontron.de --- drivers/mtd/spi-nor/macronix.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/mtd/spi-nor/macronix.c b/drivers/mtd/spi-nor/macronix.c index 96735d83c77c..0ae0815a3633 100644 --- a/drivers/mtd/spi-nor/macronix.c +++ b/drivers/mtd/spi-nor/macronix.c @@ -52,6 +52,9 @@ static const struct flash_info macronix_parts[] = { { "mx25u6435f", INFO(0xc22537, 0, 64 * 1024, 128, SECT_4K) }, { "mx25l12805d", INFO(0xc22018, 0, 64 * 1024, 256, 0) }, { "mx25l12855e", INFO(0xc22618, 0, 64 * 1024, 256, 0) }, + { "mx25r1635f", INFO(0xc22815, 0, 64 * 1024, 32, + SECT_4K | SPI_NOR_DUAL_READ | + SPI_NOR_QUAD_READ) }, { "mx25r3235f", INFO(0xc22816, 0, 64 * 1024, 64, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, -- cgit v1.2.3 From 0ee2872f105b997ba5f09f7fdae542e4cbc1d676 Mon Sep 17 00:00:00 2001 From: Sven Van Asbroeck Date: Mon, 29 Jun 2020 15:53:06 -0400 Subject: mtd: spi-nor: winbond: Add support for w25q64jvm This chip is (nearly) identical to the Winbond w25q64 which is already supported by Linux. Compared to the w25q64, the 'jvm' has a different JEDEC ID. Signed-off-by: Sven Van Asbroeck [tudor.ambarus@microchip.com: Order entry alphabetically, update subject, update Sven's email address] Signed-off-by: Tudor Ambarus Link: https://lore.kernel.org/r/20200629195306.1030-1-TheSven73@gmail.com --- drivers/mtd/spi-nor/winbond.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mtd/spi-nor/winbond.c b/drivers/mtd/spi-nor/winbond.c index 5062af10f138..a5eb1d56cb88 100644 --- a/drivers/mtd/spi-nor/winbond.c +++ b/drivers/mtd/spi-nor/winbond.c @@ -68,6 +68,7 @@ static const struct flash_info winbond_parts[] = { { "w25q64dw", INFO(0xef6017, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) }, + { "w25q64jvm", INFO(0xef7017, 0, 64 * 1024, 128, SECT_4K) }, { "w25q128fw", INFO(0xef6018, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) }, -- cgit v1.2.3 From d2e639d6ad60fc164b75462bcdf8a43331116fd8 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 24 Jun 2020 16:26:40 +0300 Subject: mtd: rawnand: ingenic: cleanup ARRAY_SIZE() vs sizeof() use The ARRAY_SIZE() is the number of elements but we want to use sizeof() here for the number of bytes. Fortunately, they are the same thing because it's an array of u8 so this has no effect on runtime. Signed-off-by: Dan Carpenter Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20200624132640.GC9972@mwanda --- drivers/mtd/nand/raw/ingenic/jz4740_ecc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/nand/raw/ingenic/jz4740_ecc.c b/drivers/mtd/nand/raw/ingenic/jz4740_ecc.c index 13fea645c7f0..54e377754a6c 100644 --- a/drivers/mtd/nand/raw/ingenic/jz4740_ecc.c +++ b/drivers/mtd/nand/raw/ingenic/jz4740_ecc.c @@ -90,8 +90,8 @@ static int jz4740_ecc_calculate(struct ingenic_ecc *ecc, * 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)); + if (memcmp(ecc_code, empty_block_ecc, sizeof(empty_block_ecc)) == 0) + memset(ecc_code, 0xff, sizeof(empty_block_ecc)); return 0; } -- cgit v1.2.3 From 5eeb7fe919ff4f683d96cf8c74a9de7e54722040 Mon Sep 17 00:00:00 2001 From: Christophe Kerello Date: Fri, 12 Jun 2020 17:22:37 +0200 Subject: mtd: rawnand: stm32_fmc2: do not display errors if the driver is deferred A MDMA issue has been solved on Kernel 5.7. The effect of this fix is that the MDMA driver is now deferred and the FMC2 NFC driver is also deferred. All is working fine but there is a FMC2 log in the console: stm32_fmc2_nfc 58002000.nand-controller: failed to request tx DMA channel: -517 This patch removes the display of this log in the console in case of this error is -EPROBE_DEFER. Signed-off-by: Christophe Kerello Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/1591975362-22009-2-git-send-email-christophe.kerello@st.com --- drivers/mtd/nand/raw/stm32_fmc2_nand.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/mtd/nand/raw/stm32_fmc2_nand.c b/drivers/mtd/nand/raw/stm32_fmc2_nand.c index 65c9d17b25a3..e7b706b8ec4e 100644 --- a/drivers/mtd/nand/raw/stm32_fmc2_nand.c +++ b/drivers/mtd/nand/raw/stm32_fmc2_nand.c @@ -1570,7 +1570,7 @@ static int stm32_fmc2_nfc_dma_setup(struct stm32_fmc2_nfc *nfc) nfc->dma_tx_ch = dma_request_chan(nfc->dev, "tx"); if (IS_ERR(nfc->dma_tx_ch)) { ret = PTR_ERR(nfc->dma_tx_ch); - if (ret != -ENODEV) + if (ret != -ENODEV && ret != -EPROBE_DEFER) dev_err(nfc->dev, "failed to request tx DMA channel: %d\n", ret); nfc->dma_tx_ch = NULL; @@ -1580,7 +1580,7 @@ static int stm32_fmc2_nfc_dma_setup(struct stm32_fmc2_nfc *nfc) nfc->dma_rx_ch = dma_request_chan(nfc->dev, "rx"); if (IS_ERR(nfc->dma_rx_ch)) { ret = PTR_ERR(nfc->dma_rx_ch); - if (ret != -ENODEV) + if (ret != -ENODEV && ret != -EPROBE_DEFER) dev_err(nfc->dev, "failed to request rx DMA channel: %d\n", ret); nfc->dma_rx_ch = NULL; @@ -1590,7 +1590,7 @@ static int stm32_fmc2_nfc_dma_setup(struct stm32_fmc2_nfc *nfc) nfc->dma_ecc_ch = dma_request_chan(nfc->dev, "ecc"); if (IS_ERR(nfc->dma_ecc_ch)) { ret = PTR_ERR(nfc->dma_ecc_ch); - if (ret != -ENODEV) + if (ret != -ENODEV && ret != -EPROBE_DEFER) dev_err(nfc->dev, "failed to request ecc DMA channel: %d\n", ret); nfc->dma_ecc_ch = NULL; -- cgit v1.2.3 From bce49d1e3cfe48eb7a33a39da2530156c27fa3b2 Mon Sep 17 00:00:00 2001 From: Christophe Kerello Date: Fri, 12 Jun 2020 17:22:38 +0200 Subject: dt-bindings: mtd: update STM32 FMC2 NAND controller documentation These bindings can be used on SOCs where the FMC2 NAND controller is in standalone. In case that the FMC2 embeds 2 controllers (an external bus controller and a raw NAND controller), the register base address, the clock and the reset will be defined in the parent node. Signed-off-by: Christophe Kerello Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/1591975362-22009-3-git-send-email-christophe.kerello@st.com --- .../bindings/mtd/st,stm32-fmc2-nand.yaml | 83 +++++++++++++++------- 1 file changed, 57 insertions(+), 26 deletions(-) diff --git a/Documentation/devicetree/bindings/mtd/st,stm32-fmc2-nand.yaml b/Documentation/devicetree/bindings/mtd/st,stm32-fmc2-nand.yaml index b059267f6d20..6ae7de15d172 100644 --- a/Documentation/devicetree/bindings/mtd/st,stm32-fmc2-nand.yaml +++ b/Documentation/devicetree/bindings/mtd/st,stm32-fmc2-nand.yaml @@ -9,32 +9,19 @@ title: STMicroelectronics Flexible Memory Controller 2 (FMC2) Bindings maintainers: - Christophe Kerello -allOf: - - $ref: "nand-controller.yaml#" - properties: compatible: - const: st,stm32mp15-fmc2 + enum: + - st,stm32mp15-fmc2 + - st,stm32mp1-fmc2-nfc reg: - items: - - description: Registers - - description: Chip select 0 data - - description: Chip select 0 command - - description: Chip select 0 address space - - description: Chip select 1 data - - description: Chip select 1 command - - description: Chip select 1 address space + minItems: 6 + maxItems: 7 interrupts: maxItems: 1 - clocks: - maxItems: 1 - - resets: - maxItems: 1 - dmas: items: - description: tx DMA channel @@ -57,11 +44,55 @@ patternProperties: nand-ecc-strength: enum: [1, 4 ,8 ] +allOf: + - $ref: "nand-controller.yaml#" + + - if: + properties: + compatible: + contains: + const: st,stm32mp15-fmc2 + then: + properties: + reg: + items: + - description: Registers + - description: Chip select 0 data + - description: Chip select 0 command + - description: Chip select 0 address space + - description: Chip select 1 data + - description: Chip select 1 command + - description: Chip select 1 address space + + clocks: + maxItems: 1 + + resets: + maxItems: 1 + + required: + - clocks + + - if: + properties: + compatible: + contains: + const: st,stm32mp1-fmc2-nfc + then: + properties: + reg: + items: + - description: Chip select 0 data + - description: Chip select 0 command + - description: Chip select 0 address space + - description: Chip select 1 data + - description: Chip select 1 command + - description: Chip select 1 address space + required: - compatible - reg - interrupts - - clocks examples: - | @@ -77,13 +108,13 @@ examples: <0x81000000 0x1000>, <0x89010000 0x1000>, <0x89020000 0x1000>; - interrupts = ; - dmas = <&mdma1 20 0x10 0x12000a02 0x0 0x0>, - <&mdma1 20 0x10 0x12000a08 0x0 0x0>, - <&mdma1 21 0x10 0x12000a0a 0x0 0x0>; - dma-names = "tx", "rx", "ecc"; - clocks = <&rcc FMC_K>; - resets = <&rcc FMC_R>; + interrupts = ; + dmas = <&mdma1 20 0x2 0x12000a02 0x0 0x0>, + <&mdma1 20 0x2 0x12000a08 0x0 0x0>, + <&mdma1 21 0x2 0x12000a0a 0x0 0x0>; + dma-names = "tx", "rx", "ecc"; + clocks = <&rcc FMC_K>; + resets = <&rcc FMC_R>; #address-cells = <1>; #size-cells = <0>; -- cgit v1.2.3 From 1ab2f86f996fae09e2e216511584143c82efd030 Mon Sep 17 00:00:00 2001 From: Christophe Kerello Date: Fri, 12 Jun 2020 17:22:39 +0200 Subject: dt-bindings: memory-controller: add STM32 FMC2 EBI controller documentation This patch adds the documentation of the device tree bindings for the STM32 FMC2 EBI controller. Signed-off-by: Christophe Kerello Reviewed-by: Rob Herring Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/1591975362-22009-4-git-send-email-christophe.kerello@st.com --- .../memory-controllers/st,stm32-fmc2-ebi.yaml | 252 +++++++++++++++++++++ 1 file changed, 252 insertions(+) create mode 100644 Documentation/devicetree/bindings/memory-controllers/st,stm32-fmc2-ebi.yaml diff --git a/Documentation/devicetree/bindings/memory-controllers/st,stm32-fmc2-ebi.yaml b/Documentation/devicetree/bindings/memory-controllers/st,stm32-fmc2-ebi.yaml new file mode 100644 index 000000000000..70eaf739036b --- /dev/null +++ b/Documentation/devicetree/bindings/memory-controllers/st,stm32-fmc2-ebi.yaml @@ -0,0 +1,252 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/memory-controllers/st,stm32-fmc2-ebi.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: STMicroelectronics Flexible Memory Controller 2 (FMC2) Bindings + +description: | + The FMC2 functional block makes the interface with: synchronous and + asynchronous static devices (such as PSNOR, PSRAM or other memory-mapped + peripherals) and NAND flash memories. + Its main purposes are: + - to translate AXI transactions into the appropriate external device + protocol + - to meet the access time requirements of the external devices + All external devices share the addresses, data and control signals with the + controller. Each external device is accessed by means of a unique Chip + Select. The FMC2 performs only one access at a time to an external device. + +maintainers: + - Christophe Kerello + +properties: + compatible: + const: st,stm32mp1-fmc2-ebi + + reg: + maxItems: 1 + + clocks: + maxItems: 1 + + resets: + maxItems: 1 + + "#address-cells": + const: 2 + + "#size-cells": + const: 1 + + ranges: + description: | + Reflects the memory layout with four integer values per bank. Format: + 0
+ +patternProperties: + "^.*@[0-4],[a-f0-9]+$": + type: object + + properties: + reg: + description: Bank number, base address and size of the device. + + st,fmc2-ebi-cs-transaction-type: + description: | + Select one of the transactions type supported + 0: Asynchronous mode 1 SRAM/FRAM. + 1: Asynchronous mode 1 PSRAM. + 2: Asynchronous mode A SRAM/FRAM. + 3: Asynchronous mode A PSRAM. + 4: Asynchronous mode 2 NOR. + 5: Asynchronous mode B NOR. + 6: Asynchronous mode C NOR. + 7: Asynchronous mode D NOR. + 8: Synchronous read synchronous write PSRAM. + 9: Synchronous read asynchronous write PSRAM. + 10: Synchronous read synchronous write NOR. + 11: Synchronous read asynchronous write NOR. + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + maximum: 11 + + st,fmc2-ebi-cs-cclk-enable: + description: Continuous clock enable (first bank must be configured + in synchronous mode). The FMC_CLK is generated continuously + during asynchronous and synchronous access. By default, the + FMC_CLK is only generated during synchronous access. + $ref: /schemas/types.yaml#/definitions/flag + + st,fmc2-ebi-cs-mux-enable: + description: Address/Data multiplexed on databus (valid only with + NOR and PSRAM transactions type). By default, Address/Data + are not multiplexed. + $ref: /schemas/types.yaml#/definitions/flag + + st,fmc2-ebi-cs-buswidth: + description: Data bus width + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [ 8, 16 ] + default: 16 + + st,fmc2-ebi-cs-waitpol-high: + description: Wait signal polarity (NWAIT signal active high). + By default, NWAIT is active low. + $ref: /schemas/types.yaml#/definitions/flag + + st,fmc2-ebi-cs-waitcfg-enable: + description: The NWAIT signal indicates wheither the data from the + device are valid or if a wait state must be inserted when accessing + the device in synchronous mode. By default, the NWAIT signal is + active one data cycle before wait state. + $ref: /schemas/types.yaml#/definitions/flag + + st,fmc2-ebi-cs-wait-enable: + description: The NWAIT signal is enabled (its level is taken into + account after the programmed latency period to insert wait states + if asserted). By default, the NWAIT signal is disabled. + $ref: /schemas/types.yaml#/definitions/flag + + st,fmc2-ebi-cs-asyncwait-enable: + description: The NWAIT signal is taken into account during asynchronous + transactions. By default, the NWAIT signal is not taken into account + during asynchronous transactions. + $ref: /schemas/types.yaml#/definitions/flag + + st,fmc2-ebi-cs-cpsize: + description: CRAM page size. The controller splits the burst access + when the memory page is reached. By default, no burst split when + crossing page boundary. + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [ 0, 128, 256, 512, 1024 ] + default: 0 + + st,fmc2-ebi-cs-byte-lane-setup-ns: + description: This property configures the byte lane setup timing + defined in nanoseconds from NBLx low to Chip Select NEx low. + + st,fmc2-ebi-cs-address-setup-ns: + description: This property defines the duration of the address setup + phase in nanoseconds used for asynchronous read/write transactions. + + st,fmc2-ebi-cs-address-hold-ns: + description: This property defines the duration of the address hold + phase in nanoseconds used for asynchronous multiplexed read/write + transactions. + + st,fmc2-ebi-cs-data-setup-ns: + description: This property defines the duration of the data setup phase + in nanoseconds used for asynchronous read/write transactions. + + st,fmc2-ebi-cs-bus-turnaround-ns: + description: This property defines the delay in nanoseconds between the + end of current read/write transaction and the next transaction. + + st,fmc2-ebi-cs-data-hold-ns: + description: This property defines the duration of the data hold phase + in nanoseconds used for asynchronous read/write transactions. + + st,fmc2-ebi-cs-clk-period-ns: + description: This property defines the FMC_CLK output signal period in + nanoseconds. + + st,fmc2-ebi-cs-data-latency-ns: + description: This property defines the data latency before reading or + writing the first data in nanoseconds. + + st,fmc2_ebi-cs-write-address-setup-ns: + description: This property defines the duration of the address setup + phase in nanoseconds used for asynchronous write transactions. + + st,fmc2-ebi-cs-write-address-hold-ns: + description: This property defines the duration of the address hold + phase in nanoseconds used for asynchronous multiplexed write + transactions. + + st,fmc2-ebi-cs-write-data-setup-ns: + description: This property defines the duration of the data setup + phase in nanoseconds used for asynchronous write transactions. + + st,fmc2-ebi-cs-write-bus-turnaround-ns: + description: This property defines the delay between the end of current + write transaction and the next transaction in nanoseconds. + + st,fmc2-ebi-cs-write-data-hold-ns: + description: This property defines the duration of the data hold phase + in nanoseconds used for asynchronous write transactions. + + st,fmc2-ebi-cs-max-low-pulse-ns: + description: This property defines the maximum chip select low pulse + duration in nanoseconds for synchronous transactions. When this timing + reaches 0, the controller splits the current access, toggles NE to + allow device refresh and restarts a new access. + + required: + - reg + +required: + - "#address-cells" + - "#size-cells" + - compatible + - reg + - clocks + - ranges + +examples: + - | + #include + #include + #include + memory-controller@58002000 { + #address-cells = <2>; + #size-cells = <1>; + compatible = "st,stm32mp1-fmc2-ebi"; + reg = <0x58002000 0x1000>; + clocks = <&rcc FMC_K>; + resets = <&rcc FMC_R>; + + ranges = <0 0 0x60000000 0x04000000>, /* EBI CS 1 */ + <1 0 0x64000000 0x04000000>, /* EBI CS 2 */ + <2 0 0x68000000 0x04000000>, /* EBI CS 3 */ + <3 0 0x6c000000 0x04000000>, /* EBI CS 4 */ + <4 0 0x80000000 0x10000000>; /* NAND */ + + psram@0,0 { + compatible = "mtd-ram"; + reg = <0 0x00000000 0x100000>; + bank-width = <2>; + + st,fmc2-ebi-cs-transaction-type = <1>; + st,fmc2-ebi-cs-address-setup-ns = <60>; + st,fmc2-ebi-cs-data-setup-ns = <30>; + st,fmc2-ebi-cs-bus-turnaround-ns = <5>; + }; + + nand-controller@4,0 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "st,stm32mp1-fmc2-nfc"; + reg = <4 0x00000000 0x1000>, + <4 0x08010000 0x1000>, + <4 0x08020000 0x1000>, + <4 0x01000000 0x1000>, + <4 0x09010000 0x1000>, + <4 0x09020000 0x1000>; + interrupts = ; + dmas = <&mdma1 20 0x2 0x12000a02 0x0 0x0>, + <&mdma1 20 0x2 0x12000a08 0x0 0x0>, + <&mdma1 21 0x2 0x12000a0a 0x0 0x0>; + dma-names = "tx", "rx", "ecc"; + + nand@0 { + reg = <0>; + nand-on-flash-bbt; + #address-cells = <1>; + #size-cells = <1>; + }; + }; + }; + +... -- cgit v1.2.3 From 66b8173a197fb754a54798820f1e46f3d9df7819 Mon Sep 17 00:00:00 2001 From: Christophe Kerello Date: Fri, 12 Jun 2020 17:22:40 +0200 Subject: memory: stm32-fmc2-ebi: add STM32 FMC2 EBI controller driver The driver adds the support for the STMicroelectronics FMC2 EBI controller found on STM32MP SOCs. Signed-off-by: Christophe Kerello Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/1591975362-22009-5-git-send-email-christophe.kerello@st.com --- drivers/memory/Kconfig | 10 + drivers/memory/Makefile | 1 + drivers/memory/stm32-fmc2-ebi.c | 1206 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 1217 insertions(+) create mode 100644 drivers/memory/stm32-fmc2-ebi.c diff --git a/drivers/memory/Kconfig b/drivers/memory/Kconfig index 04368ee2a809..be69c07b8941 100644 --- a/drivers/memory/Kconfig +++ b/drivers/memory/Kconfig @@ -174,6 +174,16 @@ config PL353_SMC This driver is for the ARM PL351/PL353 Static Memory Controller(SMC) module. +config STM32_FMC2_EBI + tristate "Support for FMC2 External Bus Interface on STM32MP SoCs" + depends on MACH_STM32MP157 || COMPILE_TEST + select MFD_SYSCON + help + Select this option to enable the STM32 FMC2 External Bus Interface + controller. This driver configures the transactions with external + devices (like SRAM, ethernet adapters, FPGAs, LCD displays, ...) on + SOCs containing the FMC2 External Bus Interface. + source "drivers/memory/samsung/Kconfig" source "drivers/memory/tegra/Kconfig" diff --git a/drivers/memory/Makefile b/drivers/memory/Makefile index 6d7e3e64ba62..d3d8d6ced342 100644 --- a/drivers/memory/Makefile +++ b/drivers/memory/Makefile @@ -22,6 +22,7 @@ obj-$(CONFIG_JZ4780_NEMC) += jz4780-nemc.o obj-$(CONFIG_MTK_SMI) += mtk-smi.o obj-$(CONFIG_DA8XX_DDRCTL) += da8xx-ddrctl.o obj-$(CONFIG_PL353_SMC) += pl353-smc.o +obj-$(CONFIG_STM32_FMC2_EBI) += stm32-fmc2-ebi.o obj-$(CONFIG_SAMSUNG_MC) += samsung/ obj-$(CONFIG_TEGRA_MC) += tegra/ diff --git a/drivers/memory/stm32-fmc2-ebi.c b/drivers/memory/stm32-fmc2-ebi.c new file mode 100644 index 000000000000..4d5758c419c5 --- /dev/null +++ b/drivers/memory/stm32-fmc2-ebi.c @@ -0,0 +1,1206 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) STMicroelectronics 2020 + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* FMC2 Controller Registers */ +#define FMC2_BCR1 0x0 +#define FMC2_BTR1 0x4 +#define FMC2_BCR(x) ((x) * 0x8 + FMC2_BCR1) +#define FMC2_BTR(x) ((x) * 0x8 + FMC2_BTR1) +#define FMC2_PCSCNTR 0x20 +#define FMC2_BWTR1 0x104 +#define FMC2_BWTR(x) ((x) * 0x8 + FMC2_BWTR1) + +/* Register: FMC2_BCR1 */ +#define FMC2_BCR1_CCLKEN BIT(20) +#define FMC2_BCR1_FMC2EN BIT(31) + +/* Register: FMC2_BCRx */ +#define FMC2_BCR_MBKEN BIT(0) +#define FMC2_BCR_MUXEN BIT(1) +#define FMC2_BCR_MTYP GENMASK(3, 2) +#define FMC2_BCR_MWID GENMASK(5, 4) +#define FMC2_BCR_FACCEN BIT(6) +#define FMC2_BCR_BURSTEN BIT(8) +#define FMC2_BCR_WAITPOL BIT(9) +#define FMC2_BCR_WAITCFG BIT(11) +#define FMC2_BCR_WREN BIT(12) +#define FMC2_BCR_WAITEN BIT(13) +#define FMC2_BCR_EXTMOD BIT(14) +#define FMC2_BCR_ASYNCWAIT BIT(15) +#define FMC2_BCR_CPSIZE GENMASK(18, 16) +#define FMC2_BCR_CBURSTRW BIT(19) +#define FMC2_BCR_NBLSET GENMASK(23, 22) + +/* Register: FMC2_BTRx/FMC2_BWTRx */ +#define FMC2_BXTR_ADDSET GENMASK(3, 0) +#define FMC2_BXTR_ADDHLD GENMASK(7, 4) +#define FMC2_BXTR_DATAST GENMASK(15, 8) +#define FMC2_BXTR_BUSTURN GENMASK(19, 16) +#define FMC2_BTR_CLKDIV GENMASK(23, 20) +#define FMC2_BTR_DATLAT GENMASK(27, 24) +#define FMC2_BXTR_ACCMOD GENMASK(29, 28) +#define FMC2_BXTR_DATAHLD GENMASK(31, 30) + +/* Register: FMC2_PCSCNTR */ +#define FMC2_PCSCNTR_CSCOUNT GENMASK(15, 0) +#define FMC2_PCSCNTR_CNTBEN(x) BIT((x) + 16) + +#define FMC2_MAX_EBI_CE 4 +#define FMC2_MAX_BANKS 5 + +#define FMC2_BCR_CPSIZE_0 0x0 +#define FMC2_BCR_CPSIZE_128 0x1 +#define FMC2_BCR_CPSIZE_256 0x2 +#define FMC2_BCR_CPSIZE_512 0x3 +#define FMC2_BCR_CPSIZE_1024 0x4 + +#define FMC2_BCR_MWID_8 0x0 +#define FMC2_BCR_MWID_16 0x1 + +#define FMC2_BCR_MTYP_SRAM 0x0 +#define FMC2_BCR_MTYP_PSRAM 0x1 +#define FMC2_BCR_MTYP_NOR 0x2 + +#define FMC2_BXTR_EXTMOD_A 0x0 +#define FMC2_BXTR_EXTMOD_B 0x1 +#define FMC2_BXTR_EXTMOD_C 0x2 +#define FMC2_BXTR_EXTMOD_D 0x3 + +#define FMC2_BCR_NBLSET_MAX 0x3 +#define FMC2_BXTR_ADDSET_MAX 0xf +#define FMC2_BXTR_ADDHLD_MAX 0xf +#define FMC2_BXTR_DATAST_MAX 0xff +#define FMC2_BXTR_BUSTURN_MAX 0xf +#define FMC2_BXTR_DATAHLD_MAX 0x3 +#define FMC2_BTR_CLKDIV_MAX 0xf +#define FMC2_BTR_DATLAT_MAX 0xf +#define FMC2_PCSCNTR_CSCOUNT_MAX 0xff + +enum stm32_fmc2_ebi_bank { + FMC2_EBI1 = 0, + FMC2_EBI2, + FMC2_EBI3, + FMC2_EBI4, + FMC2_NAND +}; + +enum stm32_fmc2_ebi_register_type { + FMC2_REG_BCR = 1, + FMC2_REG_BTR, + FMC2_REG_BWTR, + FMC2_REG_PCSCNTR +}; + +enum stm32_fmc2_ebi_transaction_type { + FMC2_ASYNC_MODE_1_SRAM = 0, + FMC2_ASYNC_MODE_1_PSRAM, + FMC2_ASYNC_MODE_A_SRAM, + FMC2_ASYNC_MODE_A_PSRAM, + FMC2_ASYNC_MODE_2_NOR, + FMC2_ASYNC_MODE_B_NOR, + FMC2_ASYNC_MODE_C_NOR, + FMC2_ASYNC_MODE_D_NOR, + FMC2_SYNC_READ_SYNC_WRITE_PSRAM, + FMC2_SYNC_READ_ASYNC_WRITE_PSRAM, + FMC2_SYNC_READ_SYNC_WRITE_NOR, + FMC2_SYNC_READ_ASYNC_WRITE_NOR +}; + +enum stm32_fmc2_ebi_buswidth { + FMC2_BUSWIDTH_8 = 8, + FMC2_BUSWIDTH_16 = 16 +}; + +enum stm32_fmc2_ebi_cpsize { + FMC2_CPSIZE_0 = 0, + FMC2_CPSIZE_128 = 128, + FMC2_CPSIZE_256 = 256, + FMC2_CPSIZE_512 = 512, + FMC2_CPSIZE_1024 = 1024 +}; + +struct stm32_fmc2_ebi { + struct device *dev; + struct clk *clk; + struct regmap *regmap; + u8 bank_assigned; + + u32 bcr[FMC2_MAX_EBI_CE]; + u32 btr[FMC2_MAX_EBI_CE]; + u32 bwtr[FMC2_MAX_EBI_CE]; + u32 pcscntr; +}; + +/* + * struct stm32_fmc2_prop - STM32 FMC2 EBI property + * @name: the device tree binding name of the property + * @bprop: indicate that it is a boolean property + * @mprop: indicate that it is a mandatory property + * @reg_type: the register that have to be modified + * @reg_mask: the bit that have to be modified in the selected register + * in case of it is a boolean property + * @reset_val: the default value that have to be set in case the property + * has not been defined in the device tree + * @check: this callback ckecks that the property is compliant with the + * transaction type selected + * @calculate: this callback is called to calculate for exemple a timing + * set in nanoseconds in the device tree in clock cycles or in + * clock period + * @set: this callback applies the values in the registers + */ +struct stm32_fmc2_prop { + const char *name; + bool bprop; + bool mprop; + int reg_type; + u32 reg_mask; + u32 reset_val; + int (*check)(struct stm32_fmc2_ebi *ebi, + const struct stm32_fmc2_prop *prop, int cs); + u32 (*calculate)(struct stm32_fmc2_ebi *ebi, int cs, u32 setup); + int (*set)(struct stm32_fmc2_ebi *ebi, + const struct stm32_fmc2_prop *prop, + int cs, u32 setup); +}; + +static int stm32_fmc2_ebi_check_mux(struct stm32_fmc2_ebi *ebi, + const struct stm32_fmc2_prop *prop, + int cs) +{ + u32 bcr; + + regmap_read(ebi->regmap, FMC2_BCR(cs), &bcr); + + if (bcr & FMC2_BCR_MTYP) + return 0; + + return -EINVAL; +} + +static int stm32_fmc2_ebi_check_waitcfg(struct stm32_fmc2_ebi *ebi, + const struct stm32_fmc2_prop *prop, + int cs) +{ + u32 bcr, val = FIELD_PREP(FMC2_BCR_MTYP, FMC2_BCR_MTYP_NOR); + + regmap_read(ebi->regmap, FMC2_BCR(cs), &bcr); + + if ((bcr & FMC2_BCR_MTYP) == val && bcr & FMC2_BCR_BURSTEN) + return 0; + + return -EINVAL; +} + +static int stm32_fmc2_ebi_check_sync_trans(struct stm32_fmc2_ebi *ebi, + const struct stm32_fmc2_prop *prop, + int cs) +{ + u32 bcr; + + regmap_read(ebi->regmap, FMC2_BCR(cs), &bcr); + + if (bcr & FMC2_BCR_BURSTEN) + return 0; + + return -EINVAL; +} + +static int stm32_fmc2_ebi_check_async_trans(struct stm32_fmc2_ebi *ebi, + const struct stm32_fmc2_prop *prop, + int cs) +{ + u32 bcr; + + regmap_read(ebi->regmap, FMC2_BCR(cs), &bcr); + + if (!(bcr & FMC2_BCR_BURSTEN) || !(bcr & FMC2_BCR_CBURSTRW)) + return 0; + + return -EINVAL; +} + +static int stm32_fmc2_ebi_check_cpsize(struct stm32_fmc2_ebi *ebi, + const struct stm32_fmc2_prop *prop, + int cs) +{ + u32 bcr, val = FIELD_PREP(FMC2_BCR_MTYP, FMC2_BCR_MTYP_PSRAM); + + regmap_read(ebi->regmap, FMC2_BCR(cs), &bcr); + + if ((bcr & FMC2_BCR_MTYP) == val && bcr & FMC2_BCR_BURSTEN) + return 0; + + return -EINVAL; +} + +static int stm32_fmc2_ebi_check_address_hold(struct stm32_fmc2_ebi *ebi, + const struct stm32_fmc2_prop *prop, + int cs) +{ + u32 bcr, bxtr, val = FIELD_PREP(FMC2_BXTR_ACCMOD, FMC2_BXTR_EXTMOD_D); + + regmap_read(ebi->regmap, FMC2_BCR(cs), &bcr); + if (prop->reg_type == FMC2_REG_BWTR) + regmap_read(ebi->regmap, FMC2_BWTR(cs), &bxtr); + else + regmap_read(ebi->regmap, FMC2_BTR(cs), &bxtr); + + if ((!(bcr & FMC2_BCR_BURSTEN) || !(bcr & FMC2_BCR_CBURSTRW)) && + ((bxtr & FMC2_BXTR_ACCMOD) == val || bcr & FMC2_BCR_MUXEN)) + return 0; + + return -EINVAL; +} + +static int stm32_fmc2_ebi_check_clk_period(struct stm32_fmc2_ebi *ebi, + const struct stm32_fmc2_prop *prop, + int cs) +{ + u32 bcr, bcr1; + + regmap_read(ebi->regmap, FMC2_BCR(cs), &bcr); + if (cs) + regmap_read(ebi->regmap, FMC2_BCR1, &bcr1); + else + bcr1 = bcr; + + if (bcr & FMC2_BCR_BURSTEN && (!cs || !(bcr1 & FMC2_BCR1_CCLKEN))) + return 0; + + return -EINVAL; +} + +static int stm32_fmc2_ebi_check_cclk(struct stm32_fmc2_ebi *ebi, + const struct stm32_fmc2_prop *prop, + int cs) +{ + if (cs) + return -EINVAL; + + return stm32_fmc2_ebi_check_sync_trans(ebi, prop, cs); +} + +static u32 stm32_fmc2_ebi_ns_to_clock_cycles(struct stm32_fmc2_ebi *ebi, + int cs, u32 setup) +{ + unsigned long hclk = clk_get_rate(ebi->clk); + unsigned long hclkp = NSEC_PER_SEC / (hclk / 1000); + + return DIV_ROUND_UP(setup * 1000, hclkp); +} + +static u32 stm32_fmc2_ebi_ns_to_clk_period(struct stm32_fmc2_ebi *ebi, + int cs, u32 setup) +{ + u32 nb_clk_cycles = stm32_fmc2_ebi_ns_to_clock_cycles(ebi, cs, setup); + u32 bcr, btr, clk_period; + + regmap_read(ebi->regmap, FMC2_BCR1, &bcr); + if (bcr & FMC2_BCR1_CCLKEN || !cs) + regmap_read(ebi->regmap, FMC2_BTR1, &btr); + else + regmap_read(ebi->regmap, FMC2_BTR(cs), &btr); + + clk_period = FIELD_GET(FMC2_BTR_CLKDIV, btr) + 1; + + return DIV_ROUND_UP(nb_clk_cycles, clk_period); +} + +static int stm32_fmc2_ebi_get_reg(int reg_type, int cs, u32 *reg) +{ + switch (reg_type) { + case FMC2_REG_BCR: + *reg = FMC2_BCR(cs); + break; + case FMC2_REG_BTR: + *reg = FMC2_BTR(cs); + break; + case FMC2_REG_BWTR: + *reg = FMC2_BWTR(cs); + break; + case FMC2_REG_PCSCNTR: + *reg = FMC2_PCSCNTR; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int stm32_fmc2_ebi_set_bit_field(struct stm32_fmc2_ebi *ebi, + const struct stm32_fmc2_prop *prop, + int cs, u32 setup) +{ + u32 reg; + int ret; + + ret = stm32_fmc2_ebi_get_reg(prop->reg_type, cs, ®); + if (ret) + return ret; + + regmap_update_bits(ebi->regmap, reg, prop->reg_mask, + setup ? prop->reg_mask : 0); + + return 0; +} + +static int stm32_fmc2_ebi_set_trans_type(struct stm32_fmc2_ebi *ebi, + const struct stm32_fmc2_prop *prop, + int cs, u32 setup) +{ + u32 bcr_mask, bcr = FMC2_BCR_WREN; + u32 btr_mask, btr = 0; + u32 bwtr_mask, bwtr = 0; + + bwtr_mask = FMC2_BXTR_ACCMOD; + btr_mask = FMC2_BXTR_ACCMOD; + bcr_mask = FMC2_BCR_MUXEN | FMC2_BCR_MTYP | FMC2_BCR_FACCEN | + FMC2_BCR_WREN | FMC2_BCR_WAITEN | FMC2_BCR_BURSTEN | + FMC2_BCR_EXTMOD | FMC2_BCR_CBURSTRW; + + switch (setup) { + case FMC2_ASYNC_MODE_1_SRAM: + bcr |= FIELD_PREP(FMC2_BCR_MTYP, FMC2_BCR_MTYP_SRAM); + /* + * MUXEN = 0, MTYP = 0, FACCEN = 0, BURSTEN = 0, WAITEN = 0, + * WREN = 1, EXTMOD = 0, CBURSTRW = 0, ACCMOD = 0 + */ + break; + case FMC2_ASYNC_MODE_1_PSRAM: + /* + * MUXEN = 0, MTYP = 1, FACCEN = 0, BURSTEN = 0, WAITEN = 0, + * WREN = 1, EXTMOD = 0, CBURSTRW = 0, ACCMOD = 0 + */ + bcr |= FIELD_PREP(FMC2_BCR_MTYP, FMC2_BCR_MTYP_PSRAM); + break; + case FMC2_ASYNC_MODE_A_SRAM: + /* + * MUXEN = 0, MTYP = 0, FACCEN = 0, BURSTEN = 0, WAITEN = 0, + * WREN = 1, EXTMOD = 1, CBURSTRW = 0, ACCMOD = 0 + */ + bcr |= FIELD_PREP(FMC2_BCR_MTYP, FMC2_BCR_MTYP_SRAM); + bcr |= FMC2_BCR_EXTMOD; + btr |= FIELD_PREP(FMC2_BXTR_ACCMOD, FMC2_BXTR_EXTMOD_A); + bwtr |= FIELD_PREP(FMC2_BXTR_ACCMOD, FMC2_BXTR_EXTMOD_A); + break; + case FMC2_ASYNC_MODE_A_PSRAM: + /* + * MUXEN = 0, MTYP = 1, FACCEN = 0, BURSTEN = 0, WAITEN = 0, + * WREN = 1, EXTMOD = 1, CBURSTRW = 0, ACCMOD = 0 + */ + bcr |= FIELD_PREP(FMC2_BCR_MTYP, FMC2_BCR_MTYP_PSRAM); + bcr |= FMC2_BCR_EXTMOD; + btr |= FIELD_PREP(FMC2_BXTR_ACCMOD, FMC2_BXTR_EXTMOD_A); + bwtr |= FIELD_PREP(FMC2_BXTR_ACCMOD, FMC2_BXTR_EXTMOD_A); + break; + case FMC2_ASYNC_MODE_2_NOR: + /* + * MUXEN = 0, MTYP = 2, FACCEN = 1, BURSTEN = 0, WAITEN = 0, + * WREN = 1, EXTMOD = 0, CBURSTRW = 0, ACCMOD = 0 + */ + bcr |= FIELD_PREP(FMC2_BCR_MTYP, FMC2_BCR_MTYP_NOR); + bcr |= FMC2_BCR_FACCEN; + break; + case FMC2_ASYNC_MODE_B_NOR: + /* + * MUXEN = 0, MTYP = 2, FACCEN = 1, BURSTEN = 0, WAITEN = 0, + * WREN = 1, EXTMOD = 1, CBURSTRW = 0, ACCMOD = 1 + */ + bcr |= FIELD_PREP(FMC2_BCR_MTYP, FMC2_BCR_MTYP_NOR); + bcr |= FMC2_BCR_FACCEN | FMC2_BCR_EXTMOD; + btr |= FIELD_PREP(FMC2_BXTR_ACCMOD, FMC2_BXTR_EXTMOD_B); + bwtr |= FIELD_PREP(FMC2_BXTR_ACCMOD, FMC2_BXTR_EXTMOD_B); + break; + case FMC2_ASYNC_MODE_C_NOR: + /* + * MUXEN = 0, MTYP = 2, FACCEN = 1, BURSTEN = 0, WAITEN = 0, + * WREN = 1, EXTMOD = 1, CBURSTRW = 0, ACCMOD = 2 + */ + bcr |= FIELD_PREP(FMC2_BCR_MTYP, FMC2_BCR_MTYP_NOR); + bcr |= FMC2_BCR_FACCEN | FMC2_BCR_EXTMOD; + btr |= FIELD_PREP(FMC2_BXTR_ACCMOD, FMC2_BXTR_EXTMOD_C); + bwtr |= FIELD_PREP(FMC2_BXTR_ACCMOD, FMC2_BXTR_EXTMOD_C); + break; + case FMC2_ASYNC_MODE_D_NOR: + /* + * MUXEN = 0, MTYP = 2, FACCEN = 1, BURSTEN = 0, WAITEN = 0, + * WREN = 1, EXTMOD = 1, CBURSTRW = 0, ACCMOD = 3 + */ + bcr |= FIELD_PREP(FMC2_BCR_MTYP, FMC2_BCR_MTYP_NOR); + bcr |= FMC2_BCR_FACCEN | FMC2_BCR_EXTMOD; + btr |= FIELD_PREP(FMC2_BXTR_ACCMOD, FMC2_BXTR_EXTMOD_D); + bwtr |= FIELD_PREP(FMC2_BXTR_ACCMOD, FMC2_BXTR_EXTMOD_D); + break; + case FMC2_SYNC_READ_SYNC_WRITE_PSRAM: + /* + * MUXEN = 0, MTYP = 1, FACCEN = 0, BURSTEN = 1, WAITEN = 0, + * WREN = 1, EXTMOD = 0, CBURSTRW = 1, ACCMOD = 0 + */ + bcr |= FIELD_PREP(FMC2_BCR_MTYP, FMC2_BCR_MTYP_PSRAM); + bcr |= FMC2_BCR_BURSTEN | FMC2_BCR_CBURSTRW; + break; + case FMC2_SYNC_READ_ASYNC_WRITE_PSRAM: + /* + * MUXEN = 0, MTYP = 1, FACCEN = 0, BURSTEN = 1, WAITEN = 0, + * WREN = 1, EXTMOD = 0, CBURSTRW = 0, ACCMOD = 0 + */ + bcr |= FIELD_PREP(FMC2_BCR_MTYP, FMC2_BCR_MTYP_PSRAM); + bcr |= FMC2_BCR_BURSTEN; + break; + case FMC2_SYNC_READ_SYNC_WRITE_NOR: + /* + * MUXEN = 0, MTYP = 2, FACCEN = 1, BURSTEN = 1, WAITEN = 0, + * WREN = 1, EXTMOD = 0, CBURSTRW = 1, ACCMOD = 0 + */ + bcr |= FIELD_PREP(FMC2_BCR_MTYP, FMC2_BCR_MTYP_NOR); + bcr |= FMC2_BCR_FACCEN | FMC2_BCR_BURSTEN | FMC2_BCR_CBURSTRW; + break; + case FMC2_SYNC_READ_ASYNC_WRITE_NOR: + /* + * MUXEN = 0, MTYP = 2, FACCEN = 1, BURSTEN = 1, WAITEN = 0, + * WREN = 1, EXTMOD = 0, CBURSTRW = 0, ACCMOD = 0 + */ + bcr |= FIELD_PREP(FMC2_BCR_MTYP, FMC2_BCR_MTYP_NOR); + bcr |= FMC2_BCR_FACCEN | FMC2_BCR_BURSTEN; + break; + default: + /* Type of transaction not supported */ + return -EINVAL; + } + + if (bcr & FMC2_BCR_EXTMOD) + regmap_update_bits(ebi->regmap, FMC2_BWTR(cs), + bwtr_mask, bwtr); + regmap_update_bits(ebi->regmap, FMC2_BTR(cs), btr_mask, btr); + regmap_update_bits(ebi->regmap, FMC2_BCR(cs), bcr_mask, bcr); + + return 0; +} + +static int stm32_fmc2_ebi_set_buswidth(struct stm32_fmc2_ebi *ebi, + const struct stm32_fmc2_prop *prop, + int cs, u32 setup) +{ + u32 val; + + switch (setup) { + case FMC2_BUSWIDTH_8: + val = FIELD_PREP(FMC2_BCR_MWID, FMC2_BCR_MWID_8); + break; + case FMC2_BUSWIDTH_16: + val = FIELD_PREP(FMC2_BCR_MWID, FMC2_BCR_MWID_16); + break; + default: + /* Buswidth not supported */ + return -EINVAL; + } + + regmap_update_bits(ebi->regmap, FMC2_BCR(cs), FMC2_BCR_MWID, val); + + return 0; +} + +static int stm32_fmc2_ebi_set_cpsize(struct stm32_fmc2_ebi *ebi, + const struct stm32_fmc2_prop *prop, + int cs, u32 setup) +{ + u32 val; + + switch (setup) { + case FMC2_CPSIZE_0: + val = FIELD_PREP(FMC2_BCR_CPSIZE, FMC2_BCR_CPSIZE_0); + break; + case FMC2_CPSIZE_128: + val = FIELD_PREP(FMC2_BCR_CPSIZE, FMC2_BCR_CPSIZE_128); + break; + case FMC2_CPSIZE_256: + val = FIELD_PREP(FMC2_BCR_CPSIZE, FMC2_BCR_CPSIZE_256); + break; + case FMC2_CPSIZE_512: + val = FIELD_PREP(FMC2_BCR_CPSIZE, FMC2_BCR_CPSIZE_512); + break; + case FMC2_CPSIZE_1024: + val = FIELD_PREP(FMC2_BCR_CPSIZE, FMC2_BCR_CPSIZE_1024); + break; + default: + /* Cpsize not supported */ + return -EINVAL; + } + + regmap_update_bits(ebi->regmap, FMC2_BCR(cs), FMC2_BCR_CPSIZE, val); + + return 0; +} + +static int stm32_fmc2_ebi_set_bl_setup(struct stm32_fmc2_ebi *ebi, + const struct stm32_fmc2_prop *prop, + int cs, u32 setup) +{ + u32 val; + + val = min_t(u32, setup, FMC2_BCR_NBLSET_MAX); + val = FIELD_PREP(FMC2_BCR_NBLSET, val); + regmap_update_bits(ebi->regmap, FMC2_BCR(cs), FMC2_BCR_NBLSET, val); + + return 0; +} + +static int stm32_fmc2_ebi_set_address_setup(struct stm32_fmc2_ebi *ebi, + const struct stm32_fmc2_prop *prop, + int cs, u32 setup) +{ + u32 bcr, bxtr, reg; + u32 val = FIELD_PREP(FMC2_BXTR_ACCMOD, FMC2_BXTR_EXTMOD_D); + int ret; + + ret = stm32_fmc2_ebi_get_reg(prop->reg_type, cs, ®); + if (ret) + return ret; + + regmap_read(ebi->regmap, FMC2_BCR(cs), &bcr); + if (prop->reg_type == FMC2_REG_BWTR) + regmap_read(ebi->regmap, FMC2_BWTR(cs), &bxtr); + else + regmap_read(ebi->regmap, FMC2_BTR(cs), &bxtr); + + if ((bxtr & FMC2_BXTR_ACCMOD) == val || bcr & FMC2_BCR_MUXEN) + val = clamp_val(setup, 1, FMC2_BXTR_ADDSET_MAX); + else + val = min_t(u32, setup, FMC2_BXTR_ADDSET_MAX); + val = FIELD_PREP(FMC2_BXTR_ADDSET, val); + regmap_update_bits(ebi->regmap, reg, FMC2_BXTR_ADDSET, val); + + return 0; +} + +static int stm32_fmc2_ebi_set_address_hold(struct stm32_fmc2_ebi *ebi, + const struct stm32_fmc2_prop *prop, + int cs, u32 setup) +{ + u32 val, reg; + int ret; + + ret = stm32_fmc2_ebi_get_reg(prop->reg_type, cs, ®); + if (ret) + return ret; + + val = clamp_val(setup, 1, FMC2_BXTR_ADDHLD_MAX); + val = FIELD_PREP(FMC2_BXTR_ADDHLD, val); + regmap_update_bits(ebi->regmap, reg, FMC2_BXTR_ADDHLD, val); + + return 0; +} + +static int stm32_fmc2_ebi_set_data_setup(struct stm32_fmc2_ebi *ebi, + const struct stm32_fmc2_prop *prop, + int cs, u32 setup) +{ + u32 val, reg; + int ret; + + ret = stm32_fmc2_ebi_get_reg(prop->reg_type, cs, ®); + if (ret) + return ret; + + val = clamp_val(setup, 1, FMC2_BXTR_DATAST_MAX); + val = FIELD_PREP(FMC2_BXTR_DATAST, val); + regmap_update_bits(ebi->regmap, reg, FMC2_BXTR_DATAST, val); + + return 0; +} + +static int stm32_fmc2_ebi_set_bus_turnaround(struct stm32_fmc2_ebi *ebi, + const struct stm32_fmc2_prop *prop, + int cs, u32 setup) +{ + u32 val, reg; + int ret; + + ret = stm32_fmc2_ebi_get_reg(prop->reg_type, cs, ®); + if (ret) + return ret; + + val = setup ? min_t(u32, setup - 1, FMC2_BXTR_BUSTURN_MAX) : 0; + val = FIELD_PREP(FMC2_BXTR_BUSTURN, val); + regmap_update_bits(ebi->regmap, reg, FMC2_BXTR_BUSTURN, val); + + return 0; +} + +static int stm32_fmc2_ebi_set_data_hold(struct stm32_fmc2_ebi *ebi, + const struct stm32_fmc2_prop *prop, + int cs, u32 setup) +{ + u32 val, reg; + int ret; + + ret = stm32_fmc2_ebi_get_reg(prop->reg_type, cs, ®); + if (ret) + return ret; + + if (prop->reg_type == FMC2_REG_BWTR) + val = setup ? min_t(u32, setup - 1, FMC2_BXTR_DATAHLD_MAX) : 0; + else + val = min_t(u32, setup, FMC2_BXTR_DATAHLD_MAX); + val = FIELD_PREP(FMC2_BXTR_DATAHLD, val); + regmap_update_bits(ebi->regmap, reg, FMC2_BXTR_DATAHLD, val); + + return 0; +} + +static int stm32_fmc2_ebi_set_clk_period(struct stm32_fmc2_ebi *ebi, + const struct stm32_fmc2_prop *prop, + int cs, u32 setup) +{ + u32 val; + + val = setup ? clamp_val(setup - 1, 1, FMC2_BTR_CLKDIV_MAX) : 1; + val = FIELD_PREP(FMC2_BTR_CLKDIV, val); + regmap_update_bits(ebi->regmap, FMC2_BTR(cs), FMC2_BTR_CLKDIV, val); + + return 0; +} + +static int stm32_fmc2_ebi_set_data_latency(struct stm32_fmc2_ebi *ebi, + const struct stm32_fmc2_prop *prop, + int cs, u32 setup) +{ + u32 val; + + val = setup > 1 ? min_t(u32, setup - 2, FMC2_BTR_DATLAT_MAX) : 0; + val = FIELD_PREP(FMC2_BTR_DATLAT, val); + regmap_update_bits(ebi->regmap, FMC2_BTR(cs), FMC2_BTR_DATLAT, val); + + return 0; +} + +static int stm32_fmc2_ebi_set_max_low_pulse(struct stm32_fmc2_ebi *ebi, + const struct stm32_fmc2_prop *prop, + int cs, u32 setup) +{ + u32 old_val, new_val, pcscntr; + + if (setup < 1) + return 0; + + regmap_read(ebi->regmap, FMC2_PCSCNTR, &pcscntr); + + /* Enable counter for the bank */ + regmap_update_bits(ebi->regmap, FMC2_PCSCNTR, + FMC2_PCSCNTR_CNTBEN(cs), + FMC2_PCSCNTR_CNTBEN(cs)); + + new_val = min_t(u32, setup - 1, FMC2_PCSCNTR_CSCOUNT_MAX); + old_val = FIELD_GET(FMC2_PCSCNTR_CSCOUNT, pcscntr); + if (old_val && new_val > old_val) + /* Keep current counter value */ + return 0; + + new_val = FIELD_PREP(FMC2_PCSCNTR_CSCOUNT, new_val); + regmap_update_bits(ebi->regmap, FMC2_PCSCNTR, + FMC2_PCSCNTR_CSCOUNT, new_val); + + return 0; +} + +static const struct stm32_fmc2_prop stm32_fmc2_child_props[] = { + /* st,fmc2-ebi-cs-trans-type must be the first property */ + { + .name = "st,fmc2-ebi-cs-transaction-type", + .mprop = true, + .set = stm32_fmc2_ebi_set_trans_type, + }, + { + .name = "st,fmc2-ebi-cs-cclk-enable", + .bprop = true, + .reg_type = FMC2_REG_BCR, + .reg_mask = FMC2_BCR1_CCLKEN, + .check = stm32_fmc2_ebi_check_cclk, + .set = stm32_fmc2_ebi_set_bit_field, + }, + { + .name = "st,fmc2-ebi-cs-mux-enable", + .bprop = true, + .reg_type = FMC2_REG_BCR, + .reg_mask = FMC2_BCR_MUXEN, + .check = stm32_fmc2_ebi_check_mux, + .set = stm32_fmc2_ebi_set_bit_field, + }, + { + .name = "st,fmc2-ebi-cs-buswidth", + .reset_val = FMC2_BUSWIDTH_16, + .set = stm32_fmc2_ebi_set_buswidth, + }, + { + .name = "st,fmc2-ebi-cs-waitpol-high", + .bprop = true, + .reg_type = FMC2_REG_BCR, + .reg_mask = FMC2_BCR_WAITPOL, + .set = stm32_fmc2_ebi_set_bit_field, + }, + { + .name = "st,fmc2-ebi-cs-waitcfg-enable", + .bprop = true, + .reg_type = FMC2_REG_BCR, + .reg_mask = FMC2_BCR_WAITCFG, + .check = stm32_fmc2_ebi_check_waitcfg, + .set = stm32_fmc2_ebi_set_bit_field, + }, + { + .name = "st,fmc2-ebi-cs-wait-enable", + .bprop = true, + .reg_type = FMC2_REG_BCR, + .reg_mask = FMC2_BCR_WAITEN, + .check = stm32_fmc2_ebi_check_sync_trans, + .set = stm32_fmc2_ebi_set_bit_field, + }, + { + .name = "st,fmc2-ebi-cs-asyncwait-enable", + .bprop = true, + .reg_type = FMC2_REG_BCR, + .reg_mask = FMC2_BCR_ASYNCWAIT, + .check = stm32_fmc2_ebi_check_async_trans, + .set = stm32_fmc2_ebi_set_bit_field, + }, + { + .name = "st,fmc2-ebi-cs-cpsize", + .check = stm32_fmc2_ebi_check_cpsize, + .set = stm32_fmc2_ebi_set_cpsize, + }, + { + .name = "st,fmc2-ebi-cs-byte-lane-setup-ns", + .calculate = stm32_fmc2_ebi_ns_to_clock_cycles, + .set = stm32_fmc2_ebi_set_bl_setup, + }, + { + .name = "st,fmc2-ebi-cs-address-setup-ns", + .reg_type = FMC2_REG_BTR, + .reset_val = FMC2_BXTR_ADDSET_MAX, + .check = stm32_fmc2_ebi_check_async_trans, + .calculate = stm32_fmc2_ebi_ns_to_clock_cycles, + .set = stm32_fmc2_ebi_set_address_setup, + }, + { + .name = "st,fmc2-ebi-cs-address-hold-ns", + .reg_type = FMC2_REG_BTR, + .reset_val = FMC2_BXTR_ADDHLD_MAX, + .check = stm32_fmc2_ebi_check_address_hold, + .calculate = stm32_fmc2_ebi_ns_to_clock_cycles, + .set = stm32_fmc2_ebi_set_address_hold, + }, + { + .name = "st,fmc2-ebi-cs-data-setup-ns", + .reg_type = FMC2_REG_BTR, + .reset_val = FMC2_BXTR_DATAST_MAX, + .check = stm32_fmc2_ebi_check_async_trans, + .calculate = stm32_fmc2_ebi_ns_to_clock_cycles, + .set = stm32_fmc2_ebi_set_data_setup, + }, + { + .name = "st,fmc2-ebi-cs-bus-turnaround-ns", + .reg_type = FMC2_REG_BTR, + .reset_val = FMC2_BXTR_BUSTURN_MAX + 1, + .calculate = stm32_fmc2_ebi_ns_to_clock_cycles, + .set = stm32_fmc2_ebi_set_bus_turnaround, + }, + { + .name = "st,fmc2-ebi-cs-data-hold-ns", + .reg_type = FMC2_REG_BTR, + .check = stm32_fmc2_ebi_check_async_trans, + .calculate = stm32_fmc2_ebi_ns_to_clock_cycles, + .set = stm32_fmc2_ebi_set_data_hold, + }, + { + .name = "st,fmc2-ebi-cs-clk-period-ns", + .reset_val = FMC2_BTR_CLKDIV_MAX + 1, + .check = stm32_fmc2_ebi_check_clk_period, + .calculate = stm32_fmc2_ebi_ns_to_clock_cycles, + .set = stm32_fmc2_ebi_set_clk_period, + }, + { + .name = "st,fmc2-ebi-cs-data-latency-ns", + .check = stm32_fmc2_ebi_check_sync_trans, + .calculate = stm32_fmc2_ebi_ns_to_clk_period, + .set = stm32_fmc2_ebi_set_data_latency, + }, + { + .name = "st,fmc2-ebi-cs-write-address-setup-ns", + .reg_type = FMC2_REG_BWTR, + .reset_val = FMC2_BXTR_ADDSET_MAX, + .check = stm32_fmc2_ebi_check_async_trans, + .calculate = stm32_fmc2_ebi_ns_to_clock_cycles, + .set = stm32_fmc2_ebi_set_address_setup, + }, + { + .name = "st,fmc2-ebi-cs-write-address-hold-ns", + .reg_type = FMC2_REG_BWTR, + .reset_val = FMC2_BXTR_ADDHLD_MAX, + .check = stm32_fmc2_ebi_check_address_hold, + .calculate = stm32_fmc2_ebi_ns_to_clock_cycles, + .set = stm32_fmc2_ebi_set_address_hold, + }, + { + .name = "st,fmc2-ebi-cs-write-data-setup-ns", + .reg_type = FMC2_REG_BWTR, + .reset_val = FMC2_BXTR_DATAST_MAX, + .check = stm32_fmc2_ebi_check_async_trans, + .calculate = stm32_fmc2_ebi_ns_to_clock_cycles, + .set = stm32_fmc2_ebi_set_data_setup, + }, + { + .name = "st,fmc2-ebi-cs-write-bus-turnaround-ns", + .reg_type = FMC2_REG_BWTR, + .reset_val = FMC2_BXTR_BUSTURN_MAX + 1, + .calculate = stm32_fmc2_ebi_ns_to_clock_cycles, + .set = stm32_fmc2_ebi_set_bus_turnaround, + }, + { + .name = "st,fmc2-ebi-cs-write-data-hold-ns", + .reg_type = FMC2_REG_BWTR, + .check = stm32_fmc2_ebi_check_async_trans, + .calculate = stm32_fmc2_ebi_ns_to_clock_cycles, + .set = stm32_fmc2_ebi_set_data_hold, + }, + { + .name = "st,fmc2-ebi-cs-max-low-pulse-ns", + .calculate = stm32_fmc2_ebi_ns_to_clock_cycles, + .set = stm32_fmc2_ebi_set_max_low_pulse, + }, +}; + +static int stm32_fmc2_ebi_parse_prop(struct stm32_fmc2_ebi *ebi, + struct device_node *dev_node, + const struct stm32_fmc2_prop *prop, + int cs) +{ + struct device *dev = ebi->dev; + u32 setup = 0; + + if (!prop->set) { + dev_err(dev, "property %s is not well defined\n", prop->name); + return -EINVAL; + } + + if (prop->check && prop->check(ebi, prop, cs)) + /* Skeep this property */ + return 0; + + if (prop->bprop) { + bool bprop; + + bprop = of_property_read_bool(dev_node, prop->name); + if (prop->mprop && !bprop) { + dev_err(dev, "mandatory property %s not defined in the device tree\n", + prop->name); + return -EINVAL; + } + + if (bprop) + setup = 1; + } else { + u32 val; + int ret; + + ret = of_property_read_u32(dev_node, prop->name, &val); + if (prop->mprop && ret) { + dev_err(dev, "mandatory property %s not defined in the device tree\n", + prop->name); + return ret; + } + + if (ret) + setup = prop->reset_val; + else if (prop->calculate) + setup = prop->calculate(ebi, cs, val); + else + setup = val; + } + + return prop->set(ebi, prop, cs, setup); +} + +static void stm32_fmc2_ebi_enable_bank(struct stm32_fmc2_ebi *ebi, int cs) +{ + regmap_update_bits(ebi->regmap, FMC2_BCR(cs), + FMC2_BCR_MBKEN, FMC2_BCR_MBKEN); +} + +static void stm32_fmc2_ebi_disable_bank(struct stm32_fmc2_ebi *ebi, int cs) +{ + regmap_update_bits(ebi->regmap, FMC2_BCR(cs), FMC2_BCR_MBKEN, 0); +} + +static void stm32_fmc2_ebi_save_setup(struct stm32_fmc2_ebi *ebi) +{ + unsigned int cs; + + for (cs = 0; cs < FMC2_MAX_EBI_CE; cs++) { + regmap_read(ebi->regmap, FMC2_BCR(cs), &ebi->bcr[cs]); + regmap_read(ebi->regmap, FMC2_BTR(cs), &ebi->btr[cs]); + regmap_read(ebi->regmap, FMC2_BWTR(cs), &ebi->bwtr[cs]); + } + + regmap_read(ebi->regmap, FMC2_PCSCNTR, &ebi->pcscntr); +} + +static void stm32_fmc2_ebi_set_setup(struct stm32_fmc2_ebi *ebi) +{ + unsigned int cs; + + for (cs = 0; cs < FMC2_MAX_EBI_CE; cs++) { + regmap_write(ebi->regmap, FMC2_BCR(cs), ebi->bcr[cs]); + regmap_write(ebi->regmap, FMC2_BTR(cs), ebi->btr[cs]); + regmap_write(ebi->regmap, FMC2_BWTR(cs), ebi->bwtr[cs]); + } + + regmap_write(ebi->regmap, FMC2_PCSCNTR, ebi->pcscntr); +} + +static void stm32_fmc2_ebi_disable_banks(struct stm32_fmc2_ebi *ebi) +{ + unsigned int cs; + + for (cs = 0; cs < FMC2_MAX_EBI_CE; cs++) { + if (!(ebi->bank_assigned & BIT(cs))) + continue; + + stm32_fmc2_ebi_disable_bank(ebi, cs); + } +} + +/* NWAIT signal can not be connected to EBI controller and NAND controller */ +static bool stm32_fmc2_ebi_nwait_used_by_ctrls(struct stm32_fmc2_ebi *ebi) +{ + unsigned int cs; + u32 bcr; + + for (cs = 0; cs < FMC2_MAX_EBI_CE; cs++) { + if (!(ebi->bank_assigned & BIT(cs))) + continue; + + regmap_read(ebi->regmap, FMC2_BCR(cs), &bcr); + if ((bcr & FMC2_BCR_WAITEN || bcr & FMC2_BCR_ASYNCWAIT) && + ebi->bank_assigned & BIT(FMC2_NAND)) + return true; + } + + return false; +} + +static void stm32_fmc2_ebi_enable(struct stm32_fmc2_ebi *ebi) +{ + regmap_update_bits(ebi->regmap, FMC2_BCR1, + FMC2_BCR1_FMC2EN, FMC2_BCR1_FMC2EN); +} + +static void stm32_fmc2_ebi_disable(struct stm32_fmc2_ebi *ebi) +{ + regmap_update_bits(ebi->regmap, FMC2_BCR1, FMC2_BCR1_FMC2EN, 0); +} + +static int stm32_fmc2_ebi_setup_cs(struct stm32_fmc2_ebi *ebi, + struct device_node *dev_node, + u32 cs) +{ + unsigned int i; + int ret; + + stm32_fmc2_ebi_disable_bank(ebi, cs); + + for (i = 0; i < ARRAY_SIZE(stm32_fmc2_child_props); i++) { + const struct stm32_fmc2_prop *p = &stm32_fmc2_child_props[i]; + + ret = stm32_fmc2_ebi_parse_prop(ebi, dev_node, p, cs); + if (ret) { + dev_err(ebi->dev, "property %s could not be set: %d\n", + p->name, ret); + return ret; + } + } + + stm32_fmc2_ebi_enable_bank(ebi, cs); + + return 0; +} + +static int stm32_fmc2_ebi_parse_dt(struct stm32_fmc2_ebi *ebi) +{ + struct device *dev = ebi->dev; + struct device_node *child; + bool child_found = false; + u32 bank; + int ret; + + for_each_available_child_of_node(dev->of_node, child) { + ret = of_property_read_u32(child, "reg", &bank); + if (ret) { + dev_err(dev, "could not retrieve reg property: %d\n", + ret); + return ret; + } + + if (bank >= FMC2_MAX_BANKS) { + dev_err(dev, "invalid reg value: %d\n", bank); + return -EINVAL; + } + + if (ebi->bank_assigned & BIT(bank)) { + dev_err(dev, "bank already assigned: %d\n", bank); + return -EINVAL; + } + + if (bank < FMC2_MAX_EBI_CE) { + ret = stm32_fmc2_ebi_setup_cs(ebi, child, bank); + if (ret) { + dev_err(dev, "setup chip select %d failed: %d\n", + bank, ret); + return ret; + } + } + + ebi->bank_assigned |= BIT(bank); + child_found = true; + } + + if (!child_found) { + dev_warn(dev, "no subnodes found, disable the driver.\n"); + return -ENODEV; + } + + if (stm32_fmc2_ebi_nwait_used_by_ctrls(ebi)) { + dev_err(dev, "NWAIT signal connected to EBI and NAND controllers\n"); + return -EINVAL; + } + + stm32_fmc2_ebi_enable(ebi); + + return of_platform_populate(dev->of_node, NULL, NULL, dev); +} + +static int stm32_fmc2_ebi_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct stm32_fmc2_ebi *ebi; + struct reset_control *rstc; + int ret; + + ebi = devm_kzalloc(&pdev->dev, sizeof(*ebi), GFP_KERNEL); + if (!ebi) + return -ENOMEM; + + ebi->dev = dev; + + ebi->regmap = device_node_to_regmap(dev->of_node); + if (IS_ERR(ebi->regmap)) + return PTR_ERR(ebi->regmap); + + ebi->clk = devm_clk_get(dev, NULL); + if (IS_ERR(ebi->clk)) + return PTR_ERR(ebi->clk); + + rstc = devm_reset_control_get(dev, NULL); + if (PTR_ERR(rstc) == -EPROBE_DEFER) + return -EPROBE_DEFER; + + ret = clk_prepare_enable(ebi->clk); + if (ret) + return ret; + + if (!IS_ERR(rstc)) { + reset_control_assert(rstc); + reset_control_deassert(rstc); + } + + ret = stm32_fmc2_ebi_parse_dt(ebi); + if (ret) + goto err_release; + + stm32_fmc2_ebi_save_setup(ebi); + platform_set_drvdata(pdev, ebi); + + return 0; + +err_release: + stm32_fmc2_ebi_disable_banks(ebi); + stm32_fmc2_ebi_disable(ebi); + clk_disable_unprepare(ebi->clk); + + return ret; +} + +static int stm32_fmc2_ebi_remove(struct platform_device *pdev) +{ + struct stm32_fmc2_ebi *ebi = platform_get_drvdata(pdev); + + of_platform_depopulate(&pdev->dev); + stm32_fmc2_ebi_disable_banks(ebi); + stm32_fmc2_ebi_disable(ebi); + clk_disable_unprepare(ebi->clk); + + return 0; +} + +static int __maybe_unused stm32_fmc2_ebi_suspend(struct device *dev) +{ + struct stm32_fmc2_ebi *ebi = dev_get_drvdata(dev); + + stm32_fmc2_ebi_disable(ebi); + clk_disable_unprepare(ebi->clk); + pinctrl_pm_select_sleep_state(dev); + + return 0; +} + +static int __maybe_unused stm32_fmc2_ebi_resume(struct device *dev) +{ + struct stm32_fmc2_ebi *ebi = dev_get_drvdata(dev); + int ret; + + pinctrl_pm_select_default_state(dev); + + ret = clk_prepare_enable(ebi->clk); + if (ret) + return ret; + + stm32_fmc2_ebi_set_setup(ebi); + stm32_fmc2_ebi_enable(ebi); + + return 0; +} + +static SIMPLE_DEV_PM_OPS(stm32_fmc2_ebi_pm_ops, stm32_fmc2_ebi_suspend, + stm32_fmc2_ebi_resume); + +static const struct of_device_id stm32_fmc2_ebi_match[] = { + {.compatible = "st,stm32mp1-fmc2-ebi"}, + {} +}; +MODULE_DEVICE_TABLE(of, stm32_fmc2_ebi_match); + +static struct platform_driver stm32_fmc2_ebi_driver = { + .probe = stm32_fmc2_ebi_probe, + .remove = stm32_fmc2_ebi_remove, + .driver = { + .name = "stm32_fmc2_ebi", + .of_match_table = stm32_fmc2_ebi_match, + .pm = &stm32_fmc2_ebi_pm_ops, + }, +}; +module_platform_driver(stm32_fmc2_ebi_driver); + +MODULE_ALIAS("platform:stm32_fmc2_ebi"); +MODULE_AUTHOR("Christophe Kerello "); +MODULE_DESCRIPTION("STMicroelectronics STM32 FMC2 ebi driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 51c88a8d3b02cfd4d9209c282b815336c5952619 Mon Sep 17 00:00:00 2001 From: Christophe Kerello Date: Fri, 12 Jun 2020 17:22:41 +0200 Subject: mtd: rawnand: stm32_fmc2: use regmap APIs This patch uses regmap APIs to access all FMC2 registers. Signed-off-by: Christophe Kerello Reviewed-by: Miquel Raynal Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/1591975362-22009-6-git-send-email-christophe.kerello@st.com --- drivers/mtd/nand/raw/Kconfig | 2 + drivers/mtd/nand/raw/stm32_fmc2_nand.c | 268 +++++++++++++++------------------ 2 files changed, 127 insertions(+), 143 deletions(-) diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig index 113f61052269..0a03ebf08cd6 100644 --- a/drivers/mtd/nand/raw/Kconfig +++ b/drivers/mtd/nand/raw/Kconfig @@ -415,6 +415,8 @@ config MTD_NAND_TEGRA config MTD_NAND_STM32_FMC2 tristate "Support for NAND controller on STM32MP SoCs" depends on MACH_STM32MP157 || COMPILE_TEST + select REGMAP + select REGMAP_MMIO help Enables support for NAND Flash chips on SoCs containing the FMC2 NAND controller. This controller is found on STM32MP SoCs. diff --git a/drivers/mtd/nand/raw/stm32_fmc2_nand.c b/drivers/mtd/nand/raw/stm32_fmc2_nand.c index e7b706b8ec4e..6aa36950810c 100644 --- a/drivers/mtd/nand/raw/stm32_fmc2_nand.c +++ b/drivers/mtd/nand/raw/stm32_fmc2_nand.c @@ -15,6 +15,7 @@ #include #include #include +#include #include /* Bad block marker length */ @@ -203,6 +204,16 @@ #define FMC2_BCHDSR4_EBP7 GENMASK(12, 0) #define FMC2_BCHDSR4_EBP8 GENMASK(28, 16) +/* Regmap registers configuration */ +#define FMC2_MAX_REGISTER 0x3fc + +static const struct regmap_config stm32_fmc2_regmap_cfg = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = sizeof(u32), + .max_register = FMC2_MAX_REGISTER, +}; + enum stm32_fmc2_ecc { FMC2_ECC_HAM = 1, FMC2_ECC_BCH4 = 4, @@ -242,7 +253,7 @@ struct stm32_fmc2_nfc { struct nand_controller base; struct stm32_fmc2_nand nand; struct device *dev; - void __iomem *io_base; + struct regmap *regmap; void __iomem *data_base[FMC2_MAX_CE]; void __iomem *cmd_base[FMC2_MAX_CE]; void __iomem *addr_base[FMC2_MAX_CE]; @@ -277,40 +288,37 @@ static void stm32_fmc2_nfc_timings_init(struct nand_chip *chip) struct stm32_fmc2_nfc *nfc = to_stm32_nfc(chip->controller); struct stm32_fmc2_nand *nand = to_fmc2_nand(chip); struct stm32_fmc2_timings *timings = &nand->timings; - u32 pcr = readl_relaxed(nfc->io_base + FMC2_PCR); u32 pmem, patt; /* Set tclr/tar timings */ - pcr &= ~FMC2_PCR_TCLR; - pcr |= FIELD_PREP(FMC2_PCR_TCLR, timings->tclr); - pcr &= ~FMC2_PCR_TAR; - pcr |= FIELD_PREP(FMC2_PCR_TAR, timings->tar); + regmap_update_bits(nfc->regmap, FMC2_PCR, + FMC2_PCR_TCLR | FMC2_PCR_TAR, + FIELD_PREP(FMC2_PCR_TCLR, timings->tclr) | + FIELD_PREP(FMC2_PCR_TAR, timings->tar)); /* Set tset/twait/thold/thiz timings in common bank */ pmem = FIELD_PREP(FMC2_PMEM_MEMSET, timings->tset_mem); pmem |= FIELD_PREP(FMC2_PMEM_MEMWAIT, timings->twait); pmem |= FIELD_PREP(FMC2_PMEM_MEMHOLD, timings->thold_mem); pmem |= FIELD_PREP(FMC2_PMEM_MEMHIZ, timings->thiz); + regmap_write(nfc->regmap, FMC2_PMEM, pmem); /* Set tset/twait/thold/thiz timings in attribut bank */ patt = FIELD_PREP(FMC2_PATT_ATTSET, timings->tset_att); patt |= FIELD_PREP(FMC2_PATT_ATTWAIT, timings->twait); patt |= FIELD_PREP(FMC2_PATT_ATTHOLD, timings->thold_att); patt |= FIELD_PREP(FMC2_PATT_ATTHIZ, timings->thiz); - - writel_relaxed(pcr, nfc->io_base + FMC2_PCR); - writel_relaxed(pmem, nfc->io_base + FMC2_PMEM); - writel_relaxed(patt, nfc->io_base + FMC2_PATT); + regmap_write(nfc->regmap, FMC2_PATT, patt); } static void stm32_fmc2_nfc_setup(struct nand_chip *chip) { struct stm32_fmc2_nfc *nfc = to_stm32_nfc(chip->controller); - u32 pcr = readl_relaxed(nfc->io_base + FMC2_PCR); + u32 pcr = 0, pcr_mask; /* Configure ECC algorithm (default configuration is Hamming) */ - pcr &= ~FMC2_PCR_ECCALG; - pcr &= ~FMC2_PCR_BCHECC; + pcr_mask = FMC2_PCR_ECCALG; + pcr_mask |= FMC2_PCR_BCHECC; if (chip->ecc.strength == FMC2_ECC_BCH8) { pcr |= FMC2_PCR_ECCALG; pcr |= FMC2_PCR_BCHECC; @@ -319,15 +327,15 @@ static void stm32_fmc2_nfc_setup(struct nand_chip *chip) } /* Set buswidth */ - pcr &= ~FMC2_PCR_PWID; + pcr_mask |= FMC2_PCR_PWID; if (chip->options & NAND_BUSWIDTH_16) pcr |= FIELD_PREP(FMC2_PCR_PWID, FMC2_PCR_PWID_BUSWIDTH_16); /* Set ECC sector size */ - pcr &= ~FMC2_PCR_ECCSS; + pcr_mask |= FMC2_PCR_ECCSS; pcr |= FIELD_PREP(FMC2_PCR_ECCSS, FMC2_PCR_ECCSS_512); - writel_relaxed(pcr, nfc->io_base + FMC2_PCR); + regmap_update_bits(nfc->regmap, FMC2_PCR, pcr_mask, pcr); } static int stm32_fmc2_nfc_select_chip(struct nand_chip *chip, int chipnr) @@ -393,81 +401,63 @@ static int stm32_fmc2_nfc_select_chip(struct nand_chip *chip, int chipnr) static void stm32_fmc2_nfc_set_buswidth_16(struct stm32_fmc2_nfc *nfc, bool set) { - u32 pcr = readl_relaxed(nfc->io_base + FMC2_PCR); + u32 pcr; - pcr &= ~FMC2_PCR_PWID; - if (set) - pcr |= FIELD_PREP(FMC2_PCR_PWID, FMC2_PCR_PWID_BUSWIDTH_16); - writel_relaxed(pcr, nfc->io_base + FMC2_PCR); + pcr = set ? FIELD_PREP(FMC2_PCR_PWID, FMC2_PCR_PWID_BUSWIDTH_16) : + FIELD_PREP(FMC2_PCR_PWID, FMC2_PCR_PWID_BUSWIDTH_8); + + regmap_update_bits(nfc->regmap, FMC2_PCR, FMC2_PCR_PWID, pcr); } static void stm32_fmc2_nfc_set_ecc(struct stm32_fmc2_nfc *nfc, bool enable) { - u32 pcr = readl(nfc->io_base + FMC2_PCR); - - pcr &= ~FMC2_PCR_ECCEN; - if (enable) - pcr |= FMC2_PCR_ECCEN; - writel(pcr, nfc->io_base + FMC2_PCR); + regmap_update_bits(nfc->regmap, FMC2_PCR, FMC2_PCR_ECCEN, + enable ? FMC2_PCR_ECCEN : 0); } -static inline void stm32_fmc2_nfc_enable_seq_irq(struct stm32_fmc2_nfc *nfc) +static void stm32_fmc2_nfc_enable_seq_irq(struct stm32_fmc2_nfc *nfc) { - u32 csqier = readl_relaxed(nfc->io_base + FMC2_CSQIER); - - csqier |= FMC2_CSQIER_TCIE; - nfc->irq_state = FMC2_IRQ_SEQ; - writel_relaxed(csqier, nfc->io_base + FMC2_CSQIER); + regmap_update_bits(nfc->regmap, FMC2_CSQIER, + FMC2_CSQIER_TCIE, FMC2_CSQIER_TCIE); } -static inline void stm32_fmc2_nfc_disable_seq_irq(struct stm32_fmc2_nfc *nfc) +static void stm32_fmc2_nfc_disable_seq_irq(struct stm32_fmc2_nfc *nfc) { - u32 csqier = readl_relaxed(nfc->io_base + FMC2_CSQIER); - - csqier &= ~FMC2_CSQIER_TCIE; - - writel_relaxed(csqier, nfc->io_base + FMC2_CSQIER); + regmap_update_bits(nfc->regmap, FMC2_CSQIER, FMC2_CSQIER_TCIE, 0); nfc->irq_state = FMC2_IRQ_UNKNOWN; } -static inline void stm32_fmc2_nfc_clear_seq_irq(struct stm32_fmc2_nfc *nfc) +static void stm32_fmc2_nfc_clear_seq_irq(struct stm32_fmc2_nfc *nfc) { - writel_relaxed(FMC2_CSQICR_CLEAR_IRQ, nfc->io_base + FMC2_CSQICR); + regmap_write(nfc->regmap, FMC2_CSQICR, FMC2_CSQICR_CLEAR_IRQ); } -static inline void stm32_fmc2_nfc_enable_bch_irq(struct stm32_fmc2_nfc *nfc, - int mode) +static void stm32_fmc2_nfc_enable_bch_irq(struct stm32_fmc2_nfc *nfc, int mode) { - u32 bchier = readl_relaxed(nfc->io_base + FMC2_BCHIER); + nfc->irq_state = FMC2_IRQ_BCH; if (mode == NAND_ECC_WRITE) - bchier |= FMC2_BCHIER_EPBRIE; + regmap_update_bits(nfc->regmap, FMC2_BCHIER, + FMC2_BCHIER_EPBRIE, FMC2_BCHIER_EPBRIE); else - bchier |= FMC2_BCHIER_DERIE; - - nfc->irq_state = FMC2_IRQ_BCH; - - writel_relaxed(bchier, nfc->io_base + FMC2_BCHIER); + regmap_update_bits(nfc->regmap, FMC2_BCHIER, + FMC2_BCHIER_DERIE, FMC2_BCHIER_DERIE); } -static inline void stm32_fmc2_nfc_disable_bch_irq(struct stm32_fmc2_nfc *nfc) +static void stm32_fmc2_nfc_disable_bch_irq(struct stm32_fmc2_nfc *nfc) { - u32 bchier = readl_relaxed(nfc->io_base + FMC2_BCHIER); - - bchier &= ~FMC2_BCHIER_DERIE; - bchier &= ~FMC2_BCHIER_EPBRIE; - - writel_relaxed(bchier, nfc->io_base + FMC2_BCHIER); + regmap_update_bits(nfc->regmap, FMC2_BCHIER, + FMC2_BCHIER_DERIE | FMC2_BCHIER_EPBRIE, 0); nfc->irq_state = FMC2_IRQ_UNKNOWN; } -static inline void stm32_fmc2_nfc_clear_bch_irq(struct stm32_fmc2_nfc *nfc) +static void stm32_fmc2_nfc_clear_bch_irq(struct stm32_fmc2_nfc *nfc) { - writel_relaxed(FMC2_BCHICR_CLEAR_IRQ, nfc->io_base + FMC2_BCHICR); + regmap_write(nfc->regmap, FMC2_BCHICR, FMC2_BCHICR_CLEAR_IRQ); } /* @@ -481,13 +471,8 @@ static void stm32_fmc2_nfc_hwctl(struct nand_chip *chip, int mode) stm32_fmc2_nfc_set_ecc(nfc, false); if (chip->ecc.strength != FMC2_ECC_HAM) { - u32 pcr = readl_relaxed(nfc->io_base + FMC2_PCR); - - if (mode == NAND_ECC_WRITE) - pcr |= FMC2_PCR_WEN; - else - pcr &= ~FMC2_PCR_WEN; - writel_relaxed(pcr, nfc->io_base + FMC2_PCR); + regmap_update_bits(nfc->regmap, FMC2_PCR, FMC2_PCR_WEN, + mode == NAND_ECC_WRITE ? FMC2_PCR_WEN : 0); reinit_completion(&nfc->complete); stm32_fmc2_nfc_clear_bch_irq(nfc); @@ -502,7 +487,7 @@ static void stm32_fmc2_nfc_hwctl(struct nand_chip *chip, int mode) * ECC is 3 bytes for 512 bytes of data (supports error correction up to * max of 1-bit) */ -static inline void stm32_fmc2_nfc_ham_set_ecc(const u32 ecc_sta, u8 *ecc) +static void stm32_fmc2_nfc_ham_set_ecc(const u32 ecc_sta, u8 *ecc) { ecc[0] = ecc_sta; ecc[1] = ecc_sta >> 8; @@ -516,15 +501,15 @@ static int stm32_fmc2_nfc_ham_calculate(struct nand_chip *chip, const u8 *data, u32 sr, heccr; int ret; - ret = readl_relaxed_poll_timeout(nfc->io_base + FMC2_SR, - sr, sr & FMC2_SR_NWRF, 1, - 1000 * FMC2_TIMEOUT_MS); + ret = regmap_read_poll_timeout(nfc->regmap, FMC2_SR, sr, + sr & FMC2_SR_NWRF, 1, + 1000 * FMC2_TIMEOUT_MS); if (ret) { dev_err(nfc->dev, "ham timeout\n"); return ret; } - heccr = readl_relaxed(nfc->io_base + FMC2_HECCR); + regmap_read(nfc->regmap, FMC2_HECCR, &heccr); stm32_fmc2_nfc_ham_set_ecc(heccr, ecc); stm32_fmc2_nfc_set_ecc(nfc, false); @@ -603,13 +588,13 @@ static int stm32_fmc2_nfc_bch_calculate(struct nand_chip *chip, const u8 *data, } /* Read parity bits */ - bchpbr = readl_relaxed(nfc->io_base + FMC2_BCHPBR1); + regmap_read(nfc->regmap, FMC2_BCHPBR1, &bchpbr); ecc[0] = bchpbr; ecc[1] = bchpbr >> 8; ecc[2] = bchpbr >> 16; ecc[3] = bchpbr >> 24; - bchpbr = readl_relaxed(nfc->io_base + FMC2_BCHPBR2); + regmap_read(nfc->regmap, FMC2_BCHPBR2, &bchpbr); ecc[4] = bchpbr; ecc[5] = bchpbr >> 8; ecc[6] = bchpbr >> 16; @@ -617,13 +602,13 @@ static int stm32_fmc2_nfc_bch_calculate(struct nand_chip *chip, const u8 *data, if (chip->ecc.strength == FMC2_ECC_BCH8) { ecc[7] = bchpbr >> 24; - bchpbr = readl_relaxed(nfc->io_base + FMC2_BCHPBR3); + regmap_read(nfc->regmap, FMC2_BCHPBR3, &bchpbr); ecc[8] = bchpbr; ecc[9] = bchpbr >> 8; ecc[10] = bchpbr >> 16; ecc[11] = bchpbr >> 24; - bchpbr = readl_relaxed(nfc->io_base + FMC2_BCHPBR4); + regmap_read(nfc->regmap, FMC2_BCHPBR4, &bchpbr); ecc[12] = bchpbr; } @@ -685,11 +670,7 @@ static int stm32_fmc2_nfc_bch_correct(struct nand_chip *chip, u8 *dat, return -ETIMEDOUT; } - ecc_sta[0] = readl_relaxed(nfc->io_base + FMC2_BCHDSR0); - ecc_sta[1] = readl_relaxed(nfc->io_base + FMC2_BCHDSR1); - ecc_sta[2] = readl_relaxed(nfc->io_base + FMC2_BCHDSR2); - ecc_sta[3] = readl_relaxed(nfc->io_base + FMC2_BCHDSR3); - ecc_sta[4] = readl_relaxed(nfc->io_base + FMC2_BCHDSR4); + regmap_bulk_read(nfc->regmap, FMC2_BCHDSR0, ecc_sta, 5); stm32_fmc2_nfc_set_ecc(nfc, false); @@ -764,30 +745,29 @@ static void stm32_fmc2_nfc_rw_page_init(struct nand_chip *chip, int page, { struct stm32_fmc2_nfc *nfc = to_stm32_nfc(chip->controller); struct mtd_info *mtd = nand_to_mtd(chip); - u32 csqcfgr1, csqcfgr2, csqcfgr3; - u32 csqar1, csqar2; u32 ecc_offset = mtd->writesize + FMC2_BBM_LEN; - u32 pcr = readl_relaxed(nfc->io_base + FMC2_PCR); + /* + * cfg[0] => csqcfgr1, cfg[1] => csqcfgr2, cfg[2] => csqcfgr3 + * cfg[3] => csqar1, cfg[4] => csqar2 + */ + u32 cfg[5]; - if (write_data) - pcr |= FMC2_PCR_WEN; - else - pcr &= ~FMC2_PCR_WEN; - writel_relaxed(pcr, nfc->io_base + FMC2_PCR); + regmap_update_bits(nfc->regmap, FMC2_PCR, FMC2_PCR_WEN, + write_data ? FMC2_PCR_WEN : 0); /* * - Set Program Page/Page Read command * - Enable DMA request data * - Set timings */ - csqcfgr1 = FMC2_CSQCFGR1_DMADEN | FMC2_CSQCFGR1_CMD1T; + cfg[0] = FMC2_CSQCFGR1_DMADEN | FMC2_CSQCFGR1_CMD1T; if (write_data) - csqcfgr1 |= FIELD_PREP(FMC2_CSQCFGR1_CMD1, NAND_CMD_SEQIN); + cfg[0] |= FIELD_PREP(FMC2_CSQCFGR1_CMD1, NAND_CMD_SEQIN); else - csqcfgr1 |= FIELD_PREP(FMC2_CSQCFGR1_CMD1, NAND_CMD_READ0) | - FMC2_CSQCFGR1_CMD2EN | - FIELD_PREP(FMC2_CSQCFGR1_CMD2, NAND_CMD_READSTART) | - FMC2_CSQCFGR1_CMD2T; + cfg[0] |= FIELD_PREP(FMC2_CSQCFGR1_CMD1, NAND_CMD_READ0) | + FMC2_CSQCFGR1_CMD2EN | + FIELD_PREP(FMC2_CSQCFGR1_CMD2, NAND_CMD_READSTART) | + FMC2_CSQCFGR1_CMD2T; /* * - Set Random Data Input/Random Data Read command @@ -796,30 +776,29 @@ static void stm32_fmc2_nfc_rw_page_init(struct nand_chip *chip, int page, * - Set timings */ if (write_data) - csqcfgr2 = FIELD_PREP(FMC2_CSQCFGR2_RCMD1, NAND_CMD_RNDIN); + cfg[1] = FIELD_PREP(FMC2_CSQCFGR2_RCMD1, NAND_CMD_RNDIN); else - csqcfgr2 = FIELD_PREP(FMC2_CSQCFGR2_RCMD1, NAND_CMD_RNDOUT) | - FMC2_CSQCFGR2_RCMD2EN | - FIELD_PREP(FMC2_CSQCFGR2_RCMD2, - NAND_CMD_RNDOUTSTART) | - FMC2_CSQCFGR2_RCMD1T | - FMC2_CSQCFGR2_RCMD2T; + cfg[1] = FIELD_PREP(FMC2_CSQCFGR2_RCMD1, NAND_CMD_RNDOUT) | + FMC2_CSQCFGR2_RCMD2EN | + FIELD_PREP(FMC2_CSQCFGR2_RCMD2, NAND_CMD_RNDOUTSTART) | + FMC2_CSQCFGR2_RCMD1T | + FMC2_CSQCFGR2_RCMD2T; if (!raw) { - csqcfgr2 |= write_data ? 0 : FMC2_CSQCFGR2_DMASEN; - csqcfgr2 |= FMC2_CSQCFGR2_SQSDTEN; + cfg[1] |= write_data ? 0 : FMC2_CSQCFGR2_DMASEN; + cfg[1] |= FMC2_CSQCFGR2_SQSDTEN; } /* * - Set the number of sectors to be written * - Set timings */ - csqcfgr3 = FIELD_PREP(FMC2_CSQCFGR3_SNBR, chip->ecc.steps - 1); + cfg[2] = FIELD_PREP(FMC2_CSQCFGR3_SNBR, chip->ecc.steps - 1); if (write_data) { - csqcfgr3 |= FMC2_CSQCFGR3_RAC2T; + cfg[2] |= FMC2_CSQCFGR3_RAC2T; if (chip->options & NAND_ROW_ADDR_3) - csqcfgr3 |= FMC2_CSQCFGR3_AC5T; + cfg[2] |= FMC2_CSQCFGR3_AC5T; else - csqcfgr3 |= FMC2_CSQCFGR3_AC4T; + cfg[2] |= FMC2_CSQCFGR3_AC4T; } /* @@ -827,8 +806,8 @@ static void stm32_fmc2_nfc_rw_page_init(struct nand_chip *chip, int page, * Byte 1 and byte 2 => column, we start at 0x0 * Byte 3 and byte 4 => page */ - csqar1 = FIELD_PREP(FMC2_CSQCAR1_ADDC3, page); - csqar1 |= FIELD_PREP(FMC2_CSQCAR1_ADDC4, page >> 8); + cfg[3] = FIELD_PREP(FMC2_CSQCAR1_ADDC3, page); + cfg[3] |= FIELD_PREP(FMC2_CSQCAR1_ADDC4, page >> 8); /* * - Set chip enable number @@ -836,23 +815,19 @@ static void stm32_fmc2_nfc_rw_page_init(struct nand_chip *chip, int page, * - Calculate the number of address cycles to be issued * - Set byte 5 of address cycle if needed */ - csqar2 = FIELD_PREP(FMC2_CSQCAR2_NANDCEN, nfc->cs_sel); + cfg[4] = FIELD_PREP(FMC2_CSQCAR2_NANDCEN, nfc->cs_sel); if (chip->options & NAND_BUSWIDTH_16) - csqar2 |= FIELD_PREP(FMC2_CSQCAR2_SAO, ecc_offset >> 1); + cfg[4] |= FIELD_PREP(FMC2_CSQCAR2_SAO, ecc_offset >> 1); else - csqar2 |= FIELD_PREP(FMC2_CSQCAR2_SAO, ecc_offset); + cfg[4] |= FIELD_PREP(FMC2_CSQCAR2_SAO, ecc_offset); if (chip->options & NAND_ROW_ADDR_3) { - csqcfgr1 |= FIELD_PREP(FMC2_CSQCFGR1_ACYNBR, 5); - csqar2 |= FIELD_PREP(FMC2_CSQCAR2_ADDC5, page >> 16); + cfg[0] |= FIELD_PREP(FMC2_CSQCFGR1_ACYNBR, 5); + cfg[4] |= FIELD_PREP(FMC2_CSQCAR2_ADDC5, page >> 16); } else { - csqcfgr1 |= FIELD_PREP(FMC2_CSQCFGR1_ACYNBR, 4); + cfg[0] |= FIELD_PREP(FMC2_CSQCFGR1_ACYNBR, 4); } - writel_relaxed(csqcfgr1, nfc->io_base + FMC2_CSQCFGR1); - writel_relaxed(csqcfgr2, nfc->io_base + FMC2_CSQCFGR2); - writel_relaxed(csqcfgr3, nfc->io_base + FMC2_CSQCFGR3); - writel_relaxed(csqar1, nfc->io_base + FMC2_CSQAR1); - writel_relaxed(csqar2, nfc->io_base + FMC2_CSQAR2); + regmap_bulk_write(nfc->regmap, FMC2_CSQCFGR1, cfg, 5); } static void stm32_fmc2_nfc_dma_callback(void *arg) @@ -870,7 +845,6 @@ static int stm32_fmc2_nfc_xfer(struct nand_chip *chip, const u8 *buf, struct dma_chan *dma_ch = nfc->dma_rx_ch; enum dma_data_direction dma_data_dir = DMA_FROM_DEVICE; enum dma_transfer_direction dma_transfer_dir = DMA_DEV_TO_MEM; - u32 csqcr = readl_relaxed(nfc->io_base + FMC2_CSQCR); int eccsteps = chip->ecc.steps; int eccsize = chip->ecc.size; unsigned long timeout = msecs_to_jiffies(FMC2_TIMEOUT_MS); @@ -948,8 +922,8 @@ static int stm32_fmc2_nfc_xfer(struct nand_chip *chip, const u8 *buf, stm32_fmc2_nfc_enable_seq_irq(nfc); /* Start the transfer */ - csqcr |= FMC2_CSQCR_CSQSTART; - writel_relaxed(csqcr, nfc->io_base + FMC2_CSQCR); + regmap_update_bits(nfc->regmap, FMC2_CSQCR, + FMC2_CSQCR_CSQSTART, FMC2_CSQCR_CSQSTART); /* Wait end of sequencer transfer */ if (!wait_for_completion_timeout(&nfc->complete, timeout)) { @@ -1042,11 +1016,13 @@ static int stm32_fmc2_nfc_seq_write_page_raw(struct nand_chip *chip, } /* Get a status indicating which sectors have errors */ -static inline u16 stm32_fmc2_nfc_get_mapping_status(struct stm32_fmc2_nfc *nfc) +static u16 stm32_fmc2_nfc_get_mapping_status(struct stm32_fmc2_nfc *nfc) { - u32 csqemsr = readl_relaxed(nfc->io_base + FMC2_CSQEMSR); + u32 csqemsr; + + regmap_read(nfc->regmap, FMC2_CSQEMSR, &csqemsr); - return csqemsr & FMC2_CSQEMSR_SEM; + return FIELD_GET(FMC2_CSQEMSR_SEM, csqemsr); } static int stm32_fmc2_nfc_seq_correct(struct nand_chip *chip, u8 *dat, @@ -1302,9 +1278,9 @@ static int stm32_fmc2_nfc_waitrdy(struct nand_chip *chip, u32 isr, sr; /* Check if there is no pending requests to the NAND flash */ - if (readl_relaxed_poll_timeout_atomic(nfc->io_base + FMC2_SR, sr, - sr & FMC2_SR_NWRF, 1, - 1000 * FMC2_TIMEOUT_MS)) + if (regmap_read_poll_timeout(nfc->regmap, FMC2_SR, sr, + sr & FMC2_SR_NWRF, 1, + 1000 * FMC2_TIMEOUT_MS)) dev_warn(nfc->dev, "Waitrdy timeout\n"); /* Wait tWB before R/B# signal is low */ @@ -1312,12 +1288,12 @@ static int stm32_fmc2_nfc_waitrdy(struct nand_chip *chip, ndelay(PSEC_TO_NSEC(timings->tWB_max)); /* R/B# signal is low, clear high level flag */ - writel_relaxed(FMC2_ICR_CIHLF, nfc->io_base + FMC2_ICR); + regmap_write(nfc->regmap, FMC2_ICR, FMC2_ICR_CIHLF); /* Wait R/B# signal is high */ - return readl_relaxed_poll_timeout_atomic(nfc->io_base + FMC2_ISR, - isr, isr & FMC2_ISR_IHLF, - 5, 1000 * timeout_ms); + return regmap_read_poll_timeout(nfc->regmap, FMC2_ISR, isr, + isr & FMC2_ISR_IHLF, 5, + 1000 * FMC2_TIMEOUT_MS); } static int stm32_fmc2_nfc_exec_op(struct nand_chip *chip, @@ -1375,8 +1351,9 @@ static int stm32_fmc2_nfc_exec_op(struct nand_chip *chip, static void stm32_fmc2_nfc_init(struct stm32_fmc2_nfc *nfc) { - u32 pcr = readl_relaxed(nfc->io_base + FMC2_PCR); - u32 bcr1 = readl_relaxed(nfc->io_base + FMC2_BCR1); + u32 pcr; + + regmap_read(nfc->regmap, FMC2_PCR, &pcr); /* Set CS used to undefined */ nfc->cs_sel = -1; @@ -1407,12 +1384,12 @@ static void stm32_fmc2_nfc_init(struct stm32_fmc2_nfc *nfc) pcr |= FIELD_PREP(FMC2_PCR_TAR, FMC2_PCR_TAR_DEFAULT); /* Enable FMC2 controller */ - bcr1 |= FMC2_BCR1_FMC2EN; + regmap_update_bits(nfc->regmap, FMC2_BCR1, + FMC2_BCR1_FMC2EN, FMC2_BCR1_FMC2EN); - writel_relaxed(bcr1, nfc->io_base + FMC2_BCR1); - writel_relaxed(pcr, nfc->io_base + FMC2_PCR); - writel_relaxed(FMC2_PMEM_DEFAULT, nfc->io_base + FMC2_PMEM); - writel_relaxed(FMC2_PATT_DEFAULT, nfc->io_base + FMC2_PATT); + regmap_write(nfc->regmap, FMC2_PCR, pcr); + regmap_write(nfc->regmap, FMC2_PMEM, FMC2_PMEM_DEFAULT); + regmap_write(nfc->regmap, FMC2_PATT, FMC2_PATT_DEFAULT); } static void stm32_fmc2_nfc_calc_timings(struct nand_chip *chip, @@ -1847,6 +1824,7 @@ static int stm32_fmc2_nfc_probe(struct platform_device *pdev) struct resource *res; struct mtd_info *mtd; struct nand_chip *chip; + void __iomem *mmio; int chip_cs, mem_region, ret, irq; nfc = devm_kzalloc(dev, sizeof(*nfc), GFP_KERNEL); @@ -1862,9 +1840,13 @@ static int stm32_fmc2_nfc_probe(struct platform_device *pdev) return ret; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - nfc->io_base = devm_ioremap_resource(dev, res); - if (IS_ERR(nfc->io_base)) - return PTR_ERR(nfc->io_base); + mmio = devm_ioremap_resource(dev, res); + if (IS_ERR(mmio)) + return PTR_ERR(mmio); + + nfc->regmap = devm_regmap_init_mmio(dev, mmio, &stm32_fmc2_regmap_cfg); + if (IS_ERR(nfc->regmap)) + return PTR_ERR(nfc->regmap); nfc->io_phys_addr = res->start; -- cgit v1.2.3 From fbd9b5437b668900f6d8c8e29c8aabf4955189ff Mon Sep 17 00:00:00 2001 From: Christophe Kerello Date: Fri, 12 Jun 2020 17:22:42 +0200 Subject: mtd: rawnand: stm32_fmc2: get resources from parent node FMC2 EBI support has been added. Common resources (registers base address and clock) can now be shared between the 2 drivers using "st,stm32mp1-fmc2-nfc" compatible string. It means that the common resources should now be found in the parent device when EBI node is available. Signed-off-by: Christophe Kerello Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/1591975362-22009-7-git-send-email-christophe.kerello@st.com --- drivers/mtd/nand/raw/Kconfig | 3 +- drivers/mtd/nand/raw/stm32_fmc2_nand.c | 71 ++++++++++++++++++++++++---------- 2 files changed, 51 insertions(+), 23 deletions(-) diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig index 0a03ebf08cd6..8dd0d7c8dfcf 100644 --- a/drivers/mtd/nand/raw/Kconfig +++ b/drivers/mtd/nand/raw/Kconfig @@ -415,8 +415,7 @@ config MTD_NAND_TEGRA config MTD_NAND_STM32_FMC2 tristate "Support for NAND controller on STM32MP SoCs" depends on MACH_STM32MP157 || COMPILE_TEST - select REGMAP - select REGMAP_MMIO + select MFD_SYSCON help Enables support for NAND Flash chips on SoCs containing the FMC2 NAND controller. This controller is found on STM32MP SoCs. diff --git a/drivers/mtd/nand/raw/stm32_fmc2_nand.c b/drivers/mtd/nand/raw/stm32_fmc2_nand.c index 6aa36950810c..396b3257f707 100644 --- a/drivers/mtd/nand/raw/stm32_fmc2_nand.c +++ b/drivers/mtd/nand/raw/stm32_fmc2_nand.c @@ -11,8 +11,10 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -204,16 +206,6 @@ #define FMC2_BCHDSR4_EBP7 GENMASK(12, 0) #define FMC2_BCHDSR4_EBP8 GENMASK(28, 16) -/* Regmap registers configuration */ -#define FMC2_MAX_REGISTER 0x3fc - -static const struct regmap_config stm32_fmc2_regmap_cfg = { - .reg_bits = 32, - .val_bits = 32, - .reg_stride = sizeof(u32), - .max_register = FMC2_MAX_REGISTER, -}; - enum stm32_fmc2_ecc { FMC2_ECC_HAM = 1, FMC2_ECC_BCH4 = 4, @@ -253,6 +245,7 @@ struct stm32_fmc2_nfc { struct nand_controller base; struct stm32_fmc2_nand nand; struct device *dev; + struct device *cdev; struct regmap *regmap; void __iomem *data_base[FMC2_MAX_CE]; void __iomem *cmd_base[FMC2_MAX_CE]; @@ -1384,8 +1377,9 @@ static void stm32_fmc2_nfc_init(struct stm32_fmc2_nfc *nfc) pcr |= FIELD_PREP(FMC2_PCR_TAR, FMC2_PCR_TAR_DEFAULT); /* Enable FMC2 controller */ - regmap_update_bits(nfc->regmap, FMC2_BCR1, - FMC2_BCR1_FMC2EN, FMC2_BCR1_FMC2EN); + if (nfc->dev == nfc->cdev) + regmap_update_bits(nfc->regmap, FMC2_BCR1, + FMC2_BCR1_FMC2EN, FMC2_BCR1_FMC2EN); regmap_write(nfc->regmap, FMC2_PCR, pcr); regmap_write(nfc->regmap, FMC2_PMEM, FMC2_PMEM_DEFAULT); @@ -1815,6 +1809,33 @@ static int stm32_fmc2_nfc_parse_dt(struct stm32_fmc2_nfc *nfc) return ret; } +static int stm32_fmc2_nfc_set_cdev(struct stm32_fmc2_nfc *nfc) +{ + struct device *dev = nfc->dev; + bool ebi_found = false; + + if (dev->parent && of_device_is_compatible(dev->parent->of_node, + "st,stm32mp1-fmc2-ebi")) + ebi_found = true; + + if (of_device_is_compatible(dev->of_node, "st,stm32mp1-fmc2-nfc")) { + if (ebi_found) { + nfc->cdev = dev->parent; + + return 0; + } + + return -EINVAL; + } + + if (ebi_found) + return -EINVAL; + + nfc->cdev = dev; + + return 0; +} + static int stm32_fmc2_nfc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -1824,8 +1845,9 @@ static int stm32_fmc2_nfc_probe(struct platform_device *pdev) struct resource *res; struct mtd_info *mtd; struct nand_chip *chip; - void __iomem *mmio; + struct resource cres; int chip_cs, mem_region, ret, irq; + int start_region = 0; nfc = devm_kzalloc(dev, sizeof(*nfc), GFP_KERNEL); if (!nfc) @@ -1835,22 +1857,28 @@ static int stm32_fmc2_nfc_probe(struct platform_device *pdev) nand_controller_init(&nfc->base); nfc->base.ops = &stm32_fmc2_nfc_controller_ops; + ret = stm32_fmc2_nfc_set_cdev(nfc); + if (ret) + return ret; + ret = stm32_fmc2_nfc_parse_dt(nfc); if (ret) return ret; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - mmio = devm_ioremap_resource(dev, res); - if (IS_ERR(mmio)) - return PTR_ERR(mmio); + ret = of_address_to_resource(nfc->cdev->of_node, 0, &cres); + if (ret) + return ret; + + nfc->io_phys_addr = cres.start; - nfc->regmap = devm_regmap_init_mmio(dev, mmio, &stm32_fmc2_regmap_cfg); + nfc->regmap = device_node_to_regmap(nfc->cdev->of_node); if (IS_ERR(nfc->regmap)) return PTR_ERR(nfc->regmap); - nfc->io_phys_addr = res->start; + if (nfc->dev == nfc->cdev) + start_region = 1; - for (chip_cs = 0, mem_region = 1; chip_cs < FMC2_MAX_CE; + for (chip_cs = 0, mem_region = start_region; chip_cs < FMC2_MAX_CE; chip_cs++, mem_region += 3) { if (!(nfc->cs_assigned & BIT(chip_cs))) continue; @@ -1888,7 +1916,7 @@ static int stm32_fmc2_nfc_probe(struct platform_device *pdev) init_completion(&nfc->complete); - nfc->clk = devm_clk_get(dev, NULL); + nfc->clk = devm_clk_get(nfc->cdev, NULL); if (IS_ERR(nfc->clk)) return PTR_ERR(nfc->clk); @@ -2029,6 +2057,7 @@ static SIMPLE_DEV_PM_OPS(stm32_fmc2_nfc_pm_ops, stm32_fmc2_nfc_suspend, static const struct of_device_id stm32_fmc2_nfc_match[] = { {.compatible = "st,stm32mp15-fmc2"}, + {.compatible = "st,stm32mp1-fmc2-nfc"}, {} }; MODULE_DEVICE_TABLE(of, stm32_fmc2_nfc_match); -- cgit v1.2.3 From da151e3458c825fa9d57c2db6e37748166e4d129 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Wed, 3 Jun 2020 15:49:22 +0200 Subject: dt-bindings: mtd: fsl-upm-nand: Deprecate chip-delay and fsl, upm-wait-flags Those properties are no longer parsed by the driver which is being passed those information by the core now. Let's deprecate them. Signed-off-by: Boris Brezillon Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20200603134922.1352340-11-boris.brezillon@collabora.com --- Documentation/devicetree/bindings/mtd/fsl-upm-nand.txt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Documentation/devicetree/bindings/mtd/fsl-upm-nand.txt b/Documentation/devicetree/bindings/mtd/fsl-upm-nand.txt index fce4894f5a98..25f07c1f9e44 100644 --- a/Documentation/devicetree/bindings/mtd/fsl-upm-nand.txt +++ b/Documentation/devicetree/bindings/mtd/fsl-upm-nand.txt @@ -7,14 +7,16 @@ Required properties: - fsl,upm-cmd-offset : UPM pattern offset for the command latch. Optional properties: -- fsl,upm-wait-flags : add chip-dependent short delays after running the - UPM pattern (0x1), after writing a data byte (0x2) or after - writing out a buffer (0x4). - fsl,upm-addr-line-cs-offsets : address offsets for multi-chip support. The corresponding address lines are used to select the chip. - gpios : may specify optional GPIOs connected to the Ready-Not-Busy pins (R/B#). For multi-chip devices, "n" GPIO definitions are required according to the number of chips. + +Deprecated properties: +- fsl,upm-wait-flags : add chip-dependent short delays after running the + UPM pattern (0x1), after writing a data byte (0x2) or after + writing out a buffer (0x4). - chip-delay : chip dependent delay for transferring data from array to read registers (tR). Required if property "gpios" is not used (R/B# pins not connected). @@ -52,8 +54,6 @@ upm@3,0 { fsl,upm-cmd-offset = <0x08>; /* Multi-chip NAND device */ fsl,upm-addr-line-cs-offsets = <0x0 0x200>; - fsl,upm-wait-flags = <0x5>; - chip-delay = <25>; // in micro-seconds nand@0 { #address-cells = <1>; -- cgit v1.2.3 From 5cec8bc3707be699e2ace103bb4daecfdd0d3386 Mon Sep 17 00:00:00 2001 From: Pratyush Yadav Date: Wed, 24 Jun 2020 00:00:24 +0530 Subject: mtd: spi-nor: sfdp: do not make invalid quad enable fatal The Micron MT35XU512ABA flash does not support the quad enable bit. But instead of programming the Quad Enable Require field to 000b ("Device does not have a QE bit"), it is programmed to 111b ("Reserved"). While this is technically incorrect, it is not reason enough to abort BFPT parsing. Instead, continue BFPT parsing and let flashes set it in their fixup hooks. Signed-off-by: Pratyush Yadav Signed-off-by: Tudor Ambarus Link: https://lore.kernel.org/r/20200623183030.26591-12-p.yadav@ti.com --- drivers/mtd/spi-nor/sfdp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/spi-nor/sfdp.c b/drivers/mtd/spi-nor/sfdp.c index 55c0c508464b..e2a43d39eb5f 100644 --- a/drivers/mtd/spi-nor/sfdp.c +++ b/drivers/mtd/spi-nor/sfdp.c @@ -598,7 +598,8 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor, break; default: - return -EINVAL; + dev_dbg(nor->dev, "BFPT QER reserved value used\n"); + break; } /* Stop here if not JESD216 rev C or later. */ -- cgit v1.2.3 From 8c8f97573eb3843ddd2d8cb95c80ce0243b17d7e Mon Sep 17 00:00:00 2001 From: Takahiro Kuwano Date: Fri, 26 Jun 2020 14:16:50 +0900 Subject: mtd: spi-nor: spansion: Remove s70fl01gs from flash_info The s70fl01gs is a dual die stack of two s25fl512s die with dedicated chip select pins to each. Tested with the device and confirmed that is working as two s25fl512s devices. The current device ID in the flash_info table matches with s70fs01gs which does not work with current MTD (s70fs01gs does not support RDSR(05h) which is critical for erase/write). Signed-off-by: Takahiro Kuwano Signed-off-by: Tudor Ambarus Link: https://lore.kernel.org/r/20200626051650.495-1-Takahiro.Kuwano@cypress.com --- drivers/mtd/spi-nor/spansion.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/mtd/spi-nor/spansion.c b/drivers/mtd/spi-nor/spansion.c index e550cd5c9d3a..953df1c488ec 100644 --- a/drivers/mtd/spi-nor/spansion.c +++ b/drivers/mtd/spi-nor/spansion.c @@ -64,7 +64,6 @@ static const struct flash_info spansion_parts[] = { { "s25fs512s", INFO6(0x010220, 0x4d0081, 256 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) .fixups = &s25fs_s_fixups, }, - { "s70fl01gs", INFO(0x010221, 0x4d00, 256 * 1024, 256, 0) }, { "s25sl12800", INFO(0x012018, 0x0300, 256 * 1024, 64, 0) }, { "s25sl12801", INFO(0x012018, 0x0301, 64 * 1024, 256, 0) }, { "s25fl129p0", INFO(0x012018, 0x4d00, 256 * 1024, 64, -- cgit v1.2.3 From be192209d5a33c912caa4a05d6f92b89328d8db8 Mon Sep 17 00:00:00 2001 From: Yicong Yang Date: Mon, 6 Jul 2020 17:22:35 +0800 Subject: mtd: spi-nor: Add capability to disable flash quad mode Previous we didn't provide a way to disable the flash's quad mode. Which means we cannot do some cleanup works when to remove or poweroff the flash, like what set 4-byte address mode does in spi_nor_restore(). Add the capability to disable the flash quad mode, by introducing an enable flag in the flash parameters quad_enable() hooks and related functions. Signed-off-by: Yicong Yang Signed-off-by: Tudor Ambarus Reviewed-by: Pratyush Yadav Link: https://lore.kernel.org/r/1594027356-19088-2-git-send-email-yangyicong@hisilicon.com --- drivers/mtd/spi-nor/core.c | 55 ++++++++++++++++++++++++++++++---------------- drivers/mtd/spi-nor/core.h | 10 ++++----- 2 files changed, 41 insertions(+), 24 deletions(-) diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c index 0369d98b2d12..ab8f55438e21 100644 --- a/drivers/mtd/spi-nor/core.c +++ b/drivers/mtd/spi-nor/core.c @@ -1907,15 +1907,16 @@ static int spi_nor_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len) } /** - * spi_nor_sr1_bit6_quad_enable() - Set the Quad Enable BIT(6) in the Status - * Register 1. + * spi_nor_sr1_bit6_quad_enable() - Set/Unset the Quad Enable BIT(6) in the + * Status Register 1. * @nor: pointer to a 'struct spi_nor' + * @enable: true to enable Quad mode, false to disable Quad mode. * * Bit 6 of the Status Register 1 is the QE bit for Macronix like QSPI memories. * * Return: 0 on success, -errno otherwise. */ -int spi_nor_sr1_bit6_quad_enable(struct spi_nor *nor) +int spi_nor_sr1_bit6_quad_enable(struct spi_nor *nor, bool enable) { int ret; @@ -1923,45 +1924,56 @@ int spi_nor_sr1_bit6_quad_enable(struct spi_nor *nor) if (ret) return ret; - if (nor->bouncebuf[0] & SR1_QUAD_EN_BIT6) + if ((enable && (nor->bouncebuf[0] & SR1_QUAD_EN_BIT6)) || + (!enable && !(nor->bouncebuf[0] & SR1_QUAD_EN_BIT6))) return 0; - nor->bouncebuf[0] |= SR1_QUAD_EN_BIT6; + if (enable) + nor->bouncebuf[0] |= SR1_QUAD_EN_BIT6; + else + nor->bouncebuf[0] &= ~SR1_QUAD_EN_BIT6; return spi_nor_write_sr1_and_check(nor, nor->bouncebuf[0]); } /** - * spi_nor_sr2_bit1_quad_enable() - set the Quad Enable BIT(1) in the Status - * Register 2. + * spi_nor_sr2_bit1_quad_enable() - set/unset the Quad Enable BIT(1) in the + * Status Register 2. * @nor: pointer to a 'struct spi_nor'. + * @enable: true to enable Quad mode, false to disable Quad mode. * * Bit 1 of the Status Register 2 is the QE bit for Spansion like QSPI memories. * * Return: 0 on success, -errno otherwise. */ -int spi_nor_sr2_bit1_quad_enable(struct spi_nor *nor) +int spi_nor_sr2_bit1_quad_enable(struct spi_nor *nor, bool enable) { int ret; if (nor->flags & SNOR_F_NO_READ_CR) - return spi_nor_write_16bit_cr_and_check(nor, SR2_QUAD_EN_BIT1); + return spi_nor_write_16bit_cr_and_check(nor, + enable ? SR2_QUAD_EN_BIT1 : 0); ret = spi_nor_read_cr(nor, nor->bouncebuf); if (ret) return ret; - if (nor->bouncebuf[0] & SR2_QUAD_EN_BIT1) + if ((enable && (nor->bouncebuf[0] & SR2_QUAD_EN_BIT1)) || + (!enable && !(nor->bouncebuf[0] & SR2_QUAD_EN_BIT1))) return 0; - nor->bouncebuf[0] |= SR2_QUAD_EN_BIT1; + if (enable) + nor->bouncebuf[0] |= SR2_QUAD_EN_BIT1; + else + nor->bouncebuf[0] &= ~SR2_QUAD_EN_BIT1; return spi_nor_write_16bit_cr_and_check(nor, nor->bouncebuf[0]); } /** - * spi_nor_sr2_bit7_quad_enable() - set QE bit in Status Register 2. + * spi_nor_sr2_bit7_quad_enable() - set/unset QE bit in Status Register 2. * @nor: pointer to a 'struct spi_nor' + * @enable: true to enable Quad mode, false to disable Quad mode. * * Set the Quad Enable (QE) bit in the Status Register 2. * @@ -1971,7 +1983,7 @@ int spi_nor_sr2_bit1_quad_enable(struct spi_nor *nor) * * Return: 0 on success, -errno otherwise. */ -int spi_nor_sr2_bit7_quad_enable(struct spi_nor *nor) +int spi_nor_sr2_bit7_quad_enable(struct spi_nor *nor, bool enable) { u8 *sr2 = nor->bouncebuf; int ret; @@ -1981,11 +1993,15 @@ int spi_nor_sr2_bit7_quad_enable(struct spi_nor *nor) ret = spi_nor_read_sr2(nor, sr2); if (ret) return ret; - if (*sr2 & SR2_QUAD_EN_BIT7) + if ((enable && (*sr2 & SR2_QUAD_EN_BIT7)) || + (!enable && !(*sr2 & SR2_QUAD_EN_BIT7))) return 0; /* Update the Quad Enable bit. */ - *sr2 |= SR2_QUAD_EN_BIT7; + if (enable) + *sr2 |= SR2_QUAD_EN_BIT7; + else + *sr2 &= ~SR2_QUAD_EN_BIT7; ret = spi_nor_write_sr2(nor, sr2); if (ret) @@ -2898,12 +2914,13 @@ static int spi_nor_init_params(struct spi_nor *nor) } /** - * spi_nor_quad_enable() - enable Quad I/O if needed. + * spi_nor_quad_enable() - enable/disable Quad I/O if needed. * @nor: pointer to a 'struct spi_nor' + * @enable: true to enable Quad mode. false to disable Quad mode. * * Return: 0 on success, -errno otherwise. */ -static int spi_nor_quad_enable(struct spi_nor *nor) +static int spi_nor_quad_enable(struct spi_nor *nor, bool enable) { if (!nor->params->quad_enable) return 0; @@ -2912,7 +2929,7 @@ static int spi_nor_quad_enable(struct spi_nor *nor) spi_nor_get_protocol_width(nor->write_proto) == 4)) return 0; - return nor->params->quad_enable(nor); + return nor->params->quad_enable(nor, enable); } /** @@ -2936,7 +2953,7 @@ static int spi_nor_init(struct spi_nor *nor) { int err; - err = spi_nor_quad_enable(nor); + err = spi_nor_quad_enable(nor, true); if (err) { dev_dbg(nor->dev, "quad mode not supported\n"); return err; diff --git a/drivers/mtd/spi-nor/core.h b/drivers/mtd/spi-nor/core.h index 6f2f6b27173f..95aa32f3ceb1 100644 --- a/drivers/mtd/spi-nor/core.h +++ b/drivers/mtd/spi-nor/core.h @@ -198,7 +198,7 @@ struct spi_nor_locking_ops { * higher index in the array, the higher priority. * @erase_map: the erase map parsed from the SFDP Sector Map Parameter * Table. - * @quad_enable: enables SPI NOR quad mode. + * @quad_enable: enables/disables SPI NOR Quad mode. * @set_4byte_addr_mode: puts the SPI NOR in 4 byte addressing mode. * @convert_addr: converts an absolute address into something the flash * will understand. Particularly useful when pagesize is @@ -219,7 +219,7 @@ struct spi_nor_flash_parameter { struct spi_nor_erase_map erase_map; - int (*quad_enable)(struct spi_nor *nor); + int (*quad_enable)(struct spi_nor *nor, bool enable); int (*set_4byte_addr_mode)(struct spi_nor *nor, bool enable); u32 (*convert_addr)(struct spi_nor *nor, u32 addr); int (*setup)(struct spi_nor *nor, const struct spi_nor_hwcaps *hwcaps); @@ -406,9 +406,9 @@ int spi_nor_write_ear(struct spi_nor *nor, u8 ear); int spi_nor_wait_till_ready(struct spi_nor *nor); int spi_nor_lock_and_prep(struct spi_nor *nor); void spi_nor_unlock_and_unprep(struct spi_nor *nor); -int spi_nor_sr1_bit6_quad_enable(struct spi_nor *nor); -int spi_nor_sr2_bit1_quad_enable(struct spi_nor *nor); -int spi_nor_sr2_bit7_quad_enable(struct spi_nor *nor); +int spi_nor_sr1_bit6_quad_enable(struct spi_nor *nor, bool enable); +int spi_nor_sr2_bit1_quad_enable(struct spi_nor *nor, bool enable); +int spi_nor_sr2_bit7_quad_enable(struct spi_nor *nor, bool enable); int spi_nor_xread_sr(struct spi_nor *nor, u8 *sr); ssize_t spi_nor_read_data(struct spi_nor *nor, loff_t from, size_t len, -- cgit v1.2.3 From cc59e6bb6cd69d3347c06ccce088c5c6052e041e Mon Sep 17 00:00:00 2001 From: Yicong Yang Date: Mon, 6 Jul 2020 17:22:36 +0800 Subject: mtd: spi-nor: Disable the flash quad mode in spi_nor_restore() If the flash's quad mode is enabled, it'll remain in the quad mode when it's removed. If we drive the flash next time in Standard/Dual SPI mode, the QE bit is not cleared and the function of flash's WP# and RESET#/HOLD# have been switched to IO2 and IO3 and are not restored. Disable the Quad mode in spi_nor_restore(), then the flash's QE bit will be cleared when removed. This will make sure the flash always enter the Standard/Dual SPI mode when loaded. Signed-off-by: Yicong Yang Signed-off-by: Tudor Ambarus Reviewed-by: Pratyush Yadav Link: https://lore.kernel.org/r/1594027356-19088-3-git-send-email-yangyicong@hisilicon.com --- drivers/mtd/spi-nor/core.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c index ab8f55438e21..65eff4ce6ab1 100644 --- a/drivers/mtd/spi-nor/core.c +++ b/drivers/mtd/spi-nor/core.c @@ -3000,6 +3000,8 @@ void spi_nor_restore(struct spi_nor *nor) if (nor->addr_width == 4 && !(nor->flags & SNOR_F_4B_OPCODES) && nor->flags & SNOR_F_BROKEN_RESET) nor->params->set_4byte_addr_mode(nor, false); + + spi_nor_quad_enable(nor, false); } EXPORT_SYMBOL_GPL(spi_nor_restore); -- cgit v1.2.3 From 44a80df4bfce02f5d51fe5040bdbdf10d0d78f4e Mon Sep 17 00:00:00 2001 From: Alexander Sverdlin Date: Wed, 22 Jul 2020 16:01:36 +0200 Subject: mtd: spi-nor: intel-spi: Simulate WRDI command After spi_nor_write_disable() return code checks were introduced in the spi-nor front end intel-spi backend stopped to work because WRDI was never supported and always failed. Just pretend it was sucessful and ignore the command itself. HW sequencer shall do the right thing automatically, while with SW sequencer we cannot do it anyway, because the only tool we had was preopcode and it makes no sense for WRDI. Fixes: bce679e5ae3a ("mtd: spi-nor: Check for errors after each Register Operation") Signed-off-by: Alexander Sverdlin Reviewed-by: Mika Westerberg Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/282e1305-fd08-e446-1a22-eb4dff78cfb4@nokia.com Signed-off-by: Tudor Ambarus --- drivers/mtd/spi-nor/controllers/intel-spi.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/mtd/spi-nor/controllers/intel-spi.c b/drivers/mtd/spi-nor/controllers/intel-spi.c index 61d2a0ad2131..3259c9fc981f 100644 --- a/drivers/mtd/spi-nor/controllers/intel-spi.c +++ b/drivers/mtd/spi-nor/controllers/intel-spi.c @@ -612,6 +612,15 @@ static int intel_spi_write_reg(struct spi_nor *nor, u8 opcode, const u8 *buf, return 0; } + /* + * We hope that HW sequencer will do the right thing automatically and + * with the SW sequencer we cannot use preopcode anyway, so just ignore + * the Write Disable operation and pretend it was completed + * successfully. + */ + if (opcode == SPINOR_OP_WRDI) + return 0; + writel(0, ispi->base + FADDR); /* Write the value beforehand */ -- cgit v1.2.3 From 48029e620decc185c88041e12156e4f5d871b28a Mon Sep 17 00:00:00 2001 From: David Clear Date: Mon, 20 Jul 2020 09:36:55 -0700 Subject: mtd: spi-nor: macronix: Add support for mx66u2g45g The Macronix mx66u2g45g is a 1.8V, 2Gbit (256MB) device that supports x1, x2, or x4 operation. Tested on Pensando SoC hardware with a cadence quadspi controller via drivers/spi/spi-cadence-quadspi.c, in x2 mode at 50MHz. - random data write, erase, read - verified erase operations - random data write, read/compare - verified write/read operations Signed-off-by: David Clear Acked-by: Shannon Nelson Link: https://lore.kernel.org/r/20200720163656.38006-2-dac2@pensando.io Signed-off-by: Tudor Ambarus --- drivers/mtd/spi-nor/macronix.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/mtd/spi-nor/macronix.c b/drivers/mtd/spi-nor/macronix.c index 0ae0815a3633..f97f3d127575 100644 --- a/drivers/mtd/spi-nor/macronix.c +++ b/drivers/mtd/spi-nor/macronix.c @@ -87,6 +87,9 @@ static const struct flash_info macronix_parts[] = { SPI_NOR_QUAD_READ) }, { "mx66l1g55g", INFO(0xc2261b, 0, 64 * 1024, 2048, SPI_NOR_QUAD_READ) }, + { "mx66u2g45g", INFO(0xc2253c, 0, 64 * 1024, 4096, + SECT_4K | SPI_NOR_DUAL_READ | + SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, }; static void macronix_default_init(struct spi_nor *nor) -- cgit v1.2.3 From 1371a80cac33d5b0df4c33f918b9dd810cf4edab Mon Sep 17 00:00:00 2001 From: David Clear Date: Mon, 20 Jul 2020 09:36:56 -0700 Subject: mtd: spi-nor: micron: Add SPI_NOR_DUAL_READ flag on mt25qu02g The Micron mt25qu02g supports both x2 and x4 transactions. Add the SPI_NOR_DUAL_READ flag to its spi_nor_ids[] table entry. Tested on Pensando SoC hardware with a cadence quadspi controller via drivers/spi/spi-cadence-quadspi.c, in x2 mode at 50MHz. - random data write, erase, read - verified erase operations - random data write, read/compare - verified write/read operations Signed-off-by: David Clear Acked-by: Shannon Nelson Link: https://lore.kernel.org/r/20200720163656.38006-3-dac2@pensando.io Signed-off-by: Tudor Ambarus --- drivers/mtd/spi-nor/micron-st.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/spi-nor/micron-st.c b/drivers/mtd/spi-nor/micron-st.c index 3dca5b9af3b6..ef3695080710 100644 --- a/drivers/mtd/spi-nor/micron-st.c +++ b/drivers/mtd/spi-nor/micron-st.c @@ -71,8 +71,8 @@ static const struct flash_info st_parts[] = { SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE) }, { "mt25qu02g", INFO(0x20bb22, 0, 64 * 1024, 4096, - SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | - NO_CHIP_ERASE) }, + SECT_4K | USE_FSR | SPI_NOR_DUAL_READ | + SPI_NOR_QUAD_READ | NO_CHIP_ERASE) }, { "m25p05", INFO(0x202010, 0, 32 * 1024, 2, 0) }, { "m25p10", INFO(0x202011, 0, 32 * 1024, 4, 0) }, -- cgit v1.2.3 From 99eae48fd4c5c59a76de17bc036a2dbd7f698bfd Mon Sep 17 00:00:00 2001 From: Rayagonda Kokatanur Date: Fri, 29 May 2020 12:46:55 +0530 Subject: mtd: spi-nor: update read capabilities for w25q64 and s25fl064k Both w25q64 and s25fl064k nor flash support QUAD and DUAL read command, hence update the same in flash_info table. This is tested on Broadcom Stingray SoC (bcm958742t). s25fl064k and w25q64 share the same JEDEC ID. The search alg will return the first hit, so s25fl064k even for the winbond parts. We should differentiate between these flashes, but it's not in the scope of this patch. Related discussion at: Link: https://lore.kernel.org/patchwork/patch/628090/ Signed-off-by: Rayagonda Kokatanur Link: https://lore.kernel.org/r/20200529071655.739-1-rayagonda.kokatanur@broadcom.com [tudor.ambarus@microchip.com: Update commit message and indicate that s25fl064k and w25q64 share the same JEDEC ID] Signed-off-by: Tudor Ambarus --- drivers/mtd/spi-nor/spansion.c | 3 ++- drivers/mtd/spi-nor/winbond.c | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/spi-nor/spansion.c b/drivers/mtd/spi-nor/spansion.c index 953df1c488ec..8429b4af999a 100644 --- a/drivers/mtd/spi-nor/spansion.c +++ b/drivers/mtd/spi-nor/spansion.c @@ -83,7 +83,8 @@ static const struct flash_info spansion_parts[] = { SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, { "s25fl016k", INFO(0xef4015, 0, 64 * 1024, 32, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { "s25fl064k", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) }, + { "s25fl064k", INFO(0xef4017, 0, 64 * 1024, 128, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, { "s25fl116k", INFO(0x014015, 0, 64 * 1024, 32, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, { "s25fl132k", INFO(0x014016, 0, 64 * 1024, 64, SECT_4K) }, diff --git a/drivers/mtd/spi-nor/winbond.c b/drivers/mtd/spi-nor/winbond.c index a5eb1d56cb88..6dcde15fb1aa 100644 --- a/drivers/mtd/spi-nor/winbond.c +++ b/drivers/mtd/spi-nor/winbond.c @@ -64,7 +64,8 @@ static const struct flash_info winbond_parts[] = { SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) }, { "w25x64", INFO(0xef3017, 0, 64 * 1024, 128, SECT_4K) }, - { "w25q64", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) }, + { "w25q64", INFO(0xef4017, 0, 64 * 1024, 128, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, { "w25q64dw", INFO(0xef6017, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) }, -- cgit v1.2.3 From e93a977367b2aefff3c1fb426bbdfc6e2980815f Mon Sep 17 00:00:00 2001 From: Luis Alberto Herrera Date: Wed, 10 Jun 2020 22:46:49 +0000 Subject: mtd: revert "spi-nor: intel: provide a range for poll_timout" This change reverts aba3a882a178: "mtd: spi-nor: intel: provide a range for poll_timout". That change introduces a performance regression when reading sequentially from flash. Logging calls to intel_spi_read without this change we get: Start MTD read [ 20.045527] intel_spi_read(from=1800000, len=400000) [ 20.045527] intel_spi_read(from=1800000, len=400000) [ 282.199274] intel_spi_read(from=1c00000, len=400000) [ 282.199274] intel_spi_read(from=1c00000, len=400000) [ 544.351528] intel_spi_read(from=2000000, len=400000) [ 544.351528] intel_spi_read(from=2000000, len=400000) End MTD read With this change: Start MTD read [ 21.942922] intel_spi_read(from=1c00000, len=400000) [ 21.942922] intel_spi_read(from=1c00000, len=400000) [ 23.784058] intel_spi_read(from=2000000, len=400000) [ 23.784058] intel_spi_read(from=2000000, len=400000) [ 25.625006] intel_spi_read(from=2400000, len=400000) [ 25.625006] intel_spi_read(from=2400000, len=400000) End MTD read Signed-off-by: Luis Alberto Herrera Tested-by: Alexander Sverdlin Acked-by: Mika Westerberg Link: https://lore.kernel.org/r/20200610224652.64336-1-luisalberto@google.com Signed-off-by: Tudor Ambarus --- drivers/mtd/spi-nor/controllers/intel-spi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/spi-nor/controllers/intel-spi.c b/drivers/mtd/spi-nor/controllers/intel-spi.c index 3259c9fc981f..b54a56a68100 100644 --- a/drivers/mtd/spi-nor/controllers/intel-spi.c +++ b/drivers/mtd/spi-nor/controllers/intel-spi.c @@ -292,7 +292,7 @@ static int intel_spi_wait_hw_busy(struct intel_spi *ispi) u32 val; return readl_poll_timeout(ispi->base + HSFSTS_CTL, val, - !(val & HSFSTS_CTL_SCIP), 40, + !(val & HSFSTS_CTL_SCIP), 0, INTEL_SPI_TIMEOUT * 1000); } @@ -301,7 +301,7 @@ static int intel_spi_wait_sw_busy(struct intel_spi *ispi) u32 val; return readl_poll_timeout(ispi->sregs + SSFSTS_CTL, val, - !(val & SSFSTS_CTL_SCIP), 40, + !(val & SSFSTS_CTL_SCIP), 0, INTEL_SPI_TIMEOUT * 1000); } -- cgit v1.2.3 From 614a895fc69497d99cc02c076fa712c75194eab3 Mon Sep 17 00:00:00 2001 From: "Alexander A. Klimov" Date: Thu, 9 Jul 2020 20:07:33 +0200 Subject: mtd: hyperbus: Replace HTTP links with HTTPS ones Rationale: Reduces attack surface on kernel devs opening the links for MITM as HTTPS traffic is much harder to manipulate. Deterministic algorithm: For each file: If not .svg: For each line: If doesn't contain `\bxmlns\b`: For each link, `\bhttp://[^# \t\r\n]*(?:\w|/)`: If neither `\bgnu\.org/license`, nor `\bmozilla\.org/MPL\b`: If both the HTTP and HTTPS versions return 200 OK and serve the same content: Replace HTTP with HTTPS. Signed-off-by: Alexander A. Klimov Signed-off-by: Richard Weinberger --- drivers/mtd/hyperbus/hbmc-am654.c | 2 +- drivers/mtd/hyperbus/hyperbus-core.c | 2 +- include/linux/mtd/hyperbus.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/mtd/hyperbus/hbmc-am654.c b/drivers/mtd/hyperbus/hbmc-am654.c index f350a0809f88..e0e33f6bf513 100644 --- a/drivers/mtd/hyperbus/hbmc-am654.c +++ b/drivers/mtd/hyperbus/hbmc-am654.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 // -// Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/ +// Copyright (C) 2019 Texas Instruments Incorporated - https://www.ti.com/ // Author: Vignesh Raghavendra #include diff --git a/drivers/mtd/hyperbus/hyperbus-core.c b/drivers/mtd/hyperbus/hyperbus-core.c index 32685e8dd278..2f9fc4e17d53 100644 --- a/drivers/mtd/hyperbus/hyperbus-core.c +++ b/drivers/mtd/hyperbus/hyperbus-core.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 // -// Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/ +// Copyright (C) 2019 Texas Instruments Incorporated - https://www.ti.com/ // Author: Vignesh Raghavendra #include diff --git a/include/linux/mtd/hyperbus.h b/include/linux/mtd/hyperbus.h index 2dfe65964f6e..2129f7d3b6eb 100644 --- a/include/linux/mtd/hyperbus.h +++ b/include/linux/mtd/hyperbus.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 * - * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (C) 2019 Texas Instruments Incorporated - https://www.ti.com/ */ #ifndef __LINUX_MTD_HYPERBUS_H__ -- cgit v1.2.3 From c13ac5552546c8971c0a4a3e947e25b0f8786aa9 Mon Sep 17 00:00:00 2001 From: "Alexander A. Klimov" Date: Mon, 13 Jul 2020 18:54:08 +0200 Subject: mtd: Replace HTTP links with HTTPS ones Rationale: Reduces attack surface on kernel devs opening the links for MITM as HTTPS traffic is much harder to manipulate. Deterministic algorithm: For each file: If not .svg: For each line: If doesn't contain `\bxmlns\b`: For each link, `\bhttp://[^# \t\r\n]*(?:\w|/)`: If neither `\bgnu\.org/license`, nor `\bmozilla\.org/MPL\b`: If both the HTTP and HTTPS versions return 200 OK and serve the same content: Replace HTTP with HTTPS. Signed-off-by: Alexander A. Klimov Acked-by: Rob Herring Signed-off-by: Richard Weinberger --- Documentation/devicetree/bindings/mtd/davinci-nand.txt | 4 ++-- drivers/mtd/chips/Kconfig | 2 +- drivers/mtd/maps/Kconfig | 2 +- drivers/mtd/maps/sc520cdp.c | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Documentation/devicetree/bindings/mtd/davinci-nand.txt b/Documentation/devicetree/bindings/mtd/davinci-nand.txt index cfb18abe6001..edebeae1f5b3 100644 --- a/Documentation/devicetree/bindings/mtd/davinci-nand.txt +++ b/Documentation/devicetree/bindings/mtd/davinci-nand.txt @@ -4,8 +4,8 @@ This file provides information, what the device node for the davinci/keystone NAND interface contains. Documentation: -Davinci DM646x - http://www.ti.com/lit/ug/sprueq7c/sprueq7c.pdf -Kestone - http://www.ti.com/lit/ug/sprugz3a/sprugz3a.pdf +Davinci DM646x - https://www.ti.com/lit/ug/sprueq7c/sprueq7c.pdf +Kestone - https://www.ti.com/lit/ug/sprugz3a/sprugz3a.pdf Required properties: diff --git a/drivers/mtd/chips/Kconfig b/drivers/mtd/chips/Kconfig index a7e47e068ad9..aef14990e5f7 100644 --- a/drivers/mtd/chips/Kconfig +++ b/drivers/mtd/chips/Kconfig @@ -11,7 +11,7 @@ config MTD_CFI AMD and other flash manufactures that provides a universal method for probing the capabilities of flash devices. If you wish to support any device that is CFI-compliant, you need to enable this - option. Visit + option. Visit for more information on CFI. config MTD_JEDECPROBE diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig index b28225a7c4f3..fd37553f1b07 100644 --- a/drivers/mtd/maps/Kconfig +++ b/drivers/mtd/maps/Kconfig @@ -310,7 +310,7 @@ config MTD_DC21285 help This provides a driver for the flash accessed using Intel's 21285 bridge used with Intel's StrongARM processors. More info at - . + . config MTD_IXP4XX tristate "CFI Flash device mapped on Intel IXP4xx based systems" diff --git a/drivers/mtd/maps/sc520cdp.c b/drivers/mtd/maps/sc520cdp.c index 9902b37e18b4..8ef7aec634c7 100644 --- a/drivers/mtd/maps/sc520cdp.c +++ b/drivers/mtd/maps/sc520cdp.c @@ -6,7 +6,7 @@ * The SC520CDP is an evaluation board for the Elan SC520 processor available * from AMD. It has two banks of 32-bit Flash ROM, each 8 Megabytes in size, * and up to 512 KiB of 8-bit DIL Flash ROM. - * For details see http://www.amd.com/products/epd/desiging/evalboards/18.elansc520/520_cdp_brief/index.html + * For details see https://www.amd.com/products/epd/desiging/evalboards/18.elansc520/520_cdp_brief/index.html */ #include -- cgit v1.2.3 From 3d19792a7d7279b1aece733c2605a3671c6459c9 Mon Sep 17 00:00:00 2001 From: "Alexander A. Klimov" Date: Mon, 13 Jul 2020 19:04:20 +0200 Subject: mtd: rawnand: omap_elm: Replace HTTP links with HTTPS ones Rationale: Reduces attack surface on kernel devs opening the links for MITM as HTTPS traffic is much harder to manipulate. Deterministic algorithm: For each file: If not .svg: For each line: If doesn't contain `\bxmlns\b`: For each link, `\bhttp://[^# \t\r\n]*(?:\w|/)`: If neither `\bgnu\.org/license`, nor `\bmozilla\.org/MPL\b`: If both the HTTP and HTTPS versions return 200 OK and serve the same content: Replace HTTP with HTTPS. Signed-off-by: Alexander A. Klimov Signed-off-by: Richard Weinberger --- drivers/mtd/nand/raw/omap_elm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/nand/raw/omap_elm.c b/drivers/mtd/nand/raw/omap_elm.c index 078b1022ac2a..4b799521a427 100644 --- a/drivers/mtd/nand/raw/omap_elm.c +++ b/drivers/mtd/nand/raw/omap_elm.c @@ -2,7 +2,7 @@ /* * Error Location Module * - * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (C) 2012 Texas Instruments Incorporated - https://www.ti.com/ */ #define DRIVER_NAME "omap-elm" -- cgit v1.2.3 From f8951902b9daa65ba240ce8a054c727748df2147 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sat, 18 Jul 2020 17:32:08 -0700 Subject: MTD: mtd-abi.h: drop a duplicated word Drop the repeated word "mode" in a comment. Signed-off-by: Randy Dunlap Cc: Miquel Raynal Cc: Richard Weinberger Cc: Vignesh Raghavendra Cc: linux-mtd@lists.infradead.org Signed-off-by: Richard Weinberger --- include/uapi/mtd/mtd-abi.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/uapi/mtd/mtd-abi.h b/include/uapi/mtd/mtd-abi.h index 4b48fbf7d343..65b9db936557 100644 --- a/include/uapi/mtd/mtd-abi.h +++ b/include/uapi/mtd/mtd-abi.h @@ -262,7 +262,7 @@ struct mtd_ecc_stats { * @MTD_FILE_MODE_OTP_USER: OTP enabled in user mode * @MTD_FILE_MODE_RAW: OTP disabled, ECC disabled * - * These modes can be set via ioctl(MTDFILEMODE). The mode mode will be retained + * These modes can be set via ioctl(MTDFILEMODE). The mode will be retained * separately for each open file descriptor. * * Note: %MTD_FILE_MODE_RAW provides the same functionality as %MTD_OPS_RAW - -- cgit v1.2.3 From 0c84b7fc973f9220ef8732c430ccc7c92d083184 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sat, 18 Jul 2020 17:29:54 -0700 Subject: MTD: pfow.h: drop a duplicated word Drop the repeated word "can" in a comment. Signed-off-by: Randy Dunlap Cc: Miquel Raynal Cc: Richard Weinberger Cc: Vignesh Raghavendra Cc: linux-mtd@lists.infradead.org Signed-off-by: Richard Weinberger --- include/linux/mtd/pfow.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/mtd/pfow.h b/include/linux/mtd/pfow.h index 122f3439e1af..6166e7c60869 100644 --- a/include/linux/mtd/pfow.h +++ b/include/linux/mtd/pfow.h @@ -19,7 +19,7 @@ /* Identification info for LPDDR chip */ #define PFOW_MANUFACTURER_ID 0x0020 #define PFOW_DEVICE_ID 0x0022 -/* Address in PFOW where prog buffer can can be found */ +/* Address in PFOW where prog buffer can be found */ #define PFOW_PROGRAM_BUFFER_OFFSET 0x0040 /* Size of program buffer in words */ #define PFOW_PROGRAM_BUFFER_SIZE 0x0042 -- cgit v1.2.3