From 434b8356df416678fb29d21b02bb5755c5f778f0 Mon Sep 17 00:00:00 2001 From: Ye Xingchen Date: Fri, 10 Feb 2023 17:23:56 +0800 Subject: mtd: rawnand: orion: use devm_platform_ioremap_resource() Convert platform_get_resource(), devm_ioremap_resource() to a single call to devm_platform_ioremap_resource(), as this is exactly what this function does. Signed-off-by: Ye Xingchen Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/202302101723563685569@zte.com.cn --- drivers/mtd/nand/raw/orion_nand.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/mtd/nand/raw/orion_nand.c b/drivers/mtd/nand/raw/orion_nand.c index 1bfecf502216..1bdcd544c3fa 100644 --- a/drivers/mtd/nand/raw/orion_nand.c +++ b/drivers/mtd/nand/raw/orion_nand.c @@ -102,7 +102,6 @@ static int __init orion_nand_probe(struct platform_device *pdev) struct mtd_info *mtd; struct nand_chip *nc; struct orion_nand_data *board; - struct resource *res; void __iomem *io_base; int ret = 0; u32 val = 0; @@ -119,8 +118,7 @@ static int __init orion_nand_probe(struct platform_device *pdev) info->controller.ops = &orion_nand_ops; nc->controller = &info->controller; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - io_base = devm_ioremap_resource(&pdev->dev, res); + io_base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(io_base)) return PTR_ERR(io_base); -- cgit v1.2.3 From bcf09d7e2ff435a5d587760170728c11773a4362 Mon Sep 17 00:00:00 2001 From: Md Sadre Alam Date: Mon, 6 Mar 2023 20:11:41 +0530 Subject: mtd: nand: raw: qcom_nandc: Use devm_platform_get_and_ioremap_resource() Convert platform_get_resource(), devm_ioremap_resource() to a single call to devm_platform_get_and_ioremap_resource(), as this is exactly what this function does. Signed-off-by: Md Sadre Alam Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20230306144141.15360-1-quic_mdalam@quicinc.com --- drivers/mtd/nand/raw/qcom_nandc.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/mtd/nand/raw/qcom_nandc.c b/drivers/mtd/nand/raw/qcom_nandc.c index 198a44794d2d..5cc1cbc9517d 100644 --- a/drivers/mtd/nand/raw/qcom_nandc.c +++ b/drivers/mtd/nand/raw/qcom_nandc.c @@ -3269,8 +3269,7 @@ static int qcom_nandc_probe(struct platform_device *pdev) if (ret) return ret; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - nandc->base = devm_ioremap_resource(dev, res); + nandc->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(nandc->base)) return PTR_ERR(nandc->base); -- cgit v1.2.3 From 42bf4597b7da8d9e3bc6039260e5437902af925a Mon Sep 17 00:00:00 2001 From: Md Sadre Alam Date: Mon, 6 Mar 2023 20:18:10 +0530 Subject: mtd: rawnand: Fix spelling mistake waifunc() -> waitfunc() There is a spelling mistake in a chip->legacy.waifunc(). Fix it. Signed-off-by: Md Sadre Alam Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20230306144810.22078-1-quic_mdalam@quicinc.com --- include/linux/mtd/rawnand.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h index f8d4be9c587a..5159d692f9ce 100644 --- a/include/linux/mtd/rawnand.h +++ b/include/linux/mtd/rawnand.h @@ -1075,7 +1075,7 @@ static inline void nand_op_trace(const char *prefix, * @exec_op: controller specific method to execute NAND operations. * This method replaces chip->legacy.cmdfunc(), * chip->legacy.{read,write}_{buf,byte,word}(), - * chip->legacy.dev_ready() and chip->legacy.waifunc(). + * chip->legacy.dev_ready() and chip->legacy.waitfunc(). * @setup_interface: setup the data interface and timing. If chipnr is set to * %NAND_DATA_IFACE_CHECK_ONLY this means the configuration * should not be applied but only checked. -- cgit v1.2.3 From 4080d536241652af43996d9ceee2b79aeca57267 Mon Sep 17 00:00:00 2001 From: Lukas Bulwahn Date: Tue, 7 Mar 2023 08:40:38 +0100 Subject: mtd: parsers: remove reference to config MTD_NAND_TMIO Commit 568494db6809 ("mtd: remove tmio_nand driver") removes the config MTD_NAND_TMIO and its corresponding driver. Remove the reference in MTD_SHARPSL_PARTS to that removed config. Signed-off-by: Lukas Bulwahn Acked-by: Arnd Bergmann Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20230307074038.17391-1-lukas.bulwahn@gmail.com --- drivers/mtd/parsers/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/parsers/Kconfig b/drivers/mtd/parsers/Kconfig index b20e0c38b517..60738edcd5d5 100644 --- a/drivers/mtd/parsers/Kconfig +++ b/drivers/mtd/parsers/Kconfig @@ -149,7 +149,7 @@ config MTD_PARSER_TRX config MTD_SHARPSL_PARTS tristate "Sharp SL Series NAND flash partition parser" - depends on MTD_NAND_SHARPSL || MTD_NAND_TMIO || COMPILE_TEST + depends on MTD_NAND_SHARPSL || COMPILE_TEST help This provides the read-only FTL logic necessary to read the partition table from the NAND flash of Sharp SL Series (Zaurus) and the MTD -- cgit v1.2.3 From 1cd9ceaa5282ff10ea20a7fbadde5a476a1cc99e Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Wed, 8 Mar 2023 09:20:18 +0100 Subject: mtd: core: provide unique name for nvmem device, take two Commit c048b60d39e1 ("mtd: core: provide unique name for nvmem device") tries to give the nvmem device a unique name, but fails badly if the mtd device doesn't have a "struct device" associated with it, i.e. if CONFIG_MTD_PARTITIONED_MASTER is not set. This will result in the name "(null)-user-otp", which is not unique. It seems the best we can do is to use the compatible name together with a unique identifier added by the nvmem subsystem by using NVMEM_DEVID_AUTO. Fixes: c048b60d39e1 ("mtd: core: provide unique name for nvmem device") Cc: stable@vger.kernel.org Signed-off-by: Michael Walle Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20230308082021.870459-1-michael@walle.cc --- drivers/mtd/mtdcore.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index 0feacb9fbdac..8fc66cda4a09 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -888,8 +888,8 @@ static struct nvmem_device *mtd_otp_nvmem_register(struct mtd_info *mtd, /* OTP nvmem will be registered on the physical device */ config.dev = mtd->dev.parent; - config.name = kasprintf(GFP_KERNEL, "%s-%s", dev_name(&mtd->dev), compatible); - config.id = NVMEM_DEVID_NONE; + config.name = compatible; + config.id = NVMEM_DEVID_AUTO; config.owner = THIS_MODULE; config.type = NVMEM_TYPE_OTP; config.root_only = true; @@ -905,7 +905,6 @@ static struct nvmem_device *mtd_otp_nvmem_register(struct mtd_info *mtd, nvmem = NULL; of_node_put(np); - kfree(config.name); return nvmem; } -- cgit v1.2.3 From 8bd1d24e6ca3c599dd455b0e1b22f77bab8290eb Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Wed, 8 Mar 2023 09:20:19 +0100 Subject: mtd: core: fix nvmem error reporting The master MTD will only have an associated device if CONFIG_MTD_PARTITIONED_MASTER is set, thus we cannot use dev_err() on mtd->dev. Instead use the parent device which is the physical flash memory. Fixes: 4b361cfa8624 ("mtd: core: add OTP nvmem provider support") Cc: stable@vger.kernel.org Signed-off-by: Michael Walle Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20230308082021.870459-2-michael@walle.cc --- drivers/mtd/mtdcore.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index 8fc66cda4a09..c38a13cb8d5e 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -939,6 +939,7 @@ static int mtd_nvmem_fact_otp_reg_read(void *priv, unsigned int offset, static int mtd_otp_nvmem_add(struct mtd_info *mtd) { + struct device *dev = mtd->dev.parent; struct nvmem_device *nvmem; ssize_t size; int err; @@ -952,7 +953,7 @@ static int mtd_otp_nvmem_add(struct mtd_info *mtd) nvmem = mtd_otp_nvmem_register(mtd, "user-otp", size, mtd_nvmem_user_otp_reg_read); if (IS_ERR(nvmem)) { - dev_err(&mtd->dev, "Failed to register OTP NVMEM device\n"); + dev_err(dev, "Failed to register OTP NVMEM device\n"); return PTR_ERR(nvmem); } mtd->otp_user_nvmem = nvmem; @@ -970,7 +971,7 @@ static int mtd_otp_nvmem_add(struct mtd_info *mtd) nvmem = mtd_otp_nvmem_register(mtd, "factory-otp", size, mtd_nvmem_fact_otp_reg_read); if (IS_ERR(nvmem)) { - dev_err(&mtd->dev, "Failed to register OTP NVMEM device\n"); + dev_err(dev, "Failed to register OTP NVMEM device\n"); err = PTR_ERR(nvmem); goto err; } -- cgit v1.2.3 From e0489f6e221f5ddee6cb3bd51b992b790c5fa4b9 Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Wed, 8 Mar 2023 09:20:20 +0100 Subject: mtd: core: fix error path for nvmem provider If mtd_otp_nvmem_add() fails, the partitions won't be removed because there is simply no call to del_mtd_partitions(). Unfortunately, add_mtd_partitions() will print all partitions to the kernel console. If mtd_otp_nvmem_add() returns -EPROBE_DEFER this would print the partitions multiple times to the kernel console. Instead move mtd_otp_nvmem_add() to the beginning of the function. Fixes: 4b361cfa8624 ("mtd: core: add OTP nvmem provider support") Cc: stable@vger.kernel.org Signed-off-by: Michael Walle Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20230308082021.870459-3-michael@walle.cc --- drivers/mtd/mtdcore.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index c38a13cb8d5e..0bc9676fe029 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -1023,10 +1023,14 @@ int mtd_device_parse_register(struct mtd_info *mtd, const char * const *types, mtd_set_dev_defaults(mtd); + ret = mtd_otp_nvmem_add(mtd); + if (ret) + goto out; + if (IS_ENABLED(CONFIG_MTD_PARTITIONED_MASTER)) { ret = add_mtd_device(mtd); if (ret) - return ret; + goto out; } /* Prefer parsed partitions over driver-provided fallback */ @@ -1061,9 +1065,12 @@ int mtd_device_parse_register(struct mtd_info *mtd, const char * const *types, register_reboot_notifier(&mtd->reboot_notifier); } - ret = mtd_otp_nvmem_add(mtd); - out: + if (ret) { + nvmem_unregister(mtd->otp_user_nvmem); + nvmem_unregister(mtd->otp_factory_nvmem); + } + if (ret && device_is_registered(&mtd->dev)) del_mtd_device(mtd); -- cgit v1.2.3 From 281f7a6c1a33fffcde32001bacbb4f672140fbf9 Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Wed, 8 Mar 2023 09:20:21 +0100 Subject: mtd: core: prepare mtd_otp_nvmem_add() to handle -EPROBE_DEFER NVMEM soon will get the ability for nvmem layouts and these might not be ready when nvmem_register() is called and thus it might return -EPROBE_DEFER. Don't print the error message in this case. Signed-off-by: Michael Walle Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20230308082021.870459-4-michael@walle.cc --- drivers/mtd/mtdcore.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index 0bc9676fe029..83a22566a8ce 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -953,8 +953,8 @@ static int mtd_otp_nvmem_add(struct mtd_info *mtd) nvmem = mtd_otp_nvmem_register(mtd, "user-otp", size, mtd_nvmem_user_otp_reg_read); if (IS_ERR(nvmem)) { - dev_err(dev, "Failed to register OTP NVMEM device\n"); - return PTR_ERR(nvmem); + err = PTR_ERR(nvmem); + goto err; } mtd->otp_user_nvmem = nvmem; } @@ -971,7 +971,6 @@ static int mtd_otp_nvmem_add(struct mtd_info *mtd) nvmem = mtd_otp_nvmem_register(mtd, "factory-otp", size, mtd_nvmem_fact_otp_reg_read); if (IS_ERR(nvmem)) { - dev_err(dev, "Failed to register OTP NVMEM device\n"); err = PTR_ERR(nvmem); goto err; } @@ -983,7 +982,7 @@ static int mtd_otp_nvmem_add(struct mtd_info *mtd) err: nvmem_unregister(mtd->otp_user_nvmem); - return err; + return dev_err_probe(dev, err, "Failed to register OTP NVMEM device\n"); } /** -- cgit v1.2.3 From 3e79e1b4addb209038eea094d1a2de8ab3fc7298 Mon Sep 17 00:00:00 2001 From: Nick Alcock Date: Fri, 24 Feb 2023 15:08:02 +0000 Subject: mtd: bcm63xxpart: remove MODULE_LICENSE in non-modules Since commit 8b41fc4454e ("kbuild: create modules.builtin without Makefile.modbuiltin or tristate.conf"), MODULE_LICENSE declarations are used to identify modules. As a consequence, uses of the macro in non-modules will cause modprobe to misidentify their containing object file as a module when it is not (false positives), and modprobe might succeed rather than failing with a suitable error message. So remove it in the files in this commit, none of which can be built as modules. Signed-off-by: Nick Alcock Suggested-by: Luis Chamberlain Cc: Luis Chamberlain Cc: linux-modules@vger.kernel.org Cc: linux-kernel@vger.kernel.org Cc: Hitomi Hasegawa Cc: Miquel Raynal Cc: Richard Weinberger Cc: Vignesh Raghavendra Cc: linux-mtd@lists.infradead.org Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20230224150811.80316-19-nick.alcock@oracle.com --- drivers/mtd/parsers/bcm63xxpart.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/mtd/parsers/bcm63xxpart.c b/drivers/mtd/parsers/bcm63xxpart.c index b15bdadaedb5..6e7b1ae8f58f 100644 --- a/drivers/mtd/parsers/bcm63xxpart.c +++ b/drivers/mtd/parsers/bcm63xxpart.c @@ -164,7 +164,6 @@ static struct mtd_part_parser bcm63xx_cfe_parser = { }; module_mtd_part_parser(bcm63xx_cfe_parser); -MODULE_LICENSE("GPL"); MODULE_AUTHOR("Daniel Dickinson "); MODULE_AUTHOR("Florian Fainelli "); MODULE_AUTHOR("Mike Albon "); -- cgit v1.2.3 From 5cab06156aade17fbee2fd926bce8c503e55b2b5 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Tue, 7 Mar 2023 20:25:06 +0100 Subject: mtd: Avoid printing error messages on probe deferrals There is no reason to complain about probe errors in case of deferrals. Signed-off-by: Miquel Raynal Reviewed-by: Michael Walle Link: https://lore.kernel.org/linux-mtd/20230307192506.439532-1-miquel.raynal@bootlin.com --- drivers/mtd/mtdcore.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index 83a22566a8ce..83fb7192a593 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -536,12 +536,11 @@ static int mtd_nvmem_add(struct mtd_info *mtd) mtd->nvmem = nvmem_register(&config); if (IS_ERR(mtd->nvmem)) { /* Just ignore if there is no NVMEM support in the kernel */ - if (PTR_ERR(mtd->nvmem) == -EOPNOTSUPP) { + if (PTR_ERR(mtd->nvmem) == -EOPNOTSUPP) mtd->nvmem = NULL; - } else { - dev_err(&mtd->dev, "Failed to register NVMEM device\n"); - return PTR_ERR(mtd->nvmem); - } + else + return dev_err_probe(&mtd->dev, PTR_ERR(mtd->nvmem), + "Failed to register NVMEM device\n"); } return 0; -- cgit v1.2.3 From 75f32f4b9d5263829d1d13f990000db929140559 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Tue, 7 Mar 2023 20:25:36 +0100 Subject: mtd: Avoid magic values Nvmem producer config ID "-1" is actually defined, so use the definition rather than hardcoding it with a magic value. Suggested-by: Michael Walle Signed-off-by: Miquel Raynal Reviewed-by: Michael Walle Link: https://lore.kernel.org/linux-mtd/20230307192536.470997-1-miquel.raynal@bootlin.com --- drivers/mtd/mtdcore.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index 83fb7192a593..c78f9f4d522c 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -519,7 +519,7 @@ static int mtd_nvmem_add(struct mtd_info *mtd) struct device_node *node = mtd_get_of_node(mtd); struct nvmem_config config = {}; - config.id = -1; + config.id = NVMEM_DEVID_NONE; config.dev = &mtd->dev; config.name = dev_name(&mtd->dev); config.owner = THIS_MODULE; -- cgit v1.2.3 From d628783c46d3c317deb0671ceb986be358fbaf69 Mon Sep 17 00:00:00 2001 From: Takahiro Kuwano Date: Thu, 2 Mar 2023 16:35:06 +0900 Subject: mtd: spi-nor: spansion: Make RD_ANY_REG_OP macro take number of dummy bytes Currently Read Any Register op is used to read volatile registers without any dummy cycles, but the op requires dummy cycles depending on register type (volatiler or non-volatile), device family, and device configuration. Add 'ndummy' argument to RD_ANY_REG_OP macro to support other use cases. Suggested-by: Tudor Ambarus Signed-off-by: Takahiro Kuwano Link: https://lore.kernel.org/r/03756e9e3ac41d2016a71d2afb702398dd0b19ed.1677557525.git.Takahiro.Kuwano@infineon.com Signed-off-by: Tudor Ambarus --- drivers/mtd/spi-nor/spansion.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/mtd/spi-nor/spansion.c b/drivers/mtd/spi-nor/spansion.c index 12a256c0ef4c..9faab29aba57 100644 --- a/drivers/mtd/spi-nor/spansion.c +++ b/drivers/mtd/spi-nor/spansion.c @@ -37,10 +37,10 @@ SPI_MEM_OP_NO_DUMMY, \ SPI_MEM_OP_DATA_OUT(ndata, buf, 0)) -#define CYPRESS_NOR_RD_ANY_REG_OP(naddr, addr, buf) \ +#define CYPRESS_NOR_RD_ANY_REG_OP(naddr, addr, ndummy, buf) \ SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_RD_ANY_REG, 0), \ SPI_MEM_OP_ADDR(naddr, addr, 0), \ - SPI_MEM_OP_NO_DUMMY, \ + SPI_MEM_OP_DUMMY(ndummy, 0), \ SPI_MEM_OP_DATA_IN(1, buf, 0)) #define SPANSION_CLSR_OP \ @@ -148,7 +148,7 @@ static int cypress_nor_quad_enable_volatile(struct spi_nor *nor) op = (struct spi_mem_op) CYPRESS_NOR_RD_ANY_REG_OP(addr_mode_nbytes, - SPINOR_REG_CYPRESS_CFR1V, + SPINOR_REG_CYPRESS_CFR1V, 0, nor->bouncebuf); ret = spi_nor_read_any_reg(nor, &op, nor->reg_proto); @@ -173,7 +173,7 @@ static int cypress_nor_quad_enable_volatile(struct spi_nor *nor) /* Read back and check it. */ op = (struct spi_mem_op) CYPRESS_NOR_RD_ANY_REG_OP(addr_mode_nbytes, - SPINOR_REG_CYPRESS_CFR1V, + SPINOR_REG_CYPRESS_CFR1V, 0, nor->bouncebuf); ret = spi_nor_read_any_reg(nor, &op, nor->reg_proto); if (ret) @@ -202,7 +202,7 @@ static int cypress_nor_set_page_size(struct spi_nor *nor) { struct spi_mem_op op = CYPRESS_NOR_RD_ANY_REG_OP(nor->params->addr_mode_nbytes, - SPINOR_REG_CYPRESS_CFR3V, + SPINOR_REG_CYPRESS_CFR3V, 0, nor->bouncebuf); int ret; -- cgit v1.2.3 From 6afcc84080c415df81765c6d773edcba8fc30f6c Mon Sep 17 00:00:00 2001 From: Takahiro Kuwano Date: Thu, 2 Mar 2023 16:35:07 +0900 Subject: mtd: spi-nor: spansion: Add support for Infineon S25FS256T Infineon S25FS256T is 256Mbit Quad SPI NOR flash. The key features and differences comparing to other Spansion/Cypress flash familes are: - 4-byte address mode by factory default - Quad mode is enabled by factory default - OP_READ_FAST_4B(0Ch) is not supported - Supports mixture of 128KB and 64KB sectors by OTP configuration (this patch supports uniform 128KB only due to complexity of non-uniform layout) Tested on Xilinx Zynq-7000 FPGA board. Link: https://www.infineon.com/dgdlac/Infineon-S25FS256T_256Mb_SEMPER_Nano_Flash_Quad_SPI_1.8V-DataSheet-v12_00-EN.pdf?fileId=8ac78c8c80027ecd0180740c5a46707a Signed-off-by: Takahiro Kuwano Link: https://lore.kernel.org/r/097ef04484966593ba1326d0a99462753d7d1073.1677557525.git.Takahiro.Kuwano@infineon.com Signed-off-by: Tudor Ambarus --- drivers/mtd/spi-nor/spansion.c | 60 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/drivers/mtd/spi-nor/spansion.c b/drivers/mtd/spi-nor/spansion.c index 9faab29aba57..1678b7b2e9f7 100644 --- a/drivers/mtd/spi-nor/spansion.c +++ b/drivers/mtd/spi-nor/spansion.c @@ -29,6 +29,7 @@ SPINOR_REG_CYPRESS_CFR5_OPI) #define SPINOR_REG_CYPRESS_CFR5_OCT_DTR_DS SPINOR_REG_CYPRESS_CFR5_BIT6 #define SPINOR_OP_CYPRESS_RD_FAST 0xee +#define SPINOR_REG_CYPRESS_ARCFN 0x00000006 /* Cypress SPI NOR flash operations. */ #define CYPRESS_NOR_WR_ANY_REG_OP(naddr, addr, ndata, buf) \ @@ -218,6 +219,62 @@ static int cypress_nor_set_page_size(struct spi_nor *nor) return 0; } +static int +s25fs256t_post_bfpt_fixup(struct spi_nor *nor, + const struct sfdp_parameter_header *bfpt_header, + const struct sfdp_bfpt *bfpt) +{ + struct spi_mem_op op; + int ret; + + /* 4-byte address mode is enabled by default */ + nor->params->addr_nbytes = 4; + nor->params->addr_mode_nbytes = 4; + + /* Read Architecture Configuration Register (ARCFN) */ + op = (struct spi_mem_op) + CYPRESS_NOR_RD_ANY_REG_OP(nor->params->addr_mode_nbytes, + SPINOR_REG_CYPRESS_ARCFN, 1, + nor->bouncebuf); + ret = spi_nor_read_any_reg(nor, &op, nor->reg_proto); + if (ret) + return ret; + + /* ARCFN value must be 0 if uniform sector is selected */ + if (nor->bouncebuf[0]) + return -ENODEV; + + return cypress_nor_set_page_size(nor); +} + +static void s25fs256t_post_sfdp_fixup(struct spi_nor *nor) +{ + struct spi_nor_flash_parameter *params = nor->params; + + /* PP_1_1_4_4B is supported but missing in 4BAIT. */ + 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_4B, + SNOR_PROTO_1_1_4); +} + +static void s25fs256t_late_init(struct spi_nor *nor) +{ + /* + * Programming is supported only in 16-byte ECC data unit granularity. + * Byte-programming, bit-walking, or multiple program operations to the + * same ECC data unit without an erase are not allowed. See chapter + * 5.3.1 and 5.6 in the datasheet. + */ + nor->params->writesize = 16; +} + +static struct spi_nor_fixups s25fs256t_fixups = { + .post_bfpt = s25fs256t_post_bfpt_fixup, + .post_sfdp = s25fs256t_post_sfdp_fixup, + .late_init = s25fs256t_late_init, +}; + static int s25hx_t_post_bfpt_fixup(struct spi_nor *nor, const struct sfdp_parameter_header *bfpt_header, @@ -446,6 +503,9 @@ static const struct flash_info spansion_nor_parts[] = { { "s25fl256l", INFO(0x016019, 0, 64 * 1024, 512) NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) FIXUP_FLAGS(SPI_NOR_4B_OPCODES) }, + { "s25fs256t", INFO6(0x342b19, 0x0f0890, 0, 0) + PARSE_SFDP + .fixups = &s25fs256t_fixups }, { "s25hl512t", INFO6(0x342a1a, 0x0f0390, 256 * 1024, 256) PARSE_SFDP MFR_FLAGS(USE_CLSR) -- cgit v1.2.3 From 57150c40b6391bc350c6016641b2a487a3de3cba Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 10 Mar 2023 08:47:15 -0600 Subject: mtd: Use of_property_read_bool() for boolean properties It is preferred to use typed property access functions (i.e. of_property_read_ functions) rather than low-level of_get_property/of_find_property functions for reading properties. Convert reading boolean properties to to of_property_read_bool(). Signed-off-by: Rob Herring Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20230310144716.1543995-1-robh@kernel.org --- drivers/mtd/devices/spear_smi.c | 4 ++-- drivers/mtd/maps/sun_uflash.c | 2 +- drivers/mtd/mtdcore.c | 2 +- drivers/mtd/nand/raw/fsmc_nand.c | 2 +- drivers/mtd/nand/raw/nand_macronix.c | 5 ++--- drivers/mtd/spi-nor/controllers/nxp-spifi.c | 4 ++-- 6 files changed, 9 insertions(+), 10 deletions(-) diff --git a/drivers/mtd/devices/spear_smi.c b/drivers/mtd/devices/spear_smi.c index f58742486d3d..cc17133be297 100644 --- a/drivers/mtd/devices/spear_smi.c +++ b/drivers/mtd/devices/spear_smi.c @@ -820,8 +820,8 @@ static int spear_smi_probe_config_dt(struct platform_device *pdev, pdata->board_flash_info->mem_base = be32_to_cpup(&addr[0]); pdata->board_flash_info->size = be32_to_cpup(&addr[1]); - if (of_get_property(pp, "st,smi-fast-mode", NULL)) - pdata->board_flash_info->fast_mode = 1; + pdata->board_flash_info->fast_mode = + of_property_read_bool(pp, "st,smi-fast-mode"); i++; } diff --git a/drivers/mtd/maps/sun_uflash.c b/drivers/mtd/maps/sun_uflash.c index 6c0c91bfec05..860b19f77090 100644 --- a/drivers/mtd/maps/sun_uflash.c +++ b/drivers/mtd/maps/sun_uflash.c @@ -112,7 +112,7 @@ static int uflash_probe(struct platform_device *op) /* Flashprom must have the "user" property in order to * be used by this driver. */ - if (!of_find_property(dp, "user", NULL)) + if (!of_property_read_bool(dp, "user")) return -ENODEV; return uflash_devinit(op, dp); diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index c78f9f4d522c..a1a08c2b6f77 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -738,7 +738,7 @@ int add_mtd_device(struct mtd_info *mtd) mutex_unlock(&mtd_table_mutex); - if (of_find_property(mtd_get_of_node(mtd), "linux,rootfs", NULL)) { + if (of_property_read_bool(mtd_get_of_node(mtd), "linux,rootfs")) { 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); diff --git a/drivers/mtd/nand/raw/fsmc_nand.c b/drivers/mtd/nand/raw/fsmc_nand.c index 6b2bda815b88..0d34d433b732 100644 --- a/drivers/mtd/nand/raw/fsmc_nand.c +++ b/drivers/mtd/nand/raw/fsmc_nand.c @@ -880,7 +880,7 @@ static int fsmc_nand_probe_config_dt(struct platform_device *pdev, } } - if (of_get_property(np, "nand-skip-bbtscan", NULL)) + if (of_property_read_bool(np, "nand-skip-bbtscan")) nand->options |= NAND_SKIP_BBTSCAN; host->dev_timings = devm_kzalloc(&pdev->dev, diff --git a/drivers/mtd/nand/raw/nand_macronix.c b/drivers/mtd/nand/raw/nand_macronix.c index 1472f925f386..385957eb6762 100644 --- a/drivers/mtd/nand/raw/nand_macronix.c +++ b/drivers/mtd/nand/raw/nand_macronix.c @@ -93,14 +93,13 @@ static void macronix_nand_onfi_init(struct nand_chip *chip) struct nand_parameters *p = &chip->parameters; struct nand_onfi_vendor_macronix *mxic; struct device_node *dn = nand_get_flash_node(chip); - int rand_otp = 0; + int rand_otp; int ret; if (!p->onfi) return; - if (of_find_property(dn, "mxic,enable-randomizer-otp", NULL)) - rand_otp = 1; + rand_otp = of_property_read_bool(dn, "mxic,enable-randomizer-otp"); mxic = (struct nand_onfi_vendor_macronix *)p->onfi->vendor; /* Subpage write is prohibited in randomizer operatoin */ diff --git a/drivers/mtd/spi-nor/controllers/nxp-spifi.c b/drivers/mtd/spi-nor/controllers/nxp-spifi.c index ab3990e6ac25..794c7b7d5c92 100644 --- a/drivers/mtd/spi-nor/controllers/nxp-spifi.c +++ b/drivers/mtd/spi-nor/controllers/nxp-spifi.c @@ -305,10 +305,10 @@ static int nxp_spifi_setup_flash(struct nxp_spifi *spifi, } } - if (of_find_property(np, "spi-cpha", NULL)) + if (of_property_read_bool(np, "spi-cpha")) mode |= SPI_CPHA; - if (of_find_property(np, "spi-cpol", NULL)) + if (of_property_read_bool(np, "spi-cpol")) mode |= SPI_CPOL; /* Setup control register defaults */ -- cgit v1.2.3 From e6b0922a9c614d7689393391325c943b34afd6d4 Mon Sep 17 00:00:00 2001 From: Bang Li Date: Wed, 15 Mar 2023 00:56:53 +0800 Subject: mtdblock: tolerate corrected bit-flips mtd_read() may return -EUCLEAN in case of corrected bit-flips.This particular condition should not be treated like an error. Signed-off-by: Bang Li Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20230314165653.252673-1-libang.linuxer@gmail.com --- drivers/mtd/mtdblock_ro.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/mtdblock_ro.c b/drivers/mtd/mtdblock_ro.c index 7c51952ce55d..66ffc9f1ead2 100644 --- a/drivers/mtd/mtdblock_ro.c +++ b/drivers/mtd/mtdblock_ro.c @@ -16,8 +16,10 @@ static int mtdblock_readsect(struct mtd_blktrans_dev *dev, unsigned long block, char *buf) { size_t retlen; + int err; - if (mtd_read(dev->mtd, (block * 512), 512, &retlen, buf)) + err = mtd_read(dev->mtd, (block * 512), 512, &retlen, buf); + if (err && !mtd_is_bitflip(err)) return 1; return 0; } -- cgit v1.2.3 From e8c047b4a92cf4af7a81bf31e9b31fedc7434335 Mon Sep 17 00:00:00 2001 From: Hector Palacios Date: Fri, 10 Mar 2023 09:06:09 +0100 Subject: mtd: rawnand: hynix: fix up bit 0 of sdr_timing_mode According to the ONFI specification, bit 0 of 'SDR timing mode support' (bytes 129-130) "shall be 1". That means the NAND supports at least timing mode 0. NAND chip Hynix H27U4G8F2GDA-BI (at least) is reading a 0 on this field which makes nand_choose_best_sdr_timings() return with error and the probe function to eventually fail. Given that sdr_timing_modes bit 0 must be 1 by specification, force it in case the NAND reports it is not set. This is a safe assumption because the mode 0 is the minimum (safer) set of timings that the NAND can work with. Signed-off-by: Hector Palacios Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20230223165104.525852-1-hector.palacios@digi.com Link: https://lore.kernel.org/linux-mtd/20230310080609.1930869-1-hector.palacios@digi.com --- drivers/mtd/nand/raw/nand_hynix.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/mtd/nand/raw/nand_hynix.c b/drivers/mtd/nand/raw/nand_hynix.c index 0d4d4bbfdece..39076735a3fb 100644 --- a/drivers/mtd/nand/raw/nand_hynix.c +++ b/drivers/mtd/nand/raw/nand_hynix.c @@ -728,8 +728,21 @@ static int hynix_nand_init(struct nand_chip *chip) return ret; } +static void hynix_fixup_onfi_param_page(struct nand_chip *chip, + struct nand_onfi_params *p) +{ + /* + * Certain chips might report a 0 on sdr_timing_mode field + * (bytes 129-130). This has been seen on H27U4G8F2GDA-BI. + * According to ONFI specification, bit 0 of this field "shall be 1". + * Forcibly set this bit. + */ + p->sdr_timing_modes |= cpu_to_le16(BIT(0)); +} + const struct nand_manufacturer_ops hynix_nand_manuf_ops = { .detect = hynix_nand_decode_id, .init = hynix_nand_init, .cleanup = hynix_nand_cleanup, + .fixup_onfi_param_page = hynix_fixup_onfi_param_page, }; -- cgit v1.2.3 From 7c09abba58cf912fa417be8720cff00df12354aa Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 10 Mar 2023 08:47:15 -0600 Subject: mtd: nand: qcom: Use of_property_present() for testing DT property presence It is preferred to use typed property access functions (i.e. of_property_read_ functions) rather than low-level of_get_property/of_find_property functions for reading properties. As part of this, convert of_get_property/of_find_property calls to the recently added of_property_present() helper when we just want to test for presence of a property and nothing more. Signed-off-by: Rob Herring Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20230310144715.1543926-1-robh@kernel.org --- drivers/mtd/nand/raw/qcom_nandc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/nand/raw/qcom_nandc.c b/drivers/mtd/nand/raw/qcom_nandc.c index 5cc1cbc9517d..e1f7e2cb95a5 100644 --- a/drivers/mtd/nand/raw/qcom_nandc.c +++ b/drivers/mtd/nand/raw/qcom_nandc.c @@ -3054,7 +3054,7 @@ static int qcom_nand_host_parse_boot_partitions(struct qcom_nand_controller *nan struct device *dev = nandc->dev; int partitions_count, i, j, ret; - if (!of_find_property(dn, "qcom,boot-partitions", NULL)) + if (!of_property_present(dn, "qcom,boot-partitions")) return 0; partitions_count = of_property_count_u32_elems(dn, "qcom,boot-partitions"); -- cgit v1.2.3 From cb70cf99abae487941bbb5d3661653c02a5103cc Mon Sep 17 00:00:00 2001 From: Tom Rix Date: Tue, 21 Mar 2023 07:46:38 -0400 Subject: mtd: rawnand: remove unused is_imx51_nfc and imx53_nfc functions clang with W=1 reports drivers/mtd/nand/raw/mxc_nand.c:1602:19: error: unused function 'is_imx51_nfc' [-Werror,-Wunused-function] static inline int is_imx51_nfc(struct mxc_nand_host *host) ^ drivers/mtd/nand/raw/mxc_nand.c:1607:19: error: unused function 'is_imx53_nfc' [-Werror,-Wunused-function] static inline int is_imx53_nfc(struct mxc_nand_host *host) ^ These functions are not used, so remove them. Signed-off-by: Tom Rix Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20230321114638.1782086-1-trix@redhat.com --- drivers/mtd/nand/raw/mxc_nand.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/drivers/mtd/nand/raw/mxc_nand.c b/drivers/mtd/nand/raw/mxc_nand.c index f6c96341b896..f61ffcbe57c8 100644 --- a/drivers/mtd/nand/raw/mxc_nand.c +++ b/drivers/mtd/nand/raw/mxc_nand.c @@ -1599,16 +1599,6 @@ static inline int is_imx25_nfc(struct mxc_nand_host *host) return host->devtype_data == &imx25_nand_devtype_data; } -static inline int is_imx51_nfc(struct mxc_nand_host *host) -{ - return host->devtype_data == &imx51_nand_devtype_data; -} - -static inline int is_imx53_nfc(struct mxc_nand_host *host) -{ - return host->devtype_data == &imx53_nand_devtype_data; -} - static const struct of_device_id mxcnd_dt_ids[] = { { .compatible = "fsl,imx21-nand", .data = &imx21_nand_devtype_data, }, { .compatible = "fsl,imx27-nand", .data = &imx27_nand_devtype_data, }, -- cgit v1.2.3 From 1f79a611e74c97dcb76054b9f28f41a122a7a93b Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 17 Mar 2023 18:36:30 -0500 Subject: dt-bindings: mtd: Drop unneeded quotes Cleanup bindings dropping unneeded quotes. Once all these are fixed, checking for this can be enabled in yamllint. Signed-off-by: Rob Herring Acked-by: Jernej Skrabec Reviewed-by: Krzysztof Kozlowski Reviewed-by: Linus Walleij Reviewed-by: Heiko Stuebner #rockchip Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20230317233631.3968509-1-robh@kernel.org --- Documentation/devicetree/bindings/mtd/allwinner,sun4i-a10-nand.yaml | 2 +- Documentation/devicetree/bindings/mtd/arasan,nand-controller.yaml | 2 +- Documentation/devicetree/bindings/mtd/arm,pl353-nand-r2p1.yaml | 2 +- Documentation/devicetree/bindings/mtd/gpmi-nand.yaml | 2 +- Documentation/devicetree/bindings/mtd/intel,lgm-ebunand.yaml | 2 +- Documentation/devicetree/bindings/mtd/jedec,spi-nor.yaml | 2 +- Documentation/devicetree/bindings/mtd/mtd-physmap.yaml | 2 +- Documentation/devicetree/bindings/mtd/mxc-nand.yaml | 2 +- Documentation/devicetree/bindings/mtd/nand-chip.yaml | 2 +- Documentation/devicetree/bindings/mtd/nand-controller.yaml | 2 +- .../devicetree/bindings/mtd/partitions/brcm,bcm4908-partitions.yaml | 2 +- .../devicetree/bindings/mtd/partitions/linksys,ns-partitions.yaml | 2 +- Documentation/devicetree/bindings/mtd/qcom,nandc.yaml | 2 +- Documentation/devicetree/bindings/mtd/renesas-nandc.yaml | 2 +- Documentation/devicetree/bindings/mtd/rockchip,nand-controller.yaml | 2 +- Documentation/devicetree/bindings/mtd/spi-nand.yaml | 2 +- Documentation/devicetree/bindings/mtd/st,stm32-fmc2-nand.yaml | 2 +- Documentation/devicetree/bindings/mtd/ti,gpmc-nand.yaml | 4 ++-- Documentation/devicetree/bindings/mtd/ti,gpmc-onenand.yaml | 4 ++-- 19 files changed, 21 insertions(+), 21 deletions(-) diff --git a/Documentation/devicetree/bindings/mtd/allwinner,sun4i-a10-nand.yaml b/Documentation/devicetree/bindings/mtd/allwinner,sun4i-a10-nand.yaml index e7ec0c59bca6..9a88870cd865 100644 --- a/Documentation/devicetree/bindings/mtd/allwinner,sun4i-a10-nand.yaml +++ b/Documentation/devicetree/bindings/mtd/allwinner,sun4i-a10-nand.yaml @@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml# title: Allwinner A10 NAND Controller allOf: - - $ref: "nand-controller.yaml" + - $ref: nand-controller.yaml maintainers: - Chen-Yu Tsai diff --git a/Documentation/devicetree/bindings/mtd/arasan,nand-controller.yaml b/Documentation/devicetree/bindings/mtd/arasan,nand-controller.yaml index d028269cdbaa..2fe53cbfbee0 100644 --- a/Documentation/devicetree/bindings/mtd/arasan,nand-controller.yaml +++ b/Documentation/devicetree/bindings/mtd/arasan,nand-controller.yaml @@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml# title: Arasan NAND Flash Controller with ONFI 3.1 support allOf: - - $ref: "nand-controller.yaml" + - $ref: nand-controller.yaml maintainers: - Naga Sureshkumar Relli diff --git a/Documentation/devicetree/bindings/mtd/arm,pl353-nand-r2p1.yaml b/Documentation/devicetree/bindings/mtd/arm,pl353-nand-r2p1.yaml index e552875040e2..f8c0f606f451 100644 --- a/Documentation/devicetree/bindings/mtd/arm,pl353-nand-r2p1.yaml +++ b/Documentation/devicetree/bindings/mtd/arm,pl353-nand-r2p1.yaml @@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml# title: PL353 NAND Controller allOf: - - $ref: "nand-controller.yaml" + - $ref: nand-controller.yaml maintainers: - Miquel Raynal diff --git a/Documentation/devicetree/bindings/mtd/gpmi-nand.yaml b/Documentation/devicetree/bindings/mtd/gpmi-nand.yaml index 8487089b6e16..ba086c34626d 100644 --- a/Documentation/devicetree/bindings/mtd/gpmi-nand.yaml +++ b/Documentation/devicetree/bindings/mtd/gpmi-nand.yaml @@ -93,7 +93,7 @@ required: unevaluatedProperties: false allOf: - - $ref: "nand-controller.yaml" + - $ref: nand-controller.yaml - if: properties: diff --git a/Documentation/devicetree/bindings/mtd/intel,lgm-ebunand.yaml b/Documentation/devicetree/bindings/mtd/intel,lgm-ebunand.yaml index 8c62c7d3d0cd..cc3def758e00 100644 --- a/Documentation/devicetree/bindings/mtd/intel,lgm-ebunand.yaml +++ b/Documentation/devicetree/bindings/mtd/intel,lgm-ebunand.yaml @@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml# title: Intel LGM SoC NAND Controller allOf: - - $ref: "nand-controller.yaml" + - $ref: nand-controller.yaml maintainers: - Ramuthevar Vadivel Murugan diff --git a/Documentation/devicetree/bindings/mtd/jedec,spi-nor.yaml b/Documentation/devicetree/bindings/mtd/jedec,spi-nor.yaml index 3fe981b14e2c..2bece155699f 100644 --- a/Documentation/devicetree/bindings/mtd/jedec,spi-nor.yaml +++ b/Documentation/devicetree/bindings/mtd/jedec,spi-nor.yaml @@ -10,7 +10,7 @@ maintainers: - Rob Herring allOf: - - $ref: "mtd.yaml#" + - $ref: mtd.yaml# - $ref: /schemas/spi/spi-peripheral-props.yaml# properties: diff --git a/Documentation/devicetree/bindings/mtd/mtd-physmap.yaml b/Documentation/devicetree/bindings/mtd/mtd-physmap.yaml index 44cd4476d1d3..f8c976898a95 100644 --- a/Documentation/devicetree/bindings/mtd/mtd-physmap.yaml +++ b/Documentation/devicetree/bindings/mtd/mtd-physmap.yaml @@ -14,7 +14,7 @@ description: | file systems on embedded devices. allOf: - - $ref: "mtd.yaml#" + - $ref: mtd.yaml# - $ref: /schemas/memory-controllers/mc-peripheral-props.yaml# properties: diff --git a/Documentation/devicetree/bindings/mtd/mxc-nand.yaml b/Documentation/devicetree/bindings/mtd/mxc-nand.yaml index 7f6f7c9596c4..cf4198e43d7f 100644 --- a/Documentation/devicetree/bindings/mtd/mxc-nand.yaml +++ b/Documentation/devicetree/bindings/mtd/mxc-nand.yaml @@ -10,7 +10,7 @@ maintainers: - Uwe Kleine-König allOf: - - $ref: "nand-controller.yaml" + - $ref: nand-controller.yaml properties: compatible: diff --git a/Documentation/devicetree/bindings/mtd/nand-chip.yaml b/Documentation/devicetree/bindings/mtd/nand-chip.yaml index 33d079f76c05..609d4a4ddd80 100644 --- a/Documentation/devicetree/bindings/mtd/nand-chip.yaml +++ b/Documentation/devicetree/bindings/mtd/nand-chip.yaml @@ -10,7 +10,7 @@ maintainers: - Miquel Raynal allOf: - - $ref: "mtd.yaml#" + - $ref: mtd.yaml# description: | This file covers the generic description of a NAND chip. It implies that the diff --git a/Documentation/devicetree/bindings/mtd/nand-controller.yaml b/Documentation/devicetree/bindings/mtd/nand-controller.yaml index efcd415f8641..f70a32d2d9d4 100644 --- a/Documentation/devicetree/bindings/mtd/nand-controller.yaml +++ b/Documentation/devicetree/bindings/mtd/nand-controller.yaml @@ -51,7 +51,7 @@ properties: patternProperties: "^nand@[a-f0-9]$": - $ref: "nand-chip.yaml#" + $ref: nand-chip.yaml# properties: reg: diff --git a/Documentation/devicetree/bindings/mtd/partitions/brcm,bcm4908-partitions.yaml b/Documentation/devicetree/bindings/mtd/partitions/brcm,bcm4908-partitions.yaml index 5bbb1c01ddee..94f0742b375c 100644 --- a/Documentation/devicetree/bindings/mtd/partitions/brcm,bcm4908-partitions.yaml +++ b/Documentation/devicetree/bindings/mtd/partitions/brcm,bcm4908-partitions.yaml @@ -31,7 +31,7 @@ properties: patternProperties: "^partition@[0-9a-f]+$": - $ref: "partition.yaml#" + $ref: partition.yaml# properties: compatible: const: brcm,bcm4908-firmware diff --git a/Documentation/devicetree/bindings/mtd/partitions/linksys,ns-partitions.yaml b/Documentation/devicetree/bindings/mtd/partitions/linksys,ns-partitions.yaml index 213858f60375..c5fa78ff7125 100644 --- a/Documentation/devicetree/bindings/mtd/partitions/linksys,ns-partitions.yaml +++ b/Documentation/devicetree/bindings/mtd/partitions/linksys,ns-partitions.yaml @@ -32,7 +32,7 @@ properties: patternProperties: "^partition@[0-9a-f]+$": - $ref: "partition.yaml#" + $ref: partition.yaml# properties: compatible: items: diff --git a/Documentation/devicetree/bindings/mtd/qcom,nandc.yaml b/Documentation/devicetree/bindings/mtd/qcom,nandc.yaml index 07024ee45951..00c991ffa6c4 100644 --- a/Documentation/devicetree/bindings/mtd/qcom,nandc.yaml +++ b/Documentation/devicetree/bindings/mtd/qcom,nandc.yaml @@ -46,7 +46,7 @@ patternProperties: - 512 allOf: - - $ref: "nand-controller.yaml#" + - $ref: nand-controller.yaml# - if: properties: diff --git a/Documentation/devicetree/bindings/mtd/renesas-nandc.yaml b/Documentation/devicetree/bindings/mtd/renesas-nandc.yaml index f0dc78bb0515..cc6b8274e6a2 100644 --- a/Documentation/devicetree/bindings/mtd/renesas-nandc.yaml +++ b/Documentation/devicetree/bindings/mtd/renesas-nandc.yaml @@ -10,7 +10,7 @@ maintainers: - Miquel Raynal allOf: - - $ref: "nand-controller.yaml" + - $ref: nand-controller.yaml properties: compatible: diff --git a/Documentation/devicetree/bindings/mtd/rockchip,nand-controller.yaml b/Documentation/devicetree/bindings/mtd/rockchip,nand-controller.yaml index 566f330851f7..7eb1d0a38565 100644 --- a/Documentation/devicetree/bindings/mtd/rockchip,nand-controller.yaml +++ b/Documentation/devicetree/bindings/mtd/rockchip,nand-controller.yaml @@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml# title: Rockchip SoCs NAND FLASH Controller (NFC) allOf: - - $ref: "nand-controller.yaml#" + - $ref: nand-controller.yaml# maintainers: - Heiko Stuebner diff --git a/Documentation/devicetree/bindings/mtd/spi-nand.yaml b/Documentation/devicetree/bindings/mtd/spi-nand.yaml index 4d095e613204..77a8727c7966 100644 --- a/Documentation/devicetree/bindings/mtd/spi-nand.yaml +++ b/Documentation/devicetree/bindings/mtd/spi-nand.yaml @@ -10,7 +10,7 @@ maintainers: - Miquel Raynal allOf: - - $ref: "nand-chip.yaml#" + - $ref: nand-chip.yaml# - $ref: /schemas/spi/spi-peripheral-props.yaml# properties: diff --git a/Documentation/devicetree/bindings/mtd/st,stm32-fmc2-nand.yaml b/Documentation/devicetree/bindings/mtd/st,stm32-fmc2-nand.yaml index 19cf1f18b61c..986e85ccebc7 100644 --- a/Documentation/devicetree/bindings/mtd/st,stm32-fmc2-nand.yaml +++ b/Documentation/devicetree/bindings/mtd/st,stm32-fmc2-nand.yaml @@ -45,7 +45,7 @@ patternProperties: enum: [1, 4, 8] allOf: - - $ref: "nand-controller.yaml#" + - $ref: nand-controller.yaml# - if: properties: diff --git a/Documentation/devicetree/bindings/mtd/ti,gpmc-nand.yaml b/Documentation/devicetree/bindings/mtd/ti,gpmc-nand.yaml index 4ac198814b7a..115682fa81b7 100644 --- a/Documentation/devicetree/bindings/mtd/ti,gpmc-nand.yaml +++ b/Documentation/devicetree/bindings/mtd/ti,gpmc-nand.yaml @@ -63,10 +63,10 @@ properties: patternProperties: "@[0-9a-f]+$": - $ref: "/schemas/mtd/partitions/partition.yaml" + $ref: /schemas/mtd/partitions/partition.yaml allOf: - - $ref: "/schemas/memory-controllers/ti,gpmc-child.yaml" + - $ref: /schemas/memory-controllers/ti,gpmc-child.yaml required: - compatible diff --git a/Documentation/devicetree/bindings/mtd/ti,gpmc-onenand.yaml b/Documentation/devicetree/bindings/mtd/ti,gpmc-onenand.yaml index 8a79ad300216..7d3ace4f5505 100644 --- a/Documentation/devicetree/bindings/mtd/ti,gpmc-onenand.yaml +++ b/Documentation/devicetree/bindings/mtd/ti,gpmc-onenand.yaml @@ -36,10 +36,10 @@ properties: patternProperties: "@[0-9a-f]+$": - $ref: "/schemas/mtd/partitions/partition.yaml" + $ref: /schemas/mtd/partitions/partition.yaml allOf: - - $ref: "/schemas/memory-controllers/ti,gpmc-child.yaml" + - $ref: /schemas/memory-controllers/ti,gpmc-child.yaml required: - compatible -- cgit v1.2.3 From bb685c1f35c357e9b935880b2946b402d6860ee0 Mon Sep 17 00:00:00 2001 From: Christophe Kerello Date: Fri, 24 Mar 2023 16:51:05 +0100 Subject: mtd: rawnand: stm32_fmc2: depends on ARCH_STM32 instead of MACH_STM32MP157 To be able to compile the driver on all STM32MP SOCs, we move the "depends on" on ARCH_STM32. Signed-off-by: Christophe Kerello Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20230324155105.826063-3-christophe.kerello@foss.st.com --- drivers/mtd/nand/raw/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig index 170f1185ddc4..b523354dfb00 100644 --- a/drivers/mtd/nand/raw/Kconfig +++ b/drivers/mtd/nand/raw/Kconfig @@ -373,7 +373,7 @@ config MTD_NAND_TEGRA config MTD_NAND_STM32_FMC2 tristate "Support for NAND controller on STM32MP SoCs" - depends on MACH_STM32MP157 || COMPILE_TEST + depends on ARCH_STM32 || COMPILE_TEST select MFD_SYSCON help Enables support for NAND Flash chips on SoCs containing the FMC2 -- cgit v1.2.3 From e6026eb080fa1c1ef6eec24567b733809a5e3018 Mon Sep 17 00:00:00 2001 From: Tom Rix Date: Mon, 27 Mar 2023 20:06:20 -0400 Subject: mtd: lpddr_cmds: remove unused words variable clang with W=1 reports drivers/mtd/lpddr/lpddr_cmds.c:409:31: error: variable 'words' set but not used [-Werror,-Wunused-but-set-variable] int ret, wbufsize, word_gap, words; ^ This variable is not used so remove it. Signed-off-by: Tom Rix Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20230328000620.1778033-1-trix@redhat.com --- drivers/mtd/lpddr/lpddr_cmds.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/mtd/lpddr/lpddr_cmds.c b/drivers/mtd/lpddr/lpddr_cmds.c index ee063baed136..3c3939bc2dad 100644 --- a/drivers/mtd/lpddr/lpddr_cmds.c +++ b/drivers/mtd/lpddr/lpddr_cmds.c @@ -406,7 +406,7 @@ static int do_write_buffer(struct map_info *map, struct flchip *chip, { struct lpddr_private *lpddr = map->fldrv_priv; map_word datum; - int ret, wbufsize, word_gap, words; + int ret, wbufsize, word_gap; const struct kvec *vec; unsigned long vec_seek; unsigned long prog_buf_ofs; @@ -421,10 +421,7 @@ static int do_write_buffer(struct map_info *map, struct flchip *chip, } /* Figure out the number of words to write */ word_gap = (-adr & (map_bankwidth(map)-1)); - words = (len - word_gap + map_bankwidth(map) - 1) / map_bankwidth(map); - if (!word_gap) { - words--; - } else { + if (word_gap) { word_gap = map_bankwidth(map) - word_gap; adr -= word_gap; datum = map_word_ff(map); -- cgit v1.2.3 From 9d6c5d64f0288a814d4435b7da39e360a4c39e40 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Tue, 28 Mar 2023 17:40:58 +0200 Subject: mtd: spi-nor: Introduce the concept of bank SPI NOR chips are made of pages, which gathered in small groups make (erase) sectors. Sectors, gathered together, make banks inside the chip. Until now, there was only one bank per device supported, but we are about to introduce support for new chips featuring several banks (up to 4 so far) where different operations may happen in parallel. Let's allow describing these additional bank parameters, and let's do this independently of any other value (like the number of sectors) with an absolute value. By default we consider that all chips have a single bank. Signed-off-by: Miquel Raynal Reviewed-by: Pratyush Yadav Link: https://lore.kernel.org/r/20230328154105.448540-2-miquel.raynal@bootlin.com Signed-off-by: Tudor Ambarus --- drivers/mtd/spi-nor/core.c | 1 + drivers/mtd/spi-nor/core.h | 16 +++++++++++----- drivers/mtd/spi-nor/xilinx.c | 1 + 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c index 0a78045ca1d9..7d9ca799f767 100644 --- a/drivers/mtd/spi-nor/core.c +++ b/drivers/mtd/spi-nor/core.c @@ -2583,6 +2583,7 @@ static void spi_nor_init_default_params(struct spi_nor *nor) /* Set SPI NOR sizes. */ params->writesize = 1; params->size = (u64)info->sector_size * info->n_sectors; + params->bank_size = div64_u64(params->size, info->n_banks); params->page_size = info->page_size; if (!(info->flags & SPI_NOR_NO_FR)) { diff --git a/drivers/mtd/spi-nor/core.h b/drivers/mtd/spi-nor/core.h index 25423225c29d..db0e458810c7 100644 --- a/drivers/mtd/spi-nor/core.h +++ b/drivers/mtd/spi-nor/core.h @@ -336,7 +336,8 @@ struct spi_nor_otp { * by the spi_nor_fixups hooks, or dynamically when parsing the JESD216 * Serial Flash Discoverable Parameters (SFDP) tables. * - * @size: the flash memory density in bytes. + * @bank_size: the flash memory bank density in bytes. + * @size: the total flash memory density in bytes. * @writesize Minimal writable flash unit size. Defaults to 1. Set to * ECC unit size for ECC-ed flashes. * @page_size: the page size of the SPI NOR flash memory. @@ -374,6 +375,7 @@ struct spi_nor_otp { * @locking_ops: SPI NOR locking methods. */ struct spi_nor_flash_parameter { + u64 bank_size; u64 size; u32 writesize; u32 page_size; @@ -435,6 +437,7 @@ struct spi_nor_fixups { * @sector_size: the size listed here is what works with SPINOR_OP_SE, which * isn't necessarily called a "sector" by the vendor. * @n_sectors: the number of sectors. + * @n_banks: the number of banks. * @page_size: the flash's page size. * @addr_nbytes: number of address bytes to send. * @@ -495,6 +498,7 @@ struct flash_info { unsigned sector_size; u16 n_sectors; u16 page_size; + u8 n_banks; u8 addr_nbytes; bool parse_sfdp; @@ -540,24 +544,26 @@ struct flash_info { .id = { SPI_NOR_ID_3ITEMS(_jedec_id), SPI_NOR_ID_3ITEMS(_ext_id) }, \ .id_len = 6 -#define SPI_NOR_GEOMETRY(_sector_size, _n_sectors) \ +#define SPI_NOR_GEOMETRY(_sector_size, _n_sectors, _n_banks) \ .sector_size = (_sector_size), \ .n_sectors = (_n_sectors), \ - .page_size = 256 + .page_size = 256, \ + .n_banks = (_n_banks) /* Used when the "_ext_id" is two bytes at most */ #define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors) \ SPI_NOR_ID((_jedec_id), (_ext_id)), \ - SPI_NOR_GEOMETRY((_sector_size), (_n_sectors)), + SPI_NOR_GEOMETRY((_sector_size), (_n_sectors), 1), #define INFO6(_jedec_id, _ext_id, _sector_size, _n_sectors) \ SPI_NOR_ID6((_jedec_id), (_ext_id)), \ - SPI_NOR_GEOMETRY((_sector_size), (_n_sectors)), + SPI_NOR_GEOMETRY((_sector_size), (_n_sectors), 1), #define CAT25_INFO(_sector_size, _n_sectors, _page_size, _addr_nbytes) \ .sector_size = (_sector_size), \ .n_sectors = (_n_sectors), \ .page_size = (_page_size), \ + .n_banks = 1, \ .addr_nbytes = (_addr_nbytes), \ .flags = SPI_NOR_NO_ERASE | SPI_NOR_NO_FR, \ diff --git a/drivers/mtd/spi-nor/xilinx.c b/drivers/mtd/spi-nor/xilinx.c index 5723157739fc..7175de8aa336 100644 --- a/drivers/mtd/spi-nor/xilinx.c +++ b/drivers/mtd/spi-nor/xilinx.c @@ -31,6 +31,7 @@ .sector_size = (8 * (_page_size)), \ .n_sectors = (_n_sectors), \ .page_size = (_page_size), \ + .n_banks = 1, \ .addr_nbytes = 3, \ .flags = SPI_NOR_NO_FR -- cgit v1.2.3 From ccff2cfa1ac347ee91f1b21ee99ca7ecc1d201fc Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Tue, 28 Mar 2023 17:40:59 +0200 Subject: mtd: spi-nor: Add a macro to define more banks Most of the chips on the market only feature a single bank. However, new chips may support more than a single bank, with the possibility to parallelize some operations. Let's introduce an INFOB() macro which also takes a n_bank parameter. Signed-off-by: Miquel Raynal Reviewed-by: Pratyush Yadav Link: https://lore.kernel.org/r/20230328154105.448540-3-miquel.raynal@bootlin.com Signed-off-by: Tudor Ambarus --- drivers/mtd/spi-nor/core.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/mtd/spi-nor/core.h b/drivers/mtd/spi-nor/core.h index db0e458810c7..bf2e64671856 100644 --- a/drivers/mtd/spi-nor/core.h +++ b/drivers/mtd/spi-nor/core.h @@ -555,6 +555,10 @@ struct flash_info { SPI_NOR_ID((_jedec_id), (_ext_id)), \ SPI_NOR_GEOMETRY((_sector_size), (_n_sectors), 1), +#define INFOB(_jedec_id, _ext_id, _sector_size, _n_sectors, _n_banks) \ + SPI_NOR_ID((_jedec_id), (_ext_id)), \ + SPI_NOR_GEOMETRY((_sector_size), (_n_sectors), (_n_banks)), + #define INFO6(_jedec_id, _ext_id, _sector_size, _n_sectors) \ SPI_NOR_ID6((_jedec_id), (_ext_id)), \ SPI_NOR_GEOMETRY((_sector_size), (_n_sectors), 1), -- cgit v1.2.3 From 3204634772353ba965ac1f2effa948e32044efbc Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Tue, 28 Mar 2023 17:41:00 +0200 Subject: mtd: spi-nor: Reorder the preparation vs. locking steps The ->prepare()/->unprepare() hooks are now legacy, we no longer accept new drivers supporting them. The only remaining controllers using them acquires a per-chip mutex, which should not interfere with the rest of the operation done in the core. As a result, we should be safe to reorganize these helpers to first perform the preparation, before acquiring the core locks. This is necessary in order to be able to improve the locking mechanism in the core (coming next). No side effects are expected. Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/r/20230328154105.448540-4-miquel.raynal@bootlin.com Signed-off-by: Tudor Ambarus --- drivers/mtd/spi-nor/core.c | 21 +++++++++------------ drivers/mtd/spi-nor/core.h | 2 +- drivers/mtd/spi-nor/otp.c | 8 ++++---- drivers/mtd/spi-nor/sst.c | 2 +- drivers/mtd/spi-nor/swp.c | 6 +++--- 5 files changed, 18 insertions(+), 21 deletions(-) diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c index 7d9ca799f767..3a7a407919e7 100644 --- a/drivers/mtd/spi-nor/core.c +++ b/drivers/mtd/spi-nor/core.c @@ -1070,27 +1070,24 @@ static void spi_nor_set_4byte_opcodes(struct spi_nor *nor) } } -int spi_nor_lock_and_prep(struct spi_nor *nor) +int spi_nor_prep_and_lock(struct spi_nor *nor) { int ret = 0; + if (nor->controller_ops && nor->controller_ops->prepare) + ret = nor->controller_ops->prepare(nor); + mutex_lock(&nor->lock); - if (nor->controller_ops && nor->controller_ops->prepare) { - ret = nor->controller_ops->prepare(nor); - if (ret) { - mutex_unlock(&nor->lock); - return ret; - } - } return ret; } void spi_nor_unlock_and_unprep(struct spi_nor *nor) { + mutex_unlock(&nor->lock); + if (nor->controller_ops && nor->controller_ops->unprepare) nor->controller_ops->unprepare(nor); - mutex_unlock(&nor->lock); } static u32 spi_nor_convert_addr(struct spi_nor *nor, loff_t addr) @@ -1446,7 +1443,7 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr) addr = instr->addr; len = instr->len; - ret = spi_nor_lock_and_prep(nor); + ret = spi_nor_prep_and_lock(nor); if (ret) return ret; @@ -1706,7 +1703,7 @@ static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len, dev_dbg(nor->dev, "from 0x%08x, len %zd\n", (u32)from, len); - ret = spi_nor_lock_and_prep(nor); + ret = spi_nor_prep_and_lock(nor); if (ret) return ret; @@ -1752,7 +1749,7 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len, dev_dbg(nor->dev, "to 0x%08x, len %zd\n", (u32)to, len); - ret = spi_nor_lock_and_prep(nor); + ret = spi_nor_prep_and_lock(nor); if (ret) return ret; diff --git a/drivers/mtd/spi-nor/core.h b/drivers/mtd/spi-nor/core.h index bf2e64671856..c4c78729ccea 100644 --- a/drivers/mtd/spi-nor/core.h +++ b/drivers/mtd/spi-nor/core.h @@ -647,7 +647,7 @@ int spi_nor_write_disable(struct spi_nor *nor); int spi_nor_set_4byte_addr_mode(struct spi_nor *nor, bool enable); int spi_nor_wait_till_ready(struct spi_nor *nor); int spi_nor_global_block_unlock(struct spi_nor *nor); -int spi_nor_lock_and_prep(struct spi_nor *nor); +int spi_nor_prep_and_lock(struct spi_nor *nor); void spi_nor_unlock_and_unprep(struct spi_nor *nor); int spi_nor_sr1_bit6_quad_enable(struct spi_nor *nor); int spi_nor_sr2_bit1_quad_enable(struct spi_nor *nor); diff --git a/drivers/mtd/spi-nor/otp.c b/drivers/mtd/spi-nor/otp.c index 00ab0d2d6d2f..9a729aa3452d 100644 --- a/drivers/mtd/spi-nor/otp.c +++ b/drivers/mtd/spi-nor/otp.c @@ -255,7 +255,7 @@ static int spi_nor_mtd_otp_info(struct mtd_info *mtd, size_t len, if (len < n_regions * sizeof(*buf)) return -ENOSPC; - ret = spi_nor_lock_and_prep(nor); + ret = spi_nor_prep_and_lock(nor); if (ret) return ret; @@ -325,7 +325,7 @@ static int spi_nor_mtd_otp_read_write(struct mtd_info *mtd, loff_t ofs, if (!total_len) return 0; - ret = spi_nor_lock_and_prep(nor); + ret = spi_nor_prep_and_lock(nor); if (ret) return ret; @@ -415,7 +415,7 @@ static int spi_nor_mtd_otp_erase(struct mtd_info *mtd, loff_t from, size_t len) if (!IS_ALIGNED(len, rlen) || !IS_ALIGNED(from, rlen)) return -EINVAL; - ret = spi_nor_lock_and_prep(nor); + ret = spi_nor_prep_and_lock(nor); if (ret) return ret; @@ -460,7 +460,7 @@ static int spi_nor_mtd_otp_lock(struct mtd_info *mtd, loff_t from, size_t len) if (!IS_ALIGNED(len, rlen) || !IS_ALIGNED(from, rlen)) return -EINVAL; - ret = spi_nor_lock_and_prep(nor); + ret = spi_nor_prep_and_lock(nor); if (ret) return ret; diff --git a/drivers/mtd/spi-nor/sst.c b/drivers/mtd/spi-nor/sst.c index 63bcc97bf978..688eb20c763e 100644 --- a/drivers/mtd/spi-nor/sst.c +++ b/drivers/mtd/spi-nor/sst.c @@ -126,7 +126,7 @@ static int sst_nor_write(struct mtd_info *mtd, loff_t to, size_t len, dev_dbg(nor->dev, "to 0x%08x, len %zd\n", (u32)to, len); - ret = spi_nor_lock_and_prep(nor); + ret = spi_nor_prep_and_lock(nor); if (ret) return ret; diff --git a/drivers/mtd/spi-nor/swp.c b/drivers/mtd/spi-nor/swp.c index 1f178313ba8f..0ba716e84377 100644 --- a/drivers/mtd/spi-nor/swp.c +++ b/drivers/mtd/spi-nor/swp.c @@ -348,7 +348,7 @@ static int spi_nor_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) struct spi_nor *nor = mtd_to_spi_nor(mtd); int ret; - ret = spi_nor_lock_and_prep(nor); + ret = spi_nor_prep_and_lock(nor); if (ret) return ret; @@ -363,7 +363,7 @@ static int spi_nor_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) struct spi_nor *nor = mtd_to_spi_nor(mtd); int ret; - ret = spi_nor_lock_and_prep(nor); + ret = spi_nor_prep_and_lock(nor); if (ret) return ret; @@ -378,7 +378,7 @@ static int spi_nor_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len) struct spi_nor *nor = mtd_to_spi_nor(mtd); int ret; - ret = spi_nor_lock_and_prep(nor); + ret = spi_nor_prep_and_lock(nor); if (ret) return ret; -- cgit v1.2.3 From c154dbd28003d8fcc857d88596b2f0383617d1e7 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Tue, 28 Mar 2023 17:41:01 +0200 Subject: mtd: spi-nor: Separate preparation and locking While this operation will remain a single function call in the end, let's extract the logic of the [un]prepare calls within their own static helper. We will soon add new flavors of the *_[un]prepare_and_[un]lock() helpers, having the preparation logic outside will save us from duplicating code over and over again. There is no functional change. Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/r/20230328154105.448540-5-miquel.raynal@bootlin.com Signed-off-by: Tudor Ambarus --- drivers/mtd/spi-nor/core.c | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c index 3a7a407919e7..e80677d36a8c 100644 --- a/drivers/mtd/spi-nor/core.c +++ b/drivers/mtd/spi-nor/core.c @@ -1070,24 +1070,40 @@ static void spi_nor_set_4byte_opcodes(struct spi_nor *nor) } } -int spi_nor_prep_and_lock(struct spi_nor *nor) +static int spi_nor_prep(struct spi_nor *nor) { int ret = 0; if (nor->controller_ops && nor->controller_ops->prepare) ret = nor->controller_ops->prepare(nor); + return ret; +} + +static void spi_nor_unprep(struct spi_nor *nor) +{ + if (nor->controller_ops && nor->controller_ops->unprepare) + nor->controller_ops->unprepare(nor); +} + +int spi_nor_prep_and_lock(struct spi_nor *nor) +{ + int ret; + + ret = spi_nor_prep(nor); + if (ret) + return ret; + mutex_lock(&nor->lock); - return ret; + return 0; } void spi_nor_unlock_and_unprep(struct spi_nor *nor) { mutex_unlock(&nor->lock); - if (nor->controller_ops && nor->controller_ops->unprepare) - nor->controller_ops->unprepare(nor); + spi_nor_unprep(nor); } static u32 spi_nor_convert_addr(struct spi_nor *nor, loff_t addr) -- cgit v1.2.3 From e96d4605b024495d42279ae8e899969b29f7ce5f Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Tue, 28 Mar 2023 17:41:02 +0200 Subject: mtd: spi-nor: Prepare the introduction of a new locking mechanism This commit alone just introduces two new "prepare and lock" pairs of helpers which do the exact same thing as before. They will soon be improved in a followup commit which actually brings the logic, but I figured out it was more readable to do it this way. One new pair is suffixed _pe which stands for "program and erase" and hence is being called by spi_nor_write() and spi_nor_erase(). The other pair is suffixed _rd which stands for "read" and hence is being called by spi_nor_read(). One note however, these extra helpers will need to know the operation range, so they come with two new parameters to define it. Otherwise there is no functional change. Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/r/20230328154105.448540-6-miquel.raynal@bootlin.com Signed-off-by: Tudor Ambarus --- drivers/mtd/spi-nor/core.c | 59 +++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 53 insertions(+), 6 deletions(-) diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c index e80677d36a8c..daed09950ee1 100644 --- a/drivers/mtd/spi-nor/core.c +++ b/drivers/mtd/spi-nor/core.c @@ -1086,6 +1086,7 @@ static void spi_nor_unprep(struct spi_nor *nor) nor->controller_ops->unprepare(nor); } +/* Generic helpers for internal locking and serialization */ int spi_nor_prep_and_lock(struct spi_nor *nor) { int ret; @@ -1106,6 +1107,48 @@ void spi_nor_unlock_and_unprep(struct spi_nor *nor) spi_nor_unprep(nor); } +/* Internal locking helpers for program and erase operations */ +static int spi_nor_prep_and_lock_pe(struct spi_nor *nor, loff_t start, size_t len) +{ + int ret; + + ret = spi_nor_prep(nor); + if (ret) + return ret; + + mutex_lock(&nor->lock); + + return 0; +} + +static void spi_nor_unlock_and_unprep_pe(struct spi_nor *nor, loff_t start, size_t len) +{ + mutex_unlock(&nor->lock); + + spi_nor_unprep(nor); +} + +/* Internal locking helpers for read operations */ +static int spi_nor_prep_and_lock_rd(struct spi_nor *nor, loff_t start, size_t len) +{ + int ret; + + ret = spi_nor_prep(nor); + if (ret) + return ret; + + mutex_lock(&nor->lock); + + return 0; +} + +static void spi_nor_unlock_and_unprep_rd(struct spi_nor *nor, loff_t start, size_t len) +{ + mutex_unlock(&nor->lock); + + spi_nor_unprep(nor); +} + static u32 spi_nor_convert_addr(struct spi_nor *nor, loff_t addr) { if (!nor->params->convert_addr) @@ -1459,7 +1502,7 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr) addr = instr->addr; len = instr->len; - ret = spi_nor_prep_and_lock(nor); + ret = spi_nor_prep_and_lock_pe(nor, instr->addr, instr->len); if (ret) return ret; @@ -1522,7 +1565,7 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr) ret = spi_nor_write_disable(nor); erase_err: - spi_nor_unlock_and_unprep(nor); + spi_nor_unlock_and_unprep_pe(nor, instr->addr, instr->len); return ret; } @@ -1715,11 +1758,13 @@ static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) { struct spi_nor *nor = mtd_to_spi_nor(mtd); + loff_t from_lock = from; + size_t len_lock = len; ssize_t ret; dev_dbg(nor->dev, "from 0x%08x, len %zd\n", (u32)from, len); - ret = spi_nor_prep_and_lock(nor); + ret = spi_nor_prep_and_lock_rd(nor, from_lock, len_lock); if (ret) return ret; @@ -1746,7 +1791,8 @@ static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len, ret = 0; read_err: - spi_nor_unlock_and_unprep(nor); + spi_nor_unlock_and_unprep_rd(nor, from_lock, len_lock); + return ret; } @@ -1765,7 +1811,7 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len, dev_dbg(nor->dev, "to 0x%08x, len %zd\n", (u32)to, len); - ret = spi_nor_prep_and_lock(nor); + ret = spi_nor_prep_and_lock_pe(nor, to, len); if (ret) return ret; @@ -1807,7 +1853,8 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len, } write_err: - spi_nor_unlock_and_unprep(nor); + spi_nor_unlock_and_unprep_pe(nor, to, len); + return ret; } -- cgit v1.2.3 From 4eddee70140b3ae183398b246a609756546c51f1 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Tue, 28 Mar 2023 17:41:03 +0200 Subject: mtd: spi-nor: Add a RWW flag Introduce a new (no SFDP) flag for the feature that we are about to support: Read While Write. This means, if the chip has several banks and supports RWW, once a page of data to write has been transferred into the chip's internal SRAM, another read operation happening on a different bank can be performed during the tPROG delay. Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/r/20230328154105.448540-7-miquel.raynal@bootlin.com Signed-off-by: Tudor Ambarus --- drivers/mtd/spi-nor/core.c | 3 +++ drivers/mtd/spi-nor/core.h | 3 +++ drivers/mtd/spi-nor/debugfs.c | 1 + 3 files changed, 7 insertions(+) diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c index daed09950ee1..75ec7a3d0b43 100644 --- a/drivers/mtd/spi-nor/core.c +++ b/drivers/mtd/spi-nor/core.c @@ -2530,6 +2530,9 @@ static void spi_nor_init_flags(struct spi_nor *nor) if (flags & NO_CHIP_ERASE) nor->flags |= SNOR_F_NO_OP_CHIP_ERASE; + + if (flags & SPI_NOR_RWW) + nor->flags |= SNOR_F_RWW; } /** diff --git a/drivers/mtd/spi-nor/core.h b/drivers/mtd/spi-nor/core.h index c4c78729ccea..de31e430f77e 100644 --- a/drivers/mtd/spi-nor/core.h +++ b/drivers/mtd/spi-nor/core.h @@ -130,6 +130,7 @@ enum spi_nor_option_flags { SNOR_F_IO_MODE_EN_VOLATILE = BIT(11), SNOR_F_SOFT_RESET = BIT(12), SNOR_F_SWP_IS_VOLATILE = BIT(13), + SNOR_F_RWW = BIT(14), }; struct spi_nor_read_command { @@ -462,6 +463,7 @@ struct spi_nor_fixups { * 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. + * SPI_NOR_RWW: flash supports reads while write. * * @no_sfdp_flags: flags that indicate support that can be discovered via SFDP. * Used when SFDP tables are not defined in the flash. These @@ -513,6 +515,7 @@ struct flash_info { #define NO_CHIP_ERASE BIT(7) #define SPI_NOR_NO_FR BIT(8) #define SPI_NOR_QUAD_PP BIT(9) +#define SPI_NOR_RWW BIT(10) u8 no_sfdp_flags; #define SPI_NOR_SKIP_SFDP BIT(0) diff --git a/drivers/mtd/spi-nor/debugfs.c b/drivers/mtd/spi-nor/debugfs.c index 845b78c7ecc7..e200f5b9234c 100644 --- a/drivers/mtd/spi-nor/debugfs.c +++ b/drivers/mtd/spi-nor/debugfs.c @@ -25,6 +25,7 @@ static const char *const snor_f_names[] = { SNOR_F_NAME(IO_MODE_EN_VOLATILE), SNOR_F_NAME(SOFT_RESET), SNOR_F_NAME(SWP_IS_VOLATILE), + SNOR_F_NAME(RWW), }; #undef SNOR_F_NAME -- cgit v1.2.3 From 74df43b3f626a3594a4de50556048852bf2753f7 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Tue, 28 Mar 2023 17:41:04 +0200 Subject: mtd: spi-nor: Enhance locking to support reads while writes On devices featuring several banks, the Read While Write (RWW) feature is here to improve the overall performance when performing parallel reads and writes at different locations (different banks). The following constraints have to be taken into account: 1#: A single operation can be performed in a given bank. 2#: Only a single program or erase operation can happen on the entire chip (common hardware limitation to limit costs) 3#: Reads must remain serialized even though reads crossing bank boundaries are allowed. 4#: The I/O bus is unique and thus is the most constrained resource, all spi-nor operations requiring access to the spi bus (through the spi controller) must be serialized until the bus exchanges are over. So we must ensure a single operation can be "sent" at a time. 5#: Any other operation that would not be either a read or a write or an erase is considered requiring access to the full chip and cannot be parallelized, we then need to ensure the full chip is in the idle state when this occurs. All these constraints can easily be managed with a proper locking model: 1#: Is enforced by a bitfield of the in-use banks, so that only a single operation can happen in a specific bank at any time. 2#: Is handled by the ongoing_pe boolean which is set before any write or erase, and is released only at the very end of the operation. This way, no other destructive operation on the chip can start during this time frame. 3#: An ongoing_rd boolean allows to track the ongoing reads, so that only one can be performed at a time. 4#: An ongoing_io boolean is introduced in order to capture and serialize bus accessed. This is the one being released "sooner" than before, because we only need to protect the chip against other SPI accesses during the I/O phase, which for the destructive operations is the beginning of the operation (when we send the command cycles and possibly the data), while the second part of the operation (the erase delay or the programmation delay) is when we can do something else in another bank. 5#: Is handled by the three booleans presented above, if any of them is set, the chip is not yet ready for the operation and must wait. All these internal variables are protected by the existing lock, so that changes in this structure are atomic. The serialization is handled with a wait queue. Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/r/20230328154105.448540-8-miquel.raynal@bootlin.com Signed-off-by: Tudor Ambarus --- drivers/mtd/spi-nor/core.c | 337 +++++++++++++++++++++++++++++++++++++++++--- include/linux/mtd/spi-nor.h | 13 ++ 2 files changed, 334 insertions(+), 16 deletions(-) diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c index 75ec7a3d0b43..9e6a0730cdb8 100644 --- a/drivers/mtd/spi-nor/core.c +++ b/drivers/mtd/spi-nor/core.c @@ -588,6 +588,65 @@ int spi_nor_sr_ready(struct spi_nor *nor) return !(nor->bouncebuf[0] & SR_WIP); } +/** + * spi_nor_use_parallel_locking() - Checks if RWW locking scheme shall be used + * @nor: pointer to 'struct spi_nor'. + * + * Return: true if parallel locking is enabled, false otherwise. + */ +static bool spi_nor_use_parallel_locking(struct spi_nor *nor) +{ + return nor->flags & SNOR_F_RWW; +} + +/* Locking helpers for status read operations */ +static int spi_nor_rww_start_rdst(struct spi_nor *nor) +{ + struct spi_nor_rww *rww = &nor->rww; + int ret = -EAGAIN; + + mutex_lock(&nor->lock); + + if (rww->ongoing_io || rww->ongoing_rd) + goto busy; + + rww->ongoing_io = true; + rww->ongoing_rd = true; + ret = 0; + +busy: + mutex_unlock(&nor->lock); + return ret; +} + +static void spi_nor_rww_end_rdst(struct spi_nor *nor) +{ + struct spi_nor_rww *rww = &nor->rww; + + mutex_lock(&nor->lock); + + rww->ongoing_io = false; + rww->ongoing_rd = false; + + mutex_unlock(&nor->lock); +} + +static int spi_nor_lock_rdst(struct spi_nor *nor) +{ + if (spi_nor_use_parallel_locking(nor)) + return spi_nor_rww_start_rdst(nor); + + return 0; +} + +static void spi_nor_unlock_rdst(struct spi_nor *nor) +{ + if (spi_nor_use_parallel_locking(nor)) { + spi_nor_rww_end_rdst(nor); + wake_up(&nor->rww.wait); + } +} + /** * spi_nor_ready() - Query the flash to see if it is ready for new commands. * @nor: pointer to 'struct spi_nor'. @@ -596,11 +655,21 @@ int spi_nor_sr_ready(struct spi_nor *nor) */ static int spi_nor_ready(struct spi_nor *nor) { + int ret; + + ret = spi_nor_lock_rdst(nor); + if (ret) + return 0; + /* Flashes might override the standard routine. */ if (nor->params->ready) - return nor->params->ready(nor); + ret = nor->params->ready(nor); + else + ret = spi_nor_sr_ready(nor); - return spi_nor_sr_ready(nor); + spi_nor_unlock_rdst(nor); + + return ret; } /** @@ -1086,7 +1155,88 @@ static void spi_nor_unprep(struct spi_nor *nor) nor->controller_ops->unprepare(nor); } +static void spi_nor_offset_to_banks(u64 bank_size, loff_t start, size_t len, + u8 *first, u8 *last) +{ + /* This is currently safe, the number of banks being very small */ + *first = DIV_ROUND_DOWN_ULL(start, bank_size); + *last = DIV_ROUND_DOWN_ULL(start + len - 1, bank_size); +} + /* Generic helpers for internal locking and serialization */ +static bool spi_nor_rww_start_io(struct spi_nor *nor) +{ + struct spi_nor_rww *rww = &nor->rww; + bool start = false; + + mutex_lock(&nor->lock); + + if (rww->ongoing_io) + goto busy; + + rww->ongoing_io = true; + start = true; + +busy: + mutex_unlock(&nor->lock); + return start; +} + +static void spi_nor_rww_end_io(struct spi_nor *nor) +{ + mutex_lock(&nor->lock); + nor->rww.ongoing_io = false; + mutex_unlock(&nor->lock); +} + +static int spi_nor_lock_device(struct spi_nor *nor) +{ + if (!spi_nor_use_parallel_locking(nor)) + return 0; + + return wait_event_killable(nor->rww.wait, spi_nor_rww_start_io(nor)); +} + +static void spi_nor_unlock_device(struct spi_nor *nor) +{ + if (spi_nor_use_parallel_locking(nor)) { + spi_nor_rww_end_io(nor); + wake_up(&nor->rww.wait); + } +} + +/* Generic helpers for internal locking and serialization */ +static bool spi_nor_rww_start_exclusive(struct spi_nor *nor) +{ + struct spi_nor_rww *rww = &nor->rww; + bool start = false; + + mutex_lock(&nor->lock); + + if (rww->ongoing_io || rww->ongoing_rd || rww->ongoing_pe) + goto busy; + + rww->ongoing_io = true; + rww->ongoing_rd = true; + rww->ongoing_pe = true; + start = true; + +busy: + mutex_unlock(&nor->lock); + return start; +} + +static void spi_nor_rww_end_exclusive(struct spi_nor *nor) +{ + struct spi_nor_rww *rww = &nor->rww; + + mutex_lock(&nor->lock); + rww->ongoing_io = false; + rww->ongoing_rd = false; + rww->ongoing_pe = false; + mutex_unlock(&nor->lock); +} + int spi_nor_prep_and_lock(struct spi_nor *nor) { int ret; @@ -1095,19 +1245,75 @@ int spi_nor_prep_and_lock(struct spi_nor *nor) if (ret) return ret; - mutex_lock(&nor->lock); + if (!spi_nor_use_parallel_locking(nor)) + mutex_lock(&nor->lock); + else + ret = wait_event_killable(nor->rww.wait, + spi_nor_rww_start_exclusive(nor)); - return 0; + return ret; } void spi_nor_unlock_and_unprep(struct spi_nor *nor) { - mutex_unlock(&nor->lock); + if (!spi_nor_use_parallel_locking(nor)) { + mutex_unlock(&nor->lock); + } else { + spi_nor_rww_end_exclusive(nor); + wake_up(&nor->rww.wait); + } spi_nor_unprep(nor); } /* Internal locking helpers for program and erase operations */ +static bool spi_nor_rww_start_pe(struct spi_nor *nor, loff_t start, size_t len) +{ + struct spi_nor_rww *rww = &nor->rww; + unsigned int used_banks = 0; + bool started = false; + u8 first, last; + int bank; + + mutex_lock(&nor->lock); + + if (rww->ongoing_io || rww->ongoing_rd || rww->ongoing_pe) + goto busy; + + spi_nor_offset_to_banks(nor->params->bank_size, start, len, &first, &last); + for (bank = first; bank <= last; bank++) { + if (rww->used_banks & BIT(bank)) + goto busy; + + used_banks |= BIT(bank); + } + + rww->used_banks |= used_banks; + rww->ongoing_pe = true; + started = true; + +busy: + mutex_unlock(&nor->lock); + return started; +} + +static void spi_nor_rww_end_pe(struct spi_nor *nor, loff_t start, size_t len) +{ + struct spi_nor_rww *rww = &nor->rww; + u8 first, last; + int bank; + + mutex_lock(&nor->lock); + + spi_nor_offset_to_banks(nor->params->bank_size, start, len, &first, &last); + for (bank = first; bank <= last; bank++) + rww->used_banks &= ~BIT(bank); + + rww->ongoing_pe = false; + + mutex_unlock(&nor->lock); +} + static int spi_nor_prep_and_lock_pe(struct spi_nor *nor, loff_t start, size_t len) { int ret; @@ -1116,19 +1322,77 @@ static int spi_nor_prep_and_lock_pe(struct spi_nor *nor, loff_t start, size_t le if (ret) return ret; - mutex_lock(&nor->lock); + if (!spi_nor_use_parallel_locking(nor)) + mutex_lock(&nor->lock); + else + ret = wait_event_killable(nor->rww.wait, + spi_nor_rww_start_pe(nor, start, len)); - return 0; + return ret; } static void spi_nor_unlock_and_unprep_pe(struct spi_nor *nor, loff_t start, size_t len) { - mutex_unlock(&nor->lock); + if (!spi_nor_use_parallel_locking(nor)) { + mutex_unlock(&nor->lock); + } else { + spi_nor_rww_end_pe(nor, start, len); + wake_up(&nor->rww.wait); + } spi_nor_unprep(nor); } /* Internal locking helpers for read operations */ +static bool spi_nor_rww_start_rd(struct spi_nor *nor, loff_t start, size_t len) +{ + struct spi_nor_rww *rww = &nor->rww; + unsigned int used_banks = 0; + bool started = false; + u8 first, last; + int bank; + + mutex_lock(&nor->lock); + + if (rww->ongoing_io || rww->ongoing_rd) + goto busy; + + spi_nor_offset_to_banks(nor->params->bank_size, start, len, &first, &last); + for (bank = first; bank <= last; bank++) { + if (rww->used_banks & BIT(bank)) + goto busy; + + used_banks |= BIT(bank); + } + + rww->used_banks |= used_banks; + rww->ongoing_io = true; + rww->ongoing_rd = true; + started = true; + +busy: + mutex_unlock(&nor->lock); + return started; +} + +static void spi_nor_rww_end_rd(struct spi_nor *nor, loff_t start, size_t len) +{ + struct spi_nor_rww *rww = &nor->rww; + u8 first, last; + int bank; + + mutex_lock(&nor->lock); + + spi_nor_offset_to_banks(nor->params->bank_size, start, len, &first, &last); + for (bank = first; bank <= last; bank++) + nor->rww.used_banks &= ~BIT(bank); + + rww->ongoing_io = false; + rww->ongoing_rd = false; + + mutex_unlock(&nor->lock); +} + static int spi_nor_prep_and_lock_rd(struct spi_nor *nor, loff_t start, size_t len) { int ret; @@ -1137,14 +1401,23 @@ static int spi_nor_prep_and_lock_rd(struct spi_nor *nor, loff_t start, size_t le if (ret) return ret; - mutex_lock(&nor->lock); + if (!spi_nor_use_parallel_locking(nor)) + mutex_lock(&nor->lock); + else + ret = wait_event_killable(nor->rww.wait, + spi_nor_rww_start_rd(nor, start, len)); - return 0; + return ret; } static void spi_nor_unlock_and_unprep_rd(struct spi_nor *nor, loff_t start, size_t len) { - mutex_unlock(&nor->lock); + if (!spi_nor_use_parallel_locking(nor)) { + mutex_unlock(&nor->lock); + } else { + spi_nor_rww_end_rd(nor, start, len); + wake_up(&nor->rww.wait); + } spi_nor_unprep(nor); } @@ -1453,11 +1726,18 @@ static int spi_nor_erase_multi_sectors(struct spi_nor *nor, u64 addr, u32 len) dev_vdbg(nor->dev, "erase_cmd->size = 0x%08x, erase_cmd->opcode = 0x%02x, erase_cmd->count = %u\n", cmd->size, cmd->opcode, cmd->count); - ret = spi_nor_write_enable(nor); + ret = spi_nor_lock_device(nor); if (ret) goto destroy_erase_cmd_list; + ret = spi_nor_write_enable(nor); + if (ret) { + spi_nor_unlock_device(nor); + goto destroy_erase_cmd_list; + } + ret = spi_nor_erase_sector(nor, addr); + spi_nor_unlock_device(nor); if (ret) goto destroy_erase_cmd_list; @@ -1510,11 +1790,18 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr) if (len == mtd->size && !(nor->flags & SNOR_F_NO_OP_CHIP_ERASE)) { unsigned long timeout; - ret = spi_nor_write_enable(nor); + ret = spi_nor_lock_device(nor); if (ret) goto erase_err; + ret = spi_nor_write_enable(nor); + if (ret) { + spi_nor_unlock_device(nor); + goto erase_err; + } + ret = spi_nor_erase_chip(nor); + spi_nor_unlock_device(nor); if (ret) goto erase_err; @@ -1539,11 +1826,18 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr) /* "sector"-at-a-time erase */ } else if (spi_nor_has_uniform_erase(nor)) { while (len) { - ret = spi_nor_write_enable(nor); + ret = spi_nor_lock_device(nor); if (ret) goto erase_err; + ret = spi_nor_write_enable(nor); + if (ret) { + spi_nor_unlock_device(nor); + goto erase_err; + } + ret = spi_nor_erase_sector(nor, addr); + spi_nor_unlock_device(nor); if (ret) goto erase_err; @@ -1836,11 +2130,18 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len, addr = spi_nor_convert_addr(nor, addr); - ret = spi_nor_write_enable(nor); + ret = spi_nor_lock_device(nor); if (ret) goto write_err; + ret = spi_nor_write_enable(nor); + if (ret) { + spi_nor_unlock_device(nor); + goto write_err; + } + ret = spi_nor_write_data(nor, addr, page_remain, buf + i); + spi_nor_unlock_device(nor); if (ret < 0) goto write_err; written = ret; @@ -2531,7 +2832,8 @@ static void spi_nor_init_flags(struct spi_nor *nor) if (flags & NO_CHIP_ERASE) nor->flags |= SNOR_F_NO_OP_CHIP_ERASE; - if (flags & SPI_NOR_RWW) + if (flags & SPI_NOR_RWW && nor->info->n_banks > 1 && + !nor->controller_ops) nor->flags |= SNOR_F_RWW; } @@ -3128,6 +3430,9 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, if (ret) return ret; + if (spi_nor_use_parallel_locking(nor)) + init_waitqueue_head(&nor->rww.wait); + /* * Configure the SPI memory: * - select op codes for (Fast) Read, Page Program and Sector Erase. diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h index a3f8cdca90c8..82547b4b3708 100644 --- a/include/linux/mtd/spi-nor.h +++ b/include/linux/mtd/spi-nor.h @@ -343,6 +343,12 @@ struct spi_nor_flash_parameter; * struct spi_nor - Structure for defining the SPI NOR layer * @mtd: an mtd_info structure * @lock: the lock for the read/write/erase/lock/unlock operations + * @rww: Read-While-Write (RWW) sync lock + * @rww.wait: wait queue for the RWW sync + * @rww.ongoing_io: the bus is busy + * @rww.ongoing_rd: a read is ongoing on the chip + * @rww.ongoing_pe: a program/erase is ongoing on the chip + * @rww.used_banks: bitmap of the banks in use * @dev: pointer to an SPI device or an SPI NOR controller device * @spimem: pointer to the SPI memory device * @bouncebuf: bounce buffer used when the buffer passed by the MTD @@ -376,6 +382,13 @@ struct spi_nor_flash_parameter; struct spi_nor { struct mtd_info mtd; struct mutex lock; + struct spi_nor_rww { + wait_queue_head_t wait; + bool ongoing_io; + bool ongoing_rd; + bool ongoing_pe; + unsigned int used_banks; + } rww; struct device *dev; struct spi_mem *spimem; u8 *bouncebuf; -- cgit v1.2.3 From d74c36480a679b27ce8a70c2e88fed31b86323d9 Mon Sep 17 00:00:00 2001 From: Chuanhong Guo Date: Wed, 29 Mar 2023 14:42:40 +0300 Subject: mtd: spinand: add support for ESMT F50x1G41LB This patch adds support for ESMT F50L1G41LB and F50D1G41LB. It seems that ESMT likes to use random JEDEC ID from other vendors. Their 1G chips uses 0xc8 from GigaDevice and 2G/4G chips uses 0x2c from Micron. For this reason, the ESMT entry is named esmt_c8 with explicit JEDEC ID in variable name. Datasheets: https://www.esmt.com.tw/upload/pdf/ESMT/datasheets/F50L1G41LB(2M).pdf https://www.esmt.com.tw/upload/pdf/ESMT/datasheets/F50D1G41LB(2M).pdf Signed-off-by: Chuanhong Guo Signed-off-by: Martin Kurbanov Signed-off-by: Dmitry Rokosov Tested-by: Martin Kurbanov Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20230329114240.378722-1-mmkurbanov@sberdevices.ru --- drivers/mtd/nand/spi/Makefile | 3 +- drivers/mtd/nand/spi/core.c | 1 + drivers/mtd/nand/spi/esmt.c | 135 ++++++++++++++++++++++++++++++++++++++++++ include/linux/mtd/spinand.h | 1 + 4 files changed, 139 insertions(+), 1 deletion(-) create mode 100644 drivers/mtd/nand/spi/esmt.c diff --git a/drivers/mtd/nand/spi/Makefile b/drivers/mtd/nand/spi/Makefile index 4ec973b8b6bf..cd8b66bf7740 100644 --- a/drivers/mtd/nand/spi/Makefile +++ b/drivers/mtd/nand/spi/Makefile @@ -1,3 +1,4 @@ # SPDX-License-Identifier: GPL-2.0 -spinand-objs := core.o alliancememory.o ato.o gigadevice.o macronix.o micron.o paragon.o toshiba.o winbond.o xtx.o +spinand-objs := core.o alliancememory.o ato.o esmt.o gigadevice.o macronix.o +spinand-objs += micron.o paragon.o toshiba.o winbond.o xtx.o obj-$(CONFIG_MTD_SPI_NAND) += spinand.o diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c index 638391f77d8c..393ff37f0d23 100644 --- a/drivers/mtd/nand/spi/core.c +++ b/drivers/mtd/nand/spi/core.c @@ -939,6 +939,7 @@ static const struct nand_ops spinand_ops = { static const struct spinand_manufacturer *spinand_manufacturers[] = { &alliancememory_spinand_manufacturer, &ato_spinand_manufacturer, + &esmt_c8_spinand_manufacturer, &gigadevice_spinand_manufacturer, ¯onix_spinand_manufacturer, µn_spinand_manufacturer, diff --git a/drivers/mtd/nand/spi/esmt.c b/drivers/mtd/nand/spi/esmt.c new file mode 100644 index 000000000000..1a3ffb982335 --- /dev/null +++ b/drivers/mtd/nand/spi/esmt.c @@ -0,0 +1,135 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Author: + * Chuanhong Guo - the main driver logic + * Martin Kurbanov - OOB layout + */ + +#include +#include +#include + +/* ESMT uses GigaDevice 0xc8 JECDEC ID on some SPI NANDs */ +#define SPINAND_MFR_ESMT_C8 0xc8 + +static SPINAND_OP_VARIANTS(read_cache_variants, + SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0), + SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0), + SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0), + SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0)); + +static SPINAND_OP_VARIANTS(write_cache_variants, + SPINAND_PROG_LOAD_X4(true, 0, NULL, 0), + SPINAND_PROG_LOAD(true, 0, NULL, 0)); + +static SPINAND_OP_VARIANTS(update_cache_variants, + SPINAND_PROG_LOAD_X4(false, 0, NULL, 0), + SPINAND_PROG_LOAD(false, 0, NULL, 0)); + +/* + * OOB spare area map (64 bytes) + * + * Bad Block Markers + * filled by HW and kernel Reserved + * | +-----------------------+-----------------------+ + * | | | | + * | | OOB free data Area |non ECC protected | + * | +-------------|-----+-----------------|-----+-----------------|-----+ + * | | | | | | | | + * +-|---|----------+--|-----|--------------+--|-----|--------------+--|-----|--------------+ + * | | | section0 | | | section1 | | | section2 | | | section3 | + * +-v-+-v-+---+----+--v--+--v--+-----+-----+--v--+--v--+-----+-----+--v--+--v--+-----+-----+ + * | | | | | | | | | | | | | | | | | + * |0:1|2:3|4:7|8:15|16:17|18:19|20:23|24:31|32:33|34:35|36:39|40:47|48:49|50:51|52:55|56:63| + * | | | | | | | | | | | | | | | | | + * +---+---+-^-+--^-+-----+-----+--^--+--^--+-----+-----+--^--+--^--+-----+-----+--^--+--^--+ + * | | | | | | | | + * | +----------------|-----+-----------------|-----+-----------------|-----+ + * | ECC Area|(Main + Spare) - filled|by ESMT NAND HW | + * | | | | + * +---------------------+-----------------------+-----------------------+ + * OOB ECC protected Area - not used due to + * partial programming from some filesystems + * (like JFFS2 with cleanmarkers) + */ + +#define ESMT_OOB_SECTION_COUNT 4 +#define ESMT_OOB_SECTION_SIZE(nand) \ + (nanddev_per_page_oobsize(nand) / ESMT_OOB_SECTION_COUNT) +#define ESMT_OOB_FREE_SIZE(nand) \ + (ESMT_OOB_SECTION_SIZE(nand) / 2) +#define ESMT_OOB_ECC_SIZE(nand) \ + (ESMT_OOB_SECTION_SIZE(nand) - ESMT_OOB_FREE_SIZE(nand)) +#define ESMT_OOB_BBM_SIZE 2 + +static int f50l1g41lb_ooblayout_ecc(struct mtd_info *mtd, int section, + struct mtd_oob_region *region) +{ + struct nand_device *nand = mtd_to_nanddev(mtd); + + if (section >= ESMT_OOB_SECTION_COUNT) + return -ERANGE; + + region->offset = section * ESMT_OOB_SECTION_SIZE(nand) + + ESMT_OOB_FREE_SIZE(nand); + region->length = ESMT_OOB_ECC_SIZE(nand); + + return 0; +} + +static int f50l1g41lb_ooblayout_free(struct mtd_info *mtd, int section, + struct mtd_oob_region *region) +{ + struct nand_device *nand = mtd_to_nanddev(mtd); + + if (section >= ESMT_OOB_SECTION_COUNT) + return -ERANGE; + + /* + * Reserve space for bad blocks markers (section0) and + * reserved bytes (sections 1-3) + */ + region->offset = section * ESMT_OOB_SECTION_SIZE(nand) + 2; + + /* Use only 2 non-protected ECC bytes per each OOB section */ + region->length = 2; + + return 0; +} + +static const struct mtd_ooblayout_ops f50l1g41lb_ooblayout = { + .ecc = f50l1g41lb_ooblayout_ecc, + .free = f50l1g41lb_ooblayout_free, +}; + +static const struct spinand_info esmt_c8_spinand_table[] = { + SPINAND_INFO("F50L1G41LB", + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x01), + NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1), + NAND_ECCREQ(1, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants, + &write_cache_variants, + &update_cache_variants), + 0, + SPINAND_ECCINFO(&f50l1g41lb_ooblayout, NULL)), + SPINAND_INFO("F50D1G41LB", + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x11), + NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1), + NAND_ECCREQ(1, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants, + &write_cache_variants, + &update_cache_variants), + 0, + SPINAND_ECCINFO(&f50l1g41lb_ooblayout, NULL)), +}; + +static const struct spinand_manufacturer_ops esmt_spinand_manuf_ops = { +}; + +const struct spinand_manufacturer esmt_c8_spinand_manufacturer = { + .id = SPINAND_MFR_ESMT_C8, + .name = "ESMT", + .chips = esmt_c8_spinand_table, + .nchips = ARRAY_SIZE(esmt_c8_spinand_table), + .ops = &esmt_spinand_manuf_ops, +}; diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h index 01be9f0f008a..3e285c09d16d 100644 --- a/include/linux/mtd/spinand.h +++ b/include/linux/mtd/spinand.h @@ -262,6 +262,7 @@ struct spinand_manufacturer { /* SPI NAND manufacturers */ extern const struct spinand_manufacturer alliancememory_spinand_manufacturer; extern const struct spinand_manufacturer ato_spinand_manufacturer; +extern const struct spinand_manufacturer esmt_c8_spinand_manufacturer; extern const struct spinand_manufacturer gigadevice_spinand_manufacturer; extern const struct spinand_manufacturer macronix_spinand_manufacturer; extern const struct spinand_manufacturer micron_spinand_manufacturer; -- cgit v1.2.3 From 705c9ef831ce505f007d0af3fed2475764619533 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Fri, 31 Mar 2023 21:47:26 +0200 Subject: mtd: spi-nor: Fix a trivial typo Fix a trivial typo in one of the core's comments. Fixes: 620df2497415 ("mtd: spi-nor: Introduce spi_nor_get_flash_info()") Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/r/20230331194726.840208-1-miquel.raynal@bootlin.com Signed-off-by: Tudor Ambarus --- drivers/mtd/spi-nor/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c index 9e6a0730cdb8..c6a313d87c17 100644 --- a/drivers/mtd/spi-nor/core.c +++ b/drivers/mtd/spi-nor/core.c @@ -3318,7 +3318,7 @@ static const struct flash_info *spi_nor_get_flash_info(struct spi_nor *nor, * JEDEC knows better, so overwrite platform ID. We * can't trust partitions any longer, but we'll let * mtd apply them anyway, since some partitions may be - * marked read-only, and we don't want to lose that + * marked read-only, and we don't want to loose that * information, even if it's not 100% accurate. */ dev_warn(nor->dev, "found %s, expected %s\n", -- cgit v1.2.3 From 79a4db50192c196757e1dffa7f590fc7080ad746 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Fri, 31 Mar 2023 21:46:19 +0200 Subject: mtd: spi-nor: Delay the initialization of bank_size Bank size is derived from the chip's size, which in spi_nor_init_default_params() can still be zero if the flash size is not specified at flash declaration. Let the flash size be updated by parsing SFDP and do the initialization of the bank size in spi_nor_late_init_params(). Flashes that don't define the SFDP tables must specify the flash size at declaration. Fixes: 9d6c5d64f028 ("mtd: spi-nor: Introduce the concept of bank") Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/r/20230331194620.839899-1-miquel.raynal@bootlin.com [ta: drop superfluous initialization in spi_nor_init_default_params(), reword commit message, add Fixes tag.] Signed-off-by: Tudor Ambarus --- drivers/mtd/spi-nor/core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c index c6a313d87c17..35295d98542f 100644 --- a/drivers/mtd/spi-nor/core.c +++ b/drivers/mtd/spi-nor/core.c @@ -2882,6 +2882,8 @@ static void spi_nor_late_init_params(struct spi_nor *nor) */ if (nor->flags & SNOR_F_HAS_LOCK && !nor->params->locking_ops) spi_nor_init_default_locking_ops(nor); + + nor->params->bank_size = div64_u64(nor->params->size, nor->info->n_banks); } /** @@ -2948,7 +2950,6 @@ static void spi_nor_init_default_params(struct spi_nor *nor) /* Set SPI NOR sizes. */ params->writesize = 1; params->size = (u64)info->sector_size * info->n_sectors; - params->bank_size = div64_u64(params->size, info->n_banks); params->page_size = info->page_size; if (!(info->flags & SPI_NOR_NO_FR)) { -- cgit v1.2.3 From f0a499acb4b6f4c9a169ce35195b8021578ea14a Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Fri, 31 Mar 2023 21:46:20 +0200 Subject: mtd: spi-nor: macronix: Add support for mx25uw51245g with RWW Describe this new part and provide the RWW flag for it. There is no public datasheet, but here are the sfdp tables plus base testing to show it works. $ cat /sys/bus/spi/devices/spi0.0/spi-nor/partname mx25uw51245g $ cat /sys/bus/spi/devices/spi0.0/spi-nor/jedec_id c2813a $ cat /sys/bus/spi/devices/spi0.0/spi-nor/manufacturer macronix $ xxd -p /sys/bus/spi/devices/spi0.0/spi-nor/sfdp 53464450080104fd00070114400000ff8701011c900000ff0a0001080001 00ff05000105200100ff84000102340100ff0000000000000000ffffffff ffffffffe5208affffffff1f00ff00ff00ff00ffeeffffffffff00ffffff 00ff0c2010d800ff00ff87790100821200e27704674630b030b0f4bdd55c 000000ff101000200000000000007ca14800000000008888000000000000 00400fd1fff30fd1fff300050090000500b1002b0095002b0096727103b8 727103b80000000090a3188200c069960000000000000000727100987271 00b8727100990000000072710098727100f872710099727100f900000000 00000000011501d0727106d8000086500000060100000000020001030002 00000000060100000000000072060002000000eec0697272717100d8f7f6 000a00001445988043060f0021dcffff $ md5sum /sys/bus/spi/devices/spi0.0/spi-nor/sfdp 047a884cf44d9ffc2a94d3ab37b48c63 /sys/bus/spi/devices/spi0.0/spi-nor/sfdp $ dd if=/dev/urandom of=./qspi_test bs=1M count=6 6+0 records in 6+0 records out $ mtd_debug write /dev/mtd1 0 6291456 qspi_test Copied 6291456 bytes from qspi_test to address 0x00000000 in flash $ mtd_debug erase /dev/mtd1 0 6291456 Erased 6291456 bytes from address 0x00000000 in flash $ mtd_debug read /dev/mtd1 0 6291456 qspi_read Copied 6291456 bytes from address 0x00000000 in flash to qspi_read $ hexdump qspi_read 0000000 ffff ffff ffff ffff ffff ffff ffff ffff * 0600000 $ mtd_debug write /dev/mtd1 0 6291456 qspi_test Copied 6291456 bytes from qspi_test to address 0x00000000 in flash $ mtd_debug read /dev/mtd1 0 6291456 qspi_read Copied 6291456 bytes from address 0x00000000 in flash to qspi_read $ sha1sum qspi_test qspi_read d24a9523db829a0df688f34b8dc76a1383b74024 qspi_test d24a9523db829a0df688f34b8dc76a1383b74024 qspi_read Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/r/20230331194620.839899-2-miquel.raynal@bootlin.com Signed-off-by: Tudor Ambarus --- drivers/mtd/spi-nor/macronix.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/mtd/spi-nor/macronix.c b/drivers/mtd/spi-nor/macronix.c index 6853ec9ae65d..7db1a1a6a1fb 100644 --- a/drivers/mtd/spi-nor/macronix.c +++ b/drivers/mtd/spi-nor/macronix.c @@ -82,6 +82,9 @@ static const struct flash_info macronix_nor_parts[] = { { "mx25u51245g", INFO(0xc2253a, 0, 64 * 1024, 1024) NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) FIXUP_FLAGS(SPI_NOR_4B_OPCODES) }, + { "mx25uw51245g", INFOB(0xc2813a, 0, 0, 0, 4) + PARSE_SFDP + FLAGS(SPI_NOR_RWW) }, { "mx25v8035f", INFO(0xc22314, 0, 64 * 1024, 16) NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, -- cgit v1.2.3 From 076aa4eac8b3f7e8ade56a64a7197836d6bd3a72 Mon Sep 17 00:00:00 2001 From: Tudor Ambarus Date: Fri, 31 Mar 2023 07:45:57 +0000 Subject: mtd: spi-nor: core: Move generic method to core - micron_st_nor_set_4byte_addr_mode This method is described in JESD216 BFPT[SFDP_DWORD(16)], BIT(30) and BIT(22). Move the method to core. Reviewed-by: Michael Walle Link: https://lore.kernel.org/r/20230331074606.3559258-2-tudor.ambarus@linaro.org Signed-off-by: Tudor Ambarus --- drivers/mtd/spi-nor/core.c | 24 ++++++++++++++++++++++++ drivers/mtd/spi-nor/core.h | 1 + drivers/mtd/spi-nor/micron-st.c | 24 ------------------------ 3 files changed, 25 insertions(+), 24 deletions(-) diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c index 35295d98542f..34256593acde 100644 --- a/drivers/mtd/spi-nor/core.c +++ b/drivers/mtd/spi-nor/core.c @@ -538,6 +538,30 @@ int spi_nor_set_4byte_addr_mode(struct spi_nor *nor, bool enable) return ret; } +/** + * micron_st_nor_set_4byte_addr_mode() - Set 4-byte address mode for ST and + * Micron flashes. + * @nor: pointer to 'struct spi_nor'. + * @enable: true to enter the 4-byte address mode, false to exit the 4-byte + * address mode. + * + * Return: 0 on success, -errno otherwise. + */ +int micron_st_nor_set_4byte_addr_mode(struct spi_nor *nor, bool enable) +{ + int ret; + + ret = spi_nor_write_enable(nor); + if (ret) + return ret; + + ret = spi_nor_set_4byte_addr_mode(nor, enable); + if (ret) + return ret; + + return spi_nor_write_disable(nor); +} + /** * spansion_set_4byte_addr_mode() - Set 4-byte address mode for Spansion * flashes. diff --git a/drivers/mtd/spi-nor/core.h b/drivers/mtd/spi-nor/core.h index de31e430f77e..d5cb42245820 100644 --- a/drivers/mtd/spi-nor/core.h +++ b/drivers/mtd/spi-nor/core.h @@ -648,6 +648,7 @@ void spi_nor_spimem_setup_op(const struct spi_nor *nor, int spi_nor_write_enable(struct spi_nor *nor); int spi_nor_write_disable(struct spi_nor *nor); int spi_nor_set_4byte_addr_mode(struct spi_nor *nor, bool enable); +int micron_st_nor_set_4byte_addr_mode(struct spi_nor *nor, bool enable); int spi_nor_wait_till_ready(struct spi_nor *nor); int spi_nor_global_block_unlock(struct spi_nor *nor); int spi_nor_prep_and_lock(struct spi_nor *nor); diff --git a/drivers/mtd/spi-nor/micron-st.c b/drivers/mtd/spi-nor/micron-st.c index 7bb86df52f0b..3bbf65234ebd 100644 --- a/drivers/mtd/spi-nor/micron-st.c +++ b/drivers/mtd/spi-nor/micron-st.c @@ -301,30 +301,6 @@ static const struct flash_info st_nor_parts[] = { { "m25px80", INFO(0x207114, 0, 64 * 1024, 16) }, }; -/** - * micron_st_nor_set_4byte_addr_mode() - Set 4-byte address mode for ST and - * Micron flashes. - * @nor: pointer to 'struct spi_nor'. - * @enable: true to enter the 4-byte address mode, false to exit the 4-byte - * address mode. - * - * Return: 0 on success, -errno otherwise. - */ -static int micron_st_nor_set_4byte_addr_mode(struct spi_nor *nor, bool enable) -{ - int ret; - - ret = spi_nor_write_enable(nor); - if (ret) - return ret; - - ret = spi_nor_set_4byte_addr_mode(nor, enable); - if (ret) - return ret; - - return spi_nor_write_disable(nor); -} - /** * micron_st_nor_read_fsr() - Read the Flag Status Register. * @nor: pointer to 'struct spi_nor' -- cgit v1.2.3 From 288df43783199dd796eb58552b997d92a115ebbd Mon Sep 17 00:00:00 2001 From: Tudor Ambarus Date: Fri, 31 Mar 2023 07:45:58 +0000 Subject: mtd: spi-nor: core: Update name and description of micron_st_nor_set_4byte_addr_mode Rename method to spi_nor_set_4byte_addr_mode_wren_en4b_ex4b and extend its description. This method is described in JESD216 BFPT[SFDP_DWORD(16)], BIT(30) and BIT(22). Reviewed-by: Michael Walle Link: https://lore.kernel.org/r/20230331074606.3559258-3-tudor.ambarus@linaro.org Signed-off-by: Tudor Ambarus --- drivers/mtd/spi-nor/core.c | 7 ++++--- drivers/mtd/spi-nor/core.h | 3 ++- drivers/mtd/spi-nor/micron-st.c | 2 +- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c index 34256593acde..7c02983ce137 100644 --- a/drivers/mtd/spi-nor/core.c +++ b/drivers/mtd/spi-nor/core.c @@ -539,15 +539,16 @@ int spi_nor_set_4byte_addr_mode(struct spi_nor *nor, bool enable) } /** - * micron_st_nor_set_4byte_addr_mode() - Set 4-byte address mode for ST and - * Micron flashes. + * spi_nor_set_4byte_addr_mode_wren_en4b_ex4b() - Set 4-byte address mode using + * SPINOR_OP_WREN followed by SPINOR_OP_EN4B or SPINOR_OP_EX4B. Typically used + * by ST and Micron flashes. * @nor: pointer to 'struct spi_nor'. * @enable: true to enter the 4-byte address mode, false to exit the 4-byte * address mode. * * Return: 0 on success, -errno otherwise. */ -int micron_st_nor_set_4byte_addr_mode(struct spi_nor *nor, bool enable) +int spi_nor_set_4byte_addr_mode_wren_en4b_ex4b(struct spi_nor *nor, bool enable) { int ret; diff --git a/drivers/mtd/spi-nor/core.h b/drivers/mtd/spi-nor/core.h index d5cb42245820..d8e3fd60d6ee 100644 --- a/drivers/mtd/spi-nor/core.h +++ b/drivers/mtd/spi-nor/core.h @@ -648,7 +648,8 @@ void spi_nor_spimem_setup_op(const struct spi_nor *nor, int spi_nor_write_enable(struct spi_nor *nor); int spi_nor_write_disable(struct spi_nor *nor); int spi_nor_set_4byte_addr_mode(struct spi_nor *nor, bool enable); -int micron_st_nor_set_4byte_addr_mode(struct spi_nor *nor, bool enable); +int spi_nor_set_4byte_addr_mode_wren_en4b_ex4b(struct spi_nor *nor, + bool enable); int spi_nor_wait_till_ready(struct spi_nor *nor); int spi_nor_global_block_unlock(struct spi_nor *nor); int spi_nor_prep_and_lock(struct spi_nor *nor); diff --git a/drivers/mtd/spi-nor/micron-st.c b/drivers/mtd/spi-nor/micron-st.c index 3bbf65234ebd..a75f0f4e1c38 100644 --- a/drivers/mtd/spi-nor/micron-st.c +++ b/drivers/mtd/spi-nor/micron-st.c @@ -425,7 +425,7 @@ static void micron_st_nor_default_init(struct spi_nor *nor) nor->flags |= SNOR_F_HAS_LOCK; nor->flags &= ~SNOR_F_HAS_16BIT_SR; nor->params->quad_enable = NULL; - nor->params->set_4byte_addr_mode = micron_st_nor_set_4byte_addr_mode; + nor->params->set_4byte_addr_mode = spi_nor_set_4byte_addr_mode_wren_en4b_ex4b; } static void micron_st_nor_late_init(struct spi_nor *nor) -- cgit v1.2.3 From f1f1976224f3b2e0197cddf57b905a995c5528ca Mon Sep 17 00:00:00 2001 From: Tudor Ambarus Date: Fri, 31 Mar 2023 07:45:59 +0000 Subject: mtd: spi-nor: core: Update name and description of spansion_set_4byte_addr_mode Rename method to spi_nor_set_4byte_addr_mode_brwr and extend its description. This method is described in JESD216 BFPT[SFDP_DWORD(16)], BIT(28) and BIT(20). Reviewed-by: Michael Walle Link: https://lore.kernel.org/r/20230331074606.3559258-4-tudor.ambarus@linaro.org Signed-off-by: Tudor Ambarus --- drivers/mtd/spi-nor/core.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c index 7c02983ce137..b868a06c6902 100644 --- a/drivers/mtd/spi-nor/core.c +++ b/drivers/mtd/spi-nor/core.c @@ -564,15 +564,20 @@ int spi_nor_set_4byte_addr_mode_wren_en4b_ex4b(struct spi_nor *nor, bool enable) } /** - * spansion_set_4byte_addr_mode() - Set 4-byte address mode for Spansion - * flashes. + * spi_nor_set_4byte_addr_mode_brwr() - Set 4-byte address mode using + * SPINOR_OP_BRWR. Typically used by Spansion flashes. * @nor: pointer to 'struct spi_nor'. * @enable: true to enter the 4-byte address mode, false to exit the 4-byte * address mode. * + * 8-bit volatile bank register used to define A[30:A24] bits. MSB (bit[7]) is + * used to enable/disable 4-byte address mode. When MSB is set to ‘1’, 4-byte + * address mode is active and A[30:24] bits are don’t care. Write instruction is + * SPINOR_OP_BRWR(17h) with 1 byte of data. + * * Return: 0 on success, -errno otherwise. */ -static int spansion_set_4byte_addr_mode(struct spi_nor *nor, bool enable) +static int spi_nor_set_4byte_addr_mode_brwr(struct spi_nor *nor, bool enable) { int ret; @@ -2966,7 +2971,7 @@ static void spi_nor_init_default_params(struct spi_nor *nor) struct device_node *np = spi_nor_get_flash_node(nor); params->quad_enable = spi_nor_sr2_bit1_quad_enable; - params->set_4byte_addr_mode = spansion_set_4byte_addr_mode; + params->set_4byte_addr_mode = spi_nor_set_4byte_addr_mode_brwr; params->otp.org = &info->otp_org; /* Default to 16-bit Write Status (01h) Command */ -- cgit v1.2.3 From d75c22f376f6c31b6f16da3989c8f07ccc6cb2ca Mon Sep 17 00:00:00 2001 From: Tudor Ambarus Date: Fri, 31 Mar 2023 07:46:00 +0000 Subject: mtd: spi-nor: core: Update name and description of spi_nor_set_4byte_addr_mode Rename method to spi_nor_set_4byte_addr_mode_en4b_ex4b and extend its description. This method is described in JESD216 BFPT[SFDP_DWORD(16)], BIT(31) and BIT(23). Reviewed-by: Michael Walle Link: https://lore.kernel.org/r/20230331074606.3559258-5-tudor.ambarus@linaro.org Signed-off-by: Tudor Ambarus --- drivers/mtd/spi-nor/core.c | 8 +++++--- drivers/mtd/spi-nor/core.h | 2 +- drivers/mtd/spi-nor/macronix.c | 2 +- drivers/mtd/spi-nor/winbond.c | 2 +- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c index b868a06c6902..0cc34f4f3899 100644 --- a/drivers/mtd/spi-nor/core.c +++ b/drivers/mtd/spi-nor/core.c @@ -508,14 +508,16 @@ int spi_nor_read_cr(struct spi_nor *nor, u8 *cr) } /** - * spi_nor_set_4byte_addr_mode() - Enter/Exit 4-byte address mode. + * spi_nor_set_4byte_addr_mode_en4b_ex4b() - Enter/Exit 4-byte address mode + * using SPINOR_OP_EN4B/SPINOR_OP_EX4B. Typically used by + * Winbond and Macronix. * @nor: pointer to 'struct spi_nor'. * @enable: true to enter the 4-byte address mode, false to exit the 4-byte * address mode. * * Return: 0 on success, -errno otherwise. */ -int spi_nor_set_4byte_addr_mode(struct spi_nor *nor, bool enable) +int spi_nor_set_4byte_addr_mode_en4b_ex4b(struct spi_nor *nor, bool enable) { int ret; @@ -556,7 +558,7 @@ int spi_nor_set_4byte_addr_mode_wren_en4b_ex4b(struct spi_nor *nor, bool enable) if (ret) return ret; - ret = spi_nor_set_4byte_addr_mode(nor, enable); + ret = spi_nor_set_4byte_addr_mode_en4b_ex4b(nor, enable); if (ret) return ret; diff --git a/drivers/mtd/spi-nor/core.h b/drivers/mtd/spi-nor/core.h index d8e3fd60d6ee..067945c10023 100644 --- a/drivers/mtd/spi-nor/core.h +++ b/drivers/mtd/spi-nor/core.h @@ -647,7 +647,7 @@ void spi_nor_spimem_setup_op(const struct spi_nor *nor, const enum spi_nor_protocol proto); int spi_nor_write_enable(struct spi_nor *nor); int spi_nor_write_disable(struct spi_nor *nor); -int spi_nor_set_4byte_addr_mode(struct spi_nor *nor, bool enable); +int spi_nor_set_4byte_addr_mode_en4b_ex4b(struct spi_nor *nor, bool enable); int spi_nor_set_4byte_addr_mode_wren_en4b_ex4b(struct spi_nor *nor, bool enable); int spi_nor_wait_till_ready(struct spi_nor *nor); diff --git a/drivers/mtd/spi-nor/macronix.c b/drivers/mtd/spi-nor/macronix.c index 7db1a1a6a1fb..1cd55ba6c016 100644 --- a/drivers/mtd/spi-nor/macronix.c +++ b/drivers/mtd/spi-nor/macronix.c @@ -108,7 +108,7 @@ static const struct flash_info macronix_nor_parts[] = { static void macronix_nor_default_init(struct spi_nor *nor) { nor->params->quad_enable = spi_nor_sr1_bit6_quad_enable; - nor->params->set_4byte_addr_mode = spi_nor_set_4byte_addr_mode; + nor->params->set_4byte_addr_mode = spi_nor_set_4byte_addr_mode_en4b_ex4b; } static const struct spi_nor_fixups macronix_nor_fixups = { diff --git a/drivers/mtd/spi-nor/winbond.c b/drivers/mtd/spi-nor/winbond.c index ca39acf4112c..9cea241c204b 100644 --- a/drivers/mtd/spi-nor/winbond.c +++ b/drivers/mtd/spi-nor/winbond.c @@ -188,7 +188,7 @@ static int winbond_nor_set_4byte_addr_mode(struct spi_nor *nor, bool enable) { int ret; - ret = spi_nor_set_4byte_addr_mode(nor, enable); + ret = spi_nor_set_4byte_addr_mode_en4b_ex4b(nor, enable); if (ret || enable) return ret; -- cgit v1.2.3 From 3a4d5f4af9e668e59ce65115221fd964b3041da5 Mon Sep 17 00:00:00 2001 From: Tudor Ambarus Date: Fri, 31 Mar 2023 07:46:01 +0000 Subject: mtd: spi-nor: core: Make spi_nor_set_4byte_addr_mode_brwr public This method can be retrieved at BFPT parsing time. The method is described in JESD216 BFPT[SFDP_DWORD(16)], BIT(28) and BIT(20). Reviewed-by: Michael Walle Link: https://lore.kernel.org/r/20230331074606.3559258-6-tudor.ambarus@linaro.org Signed-off-by: Tudor Ambarus --- drivers/mtd/spi-nor/core.c | 2 +- drivers/mtd/spi-nor/core.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c index 0cc34f4f3899..c65c0252863e 100644 --- a/drivers/mtd/spi-nor/core.c +++ b/drivers/mtd/spi-nor/core.c @@ -579,7 +579,7 @@ int spi_nor_set_4byte_addr_mode_wren_en4b_ex4b(struct spi_nor *nor, bool enable) * * Return: 0 on success, -errno otherwise. */ -static int spi_nor_set_4byte_addr_mode_brwr(struct spi_nor *nor, bool enable) +int spi_nor_set_4byte_addr_mode_brwr(struct spi_nor *nor, bool enable) { int ret; diff --git a/drivers/mtd/spi-nor/core.h b/drivers/mtd/spi-nor/core.h index 067945c10023..8953ddeb8625 100644 --- a/drivers/mtd/spi-nor/core.h +++ b/drivers/mtd/spi-nor/core.h @@ -650,6 +650,7 @@ int spi_nor_write_disable(struct spi_nor *nor); int spi_nor_set_4byte_addr_mode_en4b_ex4b(struct spi_nor *nor, bool enable); int spi_nor_set_4byte_addr_mode_wren_en4b_ex4b(struct spi_nor *nor, bool enable); +int spi_nor_set_4byte_addr_mode_brwr(struct spi_nor *nor, bool enable); int spi_nor_wait_till_ready(struct spi_nor *nor); int spi_nor_global_block_unlock(struct spi_nor *nor); int spi_nor_prep_and_lock(struct spi_nor *nor); -- cgit v1.2.3 From 4e53ab0c292db99eff5dd65670bfdba79bbf338f Mon Sep 17 00:00:00 2001 From: Tudor Ambarus Date: Fri, 31 Mar 2023 07:46:02 +0000 Subject: mtd: spi-nor: Set the 4-Byte Address Mode method based on SFDP data JESD216 SFDP defines in BFPT methods to enter and exit the 4-Byte Address Mode. The flash parameters and settings that are retrieved from SFDP have higher precedence than the static initialized ones, because they should be more accurate and less error prone than those initialized statically. Parse and favor the BFPT-parsed set_4byte_addr_mode methods. Some regressions may be introduced by this patch, because the params->set_4byte_addr_mode method that was set either in spi_nor_init_default_params() or later overwritten in default_init() hooks, are now be overwritten with a different value based on the BFPT data. If that's the case, the fix is to introduce a post_bfpt fixup hook where one should fix the wrong BFPT info. Link: https://lore.kernel.org/r/20230331074606.3559258-7-tudor.ambarus@linaro.org Signed-off-by: Tudor Ambarus --- drivers/mtd/spi-nor/core.c | 7 ++++++- drivers/mtd/spi-nor/macronix.c | 8 +++++++- drivers/mtd/spi-nor/micron-st.c | 8 ++++++-- drivers/mtd/spi-nor/sfdp.c | 11 +++++++++++ drivers/mtd/spi-nor/sfdp.h | 27 +++++++++++++++++++++++++++ drivers/mtd/spi-nor/winbond.c | 22 ++++++++++++++-------- 6 files changed, 71 insertions(+), 12 deletions(-) diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c index c65c0252863e..afb56b2cf8fe 100644 --- a/drivers/mtd/spi-nor/core.c +++ b/drivers/mtd/spi-nor/core.c @@ -2898,6 +2898,8 @@ static void spi_nor_init_fixup_flags(struct spi_nor *nor) */ static void spi_nor_late_init_params(struct spi_nor *nor) { + struct spi_nor_flash_parameter *params = nor->params; + if (nor->manufacturer && nor->manufacturer->fixups && nor->manufacturer->fixups->late_init) nor->manufacturer->fixups->late_init(nor); @@ -2905,6 +2907,10 @@ static void spi_nor_late_init_params(struct spi_nor *nor) if (nor->info->fixups && nor->info->fixups->late_init) nor->info->fixups->late_init(nor); + /* Default method kept for backward compatibility. */ + if (!params->set_4byte_addr_mode) + params->set_4byte_addr_mode = spi_nor_set_4byte_addr_mode_brwr; + spi_nor_init_flags(nor); spi_nor_init_fixup_flags(nor); @@ -2973,7 +2979,6 @@ static void spi_nor_init_default_params(struct spi_nor *nor) struct device_node *np = spi_nor_get_flash_node(nor); params->quad_enable = spi_nor_sr2_bit1_quad_enable; - params->set_4byte_addr_mode = spi_nor_set_4byte_addr_mode_brwr; params->otp.org = &info->otp_org; /* Default to 16-bit Write Status (01h) Command */ diff --git a/drivers/mtd/spi-nor/macronix.c b/drivers/mtd/spi-nor/macronix.c index 1cd55ba6c016..04888258e891 100644 --- a/drivers/mtd/spi-nor/macronix.c +++ b/drivers/mtd/spi-nor/macronix.c @@ -108,11 +108,17 @@ static const struct flash_info macronix_nor_parts[] = { static void macronix_nor_default_init(struct spi_nor *nor) { nor->params->quad_enable = spi_nor_sr1_bit6_quad_enable; - nor->params->set_4byte_addr_mode = spi_nor_set_4byte_addr_mode_en4b_ex4b; +} + +static void macronix_nor_late_init(struct spi_nor *nor) +{ + if (!nor->params->set_4byte_addr_mode) + nor->params->set_4byte_addr_mode = spi_nor_set_4byte_addr_mode_en4b_ex4b; } static const struct spi_nor_fixups macronix_nor_fixups = { .default_init = macronix_nor_default_init, + .late_init = macronix_nor_late_init, }; const struct spi_nor_manufacturer spi_nor_macronix = { diff --git a/drivers/mtd/spi-nor/micron-st.c b/drivers/mtd/spi-nor/micron-st.c index a75f0f4e1c38..a6f080112a51 100644 --- a/drivers/mtd/spi-nor/micron-st.c +++ b/drivers/mtd/spi-nor/micron-st.c @@ -425,13 +425,17 @@ static void micron_st_nor_default_init(struct spi_nor *nor) nor->flags |= SNOR_F_HAS_LOCK; nor->flags &= ~SNOR_F_HAS_16BIT_SR; nor->params->quad_enable = NULL; - nor->params->set_4byte_addr_mode = spi_nor_set_4byte_addr_mode_wren_en4b_ex4b; } static void micron_st_nor_late_init(struct spi_nor *nor) { + struct spi_nor_flash_parameter *params = nor->params; + if (nor->info->mfr_flags & USE_FSR) - nor->params->ready = micron_st_nor_ready; + params->ready = micron_st_nor_ready; + + if (!params->set_4byte_addr_mode) + params->set_4byte_addr_mode = spi_nor_set_4byte_addr_mode_wren_en4b_ex4b; } static const struct spi_nor_fixups micron_st_nor_fixups = { diff --git a/drivers/mtd/spi-nor/sfdp.c b/drivers/mtd/spi-nor/sfdp.c index 298ab5e53a8c..69e47c9778a2 100644 --- a/drivers/mtd/spi-nor/sfdp.c +++ b/drivers/mtd/spi-nor/sfdp.c @@ -438,6 +438,7 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor, size_t len; int i, cmd, err; u32 addr, val; + u32 dword; u16 half; u8 erase_mask; @@ -607,6 +608,16 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor, break; } + dword = bfpt.dwords[SFDP_DWORD(16)] & BFPT_DWORD16_4B_ADDR_MODE_MASK; + if (SFDP_MASK_CHECK(dword, BFPT_DWORD16_4B_ADDR_MODE_BRWR)) + params->set_4byte_addr_mode = spi_nor_set_4byte_addr_mode_brwr; + else if (SFDP_MASK_CHECK(dword, BFPT_DWORD16_4B_ADDR_MODE_WREN_EN4B_EX4B)) + params->set_4byte_addr_mode = spi_nor_set_4byte_addr_mode_wren_en4b_ex4b; + else if (SFDP_MASK_CHECK(dword, BFPT_DWORD16_4B_ADDR_MODE_EN4B_EX4B)) + params->set_4byte_addr_mode = spi_nor_set_4byte_addr_mode_en4b_ex4b; + else + dev_dbg(nor->dev, "BFPT: 4-Byte Address Mode method is not recognized or not implemented\n"); + /* Soft Reset support. */ if (bfpt.dwords[SFDP_DWORD(16)] & BFPT_DWORD16_SWRST_EN_RST) nor->flags |= SNOR_F_SOFT_RESET; diff --git a/drivers/mtd/spi-nor/sfdp.h b/drivers/mtd/spi-nor/sfdp.h index 500659b35655..6eb99e1cdd61 100644 --- a/drivers/mtd/spi-nor/sfdp.h +++ b/drivers/mtd/spi-nor/sfdp.h @@ -15,6 +15,7 @@ /* SFDP DWORDS are indexed from 1 but C arrays are indexed from 0. */ #define SFDP_DWORD(i) ((i) - 1) +#define SFDP_MASK_CHECK(dword, mask) (((dword) & (mask)) == (mask)) /* Basic Flash Parameter Table */ @@ -89,6 +90,32 @@ struct sfdp_bfpt { #define BFPT_DWORD15_QER_SR2_BIT1_NO_RD (0x4UL << 20) #define BFPT_DWORD15_QER_SR2_BIT1 (0x5UL << 20) /* Spansion */ +#define BFPT_DWORD16_EN4B_MASK GENMASK(31, 24) +#define BFPT_DWORD16_EN4B_ALWAYS_4B BIT(30) +#define BFPT_DWORD16_EN4B_4B_OPCODES BIT(29) +#define BFPT_DWORD16_EN4B_16BIT_NV_CR BIT(28) +#define BFPT_DWORD16_EN4B_BRWR BIT(27) +#define BFPT_DWORD16_EN4B_WREAR BIT(26) +#define BFPT_DWORD16_EN4B_WREN_EN4B BIT(25) +#define BFPT_DWORD16_EN4B_EN4B BIT(24) +#define BFPT_DWORD16_EX4B_MASK GENMASK(18, 14) +#define BFPT_DWORD16_EX4B_16BIT_NV_CR BIT(18) +#define BFPT_DWORD16_EX4B_BRWR BIT(17) +#define BFPT_DWORD16_EX4B_WREAR BIT(16) +#define BFPT_DWORD16_EX4B_WREN_EX4B BIT(15) +#define BFPT_DWORD16_EX4B_EX4B BIT(14) +#define BFPT_DWORD16_4B_ADDR_MODE_MASK \ + (BFPT_DWORD16_EN4B_MASK | BFPT_DWORD16_EX4B_MASK) +#define BFPT_DWORD16_4B_ADDR_MODE_16BIT_NV_CR \ + (BFPT_DWORD16_EN4B_16BIT_NV_CR | BFPT_DWORD16_EX4B_16BIT_NV_CR) +#define BFPT_DWORD16_4B_ADDR_MODE_BRWR \ + (BFPT_DWORD16_EN4B_BRWR | BFPT_DWORD16_EX4B_BRWR) +#define BFPT_DWORD16_4B_ADDR_MODE_WREAR \ + (BFPT_DWORD16_EN4B_WREAR | BFPT_DWORD16_EX4B_WREAR) +#define BFPT_DWORD16_4B_ADDR_MODE_WREN_EN4B_EX4B \ + (BFPT_DWORD16_EN4B_WREN_EN4B | BFPT_DWORD16_EX4B_WREN_EX4B) +#define BFPT_DWORD16_4B_ADDR_MODE_EN4B_EX4B \ + (BFPT_DWORD16_EN4B_EN4B | BFPT_DWORD16_EX4B_EX4B) #define BFPT_DWORD16_SWRST_EN_RST BIT(12) #define BFPT_DWORD18_CMD_EXT_MASK GENMASK(30, 29) diff --git a/drivers/mtd/spi-nor/winbond.c b/drivers/mtd/spi-nor/winbond.c index 9cea241c204b..834d6ba5ce70 100644 --- a/drivers/mtd/spi-nor/winbond.c +++ b/drivers/mtd/spi-nor/winbond.c @@ -216,19 +216,25 @@ static const struct spi_nor_otp_ops winbond_nor_otp_ops = { .is_locked = spi_nor_otp_is_locked_sr2, }; -static void winbond_nor_default_init(struct spi_nor *nor) -{ - nor->params->set_4byte_addr_mode = winbond_nor_set_4byte_addr_mode; -} - static void winbond_nor_late_init(struct spi_nor *nor) { - if (nor->params->otp.org->n_regions) - nor->params->otp.ops = &winbond_nor_otp_ops; + struct spi_nor_flash_parameter *params = nor->params; + + if (params->otp.org->n_regions) + params->otp.ops = &winbond_nor_otp_ops; + + /* + * Winbond seems to require that the Extended Address Register to be set + * to zero when exiting the 4-Byte Address Mode, at least for W25Q256FV. + * This requirement is not described in the JESD216 SFDP standard, thus + * it is Winbond specific. Since we do not know if other Winbond flashes + * have the same requirement, play safe and overwrite the method parsed + * from BFPT, if any. + */ + params->set_4byte_addr_mode = winbond_nor_set_4byte_addr_mode; } static const struct spi_nor_fixups winbond_nor_fixups = { - .default_init = winbond_nor_default_init, .late_init = winbond_nor_late_init, }; -- cgit v1.2.3 From 7fe1b00d92eaceb83f95200b5114cf5df0919892 Mon Sep 17 00:00:00 2001 From: Tudor Ambarus Date: Fri, 31 Mar 2023 07:46:03 +0000 Subject: mtd: spi-nor: Stop exporting spi_nor_restore() Some SPI NOR controllers that used this method were moved to drivers/spi/. We don't accept new support for the existing SPI NOR controllers drivers under drivers/mtd/spi-nor/controllers/ and we encourage their owners to move the drivers under drivers/spi/. Make spi_nor_restore() private as we're going to use it just in core.c. Link: https://lore.kernel.org/r/20230331074606.3559258-8-tudor.ambarus@linaro.org Signed-off-by: Tudor Ambarus --- Documentation/driver-api/mtd/spi-nor.rst | 3 --- drivers/mtd/spi-nor/core.c | 3 +-- include/linux/mtd/spi-nor.h | 6 ------ 3 files changed, 1 insertion(+), 11 deletions(-) diff --git a/Documentation/driver-api/mtd/spi-nor.rst b/Documentation/driver-api/mtd/spi-nor.rst index 4a3adca417fd..c22f8c0f7950 100644 --- a/Documentation/driver-api/mtd/spi-nor.rst +++ b/Documentation/driver-api/mtd/spi-nor.rst @@ -63,6 +63,3 @@ The main API is spi_nor_scan(). Before you call the hook, a driver should initialize the necessary fields for spi_nor{}. Please see drivers/mtd/spi-nor/spi-nor.c for detail. Please also refer to spi-fsl-qspi.c when you want to write a new driver for a SPI NOR controller. -Another API is spi_nor_restore(), this is used to restore the status of SPI -flash chip such as addressing mode. Call it whenever detach the driver from -device or reboot the system. diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c index afb56b2cf8fe..75a7839af034 100644 --- a/drivers/mtd/spi-nor/core.c +++ b/drivers/mtd/spi-nor/core.c @@ -3291,7 +3291,7 @@ static void spi_nor_put_device(struct mtd_info *mtd) module_put(dev->driver->owner); } -void spi_nor_restore(struct spi_nor *nor) +static void spi_nor_restore(struct spi_nor *nor) { int ret; @@ -3311,7 +3311,6 @@ void spi_nor_restore(struct spi_nor *nor) if (nor->flags & SNOR_F_SOFT_RESET) spi_nor_soft_reset(nor); } -EXPORT_SYMBOL_GPL(spi_nor_restore); static const struct flash_info *spi_nor_match_name(struct spi_nor *nor, const char *name) diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h index 82547b4b3708..cdcfe0fd2e7d 100644 --- a/include/linux/mtd/spi-nor.h +++ b/include/linux/mtd/spi-nor.h @@ -450,10 +450,4 @@ static inline struct device_node *spi_nor_get_flash_node(struct spi_nor *nor) int spi_nor_scan(struct spi_nor *nor, const char *name, const struct spi_nor_hwcaps *hwcaps); -/** - * spi_nor_restore_addr_mode() - restore the status of SPI NOR - * @nor: the spi_nor structure - */ -void spi_nor_restore(struct spi_nor *nor); - #endif -- cgit v1.2.3 From 37513c56139b79dd43c1774513c28f8ab2b05224 Mon Sep 17 00:00:00 2001 From: Tudor Ambarus Date: Fri, 31 Mar 2023 07:46:04 +0000 Subject: mtd: spi-nor: core: Update flash's current address mode when changing address mode The bug was obswerved while reading code. There are not many users of addr_mode_nbytes. Anyway, we should update the flash's current address mode when changing the address mode, fix it. We don't care for now about the set_4byte_addr_mode(nor, false) from spi_nor_restore(), as it is used at driver remove and shutdown. Fixes: d7931a215063 ("mtd: spi-nor: core: Track flash's internal address mode") Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20230331074606.3559258-9-tudor.ambarus@linaro.org Signed-off-by: Tudor Ambarus --- drivers/mtd/spi-nor/core.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c index 75a7839af034..b20c690a24d7 100644 --- a/drivers/mtd/spi-nor/core.c +++ b/drivers/mtd/spi-nor/core.c @@ -3136,6 +3136,7 @@ static int spi_nor_quad_enable(struct spi_nor *nor) static int spi_nor_init(struct spi_nor *nor) { + struct spi_nor_flash_parameter *params = nor->params; int err; err = spi_nor_octal_dtr_enable(nor, true); @@ -3177,9 +3178,10 @@ static int spi_nor_init(struct spi_nor *nor) */ WARN_ONCE(nor->flags & SNOR_F_BROKEN_RESET, "enabling reset hack; may not recover from unexpected reboots\n"); - err = nor->params->set_4byte_addr_mode(nor, true); + err = params->set_4byte_addr_mode(nor, true); if (err && err != -ENOTSUPP) return err; + params->addr_mode_nbytes = 4; } return 0; -- cgit v1.2.3 From b6094ac83dd4fb4fa2849b804cc9fc1c70054852 Mon Sep 17 00:00:00 2001 From: Tudor Ambarus Date: Fri, 31 Mar 2023 07:46:05 +0000 Subject: mtd: spi-nor: core: Introduce spi_nor_set_4byte_addr_mode() Make the method public, as it will be used as a last resort to enable 4byte address mode when we can't determine the address mode at runtime. Update the addr_nbytes and current address mode while exiting the 4byte address mode too, as it may be used in the future by manufacturer drivers. No functional change. spi_nor_restore didn't update the address mode nbytes, but updating them now doesn't harm as the method is called in the driver's remove and shutdown paths. Link: https://lore.kernel.org/r/20230331074606.3559258-10-tudor.ambarus@linaro.org Signed-off-by: Tudor Ambarus --- drivers/mtd/spi-nor/core.c | 35 ++++++++++++++++++++++++++++++----- drivers/mtd/spi-nor/core.h | 1 + 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c index b20c690a24d7..1e30737b607b 100644 --- a/drivers/mtd/spi-nor/core.c +++ b/drivers/mtd/spi-nor/core.c @@ -3134,9 +3134,35 @@ static int spi_nor_quad_enable(struct spi_nor *nor) return nor->params->quad_enable(nor); } -static int spi_nor_init(struct spi_nor *nor) +/** + * spi_nor_set_4byte_addr_mode() - Set address mode. + * @nor: pointer to a 'struct spi_nor'. + * @enable: enable/disable 4 byte address mode. + * + * Return: 0 on success, -errno otherwise. + */ +int spi_nor_set_4byte_addr_mode(struct spi_nor *nor, bool enable) { struct spi_nor_flash_parameter *params = nor->params; + int ret; + + ret = params->set_4byte_addr_mode(nor, enable); + if (ret && ret != -ENOTSUPP) + return ret; + + if (enable) { + params->addr_nbytes = 4; + params->addr_mode_nbytes = 4; + } else { + params->addr_nbytes = 3; + params->addr_mode_nbytes = 3; + } + + return 0; +} + +static int spi_nor_init(struct spi_nor *nor) +{ int err; err = spi_nor_octal_dtr_enable(nor, true); @@ -3178,10 +3204,9 @@ static int spi_nor_init(struct spi_nor *nor) */ WARN_ONCE(nor->flags & SNOR_F_BROKEN_RESET, "enabling reset hack; may not recover from unexpected reboots\n"); - err = params->set_4byte_addr_mode(nor, true); - if (err && err != -ENOTSUPP) + err = spi_nor_set_4byte_addr_mode(nor, true); + if (err) return err; - params->addr_mode_nbytes = 4; } return 0; @@ -3300,7 +3325,7 @@ static void spi_nor_restore(struct spi_nor *nor) /* restore the addressing mode */ if (nor->addr_nbytes == 4 && !(nor->flags & SNOR_F_4B_OPCODES) && nor->flags & SNOR_F_BROKEN_RESET) { - ret = nor->params->set_4byte_addr_mode(nor, false); + ret = spi_nor_set_4byte_addr_mode(nor, false); if (ret) /* * Do not stop the execution in the hope that the flash diff --git a/drivers/mtd/spi-nor/core.h b/drivers/mtd/spi-nor/core.h index 8953ddeb8625..ea9033cb0a01 100644 --- a/drivers/mtd/spi-nor/core.h +++ b/drivers/mtd/spi-nor/core.h @@ -651,6 +651,7 @@ int spi_nor_set_4byte_addr_mode_en4b_ex4b(struct spi_nor *nor, bool enable); int spi_nor_set_4byte_addr_mode_wren_en4b_ex4b(struct spi_nor *nor, bool enable); int spi_nor_set_4byte_addr_mode_brwr(struct spi_nor *nor, bool enable); +int spi_nor_set_4byte_addr_mode(struct spi_nor *nor, bool enable); int spi_nor_wait_till_ready(struct spi_nor *nor); int spi_nor_global_block_unlock(struct spi_nor *nor); int spi_nor_prep_and_lock(struct spi_nor *nor); -- cgit v1.2.3 From c87c9b11c53cecab8e8a93290fa3b488e6838dab Mon Sep 17 00:00:00 2001 From: Takahiro Kuwano Date: Fri, 31 Mar 2023 07:46:06 +0000 Subject: mtd: spi-nor: spansion: Determine current address mode Internal address mode (3- or 4-byte) affects to the address length in Read Any Reg op. Read Any Reg op is used in SMPT parse and other setup functions. Current driver assumes that address mode is factory default but users can change it via volatile and non-volatile registers. Current address mode can be checked by CFR2V[7] but Read Any Reg op is needed to read CFR2V (chicken-and-egg). Introduce a way to determine current address mode by comparing status register 1 values read by different address length. Suggested-by: Tudor Ambarus Signed-off-by: Takahiro Kuwano Link: https://lore.kernel.org/r/20230331074606.3559258-11-tudor.ambarus@linaro.org Signed-off-by: Tudor Ambarus --- drivers/mtd/spi-nor/spansion.c | 131 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 128 insertions(+), 3 deletions(-) diff --git a/drivers/mtd/spi-nor/spansion.c b/drivers/mtd/spi-nor/spansion.c index 1678b7b2e9f7..352c40dd3864 100644 --- a/drivers/mtd/spi-nor/spansion.c +++ b/drivers/mtd/spi-nor/spansion.c @@ -14,10 +14,12 @@ #define SPINOR_OP_CLSR 0x30 /* Clear status register 1 */ #define SPINOR_OP_RD_ANY_REG 0x65 /* Read any register */ #define SPINOR_OP_WR_ANY_REG 0x71 /* Write any register */ +#define SPINOR_REG_CYPRESS_STR1V 0x00800000 #define SPINOR_REG_CYPRESS_CFR1V 0x00800002 #define SPINOR_REG_CYPRESS_CFR1_QUAD_EN BIT(1) /* Quad Enable */ #define SPINOR_REG_CYPRESS_CFR2V 0x00800003 #define SPINOR_REG_CYPRESS_CFR2_MEMLAT_11_24 0xb +#define SPINOR_REG_CYPRESS_CFR2_ADRBYT BIT(7) #define SPINOR_REG_CYPRESS_CFR3V 0x00800004 #define SPINOR_REG_CYPRESS_CFR3_PGSZ BIT(4) /* Page size. */ #define SPINOR_REG_CYPRESS_CFR5V 0x00800006 @@ -188,6 +190,117 @@ static int cypress_nor_quad_enable_volatile(struct spi_nor *nor) return 0; } +/** + * cypress_nor_determine_addr_mode_by_sr1() - Determine current address mode + * (3 or 4-byte) by querying status + * register 1 (SR1). + * @nor: pointer to a 'struct spi_nor' + * @addr_mode: ponter to a buffer where we return the determined + * address mode. + * + * This function tries to determine current address mode by comparing SR1 value + * from RDSR1(no address), RDAR(3-byte address), and RDAR(4-byte address). + * + * Return: 0 on success, -errno otherwise. + */ +static int cypress_nor_determine_addr_mode_by_sr1(struct spi_nor *nor, + u8 *addr_mode) +{ + struct spi_mem_op op = + CYPRESS_NOR_RD_ANY_REG_OP(3, SPINOR_REG_CYPRESS_STR1V, 0, + nor->bouncebuf); + bool is3byte, is4byte; + int ret; + + ret = spi_nor_read_sr(nor, &nor->bouncebuf[1]); + if (ret) + return ret; + + ret = spi_nor_read_any_reg(nor, &op, nor->reg_proto); + if (ret) + return ret; + + is3byte = (nor->bouncebuf[0] == nor->bouncebuf[1]); + + op = (struct spi_mem_op) + CYPRESS_NOR_RD_ANY_REG_OP(4, SPINOR_REG_CYPRESS_STR1V, 0, + nor->bouncebuf); + ret = spi_nor_read_any_reg(nor, &op, nor->reg_proto); + if (ret) + return ret; + + is4byte = (nor->bouncebuf[0] == nor->bouncebuf[1]); + + if (is3byte == is4byte) + return -EIO; + if (is3byte) + *addr_mode = 3; + else + *addr_mode = 4; + + return 0; +} + +/** + * cypress_nor_set_addr_mode_nbytes() - Set the number of address bytes mode of + * current address mode. + * @nor: pointer to a 'struct spi_nor' + * + * Determine current address mode by reading SR1 with different methods, then + * query CFR2V[7] to confirm. If determination is failed, force enter to 4-byte + * address mode. + * + * Return: 0 on success, -errno otherwise. + */ +static int cypress_nor_set_addr_mode_nbytes(struct spi_nor *nor) +{ + struct spi_mem_op op; + u8 addr_mode; + int ret; + + /* + * Read SR1 by RDSR1 and RDAR(3- AND 4-byte addr). Use write enable + * that sets bit-1 in SR1. + */ + ret = spi_nor_write_enable(nor); + if (ret) + return ret; + ret = cypress_nor_determine_addr_mode_by_sr1(nor, &addr_mode); + if (ret) { + ret = spi_nor_set_4byte_addr_mode(nor, true); + if (ret) + return ret; + return spi_nor_write_disable(nor); + } + ret = spi_nor_write_disable(nor); + if (ret) + return ret; + + /* + * Query CFR2V and make sure no contradiction between determined address + * mode and CFR2V[7]. + */ + op = (struct spi_mem_op) + CYPRESS_NOR_RD_ANY_REG_OP(addr_mode, SPINOR_REG_CYPRESS_CFR2V, + 0, nor->bouncebuf); + ret = spi_nor_read_any_reg(nor, &op, nor->reg_proto); + if (ret) + return ret; + + if (nor->bouncebuf[0] & SPINOR_REG_CYPRESS_CFR2_ADRBYT) { + if (addr_mode != 4) + return spi_nor_set_4byte_addr_mode(nor, true); + } else { + if (addr_mode != 3) + return spi_nor_set_4byte_addr_mode(nor, true); + } + + nor->params->addr_nbytes = addr_mode; + nor->params->addr_mode_nbytes = addr_mode; + + return 0; +} + /** * cypress_nor_set_page_size() - Set page size which corresponds to the flash * configuration. @@ -227,9 +340,9 @@ s25fs256t_post_bfpt_fixup(struct spi_nor *nor, struct spi_mem_op op; int ret; - /* 4-byte address mode is enabled by default */ - nor->params->addr_nbytes = 4; - nor->params->addr_mode_nbytes = 4; + ret = cypress_nor_set_addr_mode_nbytes(nor); + if (ret) + return ret; /* Read Architecture Configuration Register (ARCFN) */ op = (struct spi_mem_op) @@ -280,6 +393,12 @@ s25hx_t_post_bfpt_fixup(struct spi_nor *nor, const struct sfdp_parameter_header *bfpt_header, const struct sfdp_bfpt *bfpt) { + int ret; + + ret = cypress_nor_set_addr_mode_nbytes(nor); + if (ret) + return ret; + /* Replace Quad Enable with volatile version */ nor->params->quad_enable = cypress_nor_quad_enable_volatile; @@ -375,6 +494,12 @@ static int s28hx_t_post_bfpt_fixup(struct spi_nor *nor, const struct sfdp_parameter_header *bfpt_header, const struct sfdp_bfpt *bfpt) { + int ret; + + ret = cypress_nor_set_addr_mode_nbytes(nor); + if (ret) + return ret; + return cypress_nor_set_page_size(nor); } -- cgit v1.2.3 From 9fd0945fe6fadfb6b54a9cd73be101c02b3e8134 Mon Sep 17 00:00:00 2001 From: Takahiro Kuwano Date: Thu, 6 Apr 2023 15:17:44 +0900 Subject: mtd: spi-nor: spansion: Enable JFFS2 write buffer for Infineon s28hx SEMPER flash Infineon(Cypress) SEMPER NOR flash family has on-die ECC and its program granularity is 16-byte ECC data unit size. JFFS2 supports write buffer mode for ECC'd NOR flash. Provide a way to clear the MTD_BIT_WRITEABLE flag in order to enable JFFS2 write buffer mode support. A new SNOR_F_ECC flag is introduced to determine if the part has on-die ECC and if it has, MTD_BIT_WRITEABLE is unset. In vendor specific driver, a common cypress_nor_ecc_init() helper is added. This helper takes care for ECC related initialization for SEMPER flash family by setting up params->writesize and SNOR_F_ECC. Fixes: c3266af101f2 ("mtd: spi-nor: spansion: add support for Cypress Semper flash") Suggested-by: Tudor Ambarus Signed-off-by: Takahiro Kuwano Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/d586723f6f12aaff44fbcd7b51e674b47ed554ed.1680760742.git.Takahiro.Kuwano@infineon.com Signed-off-by: Tudor Ambarus --- drivers/mtd/spi-nor/core.c | 3 +++ drivers/mtd/spi-nor/core.h | 1 + drivers/mtd/spi-nor/debugfs.c | 1 + drivers/mtd/spi-nor/spansion.c | 13 ++++++++++++- 4 files changed, 17 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c index 1e30737b607b..143ca3c9b477 100644 --- a/drivers/mtd/spi-nor/core.c +++ b/drivers/mtd/spi-nor/core.c @@ -3407,6 +3407,9 @@ static void spi_nor_set_mtd_info(struct spi_nor *nor) mtd->name = dev_name(dev); mtd->type = MTD_NORFLASH; mtd->flags = MTD_CAP_NORFLASH; + /* Unset BIT_WRITEABLE to enable JFFS2 write buffer for ECC'd NOR */ + if (nor->flags & SNOR_F_ECC) + mtd->flags &= ~MTD_BIT_WRITEABLE; if (nor->info->flags & SPI_NOR_NO_ERASE) mtd->flags |= MTD_NO_ERASE; else diff --git a/drivers/mtd/spi-nor/core.h b/drivers/mtd/spi-nor/core.h index ea9033cb0a01..8cfa82ed06c7 100644 --- a/drivers/mtd/spi-nor/core.h +++ b/drivers/mtd/spi-nor/core.h @@ -131,6 +131,7 @@ enum spi_nor_option_flags { SNOR_F_SOFT_RESET = BIT(12), SNOR_F_SWP_IS_VOLATILE = BIT(13), SNOR_F_RWW = BIT(14), + SNOR_F_ECC = BIT(15), }; struct spi_nor_read_command { diff --git a/drivers/mtd/spi-nor/debugfs.c b/drivers/mtd/spi-nor/debugfs.c index e200f5b9234c..082c0c5a8626 100644 --- a/drivers/mtd/spi-nor/debugfs.c +++ b/drivers/mtd/spi-nor/debugfs.c @@ -26,6 +26,7 @@ static const char *const snor_f_names[] = { SNOR_F_NAME(SOFT_RESET), SNOR_F_NAME(SWP_IS_VOLATILE), SNOR_F_NAME(RWW), + SNOR_F_NAME(ECC), }; #undef SNOR_F_NAME diff --git a/drivers/mtd/spi-nor/spansion.c b/drivers/mtd/spi-nor/spansion.c index 352c40dd3864..19b1436f36ea 100644 --- a/drivers/mtd/spi-nor/spansion.c +++ b/drivers/mtd/spi-nor/spansion.c @@ -332,6 +332,17 @@ static int cypress_nor_set_page_size(struct spi_nor *nor) return 0; } +static void cypress_nor_ecc_init(struct spi_nor *nor) +{ + /* + * Programming is supported only in 16-byte ECC data unit granularity. + * Byte-programming, bit-walking, or multiple program operations to the + * same ECC data unit without an erase are not allowed. + */ + nor->params->writesize = 16; + nor->flags |= SNOR_F_ECC; +} + static int s25fs256t_post_bfpt_fixup(struct spi_nor *nor, const struct sfdp_parameter_header *bfpt_header, @@ -506,7 +517,7 @@ static int s28hx_t_post_bfpt_fixup(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; + cypress_nor_ecc_init(nor); } static const struct spi_nor_fixups s28hx_t_fixups = { -- cgit v1.2.3 From 4199c1719e24e73be0acc8b0146fc31ad8af9771 Mon Sep 17 00:00:00 2001 From: Takahiro Kuwano Date: Thu, 6 Apr 2023 15:17:45 +0900 Subject: mtd: spi-nor: spansion: Enable JFFS2 write buffer for Infineon s25hx SEMPER flash Infineon(Cypress) SEMPER NOR flash family has on-die ECC and its program granularity is 16-byte ECC data unit size. JFFS2 supports write buffer mode for ECC'd NOR flash. Provide a way to clear the MTD_BIT_WRITEABLE flag in order to enable JFFS2 write buffer mode support. Fixes: b6b23833fc42 ("mtd: spi-nor: spansion: Add s25hl-t/s25hs-t IDs and fixups") Suggested-by: Tudor Ambarus Signed-off-by: Takahiro Kuwano Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/a1cc128e094db4ec141f85bd380127598dfef17e.1680760742.git.Takahiro.Kuwano@infineon.com Signed-off-by: Tudor Ambarus --- drivers/mtd/spi-nor/spansion.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/mtd/spi-nor/spansion.c b/drivers/mtd/spi-nor/spansion.c index 19b1436f36ea..4d0cc10e3d85 100644 --- a/drivers/mtd/spi-nor/spansion.c +++ b/drivers/mtd/spi-nor/spansion.c @@ -442,13 +442,10 @@ static void s25hx_t_post_sfdp_fixup(struct spi_nor *nor) static void s25hx_t_late_init(struct spi_nor *nor) { - struct spi_nor_flash_parameter *params = nor->params; - /* Fast Read 4B requires mode cycles */ - params->reads[SNOR_CMD_READ_FAST].num_mode_clocks = 8; + nor->params->reads[SNOR_CMD_READ_FAST].num_mode_clocks = 8; - /* The writesize should be ECC data unit size */ - params->writesize = 16; + cypress_nor_ecc_init(nor); } static struct spi_nor_fixups s25hx_t_fixups = { -- cgit v1.2.3 From a9180c298d3527f43563d02a62cb9e7e145642c6 Mon Sep 17 00:00:00 2001 From: Takahiro Kuwano Date: Thu, 6 Apr 2023 15:17:46 +0900 Subject: mtd: spi-nor: spansion: Enable JFFS2 write buffer for S25FS256T Infineon(Cypress) SEMPER NOR flash family has on-die ECC and its program granularity is 16-byte ECC data unit size. JFFS2 supports write buffer mode for ECC'd NOR flash. Provide a way to clear the MTD_BIT_WRITEABLE flag in order to enable JFFS2 write buffer mode support. Drop the comment as the same info is now specified in cypress_nor_ecc_init(). Fixes: 6afcc84080c4 ("mtd: spi-nor: spansion: Add support for Infineon S25FS256T") Suggested-by: Tudor Ambarus Signed-off-by: Takahiro Kuwano Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/641bfb26c6e059915ae920117b7ec278df1a6f0a.1680760742.git.Takahiro.Kuwano@infineon.com Signed-off-by: Tudor Ambarus --- drivers/mtd/spi-nor/spansion.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/mtd/spi-nor/spansion.c b/drivers/mtd/spi-nor/spansion.c index 4d0cc10e3d85..ffeede78700d 100644 --- a/drivers/mtd/spi-nor/spansion.c +++ b/drivers/mtd/spi-nor/spansion.c @@ -384,13 +384,7 @@ static void s25fs256t_post_sfdp_fixup(struct spi_nor *nor) static void s25fs256t_late_init(struct spi_nor *nor) { - /* - * Programming is supported only in 16-byte ECC data unit granularity. - * Byte-programming, bit-walking, or multiple program operations to the - * same ECC data unit without an erase are not allowed. See chapter - * 5.3.1 and 5.6 in the datasheet. - */ - nor->params->writesize = 16; + cypress_nor_ecc_init(nor); } static struct spi_nor_fixups s25fs256t_fixups = { -- cgit v1.2.3 From 120c94a67b26e4014597fc9f872803621e7a2514 Mon Sep 17 00:00:00 2001 From: Tudor Ambarus Date: Fri, 7 Apr 2023 15:40:57 +0900 Subject: mtd: spi-nor: spansion: Rename method to cypress_nor_get_page_size The method queries SPINOR_REG_CYPRESS_CFR3V to determine the page size. Rename the method accordingly, s/set/get. Link: https://lore.kernel.org/r/cd3fb2cbc42a9576377ce4506eec72a58240805d.1680849425.git.Takahiro.Kuwano@infineon.com Signed-off-by: Tudor Ambarus --- drivers/mtd/spi-nor/spansion.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/mtd/spi-nor/spansion.c b/drivers/mtd/spi-nor/spansion.c index ffeede78700d..c937f0ac61de 100644 --- a/drivers/mtd/spi-nor/spansion.c +++ b/drivers/mtd/spi-nor/spansion.c @@ -302,8 +302,7 @@ static int cypress_nor_set_addr_mode_nbytes(struct spi_nor *nor) } /** - * cypress_nor_set_page_size() - Set page size which corresponds to the flash - * configuration. + * cypress_nor_get_page_size() - Get flash page size configuration. * @nor: pointer to a 'struct spi_nor' * * The BFPT table advertises a 512B or 256B page size depending on part but the @@ -312,7 +311,7 @@ static int cypress_nor_set_addr_mode_nbytes(struct spi_nor *nor) * * Return: 0 on success, -errno otherwise. */ -static int cypress_nor_set_page_size(struct spi_nor *nor) +static int cypress_nor_get_page_size(struct spi_nor *nor) { struct spi_mem_op op = CYPRESS_NOR_RD_ANY_REG_OP(nor->params->addr_mode_nbytes, @@ -368,7 +367,7 @@ s25fs256t_post_bfpt_fixup(struct spi_nor *nor, if (nor->bouncebuf[0]) return -ENODEV; - return cypress_nor_set_page_size(nor); + return cypress_nor_get_page_size(nor); } static void s25fs256t_post_sfdp_fixup(struct spi_nor *nor) @@ -407,7 +406,7 @@ s25hx_t_post_bfpt_fixup(struct spi_nor *nor, /* Replace Quad Enable with volatile version */ nor->params->quad_enable = cypress_nor_quad_enable_volatile; - return cypress_nor_set_page_size(nor); + return cypress_nor_get_page_size(nor); } static void s25hx_t_post_sfdp_fixup(struct spi_nor *nor) @@ -502,7 +501,7 @@ static int s28hx_t_post_bfpt_fixup(struct spi_nor *nor, if (ret) return ret; - return cypress_nor_set_page_size(nor); + return cypress_nor_get_page_size(nor); } static void s28hx_t_late_init(struct spi_nor *nor) -- cgit v1.2.3 From e570f7872a34dc290014c80c7bad365d6577836b Mon Sep 17 00:00:00 2001 From: Tudor Ambarus Date: Fri, 7 Apr 2023 15:40:58 +0900 Subject: mtd: spi-nor: Allow post_sfdp hook to return errors Multi die flashes like s25hl02gt need to determine the page_size at run-time by querying a configuration register for each die. Since the number of dice is determined in an optional SFDP table, SCCR MC, the page size configuration must be done in the post_sfdp hook. Allow post_sfdp to return errors, as reading the configuration register might return errors. Link: https://lore.kernel.org/r/924ab710f128448ec62537cfbb377336e390043c.1680849425.git.Takahiro.Kuwano@infineon.com Signed-off-by: Tudor Ambarus --- drivers/mtd/spi-nor/core.h | 2 +- drivers/mtd/spi-nor/micron-st.c | 4 +++- drivers/mtd/spi-nor/sfdp.c | 17 ++++++++++++----- drivers/mtd/spi-nor/spansion.c | 12 +++++++++--- 4 files changed, 25 insertions(+), 10 deletions(-) diff --git a/drivers/mtd/spi-nor/core.h b/drivers/mtd/spi-nor/core.h index 8cfa82ed06c7..a9e5e091547d 100644 --- a/drivers/mtd/spi-nor/core.h +++ b/drivers/mtd/spi-nor/core.h @@ -426,7 +426,7 @@ struct spi_nor_fixups { int (*post_bfpt)(struct spi_nor *nor, const struct sfdp_parameter_header *bfpt_header, const struct sfdp_bfpt *bfpt); - void (*post_sfdp)(struct spi_nor *nor); + int (*post_sfdp)(struct spi_nor *nor); void (*late_init)(struct spi_nor *nor); }; diff --git a/drivers/mtd/spi-nor/micron-st.c b/drivers/mtd/spi-nor/micron-st.c index a6f080112a51..4b919756a205 100644 --- a/drivers/mtd/spi-nor/micron-st.c +++ b/drivers/mtd/spi-nor/micron-st.c @@ -131,7 +131,7 @@ static void mt35xu512aba_default_init(struct spi_nor *nor) nor->params->octal_dtr_enable = micron_st_nor_octal_dtr_enable; } -static void mt35xu512aba_post_sfdp_fixup(struct spi_nor *nor) +static int mt35xu512aba_post_sfdp_fixup(struct spi_nor *nor) { /* Set the Fast Read settings. */ nor->params->hwcaps.mask |= SNOR_HWCAPS_READ_8_8_8_DTR; @@ -149,6 +149,8 @@ static void mt35xu512aba_post_sfdp_fixup(struct spi_nor *nor) * disable it. */ nor->params->quad_enable = NULL; + + return 0; } static const struct spi_nor_fixups mt35xu512aba_fixups = { diff --git a/drivers/mtd/spi-nor/sfdp.c b/drivers/mtd/spi-nor/sfdp.c index 69e47c9778a2..e184b67f3c9f 100644 --- a/drivers/mtd/spi-nor/sfdp.c +++ b/drivers/mtd/spi-nor/sfdp.c @@ -1260,14 +1260,21 @@ out: * Used to tweak various flash parameters when information provided by the SFDP * tables are wrong. */ -static void spi_nor_post_sfdp_fixups(struct spi_nor *nor) +static int spi_nor_post_sfdp_fixups(struct spi_nor *nor) { + int ret; + if (nor->manufacturer && nor->manufacturer->fixups && - nor->manufacturer->fixups->post_sfdp) - nor->manufacturer->fixups->post_sfdp(nor); + nor->manufacturer->fixups->post_sfdp) { + ret = nor->manufacturer->fixups->post_sfdp(nor); + if (ret) + return ret; + } if (nor->info->fixups && nor->info->fixups->post_sfdp) - nor->info->fixups->post_sfdp(nor); + return nor->info->fixups->post_sfdp(nor); + + return 0; } /** @@ -1477,7 +1484,7 @@ int spi_nor_parse_sfdp(struct spi_nor *nor) } } - spi_nor_post_sfdp_fixups(nor); + err = spi_nor_post_sfdp_fixups(nor); exit: kfree(param_headers); return err; diff --git a/drivers/mtd/spi-nor/spansion.c b/drivers/mtd/spi-nor/spansion.c index c937f0ac61de..519fdad79a19 100644 --- a/drivers/mtd/spi-nor/spansion.c +++ b/drivers/mtd/spi-nor/spansion.c @@ -370,7 +370,7 @@ s25fs256t_post_bfpt_fixup(struct spi_nor *nor, return cypress_nor_get_page_size(nor); } -static void s25fs256t_post_sfdp_fixup(struct spi_nor *nor) +static int s25fs256t_post_sfdp_fixup(struct spi_nor *nor) { struct spi_nor_flash_parameter *params = nor->params; @@ -379,6 +379,8 @@ static void s25fs256t_post_sfdp_fixup(struct spi_nor *nor) spi_nor_set_pp_settings(¶ms->page_programs[SNOR_CMD_PP_1_1_4], SPINOR_OP_PP_1_1_4_4B, SNOR_PROTO_1_1_4); + + return 0; } static void s25fs256t_late_init(struct spi_nor *nor) @@ -409,7 +411,7 @@ s25hx_t_post_bfpt_fixup(struct spi_nor *nor, return cypress_nor_get_page_size(nor); } -static void s25hx_t_post_sfdp_fixup(struct spi_nor *nor) +static int s25hx_t_post_sfdp_fixup(struct spi_nor *nor) { struct spi_nor_erase_type *erase_type = nor->params->erase_map.erase_type; @@ -431,6 +433,8 @@ static void s25hx_t_post_sfdp_fixup(struct spi_nor *nor) break; } } + + return 0; } static void s25hx_t_late_init(struct spi_nor *nor) @@ -463,7 +467,7 @@ static int cypress_nor_octal_dtr_enable(struct spi_nor *nor, bool enable) cypress_nor_octal_dtr_dis(nor); } -static void s28hx_t_post_sfdp_fixup(struct spi_nor *nor) +static int s28hx_t_post_sfdp_fixup(struct spi_nor *nor) { /* * On older versions of the flash the xSPI Profile 1.0 table has the @@ -489,6 +493,8 @@ static void s28hx_t_post_sfdp_fixup(struct spi_nor *nor) * actual value for that is 4. */ nor->params->rdsr_addr_nbytes = 4; + + return 0; } static int s28hx_t_post_bfpt_fixup(struct spi_nor *nor, -- cgit v1.2.3 From 706fd00da031e24572216dc650d77111afc2501a Mon Sep 17 00:00:00 2001 From: Takahiro Kuwano Date: Fri, 7 Apr 2023 15:40:59 +0900 Subject: mtd: spi-nor: Extract volatile register offset from SCCR map In use of multi-chip devices, we need to access registers in each die for configuration and status check. The number of dice in the device and volatile register offsets for each die are essential to iterate register access ops. The volatile register offset for the first die resides in the 1st DWORD of SCCR map. Allocate the table and copy the offset value. The table may be allocated when the SCCR map for multi-chip is parsed. Since we cannot assume SCCR parse is always in ahead of SCCR multi-chip, we need to check if the table is already allocated or not. Signed-off-by: Takahiro Kuwano Link: https://lore.kernel.org/r/e2cc39ad6e0e02dd8288c4def9bb201a3f564425.1680849425.git.Takahiro.Kuwano@infineon.com Signed-off-by: Tudor Ambarus --- drivers/mtd/spi-nor/core.h | 4 ++++ drivers/mtd/spi-nor/sfdp.c | 13 +++++++++++++ 2 files changed, 17 insertions(+) diff --git a/drivers/mtd/spi-nor/core.h b/drivers/mtd/spi-nor/core.h index a9e5e091547d..fd61c4793a10 100644 --- a/drivers/mtd/spi-nor/core.h +++ b/drivers/mtd/spi-nor/core.h @@ -352,6 +352,8 @@ struct spi_nor_otp { * in octal DTR mode. * @rdsr_addr_nbytes: dummy address bytes needed for Read Status Register * command in octal DTR mode. + * @n_dice: number of dice in the flash memory. + * @vreg_offset: volatile register offset for each die. * @hwcaps: describes the read and page program hardware * capabilities. * @reads: read capabilities ordered by priority: the higher index @@ -385,6 +387,8 @@ struct spi_nor_flash_parameter { u8 addr_mode_nbytes; u8 rdsr_dummy; u8 rdsr_addr_nbytes; + u8 n_dice; + u32 *vreg_offset; struct spi_nor_hwcaps hwcaps; struct spi_nor_read_command reads[SNOR_CMD_READ_MAX]; diff --git a/drivers/mtd/spi-nor/sfdp.c b/drivers/mtd/spi-nor/sfdp.c index e184b67f3c9f..9d43e18d3770 100644 --- a/drivers/mtd/spi-nor/sfdp.c +++ b/drivers/mtd/spi-nor/sfdp.c @@ -1226,6 +1226,7 @@ out: static int spi_nor_parse_sccr(struct spi_nor *nor, const struct sfdp_parameter_header *sccr_header) { + struct spi_nor_flash_parameter *params = nor->params; u32 *dwords, addr; size_t len; int ret; @@ -1242,6 +1243,18 @@ static int spi_nor_parse_sccr(struct spi_nor *nor, le32_to_cpu_array(dwords, sccr_header->length); + /* Address offset for volatile registers (die 0) */ + if (!params->vreg_offset) { + params->vreg_offset = devm_kmalloc(nor->dev, sizeof(*dwords), + GFP_KERNEL); + if (!params->vreg_offset) { + ret = -ENOMEM; + goto out; + } + } + params->vreg_offset[0] = dwords[SFDP_DWORD(1)]; + params->n_dice = 1; + if (FIELD_GET(SCCR_DWORD22_OCTAL_DTR_EN_VOLATILE, dwords[SFDP_DWORD(22)])) nor->flags |= SNOR_F_IO_MODE_EN_VOLATILE; -- cgit v1.2.3 From 7ab8b810757a32b083c75a61b5638bca82e17a4c Mon Sep 17 00:00:00 2001 From: Takahiro Kuwano Date: Fri, 7 Apr 2023 15:41:00 +0900 Subject: mtd: spi-nor: sfdp: Add support for SCCR map for multi-chip device SCCR map for multi-chip devices contains the number of additional dice in the device and register offset values for each additional dice. spi_nor_parse_sccr_mc() is added to determine the number of dice and volatile register offset for each die. The volatile register offset table may already be allocated and contains offset value for die-0 via SCCR map parse. So, we should use devm_krealloc() to expand the table with preserving die-0 offset. Signed-off-by: Takahiro Kuwano Link: https://lore.kernel.org/r/89c892d52f8cbddbd14373f6a02db496885ae4f1.1680849425.git.Takahiro.Kuwano@infineon.com Signed-off-by: Tudor Ambarus --- drivers/mtd/spi-nor/sfdp.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/drivers/mtd/spi-nor/sfdp.c b/drivers/mtd/spi-nor/sfdp.c index 9d43e18d3770..b3b11dfed789 100644 --- a/drivers/mtd/spi-nor/sfdp.c +++ b/drivers/mtd/spi-nor/sfdp.c @@ -26,6 +26,11 @@ * Status, Control and Configuration * Register Map. */ +#define SFDP_SCCR_MAP_MC_ID 0xff88 /* + * Status, Control and Configuration + * Register Map Offsets for Multi-Chip + * SPI Memory Devices. + */ #define SFDP_SIGNATURE 0x50444653U @@ -1264,6 +1269,63 @@ out: return ret; } +/** + * spi_nor_parse_sccr_mc() - Parse the Status, Control and Configuration + * Register Map Offsets for Multi-Chip SPI Memory + * Devices. + * @nor: pointer to a 'struct spi_nor' + * @sccr_mc_header: pointer to the 'struct sfdp_parameter_header' describing + * the SCCR Map offsets table length and version. + * + * Return: 0 on success, -errno otherwise. + */ +static int spi_nor_parse_sccr_mc(struct spi_nor *nor, + const struct sfdp_parameter_header *sccr_mc_header) +{ + struct spi_nor_flash_parameter *params = nor->params; + u32 *dwords, addr; + u8 i, n_dice; + size_t len; + int ret; + + len = sccr_mc_header->length * sizeof(*dwords); + dwords = kmalloc(len, GFP_KERNEL); + if (!dwords) + return -ENOMEM; + + addr = SFDP_PARAM_HEADER_PTP(sccr_mc_header); + ret = spi_nor_read_sfdp(nor, addr, len, dwords); + if (ret) + goto out; + + le32_to_cpu_array(dwords, sccr_mc_header->length); + + /* + * Pair of DOWRDs (volatile and non-volatile register offsets) per + * additional die. Hence, length = 2 * (number of additional dice). + */ + n_dice = 1 + sccr_mc_header->length / 2; + + /* Address offset for volatile registers of additional dice */ + params->vreg_offset = + devm_krealloc(nor->dev, params->vreg_offset, + n_dice * sizeof(*dwords), + GFP_KERNEL); + if (!params->vreg_offset) { + ret = -ENOMEM; + goto out; + } + + for (i = 1; i < n_dice; i++) + params->vreg_offset[i] = dwords[SFDP_DWORD(i) * 2]; + + params->n_dice = n_dice; + +out: + kfree(dwords); + return ret; +} + /** * spi_nor_post_sfdp_fixups() - Updates the flash's parameters and settings * after SFDP has been parsed. Called only for flashes that define JESD216 SFDP @@ -1480,6 +1542,10 @@ int spi_nor_parse_sfdp(struct spi_nor *nor) err = spi_nor_parse_sccr(nor, param_header); break; + case SFDP_SCCR_MAP_MC_ID: + err = spi_nor_parse_sccr_mc(nor, param_header); + break; + default: break; } -- cgit v1.2.3 From 6c01ae11130ccb5f16e90ab0605198d25b7c1efa Mon Sep 17 00:00:00 2001 From: Takahiro Kuwano Date: Fri, 7 Apr 2023 15:41:01 +0900 Subject: mtd: spi-nor: spansion: Rework cypress_nor_get_page_size() for multi-chip device support For multi-chip devices, we can use 512B page only when the all dice are configured as 512B page size. The volatile register address is calculated by using the volatile register addresses retrieved from the SCCR tables and the (configuration) register offset. The location of cypress_nor_set_page_size() call is moved from post_bfpt_fixup() to post_sfdp_fixup(), because the number of dice and volatile register offset are parsed in the optional SCCR tables. Signed-off-by: Takahiro Kuwano Link: https://lore.kernel.org/r/6f8272f3e877dee392742d2c8401c4aed57e6d83.1680849425.git.Takahiro.Kuwano@infineon.com Signed-off-by: Tudor Ambarus --- drivers/mtd/spi-nor/spansion.c | 89 ++++++++++++++++++++++++++++++++---------- 1 file changed, 69 insertions(+), 20 deletions(-) diff --git a/drivers/mtd/spi-nor/spansion.c b/drivers/mtd/spi-nor/spansion.c index 519fdad79a19..5e021e20497b 100644 --- a/drivers/mtd/spi-nor/spansion.c +++ b/drivers/mtd/spi-nor/spansion.c @@ -14,15 +14,26 @@ #define SPINOR_OP_CLSR 0x30 /* Clear status register 1 */ #define SPINOR_OP_RD_ANY_REG 0x65 /* Read any register */ #define SPINOR_OP_WR_ANY_REG 0x71 /* Write any register */ -#define SPINOR_REG_CYPRESS_STR1V 0x00800000 -#define SPINOR_REG_CYPRESS_CFR1V 0x00800002 +#define SPINOR_REG_CYPRESS_VREG 0x00800000 +#define SPINOR_REG_CYPRESS_STR1 0x0 +#define SPINOR_REG_CYPRESS_STR1V \ + (SPINOR_REG_CYPRESS_VREG + SPINOR_REG_CYPRESS_STR1) +#define SPINOR_REG_CYPRESS_CFR1 0x2 +#define SPINOR_REG_CYPRESS_CFR1V \ + (SPINOR_REG_CYPRESS_VREG + SPINOR_REG_CYPRESS_CFR1) #define SPINOR_REG_CYPRESS_CFR1_QUAD_EN BIT(1) /* Quad Enable */ -#define SPINOR_REG_CYPRESS_CFR2V 0x00800003 +#define SPINOR_REG_CYPRESS_CFR2 0x3 +#define SPINOR_REG_CYPRESS_CFR2V \ + (SPINOR_REG_CYPRESS_VREG + SPINOR_REG_CYPRESS_CFR2) #define SPINOR_REG_CYPRESS_CFR2_MEMLAT_11_24 0xb #define SPINOR_REG_CYPRESS_CFR2_ADRBYT BIT(7) -#define SPINOR_REG_CYPRESS_CFR3V 0x00800004 +#define SPINOR_REG_CYPRESS_CFR3 0x4 +#define SPINOR_REG_CYPRESS_CFR3V \ + (SPINOR_REG_CYPRESS_VREG + SPINOR_REG_CYPRESS_CFR3) #define SPINOR_REG_CYPRESS_CFR3_PGSZ BIT(4) /* Page size. */ -#define SPINOR_REG_CYPRESS_CFR5V 0x00800006 +#define SPINOR_REG_CYPRESS_CFR5 0x6 +#define SPINOR_REG_CYPRESS_CFR5V \ + (SPINOR_REG_CYPRESS_VREG + SPINOR_REG_CYPRESS_CFR5) #define SPINOR_REG_CYPRESS_CFR5_BIT6 BIT(6) #define SPINOR_REG_CYPRESS_CFR5_DDR BIT(1) #define SPINOR_REG_CYPRESS_CFR5_OPI BIT(0) @@ -301,17 +312,7 @@ static int cypress_nor_set_addr_mode_nbytes(struct spi_nor *nor) return 0; } -/** - * cypress_nor_get_page_size() - Get flash page size configuration. - * @nor: pointer to a 'struct spi_nor' - * - * The BFPT table advertises a 512B or 256B page size depending on part but the - * page size is actually configurable (with the default being 256B). Read from - * CFR3V[4] and set the correct size. - * - * Return: 0 on success, -errno otherwise. - */ -static int cypress_nor_get_page_size(struct spi_nor *nor) +static int cypress_nor_get_page_size_single_chip(struct spi_nor *nor) { struct spi_mem_op op = CYPRESS_NOR_RD_ANY_REG_OP(nor->params->addr_mode_nbytes, @@ -331,6 +332,54 @@ static int cypress_nor_get_page_size(struct spi_nor *nor) return 0; } + +static int cypress_nor_get_page_size_mcp(struct spi_nor *nor) +{ + struct spi_mem_op op = + CYPRESS_NOR_RD_ANY_REG_OP(nor->params->addr_mode_nbytes, + 0, 0, nor->bouncebuf); + struct spi_nor_flash_parameter *params = nor->params; + int ret; + u8 i; + + /* + * Use the minimum common page size configuration. Programming 256-byte + * under 512-byte page size configuration is safe. + */ + params->page_size = 256; + for (i = 0; i < params->n_dice; i++) { + op.addr.val = params->vreg_offset[i] + SPINOR_REG_CYPRESS_CFR3; + + ret = spi_nor_read_any_reg(nor, &op, nor->reg_proto); + if (ret) + return ret; + + if (!(nor->bouncebuf[0] & SPINOR_REG_CYPRESS_CFR3_PGSZ)) + return 0; + } + + params->page_size = 512; + + return 0; +} + +/** + * cypress_nor_get_page_size() - Get flash page size configuration. + * @nor: pointer to a 'struct spi_nor' + * + * The BFPT table advertises a 512B or 256B page size depending on part but the + * page size is actually configurable (with the default being 256B). Read from + * CFR3V[4] and set the correct size. + * + * Return: 0 on success, -errno otherwise. + */ +static int cypress_nor_get_page_size(struct spi_nor *nor) +{ + if (nor->params->n_dice) + return cypress_nor_get_page_size_mcp(nor); + return cypress_nor_get_page_size_single_chip(nor); +} + static void cypress_nor_ecc_init(struct spi_nor *nor) { /* @@ -408,7 +457,7 @@ s25hx_t_post_bfpt_fixup(struct spi_nor *nor, /* Replace Quad Enable with volatile version */ nor->params->quad_enable = cypress_nor_quad_enable_volatile; - return cypress_nor_get_page_size(nor); + return 0; } static int s25hx_t_post_sfdp_fixup(struct spi_nor *nor) @@ -434,7 +483,7 @@ static int s25hx_t_post_sfdp_fixup(struct spi_nor *nor) } } - return 0; + return cypress_nor_get_page_size(nor); } static void s25hx_t_late_init(struct spi_nor *nor) @@ -494,7 +543,7 @@ static int s28hx_t_post_sfdp_fixup(struct spi_nor *nor) */ nor->params->rdsr_addr_nbytes = 4; - return 0; + return cypress_nor_get_page_size(nor); } static int s28hx_t_post_bfpt_fixup(struct spi_nor *nor, @@ -507,7 +556,7 @@ static int s28hx_t_post_bfpt_fixup(struct spi_nor *nor, if (ret) return ret; - return cypress_nor_get_page_size(nor); + return 0; } static void s28hx_t_late_init(struct spi_nor *nor) -- cgit v1.2.3 From f24d423a5c4fbcd9789ad54454f7c805798a597a Mon Sep 17 00:00:00 2001 From: Takahiro Kuwano Date: Fri, 7 Apr 2023 15:41:02 +0900 Subject: mtd: spi-nor: spansion: Rework cypress_nor_quad_enable_volatile() for multi-chip device support Rework quad method for multi-chip devices by updating CFR1V in all dice in the device. Signed-off-by: Takahiro Kuwano Link: https://lore.kernel.org/r/1b5606dbcc11b3432c306a75880f05c68e927fb9.1680849425.git.Takahiro.Kuwano@infineon.com Signed-off-by: Tudor Ambarus --- drivers/mtd/spi-nor/spansion.c | 60 +++++++++++++++++++++++++++--------------- 1 file changed, 39 insertions(+), 21 deletions(-) diff --git a/drivers/mtd/spi-nor/spansion.c b/drivers/mtd/spi-nor/spansion.c index 5e021e20497b..91bc0aace516 100644 --- a/drivers/mtd/spi-nor/spansion.c +++ b/drivers/mtd/spi-nor/spansion.c @@ -139,21 +139,7 @@ static int cypress_nor_octal_dtr_dis(struct spi_nor *nor) return 0; } -/** - * cypress_nor_quad_enable_volatile() - enable Quad I/O mode in volatile - * register. - * @nor: pointer to a 'struct spi_nor' - * - * It is recommended to update volatile registers in the field application due - * to a risk of the non-volatile registers corruption by power interrupt. This - * function sets Quad Enable bit in CFR1 volatile. If users set the Quad Enable - * bit in the CFR1 non-volatile in advance (typically by a Flash programmer - * before mounting Flash on PCB), the Quad Enable bit in the CFR1 volatile is - * also set during Flash power-up. - * - * Return: 0 on success, -errno otherwise. - */ -static int cypress_nor_quad_enable_volatile(struct spi_nor *nor) +static int cypress_nor_quad_enable_volatile_reg(struct spi_nor *nor, u64 addr) { struct spi_mem_op op; u8 addr_mode_nbytes = nor->params->addr_mode_nbytes; @@ -161,8 +147,7 @@ static int cypress_nor_quad_enable_volatile(struct spi_nor *nor) int ret; op = (struct spi_mem_op) - CYPRESS_NOR_RD_ANY_REG_OP(addr_mode_nbytes, - SPINOR_REG_CYPRESS_CFR1V, 0, + CYPRESS_NOR_RD_ANY_REG_OP(addr_mode_nbytes, addr, 0, nor->bouncebuf); ret = spi_nor_read_any_reg(nor, &op, nor->reg_proto); @@ -175,8 +160,7 @@ static int cypress_nor_quad_enable_volatile(struct spi_nor *nor) /* Update the Quad Enable bit. */ nor->bouncebuf[0] |= SPINOR_REG_CYPRESS_CFR1_QUAD_EN; op = (struct spi_mem_op) - CYPRESS_NOR_WR_ANY_REG_OP(addr_mode_nbytes, - SPINOR_REG_CYPRESS_CFR1V, 1, + CYPRESS_NOR_WR_ANY_REG_OP(addr_mode_nbytes, addr, 1, nor->bouncebuf); ret = spi_nor_write_any_volatile_reg(nor, &op, nor->reg_proto); if (ret) @@ -186,8 +170,7 @@ static int cypress_nor_quad_enable_volatile(struct spi_nor *nor) /* Read back and check it. */ op = (struct spi_mem_op) - CYPRESS_NOR_RD_ANY_REG_OP(addr_mode_nbytes, - SPINOR_REG_CYPRESS_CFR1V, 0, + CYPRESS_NOR_RD_ANY_REG_OP(addr_mode_nbytes, addr, 0, nor->bouncebuf); ret = spi_nor_read_any_reg(nor, &op, nor->reg_proto); if (ret) @@ -201,6 +184,41 @@ static int cypress_nor_quad_enable_volatile(struct spi_nor *nor) return 0; } +/** + * cypress_nor_quad_enable_volatile() - enable Quad I/O mode in volatile + * register. + * @nor: pointer to a 'struct spi_nor' + * + * It is recommended to update volatile registers in the field application due + * to a risk of the non-volatile registers corruption by power interrupt. This + * function sets Quad Enable bit in CFR1 volatile. If users set the Quad Enable + * bit in the CFR1 non-volatile in advance (typically by a Flash programmer + * before mounting Flash on PCB), the Quad Enable bit in the CFR1 volatile is + * also set during Flash power-up. + * + * Return: 0 on success, -errno otherwise. + */ +static int cypress_nor_quad_enable_volatile(struct spi_nor *nor) +{ + struct spi_nor_flash_parameter *params = nor->params; + u64 addr; + u8 i; + int ret; + + if (!params->n_dice) + return cypress_nor_quad_enable_volatile_reg(nor, + SPINOR_REG_CYPRESS_CFR1V); + + for (i = 0; i < params->n_dice; i++) { + addr = params->vreg_offset[i] + SPINOR_REG_CYPRESS_CFR1; + ret = cypress_nor_quad_enable_volatile_reg(nor, addr); + if (ret) + return ret; + } + + return 0; +} + /** * cypress_nor_determine_addr_mode_by_sr1() - Determine current address mode * (3 or 4-byte) by querying status -- cgit v1.2.3 From 91f3c430f622befb1b11f07df3bf7163f46adda6 Mon Sep 17 00:00:00 2001 From: Takahiro Kuwano Date: Fri, 7 Apr 2023 15:41:03 +0900 Subject: mtd: spi-nor: spansion: Add a new ->ready() hook for multi-chip device For multi-chip devices, we need to make sure the all dice in the device are ready. The cypress_nor_sr_ready_and_clear() reads SR in each die and returns true only when all dice are ready. This function also takes care for program or erase error handling by reusing spansion_nor_clear_sr(). To do that, spansion_nor_clear_sr() is moved to top. Signed-off-by: Takahiro Kuwano Link: https://lore.kernel.org/r/3e4a64613ee733e002279349c75083433be45bf5.1680849425.git.Takahiro.Kuwano@infineon.com Signed-off-by: Tudor Ambarus --- drivers/mtd/spi-nor/spansion.c | 109 ++++++++++++++++++++++++++++++++--------- 1 file changed, 85 insertions(+), 24 deletions(-) diff --git a/drivers/mtd/spi-nor/spansion.c b/drivers/mtd/spi-nor/spansion.c index 91bc0aace516..deb93ab6fe98 100644 --- a/drivers/mtd/spi-nor/spansion.c +++ b/drivers/mtd/spi-nor/spansion.c @@ -63,6 +63,84 @@ SPI_MEM_OP_NO_DUMMY, \ SPI_MEM_OP_NO_DATA) +/** + * spansion_nor_clear_sr() - Clear the Status Register. + * @nor: pointer to 'struct spi_nor'. + */ +static void spansion_nor_clear_sr(struct spi_nor *nor) +{ + int ret; + + if (nor->spimem) { + struct spi_mem_op op = SPANSION_CLSR_OP; + + spi_nor_spimem_setup_op(nor, &op, nor->reg_proto); + + ret = spi_mem_exec_op(nor->spimem, &op); + } else { + ret = spi_nor_controller_ops_write_reg(nor, SPINOR_OP_CLSR, + NULL, 0); + } + + if (ret) + dev_dbg(nor->dev, "error %d clearing SR\n", ret); +} + +static int cypress_nor_sr_ready_and_clear_reg(struct spi_nor *nor, u64 addr) +{ + struct spi_mem_op op = + CYPRESS_NOR_RD_ANY_REG_OP(nor->params->addr_mode_nbytes, addr, + 0, nor->bouncebuf); + int ret; + + ret = spi_nor_read_any_reg(nor, &op, nor->reg_proto); + if (ret) + return ret; + + if (nor->bouncebuf[0] & (SR_E_ERR | SR_P_ERR)) { + if (nor->bouncebuf[0] & SR_E_ERR) + dev_err(nor->dev, "Erase Error occurred\n"); + else + dev_err(nor->dev, "Programming Error occurred\n"); + + spansion_nor_clear_sr(nor); + + ret = spi_nor_write_disable(nor); + if (ret) + return ret; + + return -EIO; + } + + return !(nor->bouncebuf[0] & SR_WIP); +} +/** + * cypress_nor_sr_ready_and_clear() - Query the Status Register of each die by + * using Read Any Register command to see if the whole flash is ready for new + * commands and clear it if there are any errors. + * @nor: pointer to 'struct spi_nor'. + * + * Return: 1 if ready, 0 if not ready, -errno on errors. + */ +static int cypress_nor_sr_ready_and_clear(struct spi_nor *nor) +{ + struct spi_nor_flash_parameter *params = nor->params; + u64 addr; + int ret; + u8 i; + + for (i = 0; i < params->n_dice; i++) { + addr = params->vreg_offset[i] + SPINOR_REG_CYPRESS_STR1; + ret = cypress_nor_sr_ready_and_clear_reg(nor, addr); + if (ret < 0) + return ret; + else if (ret == 0) + return 0; + } + + return 1; +} + static int cypress_nor_octal_dtr_en(struct spi_nor *nor) { struct spi_mem_op op; @@ -506,10 +584,16 @@ static int s25hx_t_post_sfdp_fixup(struct spi_nor *nor) static void s25hx_t_late_init(struct spi_nor *nor) { + struct spi_nor_flash_parameter *params = nor->params; + /* Fast Read 4B requires mode cycles */ - nor->params->reads[SNOR_CMD_READ_FAST].num_mode_clocks = 8; + params->reads[SNOR_CMD_READ_FAST].num_mode_clocks = 8; cypress_nor_ecc_init(nor); + + /* Replace ready() with multi die version */ + if (params->n_dice) + params->ready = cypress_nor_sr_ready_and_clear; } static struct spi_nor_fixups s25hx_t_fixups = { @@ -741,29 +825,6 @@ static const struct flash_info spansion_nor_parts[] = { }, }; -/** - * spansion_nor_clear_sr() - Clear the Status Register. - * @nor: pointer to 'struct spi_nor'. - */ -static void spansion_nor_clear_sr(struct spi_nor *nor) -{ - int ret; - - if (nor->spimem) { - struct spi_mem_op op = SPANSION_CLSR_OP; - - spi_nor_spimem_setup_op(nor, &op, nor->reg_proto); - - ret = spi_mem_exec_op(nor->spimem, &op); - } else { - ret = spi_nor_controller_ops_write_reg(nor, SPINOR_OP_CLSR, - NULL, 0); - } - - if (ret) - dev_dbg(nor->dev, "error %d clearing SR\n", ret); -} - /** * spansion_nor_sr_ready_and_clear() - Query the Status Register to see if the * flash is ready for new commands and clear it if there are any errors. -- cgit v1.2.3 From df6def86b9dcbc3e8ed4964c7b79b70c9b0c3040 Mon Sep 17 00:00:00 2001 From: Takahiro Kuwano Date: Fri, 7 Apr 2023 15:41:04 +0900 Subject: mtd: spi-nor: spansion: Add support for s25hl02gt and s25hs02gt Add ID, flags, and fixup for s25hl02gt and s25hs02gt. These parts are - Dual-die package parts - Not support chip erase - 4-byte addressing mode by default - Wrong param in SCCR map that needs to be fixed Signed-off-by: Takahiro Kuwano Link: https://lore.kernel.org/r/55021d2409bf310692db0ac1c55e71ba406438a7.1680849425.git.Takahiro.Kuwano@infineon.com Signed-off-by: Tudor Ambarus --- drivers/mtd/spi-nor/spansion.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/mtd/spi-nor/spansion.c b/drivers/mtd/spi-nor/spansion.c index deb93ab6fe98..15f9a80c10b9 100644 --- a/drivers/mtd/spi-nor/spansion.c +++ b/drivers/mtd/spi-nor/spansion.c @@ -579,6 +579,10 @@ static int s25hx_t_post_sfdp_fixup(struct spi_nor *nor) } } + /* The 2 Gb parts duplicate info and advertise 4 dice instead of 2. */ + if (nor->params->size == SZ_256M) + nor->params->n_dice = 2; + return cypress_nor_get_page_size(nor); } @@ -797,6 +801,10 @@ static const struct flash_info spansion_nor_parts[] = { PARSE_SFDP MFR_FLAGS(USE_CLSR) .fixups = &s25hx_t_fixups }, + { "s25hl02gt", INFO6(0x342a1c, 0x0f0090, 0, 0) + PARSE_SFDP + FLAGS(NO_CHIP_ERASE) + .fixups = &s25hx_t_fixups }, { "s25hs512t", INFO6(0x342b1a, 0x0f0390, 256 * 1024, 256) PARSE_SFDP MFR_FLAGS(USE_CLSR) @@ -805,6 +813,10 @@ static const struct flash_info spansion_nor_parts[] = { PARSE_SFDP MFR_FLAGS(USE_CLSR) .fixups = &s25hx_t_fixups }, + { "s25hs02gt", INFO6(0x342b1c, 0x0f0090, 0, 0) + PARSE_SFDP + FLAGS(NO_CHIP_ERASE) + .fixups = &s25hx_t_fixups }, { "cy15x104q", INFO6(0x042cc2, 0x7f7f7f, 512 * 1024, 1) FLAGS(SPI_NOR_NO_ERASE) }, { "s28hl512t", INFO(0x345a1a, 0, 256 * 1024, 256) -- cgit v1.2.3 From 94b8f77fdb6e10118d9df29351e11949d1799415 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Fri, 7 Apr 2023 19:04:53 +0200 Subject: mtd: onenand: omap2: Drop obsolete dependency 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: Kyungmin Park Cc: Miquel Raynal Cc: Richard Weinberger Cc: Vignesh Raghavendra Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20230407190453.66efdf9d@endymion.delvare --- drivers/mtd/nand/onenand/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/nand/onenand/Kconfig b/drivers/mtd/nand/onenand/Kconfig index c94bf483541e..7d57836bf32f 100644 --- a/drivers/mtd/nand/onenand/Kconfig +++ b/drivers/mtd/nand/onenand/Kconfig @@ -25,7 +25,7 @@ config MTD_ONENAND_GENERIC config MTD_ONENAND_OMAP2 tristate "OneNAND on OMAP2/OMAP3 support" depends on ARCH_OMAP2 || ARCH_OMAP3 || (COMPILE_TEST && ARM) - depends on OF || COMPILE_TEST + depends on OF depends on OMAP_GPMC help Support for a OneNAND flash device connected to an OMAP2/OMAP3 SoC -- cgit v1.2.3 From ec185b18c22323cb0cde0319fa90b3e467b1ed2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 11 Apr 2023 13:38:16 +0200 Subject: mtd: nand: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is (mostly) ignored and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Acked-by: Tudor Ambarus Acked-by: Nicolas Ferre # atmel Reviewed-by: Paul Cercueil # ingenic Reviewed-by: Philippe Mathieu-Daudé # ingenic Acked-by: Martin Blumenstingl # intel Reviewed-by: Martin Blumenstingl # meson Acked-by: Roger Quadros # omap_elm Reviewed-by: Geert Uytterhoeven # renesas Reviewed-by: Heiko Stuebner # rockchip Acked-by: Jernej Skrabec # sunxi Acked-by: Thierry Reding # tegra Signed-off-by: Uwe Kleine-König Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20230411113816.3472237-1-u.kleine-koenig@pengutronix.de --- drivers/mtd/nand/ecc-mxic.c | 6 ++---- drivers/mtd/nand/onenand/generic.c | 6 ++---- drivers/mtd/nand/onenand/onenand_omap2.c | 6 ++---- drivers/mtd/nand/onenand/onenand_samsung.c | 6 ++---- drivers/mtd/nand/raw/ams-delta.c | 6 ++---- drivers/mtd/nand/raw/arasan-nand-controller.c | 6 ++---- drivers/mtd/nand/raw/atmel/nand-controller.c | 6 ++---- drivers/mtd/nand/raw/au1550nd.c | 5 ++--- drivers/mtd/nand/raw/bcm47xxnflash/main.c | 6 ++---- drivers/mtd/nand/raw/cadence-nand-controller.c | 6 ++---- drivers/mtd/nand/raw/davinci_nand.c | 6 ++---- drivers/mtd/nand/raw/denali_dt.c | 6 ++---- drivers/mtd/nand/raw/fsl_elbc_nand.c | 6 ++---- drivers/mtd/nand/raw/fsl_ifc_nand.c | 6 ++---- drivers/mtd/nand/raw/fsl_upm.c | 6 ++---- drivers/mtd/nand/raw/fsmc_nand.c | 6 ++---- drivers/mtd/nand/raw/gpio.c | 6 ++---- drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c | 5 ++--- drivers/mtd/nand/raw/hisi504_nand.c | 6 ++---- drivers/mtd/nand/raw/ingenic/ingenic_nand_drv.c | 6 ++---- drivers/mtd/nand/raw/intel-nand-controller.c | 6 ++---- drivers/mtd/nand/raw/lpc32xx_mlc.c | 6 ++---- drivers/mtd/nand/raw/lpc32xx_slc.c | 6 ++---- drivers/mtd/nand/raw/marvell_nand.c | 6 ++---- drivers/mtd/nand/raw/meson_nand.c | 6 ++---- drivers/mtd/nand/raw/mpc5121_nfc.c | 6 ++---- drivers/mtd/nand/raw/mtk_nand.c | 6 ++---- drivers/mtd/nand/raw/mxc_nand.c | 6 ++---- drivers/mtd/nand/raw/mxic_nand.c | 5 ++--- drivers/mtd/nand/raw/ndfc.c | 6 ++---- drivers/mtd/nand/raw/omap2.c | 5 ++--- drivers/mtd/nand/raw/omap_elm.c | 5 ++--- drivers/mtd/nand/raw/orion_nand.c | 6 ++---- drivers/mtd/nand/raw/oxnas_nand.c | 6 ++---- drivers/mtd/nand/raw/pasemi_nand.c | 6 ++---- drivers/mtd/nand/raw/pl35x-nand-controller.c | 6 ++---- drivers/mtd/nand/raw/plat_nand.c | 6 ++---- drivers/mtd/nand/raw/qcom_nandc.c | 6 ++---- drivers/mtd/nand/raw/renesas-nand-controller.c | 6 ++---- drivers/mtd/nand/raw/rockchip-nand-controller.c | 6 ++---- drivers/mtd/nand/raw/s3c2410.c | 8 +++----- drivers/mtd/nand/raw/sh_flctl.c | 6 ++---- drivers/mtd/nand/raw/sharpsl.c | 6 ++---- drivers/mtd/nand/raw/socrates_nand.c | 6 ++---- drivers/mtd/nand/raw/stm32_fmc2_nand.c | 6 ++---- drivers/mtd/nand/raw/sunxi_nand.c | 6 ++---- drivers/mtd/nand/raw/tegra_nand.c | 6 ++---- drivers/mtd/nand/raw/vf610_nfc.c | 5 ++--- drivers/mtd/nand/raw/xway_nand.c | 6 ++---- 49 files changed, 99 insertions(+), 191 deletions(-) diff --git a/drivers/mtd/nand/ecc-mxic.c b/drivers/mtd/nand/ecc-mxic.c index 8afdca731b87..915aadd1a170 100644 --- a/drivers/mtd/nand/ecc-mxic.c +++ b/drivers/mtd/nand/ecc-mxic.c @@ -847,13 +847,11 @@ static int mxic_ecc_probe(struct platform_device *pdev) return 0; } -static int mxic_ecc_remove(struct platform_device *pdev) +static void mxic_ecc_remove(struct platform_device *pdev) { struct mxic_ecc_engine *mxic = platform_get_drvdata(pdev); nand_ecc_unregister_on_host_hw_engine(&mxic->external_engine); - - return 0; } static const struct of_device_id mxic_ecc_of_ids[] = { @@ -870,7 +868,7 @@ static struct platform_driver mxic_ecc_driver = { .of_match_table = mxic_ecc_of_ids, }, .probe = mxic_ecc_probe, - .remove = mxic_ecc_remove, + .remove_new = mxic_ecc_remove, }; module_platform_driver(mxic_ecc_driver); diff --git a/drivers/mtd/nand/onenand/generic.c b/drivers/mtd/nand/onenand/generic.c index a4b8b65fe15f..4e7de48f07a6 100644 --- a/drivers/mtd/nand/onenand/generic.c +++ b/drivers/mtd/nand/onenand/generic.c @@ -85,7 +85,7 @@ out_free_info: return err; } -static int generic_onenand_remove(struct platform_device *pdev) +static void generic_onenand_remove(struct platform_device *pdev) { struct onenand_info *info = platform_get_drvdata(pdev); struct resource *res = pdev->resource; @@ -97,8 +97,6 @@ static int generic_onenand_remove(struct platform_device *pdev) iounmap(info->onenand.base); kfree(info); } - - return 0; } static struct platform_driver generic_onenand_driver = { @@ -106,7 +104,7 @@ static struct platform_driver generic_onenand_driver = { .name = DRIVER_NAME, }, .probe = generic_onenand_probe, - .remove = generic_onenand_remove, + .remove_new = generic_onenand_remove, }; module_platform_driver(generic_onenand_driver); diff --git a/drivers/mtd/nand/onenand/onenand_omap2.c b/drivers/mtd/nand/onenand/onenand_omap2.c index 12825eb97938..ff7af98604df 100644 --- a/drivers/mtd/nand/onenand/onenand_omap2.c +++ b/drivers/mtd/nand/onenand/onenand_omap2.c @@ -581,7 +581,7 @@ err_release_dma: return r; } -static int omap2_onenand_remove(struct platform_device *pdev) +static void omap2_onenand_remove(struct platform_device *pdev) { struct omap2_onenand *c = dev_get_drvdata(&pdev->dev); @@ -589,8 +589,6 @@ static int omap2_onenand_remove(struct platform_device *pdev) if (c->dma_chan) dma_release_channel(c->dma_chan); omap2_onenand_shutdown(pdev); - - return 0; } static const struct of_device_id omap2_onenand_id_table[] = { @@ -601,7 +599,7 @@ MODULE_DEVICE_TABLE(of, omap2_onenand_id_table); static struct platform_driver omap2_onenand_driver = { .probe = omap2_onenand_probe, - .remove = omap2_onenand_remove, + .remove_new = omap2_onenand_remove, .shutdown = omap2_onenand_shutdown, .driver = { .name = DRIVER_NAME, diff --git a/drivers/mtd/nand/onenand/onenand_samsung.c b/drivers/mtd/nand/onenand/onenand_samsung.c index b64895573515..92151aa52964 100644 --- a/drivers/mtd/nand/onenand/onenand_samsung.c +++ b/drivers/mtd/nand/onenand/onenand_samsung.c @@ -943,13 +943,11 @@ static int s3c_onenand_probe(struct platform_device *pdev) return 0; } -static int s3c_onenand_remove(struct platform_device *pdev) +static void s3c_onenand_remove(struct platform_device *pdev) { struct mtd_info *mtd = platform_get_drvdata(pdev); onenand_release(mtd); - - return 0; } static int s3c_pm_ops_suspend(struct device *dev) @@ -996,7 +994,7 @@ static struct platform_driver s3c_onenand_driver = { }, .id_table = s3c_onenand_driver_ids, .probe = s3c_onenand_probe, - .remove = s3c_onenand_remove, + .remove_new = s3c_onenand_remove, }; module_platform_driver(s3c_onenand_driver); diff --git a/drivers/mtd/nand/raw/ams-delta.c b/drivers/mtd/nand/raw/ams-delta.c index 13de39aa3288..fa621ffa6490 100644 --- a/drivers/mtd/nand/raw/ams-delta.c +++ b/drivers/mtd/nand/raw/ams-delta.c @@ -397,7 +397,7 @@ err_nand_cleanup: /* * Clean up routine */ -static int gpio_nand_remove(struct platform_device *pdev) +static void gpio_nand_remove(struct platform_device *pdev) { struct gpio_nand *priv = platform_get_drvdata(pdev); struct mtd_info *mtd = nand_to_mtd(&priv->nand_chip); @@ -410,8 +410,6 @@ static int gpio_nand_remove(struct platform_device *pdev) ret = mtd_device_unregister(mtd); WARN_ON(ret); nand_cleanup(mtd_to_nand(mtd)); - - return 0; } #ifdef CONFIG_OF @@ -434,7 +432,7 @@ MODULE_DEVICE_TABLE(platform, gpio_nand_plat_id_table); static struct platform_driver gpio_nand_driver = { .probe = gpio_nand_probe, - .remove = gpio_nand_remove, + .remove_new = gpio_nand_remove, .id_table = gpio_nand_plat_id_table, .driver = { .name = "ams-delta-nand", diff --git a/drivers/mtd/nand/raw/arasan-nand-controller.c b/drivers/mtd/nand/raw/arasan-nand-controller.c index ec7e6eeac55f..d513d2db3549 100644 --- a/drivers/mtd/nand/raw/arasan-nand-controller.c +++ b/drivers/mtd/nand/raw/arasan-nand-controller.c @@ -1496,7 +1496,7 @@ disable_controller_clk: return ret; } -static int anfc_remove(struct platform_device *pdev) +static void anfc_remove(struct platform_device *pdev) { struct arasan_nfc *nfc = platform_get_drvdata(pdev); @@ -1504,8 +1504,6 @@ static int anfc_remove(struct platform_device *pdev) clk_disable_unprepare(nfc->bus_clk); clk_disable_unprepare(nfc->controller_clk); - - return 0; } static const struct of_device_id anfc_ids[] = { @@ -1525,7 +1523,7 @@ static struct platform_driver anfc_driver = { .of_match_table = anfc_ids, }, .probe = anfc_probe, - .remove = anfc_remove, + .remove_new = anfc_remove, }; module_platform_driver(anfc_driver); diff --git a/drivers/mtd/nand/raw/atmel/nand-controller.c b/drivers/mtd/nand/raw/atmel/nand-controller.c index 41c6bd6e2d72..81e3d682a8cd 100644 --- a/drivers/mtd/nand/raw/atmel/nand-controller.c +++ b/drivers/mtd/nand/raw/atmel/nand-controller.c @@ -2626,13 +2626,11 @@ static int atmel_nand_controller_probe(struct platform_device *pdev) return caps->ops->probe(pdev, caps); } -static int atmel_nand_controller_remove(struct platform_device *pdev) +static void atmel_nand_controller_remove(struct platform_device *pdev) { struct atmel_nand_controller *nc = platform_get_drvdata(pdev); WARN_ON(nc->caps->ops->remove(nc)); - - return 0; } static __maybe_unused int atmel_nand_controller_resume(struct device *dev) @@ -2663,7 +2661,7 @@ static struct platform_driver atmel_nand_controller_driver = { .pm = &atmel_nand_controller_pm_ops, }, .probe = atmel_nand_controller_probe, - .remove = atmel_nand_controller_remove, + .remove_new = atmel_nand_controller_remove, }; module_platform_driver(atmel_nand_controller_driver); diff --git a/drivers/mtd/nand/raw/au1550nd.c b/drivers/mtd/nand/raw/au1550nd.c index 5aa3a06d740c..063a5e0b8d4b 100644 --- a/drivers/mtd/nand/raw/au1550nd.c +++ b/drivers/mtd/nand/raw/au1550nd.c @@ -337,7 +337,7 @@ out1: return ret; } -static int au1550nd_remove(struct platform_device *pdev) +static void au1550nd_remove(struct platform_device *pdev) { struct au1550nd_ctx *ctx = platform_get_drvdata(pdev); struct resource *r = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -350,7 +350,6 @@ static int au1550nd_remove(struct platform_device *pdev) iounmap(ctx->base); release_mem_region(r->start, 0x1000); kfree(ctx); - return 0; } static struct platform_driver au1550nd_driver = { @@ -358,7 +357,7 @@ static struct platform_driver au1550nd_driver = { .name = "au1550-nand", }, .probe = au1550nd_probe, - .remove = au1550nd_remove, + .remove_new = au1550nd_remove, }; module_platform_driver(au1550nd_driver); diff --git a/drivers/mtd/nand/raw/bcm47xxnflash/main.c b/drivers/mtd/nand/raw/bcm47xxnflash/main.c index dcc70d9dc6e5..ebcf508e0606 100644 --- a/drivers/mtd/nand/raw/bcm47xxnflash/main.c +++ b/drivers/mtd/nand/raw/bcm47xxnflash/main.c @@ -57,7 +57,7 @@ static int bcm47xxnflash_probe(struct platform_device *pdev) return 0; } -static int bcm47xxnflash_remove(struct platform_device *pdev) +static void bcm47xxnflash_remove(struct platform_device *pdev) { struct bcm47xxnflash *nflash = platform_get_drvdata(pdev); struct nand_chip *chip = &nflash->nand_chip; @@ -66,13 +66,11 @@ static int bcm47xxnflash_remove(struct platform_device *pdev) ret = mtd_device_unregister(nand_to_mtd(chip)); WARN_ON(ret); nand_cleanup(chip); - - return 0; } static struct platform_driver bcm47xxnflash_driver = { .probe = bcm47xxnflash_probe, - .remove = bcm47xxnflash_remove, + .remove_new = bcm47xxnflash_remove, .driver = { .name = "bcma_nflash", }, diff --git a/drivers/mtd/nand/raw/cadence-nand-controller.c b/drivers/mtd/nand/raw/cadence-nand-controller.c index 7661a5cf1883..034ec564c2ed 100644 --- a/drivers/mtd/nand/raw/cadence-nand-controller.c +++ b/drivers/mtd/nand/raw/cadence-nand-controller.c @@ -3055,18 +3055,16 @@ static int cadence_nand_dt_probe(struct platform_device *ofdev) return 0; } -static int cadence_nand_dt_remove(struct platform_device *ofdev) +static void cadence_nand_dt_remove(struct platform_device *ofdev) { struct cadence_nand_dt *dt = platform_get_drvdata(ofdev); cadence_nand_remove(&dt->cdns_ctrl); - - return 0; } static struct platform_driver cadence_nand_dt_driver = { .probe = cadence_nand_dt_probe, - .remove = cadence_nand_dt_remove, + .remove_new = cadence_nand_dt_remove, .driver = { .name = "cadence-nand-controller", .of_match_table = cadence_nand_dt_ids, diff --git a/drivers/mtd/nand/raw/davinci_nand.c b/drivers/mtd/nand/raw/davinci_nand.c index 3e98e3c255bf..415d6aaa8255 100644 --- a/drivers/mtd/nand/raw/davinci_nand.c +++ b/drivers/mtd/nand/raw/davinci_nand.c @@ -821,7 +821,7 @@ err_cleanup_nand: return ret; } -static int nand_davinci_remove(struct platform_device *pdev) +static void nand_davinci_remove(struct platform_device *pdev) { struct davinci_nand_info *info = platform_get_drvdata(pdev); struct nand_chip *chip = &info->chip; @@ -835,13 +835,11 @@ static int nand_davinci_remove(struct platform_device *pdev) ret = mtd_device_unregister(nand_to_mtd(chip)); WARN_ON(ret); nand_cleanup(chip); - - return 0; } static struct platform_driver nand_davinci_driver = { .probe = nand_davinci_probe, - .remove = nand_davinci_remove, + .remove_new = nand_davinci_remove, .driver = { .name = "davinci_nand", .of_match_table = of_match_ptr(davinci_nand_of_match), diff --git a/drivers/mtd/nand/raw/denali_dt.c b/drivers/mtd/nand/raw/denali_dt.c index 8513bb9fcfcc..915047e3fbc2 100644 --- a/drivers/mtd/nand/raw/denali_dt.c +++ b/drivers/mtd/nand/raw/denali_dt.c @@ -233,7 +233,7 @@ out_disable_clk: return ret; } -static int denali_dt_remove(struct platform_device *pdev) +static void denali_dt_remove(struct platform_device *pdev) { struct denali_dt *dt = platform_get_drvdata(pdev); @@ -243,13 +243,11 @@ static int denali_dt_remove(struct platform_device *pdev) clk_disable_unprepare(dt->clk_ecc); clk_disable_unprepare(dt->clk_x); clk_disable_unprepare(dt->clk); - - return 0; } static struct platform_driver denali_dt_driver = { .probe = denali_dt_probe, - .remove = denali_dt_remove, + .remove_new = denali_dt_remove, .driver = { .name = "denali-nand-dt", .of_match_table = denali_nand_dt_ids, diff --git a/drivers/mtd/nand/raw/fsl_elbc_nand.c b/drivers/mtd/nand/raw/fsl_elbc_nand.c index e25119e58b69..1e3a80f06f33 100644 --- a/drivers/mtd/nand/raw/fsl_elbc_nand.c +++ b/drivers/mtd/nand/raw/fsl_elbc_nand.c @@ -963,7 +963,7 @@ err: return ret; } -static int fsl_elbc_nand_remove(struct platform_device *pdev) +static void fsl_elbc_nand_remove(struct platform_device *pdev) { struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = fsl_lbc_ctrl_dev->nand; struct fsl_elbc_mtd *priv = dev_get_drvdata(&pdev->dev); @@ -984,8 +984,6 @@ static int fsl_elbc_nand_remove(struct platform_device *pdev) } mutex_unlock(&fsl_elbc_nand_mutex); - return 0; - } static const struct of_device_id fsl_elbc_nand_match[] = { @@ -1000,7 +998,7 @@ static struct platform_driver fsl_elbc_nand_driver = { .of_match_table = fsl_elbc_nand_match, }, .probe = fsl_elbc_nand_probe, - .remove = fsl_elbc_nand_remove, + .remove_new = fsl_elbc_nand_remove, }; module_platform_driver(fsl_elbc_nand_driver); diff --git a/drivers/mtd/nand/raw/fsl_ifc_nand.c b/drivers/mtd/nand/raw/fsl_ifc_nand.c index 02d500176838..fa537fee6701 100644 --- a/drivers/mtd/nand/raw/fsl_ifc_nand.c +++ b/drivers/mtd/nand/raw/fsl_ifc_nand.c @@ -1094,7 +1094,7 @@ err: return ret; } -static int fsl_ifc_nand_remove(struct platform_device *dev) +static void fsl_ifc_nand_remove(struct platform_device *dev) { struct fsl_ifc_mtd *priv = dev_get_drvdata(&dev->dev); struct nand_chip *chip = &priv->chip; @@ -1113,8 +1113,6 @@ static int fsl_ifc_nand_remove(struct platform_device *dev) kfree(ifc_nand_ctrl); } mutex_unlock(&fsl_ifc_nand_mutex); - - return 0; } static const struct of_device_id fsl_ifc_nand_match[] = { @@ -1131,7 +1129,7 @@ static struct platform_driver fsl_ifc_nand_driver = { .of_match_table = fsl_ifc_nand_match, }, .probe = fsl_ifc_nand_probe, - .remove = fsl_ifc_nand_remove, + .remove_new = fsl_ifc_nand_remove, }; module_platform_driver(fsl_ifc_nand_driver); diff --git a/drivers/mtd/nand/raw/fsl_upm.c b/drivers/mtd/nand/raw/fsl_upm.c index b3cc427100a2..086426139173 100644 --- a/drivers/mtd/nand/raw/fsl_upm.c +++ b/drivers/mtd/nand/raw/fsl_upm.c @@ -235,7 +235,7 @@ static int fun_probe(struct platform_device *ofdev) return 0; } -static int fun_remove(struct platform_device *ofdev) +static void fun_remove(struct platform_device *ofdev) { struct fsl_upm_nand *fun = dev_get_drvdata(&ofdev->dev); struct nand_chip *chip = &fun->chip; @@ -245,8 +245,6 @@ static int fun_remove(struct platform_device *ofdev) ret = mtd_device_unregister(mtd); WARN_ON(ret); nand_cleanup(chip); - - return 0; } static const struct of_device_id of_fun_match[] = { @@ -261,7 +259,7 @@ static struct platform_driver of_fun_driver = { .of_match_table = of_fun_match, }, .probe = fun_probe, - .remove = fun_remove, + .remove_new = fun_remove, }; module_platform_driver(of_fun_driver); diff --git a/drivers/mtd/nand/raw/fsmc_nand.c b/drivers/mtd/nand/raw/fsmc_nand.c index 6b2bda815b88..d57867089079 100644 --- a/drivers/mtd/nand/raw/fsmc_nand.c +++ b/drivers/mtd/nand/raw/fsmc_nand.c @@ -1165,7 +1165,7 @@ disable_clk: /* * Clean up routine */ -static int fsmc_nand_remove(struct platform_device *pdev) +static void fsmc_nand_remove(struct platform_device *pdev) { struct fsmc_nand_data *host = platform_get_drvdata(pdev); @@ -1184,8 +1184,6 @@ static int fsmc_nand_remove(struct platform_device *pdev) } clk_disable_unprepare(host->clk); } - - return 0; } #ifdef CONFIG_PM_SLEEP @@ -1224,7 +1222,7 @@ static const struct of_device_id fsmc_nand_id_table[] = { MODULE_DEVICE_TABLE(of, fsmc_nand_id_table); static struct platform_driver fsmc_nand_driver = { - .remove = fsmc_nand_remove, + .remove_new = fsmc_nand_remove, .driver = { .name = "fsmc-nand", .of_match_table = fsmc_nand_id_table, diff --git a/drivers/mtd/nand/raw/gpio.c b/drivers/mtd/nand/raw/gpio.c index dcf28cff760d..d6cc2cb65214 100644 --- a/drivers/mtd/nand/raw/gpio.c +++ b/drivers/mtd/nand/raw/gpio.c @@ -265,7 +265,7 @@ gpio_nand_get_io_sync(struct platform_device *pdev) return platform_get_resource(pdev, IORESOURCE_MEM, 1); } -static int gpio_nand_remove(struct platform_device *pdev) +static void gpio_nand_remove(struct platform_device *pdev) { struct gpiomtd *gpiomtd = platform_get_drvdata(pdev); struct nand_chip *chip = &gpiomtd->nand_chip; @@ -280,8 +280,6 @@ static int gpio_nand_remove(struct platform_device *pdev) gpiod_set_value(gpiomtd->nwp, 0); if (gpiomtd->nce && !IS_ERR(gpiomtd->nce)) gpiod_set_value(gpiomtd->nce, 0); - - return 0; } static int gpio_nand_probe(struct platform_device *pdev) @@ -394,7 +392,7 @@ out_ce: static struct platform_driver gpio_nand_driver = { .probe = gpio_nand_probe, - .remove = gpio_nand_remove, + .remove_new = gpio_nand_remove, .driver = { .name = "gpio-nand", .of_match_table = of_match_ptr(gpio_nand_id_table), diff --git a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c index ada83344b0f9..500e7a28d2e4 100644 --- a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c +++ b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c @@ -2777,7 +2777,7 @@ exit_acquire_resources: return ret; } -static int gpmi_nand_remove(struct platform_device *pdev) +static void gpmi_nand_remove(struct platform_device *pdev) { struct gpmi_nand_data *this = platform_get_drvdata(pdev); struct nand_chip *chip = &this->nand; @@ -2791,7 +2791,6 @@ static int gpmi_nand_remove(struct platform_device *pdev) nand_cleanup(chip); gpmi_free_dma_buffer(this); release_resources(this); - return 0; } #ifdef CONFIG_PM_SLEEP @@ -2860,7 +2859,7 @@ static struct platform_driver gpmi_nand_driver = { .of_match_table = gpmi_nand_id_table, }, .probe = gpmi_nand_probe, - .remove = gpmi_nand_remove, + .remove_new = gpmi_nand_remove, }; module_platform_driver(gpmi_nand_driver); diff --git a/drivers/mtd/nand/raw/hisi504_nand.c b/drivers/mtd/nand/raw/hisi504_nand.c index c74f6b2192fc..fe291a2e5c77 100644 --- a/drivers/mtd/nand/raw/hisi504_nand.c +++ b/drivers/mtd/nand/raw/hisi504_nand.c @@ -798,7 +798,7 @@ static int hisi_nfc_probe(struct platform_device *pdev) return 0; } -static int hisi_nfc_remove(struct platform_device *pdev) +static void hisi_nfc_remove(struct platform_device *pdev) { struct hinfc_host *host = platform_get_drvdata(pdev); struct nand_chip *chip = &host->chip; @@ -807,8 +807,6 @@ static int hisi_nfc_remove(struct platform_device *pdev) ret = mtd_device_unregister(nand_to_mtd(chip)); WARN_ON(ret); nand_cleanup(chip); - - return 0; } #ifdef CONFIG_PM_SLEEP @@ -860,7 +858,7 @@ static struct platform_driver hisi_nfc_driver = { .pm = &hisi_nfc_pm_ops, }, .probe = hisi_nfc_probe, - .remove = hisi_nfc_remove, + .remove_new = hisi_nfc_remove, }; module_platform_driver(hisi_nfc_driver); diff --git a/drivers/mtd/nand/raw/ingenic/ingenic_nand_drv.c b/drivers/mtd/nand/raw/ingenic/ingenic_nand_drv.c index ff26c10f295d..b9f135297aa0 100644 --- a/drivers/mtd/nand/raw/ingenic/ingenic_nand_drv.c +++ b/drivers/mtd/nand/raw/ingenic/ingenic_nand_drv.c @@ -522,7 +522,7 @@ static int ingenic_nand_probe(struct platform_device *pdev) return 0; } -static int ingenic_nand_remove(struct platform_device *pdev) +static void ingenic_nand_remove(struct platform_device *pdev) { struct ingenic_nfc *nfc = platform_get_drvdata(pdev); @@ -530,8 +530,6 @@ static int ingenic_nand_remove(struct platform_device *pdev) ingenic_ecc_release(nfc->ecc); ingenic_nand_cleanup_chips(nfc); - - return 0; } static const struct jz_soc_info jz4740_soc_info = { @@ -564,7 +562,7 @@ MODULE_DEVICE_TABLE(of, ingenic_nand_dt_match); static struct platform_driver ingenic_nand_driver = { .probe = ingenic_nand_probe, - .remove = ingenic_nand_remove, + .remove_new = ingenic_nand_remove, .driver = { .name = DRV_NAME, .of_match_table = ingenic_nand_dt_match, diff --git a/drivers/mtd/nand/raw/intel-nand-controller.c b/drivers/mtd/nand/raw/intel-nand-controller.c index 6f4cea81f97c..a9909eb08124 100644 --- a/drivers/mtd/nand/raw/intel-nand-controller.c +++ b/drivers/mtd/nand/raw/intel-nand-controller.c @@ -706,7 +706,7 @@ err_of_node_put: return ret; } -static int ebu_nand_remove(struct platform_device *pdev) +static void ebu_nand_remove(struct platform_device *pdev) { struct ebu_nand_controller *ebu_host = platform_get_drvdata(pdev); int ret; @@ -717,8 +717,6 @@ static int ebu_nand_remove(struct platform_device *pdev) ebu_nand_disable(&ebu_host->chip); ebu_dma_cleanup(ebu_host); clk_disable_unprepare(ebu_host->clk); - - return 0; } static const struct of_device_id ebu_nand_match[] = { @@ -729,7 +727,7 @@ MODULE_DEVICE_TABLE(of, ebu_nand_match); static struct platform_driver ebu_nand_driver = { .probe = ebu_nand_probe, - .remove = ebu_nand_remove, + .remove_new = ebu_nand_remove, .driver = { .name = "intel-nand-controller", .of_match_table = ebu_nand_match, diff --git a/drivers/mtd/nand/raw/lpc32xx_mlc.c b/drivers/mtd/nand/raw/lpc32xx_mlc.c index ae7f6429a5f6..b3136ae6f4e9 100644 --- a/drivers/mtd/nand/raw/lpc32xx_mlc.c +++ b/drivers/mtd/nand/raw/lpc32xx_mlc.c @@ -827,7 +827,7 @@ free_gpio: /* * Remove NAND device */ -static int lpc32xx_nand_remove(struct platform_device *pdev) +static void lpc32xx_nand_remove(struct platform_device *pdev) { struct lpc32xx_nand_host *host = platform_get_drvdata(pdev); struct nand_chip *chip = &host->nand_chip; @@ -846,8 +846,6 @@ static int lpc32xx_nand_remove(struct platform_device *pdev) lpc32xx_wp_enable(host); gpiod_put(host->wp_gpio); - - return 0; } static int lpc32xx_nand_resume(struct platform_device *pdev) @@ -889,7 +887,7 @@ MODULE_DEVICE_TABLE(of, lpc32xx_nand_match); static struct platform_driver lpc32xx_nand_driver = { .probe = lpc32xx_nand_probe, - .remove = lpc32xx_nand_remove, + .remove_new = lpc32xx_nand_remove, .resume = pm_ptr(lpc32xx_nand_resume), .suspend = pm_ptr(lpc32xx_nand_suspend), .driver = { diff --git a/drivers/mtd/nand/raw/lpc32xx_slc.c b/drivers/mtd/nand/raw/lpc32xx_slc.c index 6918737346c9..3139b6107660 100644 --- a/drivers/mtd/nand/raw/lpc32xx_slc.c +++ b/drivers/mtd/nand/raw/lpc32xx_slc.c @@ -946,7 +946,7 @@ enable_wp: /* * Remove NAND device. */ -static int lpc32xx_nand_remove(struct platform_device *pdev) +static void lpc32xx_nand_remove(struct platform_device *pdev) { uint32_t tmp; struct lpc32xx_nand_host *host = platform_get_drvdata(pdev); @@ -965,8 +965,6 @@ static int lpc32xx_nand_remove(struct platform_device *pdev) clk_disable_unprepare(host->clk); lpc32xx_wp_enable(host); - - return 0; } static int lpc32xx_nand_resume(struct platform_device *pdev) @@ -1015,7 +1013,7 @@ MODULE_DEVICE_TABLE(of, lpc32xx_nand_match); static struct platform_driver lpc32xx_nand_driver = { .probe = lpc32xx_nand_probe, - .remove = lpc32xx_nand_remove, + .remove_new = lpc32xx_nand_remove, .resume = pm_ptr(lpc32xx_nand_resume), .suspend = pm_ptr(lpc32xx_nand_suspend), .driver = { diff --git a/drivers/mtd/nand/raw/marvell_nand.c b/drivers/mtd/nand/raw/marvell_nand.c index 3034916d2e25..afb424579f0b 100644 --- a/drivers/mtd/nand/raw/marvell_nand.c +++ b/drivers/mtd/nand/raw/marvell_nand.c @@ -3004,7 +3004,7 @@ unprepare_core_clk: return ret; } -static int marvell_nfc_remove(struct platform_device *pdev) +static void marvell_nfc_remove(struct platform_device *pdev) { struct marvell_nfc *nfc = platform_get_drvdata(pdev); @@ -3017,8 +3017,6 @@ static int marvell_nfc_remove(struct platform_device *pdev) clk_disable_unprepare(nfc->reg_clk); clk_disable_unprepare(nfc->core_clk); - - return 0; } static int __maybe_unused marvell_nfc_suspend(struct device *dev) @@ -3154,7 +3152,7 @@ static struct platform_driver marvell_nfc_driver = { }, .id_table = marvell_nfc_platform_ids, .probe = marvell_nfc_probe, - .remove = marvell_nfc_remove, + .remove_new = marvell_nfc_remove, }; module_platform_driver(marvell_nfc_driver); diff --git a/drivers/mtd/nand/raw/meson_nand.c b/drivers/mtd/nand/raw/meson_nand.c index 5ee01231ac4c..24f1ad025cda 100644 --- a/drivers/mtd/nand/raw/meson_nand.c +++ b/drivers/mtd/nand/raw/meson_nand.c @@ -1434,20 +1434,18 @@ err_clk: return ret; } -static int meson_nfc_remove(struct platform_device *pdev) +static void meson_nfc_remove(struct platform_device *pdev) { struct meson_nfc *nfc = platform_get_drvdata(pdev); meson_nfc_nand_chip_cleanup(nfc); meson_nfc_disable_clk(nfc); - - return 0; } static struct platform_driver meson_nfc_driver = { .probe = meson_nfc_probe, - .remove = meson_nfc_remove, + .remove_new = meson_nfc_remove, .driver = { .name = "meson-nand", .of_match_table = meson_nfc_id_table, diff --git a/drivers/mtd/nand/raw/mpc5121_nfc.c b/drivers/mtd/nand/raw/mpc5121_nfc.c index f68349cb7824..ab05ee65702c 100644 --- a/drivers/mtd/nand/raw/mpc5121_nfc.c +++ b/drivers/mtd/nand/raw/mpc5121_nfc.c @@ -822,7 +822,7 @@ error: return retval; } -static int mpc5121_nfc_remove(struct platform_device *op) +static void mpc5121_nfc_remove(struct platform_device *op) { struct device *dev = &op->dev; struct mtd_info *mtd = dev_get_drvdata(dev); @@ -832,8 +832,6 @@ static int mpc5121_nfc_remove(struct platform_device *op) WARN_ON(ret); nand_cleanup(mtd_to_nand(mtd)); mpc5121_nfc_free(dev, mtd); - - return 0; } static const struct of_device_id mpc5121_nfc_match[] = { @@ -844,7 +842,7 @@ MODULE_DEVICE_TABLE(of, mpc5121_nfc_match); static struct platform_driver mpc5121_nfc_driver = { .probe = mpc5121_nfc_probe, - .remove = mpc5121_nfc_remove, + .remove_new = mpc5121_nfc_remove, .driver = { .name = DRV_NAME, .of_match_table = mpc5121_nfc_match, diff --git a/drivers/mtd/nand/raw/mtk_nand.c b/drivers/mtd/nand/raw/mtk_nand.c index d540454cbbdf..b2fa6b2074ab 100644 --- a/drivers/mtd/nand/raw/mtk_nand.c +++ b/drivers/mtd/nand/raw/mtk_nand.c @@ -1601,7 +1601,7 @@ release_ecc: return ret; } -static int mtk_nfc_remove(struct platform_device *pdev) +static void mtk_nfc_remove(struct platform_device *pdev) { struct mtk_nfc *nfc = platform_get_drvdata(pdev); struct mtk_nfc_nand_chip *mtk_chip; @@ -1620,8 +1620,6 @@ static int mtk_nfc_remove(struct platform_device *pdev) mtk_ecc_release(nfc->ecc); mtk_nfc_disable_clk(&nfc->clk); - - return 0; } #ifdef CONFIG_PM_SLEEP @@ -1663,7 +1661,7 @@ static SIMPLE_DEV_PM_OPS(mtk_nfc_pm_ops, mtk_nfc_suspend, mtk_nfc_resume); static struct platform_driver mtk_nfc_driver = { .probe = mtk_nfc_probe, - .remove = mtk_nfc_remove, + .remove_new = mtk_nfc_remove, .driver = { .name = MTK_NAME, .of_match_table = mtk_nfc_id_table, diff --git a/drivers/mtd/nand/raw/mxc_nand.c b/drivers/mtd/nand/raw/mxc_nand.c index f61ffcbe57c8..3d4b2e8294ea 100644 --- a/drivers/mtd/nand/raw/mxc_nand.c +++ b/drivers/mtd/nand/raw/mxc_nand.c @@ -1821,7 +1821,7 @@ escan: return err; } -static int mxcnd_remove(struct platform_device *pdev) +static void mxcnd_remove(struct platform_device *pdev) { struct mxc_nand_host *host = platform_get_drvdata(pdev); struct nand_chip *chip = &host->nand; @@ -1832,8 +1832,6 @@ static int mxcnd_remove(struct platform_device *pdev) nand_cleanup(chip); if (host->clk_act) clk_disable_unprepare(host->clk); - - return 0; } static struct platform_driver mxcnd_driver = { @@ -1842,7 +1840,7 @@ static struct platform_driver mxcnd_driver = { .of_match_table = mxcnd_dt_ids, }, .probe = mxcnd_probe, - .remove = mxcnd_remove, + .remove_new = mxcnd_remove, }; module_platform_driver(mxcnd_driver); diff --git a/drivers/mtd/nand/raw/mxic_nand.c b/drivers/mtd/nand/raw/mxic_nand.c index da1070993994..be8050e84b4f 100644 --- a/drivers/mtd/nand/raw/mxic_nand.c +++ b/drivers/mtd/nand/raw/mxic_nand.c @@ -553,7 +553,7 @@ fail: return err; } -static int mxic_nfc_remove(struct platform_device *pdev) +static void mxic_nfc_remove(struct platform_device *pdev) { struct mxic_nand_ctlr *nfc = platform_get_drvdata(pdev); struct nand_chip *chip = &nfc->chip; @@ -564,7 +564,6 @@ static int mxic_nfc_remove(struct platform_device *pdev) nand_cleanup(chip); mxic_nfc_clk_disable(nfc); - return 0; } static const struct of_device_id mxic_nfc_of_ids[] = { @@ -575,7 +574,7 @@ MODULE_DEVICE_TABLE(of, mxic_nfc_of_ids); static struct platform_driver mxic_nfc_driver = { .probe = mxic_nfc_probe, - .remove = mxic_nfc_remove, + .remove_new = mxic_nfc_remove, .driver = { .name = "mxic-nfc", .of_match_table = mxic_nfc_of_ids, diff --git a/drivers/mtd/nand/raw/ndfc.c b/drivers/mtd/nand/raw/ndfc.c index 338d6b1a189e..57f3db32122d 100644 --- a/drivers/mtd/nand/raw/ndfc.c +++ b/drivers/mtd/nand/raw/ndfc.c @@ -240,7 +240,7 @@ static int ndfc_probe(struct platform_device *ofdev) return 0; } -static int ndfc_remove(struct platform_device *ofdev) +static void ndfc_remove(struct platform_device *ofdev) { struct ndfc_controller *ndfc = dev_get_drvdata(&ofdev->dev); struct nand_chip *chip = &ndfc->chip; @@ -251,8 +251,6 @@ static int ndfc_remove(struct platform_device *ofdev) WARN_ON(ret); nand_cleanup(chip); kfree(mtd->name); - - return 0; } static const struct of_device_id ndfc_match[] = { @@ -267,7 +265,7 @@ static struct platform_driver ndfc_driver = { .of_match_table = ndfc_match, }, .probe = ndfc_probe, - .remove = ndfc_remove, + .remove_new = ndfc_remove, }; module_platform_driver(ndfc_driver); diff --git a/drivers/mtd/nand/raw/omap2.c b/drivers/mtd/nand/raw/omap2.c index 4a9f2b6c772d..db22b3af16d8 100644 --- a/drivers/mtd/nand/raw/omap2.c +++ b/drivers/mtd/nand/raw/omap2.c @@ -2273,7 +2273,7 @@ return_error: return err; } -static int omap_nand_remove(struct platform_device *pdev) +static void omap_nand_remove(struct platform_device *pdev) { struct mtd_info *mtd = platform_get_drvdata(pdev); struct nand_chip *nand_chip = mtd_to_nand(mtd); @@ -2285,7 +2285,6 @@ static int omap_nand_remove(struct platform_device *pdev) dma_release_channel(info->dma); WARN_ON(mtd_device_unregister(mtd)); nand_cleanup(nand_chip); - return 0; } /* omap_nand_ids defined in linux/platform_data/mtd-nand-omap2.h */ @@ -2293,7 +2292,7 @@ MODULE_DEVICE_TABLE(of, omap_nand_ids); static struct platform_driver omap_nand_driver = { .probe = omap_nand_probe, - .remove = omap_nand_remove, + .remove_new = omap_nand_remove, .driver = { .name = DRIVER_NAME, .of_match_table = omap_nand_ids, diff --git a/drivers/mtd/nand/raw/omap_elm.c b/drivers/mtd/nand/raw/omap_elm.c index 4796a48e1012..6e1eac6644a6 100644 --- a/drivers/mtd/nand/raw/omap_elm.c +++ b/drivers/mtd/nand/raw/omap_elm.c @@ -422,11 +422,10 @@ static int elm_probe(struct platform_device *pdev) return ret; } -static int elm_remove(struct platform_device *pdev) +static void elm_remove(struct platform_device *pdev) { pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); - return 0; } #ifdef CONFIG_PM_SLEEP @@ -561,7 +560,7 @@ static struct platform_driver elm_driver = { .pm = &elm_pm_ops, }, .probe = elm_probe, - .remove = elm_remove, + .remove_new = elm_remove, }; module_platform_driver(elm_driver); diff --git a/drivers/mtd/nand/raw/orion_nand.c b/drivers/mtd/nand/raw/orion_nand.c index 1bdcd544c3fa..7e0313889b50 100644 --- a/drivers/mtd/nand/raw/orion_nand.c +++ b/drivers/mtd/nand/raw/orion_nand.c @@ -205,7 +205,7 @@ no_dev: return ret; } -static int orion_nand_remove(struct platform_device *pdev) +static void orion_nand_remove(struct platform_device *pdev) { struct orion_nand_info *info = platform_get_drvdata(pdev); struct nand_chip *chip = &info->chip; @@ -217,8 +217,6 @@ static int orion_nand_remove(struct platform_device *pdev) nand_cleanup(chip); clk_disable_unprepare(info->clk); - - return 0; } #ifdef CONFIG_OF @@ -230,7 +228,7 @@ MODULE_DEVICE_TABLE(of, orion_nand_of_match_table); #endif static struct platform_driver orion_nand_driver = { - .remove = orion_nand_remove, + .remove_new = orion_nand_remove, .driver = { .name = "orion_nand", .of_match_table = of_match_ptr(orion_nand_of_match_table), diff --git a/drivers/mtd/nand/raw/oxnas_nand.c b/drivers/mtd/nand/raw/oxnas_nand.c index cd112d45e0b5..e3c9807df1cd 100644 --- a/drivers/mtd/nand/raw/oxnas_nand.c +++ b/drivers/mtd/nand/raw/oxnas_nand.c @@ -171,7 +171,7 @@ err_clk_unprepare: return err; } -static int oxnas_nand_remove(struct platform_device *pdev) +static void oxnas_nand_remove(struct platform_device *pdev) { struct oxnas_nand_ctrl *oxnas = platform_get_drvdata(pdev); struct nand_chip *chip; @@ -184,8 +184,6 @@ static int oxnas_nand_remove(struct platform_device *pdev) } clk_disable_unprepare(oxnas->clk); - - return 0; } static const struct of_device_id oxnas_nand_match[] = { @@ -196,7 +194,7 @@ MODULE_DEVICE_TABLE(of, oxnas_nand_match); static struct platform_driver oxnas_nand_driver = { .probe = oxnas_nand_probe, - .remove = oxnas_nand_remove, + .remove_new = oxnas_nand_remove, .driver = { .name = "oxnas_nand", .of_match_table = oxnas_nand_match, diff --git a/drivers/mtd/nand/raw/pasemi_nand.c b/drivers/mtd/nand/raw/pasemi_nand.c index f7ef6ca06ca9..19b2c9d25863 100644 --- a/drivers/mtd/nand/raw/pasemi_nand.c +++ b/drivers/mtd/nand/raw/pasemi_nand.c @@ -197,7 +197,7 @@ static int pasemi_nand_probe(struct platform_device *ofdev) return err; } -static int pasemi_nand_remove(struct platform_device *ofdev) +static void pasemi_nand_remove(struct platform_device *ofdev) { struct pasemi_ddata *ddata = platform_get_drvdata(ofdev); struct mtd_info *pasemi_nand_mtd; @@ -218,8 +218,6 @@ static int pasemi_nand_remove(struct platform_device *ofdev) /* Free the MTD device structure */ kfree(ddata); - - return 0; } static const struct of_device_id pasemi_nand_match[] = @@ -239,7 +237,7 @@ static struct platform_driver pasemi_nand_driver = .of_match_table = pasemi_nand_match, }, .probe = pasemi_nand_probe, - .remove = pasemi_nand_remove, + .remove_new = pasemi_nand_remove, }; module_platform_driver(pasemi_nand_driver); diff --git a/drivers/mtd/nand/raw/pl35x-nand-controller.c b/drivers/mtd/nand/raw/pl35x-nand-controller.c index 3c6f6aff649f..28b7bd7e22eb 100644 --- a/drivers/mtd/nand/raw/pl35x-nand-controller.c +++ b/drivers/mtd/nand/raw/pl35x-nand-controller.c @@ -1163,13 +1163,11 @@ static int pl35x_nand_probe(struct platform_device *pdev) return 0; } -static int pl35x_nand_remove(struct platform_device *pdev) +static void pl35x_nand_remove(struct platform_device *pdev) { struct pl35x_nandc *nfc = platform_get_drvdata(pdev); pl35x_nand_chips_cleanup(nfc); - - return 0; } static const struct of_device_id pl35x_nand_of_match[] = { @@ -1180,7 +1178,7 @@ MODULE_DEVICE_TABLE(of, pl35x_nand_of_match); static struct platform_driver pl35x_nandc_driver = { .probe = pl35x_nand_probe, - .remove = pl35x_nand_remove, + .remove_new = pl35x_nand_remove, .driver = { .name = PL35X_NANDC_DRIVER_NAME, .of_match_table = pl35x_nand_of_match, diff --git a/drivers/mtd/nand/raw/plat_nand.c b/drivers/mtd/nand/raw/plat_nand.c index 7e0d0a8dfd1e..b5c374b51ecd 100644 --- a/drivers/mtd/nand/raw/plat_nand.c +++ b/drivers/mtd/nand/raw/plat_nand.c @@ -122,7 +122,7 @@ out: /* * Remove a NAND device. */ -static int plat_nand_remove(struct platform_device *pdev) +static void plat_nand_remove(struct platform_device *pdev) { struct plat_nand_data *data = platform_get_drvdata(pdev); struct platform_nand_data *pdata = dev_get_platdata(&pdev->dev); @@ -134,8 +134,6 @@ static int plat_nand_remove(struct platform_device *pdev) nand_cleanup(chip); if (pdata->ctrl.remove) pdata->ctrl.remove(pdev); - - return 0; } static const struct of_device_id plat_nand_match[] = { @@ -146,7 +144,7 @@ MODULE_DEVICE_TABLE(of, plat_nand_match); static struct platform_driver plat_nand_driver = { .probe = plat_nand_probe, - .remove = plat_nand_remove, + .remove_new = plat_nand_remove, .driver = { .name = "gen_nand", .of_match_table = plat_nand_match, diff --git a/drivers/mtd/nand/raw/qcom_nandc.c b/drivers/mtd/nand/raw/qcom_nandc.c index e1f7e2cb95a5..72d6168d8a1b 100644 --- a/drivers/mtd/nand/raw/qcom_nandc.c +++ b/drivers/mtd/nand/raw/qcom_nandc.c @@ -3314,7 +3314,7 @@ err_core_clk: return ret; } -static int qcom_nandc_remove(struct platform_device *pdev) +static void qcom_nandc_remove(struct platform_device *pdev) { struct qcom_nand_controller *nandc = platform_get_drvdata(pdev); struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -3336,8 +3336,6 @@ static int qcom_nandc_remove(struct platform_device *pdev) dma_unmap_resource(&pdev->dev, nandc->base_dma, resource_size(res), DMA_BIDIRECTIONAL, 0); - - return 0; } static const struct qcom_nandc_props ipq806x_nandc_props = { @@ -3404,7 +3402,7 @@ static struct platform_driver qcom_nandc_driver = { .of_match_table = qcom_nandc_of_match, }, .probe = qcom_nandc_probe, - .remove = qcom_nandc_remove, + .remove_new = qcom_nandc_remove, }; module_platform_driver(qcom_nandc_driver); diff --git a/drivers/mtd/nand/raw/renesas-nand-controller.c b/drivers/mtd/nand/raw/renesas-nand-controller.c index 1620e25a1147..589021ea9eb2 100644 --- a/drivers/mtd/nand/raw/renesas-nand-controller.c +++ b/drivers/mtd/nand/raw/renesas-nand-controller.c @@ -1386,15 +1386,13 @@ dis_runtime_pm: return ret; } -static int rnandc_remove(struct platform_device *pdev) +static void rnandc_remove(struct platform_device *pdev) { struct rnandc *rnandc = platform_get_drvdata(pdev); rnandc_chips_cleanup(rnandc); pm_runtime_put(&pdev->dev); - - return 0; } static const struct of_device_id rnandc_id_table[] = { @@ -1410,7 +1408,7 @@ static struct platform_driver rnandc_driver = { .of_match_table = rnandc_id_table, }, .probe = rnandc_probe, - .remove = rnandc_remove, + .remove_new = rnandc_remove, }; module_platform_driver(rnandc_driver); diff --git a/drivers/mtd/nand/raw/rockchip-nand-controller.c b/drivers/mtd/nand/raw/rockchip-nand-controller.c index f133985cc053..2312e27362cb 100644 --- a/drivers/mtd/nand/raw/rockchip-nand-controller.c +++ b/drivers/mtd/nand/raw/rockchip-nand-controller.c @@ -1427,7 +1427,7 @@ release_nfc: return ret; } -static int rk_nfc_remove(struct platform_device *pdev) +static void rk_nfc_remove(struct platform_device *pdev) { struct rk_nfc *nfc = platform_get_drvdata(pdev); @@ -1435,8 +1435,6 @@ static int rk_nfc_remove(struct platform_device *pdev) kfree(nfc->oob_buf); rk_nfc_chips_cleanup(nfc); rk_nfc_disable_clks(nfc); - - return 0; } static int __maybe_unused rk_nfc_suspend(struct device *dev) @@ -1476,7 +1474,7 @@ static const struct dev_pm_ops rk_nfc_pm_ops = { static struct platform_driver rk_nfc_driver = { .probe = rk_nfc_probe, - .remove = rk_nfc_remove, + .remove_new = rk_nfc_remove, .driver = { .name = "rockchip-nfc", .of_match_table = rk_nfc_id_table, diff --git a/drivers/mtd/nand/raw/s3c2410.c b/drivers/mtd/nand/raw/s3c2410.c index 80d96f94d6cb..ac80aaf5b4e3 100644 --- a/drivers/mtd/nand/raw/s3c2410.c +++ b/drivers/mtd/nand/raw/s3c2410.c @@ -709,12 +709,12 @@ static void s3c2440_nand_write_buf(struct nand_chip *this, const u_char *buf, /* device management functions */ -static int s3c24xx_nand_remove(struct platform_device *pdev) +static void s3c24xx_nand_remove(struct platform_device *pdev) { struct s3c2410_nand_info *info = to_nand_info(pdev); if (info == NULL) - return 0; + return; /* Release all our mtds and their partitions, then go through * freeing the resources used @@ -735,8 +735,6 @@ static int s3c24xx_nand_remove(struct platform_device *pdev) if (!IS_ERR(info->clk)) s3c2410_nand_clk_set_state(info, CLOCK_DISABLE); - - return 0; } static int s3c2410_nand_add_partition(struct s3c2410_nand_info *info, @@ -1218,7 +1216,7 @@ MODULE_DEVICE_TABLE(platform, s3c24xx_driver_ids); static struct platform_driver s3c24xx_nand_driver = { .probe = s3c24xx_nand_probe, - .remove = s3c24xx_nand_remove, + .remove_new = s3c24xx_nand_remove, .suspend = s3c24xx_nand_suspend, .resume = s3c24xx_nand_resume, .id_table = s3c24xx_driver_ids, diff --git a/drivers/mtd/nand/raw/sh_flctl.c b/drivers/mtd/nand/raw/sh_flctl.c index a278829469d6..63bf20c41719 100644 --- a/drivers/mtd/nand/raw/sh_flctl.c +++ b/drivers/mtd/nand/raw/sh_flctl.c @@ -1203,7 +1203,7 @@ err_chip: return ret; } -static int flctl_remove(struct platform_device *pdev) +static void flctl_remove(struct platform_device *pdev) { struct sh_flctl *flctl = platform_get_drvdata(pdev); struct nand_chip *chip = &flctl->chip; @@ -1214,12 +1214,10 @@ static int flctl_remove(struct platform_device *pdev) WARN_ON(ret); nand_cleanup(chip); pm_runtime_disable(&pdev->dev); - - return 0; } static struct platform_driver flctl_driver = { - .remove = flctl_remove, + .remove_new = flctl_remove, .driver = { .name = "sh_flctl", .of_match_table = of_flctl_match, diff --git a/drivers/mtd/nand/raw/sharpsl.c b/drivers/mtd/nand/raw/sharpsl.c index 52ce5162538a..2402dc5465d5 100644 --- a/drivers/mtd/nand/raw/sharpsl.c +++ b/drivers/mtd/nand/raw/sharpsl.c @@ -210,7 +210,7 @@ err_get_res: /* * Clean up routine */ -static int sharpsl_nand_remove(struct platform_device *pdev) +static void sharpsl_nand_remove(struct platform_device *pdev) { struct sharpsl_nand *sharpsl = platform_get_drvdata(pdev); struct nand_chip *chip = &sharpsl->chip; @@ -227,8 +227,6 @@ static int sharpsl_nand_remove(struct platform_device *pdev) /* Free the driver's structure */ kfree(sharpsl); - - return 0; } static struct platform_driver sharpsl_nand_driver = { @@ -236,7 +234,7 @@ static struct platform_driver sharpsl_nand_driver = { .name = "sharpsl-nand", }, .probe = sharpsl_nand_probe, - .remove = sharpsl_nand_remove, + .remove_new = sharpsl_nand_remove, }; module_platform_driver(sharpsl_nand_driver); diff --git a/drivers/mtd/nand/raw/socrates_nand.c b/drivers/mtd/nand/raw/socrates_nand.c index fb39cc7ebce0..a8b720ffe9e8 100644 --- a/drivers/mtd/nand/raw/socrates_nand.c +++ b/drivers/mtd/nand/raw/socrates_nand.c @@ -201,7 +201,7 @@ out: /* * Remove a NAND device. */ -static int socrates_nand_remove(struct platform_device *ofdev) +static void socrates_nand_remove(struct platform_device *ofdev) { struct socrates_nand_host *host = dev_get_drvdata(&ofdev->dev); struct nand_chip *chip = &host->nand_chip; @@ -212,8 +212,6 @@ static int socrates_nand_remove(struct platform_device *ofdev) nand_cleanup(chip); iounmap(host->io_base); - - return 0; } static const struct of_device_id socrates_nand_match[] = @@ -232,7 +230,7 @@ static struct platform_driver socrates_nand_driver = { .of_match_table = socrates_nand_match, }, .probe = socrates_nand_probe, - .remove = socrates_nand_remove, + .remove_new = socrates_nand_remove, }; module_platform_driver(socrates_nand_driver); diff --git a/drivers/mtd/nand/raw/stm32_fmc2_nand.c b/drivers/mtd/nand/raw/stm32_fmc2_nand.c index 5d627048c420..e3d09dd5963b 100644 --- a/drivers/mtd/nand/raw/stm32_fmc2_nand.c +++ b/drivers/mtd/nand/raw/stm32_fmc2_nand.c @@ -2021,7 +2021,7 @@ err_clk_disable: return ret; } -static int stm32_fmc2_nfc_remove(struct platform_device *pdev) +static void stm32_fmc2_nfc_remove(struct platform_device *pdev) { struct stm32_fmc2_nfc *nfc = platform_get_drvdata(pdev); struct stm32_fmc2_nand *nand = &nfc->nand; @@ -2045,8 +2045,6 @@ static int stm32_fmc2_nfc_remove(struct platform_device *pdev) clk_disable_unprepare(nfc->clk); stm32_fmc2_nfc_wp_enable(nand); - - return 0; } static int __maybe_unused stm32_fmc2_nfc_suspend(struct device *dev) @@ -2103,7 +2101,7 @@ MODULE_DEVICE_TABLE(of, stm32_fmc2_nfc_match); static struct platform_driver stm32_fmc2_nfc_driver = { .probe = stm32_fmc2_nfc_probe, - .remove = stm32_fmc2_nfc_remove, + .remove_new = stm32_fmc2_nfc_remove, .driver = { .name = "stm32_fmc2_nfc", .of_match_table = stm32_fmc2_nfc_match, diff --git a/drivers/mtd/nand/raw/sunxi_nand.c b/drivers/mtd/nand/raw/sunxi_nand.c index 13e3e0198d15..9884304634f6 100644 --- a/drivers/mtd/nand/raw/sunxi_nand.c +++ b/drivers/mtd/nand/raw/sunxi_nand.c @@ -2173,7 +2173,7 @@ out_ahb_clk_unprepare: return ret; } -static int sunxi_nfc_remove(struct platform_device *pdev) +static void sunxi_nfc_remove(struct platform_device *pdev) { struct sunxi_nfc *nfc = platform_get_drvdata(pdev); @@ -2185,8 +2185,6 @@ static int sunxi_nfc_remove(struct platform_device *pdev) dma_release_channel(nfc->dmac); clk_disable_unprepare(nfc->mod_clk); clk_disable_unprepare(nfc->ahb_clk); - - return 0; } static const struct sunxi_nfc_caps sunxi_nfc_a10_caps = { @@ -2219,7 +2217,7 @@ static struct platform_driver sunxi_nfc_driver = { .of_match_table = sunxi_nfc_ids, }, .probe = sunxi_nfc_probe, - .remove = sunxi_nfc_remove, + .remove_new = sunxi_nfc_remove, }; module_platform_driver(sunxi_nfc_driver); diff --git a/drivers/mtd/nand/raw/tegra_nand.c b/drivers/mtd/nand/raw/tegra_nand.c index a9b9031ce616..eb0b9d16e8da 100644 --- a/drivers/mtd/nand/raw/tegra_nand.c +++ b/drivers/mtd/nand/raw/tegra_nand.c @@ -1220,7 +1220,7 @@ err_dis_pm: return err; } -static int tegra_nand_remove(struct platform_device *pdev) +static void tegra_nand_remove(struct platform_device *pdev) { struct tegra_nand_controller *ctrl = platform_get_drvdata(pdev); struct nand_chip *chip = ctrl->chip; @@ -1232,8 +1232,6 @@ static int tegra_nand_remove(struct platform_device *pdev) pm_runtime_put_sync_suspend(ctrl->dev); pm_runtime_force_suspend(ctrl->dev); - - return 0; } static int __maybe_unused tegra_nand_runtime_resume(struct device *dev) @@ -1277,7 +1275,7 @@ static struct platform_driver tegra_nand_driver = { .pm = &tegra_nand_pm, }, .probe = tegra_nand_probe, - .remove = tegra_nand_remove, + .remove_new = tegra_nand_remove, }; module_platform_driver(tegra_nand_driver); diff --git a/drivers/mtd/nand/raw/vf610_nfc.c b/drivers/mtd/nand/raw/vf610_nfc.c index b643332ea1ff..86522048e271 100644 --- a/drivers/mtd/nand/raw/vf610_nfc.c +++ b/drivers/mtd/nand/raw/vf610_nfc.c @@ -909,7 +909,7 @@ err_disable_clk: return err; } -static int vf610_nfc_remove(struct platform_device *pdev) +static void vf610_nfc_remove(struct platform_device *pdev) { struct vf610_nfc *nfc = platform_get_drvdata(pdev); struct nand_chip *chip = &nfc->chip; @@ -919,7 +919,6 @@ static int vf610_nfc_remove(struct platform_device *pdev) WARN_ON(ret); nand_cleanup(chip); clk_disable_unprepare(nfc->clk); - return 0; } #ifdef CONFIG_PM_SLEEP @@ -955,7 +954,7 @@ static struct platform_driver vf610_nfc_driver = { .pm = &vf610_nfc_pm_ops, }, .probe = vf610_nfc_probe, - .remove = vf610_nfc_remove, + .remove_new = vf610_nfc_remove, }; module_platform_driver(vf610_nfc_driver); diff --git a/drivers/mtd/nand/raw/xway_nand.c b/drivers/mtd/nand/raw/xway_nand.c index 035b82aa2f4a..6b1e2a2bba15 100644 --- a/drivers/mtd/nand/raw/xway_nand.c +++ b/drivers/mtd/nand/raw/xway_nand.c @@ -238,7 +238,7 @@ static int xway_nand_probe(struct platform_device *pdev) /* * Remove a NAND device. */ -static int xway_nand_remove(struct platform_device *pdev) +static void xway_nand_remove(struct platform_device *pdev) { struct xway_nand_data *data = platform_get_drvdata(pdev); struct nand_chip *chip = &data->chip; @@ -247,8 +247,6 @@ static int xway_nand_remove(struct platform_device *pdev) ret = mtd_device_unregister(nand_to_mtd(chip)); WARN_ON(ret); nand_cleanup(chip); - - return 0; } static const struct of_device_id xway_nand_match[] = { @@ -258,7 +256,7 @@ static const struct of_device_id xway_nand_match[] = { static struct platform_driver xway_nand_driver = { .probe = xway_nand_probe, - .remove = xway_nand_remove, + .remove_new = xway_nand_remove, .driver = { .name = "lantiq,nand-xway", .of_match_table = xway_nand_match, -- cgit v1.2.3