From 78e2d5410a440bc232c2f5eedb6ab0403e9675b6 Mon Sep 17 00:00:00 2001 From: Zhang Qilong Date: Thu, 22 Sep 2022 23:06:54 +0800 Subject: mtd: rawnand: gpmi: using pm_runtime_resume_and_get instead of pm_runtime_get_sync Using the newest pm_runtime_resume_and_get is more appropriate for simplifing code here. Signed-off-by: Zhang Qilong Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20220922150654.117568-1-zhangqilong3@huawei.com --- drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c index 01ccbde748f3..ada83344b0f9 100644 --- a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c +++ b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c @@ -148,11 +148,9 @@ static int gpmi_init(struct gpmi_nand_data *this) struct resources *r = &this->resources; int ret; - ret = pm_runtime_get_sync(this->dev); - if (ret < 0) { - pm_runtime_put_noidle(this->dev); + ret = pm_runtime_resume_and_get(this->dev); + if (ret < 0) return ret; - } ret = gpmi_reset_block(r->gpmi_regs, false); if (ret) @@ -2504,11 +2502,9 @@ static int gpmi_nfc_exec_op(struct nand_chip *chip, for (i = 0; i < GPMI_MAX_TRANSFERS; i++) this->transfers[i].direction = DMA_NONE; - ret = pm_runtime_get_sync(this->dev); - if (ret < 0) { - pm_runtime_put_noidle(this->dev); + ret = pm_runtime_resume_and_get(this->dev); + if (ret < 0) return ret; - } /* * This driver currently supports only one NAND chip. Plus, dies share -- cgit v1.2.3 From 782e32a990d9d7029a8400f09a4d02b1ba78cb77 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 28 Sep 2022 16:00:18 -0700 Subject: mtd: rawnand: lpc32xx_mlc: switch to using gpiod API This switches the driver from legacy gpio API to a newer gpiod API. Signed-off-by: Dmitry Torokhov Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20220928230019.2140896-1-dmitry.torokhov@gmail.com --- drivers/mtd/nand/raw/lpc32xx_mlc.c | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/raw/lpc32xx_mlc.c b/drivers/mtd/nand/raw/lpc32xx_mlc.c index 452ecaf7775a..306e2c216501 100644 --- a/drivers/mtd/nand/raw/lpc32xx_mlc.c +++ b/drivers/mtd/nand/raw/lpc32xx_mlc.c @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #include #include @@ -122,7 +122,6 @@ struct lpc32xx_nand_cfg_mlc { uint32_t rd_low; uint32_t wr_high; uint32_t wr_low; - int wp_gpio; struct mtd_partition *parts; unsigned num_parts; }; @@ -177,6 +176,7 @@ struct lpc32xx_nand_host { struct nand_chip nand_chip; struct lpc32xx_mlc_platform_data *pdata; struct clk *clk; + struct gpio_desc *wp_gpio; void __iomem *io_base; int irq; struct lpc32xx_nand_cfg_mlc *ncfg; @@ -370,8 +370,8 @@ static int lpc32xx_waitfunc(struct nand_chip *chip) */ static void lpc32xx_wp_enable(struct lpc32xx_nand_host *host) { - if (gpio_is_valid(host->ncfg->wp_gpio)) - gpio_set_value(host->ncfg->wp_gpio, 0); + if (host->wp_gpio) + gpiod_set_value_cansleep(host->wp_gpio, 1); } /* @@ -379,8 +379,8 @@ static void lpc32xx_wp_enable(struct lpc32xx_nand_host *host) */ static void lpc32xx_wp_disable(struct lpc32xx_nand_host *host) { - if (gpio_is_valid(host->ncfg->wp_gpio)) - gpio_set_value(host->ncfg->wp_gpio, 1); + if (host->wp_gpio) + gpiod_set_value_cansleep(host->wp_gpio, 0); } static void lpc32xx_dma_complete_func(void *completion) @@ -636,8 +636,6 @@ static struct lpc32xx_nand_cfg_mlc *lpc32xx_parse_dt(struct device *dev) return NULL; } - ncfg->wp_gpio = of_get_named_gpio(np, "gpios", 0); - return ncfg; } @@ -713,14 +711,18 @@ static int lpc32xx_nand_probe(struct platform_device *pdev) "Missing or bad NAND config from device tree\n"); return -ENOENT; } - if (host->ncfg->wp_gpio == -EPROBE_DEFER) - return -EPROBE_DEFER; - if (gpio_is_valid(host->ncfg->wp_gpio) && - gpio_request(host->ncfg->wp_gpio, "NAND WP")) { - dev_err(&pdev->dev, "GPIO not available\n"); - return -EBUSY; + + /* Start with WP disabled, if available */ + host->wp_gpio = gpiod_get_optional(&pdev->dev, NULL, GPIOD_OUT_LOW); + res = PTR_ERR_OR_ZERO(host->wp_gpio); + if (res) { + if (res != -EPROBE_DEFER) + dev_err(&pdev->dev, "WP GPIO is not available: %d\n", + res); + return res; } - lpc32xx_wp_disable(host); + + gpiod_set_consumer_name(host->wp_gpio, "NAND WP"); host->pdata = dev_get_platdata(&pdev->dev); @@ -817,7 +819,7 @@ put_clk: clk_put(host->clk); free_gpio: lpc32xx_wp_enable(host); - gpio_free(host->ncfg->wp_gpio); + gpiod_put(host->wp_gpio); return res; } @@ -843,7 +845,7 @@ static int lpc32xx_nand_remove(struct platform_device *pdev) clk_put(host->clk); lpc32xx_wp_enable(host); - gpio_free(host->ncfg->wp_gpio); + gpiod_put(host->wp_gpio); return 0; } -- cgit v1.2.3 From 6b923db2867cb5e18ac4a1d5d5b4eecf0b619538 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 28 Sep 2022 16:00:19 -0700 Subject: mtd: rawnand: lpc32xx_slc: switch to using gpiod API This switches the driver from legacy gpio API to a newer gpiod API. Signed-off-by: Dmitry Torokhov Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20220928230019.2140896-2-dmitry.torokhov@gmail.com --- drivers/mtd/nand/raw/lpc32xx_slc.c | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/raw/lpc32xx_slc.c b/drivers/mtd/nand/raw/lpc32xx_slc.c index 6b7269cfb7d8..4702577f74e5 100644 --- a/drivers/mtd/nand/raw/lpc32xx_slc.c +++ b/drivers/mtd/nand/raw/lpc32xx_slc.c @@ -23,9 +23,8 @@ #include #include #include -#include +#include #include -#include #include #define LPC32XX_MODNAME "lpc32xx-nand" @@ -208,7 +207,6 @@ struct lpc32xx_nand_cfg_slc { uint32_t rwidth; uint32_t rhold; uint32_t rsetup; - int wp_gpio; struct mtd_partition *parts; unsigned num_parts; }; @@ -217,6 +215,7 @@ struct lpc32xx_nand_host { struct nand_chip nand_chip; struct lpc32xx_slc_platform_data *pdata; struct clk *clk; + struct gpio_desc *wp_gpio; void __iomem *io_base; struct lpc32xx_nand_cfg_slc *ncfg; @@ -309,8 +308,8 @@ static int lpc32xx_nand_device_ready(struct nand_chip *chip) */ static void lpc32xx_wp_enable(struct lpc32xx_nand_host *host) { - if (gpio_is_valid(host->ncfg->wp_gpio)) - gpio_set_value(host->ncfg->wp_gpio, 0); + if (host->wp_gpio) + gpiod_set_value_cansleep(host->wp_gpio, 1); } /* @@ -318,8 +317,8 @@ static void lpc32xx_wp_enable(struct lpc32xx_nand_host *host) */ static void lpc32xx_wp_disable(struct lpc32xx_nand_host *host) { - if (gpio_is_valid(host->ncfg->wp_gpio)) - gpio_set_value(host->ncfg->wp_gpio, 1); + if (host->wp_gpio) + gpiod_set_value_cansleep(host->wp_gpio, 0); } /* @@ -764,8 +763,6 @@ static struct lpc32xx_nand_cfg_slc *lpc32xx_parse_dt(struct device *dev) return NULL; } - ncfg->wp_gpio = of_get_named_gpio(np, "gpios", 0); - return ncfg; } @@ -852,14 +849,18 @@ static int lpc32xx_nand_probe(struct platform_device *pdev) "Missing or bad NAND config from device tree\n"); return -ENOENT; } - if (host->ncfg->wp_gpio == -EPROBE_DEFER) - return -EPROBE_DEFER; - if (gpio_is_valid(host->ncfg->wp_gpio) && devm_gpio_request(&pdev->dev, - host->ncfg->wp_gpio, "NAND WP")) { - dev_err(&pdev->dev, "GPIO not available\n"); - return -EBUSY; + + /* Start with WP disabled, if available */ + host->wp_gpio = gpiod_get_optional(&pdev->dev, NULL, GPIOD_OUT_LOW); + res = PTR_ERR_OR_ZERO(host->wp_gpio); + if (res) { + if (res != -EPROBE_DEFER) + dev_err(&pdev->dev, "WP GPIO is not available: %d\n", + res); + return res; } - lpc32xx_wp_disable(host); + + gpiod_set_consumer_name(host->wp_gpio, "NAND WP"); host->pdata = dev_get_platdata(&pdev->dev); -- cgit v1.2.3 From 3fea699cb2d6c8c47289b16500590630f507d8fd Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Thu, 6 Oct 2022 07:29:12 +0200 Subject: mtd: rawnand: mpc5121: Replace NO_IRQ by 0 NO_IRQ is used to check the return of irq_of_parse_and_map(). On some architecture NO_IRQ is 0, on other architectures it is -1. irq_of_parse_and_map() returns 0 on error, independent of NO_IRQ. So use 0 instead of using NO_IRQ. Signed-off-by: Christophe Leroy Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/4e3ca3e0077ea124ea210c312e6e620f0f9e8bca.1665034065.git.christophe.leroy@csgroup.eu --- drivers/mtd/nand/raw/mpc5121_nfc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/raw/mpc5121_nfc.c b/drivers/mtd/nand/raw/mpc5121_nfc.c index 800d774aed8e..f68349cb7824 100644 --- a/drivers/mtd/nand/raw/mpc5121_nfc.c +++ b/drivers/mtd/nand/raw/mpc5121_nfc.c @@ -663,7 +663,7 @@ static int mpc5121_nfc_probe(struct platform_device *op) } prv->irq = irq_of_parse_and_map(dn, 0); - if (prv->irq == NO_IRQ) { + if (!prv->irq) { dev_err(dev, "Error mapping IRQ!\n"); return -EINVAL; } -- cgit v1.2.3 From dbf70fc204d2fbb0d8ad8f42038a60846502efda Mon Sep 17 00:00:00 2001 From: Mikhail Kshevetskiy Date: Mon, 10 Oct 2022 13:51:09 +0300 Subject: mtd: spinand: winbond: fix flash identification Winbond uses 3 bytes to identify flash: vendor_id, dev_id_0, dev_id_1, but current driver uses only first 2 bytes of it for devices identification. As result Winbond W25N02KV flash (id_bytes: EF, AA, 22) is identified as W25N01GV (id_bytes: EF, AA, 21). Fix this by adding missed identification bytes. Signed-off-by: Mikhail Kshevetskiy Reviewed-by: Frieder Schrempf Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20221010105110.446674-1-mikhail.kshevetskiy@iopsys.eu --- drivers/mtd/nand/spi/winbond.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/spi/winbond.c b/drivers/mtd/nand/spi/winbond.c index 76684428354e..ed368a55d68f 100644 --- a/drivers/mtd/nand/spi/winbond.c +++ b/drivers/mtd/nand/spi/winbond.c @@ -76,7 +76,7 @@ static int w25m02gv_select_target(struct spinand_device *spinand, static const struct spinand_info winbond_spinand_table[] = { SPINAND_INFO("W25M02GV", - SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xab), + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xab, 0x21), NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 2), NAND_ECCREQ(1, 512), SPINAND_INFO_OP_VARIANTS(&read_cache_variants, @@ -86,7 +86,7 @@ static const struct spinand_info winbond_spinand_table[] = { SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL), SPINAND_SELECT_TARGET(w25m02gv_select_target)), SPINAND_INFO("W25N01GV", - SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xaa), + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xaa, 0x21), NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1), NAND_ECCREQ(1, 512), SPINAND_INFO_OP_VARIANTS(&read_cache_variants, -- cgit v1.2.3 From 6154c7a583483d7b69f53bea868efdc369edd563 Mon Sep 17 00:00:00 2001 From: Mikhail Kshevetskiy Date: Mon, 10 Oct 2022 13:51:10 +0300 Subject: mtd: spinand: winbond: add Winbond W25N02KV flash support Add support of Winbond W25N02KV flash Signed-off-by: Mikhail Kshevetskiy Reviewed-by: Frieder Schrempf Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20221010105110.446674-2-mikhail.kshevetskiy@iopsys.eu --- drivers/mtd/nand/spi/winbond.c | 75 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/spi/winbond.c b/drivers/mtd/nand/spi/winbond.c index ed368a55d68f..3ad58cd284d8 100644 --- a/drivers/mtd/nand/spi/winbond.c +++ b/drivers/mtd/nand/spi/winbond.c @@ -74,6 +74,72 @@ static int w25m02gv_select_target(struct spinand_device *spinand, return spi_mem_exec_op(spinand->spimem, &op); } +static int w25n02kv_ooblayout_ecc(struct mtd_info *mtd, int section, + struct mtd_oob_region *region) +{ + if (section > 3) + return -ERANGE; + + region->offset = 64 + (16 * section); + region->length = 13; + + return 0; +} + +static int w25n02kv_ooblayout_free(struct mtd_info *mtd, int section, + struct mtd_oob_region *region) +{ + if (section > 3) + return -ERANGE; + + region->offset = (16 * section) + 2; + region->length = 14; + + return 0; +} + +static const struct mtd_ooblayout_ops w25n02kv_ooblayout = { + .ecc = w25n02kv_ooblayout_ecc, + .free = w25n02kv_ooblayout_free, +}; + +static int w25n02kv_ecc_get_status(struct spinand_device *spinand, + u8 status) +{ + struct nand_device *nand = spinand_to_nand(spinand); + u8 mbf = 0; + struct spi_mem_op op = SPINAND_GET_FEATURE_OP(0x30, &mbf); + + switch (status & STATUS_ECC_MASK) { + case STATUS_ECC_NO_BITFLIPS: + return 0; + + case STATUS_ECC_UNCOR_ERROR: + return -EBADMSG; + + case STATUS_ECC_HAS_BITFLIPS: + /* + * Let's try to retrieve the real maximum number of bitflips + * in order to avoid forcing the wear-leveling layer to move + * data around if it's not necessary. + */ + if (spi_mem_exec_op(spinand->spimem, &op)) + return nanddev_get_ecc_conf(nand)->strength; + + mbf >>= 4; + + if (WARN_ON(mbf > nanddev_get_ecc_conf(nand)->strength || !mbf)) + return nanddev_get_ecc_conf(nand)->strength; + + return mbf; + + default: + break; + } + + return -EINVAL; +} + static const struct spinand_info winbond_spinand_table[] = { SPINAND_INFO("W25M02GV", SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xab, 0x21), @@ -94,6 +160,15 @@ static const struct spinand_info winbond_spinand_table[] = { &update_cache_variants), 0, SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL)), + SPINAND_INFO("W25N02KV", + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xaa, 0x22), + NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1), + NAND_ECCREQ(8, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants, + &write_cache_variants, + &update_cache_variants), + 0, + SPINAND_ECCINFO(&w25n02kv_ooblayout, w25n02kv_ecc_get_status)), }; static int winbond_spinand_init(struct spinand_device *spinand) -- cgit v1.2.3 From 7c3fc99819fd812b00f1881537599e66b989e392 Mon Sep 17 00:00:00 2001 From: Valentin Korenblit Date: Tue, 18 Oct 2022 11:30:00 +0200 Subject: mtd: rawnand: cadence: support 64-bit slave dma interface 32-bit accesses on 64-bit sdma trigger sdma_err in intr_status register. Check dma capabilities before reading/writing from/to sdma interface. Link: https://lore.kernel.org/all/b7e5ebb4-0de8-4958-9bc4-fe06ec4c3635@www.fastmail.com/t/ Signed-off-by: Valentin Korenblit Reviewed-by: Arnd Bergmann Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20221018093000.12072-1-vkorenblit@sequans.com --- drivers/mtd/nand/raw/cadence-nand-controller.c | 70 +++++++++++++++++++++----- 1 file changed, 58 insertions(+), 12 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/raw/cadence-nand-controller.c b/drivers/mtd/nand/raw/cadence-nand-controller.c index 9dac3ca69d57..7661a5cf1883 100644 --- a/drivers/mtd/nand/raw/cadence-nand-controller.c +++ b/drivers/mtd/nand/raw/cadence-nand-controller.c @@ -1184,6 +1184,14 @@ static int cadence_nand_hw_init(struct cdns_nand_ctrl *cdns_ctrl) if (cadence_nand_read_bch_caps(cdns_ctrl)) return -EIO; +#ifndef CONFIG_64BIT + if (cdns_ctrl->caps2.data_dma_width == 8) { + dev_err(cdns_ctrl->dev, + "cannot access 64-bit dma on !64-bit architectures"); + return -EIO; + } +#endif + /* * Set IO width access to 8. * It is because during SW device discovering width access @@ -1882,17 +1890,36 @@ static int cadence_nand_read_buf(struct cdns_nand_ctrl *cdns_ctrl, return status; if (!cdns_ctrl->caps1->has_dma) { - int len_in_words = len >> 2; + u8 data_dma_width = cdns_ctrl->caps2.data_dma_width; + + int len_in_words = (data_dma_width == 4) ? len >> 2 : len >> 3; /* read alingment data */ - ioread32_rep(cdns_ctrl->io.virt, buf, len_in_words); + if (data_dma_width == 4) + ioread32_rep(cdns_ctrl->io.virt, buf, len_in_words); +#ifdef CONFIG_64BIT + else + readsq(cdns_ctrl->io.virt, buf, len_in_words); +#endif + if (sdma_size > len) { + int read_bytes = (data_dma_width == 4) ? + len_in_words << 2 : len_in_words << 3; + /* read rest data from slave DMA interface if any */ - ioread32_rep(cdns_ctrl->io.virt, cdns_ctrl->buf, - sdma_size / 4 - len_in_words); + if (data_dma_width == 4) + ioread32_rep(cdns_ctrl->io.virt, + cdns_ctrl->buf, + sdma_size / 4 - len_in_words); +#ifdef CONFIG_64BIT + else + readsq(cdns_ctrl->io.virt, cdns_ctrl->buf, + sdma_size / 8 - len_in_words); +#endif + /* copy rest of data */ - memcpy(buf + (len_in_words << 2), cdns_ctrl->buf, - len - (len_in_words << 2)); + memcpy(buf + read_bytes, cdns_ctrl->buf, + len - read_bytes); } return 0; } @@ -1936,16 +1963,35 @@ static int cadence_nand_write_buf(struct cdns_nand_ctrl *cdns_ctrl, return status; if (!cdns_ctrl->caps1->has_dma) { - int len_in_words = len >> 2; + u8 data_dma_width = cdns_ctrl->caps2.data_dma_width; + + int len_in_words = (data_dma_width == 4) ? len >> 2 : len >> 3; + + if (data_dma_width == 4) + iowrite32_rep(cdns_ctrl->io.virt, buf, len_in_words); +#ifdef CONFIG_64BIT + else + writesq(cdns_ctrl->io.virt, buf, len_in_words); +#endif - iowrite32_rep(cdns_ctrl->io.virt, buf, len_in_words); if (sdma_size > len) { + int written_bytes = (data_dma_width == 4) ? + len_in_words << 2 : len_in_words << 3; + /* copy rest of data */ - memcpy(cdns_ctrl->buf, buf + (len_in_words << 2), - len - (len_in_words << 2)); + memcpy(cdns_ctrl->buf, buf + written_bytes, + len - written_bytes); + /* write all expected by nand controller data */ - iowrite32_rep(cdns_ctrl->io.virt, cdns_ctrl->buf, - sdma_size / 4 - len_in_words); + if (data_dma_width == 4) + iowrite32_rep(cdns_ctrl->io.virt, + cdns_ctrl->buf, + sdma_size / 4 - len_in_words); +#ifdef CONFIG_64BIT + else + writesq(cdns_ctrl->io.virt, cdns_ctrl->buf, + sdma_size / 8 - len_in_words); +#endif } return 0; -- cgit v1.2.3 From 8f1ee9ef71d0c0b185d2afc800e68d6addf29fe5 Mon Sep 17 00:00:00 2001 From: Sai Krishna Potthuri Date: Thu, 8 Sep 2022 12:14:28 +0530 Subject: mtd: spi-nor: Add support for flash reset Add support for spi-nor flash reset via GPIO controller by reading the reset-gpio property. If there is a valid GPIO specifier then reset will be performed by asserting and deasserting the GPIO using gpiod APIs otherwise it will not perform any operation. Signed-off-by: Sai Krishna Potthuri Signed-off-by: Tudor Ambarus Reviewed-by: Michael Walle Link: https://lore.kernel.org/r/20220908064428.2962-3-sai.krishna.potthuri@amd.com --- drivers/mtd/spi-nor/core.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'drivers/mtd') diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c index f2c64006f8d7..a78ab9bae2be 100644 --- a/drivers/mtd/spi-nor/core.c +++ b/drivers/mtd/spi-nor/core.c @@ -2933,6 +2933,27 @@ static void spi_nor_set_mtd_info(struct spi_nor *nor) mtd->_put_device = spi_nor_put_device; } +static int spi_nor_hw_reset(struct spi_nor *nor) +{ + struct gpio_desc *reset; + + reset = devm_gpiod_get_optional(nor->dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR_OR_NULL(reset)) + return PTR_ERR_OR_ZERO(reset); + + /* + * Experimental delay values by looking at different flash device + * vendors datasheets. + */ + usleep_range(1, 5); + gpiod_set_value_cansleep(reset, 1); + usleep_range(100, 150); + gpiod_set_value_cansleep(reset, 0); + usleep_range(1000, 1200); + + return 0; +} + int spi_nor_scan(struct spi_nor *nor, const char *name, const struct spi_nor_hwcaps *hwcaps) { @@ -2965,6 +2986,10 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, if (!nor->bouncebuf) return -ENOMEM; + ret = spi_nor_hw_reset(nor); + if (ret) + return ret; + info = spi_nor_get_flash_info(nor, name); if (IS_ERR(info)) return PTR_ERR(info); -- cgit v1.2.3 From d189614f24799ce150eaf3ecca8483c0a3697e9b Mon Sep 17 00:00:00 2001 From: Takahiro Kuwano Date: Wed, 31 Aug 2022 13:59:03 +0900 Subject: mtd: spi-nor: sfdp: Update params->hwcaps.mask at xSPI profile 1.0 table parse Existece of xSPI profile 1.0 table implies that the flash supports read and program in 8D-8D-8D mode. Update the params->hwcaps.mask in spi_nor_parase_profile1(). Signed-off-by: Takahiro Kuwano Signed-off-by: Tudor Ambarus Link: https://lore.kernel.org/r/1b449bae6978f11f7636f2b5acb6435723963f59.1661915569.git.Takahiro.Kuwano@infineon.com --- drivers/mtd/spi-nor/sfdp.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/mtd') diff --git a/drivers/mtd/spi-nor/sfdp.c b/drivers/mtd/spi-nor/sfdp.c index 2257f1b4c2e2..15fb7f661ae9 100644 --- a/drivers/mtd/spi-nor/sfdp.c +++ b/drivers/mtd/spi-nor/sfdp.c @@ -1183,10 +1183,17 @@ static int spi_nor_parse_profile1(struct spi_nor *nor, dummy = round_up(dummy, 2); /* Update the fast read settings. */ + nor->params->hwcaps.mask |= SNOR_HWCAPS_READ_8_8_8_DTR; spi_nor_set_read_settings(&nor->params->reads[SNOR_CMD_READ_8_8_8_DTR], 0, dummy, opcode, SNOR_PROTO_8_8_8_DTR); + /* + * Page Program is "Required Command" in the xSPI Profile 1.0. Update + * the params->hwcaps.mask here. + */ + nor->params->hwcaps.mask |= SNOR_HWCAPS_PP_8_8_8_DTR; + out: kfree(dwords); return ret; -- cgit v1.2.3 From db391efe765cc6cfc0ffc8d8ef146dc8e6816a7e Mon Sep 17 00:00:00 2001 From: Takahiro Kuwano Date: Wed, 31 Aug 2022 13:59:04 +0900 Subject: mtd: spi-nor: spansion: Remove NO_SFDP_FLAGS from s28hs512t info Read, Page Program, and Sector Erase settings are done in SFDP so we can remove NO_SFDP_FLAGS from s28hs512t info. Since the default_init() is no longer called after removing NO_SFDP_FLAGS, the initialization in the default_init() is moved to late_init(). Signed-off-by: Takahiro Kuwano Signed-off-by: Tudor Ambarus Link: https://lore.kernel.org/r/12e468992f5d0cbd474abff3203100cc8163d4e5.1661915569.git.Takahiro.Kuwano@infineon.com --- drivers/mtd/spi-nor/spansion.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/spi-nor/spansion.c b/drivers/mtd/spi-nor/spansion.c index 0150049007be..a14308422ee6 100644 --- a/drivers/mtd/spi-nor/spansion.c +++ b/drivers/mtd/spi-nor/spansion.c @@ -275,12 +275,6 @@ static int cypress_nor_octal_dtr_enable(struct spi_nor *nor, bool enable) cypress_nor_octal_dtr_dis(nor); } -static void s28hs512t_default_init(struct spi_nor *nor) -{ - nor->params->octal_dtr_enable = cypress_nor_octal_dtr_enable; - nor->params->writesize = 16; -} - static void s28hs512t_post_sfdp_fixup(struct spi_nor *nor) { /* @@ -316,10 +310,16 @@ static int s28hs512t_post_bfpt_fixup(struct spi_nor *nor, return cypress_nor_set_page_size(nor); } +static void s28hs512t_late_init(struct spi_nor *nor) +{ + nor->params->octal_dtr_enable = cypress_nor_octal_dtr_enable; + nor->params->writesize = 16; +} + static const struct spi_nor_fixups s28hs512t_fixups = { - .default_init = s28hs512t_default_init, .post_sfdp = s28hs512t_post_sfdp_fixup, .post_bfpt = s28hs512t_post_bfpt_fixup, + .late_init = s28hs512t_late_init, }; static int @@ -454,8 +454,7 @@ static const struct flash_info spansion_nor_parts[] = { { "cy15x104q", INFO6(0x042cc2, 0x7f7f7f, 512 * 1024, 1) FLAGS(SPI_NOR_NO_ERASE) }, { "s28hs512t", INFO(0x345b1a, 0, 256 * 1024, 256) - NO_SFDP_FLAGS(SECT_4K | SPI_NOR_OCTAL_DTR_READ | - SPI_NOR_OCTAL_DTR_PP) + PARSE_SFDP .fixups = &s28hs512t_fixups, }, }; -- cgit v1.2.3 From 06051322704bf38cbd721e14bdbd6e43c8e6d7e1 Mon Sep 17 00:00:00 2001 From: Takahiro Kuwano Date: Wed, 31 Aug 2022 13:59:05 +0900 Subject: mtd: spi-nor: spansion: Rename s28hs512t prefix Change prefix to support all other devices in SEMPER S28 family. Signed-off-by: Takahiro Kuwano Signed-off-by: Tudor Ambarus Reviewed-by: Michael Walle Link: https://lore.kernel.org/r/8cf6bc9bffd50e486867c0817de1fa56c5d308ec.1661915569.git.Takahiro.Kuwano@infineon.com --- drivers/mtd/spi-nor/spansion.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/spi-nor/spansion.c b/drivers/mtd/spi-nor/spansion.c index a14308422ee6..4278d3ad6343 100644 --- a/drivers/mtd/spi-nor/spansion.c +++ b/drivers/mtd/spi-nor/spansion.c @@ -275,7 +275,7 @@ static int cypress_nor_octal_dtr_enable(struct spi_nor *nor, bool enable) cypress_nor_octal_dtr_dis(nor); } -static void s28hs512t_post_sfdp_fixup(struct spi_nor *nor) +static void s28hx_t_post_sfdp_fixup(struct spi_nor *nor) { /* * On older versions of the flash the xSPI Profile 1.0 table has the @@ -303,23 +303,23 @@ static void s28hs512t_post_sfdp_fixup(struct spi_nor *nor) nor->params->rdsr_addr_nbytes = 4; } -static int s28hs512t_post_bfpt_fixup(struct spi_nor *nor, - const struct sfdp_parameter_header *bfpt_header, - const struct sfdp_bfpt *bfpt) +static int s28hx_t_post_bfpt_fixup(struct spi_nor *nor, + const struct sfdp_parameter_header *bfpt_header, + const struct sfdp_bfpt *bfpt) { return cypress_nor_set_page_size(nor); } -static void s28hs512t_late_init(struct spi_nor *nor) +static void s28hx_t_late_init(struct spi_nor *nor) { nor->params->octal_dtr_enable = cypress_nor_octal_dtr_enable; nor->params->writesize = 16; } -static const struct spi_nor_fixups s28hs512t_fixups = { - .post_sfdp = s28hs512t_post_sfdp_fixup, - .post_bfpt = s28hs512t_post_bfpt_fixup, - .late_init = s28hs512t_late_init, +static const struct spi_nor_fixups s28hx_t_fixups = { + .post_sfdp = s28hx_t_post_sfdp_fixup, + .post_bfpt = s28hx_t_post_bfpt_fixup, + .late_init = s28hx_t_late_init, }; static int @@ -455,7 +455,7 @@ static const struct flash_info spansion_nor_parts[] = { FLAGS(SPI_NOR_NO_ERASE) }, { "s28hs512t", INFO(0x345b1a, 0, 256 * 1024, 256) PARSE_SFDP - .fixups = &s28hs512t_fixups, + .fixups = &s28hx_t_fixups, }, }; -- cgit v1.2.3 From aff1fa414a85f63f4ef5af75a9d1dc7e8f840e86 Mon Sep 17 00:00:00 2001 From: Takahiro Kuwano Date: Wed, 31 Aug 2022 13:59:06 +0900 Subject: mtd: spi-nor: spansion: Add s28hl512t, s28hl01gt, and s28hs01gt info Add flash info table entries for s28hl512gt, s28hl01gt, and s28hs01gt. These devices have the same functionality as s28hs512t. Signed-off-by: Takahiro Kuwano Signed-off-by: Tudor Ambarus Link: https://lore.kernel.org/r/6350ac204c58b94b30d70c529bf194d953085ac6.1661915569.git.Takahiro.Kuwano@infineon.com --- drivers/mtd/spi-nor/spansion.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'drivers/mtd') diff --git a/drivers/mtd/spi-nor/spansion.c b/drivers/mtd/spi-nor/spansion.c index 4278d3ad6343..bd9edfd3cd3c 100644 --- a/drivers/mtd/spi-nor/spansion.c +++ b/drivers/mtd/spi-nor/spansion.c @@ -453,10 +453,22 @@ static const struct flash_info spansion_nor_parts[] = { .fixups = &s25hx_t_fixups }, { "cy15x104q", INFO6(0x042cc2, 0x7f7f7f, 512 * 1024, 1) FLAGS(SPI_NOR_NO_ERASE) }, + { "s28hl512t", INFO(0x345a1a, 0, 256 * 1024, 256) + PARSE_SFDP + .fixups = &s28hx_t_fixups, + }, + { "s28hl01gt", INFO(0x345a1b, 0, 256 * 1024, 512) + PARSE_SFDP + .fixups = &s28hx_t_fixups, + }, { "s28hs512t", INFO(0x345b1a, 0, 256 * 1024, 256) PARSE_SFDP .fixups = &s28hx_t_fixups, }, + { "s28hs01gt", INFO(0x345b1b, 0, 256 * 1024, 512) + PARSE_SFDP + .fixups = &s28hx_t_fixups, + }, }; /** -- cgit v1.2.3 From 05ebc1ccb8affcbaaa9f8b8fe56839cbfc9b9144 Mon Sep 17 00:00:00 2001 From: Tudor Ambarus Date: Thu, 28 Jul 2022 07:14:50 +0300 Subject: mtd: spi-nor: spansion: Replace hardcoded values for addr_nbytes/addr_mode_nbytes We track in the core the internal address mode of the flash. Stop using hardcoded values for the number of bytes of address and use nor->addr_nbytes and nor->params->addr_mode_nbytes instead. Signed-off-by: Tudor Ambarus Tested-by: Takahiro Kuwano Link: https://lore.kernel.org/r/20220728041451.85559-2-tudor.ambarus@microchip.com --- drivers/mtd/spi-nor/spansion.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/spi-nor/spansion.c b/drivers/mtd/spi-nor/spansion.c index bd9edfd3cd3c..b621cdfd506f 100644 --- a/drivers/mtd/spi-nor/spansion.c +++ b/drivers/mtd/spi-nor/spansion.c @@ -49,11 +49,13 @@ static int cypress_nor_octal_dtr_en(struct spi_nor *nor) struct spi_mem_op op; u8 *buf = nor->bouncebuf; int ret; + u8 addr_mode_nbytes = nor->params->addr_mode_nbytes; /* Use 24 dummy cycles for memory array reads. */ *buf = SPINOR_REG_CYPRESS_CFR2V_MEMLAT_11_24; op = (struct spi_mem_op) - CYPRESS_NOR_WR_ANY_REG_OP(3, SPINOR_REG_CYPRESS_CFR2V, 1, buf); + CYPRESS_NOR_WR_ANY_REG_OP(addr_mode_nbytes, + SPINOR_REG_CYPRESS_CFR2V, 1, buf); ret = spi_nor_write_any_volatile_reg(nor, &op, nor->reg_proto); if (ret) @@ -64,14 +66,16 @@ static int cypress_nor_octal_dtr_en(struct spi_nor *nor) /* Set the octal and DTR enable bits. */ buf[0] = SPINOR_REG_CYPRESS_CFR5V_OCT_DTR_EN; op = (struct spi_mem_op) - CYPRESS_NOR_WR_ANY_REG_OP(3, SPINOR_REG_CYPRESS_CFR5V, 1, buf); + CYPRESS_NOR_WR_ANY_REG_OP(addr_mode_nbytes, + SPINOR_REG_CYPRESS_CFR5V, 1, buf); ret = spi_nor_write_any_volatile_reg(nor, &op, nor->reg_proto); if (ret) return ret; /* Read flash ID to make sure the switch was successful. */ - ret = spi_nor_read_id(nor, 4, 3, buf, SNOR_PROTO_8_8_8_DTR); + ret = spi_nor_read_id(nor, nor->addr_nbytes, 3, buf, + SNOR_PROTO_8_8_8_DTR); if (ret) { dev_dbg(nor->dev, "error %d reading JEDEC ID after enabling 8D-8D-8D mode\n", ret); return ret; @@ -97,7 +101,8 @@ static int cypress_nor_octal_dtr_dis(struct spi_nor *nor) buf[0] = SPINOR_REG_CYPRESS_CFR5V_OCT_DTR_DS; buf[1] = 0; op = (struct spi_mem_op) - CYPRESS_NOR_WR_ANY_REG_OP(4, SPINOR_REG_CYPRESS_CFR5V, 2, buf); + CYPRESS_NOR_WR_ANY_REG_OP(nor->addr_nbytes, + SPINOR_REG_CYPRESS_CFR5V, 2, buf); ret = spi_nor_write_any_volatile_reg(nor, &op, SNOR_PROTO_8_8_8_DTR); if (ret) return ret; @@ -191,7 +196,8 @@ static int cypress_nor_quad_enable_volatile(struct spi_nor *nor) static int cypress_nor_set_page_size(struct spi_nor *nor) { struct spi_mem_op op = - CYPRESS_NOR_RD_ANY_REG_OP(3, SPINOR_REG_CYPRESS_CFR3V, + CYPRESS_NOR_RD_ANY_REG_OP(nor->params->addr_mode_nbytes, + SPINOR_REG_CYPRESS_CFR3V, nor->bouncebuf); int ret; -- cgit v1.2.3 From 2fe99a867050bc3506a4595acc01375a48a1b87e Mon Sep 17 00:00:00 2001 From: Tudor Ambarus Date: Thu, 28 Jul 2022 07:14:51 +0300 Subject: mtd: spi-nor: micron-st.c: Replace hardcoded values for addr_nbytes/addr_mode_nbytes We track in the core the internal address mode of the flash. Stop using hardcoded values for the number of bytes of address and use nor->addr_nbytes and nor->params->addr_mode_nbytes instead. Signed-off-by: Tudor Ambarus Link: https://lore.kernel.org/r/20220728041451.85559-3-tudor.ambarus@microchip.com --- drivers/mtd/spi-nor/micron-st.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/spi-nor/micron-st.c b/drivers/mtd/spi-nor/micron-st.c index 3c9681a3f7a3..3c8a90b39c8c 100644 --- a/drivers/mtd/spi-nor/micron-st.c +++ b/drivers/mtd/spi-nor/micron-st.c @@ -52,18 +52,21 @@ static int micron_st_nor_octal_dtr_en(struct spi_nor *nor) struct spi_mem_op op; u8 *buf = nor->bouncebuf; int ret; + u8 addr_mode_nbytes = nor->params->addr_mode_nbytes; /* Use 20 dummy cycles for memory array reads. */ *buf = 20; op = (struct spi_mem_op) - MICRON_ST_NOR_WR_ANY_REG_OP(3, SPINOR_REG_MT_CFR1V, 1, buf); + MICRON_ST_NOR_WR_ANY_REG_OP(addr_mode_nbytes, + SPINOR_REG_MT_CFR1V, 1, buf); ret = spi_nor_write_any_volatile_reg(nor, &op, nor->reg_proto); if (ret) return ret; buf[0] = SPINOR_MT_OCT_DTR; op = (struct spi_mem_op) - MICRON_ST_NOR_WR_ANY_REG_OP(3, SPINOR_REG_MT_CFR0V, 1, buf); + MICRON_ST_NOR_WR_ANY_REG_OP(addr_mode_nbytes, + SPINOR_REG_MT_CFR0V, 1, buf); ret = spi_nor_write_any_volatile_reg(nor, &op, nor->reg_proto); if (ret) return ret; @@ -98,7 +101,8 @@ static int micron_st_nor_octal_dtr_dis(struct spi_nor *nor) buf[0] = SPINOR_MT_EXSPI; buf[1] = SPINOR_REG_MT_CFR1V_DEF; op = (struct spi_mem_op) - MICRON_ST_NOR_WR_ANY_REG_OP(4, SPINOR_REG_MT_CFR0V, 2, buf); + MICRON_ST_NOR_WR_ANY_REG_OP(nor->addr_nbytes, + SPINOR_REG_MT_CFR0V, 2, buf); ret = spi_nor_write_any_volatile_reg(nor, &op, SNOR_PROTO_8_8_8_DTR); if (ret) return ret; -- cgit v1.2.3 From bb0e9c600ce23a308b31e73d10b56e70a5721088 Mon Sep 17 00:00:00 2001 From: Tudor Ambarus Date: Thu, 28 Jul 2022 06:01:59 +0300 Subject: mtd: spi-nor: core: Add an error message when failing to exit the 4-byte address mode Add an error message when failing to exit the 4-byte address mode. Do not stop the execution and go through the spi_nor_soft_reset() method if used, in the hope that the flash will default to 3-byte address mode after the reset. Suggested-by: Pratyush Yadav Signed-off-by: Tudor Ambarus Reviewed-by: Pratyush Yadav Link: https://lore.kernel.org/r/20220728030159.68680-1-tudor.ambarus@microchip.com --- drivers/mtd/spi-nor/core.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c index a78ab9bae2be..aa05443c44c2 100644 --- a/drivers/mtd/spi-nor/core.c +++ b/drivers/mtd/spi-nor/core.c @@ -2838,10 +2838,20 @@ static void spi_nor_put_device(struct mtd_info *mtd) void spi_nor_restore(struct spi_nor *nor) { + int ret; + /* restore the addressing mode */ if (nor->addr_nbytes == 4 && !(nor->flags & SNOR_F_4B_OPCODES) && - nor->flags & SNOR_F_BROKEN_RESET) - nor->params->set_4byte_addr_mode(nor, false); + nor->flags & SNOR_F_BROKEN_RESET) { + ret = nor->params->set_4byte_addr_mode(nor, false); + if (ret) + /* + * Do not stop the execution in the hope that the flash + * will default to the 3-byte address mode after the + * software reset. + */ + dev_err(nor->dev, "Failed to exit 4-byte address mode, err = %d\n", ret); + } if (nor->flags & SNOR_F_SOFT_RESET) spi_nor_soft_reset(nor); -- cgit v1.2.3 From c5f5d0cd40e3bc2d6d397af788a7c0241b1c6b68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Tue, 4 Oct 2022 10:37:09 +0200 Subject: mtd: core: simplify (a bit) code find partition-matching dynamic OF node MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. Don't hardcode "partition-" string twice 2. Use simpler logic & use ->name to avoid of_property_read_string() 3. Use mtd_get_of_node() helper Cc: Christian Marangi Signed-off-by: Rafał Miłecki Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20221004083710.27704-1-zajec5@gmail.com --- drivers/mtd/mtdcore.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index 0b4ca0aa4132..6ad62ff7be23 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -551,18 +551,17 @@ static void mtd_check_of_node(struct mtd_info *mtd) struct device_node *partitions, *parent_dn, *mtd_dn = NULL; const char *pname, *prefix = "partition-"; int plen, mtd_name_len, offset, prefix_len; - struct mtd_info *parent; bool found = false; /* Check if MTD already has a device node */ - if (dev_of_node(&mtd->dev)) + if (mtd_get_of_node(mtd)) return; /* Check if a partitions node exist */ if (!mtd_is_partition(mtd)) return; - parent = mtd->parent; - parent_dn = of_node_get(dev_of_node(&parent->dev)); + + parent_dn = of_node_get(mtd_get_of_node(mtd->parent)); if (!parent_dn) return; @@ -575,15 +574,15 @@ static void mtd_check_of_node(struct mtd_info *mtd) /* Search if a partition is defined with the same name */ for_each_child_of_node(partitions, mtd_dn) { - offset = 0; - /* Skip partition with no/wrong prefix */ - if (!of_node_name_prefix(mtd_dn, "partition-")) + if (!of_node_name_prefix(mtd_dn, prefix)) continue; /* Label have priority. Check that first */ - if (of_property_read_string(mtd_dn, "label", &pname)) { - of_property_read_string(mtd_dn, "name", &pname); + if (!of_property_read_string(mtd_dn, "label", &pname)) { + offset = 0; + } else { + pname = mtd_dn->name; offset = prefix_len; } -- cgit v1.2.3 From 2df11f00100d7278185a9dbefa20ba3f5d32401d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Tue, 4 Oct 2022 10:37:10 +0200 Subject: mtd: core: try to find OF node for every MTD partition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit So far this feature was limited to the top-level "nvmem-cells" node. There are multiple parsers creating partitions and subpartitions dynamically. Extend that code to handle them too. This allows finding partition-* node for every MTD (sub)partition. Random example: partitions { compatible = "brcm,bcm947xx-cfe-partitions"; partition-firmware { compatible = "brcm,trx"; partition-loader { }; }; }; Cc: Christian Marangi Signed-off-by: Rafał Miłecki Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20221004083710.27704-2-zajec5@gmail.com --- drivers/mtd/mtdcore.c | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index 6ad62ff7be23..20fcedc3021e 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -551,13 +551,11 @@ static void mtd_check_of_node(struct mtd_info *mtd) struct device_node *partitions, *parent_dn, *mtd_dn = NULL; const char *pname, *prefix = "partition-"; int plen, mtd_name_len, offset, prefix_len; - bool found = false; /* Check if MTD already has a device node */ if (mtd_get_of_node(mtd)) return; - /* Check if a partitions node exist */ if (!mtd_is_partition(mtd)) return; @@ -565,7 +563,10 @@ static void mtd_check_of_node(struct mtd_info *mtd) if (!parent_dn) return; - partitions = of_get_child_by_name(parent_dn, "partitions"); + if (mtd_is_partition(mtd->parent)) + partitions = of_node_get(parent_dn); + else + partitions = of_get_child_by_name(parent_dn, "partitions"); if (!partitions) goto exit_parent; @@ -589,19 +590,11 @@ static void mtd_check_of_node(struct mtd_info *mtd) plen = strlen(pname) - offset; if (plen == mtd_name_len && !strncmp(mtd->name, pname + offset, plen)) { - found = true; + mtd_set_of_node(mtd, mtd_dn); break; } } - if (!found) - goto exit_partitions; - - /* Set of_node only for nvmem */ - if (of_device_is_compatible(mtd_dn, "nvmem-cells")) - mtd_set_of_node(mtd, mtd_dn); - -exit_partitions: of_node_put(partitions); exit_parent: of_node_put(parent_dn); -- cgit v1.2.3 From 43cfba56d312f0a45e0b3eaa63606e05ae7fac14 Mon Sep 17 00:00:00 2001 From: Ray Zhang Date: Mon, 10 Oct 2022 04:55:47 +0000 Subject: mtd: mtdoops: change printk() to counterpart pr_ functions To comply with latest kernel code requirement, change printk() to counterpart pr_ functions in mtdoops driver: - change printk(INFO) to pr_info() - change printk(DEBUG) to pr_debug() - change printk(WARNING) to pr_warn() - change printk(ERR) to pr_err() Note that only if dynamic debugging is enabled or DEBUG is defined, printk(KERN_DEBUG) and pr_debug() are equivalent; Otherwise pr_debug() is no-op, causing different behavior. Signed-off-by: Ray Zhang Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20221010045549.2221965-2-sgzhang@google.com --- drivers/mtd/mtdoops.c | 52 ++++++++++++++++++++++++++------------------------- 1 file changed, 27 insertions(+), 25 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/mtdoops.c b/drivers/mtd/mtdoops.c index 3d4a2ffb5b01..6b70331da3b6 100644 --- a/drivers/mtd/mtdoops.c +++ b/drivers/mtd/mtdoops.c @@ -7,6 +7,8 @@ * Author: Richard Purdie */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -93,9 +95,9 @@ static int mtdoops_erase_block(struct mtdoops_context *cxt, int offset) ret = mtd_erase(mtd, &erase); if (ret) { - printk(KERN_WARNING "mtdoops: erase of region [0x%llx, 0x%llx] on \"%s\" failed\n", - (unsigned long long)erase.addr, - (unsigned long long)erase.len, mtddev); + pr_warn("erase of region [0x%llx, 0x%llx] on \"%s\" failed\n", + (unsigned long long)erase.addr, + (unsigned long long)erase.len, mtddev); return ret; } @@ -120,8 +122,8 @@ static void mtdoops_inc_counter(struct mtdoops_context *cxt) return; } - printk(KERN_DEBUG "mtdoops: ready %d, %d (no erase)\n", - cxt->nextpage, cxt->nextcount); + pr_debug("ready %d, %d (no erase)\n", + cxt->nextpage, cxt->nextcount); } /* Scheduled work - when we can't proceed without erasing a block */ @@ -145,20 +147,20 @@ static void mtdoops_workfunc_erase(struct work_struct *work) while ((ret = mtd_block_isbad(mtd, cxt->nextpage * record_size)) > 0) { badblock: - printk(KERN_WARNING "mtdoops: bad block at %08lx\n", - cxt->nextpage * record_size); + pr_warn("bad block at %08lx\n", + cxt->nextpage * record_size); i++; cxt->nextpage = cxt->nextpage + (mtd->erasesize / record_size); if (cxt->nextpage >= cxt->oops_pages) cxt->nextpage = 0; if (i == cxt->oops_pages / (mtd->erasesize / record_size)) { - printk(KERN_ERR "mtdoops: all blocks bad!\n"); + pr_err("all blocks bad!\n"); return; } } if (ret < 0) { - printk(KERN_ERR "mtdoops: mtd_block_isbad failed, aborting\n"); + pr_err("mtd_block_isbad failed, aborting\n"); return; } @@ -166,15 +168,15 @@ badblock: ret = mtdoops_erase_block(cxt, cxt->nextpage * record_size); if (ret >= 0) { - printk(KERN_DEBUG "mtdoops: ready %d, %d\n", - cxt->nextpage, cxt->nextcount); + pr_debug("ready %d, %d\n", + cxt->nextpage, cxt->nextcount); return; } if (ret == -EIO) { ret = mtd_block_markbad(mtd, cxt->nextpage * record_size); if (ret < 0 && ret != -EOPNOTSUPP) { - printk(KERN_ERR "mtdoops: block_markbad failed, aborting\n"); + pr_err("block_markbad failed, aborting\n"); return; } } @@ -201,7 +203,7 @@ static void mtdoops_write(struct mtdoops_context *cxt, int panic) ret = mtd_panic_write(mtd, cxt->nextpage * record_size, record_size, &retlen, cxt->oops_buf); if (ret == -EOPNOTSUPP) { - printk(KERN_ERR "mtdoops: Cannot write from panic without panic_write\n"); + pr_err("Cannot write from panic without panic_write\n"); goto out; } } else @@ -209,7 +211,7 @@ static void mtdoops_write(struct mtdoops_context *cxt, int panic) record_size, &retlen, cxt->oops_buf); if (retlen != record_size || ret < 0) - printk(KERN_ERR "mtdoops: write failure at %ld (%td of %ld written), error %d\n", + pr_err("write failure at %ld (%td of %ld written), error %d\n", cxt->nextpage * record_size, retlen, record_size, ret); mark_page_used(cxt, cxt->nextpage); memset(cxt->oops_buf, 0xff, record_size); @@ -244,7 +246,7 @@ static void find_next_position(struct mtdoops_context *cxt) &retlen, (u_char *)&hdr); if (retlen != sizeof(hdr) || (ret < 0 && !mtd_is_bitflip(ret))) { - printk(KERN_ERR "mtdoops: read failure at %ld (%zu of %zu read), err %d\n", + pr_err("read failure at %ld (%zu of %zu read), err %d\n", page * record_size, retlen, sizeof(hdr), ret); continue; } @@ -324,17 +326,17 @@ static void mtdoops_notify_add(struct mtd_info *mtd) return; if (mtd->size < mtd->erasesize * 2) { - printk(KERN_ERR "mtdoops: MTD partition %d not big enough for mtdoops\n", + pr_err("MTD partition %d not big enough for mtdoops\n", mtd->index); return; } if (mtd->erasesize < record_size) { - printk(KERN_ERR "mtdoops: eraseblock size of MTD partition %d too small\n", + pr_err("eraseblock size of MTD partition %d too small\n", mtd->index); return; } if (mtd->size > MTDOOPS_MAX_MTD_SIZE) { - printk(KERN_ERR "mtdoops: mtd%d is too large (limit is %d MiB)\n", + pr_err("mtd%d is too large (limit is %d MiB)\n", mtd->index, MTDOOPS_MAX_MTD_SIZE / 1024 / 1024); return; } @@ -345,7 +347,7 @@ static void mtdoops_notify_add(struct mtd_info *mtd) DIV_ROUND_UP(mtdoops_pages, BITS_PER_LONG))); if (!cxt->oops_page_used) { - printk(KERN_ERR "mtdoops: could not allocate page array\n"); + pr_err("could not allocate page array\n"); return; } @@ -353,7 +355,7 @@ static void mtdoops_notify_add(struct mtd_info *mtd) cxt->dump.dump = mtdoops_do_dump; err = kmsg_dump_register(&cxt->dump); if (err) { - printk(KERN_ERR "mtdoops: registering kmsg dumper failed, error %d\n", err); + pr_err("registering kmsg dumper failed, error %d\n", err); vfree(cxt->oops_page_used); cxt->oops_page_used = NULL; return; @@ -362,7 +364,7 @@ static void mtdoops_notify_add(struct mtd_info *mtd) cxt->mtd = mtd; cxt->oops_pages = (int)mtd->size / record_size; find_next_position(cxt); - printk(KERN_INFO "mtdoops: Attached to MTD device %d\n", mtd->index); + pr_info("Attached to MTD device %d\n", mtd->index); } static void mtdoops_notify_remove(struct mtd_info *mtd) @@ -373,7 +375,7 @@ static void mtdoops_notify_remove(struct mtd_info *mtd) return; if (kmsg_dump_unregister(&cxt->dump) < 0) - printk(KERN_WARNING "mtdoops: could not unregister kmsg_dumper\n"); + pr_warn("could not unregister kmsg_dumper\n"); cxt->mtd = NULL; flush_work(&cxt->work_erase); @@ -393,15 +395,15 @@ static int __init mtdoops_init(void) char *endp; if (strlen(mtddev) == 0) { - printk(KERN_ERR "mtdoops: mtd device (mtddev=name/number) must be supplied\n"); + pr_err("mtd device (mtddev=name/number) must be supplied\n"); return -EINVAL; } if ((record_size & 4095) != 0) { - printk(KERN_ERR "mtdoops: record_size must be a multiple of 4096\n"); + pr_err("record_size must be a multiple of 4096\n"); return -EINVAL; } if (record_size < 4096) { - printk(KERN_ERR "mtdoops: record_size must be over 4096 bytes\n"); + pr_err("record_size must be over 4096 bytes\n"); return -EINVAL; } -- cgit v1.2.3 From 340193e079a899f5527cddccff2b5de2c98bc31b Mon Sep 17 00:00:00 2001 From: Ray Zhang Date: Mon, 10 Oct 2022 04:55:48 +0000 Subject: mtd: mtdoops: add mtdoops_erase function and move mtdoops_inc_counter to after it Preparing for next patch with minimal code difference, add mtdoops_erase function and move mtdoops_inc_counter to after it, with no functional change. Signed-off-by: Ray Zhang Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20221010045549.2221965-3-sgzhang@google.com --- drivers/mtd/mtdoops.c | 49 +++++++++++++++++++++++++++---------------------- 1 file changed, 27 insertions(+), 22 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/mtdoops.c b/drivers/mtd/mtdoops.c index 6b70331da3b6..0226b9e9ea8f 100644 --- a/drivers/mtd/mtdoops.c +++ b/drivers/mtd/mtdoops.c @@ -108,29 +108,8 @@ static int mtdoops_erase_block(struct mtdoops_context *cxt, int offset) return 0; } -static void mtdoops_inc_counter(struct mtdoops_context *cxt) -{ - cxt->nextpage++; - if (cxt->nextpage >= cxt->oops_pages) - cxt->nextpage = 0; - cxt->nextcount++; - if (cxt->nextcount == 0xffffffff) - cxt->nextcount = 0; - - if (page_is_used(cxt, cxt->nextpage)) { - schedule_work(&cxt->work_erase); - return; - } - - pr_debug("ready %d, %d (no erase)\n", - cxt->nextpage, cxt->nextcount); -} - -/* Scheduled work - when we can't proceed without erasing a block */ -static void mtdoops_workfunc_erase(struct work_struct *work) +static void mtdoops_erase(struct mtdoops_context *cxt) { - struct mtdoops_context *cxt = - container_of(work, struct mtdoops_context, work_erase); struct mtd_info *mtd = cxt->mtd; int i = 0, j, ret, mod; @@ -183,6 +162,32 @@ badblock: goto badblock; } +/* Scheduled work - when we can't proceed without erasing a block */ +static void mtdoops_workfunc_erase(struct work_struct *work) +{ + struct mtdoops_context *cxt = + container_of(work, struct mtdoops_context, work_erase); + mtdoops_erase(cxt); +} + +static void mtdoops_inc_counter(struct mtdoops_context *cxt) +{ + cxt->nextpage++; + if (cxt->nextpage >= cxt->oops_pages) + cxt->nextpage = 0; + cxt->nextcount++; + if (cxt->nextcount == 0xffffffff) + cxt->nextcount = 0; + + if (page_is_used(cxt, cxt->nextpage)) { + schedule_work(&cxt->work_erase); + return; + } + + pr_debug("ready %d, %d (no erase)\n", + cxt->nextpage, cxt->nextcount); +} + static void mtdoops_write(struct mtdoops_context *cxt, int panic) { struct mtd_info *mtd = cxt->mtd; -- cgit v1.2.3 From 7cc84e0e07d063c246809ea78f51607f858766bf Mon Sep 17 00:00:00 2001 From: Ray Zhang Date: Mon, 10 Oct 2022 04:55:49 +0000 Subject: mtd: mtdoops: panic caused mtdoops to call mtdoops_erase function immediately The panic function disables the local interrupts, preemption, and all other processors. When the invoked mtdoops needs to erase a used page, calling schedule_work() to do it will not work. Instead, just call mtdoops_erase function immediately. Tested: ~# echo c > /proc/sysrq-trigger [ 171.654759] sysrq: Trigger a crash [ 171.658325] Kernel panic - not syncing: sysrq triggered crash ...... [ 172.406423] mtdoops: not ready 34, 35 (erase immediately) [ 172.432285] mtdoops: ready 34, 35 [ 172.435633] Rebooting in 10 seconds.. Signed-off-by: Ray Zhang Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20221010045549.2221965-4-sgzhang@google.com --- drivers/mtd/mtdoops.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/mtdoops.c b/drivers/mtd/mtdoops.c index 0226b9e9ea8f..2f11585b5613 100644 --- a/drivers/mtd/mtdoops.c +++ b/drivers/mtd/mtdoops.c @@ -170,7 +170,7 @@ static void mtdoops_workfunc_erase(struct work_struct *work) mtdoops_erase(cxt); } -static void mtdoops_inc_counter(struct mtdoops_context *cxt) +static void mtdoops_inc_counter(struct mtdoops_context *cxt, int panic) { cxt->nextpage++; if (cxt->nextpage >= cxt->oops_pages) @@ -180,12 +180,20 @@ static void mtdoops_inc_counter(struct mtdoops_context *cxt) cxt->nextcount = 0; if (page_is_used(cxt, cxt->nextpage)) { - schedule_work(&cxt->work_erase); - return; + pr_debug("not ready %d, %d (erase %s)\n", + cxt->nextpage, cxt->nextcount, + panic ? "immediately" : "scheduled"); + if (panic) { + /* In case of panic, erase immediately */ + mtdoops_erase(cxt); + } else { + /* Otherwise, schedule work to erase it "nicely" */ + schedule_work(&cxt->work_erase); + } + } else { + pr_debug("ready %d, %d (no erase)\n", + cxt->nextpage, cxt->nextcount); } - - pr_debug("ready %d, %d (no erase)\n", - cxt->nextpage, cxt->nextcount); } static void mtdoops_write(struct mtdoops_context *cxt, int panic) @@ -221,7 +229,7 @@ static void mtdoops_write(struct mtdoops_context *cxt, int panic) mark_page_used(cxt, cxt->nextpage); memset(cxt->oops_buf, 0xff, record_size); - mtdoops_inc_counter(cxt); + mtdoops_inc_counter(cxt, panic); out: clear_bit(0, &cxt->oops_buf_busy); } @@ -286,7 +294,7 @@ static void find_next_position(struct mtdoops_context *cxt) cxt->nextcount = maxcount; } - mtdoops_inc_counter(cxt); + mtdoops_inc_counter(cxt, 0); } static void mtdoops_do_dump(struct kmsg_dumper *dumper, -- cgit v1.2.3 From 00a3588084bee6f37bb2b1d343f96900cfe049bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Sat, 15 Oct 2022 11:29:50 +0200 Subject: mtd: parsers: add TP-Link SafeLoader partitions table parser MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This parser deals with most TP-Link home routers. It reads info about partitions and registers them in the MTD subsystem. Example from TP-Link Archer C5 V2: spi-nor spi0.0: s25fl128s1 (16384 Kbytes) 15 tplink-safeloader partitions found on MTD device spi0.0 Creating 15 MTD partitions on "spi0.0": 0x000000000000-0x000000040000 : "fs-uboot" 0x000000040000-0x000000440000 : "os-image" 0x000000440000-0x000000e40000 : "rootfs" 0x000000e40000-0x000000e40200 : "default-mac" 0x000000e40200-0x000000e40400 : "pin" 0x000000e40400-0x000000e40600 : "product-info" 0x000000e50000-0x000000e60000 : "partition-table" 0x000000e60000-0x000000e60200 : "soft-version" 0x000000e61000-0x000000e70000 : "support-list" 0x000000e70000-0x000000e80000 : "profile" 0x000000e80000-0x000000e90000 : "default-config" 0x000000e90000-0x000000ee0000 : "user-config" 0x000000ee0000-0x000000fe0000 : "log" 0x000000fe0000-0x000000ff0000 : "radio_bk" 0x000000ff0000-0x000001000000 : "radio" Signed-off-by: Rafał Miłecki Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20221015092950.27467-2-zajec5@gmail.com --- drivers/mtd/parsers/Kconfig | 15 ++++ drivers/mtd/parsers/Makefile | 1 + drivers/mtd/parsers/tplink_safeloader.c | 150 ++++++++++++++++++++++++++++++++ 3 files changed, 166 insertions(+) create mode 100644 drivers/mtd/parsers/tplink_safeloader.c (limited to 'drivers/mtd') diff --git a/drivers/mtd/parsers/Kconfig b/drivers/mtd/parsers/Kconfig index aaa06050c9bc..c258ba2a3a6f 100644 --- a/drivers/mtd/parsers/Kconfig +++ b/drivers/mtd/parsers/Kconfig @@ -123,6 +123,21 @@ config MTD_AFS_PARTS for your particular device. It won't happen automatically. The 'physmap' map driver (CONFIG_MTD_PHYSMAP) does this, for example. +config MTD_PARSER_TPLINK_SAFELOADER + tristate "TP-Link Safeloader partitions parser" + depends on MTD && (ARCH_BCM_5301X || ATH79 || SOC_MT7620 || SOC_MT7621 || COMPILE_TEST) + help + TP-Link home routers use flash partitions to store various data. Info + about flash space layout is stored in a partitions table using a + custom ASCII-based format. + + That format was first found in devices with SafeLoader bootloader and + was named after it. Later it was adapted to CFE and U-Boot + bootloaders. + + This driver reads partitions table, parses it and creates MTD + partitions. + config MTD_PARSER_TRX tristate "Parser for TRX format partitions" depends on MTD && (BCM47XX || ARCH_BCM_5301X || ARCH_MEDIATEK || RALINK || COMPILE_TEST) diff --git a/drivers/mtd/parsers/Makefile b/drivers/mtd/parsers/Makefile index 23fa4de4016f..0e70b621a1d8 100644 --- a/drivers/mtd/parsers/Makefile +++ b/drivers/mtd/parsers/Makefile @@ -10,6 +10,7 @@ ofpart-$(CONFIG_MTD_OF_PARTS_BCM4908) += ofpart_bcm4908.o ofpart-$(CONFIG_MTD_OF_PARTS_LINKSYS_NS)+= ofpart_linksys_ns.o obj-$(CONFIG_MTD_PARSER_IMAGETAG) += parser_imagetag.o obj-$(CONFIG_MTD_AFS_PARTS) += afs.o +obj-$(CONFIG_MTD_PARSER_TPLINK_SAFELOADER) += tplink_safeloader.o obj-$(CONFIG_MTD_PARSER_TRX) += parser_trx.o obj-$(CONFIG_MTD_SERCOMM_PARTS) += scpart.o obj-$(CONFIG_MTD_SHARPSL_PARTS) += sharpslpart.o diff --git a/drivers/mtd/parsers/tplink_safeloader.c b/drivers/mtd/parsers/tplink_safeloader.c new file mode 100644 index 000000000000..23584a477391 --- /dev/null +++ b/drivers/mtd/parsers/tplink_safeloader.c @@ -0,0 +1,150 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright © 2022 Rafał Miłecki + */ + +#include +#include +#include +#include +#include +#include + +#define TPLINK_SAFELOADER_DATA_OFFSET 4 +#define TPLINK_SAFELOADER_MAX_PARTS 32 + +struct safeloader_cmn_header { + __be32 size; + uint32_t unused; +} __packed; + +static void *mtd_parser_tplink_safeloader_read_table(struct mtd_info *mtd) +{ + struct safeloader_cmn_header hdr; + struct device_node *np; + size_t bytes_read; + size_t offset; + size_t size; + char *buf; + int err; + + np = mtd_get_of_node(mtd); + if (mtd_is_partition(mtd)) + of_node_get(np); + else + np = of_get_child_by_name(np, "partitions"); + + if (of_property_read_u32(np, "partitions-table-offset", (u32 *)&offset)) { + pr_err("Failed to get partitions table offset\n"); + goto err_put; + } + + err = mtd_read(mtd, offset, sizeof(hdr), &bytes_read, (uint8_t *)&hdr); + if (err && !mtd_is_bitflip(err)) { + pr_err("Failed to read from %s at 0x%zx\n", mtd->name, offset); + goto err_put; + } + + size = be32_to_cpu(hdr.size); + + buf = kmalloc(size + 1, GFP_KERNEL); + if (!buf) + goto err_put; + + err = mtd_read(mtd, offset + sizeof(hdr), size, &bytes_read, buf); + if (err && !mtd_is_bitflip(err)) { + pr_err("Failed to read from %s at 0x%zx\n", mtd->name, offset + sizeof(hdr)); + goto err_kfree; + } + + buf[size] = '\0'; + + of_node_put(np); + + return buf; + +err_kfree: + kfree(buf); +err_put: + of_node_put(np); + return NULL; +} + +static int mtd_parser_tplink_safeloader_parse(struct mtd_info *mtd, + const struct mtd_partition **pparts, + struct mtd_part_parser_data *data) +{ + struct mtd_partition *parts; + char name[65]; + size_t offset; + size_t bytes; + char *buf; + int idx; + int err; + + parts = kcalloc(TPLINK_SAFELOADER_MAX_PARTS, sizeof(*parts), GFP_KERNEL); + if (!parts) { + err = -ENOMEM; + goto err_out; + } + + buf = mtd_parser_tplink_safeloader_read_table(mtd); + if (!buf) { + err = -ENOENT; + goto err_out; + } + + for (idx = 0, offset = TPLINK_SAFELOADER_DATA_OFFSET; + idx < TPLINK_SAFELOADER_MAX_PARTS && + sscanf(buf + offset, "partition %64s base 0x%llx size 0x%llx%zn\n", + name, &parts[idx].offset, &parts[idx].size, &bytes) == 3; + idx++, offset += bytes + 1) { + parts[idx].name = kstrdup(name, GFP_KERNEL); + if (!parts[idx].name) { + err = -ENOMEM; + goto err_free; + } + } + + if (idx == TPLINK_SAFELOADER_MAX_PARTS) + pr_warn("Reached maximum number of partitions!\n"); + + kfree(buf); + + *pparts = parts; + + return idx; + +err_free: + for (idx -= 1; idx >= 0; idx--) + kfree(parts[idx].name); +err_out: + return err; +}; + +static void mtd_parser_tplink_safeloader_cleanup(const struct mtd_partition *pparts, + int nr_parts) +{ + int i; + + for (i = 0; i < nr_parts; i++) + kfree(pparts[i].name); + + kfree(pparts); +} + +static const struct of_device_id mtd_parser_tplink_safeloader_of_match_table[] = { + { .compatible = "tplink,safeloader-partitions" }, + {}, +}; +MODULE_DEVICE_TABLE(of, mtd_parser_tplink_safeloader_of_match_table); + +static struct mtd_part_parser mtd_parser_tplink_safeloader = { + .parse_fn = mtd_parser_tplink_safeloader_parse, + .cleanup = mtd_parser_tplink_safeloader_cleanup, + .name = "tplink-safeloader", + .of_match_table = mtd_parser_tplink_safeloader_of_match_table, +}; +module_mtd_part_parser(mtd_parser_tplink_safeloader); + +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 6c0a15a3dc6b45156c5b9568c8308e3f0d802af0 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 25 Oct 2022 18:34:24 +0300 Subject: mtd: parsers: tplink_safeloader: fix uninitialized variable bug MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On 64 bit systems, the highest 32 bits of the "offset" variable are not initialized. Also the existing code is not endian safe (it will fail on big endian systems). Change the type of "offset" to a u32. Fixes: aec4d5f5ffd0 ("mtd: parsers: add TP-Link SafeLoader partitions table parser") Signed-off-by: Dan Carpenter Acked-by: Rafał Miłecki Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/Y1gCALFWXYYwqV1P@kili --- drivers/mtd/parsers/tplink_safeloader.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/parsers/tplink_safeloader.c b/drivers/mtd/parsers/tplink_safeloader.c index 23584a477391..f601e7bd8627 100644 --- a/drivers/mtd/parsers/tplink_safeloader.c +++ b/drivers/mtd/parsers/tplink_safeloader.c @@ -23,8 +23,8 @@ static void *mtd_parser_tplink_safeloader_read_table(struct mtd_info *mtd) struct safeloader_cmn_header hdr; struct device_node *np; size_t bytes_read; - size_t offset; size_t size; + u32 offset; char *buf; int err; @@ -34,14 +34,14 @@ static void *mtd_parser_tplink_safeloader_read_table(struct mtd_info *mtd) else np = of_get_child_by_name(np, "partitions"); - if (of_property_read_u32(np, "partitions-table-offset", (u32 *)&offset)) { + if (of_property_read_u32(np, "partitions-table-offset", &offset)) { pr_err("Failed to get partitions table offset\n"); goto err_put; } err = mtd_read(mtd, offset, sizeof(hdr), &bytes_read, (uint8_t *)&hdr); if (err && !mtd_is_bitflip(err)) { - pr_err("Failed to read from %s at 0x%zx\n", mtd->name, offset); + pr_err("Failed to read from %s at 0x%x\n", mtd->name, offset); goto err_put; } -- cgit v1.2.3 From a6c5f12b0df22574f8eb02b0159bc71ac66c1a64 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 21 Oct 2022 17:49:36 +0200 Subject: mtd: remove lart flash driver The sa1100 lart platform was removed, so its flash driver is no longer useful. Signed-off-by: Arnd Bergmann Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20221021155000.4108406-7-arnd@kernel.org --- drivers/mtd/devices/Kconfig | 8 - drivers/mtd/devices/Makefile | 1 - drivers/mtd/devices/lart.c | 682 ------------------------------------------- 3 files changed, 691 deletions(-) delete mode 100644 drivers/mtd/devices/lart.c (limited to 'drivers/mtd') diff --git a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig index 79cb981ececc..ff2f9e55ef28 100644 --- a/drivers/mtd/devices/Kconfig +++ b/drivers/mtd/devices/Kconfig @@ -136,14 +136,6 @@ config MTD_PHRAM doesn't have access to, memory beyond the mem=xxx limit, nvram, memory on the video card, etc... -config MTD_LART - tristate "28F160xx flash driver for LART" - depends on SA1100_LART - help - This enables the flash driver for LART. Please note that you do - not need any mapping/chip driver for LART. This one does it all - for you, so go disable all of those if you enabled some of them (: - config MTD_MTDRAM tristate "Test driver using RAM" help diff --git a/drivers/mtd/devices/Makefile b/drivers/mtd/devices/Makefile index 0362cf6bdc67..d11eb2b8b6f8 100644 --- a/drivers/mtd/devices/Makefile +++ b/drivers/mtd/devices/Makefile @@ -9,7 +9,6 @@ obj-$(CONFIG_MTD_PHRAM) += phram.o obj-$(CONFIG_MTD_PMC551) += pmc551.o obj-$(CONFIG_MTD_MS02NV) += ms02-nv.o obj-$(CONFIG_MTD_MTDRAM) += mtdram.o -obj-$(CONFIG_MTD_LART) += lart.o obj-$(CONFIG_MTD_BLOCK2MTD) += block2mtd.o obj-$(CONFIG_MTD_DATAFLASH) += mtd_dataflash.o obj-$(CONFIG_MTD_MCHP23K256) += mchp23k256.o diff --git a/drivers/mtd/devices/lart.c b/drivers/mtd/devices/lart.c deleted file mode 100644 index aecd441e4183..000000000000 --- a/drivers/mtd/devices/lart.c +++ /dev/null @@ -1,682 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only - -/* - * MTD driver for the 28F160F3 Flash Memory (non-CFI) on LART. - * - * Author: Abraham vd Merwe - * - * Copyright (c) 2001, 2d3D, Inc. - * - * References: - * - * [1] 3 Volt Fast Boot Block Flash Memory" Intel Datasheet - * - Order Number: 290644-005 - * - January 2000 - * - * [2] MTD internal API documentation - * - http://www.linux-mtd.infradead.org/ - * - * Limitations: - * - * Even though this driver is written for 3 Volt Fast Boot - * Block Flash Memory, it is rather specific to LART. With - * Minor modifications, notably the without data/address line - * mangling and different bus settings, etc. it should be - * trivial to adapt to other platforms. - * - * If somebody would sponsor me a different board, I'll - * adapt the driver (: - */ - -/* debugging */ -//#define LART_DEBUG - -#include -#include -#include -#include -#include -#include -#include -#include - -#ifndef CONFIG_SA1100_LART -#error This is for LART architecture only -#endif - -static char module_name[] = "lart"; - -/* - * These values is specific to 28Fxxxx3 flash memory. - * See section 2.3.1 in "3 Volt Fast Boot Block Flash Memory" Intel Datasheet - */ -#define FLASH_BLOCKSIZE_PARAM (4096 * BUSWIDTH) -#define FLASH_NUMBLOCKS_16m_PARAM 8 -#define FLASH_NUMBLOCKS_8m_PARAM 8 - -/* - * These values is specific to 28Fxxxx3 flash memory. - * See section 2.3.2 in "3 Volt Fast Boot Block Flash Memory" Intel Datasheet - */ -#define FLASH_BLOCKSIZE_MAIN (32768 * BUSWIDTH) -#define FLASH_NUMBLOCKS_16m_MAIN 31 -#define FLASH_NUMBLOCKS_8m_MAIN 15 - -/* - * These values are specific to LART - */ - -/* general */ -#define BUSWIDTH 4 /* don't change this - a lot of the code _will_ break if you change this */ -#define FLASH_OFFSET 0xe8000000 /* see linux/arch/arm/mach-sa1100/lart.c */ - -/* blob */ -#define NUM_BLOB_BLOCKS FLASH_NUMBLOCKS_16m_PARAM -#define PART_BLOB_START 0x00000000 -#define PART_BLOB_LEN (NUM_BLOB_BLOCKS * FLASH_BLOCKSIZE_PARAM) - -/* kernel */ -#define NUM_KERNEL_BLOCKS 7 -#define PART_KERNEL_START (PART_BLOB_START + PART_BLOB_LEN) -#define PART_KERNEL_LEN (NUM_KERNEL_BLOCKS * FLASH_BLOCKSIZE_MAIN) - -/* initial ramdisk */ -#define NUM_INITRD_BLOCKS 24 -#define PART_INITRD_START (PART_KERNEL_START + PART_KERNEL_LEN) -#define PART_INITRD_LEN (NUM_INITRD_BLOCKS * FLASH_BLOCKSIZE_MAIN) - -/* - * See section 4.0 in "3 Volt Fast Boot Block Flash Memory" Intel Datasheet - */ -#define READ_ARRAY 0x00FF00FF /* Read Array/Reset */ -#define READ_ID_CODES 0x00900090 /* Read Identifier Codes */ -#define ERASE_SETUP 0x00200020 /* Block Erase */ -#define ERASE_CONFIRM 0x00D000D0 /* Block Erase and Program Resume */ -#define PGM_SETUP 0x00400040 /* Program */ -#define STATUS_READ 0x00700070 /* Read Status Register */ -#define STATUS_CLEAR 0x00500050 /* Clear Status Register */ -#define STATUS_BUSY 0x00800080 /* Write State Machine Status (WSMS) */ -#define STATUS_ERASE_ERR 0x00200020 /* Erase Status (ES) */ -#define STATUS_PGM_ERR 0x00100010 /* Program Status (PS) */ - -/* - * See section 4.2 in "3 Volt Fast Boot Block Flash Memory" Intel Datasheet - */ -#define FLASH_MANUFACTURER 0x00890089 -#define FLASH_DEVICE_8mbit_TOP 0x88f188f1 -#define FLASH_DEVICE_8mbit_BOTTOM 0x88f288f2 -#define FLASH_DEVICE_16mbit_TOP 0x88f388f3 -#define FLASH_DEVICE_16mbit_BOTTOM 0x88f488f4 - -/***************************************************************************************************/ - -/* - * The data line mapping on LART is as follows: - * - * U2 CPU | U3 CPU - * ------------------- - * 0 20 | 0 12 - * 1 22 | 1 14 - * 2 19 | 2 11 - * 3 17 | 3 9 - * 4 24 | 4 0 - * 5 26 | 5 2 - * 6 31 | 6 7 - * 7 29 | 7 5 - * 8 21 | 8 13 - * 9 23 | 9 15 - * 10 18 | 10 10 - * 11 16 | 11 8 - * 12 25 | 12 1 - * 13 27 | 13 3 - * 14 30 | 14 6 - * 15 28 | 15 4 - */ - -/* Mangle data (x) */ -#define DATA_TO_FLASH(x) \ - ( \ - (((x) & 0x08009000) >> 11) + \ - (((x) & 0x00002000) >> 10) + \ - (((x) & 0x04004000) >> 8) + \ - (((x) & 0x00000010) >> 4) + \ - (((x) & 0x91000820) >> 3) + \ - (((x) & 0x22080080) >> 2) + \ - ((x) & 0x40000400) + \ - (((x) & 0x00040040) << 1) + \ - (((x) & 0x00110000) << 4) + \ - (((x) & 0x00220100) << 5) + \ - (((x) & 0x00800208) << 6) + \ - (((x) & 0x00400004) << 9) + \ - (((x) & 0x00000001) << 12) + \ - (((x) & 0x00000002) << 13) \ - ) - -/* Unmangle data (x) */ -#define FLASH_TO_DATA(x) \ - ( \ - (((x) & 0x00010012) << 11) + \ - (((x) & 0x00000008) << 10) + \ - (((x) & 0x00040040) << 8) + \ - (((x) & 0x00000001) << 4) + \ - (((x) & 0x12200104) << 3) + \ - (((x) & 0x08820020) << 2) + \ - ((x) & 0x40000400) + \ - (((x) & 0x00080080) >> 1) + \ - (((x) & 0x01100000) >> 4) + \ - (((x) & 0x04402000) >> 5) + \ - (((x) & 0x20008200) >> 6) + \ - (((x) & 0x80000800) >> 9) + \ - (((x) & 0x00001000) >> 12) + \ - (((x) & 0x00004000) >> 13) \ - ) - -/* - * The address line mapping on LART is as follows: - * - * U3 CPU | U2 CPU - * ------------------- - * 0 2 | 0 2 - * 1 3 | 1 3 - * 2 9 | 2 9 - * 3 13 | 3 8 - * 4 8 | 4 7 - * 5 12 | 5 6 - * 6 11 | 6 5 - * 7 10 | 7 4 - * 8 4 | 8 10 - * 9 5 | 9 11 - * 10 6 | 10 12 - * 11 7 | 11 13 - * - * BOOT BLOCK BOUNDARY - * - * 12 15 | 12 15 - * 13 14 | 13 14 - * 14 16 | 14 16 - * - * MAIN BLOCK BOUNDARY - * - * 15 17 | 15 18 - * 16 18 | 16 17 - * 17 20 | 17 20 - * 18 19 | 18 19 - * 19 21 | 19 21 - * - * As we can see from above, the addresses aren't mangled across - * block boundaries, so we don't need to worry about address - * translations except for sending/reading commands during - * initialization - */ - -/* Mangle address (x) on chip U2 */ -#define ADDR_TO_FLASH_U2(x) \ - ( \ - (((x) & 0x00000f00) >> 4) + \ - (((x) & 0x00042000) << 1) + \ - (((x) & 0x0009c003) << 2) + \ - (((x) & 0x00021080) << 3) + \ - (((x) & 0x00000010) << 4) + \ - (((x) & 0x00000040) << 5) + \ - (((x) & 0x00000024) << 7) + \ - (((x) & 0x00000008) << 10) \ - ) - -/* Unmangle address (x) on chip U2 */ -#define FLASH_U2_TO_ADDR(x) \ - ( \ - (((x) << 4) & 0x00000f00) + \ - (((x) >> 1) & 0x00042000) + \ - (((x) >> 2) & 0x0009c003) + \ - (((x) >> 3) & 0x00021080) + \ - (((x) >> 4) & 0x00000010) + \ - (((x) >> 5) & 0x00000040) + \ - (((x) >> 7) & 0x00000024) + \ - (((x) >> 10) & 0x00000008) \ - ) - -/* Mangle address (x) on chip U3 */ -#define ADDR_TO_FLASH_U3(x) \ - ( \ - (((x) & 0x00000080) >> 3) + \ - (((x) & 0x00000040) >> 1) + \ - (((x) & 0x00052020) << 1) + \ - (((x) & 0x00084f03) << 2) + \ - (((x) & 0x00029010) << 3) + \ - (((x) & 0x00000008) << 5) + \ - (((x) & 0x00000004) << 7) \ - ) - -/* Unmangle address (x) on chip U3 */ -#define FLASH_U3_TO_ADDR(x) \ - ( \ - (((x) << 3) & 0x00000080) + \ - (((x) << 1) & 0x00000040) + \ - (((x) >> 1) & 0x00052020) + \ - (((x) >> 2) & 0x00084f03) + \ - (((x) >> 3) & 0x00029010) + \ - (((x) >> 5) & 0x00000008) + \ - (((x) >> 7) & 0x00000004) \ - ) - -/***************************************************************************************************/ - -static __u8 read8 (__u32 offset) -{ - volatile __u8 *data = (__u8 *) (FLASH_OFFSET + offset); -#ifdef LART_DEBUG - printk (KERN_DEBUG "%s(): 0x%.8x -> 0x%.2x\n", __func__, offset, *data); -#endif - return (*data); -} - -static __u32 read32 (__u32 offset) -{ - volatile __u32 *data = (__u32 *) (FLASH_OFFSET + offset); -#ifdef LART_DEBUG - printk (KERN_DEBUG "%s(): 0x%.8x -> 0x%.8x\n", __func__, offset, *data); -#endif - return (*data); -} - -static void write32 (__u32 x,__u32 offset) -{ - volatile __u32 *data = (__u32 *) (FLASH_OFFSET + offset); - *data = x; -#ifdef LART_DEBUG - printk (KERN_DEBUG "%s(): 0x%.8x <- 0x%.8x\n", __func__, offset, *data); -#endif -} - -/***************************************************************************************************/ - -/* - * Probe for 16mbit flash memory on a LART board without doing - * too much damage. Since we need to write 1 dword to memory, - * we're f**cked if this happens to be DRAM since we can't - * restore the memory (otherwise we might exit Read Array mode). - * - * Returns 1 if we found 16mbit flash memory on LART, 0 otherwise. - */ -static int flash_probe (void) -{ - __u32 manufacturer,devtype; - - /* setup "Read Identifier Codes" mode */ - write32 (DATA_TO_FLASH (READ_ID_CODES),0x00000000); - - /* probe U2. U2/U3 returns the same data since the first 3 - * address lines is mangled in the same way */ - manufacturer = FLASH_TO_DATA (read32 (ADDR_TO_FLASH_U2 (0x00000000))); - devtype = FLASH_TO_DATA (read32 (ADDR_TO_FLASH_U2 (0x00000001))); - - /* put the flash back into command mode */ - write32 (DATA_TO_FLASH (READ_ARRAY),0x00000000); - - return (manufacturer == FLASH_MANUFACTURER && (devtype == FLASH_DEVICE_16mbit_TOP || devtype == FLASH_DEVICE_16mbit_BOTTOM)); -} - -/* - * Erase one block of flash memory at offset ``offset'' which is any - * address within the block which should be erased. - * - * Returns 1 if successful, 0 otherwise. - */ -static inline int erase_block (__u32 offset) -{ - __u32 status; - -#ifdef LART_DEBUG - printk (KERN_DEBUG "%s(): 0x%.8x\n", __func__, offset); -#endif - - /* erase and confirm */ - write32 (DATA_TO_FLASH (ERASE_SETUP),offset); - write32 (DATA_TO_FLASH (ERASE_CONFIRM),offset); - - /* wait for block erase to finish */ - do - { - write32 (DATA_TO_FLASH (STATUS_READ),offset); - status = FLASH_TO_DATA (read32 (offset)); - } - while ((~status & STATUS_BUSY) != 0); - - /* put the flash back into command mode */ - write32 (DATA_TO_FLASH (READ_ARRAY),offset); - - /* was the erase successful? */ - if ((status & STATUS_ERASE_ERR)) - { - printk (KERN_WARNING "%s: erase error at address 0x%.8x.\n",module_name,offset); - return (0); - } - - return (1); -} - -static int flash_erase (struct mtd_info *mtd,struct erase_info *instr) -{ - __u32 addr,len; - int i,first; - -#ifdef LART_DEBUG - printk (KERN_DEBUG "%s(addr = 0x%.8x, len = %d)\n", __func__, instr->addr, instr->len); -#endif - - /* - * check that both start and end of the requested erase are - * aligned with the erasesize at the appropriate addresses. - * - * skip all erase regions which are ended before the start of - * the requested erase. Actually, to save on the calculations, - * we skip to the first erase region which starts after the - * start of the requested erase, and then go back one. - */ - for (i = 0; i < mtd->numeraseregions && instr->addr >= mtd->eraseregions[i].offset; i++) ; - i--; - - /* - * ok, now i is pointing at the erase region in which this - * erase request starts. Check the start of the requested - * erase range is aligned with the erase size which is in - * effect here. - */ - if (i < 0 || (instr->addr & (mtd->eraseregions[i].erasesize - 1))) - return -EINVAL; - - /* Remember the erase region we start on */ - first = i; - - /* - * next, check that the end of the requested erase is aligned - * with the erase region at that address. - * - * as before, drop back one to point at the region in which - * the address actually falls - */ - for (; i < mtd->numeraseregions && instr->addr + instr->len >= mtd->eraseregions[i].offset; i++) ; - i--; - - /* is the end aligned on a block boundary? */ - if (i < 0 || ((instr->addr + instr->len) & (mtd->eraseregions[i].erasesize - 1))) - return -EINVAL; - - addr = instr->addr; - len = instr->len; - - i = first; - - /* now erase those blocks */ - while (len) - { - if (!erase_block (addr)) - return (-EIO); - - addr += mtd->eraseregions[i].erasesize; - len -= mtd->eraseregions[i].erasesize; - - if (addr == mtd->eraseregions[i].offset + (mtd->eraseregions[i].erasesize * mtd->eraseregions[i].numblocks)) i++; - } - - return (0); -} - -static int flash_read (struct mtd_info *mtd,loff_t from,size_t len,size_t *retlen,u_char *buf) -{ -#ifdef LART_DEBUG - printk (KERN_DEBUG "%s(from = 0x%.8x, len = %d)\n", __func__, (__u32)from, len); -#endif - - /* we always read len bytes */ - *retlen = len; - - /* first, we read bytes until we reach a dword boundary */ - if (from & (BUSWIDTH - 1)) - { - int gap = BUSWIDTH - (from & (BUSWIDTH - 1)); - - while (len && gap--) { - *buf++ = read8 (from++); - len--; - } - } - - /* now we read dwords until we reach a non-dword boundary */ - while (len >= BUSWIDTH) - { - *((__u32 *) buf) = read32 (from); - - buf += BUSWIDTH; - from += BUSWIDTH; - len -= BUSWIDTH; - } - - /* top up the last unaligned bytes */ - if (len & (BUSWIDTH - 1)) - while (len--) *buf++ = read8 (from++); - - return (0); -} - -/* - * Write one dword ``x'' to flash memory at offset ``offset''. ``offset'' - * must be 32 bits, i.e. it must be on a dword boundary. - * - * Returns 1 if successful, 0 otherwise. - */ -static inline int write_dword (__u32 offset,__u32 x) -{ - __u32 status; - -#ifdef LART_DEBUG - printk (KERN_DEBUG "%s(): 0x%.8x <- 0x%.8x\n", __func__, offset, x); -#endif - - /* setup writing */ - write32 (DATA_TO_FLASH (PGM_SETUP),offset); - - /* write the data */ - write32 (x,offset); - - /* wait for the write to finish */ - do - { - write32 (DATA_TO_FLASH (STATUS_READ),offset); - status = FLASH_TO_DATA (read32 (offset)); - } - while ((~status & STATUS_BUSY) != 0); - - /* put the flash back into command mode */ - write32 (DATA_TO_FLASH (READ_ARRAY),offset); - - /* was the write successful? */ - if ((status & STATUS_PGM_ERR) || read32 (offset) != x) - { - printk (KERN_WARNING "%s: write error at address 0x%.8x.\n",module_name,offset); - return (0); - } - - return (1); -} - -static int flash_write (struct mtd_info *mtd,loff_t to,size_t len,size_t *retlen,const u_char *buf) -{ - __u8 tmp[4]; - int i,n; - -#ifdef LART_DEBUG - printk (KERN_DEBUG "%s(to = 0x%.8x, len = %d)\n", __func__, (__u32)to, len); -#endif - - /* sanity checks */ - if (!len) return (0); - - /* first, we write a 0xFF.... padded byte until we reach a dword boundary */ - if (to & (BUSWIDTH - 1)) - { - __u32 aligned = to & ~(BUSWIDTH - 1); - int gap = to - aligned; - - i = n = 0; - - while (gap--) tmp[i++] = 0xFF; - while (len && i < BUSWIDTH) { - tmp[i++] = buf[n++]; - len--; - } - while (i < BUSWIDTH) tmp[i++] = 0xFF; - - if (!write_dword (aligned,*((__u32 *) tmp))) return (-EIO); - - to += n; - buf += n; - *retlen += n; - } - - /* now we write dwords until we reach a non-dword boundary */ - while (len >= BUSWIDTH) - { - if (!write_dword (to,*((__u32 *) buf))) return (-EIO); - - to += BUSWIDTH; - buf += BUSWIDTH; - *retlen += BUSWIDTH; - len -= BUSWIDTH; - } - - /* top up the last unaligned bytes, padded with 0xFF.... */ - if (len & (BUSWIDTH - 1)) - { - i = n = 0; - - while (len--) tmp[i++] = buf[n++]; - while (i < BUSWIDTH) tmp[i++] = 0xFF; - - if (!write_dword (to,*((__u32 *) tmp))) return (-EIO); - - *retlen += n; - } - - return (0); -} - -/***************************************************************************************************/ - -static struct mtd_info mtd; - -static struct mtd_erase_region_info erase_regions[] = { - /* parameter blocks */ - { - .offset = 0x00000000, - .erasesize = FLASH_BLOCKSIZE_PARAM, - .numblocks = FLASH_NUMBLOCKS_16m_PARAM, - }, - /* main blocks */ - { - .offset = FLASH_BLOCKSIZE_PARAM * FLASH_NUMBLOCKS_16m_PARAM, - .erasesize = FLASH_BLOCKSIZE_MAIN, - .numblocks = FLASH_NUMBLOCKS_16m_MAIN, - } -}; - -static const struct mtd_partition lart_partitions[] = { - /* blob */ - { - .name = "blob", - .offset = PART_BLOB_START, - .size = PART_BLOB_LEN, - }, - /* kernel */ - { - .name = "kernel", - .offset = PART_KERNEL_START, /* MTDPART_OFS_APPEND */ - .size = PART_KERNEL_LEN, - }, - /* initial ramdisk / file system */ - { - .name = "file system", - .offset = PART_INITRD_START, /* MTDPART_OFS_APPEND */ - .size = PART_INITRD_LEN, /* MTDPART_SIZ_FULL */ - } -}; -#define NUM_PARTITIONS ARRAY_SIZE(lart_partitions) - -static int __init lart_flash_init (void) -{ - int result; - memset (&mtd,0,sizeof (mtd)); - printk ("MTD driver for LART. Written by Abraham vd Merwe \n"); - printk ("%s: Probing for 28F160x3 flash on LART...\n",module_name); - if (!flash_probe ()) - { - printk (KERN_WARNING "%s: Found no LART compatible flash device\n",module_name); - return (-ENXIO); - } - printk ("%s: This looks like a LART board to me.\n",module_name); - mtd.name = module_name; - mtd.type = MTD_NORFLASH; - mtd.writesize = 1; - mtd.writebufsize = 4; - mtd.flags = MTD_CAP_NORFLASH; - mtd.size = FLASH_BLOCKSIZE_PARAM * FLASH_NUMBLOCKS_16m_PARAM + FLASH_BLOCKSIZE_MAIN * FLASH_NUMBLOCKS_16m_MAIN; - mtd.erasesize = FLASH_BLOCKSIZE_MAIN; - mtd.numeraseregions = ARRAY_SIZE(erase_regions); - mtd.eraseregions = erase_regions; - mtd._erase = flash_erase; - mtd._read = flash_read; - mtd._write = flash_write; - mtd.owner = THIS_MODULE; - -#ifdef LART_DEBUG - printk (KERN_DEBUG - "mtd.name = %s\n" - "mtd.size = 0x%.8x (%uM)\n" - "mtd.erasesize = 0x%.8x (%uK)\n" - "mtd.numeraseregions = %d\n", - mtd.name, - mtd.size,mtd.size / (1024*1024), - mtd.erasesize,mtd.erasesize / 1024, - mtd.numeraseregions); - - if (mtd.numeraseregions) - for (result = 0; result < mtd.numeraseregions; result++) - printk (KERN_DEBUG - "\n\n" - "mtd.eraseregions[%d].offset = 0x%.8x\n" - "mtd.eraseregions[%d].erasesize = 0x%.8x (%uK)\n" - "mtd.eraseregions[%d].numblocks = %d\n", - result,mtd.eraseregions[result].offset, - result,mtd.eraseregions[result].erasesize,mtd.eraseregions[result].erasesize / 1024, - result,mtd.eraseregions[result].numblocks); - - printk ("\npartitions = %d\n", ARRAY_SIZE(lart_partitions)); - - for (result = 0; result < ARRAY_SIZE(lart_partitions); result++) - printk (KERN_DEBUG - "\n\n" - "lart_partitions[%d].name = %s\n" - "lart_partitions[%d].offset = 0x%.8x\n" - "lart_partitions[%d].size = 0x%.8x (%uK)\n", - result,lart_partitions[result].name, - result,lart_partitions[result].offset, - result,lart_partitions[result].size,lart_partitions[result].size / 1024); -#endif - - result = mtd_device_register(&mtd, lart_partitions, - ARRAY_SIZE(lart_partitions)); - - return (result); -} - -static void __exit lart_flash_exit (void) -{ - mtd_device_unregister(&mtd); -} - -module_init (lart_flash_init); -module_exit (lart_flash_exit); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Abraham vd Merwe "); -MODULE_DESCRIPTION("MTD driver for Intel 28F160F3 on LART board"); -- cgit v1.2.3 From 895d68a39481a75c680aa421546931fb11942fa6 Mon Sep 17 00:00:00 2001 From: Zhang Xiaoxu Date: Sat, 22 Oct 2022 20:13:52 +0800 Subject: mtd: Fix device name leak when register device failed in add_mtd_device() There is a kmemleak when register device failed: unreferenced object 0xffff888101aab550 (size 8): comm "insmod", pid 3922, jiffies 4295277753 (age 925.408s) hex dump (first 8 bytes): 6d 74 64 30 00 88 ff ff mtd0.... backtrace: [<00000000bde26724>] __kmalloc_node_track_caller+0x4e/0x150 [<000000003c32b416>] kvasprintf+0xb0/0x130 [<000000001f7a8f15>] kobject_set_name_vargs+0x2f/0xb0 [<000000006e781163>] dev_set_name+0xab/0xe0 [<00000000e30d0c78>] add_mtd_device+0x4bb/0x700 [<00000000f3d34de7>] mtd_device_parse_register+0x2ac/0x3f0 [<00000000c0d88488>] 0xffffffffa0238457 [<00000000b40d0922>] 0xffffffffa02a008f [<0000000023d17b9d>] do_one_initcall+0x87/0x2a0 [<00000000770f6ca6>] do_init_module+0xdf/0x320 [<000000007b6768fe>] load_module+0x2f98/0x3330 [<00000000346bed5a>] __do_sys_finit_module+0x113/0x1b0 [<00000000674c2290>] do_syscall_64+0x35/0x80 [<000000004c6a8d97>] entry_SYSCALL_64_after_hwframe+0x46/0xb0 If register device failed, should call put_device() to give up the reference. Fixes: 1f24b5a8ecbb ("[MTD] driver model updates") Signed-off-by: Zhang Xiaoxu Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20221022121352.2534682-1-zhangxiaoxu5@huawei.com --- drivers/mtd/mtdcore.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index 20fcedc3021e..756fd27f4cfe 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -715,8 +715,10 @@ int add_mtd_device(struct mtd_info *mtd) mtd_check_of_node(mtd); of_node_get(mtd_get_of_node(mtd)); error = device_register(&mtd->dev); - if (error) + if (error) { + put_device(&mtd->dev); goto fail_added; + } /* Add the nvmem provider */ error = mtd_nvmem_add(mtd); -- cgit v1.2.3 From 26422ac78e9d8767bd4aabfbae616b15edbf6a1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Sat, 22 Oct 2022 23:13:18 +0200 Subject: mtd: core: set ROOT_DEV for partitions marked as rootfs in DT MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds support for "linux,rootfs" binding that is used to mark flash partition containing rootfs. It's useful for devices using device tree that don't have bootloader passing root info in cmdline. Signed-off-by: Rafał Miłecki Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20221022211318.32009-2-zajec5@gmail.com --- drivers/mtd/mtdcore.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'drivers/mtd') diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index 756fd27f4cfe..e0193054f8d9 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -737,6 +738,17 @@ int add_mtd_device(struct mtd_info *mtd) not->add(mtd); mutex_unlock(&mtd_table_mutex); + + if (of_find_property(mtd_get_of_node(mtd), "linux,rootfs", NULL)) { + if (IS_BUILTIN(CONFIG_MTD)) { + pr_info("mtd: setting mtd%d (%s) as root device\n", mtd->index, mtd->name); + ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, mtd->index); + } else { + pr_warn("mtd: can't set mtd%d (%s) as root device - mtd must be builtin\n", + mtd->index, mtd->name); + } + } + /* We _know_ we aren't being removed, because our caller is still holding us here. So none of this try_ nonsense, and no bitching about it -- cgit v1.2.3 From 1aadf01e5076b9ab6bf294b9622335c651314895 Mon Sep 17 00:00:00 2001 From: Gaosheng Cui Date: Mon, 24 Oct 2022 14:51:09 +0800 Subject: mtd: core: fix possible resource leak in init_mtd() I got the error report while inject fault in init_mtd(): sysfs: cannot create duplicate filename '/devices/virtual/bdi/mtd-0' Call Trace: dump_stack_lvl+0x67/0x83 sysfs_warn_dup+0x60/0x70 sysfs_create_dir_ns+0x109/0x120 kobject_add_internal+0xce/0x2f0 kobject_add+0x98/0x110 device_add+0x179/0xc00 device_create_groups_vargs+0xf4/0x100 device_create+0x7b/0xb0 bdi_register_va.part.13+0x58/0x2d0 bdi_register+0x9b/0xb0 init_mtd+0x62/0x171 [mtd] do_one_initcall+0x6c/0x3c0 do_init_module+0x58/0x222 load_module+0x268e/0x27d0 __do_sys_finit_module+0xd5/0x140 do_syscall_64+0x37/0x90 entry_SYSCALL_64_after_hwframe+0x63/0xcd kobject_add_internal failed for mtd-0 with -EEXIST, don't try to register things with the same name in the same directory. Error registering mtd class or bdi: -17 If init_mtdchar() fails in init_mtd(), mtd_bdi will not be unregistered, as a result, we can't load the mtd module again, to fix this by calling bdi_unregister(mtd_bdi) after out_procfs label. Fixes: 445caaa20c4d ("mtd: Allocate bdi objects dynamically") Signed-off-by: Gaosheng Cui Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20221024065109.2050705-1-cuigaosheng1@huawei.com --- drivers/mtd/mtdcore.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/mtd') diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index e0193054f8d9..6c4683a5e531 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -2489,6 +2489,7 @@ static int __init init_mtd(void) out_procfs: if (proc_mtd) remove_proc_entry("mtd", NULL); + bdi_unregister(mtd_bdi); bdi_put(mtd_bdi); err_bdi: class_unregister(&mtd_class); -- cgit v1.2.3 From 077dc37db1e1da1f0e6a745328e4caa6d414e501 Mon Sep 17 00:00:00 2001 From: Jilin Yuan Date: Fri, 28 Oct 2022 21:40:36 +0800 Subject: mtd: inftlcore: fix repeated words in comments Delete the redundant word 'it'. Signed-off-by: Jilin Yuan Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20221028134036.63000-1-yuanjilin@cdjrlc.com --- drivers/mtd/inftlcore.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/inftlcore.c b/drivers/mtd/inftlcore.c index 58ca1c21ebe6..9739387cff8c 100644 --- a/drivers/mtd/inftlcore.c +++ b/drivers/mtd/inftlcore.c @@ -356,7 +356,7 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned * Newest unit in chain now contains data from _all_ older units. * So go through and erase each unit in chain, oldest first. (This * is important, by doing oldest first if we crash/reboot then it - * it is relatively simple to clean up the mess). + * is relatively simple to clean up the mess). */ pr_debug("INFTL: want to erase virtual chain %d\n", thisVUC); -- cgit v1.2.3 From a50ae8c98e5766a4fcb78e76f13cc658b784eac1 Mon Sep 17 00:00:00 2001 From: Dario Binacchi Date: Tue, 18 Oct 2022 19:02:05 +0200 Subject: mtd: nand: drop EXPORT_SYMBOL_GPL for nanddev_erase() This function is only used within this module, so it is no longer necessary to use EXPORT_SYMBOL_GPL(). Signed-off-by: Dario Binacchi Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20221018170205.1733958-1-dario.binacchi@amarulasolutions.com --- drivers/mtd/nand/core.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/core.c b/drivers/mtd/nand/core.c index dbd7b06524b3..7737b1a4a177 100644 --- a/drivers/mtd/nand/core.c +++ b/drivers/mtd/nand/core.c @@ -126,7 +126,7 @@ EXPORT_SYMBOL_GPL(nanddev_isreserved); * * Return: 0 in case of success, a negative error code otherwise. */ -int nanddev_erase(struct nand_device *nand, const struct nand_pos *pos) +static int nanddev_erase(struct nand_device *nand, const struct nand_pos *pos) { if (nanddev_isbad(nand, pos) || nanddev_isreserved(nand, pos)) { pr_warn("attempt to erase a bad/reserved block @%llx\n", @@ -136,7 +136,6 @@ int nanddev_erase(struct nand_device *nand, const struct nand_pos *pos) return nand->ops->erase(nand, pos); } -EXPORT_SYMBOL_GPL(nanddev_erase); /** * nanddev_mtd_erase() - Generic mtd->_erase() implementation for NAND devices -- cgit v1.2.3 From 991cc42a276f1d9303674a04a351942e47c29a3f Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 27 Oct 2022 15:10:27 +0200 Subject: mtd: rawnand: lpc32xx_mlc: Switch to using pm_ptr() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The switch to using the gpiod API removed the last user of lpc32xx_wp_disable() outside #ifdef CONFIG_PM, causing build failures if CONFIG_PM=n: drivers/mtd/nand/raw/lpc32xx_mlc.c:380:13: error: ‘lpc32xx_wp_disable’ defined but not used [-Werror=unused-function] 380 | static void lpc32xx_wp_disable(struct lpc32xx_nand_host *host) | ^~~~~~~~~~~~~~~~~~ Fix this by switching from #ifdef CONFIG_PM to pm_ptr(), increasing compile-coverage as a side-effect. Reported-by: noreply@ellerman.id.au Fixes: 782e32a990d9d702 ("mtd: rawnand: lpc32xx_mlc: switch to using gpiod API") Signed-off-by: Geert Uytterhoeven Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20221027131028.3838303-1-geert@linux-m68k.org --- drivers/mtd/nand/raw/lpc32xx_mlc.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/raw/lpc32xx_mlc.c b/drivers/mtd/nand/raw/lpc32xx_mlc.c index 306e2c216501..ae7f6429a5f6 100644 --- a/drivers/mtd/nand/raw/lpc32xx_mlc.c +++ b/drivers/mtd/nand/raw/lpc32xx_mlc.c @@ -850,7 +850,6 @@ static int lpc32xx_nand_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM static int lpc32xx_nand_resume(struct platform_device *pdev) { struct lpc32xx_nand_host *host = platform_get_drvdata(pdev); @@ -882,11 +881,6 @@ static int lpc32xx_nand_suspend(struct platform_device *pdev, pm_message_t pm) return 0; } -#else -#define lpc32xx_nand_resume NULL -#define lpc32xx_nand_suspend NULL -#endif - static const struct of_device_id lpc32xx_nand_match[] = { { .compatible = "nxp,lpc3220-mlc" }, { /* sentinel */ }, @@ -896,8 +890,8 @@ MODULE_DEVICE_TABLE(of, lpc32xx_nand_match); static struct platform_driver lpc32xx_nand_driver = { .probe = lpc32xx_nand_probe, .remove = lpc32xx_nand_remove, - .resume = lpc32xx_nand_resume, - .suspend = lpc32xx_nand_suspend, + .resume = pm_ptr(lpc32xx_nand_resume), + .suspend = pm_ptr(lpc32xx_nand_suspend), .driver = { .name = DRV_NAME, .of_match_table = lpc32xx_nand_match, -- cgit v1.2.3 From bb144c285bd5585be101aaf5464ad8949ba1305d Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 27 Oct 2022 15:10:28 +0200 Subject: mtd: rawnand: lpc32xx_slc: Switch to using pm_ptr() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The switch to using the gpiod API removed the last user of lpc32xx_wp_disable() outside #ifdef CONFIG_PM, causing build failures if CONFIG_PM=n: drivers/mtd/nand/raw/lpc32xx_slc.c:318:13: error: ‘lpc32xx_wp_disable’ defined but not used [-Werror=unused-function] 318 | static void lpc32xx_wp_disable(struct lpc32xx_nand_host *host) | ^~~~~~~~~~~~~~~~~~ Fix this by switching from #ifdef CONFIG_PM to pm_ptr(), increasing compile-coverage as a side-effect. Reported-by: noreply@ellerman.id.au Fixes: 6b923db2867cb5e1 ("mtd: rawnand: lpc32xx_slc: switch to using gpiod API") Signed-off-by: Geert Uytterhoeven Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20221027131028.3838303-2-geert@linux-m68k.org --- drivers/mtd/nand/raw/lpc32xx_slc.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/raw/lpc32xx_slc.c b/drivers/mtd/nand/raw/lpc32xx_slc.c index 4702577f74e5..6918737346c9 100644 --- a/drivers/mtd/nand/raw/lpc32xx_slc.c +++ b/drivers/mtd/nand/raw/lpc32xx_slc.c @@ -969,7 +969,6 @@ static int lpc32xx_nand_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM static int lpc32xx_nand_resume(struct platform_device *pdev) { struct lpc32xx_nand_host *host = platform_get_drvdata(pdev); @@ -1008,11 +1007,6 @@ static int lpc32xx_nand_suspend(struct platform_device *pdev, pm_message_t pm) return 0; } -#else -#define lpc32xx_nand_resume NULL -#define lpc32xx_nand_suspend NULL -#endif - static const struct of_device_id lpc32xx_nand_match[] = { { .compatible = "nxp,lpc3220-slc" }, { /* sentinel */ }, @@ -1022,8 +1016,8 @@ MODULE_DEVICE_TABLE(of, lpc32xx_nand_match); static struct platform_driver lpc32xx_nand_driver = { .probe = lpc32xx_nand_probe, .remove = lpc32xx_nand_remove, - .resume = lpc32xx_nand_resume, - .suspend = lpc32xx_nand_suspend, + .resume = pm_ptr(lpc32xx_nand_resume), + .suspend = pm_ptr(lpc32xx_nand_suspend), .driver = { .name = LPC32XX_MODNAME, .of_match_table = lpc32xx_nand_match, -- cgit v1.2.3 From 6bdd45d795adf9e73b38ced5e7f750cd199499ff Mon Sep 17 00:00:00 2001 From: Hui Tang Date: Mon, 14 Nov 2022 17:02:40 +0800 Subject: mtd: lpddr2_nvm: Fix possible null-ptr-deref MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It will cause null-ptr-deref when resource_size(add_range) invoked, if platform_get_resource() returns NULL. Fixes: 96ba9dd65788 ("mtd: lpddr: add driver for LPDDR2-NVM PCM memories") Signed-off-by: Hui Tang Acked-by: Uwe Kleine-König Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20221114090240.244172-1-tanghui20@huawei.com --- drivers/mtd/lpddr/lpddr2_nvm.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/mtd') diff --git a/drivers/mtd/lpddr/lpddr2_nvm.c b/drivers/mtd/lpddr/lpddr2_nvm.c index 367e2d906de0..e71af4c49096 100644 --- a/drivers/mtd/lpddr/lpddr2_nvm.c +++ b/drivers/mtd/lpddr/lpddr2_nvm.c @@ -433,6 +433,8 @@ static int lpddr2_nvm_probe(struct platform_device *pdev) /* lpddr2_nvm address range */ add_range = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!add_range) + return -ENODEV; /* Populate map_info data structure */ *map = (struct map_info) { -- cgit v1.2.3 From f902baa917b6c1f2d70d008b2ebbe5acf79ba392 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Mon, 14 Nov 2022 10:03:00 +0100 Subject: dt-bindings: mtd: Remove useless file about partitions There is already a real partitions.yaml file, so assuming everybody knows hot to read yaml schema now, this text file is no longer needed, so drop it. Depending on the situation, the lines referring to this file are either dropped or edited to point to mtd.yaml which includes partition{,s}.yaml. Signed-off-by: Miquel Raynal Reviewed-by: Rob Herring Link: https://lore.kernel.org/linux-mtd/20221114090315.848208-3-miquel.raynal@bootlin.com --- drivers/mtd/parsers/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/parsers/Kconfig b/drivers/mtd/parsers/Kconfig index c258ba2a3a6f..00dfdc934ac8 100644 --- a/drivers/mtd/parsers/Kconfig +++ b/drivers/mtd/parsers/Kconfig @@ -75,7 +75,7 @@ config MTD_OF_PARTS This provides a open firmware device tree partition parser which derives the partition map from the children of the flash memory node, as described in - Documentation/devicetree/bindings/mtd/partition.txt. + Documentation/devicetree/bindings/mtd/mtd.yaml. config MTD_OF_PARTS_BCM4908 bool "BCM4908 partitioning support" -- cgit v1.2.3 From 085679b15b5af65f9610f619afde41da0f966194 Mon Sep 17 00:00:00 2001 From: Lukas Bulwahn Date: Wed, 16 Nov 2022 13:49:32 +0100 Subject: mtd: parsers: refer to ARCH_BCMBCA instead of ARCH_BCM4908 Commit dd5c672d7ca9 ("arm64: bcmbca: Merge ARCH_BCM4908 to ARCH_BCMBCA") removes config ARCH_BCM4908 as config ARCH_BCMBCA has the same intent. Probably due to concurrent development, commit 002181f5b150 ("mtd: parsers: add Broadcom's U-Boot parser") introduces 'Broadcom's U-Boot partition parser' that depends on ARCH_BCM4908, but this use was not visible during the config refactoring from the commit above. Hence, these two changes create a reference to a non-existing config symbol. Adjust the MTD_BRCM_U_BOOT definition to refer to ARCH_BCMBCA instead of ARCH_BCM4908 to remove the reference to the non-existing config symbol ARCH_BCM4908. Signed-off-by: Lukas Bulwahn Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20221116124932.4748-1-lukas.bulwahn@gmail.com --- drivers/mtd/parsers/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/parsers/Kconfig b/drivers/mtd/parsers/Kconfig index 00dfdc934ac8..b20e0c38b517 100644 --- a/drivers/mtd/parsers/Kconfig +++ b/drivers/mtd/parsers/Kconfig @@ -22,7 +22,7 @@ config MTD_BCM63XX_PARTS config MTD_BRCM_U_BOOT tristate "Broadcom's U-Boot partition parser" - depends on ARCH_BCM4908 || COMPILE_TEST + depends on ARCH_BCMBCA || COMPILE_TEST help Broadcom uses a custom way of storing U-Boot environment variables. They are placed inside U-Boot partition itself at unspecified offset. -- cgit v1.2.3 From c13bf589e5cff0d05ce63c4832de3fab2a19c62d Mon Sep 17 00:00:00 2001 From: Hamish Martin Date: Thu, 10 Nov 2022 12:13:25 +1300 Subject: mtd: rawnand: marvell: Enable NFC/DEVBUS arbiter The CN9130 SoC (an ARMADA 8K type) has both a NAND Flash Controller and a generic local bus controller (Device Bus Controller) that share common pins. With a board design that incorporates both a NAND flash and uses the Device Bus (in our case for an SRAM) accessing the Device Bus device fails unless the NfArbiterEn bit is set. Setting the bit enables arbitration between the Device Bus and the NAND flash. Since there is no obvious downside in enabling this for designs that don't require arbitration, we always enable it. Signed-off-by: Hamish Martin Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20221109231325.7714-1-hamish.martin@alliedtelesis.co.nz --- drivers/mtd/nand/raw/marvell_nand.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/raw/marvell_nand.c b/drivers/mtd/nand/raw/marvell_nand.c index d9f2f1d0b5ef..71e3751262b8 100644 --- a/drivers/mtd/nand/raw/marvell_nand.c +++ b/drivers/mtd/nand/raw/marvell_nand.c @@ -114,6 +114,7 @@ #define GENCONF_SOC_DEVICE_MUX_ECC_CLK_RST BIT(20) #define GENCONF_SOC_DEVICE_MUX_ECC_CORE_RST BIT(21) #define GENCONF_SOC_DEVICE_MUX_NFC_INT_EN BIT(25) +#define GENCONF_SOC_DEVICE_MUX_NFC_DEVBUS_ARB_EN BIT(27) #define GENCONF_CLK_GATING_CTRL 0x220 #define GENCONF_CLK_GATING_CTRL_ND_GATE BIT(2) #define GENCONF_ND_CLK_CTRL 0x700 @@ -2880,7 +2881,8 @@ static int marvell_nfc_init(struct marvell_nfc *nfc) GENCONF_SOC_DEVICE_MUX_NFC_EN | GENCONF_SOC_DEVICE_MUX_ECC_CLK_RST | GENCONF_SOC_DEVICE_MUX_ECC_CORE_RST | - GENCONF_SOC_DEVICE_MUX_NFC_INT_EN); + GENCONF_SOC_DEVICE_MUX_NFC_INT_EN | + GENCONF_SOC_DEVICE_MUX_NFC_DEVBUS_ARB_EN); regmap_update_bits(sysctrl_base, GENCONF_CLK_GATING_CTRL, GENCONF_CLK_GATING_CTRL_ND_GATE, -- cgit v1.2.3 From 2ebc336be08160debfe27f87660cf550d710f3e9 Mon Sep 17 00:00:00 2001 From: Alexander Sverdlin Date: Fri, 19 Nov 2021 09:14:12 +0100 Subject: mtd: spi-nor: Check for zero erase size in spi_nor_find_best_erase_type() Erase can be zeroed in spi_nor_parse_4bait() or spi_nor_init_non_uniform_erase_map(). In practice it happened with mt25qu256a, which supports 4K, 32K, 64K erases with 3b address commands, but only 4K and 64K erase with 4b address commands. Fixes: dc92843159a7 ("mtd: spi-nor: fix erase_type array to indicate current map conf") Signed-off-by: Alexander Sverdlin Signed-off-by: Tudor Ambarus Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20211119081412.29732-1-alexander.sverdlin@nokia.com --- drivers/mtd/spi-nor/core.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/mtd') diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c index aa05443c44c2..0079758b36aa 100644 --- a/drivers/mtd/spi-nor/core.c +++ b/drivers/mtd/spi-nor/core.c @@ -1184,6 +1184,8 @@ spi_nor_find_best_erase_type(const struct spi_nor_erase_map *map, continue; erase = &map->erase_type[i]; + if (!erase->size) + continue; /* Alignment is not mandatory for overlaid regions */ if (region->offset & SNOR_OVERLAID_REGION && -- cgit v1.2.3 From 7d388551b6888f3725e6c957f472526b35161a5b Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Thu, 11 Aug 2022 00:06:48 +0200 Subject: mtd: spi-nor: hide jedec_id sysfs attribute if not present Some non-jedec compliant flashes (like the Everspin flashes) don't have an ID at all. Hide the attribute in this case. Fixes: 36ac02286265 ("mtd: spi-nor: add initial sysfs support") Signed-off-by: Michael Walle Signed-off-by: Tudor Ambarus Reviewed-by: Takahiro Kuwano Link: https://lore.kernel.org/r/20220810220654.1297699-2-michael@walle.cc --- drivers/mtd/spi-nor/sysfs.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'drivers/mtd') diff --git a/drivers/mtd/spi-nor/sysfs.c b/drivers/mtd/spi-nor/sysfs.c index 9aec9d8a98ad..4c3b351aef24 100644 --- a/drivers/mtd/spi-nor/sysfs.c +++ b/drivers/mtd/spi-nor/sysfs.c @@ -67,6 +67,19 @@ static struct bin_attribute *spi_nor_sysfs_bin_entries[] = { NULL }; +static umode_t spi_nor_sysfs_is_visible(struct kobject *kobj, + struct attribute *attr, int n) +{ + struct spi_device *spi = to_spi_device(kobj_to_dev(kobj)); + struct spi_mem *spimem = spi_get_drvdata(spi); + struct spi_nor *nor = spi_mem_get_drvdata(spimem); + + if (attr == &dev_attr_jedec_id.attr && !nor->info->id_len) + return 0; + + return 0444; +} + static umode_t spi_nor_sysfs_is_bin_visible(struct kobject *kobj, struct bin_attribute *attr, int n) { @@ -82,6 +95,7 @@ static umode_t spi_nor_sysfs_is_bin_visible(struct kobject *kobj, static const struct attribute_group spi_nor_sysfs_group = { .name = "spi-nor", + .is_visible = spi_nor_sysfs_is_visible, .is_bin_visible = spi_nor_sysfs_is_bin_visible, .attrs = spi_nor_sysfs_entries, .bin_attrs = spi_nor_sysfs_bin_entries, -- cgit v1.2.3 From 0d9270f2762b8a2bd0df7c4a2e7e651703783793 Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Thu, 11 Aug 2022 00:06:49 +0200 Subject: mtd: spi-nor: sysfs: hide manufacturer if it is not set The manufacturer may be optional when pure SFDP flashes are supported. Hide the sysfs property if no manufacturer is set. Signed-off-by: Michael Walle Signed-off-by: Tudor Ambarus Reviewed-by: Takahiro Kuwano Link: https://lore.kernel.org/r/20220810220654.1297699-3-michael@walle.cc --- drivers/mtd/spi-nor/sysfs.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/mtd') diff --git a/drivers/mtd/spi-nor/sysfs.c b/drivers/mtd/spi-nor/sysfs.c index 4c3b351aef24..20563c1926f4 100644 --- a/drivers/mtd/spi-nor/sysfs.c +++ b/drivers/mtd/spi-nor/sysfs.c @@ -74,6 +74,8 @@ static umode_t spi_nor_sysfs_is_visible(struct kobject *kobj, struct spi_mem *spimem = spi_get_drvdata(spi); struct spi_nor *nor = spi_mem_get_drvdata(spimem); + if (attr == &dev_attr_manufacturer.attr && !nor->manufacturer) + return 0; if (attr == &dev_attr_jedec_id.attr && !nor->info->id_len) return 0; -- cgit v1.2.3 From 28ef7670414e309d8bbee41f9389b7e21a58572c Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Thu, 11 Aug 2022 00:06:50 +0200 Subject: mtd: spi-nor: remember full JEDEC flash ID At the moment, we print the JEDEC ID that is stored in our database. The generic flash support won't have such an entry in our database. To find out the JEDEC ID later we will have to cache it. There is also another advantage: If the flash is found in the database, the ID could be truncated because the ID of the entry is used which can be shorter. Some flashes still holds valuable information in the bytes after the JEDEC ID and come in handy during debugging of when coping with INFO6() entries. These are not accessible for now. Save a copy of the ID bytes after reading and display it via debugfs. Signed-off-by: Michael Walle Signed-off-by: Tudor Ambarus Reviewed-by: Takahiro Kuwano Link: https://lore.kernel.org/r/20220810220654.1297699-4-michael@walle.cc --- drivers/mtd/spi-nor/core.c | 5 +++++ drivers/mtd/spi-nor/debugfs.c | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c index 0079758b36aa..1358f3c45d16 100644 --- a/drivers/mtd/spi-nor/core.c +++ b/drivers/mtd/spi-nor/core.c @@ -1666,6 +1666,11 @@ static const struct flash_info *spi_nor_detect(struct spi_nor *nor) return ERR_PTR(ret); } + /* Cache the complete flash ID. */ + nor->id = devm_kmemdup(nor->dev, id, SPI_NOR_MAX_ID_LEN, GFP_KERNEL); + if (!nor->id) + return ERR_PTR(-ENOMEM); + info = spi_nor_match_id(nor, id); if (!info) { dev_err(nor->dev, "unrecognized JEDEC id bytes: %*ph\n", diff --git a/drivers/mtd/spi-nor/debugfs.c b/drivers/mtd/spi-nor/debugfs.c index df76cb5de3f9..ff895f6758ea 100644 --- a/drivers/mtd/spi-nor/debugfs.c +++ b/drivers/mtd/spi-nor/debugfs.c @@ -81,7 +81,7 @@ static int spi_nor_params_show(struct seq_file *s, void *data) int i; seq_printf(s, "name\t\t%s\n", info->name); - seq_printf(s, "id\t\t%*ph\n", info->id_len, info->id); + seq_printf(s, "id\t\t%*ph\n", SPI_NOR_MAX_ID_LEN, nor->id); string_get_size(params->size, 1, STRING_UNITS_2, buf, sizeof(buf)); seq_printf(s, "size\t\t%s\n", buf); seq_printf(s, "write size\t%u\n", params->writesize); -- cgit v1.2.3 From fa06bb26a40ca08fa0d653b04d8ce92d243aa2ce Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Thu, 11 Aug 2022 00:06:51 +0200 Subject: mtd: spi-nor: move function declaration out of sfdp.h sfdp.h should only contain constants related to the JEDEC SFDP specification(s). Signed-off-by: Michael Walle Signed-off-by: Tudor Ambarus Reviewed-by: Takahiro Kuwano Link: https://lore.kernel.org/r/20220810220654.1297699-5-michael@walle.cc --- drivers/mtd/spi-nor/core.h | 2 ++ drivers/mtd/spi-nor/sfdp.h | 2 -- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/spi-nor/core.h b/drivers/mtd/spi-nor/core.h index 85b0cf254e97..68aaccaa12d8 100644 --- a/drivers/mtd/spi-nor/core.h +++ b/drivers/mtd/spi-nor/core.h @@ -701,6 +701,8 @@ int spi_nor_controller_ops_read_reg(struct spi_nor *nor, u8 opcode, int spi_nor_controller_ops_write_reg(struct spi_nor *nor, u8 opcode, const u8 *buf, size_t len); +int spi_nor_parse_sfdp(struct spi_nor *nor); + static inline struct spi_nor *mtd_to_spi_nor(struct mtd_info *mtd) { return container_of(mtd, struct spi_nor, mtd); diff --git a/drivers/mtd/spi-nor/sfdp.h b/drivers/mtd/spi-nor/sfdp.h index bbf80d2990ab..c1969f0a2f46 100644 --- a/drivers/mtd/spi-nor/sfdp.h +++ b/drivers/mtd/spi-nor/sfdp.h @@ -107,6 +107,4 @@ struct sfdp_parameter_header { u8 id_msb; }; -int spi_nor_parse_sfdp(struct spi_nor *nor); - #endif /* __LINUX_MTD_SFDP_H */ -- cgit v1.2.3 From 39eece67a3cf027aa5b39d7da5feadc4711504e6 Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Thu, 11 Aug 2022 00:06:52 +0200 Subject: mtd: spi-nor: fix select_uniform_erase to skip 0 erase size 4bait will set the erase size to 0 if there is no corresponding opcode for the 4byte erase. Fix spi_nor_select_uniform_erase to skip the 0 erase size to avoid mtd device registration failure cases. Reported-by: Jae Hyun Yoo Signed-off-by: Michael Walle Signed-off-by: Tudor Ambarus Link: https://lore.kernel.org/r/20220810220654.1297699-6-michael@walle.cc --- drivers/mtd/spi-nor/core.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/mtd') diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c index 1358f3c45d16..2bdc5b50d8da 100644 --- a/drivers/mtd/spi-nor/core.c +++ b/drivers/mtd/spi-nor/core.c @@ -2120,6 +2120,10 @@ spi_nor_select_uniform_erase(struct spi_nor_erase_map *map, tested_erase = &map->erase_type[i]; + /* Skip masked erase types. */ + if (!tested_erase->size) + continue; + /* * If the current erase size is the one, stop here: * we have found the right uniform Sector Erase command. -- cgit v1.2.3 From 773bbe10449731c9525457873e0c2342e5cf883b Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Thu, 11 Aug 2022 00:06:53 +0200 Subject: mtd: spi-nor: add generic flash driver Our SFDP parsing is everything we need to support all basic operations of a flash device. If the flash isn't found in our in-kernel flash database, gracefully fall back to a driver described solely by its SFDP tables. Signed-off-by: Michael Walle Signed-off-by: Tudor Ambarus Tested-by: Tudor Ambarus Reviewed-by: Takahiro Kuwano Link: https://lore.kernel.org/r/20220810220654.1297699-7-michael@walle.cc --- drivers/mtd/spi-nor/core.c | 26 ++++++++++++++++++++++++-- drivers/mtd/spi-nor/core.h | 1 + drivers/mtd/spi-nor/sfdp.c | 27 +++++++++++++++++++++++++++ 3 files changed, 52 insertions(+), 2 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c index 2bdc5b50d8da..71b9bcd8991d 100644 --- a/drivers/mtd/spi-nor/core.c +++ b/drivers/mtd/spi-nor/core.c @@ -1634,6 +1634,16 @@ static const struct spi_nor_manufacturer *manufacturers[] = { &spi_nor_xmc, }; +static const struct flash_info spi_nor_generic_flash = { + .name = "spi-nor-generic", + /* + * JESD216 rev A doesn't specify the page size, therefore we need a + * sane default. + */ + .page_size = 256, + .parse_sfdp = true, +}; + static const struct flash_info *spi_nor_match_id(struct spi_nor *nor, const u8 *id) { @@ -1672,6 +1682,14 @@ static const struct flash_info *spi_nor_detect(struct spi_nor *nor) return ERR_PTR(-ENOMEM); info = spi_nor_match_id(nor, id); + + /* Fallback to a generic flash described only by its SFDP data. */ + if (!info) { + ret = spi_nor_check_sfdp_signature(nor); + if (!ret) + info = &spi_nor_generic_flash; + } + if (!info) { dev_err(nor->dev, "unrecognized JEDEC id bytes: %*ph\n", SPI_NOR_MAX_ID_LEN, id); @@ -2098,8 +2116,12 @@ static int spi_nor_select_pp(struct spi_nor *nor, * spi_nor_select_uniform_erase() - select optimum uniform erase type * @map: the erase map of the SPI NOR * @wanted_size: the erase type size to search for. Contains the value of - * info->sector_size or of the "small sector" size in case - * CONFIG_MTD_SPI_NOR_USE_4K_SECTORS is defined. + * info->sector_size, the "small sector" size in case + * CONFIG_MTD_SPI_NOR_USE_4K_SECTORS is defined or 0 if + * there is no information about the sector size. The + * latter is the case if the flash parameters are parsed + * solely by SFDP, then the largest supported erase type + * is selected. * * Once the optimum uniform sector erase command is found, disable all the * other. diff --git a/drivers/mtd/spi-nor/core.h b/drivers/mtd/spi-nor/core.h index 68aaccaa12d8..ef0a73dbf348 100644 --- a/drivers/mtd/spi-nor/core.h +++ b/drivers/mtd/spi-nor/core.h @@ -701,6 +701,7 @@ int spi_nor_controller_ops_read_reg(struct spi_nor *nor, u8 opcode, int spi_nor_controller_ops_write_reg(struct spi_nor *nor, u8 opcode, const u8 *buf, size_t len); +int spi_nor_check_sfdp_signature(struct spi_nor *nor); int spi_nor_parse_sfdp(struct spi_nor *nor); static inline struct spi_nor *mtd_to_spi_nor(struct mtd_info *mtd) diff --git a/drivers/mtd/spi-nor/sfdp.c b/drivers/mtd/spi-nor/sfdp.c index 15fb7f661ae9..c88628e8ee4e 100644 --- a/drivers/mtd/spi-nor/sfdp.c +++ b/drivers/mtd/spi-nor/sfdp.c @@ -1256,6 +1256,33 @@ static void spi_nor_post_sfdp_fixups(struct spi_nor *nor) nor->info->fixups->post_sfdp(nor); } +/** + * spi_nor_check_sfdp_signature() - check for a valid SFDP signature + * @nor: pointer to a 'struct spi_nor' + * + * Used to detect if the flash supports the RDSFDP command as well as the + * presence of a valid SFDP table. + * + * Return: 0 on success, -errno otherwise. + */ +int spi_nor_check_sfdp_signature(struct spi_nor *nor) +{ + u32 signature; + int err; + + /* Get the SFDP header. */ + err = spi_nor_read_sfdp_dma_unsafe(nor, 0, sizeof(signature), + &signature); + if (err < 0) + return err; + + /* Check the SFDP signature. */ + if (le32_to_cpu(signature) != SFDP_SIGNATURE) + return -EINVAL; + + return 0; +} + /** * spi_nor_parse_sfdp() - parse the Serial Flash Discoverable Parameters. * @nor: pointer to a 'struct spi_nor' -- cgit v1.2.3 From 0a92de16b61b5d7a52d2910f81325f0506b2fc3b Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Thu, 11 Aug 2022 00:06:54 +0200 Subject: mtd: spi-nor: sysfs: print JEDEC ID for generic flash driver We don't have a database entry for the generic SPI-NOR flash driver and thus we don't have a JEDEC ID to print. Print the (cached) JEDEC ID instead. Signed-off-by: Michael Walle Signed-off-by: Tudor Ambarus Reviewed-by: Takahiro Kuwano Link: https://lore.kernel.org/r/20220810220654.1297699-8-michael@walle.cc --- drivers/mtd/spi-nor/sysfs.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/spi-nor/sysfs.c b/drivers/mtd/spi-nor/sysfs.c index 20563c1926f4..c09bb832b3b9 100644 --- a/drivers/mtd/spi-nor/sysfs.c +++ b/drivers/mtd/spi-nor/sysfs.c @@ -35,8 +35,10 @@ static ssize_t jedec_id_show(struct device *dev, struct spi_device *spi = to_spi_device(dev); struct spi_mem *spimem = spi_get_drvdata(spi); struct spi_nor *nor = spi_mem_get_drvdata(spimem); + const u8 *id = nor->info->id_len ? nor->info->id : nor->id; + u8 id_len = nor->info->id_len ?: SPI_NOR_MAX_ID_LEN; - return sysfs_emit(buf, "%*phN\n", nor->info->id_len, nor->info->id); + return sysfs_emit(buf, "%*phN\n", id_len, id); } static DEVICE_ATTR_RO(jedec_id); @@ -76,7 +78,7 @@ static umode_t spi_nor_sysfs_is_visible(struct kobject *kobj, if (attr == &dev_attr_manufacturer.attr && !nor->manufacturer) return 0; - if (attr == &dev_attr_jedec_id.attr && !nor->info->id_len) + if (attr == &dev_attr_jedec_id.attr && !nor->info->id_len && !nor->id) return 0; return 0444; -- cgit v1.2.3 From 270450a1b6d8bef423cfe619ab8bb99b2f874cad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20Neusch=C3=A4fer?= Date: Tue, 1 Nov 2022 17:29:06 +0100 Subject: mtd: spi-nor: Fix formatting in spi_nor_read_raw() kerneldoc comment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It doesn't make sense to put "set" on its own line like that. Signed-off-by: Jonathan Neuschäfer Signed-off-by: Tudor Ambarus Acked-by: Pratyush Yadav Link: https://lore.kernel.org/r/20221101162906.990125-1-j.neuschaefer@gmx.net --- drivers/mtd/spi-nor/sfdp.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/spi-nor/sfdp.c b/drivers/mtd/spi-nor/sfdp.c index c88628e8ee4e..8434f654eca1 100644 --- a/drivers/mtd/spi-nor/sfdp.c +++ b/drivers/mtd/spi-nor/sfdp.c @@ -135,8 +135,7 @@ struct sfdp_4bait { /** * spi_nor_read_raw() - raw read of serial flash memory. read_opcode, * addr_nbytes and read_dummy members of the struct spi_nor - * should be previously - * set. + * should be previously set. * @nor: pointer to a 'struct spi_nor' * @addr: offset in the serial flash memory * @len: number of bytes to read -- cgit v1.2.3 From 4dc49062a7e9c0c7261807fb855df1c611eb78c3 Mon Sep 17 00:00:00 2001 From: Yaliang Wang Date: Mon, 17 Oct 2022 01:19:01 +0800 Subject: mtd: spi-nor: gigadevice: gd25q256: replace gd25q256_default_init with gd25q256_post_bfpt When utilizing PARSE_SFDP to initialize the flash parameter, the deprecated initializing method spi_nor_init_params_deprecated() and the function spi_nor_manufacturer_init_params() within it will never be executed, which results in the default_init hook function will also never be executed. This is okay for 'D' generation of GD25Q256, because 'D' generation is implementing the JESD216B standards, it has QER field defined in BFPT, parsing the SFDP can properly set the quad_enable function. The 'E' generation also implements the JESD216B standards, and it has the same status register definitions as 'D' generation, parsing the SFDP to set the quad_enable function should also work for 'E' generation. However, the same thing can't apply to 'C' generation. 'C' generation 'GD25Q256C' implements the JESD216 standards, and it doesn't have the QER field defined in BFPT, since it does have QE bit in status register 1, the quad_enable hook needs to be tweaked to properly set the quad_enable function, this can be done in post_bfpt fixup hook. Fixes: 047275f7de18 ("mtd: spi-nor: gigadevice: gd25q256: Init flash based on SFDP") Reported-by: kernel test robot Signed-off-by: Yaliang Wang [tudor.ambarus@microchip.com: Update comment in gd25q256_post_bfpt] Signed-off-by: Tudor Ambarus Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20221016171901.1483542-2-yaliang.wang@windriver.com --- drivers/mtd/spi-nor/gigadevice.c | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/spi-nor/gigadevice.c b/drivers/mtd/spi-nor/gigadevice.c index 119b38e6fc2a..d57ddaf1525b 100644 --- a/drivers/mtd/spi-nor/gigadevice.c +++ b/drivers/mtd/spi-nor/gigadevice.c @@ -8,19 +8,29 @@ #include "core.h" -static void gd25q256_default_init(struct spi_nor *nor) +static int +gd25q256_post_bfpt(struct spi_nor *nor, + const struct sfdp_parameter_header *bfpt_header, + const struct sfdp_bfpt *bfpt) { /* - * Some manufacturer like GigaDevice may use different - * bit to set QE on different memories, so the MFR can't - * indicate the quad_enable method for this case, we need - * to set it in the default_init fixup hook. + * GD25Q256C supports the first version of JESD216 which does not define + * the Quad Enable methods. Overwrite the default Quad Enable method. + * + * GD25Q256 GENERATION | SFDP MAJOR VERSION | SFDP MINOR VERSION + * GD25Q256C | SFDP_JESD216_MAJOR | SFDP_JESD216_MINOR + * GD25Q256D | SFDP_JESD216_MAJOR | SFDP_JESD216B_MINOR + * GD25Q256E | SFDP_JESD216_MAJOR | SFDP_JESD216B_MINOR */ - nor->params->quad_enable = spi_nor_sr1_bit6_quad_enable; + if (bfpt_header->major == SFDP_JESD216_MAJOR && + bfpt_header->minor == SFDP_JESD216_MINOR) + nor->params->quad_enable = spi_nor_sr1_bit6_quad_enable; + + return 0; } static const struct spi_nor_fixups gd25q256_fixups = { - .default_init = gd25q256_default_init, + .post_bfpt = gd25q256_post_bfpt, }; static const struct flash_info gigadevice_nor_parts[] = { -- cgit v1.2.3 From fdc20370d93e8c6d2f448a539d08c2c064af7694 Mon Sep 17 00:00:00 2001 From: Allen-KH Cheng Date: Mon, 31 Oct 2022 20:46:33 +0800 Subject: mtd: spi-nor: Fix the number of bytes for the dummy cycles The number of bytes used by spi_nor_spimem_check_readop() may be incorrect for the dummy cycles. Since nor->read_dummy is not initialized before spi_nor_spimem_adjust_hwcaps(). We use both mode and wait state clock cycles instead of nor->read_dummy. Fixes: 0e30f47232ab ("mtd: spi-nor: add support for DTR protocol") Co-developed-by: Bayi Cheng Signed-off-by: Bayi Cheng Signed-off-by: Allen-KH Cheng Signed-off-by: Tudor Ambarus Tested-by: Dhruva Gole Tested-by: AngeloGioacchino Del Regno Reviewed-by: Pratyush Yadav Link: https://lore.kernel.org/r/20221031124633.13189-1-allen-kh.cheng@mediatek.com --- drivers/mtd/spi-nor/core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c index 71b9bcd8991d..dd45f286bb4e 100644 --- a/drivers/mtd/spi-nor/core.c +++ b/drivers/mtd/spi-nor/core.c @@ -1939,7 +1939,8 @@ static int spi_nor_spimem_check_readop(struct spi_nor *nor, spi_nor_spimem_setup_op(nor, &op, read->proto); /* convert the dummy cycles to the number of bytes */ - op.dummy.nbytes = (nor->read_dummy * op.dummy.buswidth) / 8; + op.dummy.nbytes = (read->num_mode_clocks + read->num_wait_states) * + op.dummy.buswidth / 8; if (spi_nor_protocol_is_dtr(nor->read_proto)) op.dummy.nbytes *= 2; -- cgit v1.2.3 From bcc0c61e6134066f4629845691a514ea33465653 Mon Sep 17 00:00:00 2001 From: Eliav Farber Date: Thu, 20 Oct 2022 09:20:58 +0000 Subject: mtd: spi-nor: micron-st: Enable locking for mt25qu256a mt25qu256a [1] uses the 4 bit Block Protection scheme and supports Top/Bottom protection via the BP and TB bits of the Status Register. BP3 is located in bit 6 of the Status Register. Tested on MT25QU256ABA8ESF-0SIT. [1] https://www.micron.com/-/media/client/global/documents/products/data-sheet/nor-flash/serial-nor/mt25q/die-rev-a/mt25q_qljs_u_256_aba_0.pdf Signed-off-by: Eliav Farber Signed-off-by: Tudor Ambarus Reviewed-by: Michael Walle Link: https://lore.kernel.org/r/20221020092058.33844-1-farbere@amazon.com --- drivers/mtd/spi-nor/micron-st.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/mtd') diff --git a/drivers/mtd/spi-nor/micron-st.c b/drivers/mtd/spi-nor/micron-st.c index 3c8a90b39c8c..7bb86df52f0b 100644 --- a/drivers/mtd/spi-nor/micron-st.c +++ b/drivers/mtd/spi-nor/micron-st.c @@ -205,6 +205,8 @@ static const struct flash_info st_nor_parts[] = { MFR_FLAGS(USE_FSR) }, { "mt25qu256a", INFO6(0x20bb19, 0x104400, 64 * 1024, 512) + FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_4BIT_BP | + SPI_NOR_BP3_SR_BIT6) NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) FIXUP_FLAGS(SPI_NOR_4B_OPCODES) MFR_FLAGS(USE_FSR) -- cgit v1.2.3 From ef434f08b0562069cf431873a052692357d325a1 Mon Sep 17 00:00:00 2001 From: Jae Hyun Yoo Date: Fri, 15 Jul 2022 17:06:43 -0700 Subject: mtd: spi-nor: winbond: add support for W25Q512NW-IQ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for Winbond W25Q512NW-IQ/IN Signed-off-by: Jae Hyun Yoo Signed-off-by: Tudor Ambarus Reviewed-by: Cédric Le Goater Reviewed-by: Michael Walle Link: https://www.winbond.com/resource-files/W25Q512NW%20RevB%2007192021.pdf Link: https://lore.kernel.org/r/20220716000643.3541839-2-quic_jaehyoo@quicinc.com --- drivers/mtd/spi-nor/winbond.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/mtd') diff --git a/drivers/mtd/spi-nor/winbond.c b/drivers/mtd/spi-nor/winbond.c index ffaa24055259..ca39acf4112c 100644 --- a/drivers/mtd/spi-nor/winbond.c +++ b/drivers/mtd/spi-nor/winbond.c @@ -133,6 +133,9 @@ static const struct flash_info winbond_nor_parts[] = { { "w25m512jv", INFO(0xef7119, 0, 64 * 1024, 1024) NO_SFDP_FLAGS(SECT_4K | SPI_NOR_QUAD_READ | SPI_NOR_DUAL_READ) }, + { "w25q512nwq", INFO(0xef6020, 0, 0, 0) + PARSE_SFDP + OTP_INFO(256, 3, 0x1000, 0x1000) }, { "w25q512nwm", INFO(0xef8020, 0, 64 * 1024, 1024) PARSE_SFDP OTP_INFO(256, 3, 0x1000, 0x1000) }, -- cgit v1.2.3 From a30f53d8bc0f9b55b4e8eea0e17b68cfd1f07f34 Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Tue, 20 Sep 2022 19:48:07 +0100 Subject: mtd: spi-nor: issi: is25wp256: Init flash based on SFDP The datasheet of is25wp256 says it supports SFDP. Get rid of the static initialization of the flash parameters and init them when parsing SFDP. Testing showed the flash using SPINOR_OP_READ_1_1_4_4B 0x6c, SPINOR_OP_PP_4B 0x12 and SPINOR_OP_BE_4K_4B 0x21 before enabling SFDP. After this patch, it parses the SFDP information and still uses the same opcodes. Set sector_size and n_sectors to zero as they will be discovered when parsing SFDP. Signed-off-by: Sudip Mukherjee [tudor.ambarus@microchip.com: set sector_size and n_sectors to zero] Signed-off-by: Tudor Ambarus Link: https://lore.kernel.org/r/20220920184808.44876-1-sudip.mukherjee@sifive.com --- drivers/mtd/spi-nor/issi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/spi-nor/issi.c b/drivers/mtd/spi-nor/issi.c index 89a66a19d754..72dfd5f087ad 100644 --- a/drivers/mtd/spi-nor/issi.c +++ b/drivers/mtd/spi-nor/issi.c @@ -70,8 +70,8 @@ static const struct flash_info issi_nor_parts[] = { NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, { "is25wp128", INFO(0x9d7018, 0, 64 * 1024, 256) NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { "is25wp256", INFO(0x9d7019, 0, 64 * 1024, 512) - NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) + { "is25wp256", INFO(0x9d7019, 0, 0, 0) + PARSE_SFDP FIXUP_FLAGS(SPI_NOR_4B_OPCODES) .fixups = &is25lp256_fixups }, -- cgit v1.2.3 From 1799cd8540b67b88514c82f5fae1c75b986bcbd8 Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Tue, 20 Sep 2022 19:48:08 +0100 Subject: mtd: spi-nor: add SFDP fixups for Quad Page Program SFDP table of some flash chips do not advertise support of Quad Input Page Program even though it has support. Use flags and add hardware cap for these chips. Signed-off-by: Sudip Mukherjee [tudor.ambarus@microchip.com: move pp setting in spi_nor_init_default_params] Signed-off-by: Tudor Ambarus Link: https://lore.kernel.org/r/20220920184808.44876-2-sudip.mukherjee@sifive.com --- drivers/mtd/spi-nor/core.c | 6 ++++++ drivers/mtd/spi-nor/core.h | 2 ++ drivers/mtd/spi-nor/issi.c | 1 + 3 files changed, 9 insertions(+) (limited to 'drivers/mtd') diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c index dd45f286bb4e..694a555defdc 100644 --- a/drivers/mtd/spi-nor/core.c +++ b/drivers/mtd/spi-nor/core.c @@ -2599,6 +2599,12 @@ static void spi_nor_init_default_params(struct spi_nor *nor) params->hwcaps.mask |= SNOR_HWCAPS_PP; spi_nor_set_pp_settings(¶ms->page_programs[SNOR_CMD_PP], SPINOR_OP_PP, SNOR_PROTO_1_1_1); + + if (info->flags & SPI_NOR_QUAD_PP) { + params->hwcaps.mask |= SNOR_HWCAPS_PP_1_1_4; + spi_nor_set_pp_settings(¶ms->page_programs[SNOR_CMD_PP_1_1_4], + SPINOR_OP_PP_1_1_4, SNOR_PROTO_1_1_4); + } } /** diff --git a/drivers/mtd/spi-nor/core.h b/drivers/mtd/spi-nor/core.h index ef0a73dbf348..f03b55cf7e6f 100644 --- a/drivers/mtd/spi-nor/core.h +++ b/drivers/mtd/spi-nor/core.h @@ -458,6 +458,7 @@ struct spi_nor_fixups { * SPI_NOR_NO_ERASE: no erase command needed. * NO_CHIP_ERASE: chip does not support chip erase. * SPI_NOR_NO_FR: can't do fastread. + * SPI_NOR_QUAD_PP: flash supports Quad Input Page Program. * * @no_sfdp_flags: flags that indicate support that can be discovered via SFDP. * Used when SFDP tables are not defined in the flash. These @@ -507,6 +508,7 @@ struct flash_info { #define SPI_NOR_NO_ERASE BIT(6) #define NO_CHIP_ERASE BIT(7) #define SPI_NOR_NO_FR BIT(8) +#define SPI_NOR_QUAD_PP BIT(9) u8 no_sfdp_flags; #define SPI_NOR_SKIP_SFDP BIT(0) diff --git a/drivers/mtd/spi-nor/issi.c b/drivers/mtd/spi-nor/issi.c index 72dfd5f087ad..a0ddad2afffc 100644 --- a/drivers/mtd/spi-nor/issi.c +++ b/drivers/mtd/spi-nor/issi.c @@ -73,6 +73,7 @@ static const struct flash_info issi_nor_parts[] = { { "is25wp256", INFO(0x9d7019, 0, 0, 0) PARSE_SFDP FIXUP_FLAGS(SPI_NOR_4B_OPCODES) + FLAGS(SPI_NOR_QUAD_PP) .fixups = &is25lp256_fixups }, /* PMC */ -- cgit v1.2.3 From 56570bdad5e31c5c538cd6efff5c4510256e1bb4 Mon Sep 17 00:00:00 2001 From: Shang XiaoJing Date: Sat, 19 Nov 2022 14:39:15 +0800 Subject: mtd: core: Fix refcount error in del_mtd_device() del_mtd_device() will call of_node_put() to mtd_get_of_node(mtd), which is mtd->dev.of_node. However, memset(&mtd->dev, 0) is called before of_node_put(). As the result, of_node_put() won't do anything in del_mtd_device(), and causes the refcount leak. del_mtd_device() memset(&mtd->dev, 0, sizeof(mtd->dev) # clear mtd->dev of_node_put() mtd_get_of_node(mtd) # mtd->dev is cleared, can't locate of_node # of_node_put(NULL) won't do anything Fix the error by caching the pointer of the device_node. OF: ERROR: memory leak, expected refcount 1 instead of 2, of_node_get()/of_node_put() unbalanced - destroy cset entry: attach overlay node /spi/spi-sram@0 CPU: 3 PID: 275 Comm: python3 Tainted: G N 6.1.0-rc3+ #54 0d8a1edddf51f172ff5226989a7565c6313b08e2 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.15.0-0-g2dd4b9b3f840-prebuilt.qemu.org 04/01/2014 Call Trace: dump_stack_lvl+0x67/0x83 kobject_get+0x155/0x160 of_node_get+0x1f/0x30 of_fwnode_get+0x43/0x70 fwnode_handle_get+0x54/0x80 fwnode_get_nth_parent+0xc9/0xe0 fwnode_full_name_string+0x3f/0xa0 device_node_string+0x30f/0x750 pointer+0x598/0x7a0 vsnprintf+0x62d/0x9b0 ... cfs_overlay_release+0x30/0x90 config_item_release+0xbe/0x1a0 config_item_put+0x5e/0x80 configfs_rmdir+0x3bd/0x540 vfs_rmdir+0x18c/0x320 do_rmdir+0x198/0x330 __x64_sys_rmdir+0x2c/0x40 do_syscall_64+0x37/0x90 entry_SYSCALL_64_after_hwframe+0x63/0xcd Fixes: 00596576a051 ("mtd: core: clear out unregistered devices a bit more") Signed-off-by: Shang XiaoJing [: Light reword of the commit log] Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20221119063915.11108-1-shangxiaojing@huawei.com --- drivers/mtd/mtdcore.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index 6c4683a5e531..0feacb9fbdac 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -780,6 +780,7 @@ int del_mtd_device(struct mtd_info *mtd) { int ret; struct mtd_notifier *not; + struct device_node *mtd_of_node; mutex_lock(&mtd_table_mutex); @@ -798,6 +799,7 @@ int del_mtd_device(struct mtd_info *mtd) mtd->index, mtd->name, mtd->usecount); ret = -EBUSY; } else { + mtd_of_node = mtd_get_of_node(mtd); debugfs_remove_recursive(mtd->dbg.dfs_dir); /* Try to remove the NVMEM provider */ @@ -809,7 +811,7 @@ int del_mtd_device(struct mtd_info *mtd) memset(&mtd->dev, 0, sizeof(mtd->dev)); idr_remove(&mtd_idr, mtd->index); - of_node_put(mtd_get_of_node(mtd)); + of_node_put(mtd_of_node); module_put(THIS_MODULE); ret = 0; -- cgit v1.2.3 From 2399401feee27c639addc5b7e6ba519d3ca341bf Mon Sep 17 00:00:00 2001 From: Zheng Yongjun Date: Sat, 19 Nov 2022 07:33:07 +0000 Subject: mtd: maps: pxa2xx-flash: fix memory leak in probe Free 'info' upon remapping error to avoid a memory leak. Fixes: e644f7d62894 ("[MTD] MAPS: Merge Lubbock and Mainstone drivers into common PXA2xx driver") Signed-off-by: Zheng Yongjun [: Reword the commit log] Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20221119073307.22929-1-zhengyongjun3@huawei.com --- drivers/mtd/maps/pxa2xx-flash.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/mtd') diff --git a/drivers/mtd/maps/pxa2xx-flash.c b/drivers/mtd/maps/pxa2xx-flash.c index 1749dbbacc13..62a5bf41a6d7 100644 --- a/drivers/mtd/maps/pxa2xx-flash.c +++ b/drivers/mtd/maps/pxa2xx-flash.c @@ -64,6 +64,7 @@ static int pxa2xx_flash_probe(struct platform_device *pdev) if (!info->map.virt) { printk(KERN_WARNING "Failed to ioremap %s\n", info->map.name); + kfree(info); return -ENOMEM; } info->map.cached = ioremap_cache(info->map.phys, info->map.size); @@ -85,6 +86,7 @@ static int pxa2xx_flash_probe(struct platform_device *pdev) iounmap((void *)info->map.virt); if (info->map.cached) iounmap(info->map.cached); + kfree(info); return -EIO; } info->mtd->dev.parent = &pdev->dev; -- cgit v1.2.3 From 6408cc05a50aaf88074a5a31d065e5af87a456f5 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 24 Nov 2022 11:59:46 +0100 Subject: mtd: rawnand: Drop obsolete dependencies on COMPILE_TEST Since commit 0166dc11be91 ("of: make CONFIG_OF user selectable"), it is possible to test-build any driver which depends on OF on any architecture by explicitly selecting OF. Therefore depending on COMPILE_TEST as an alternative is no longer needed. It is actually better to always build such drivers with OF enabled, so that the test builds are closer to how each driver will actually be built on its intended target. Building them without OF may not test much as the compiler will optimize out potentially large parts of the code. In the worst case, this could even pop false positive warnings. Dropping COMPILE_TEST here improves the quality of our testing and avoids wasting time on non-existent issues. Signed-off-by: Jean Delvare Cc: Miquel Raynal Cc: Richard Weinberger Cc: Vignesh Raghavendra Cc: Naga Sureshkumar Relli Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20221124115946.5edb771c@endymion.delvare --- drivers/mtd/nand/raw/Kconfig | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig index 4cd40af362de..98ea1c9e65c8 100644 --- a/drivers/mtd/nand/raw/Kconfig +++ b/drivers/mtd/nand/raw/Kconfig @@ -415,7 +415,7 @@ config MTD_NAND_PLATFORM config MTD_NAND_CADENCE tristate "Support Cadence NAND (HPNFC) controller" - depends on (OF || COMPILE_TEST) && HAS_IOMEM + depends on OF && HAS_IOMEM help Enable the driver for NAND flash on platforms using a Cadence NAND controller. @@ -430,7 +430,7 @@ config MTD_NAND_ARASAN config MTD_NAND_INTEL_LGM tristate "Support for NAND controller on Intel LGM SoC" - depends on OF || COMPILE_TEST + depends on OF depends on HAS_IOMEM help Enables support for NAND Flash chips on Intel's LGM SoC. @@ -450,7 +450,7 @@ config MTD_NAND_ROCKCHIP config MTD_NAND_PL35X tristate "ARM PL35X NAND controller" - depends on OF || COMPILE_TEST + depends on OF depends on PL353_SMC help Enables support for PrimeCell SMC PL351 and PL353 NAND -- cgit v1.2.3