From 06abbef27a31a81b254b2093b67d90e04ed273b0 Mon Sep 17 00:00:00 2001 From: zhengxun Date: Tue, 23 Mar 2021 13:16:47 +0000 Subject: [PATCH 01/12] mtd: spi-nor-ids: Add Macronix MX66UW2G345G The MX66UW2G345G is Macronix Flash with SINGLE and OCTAL I/O. Hence, add SPI_NOR_OCTAL_READ flag for this flash. Reviewed-by: Jagan Teki [jagan: change order of id flags] Signed-off-by: Jagan Teki Signed-off-by: zhengxun --- drivers/mtd/spi/spi-nor-ids.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mtd/spi/spi-nor-ids.c b/drivers/mtd/spi/spi-nor-ids.c index 2b57797954..8d2b73b676 100644 --- a/drivers/mtd/spi/spi-nor-ids.c +++ b/drivers/mtd/spi/spi-nor-ids.c @@ -167,6 +167,7 @@ const struct flash_info spi_nor_ids[] = { { INFO("mx66l1g45g", 0xc2201b, 0, 64 * 1024, 2048, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, { INFO("mx25l1633e", 0xc22415, 0, 64 * 1024, 32, SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES | SECT_4K) }, { INFO("mx25r6435f", 0xc22817, 0, 64 * 1024, 128, SECT_4K) }, + { INFO("mx66uw2g345g", 0xc2943c, 0, 64 * 1024, 4096, SECT_4K | SPI_NOR_OCTAL_READ | SPI_NOR_4B_OPCODES) }, #endif #ifdef CONFIG_SPI_FLASH_STMICRO /* STMICRO */ From b388af9af459b049645aaecc8874721119b479b0 Mon Sep 17 00:00:00 2001 From: Jaime Liao Date: Mon, 7 Jun 2021 16:19:15 +0800 Subject: [PATCH 02/12] mtd: spinand: macronix: Add support for serial NAND flash Macronix NAND Flash devices are available in different configurations and densities. MX"35" means SPI NAND MX35"UF" , UF meands 1.8V MX35LF"2G" , 2G means 2Gbits MX35LF2G"E4" , E4 means internal ECC and Quad I/O(x4) MX35UF4GE4AD/MX35UF2GE4AD/MX35UF1GE4AD are 1.8V 4G/2Gbit serial NAND flash device with 8-bit on-die ECC https://www.mxic.com.tw/Lists/Datasheet/Attachments/7983/MX35UF4GE4AD,%201.8V,%204Gb,%20v0.00.pdf MX35UF2GE4AC/MX35UF1GE4AC are 1.8V 2G/1Gbit serial NAND flash device with 8-bit on-die ECC https://www.mxic.com.tw/Lists/Datasheet/Attachments/7974/MX35UF2GE4AC,%201.8V,%202Gb,%20v1.0.pdf Validated via normal(default) and QUAD mode by read, erase, read back, on Xilinx Zynq PicoZed FPGA board which included Macronix SPI Host(drivers/spi/spi-mxic.c). Signed-off-by: Jaime Liao Reviewed-by: Jagan Teki --- drivers/mtd/nand/spi/macronix.c | 46 +++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/drivers/mtd/nand/spi/macronix.c b/drivers/mtd/nand/spi/macronix.c index 215f09acc3..f4a8e81639 100644 --- a/drivers/mtd/nand/spi/macronix.c +++ b/drivers/mtd/nand/spi/macronix.c @@ -114,6 +114,52 @@ static const struct spinand_info macronix_spinand_table[] = { &update_cache_variants), SPINAND_HAS_QE_BIT, SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL)), + SPINAND_INFO("MX35UF4GE4AD", 0xb7, + NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 1), + NAND_ECCREQ(8, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants, + &write_cache_variants, + &update_cache_variants), + SPINAND_HAS_QE_BIT, + SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, + mx35lf1ge4ab_ecc_get_status)), + SPINAND_INFO("MX35UF2GE4AD", 0xa6, + NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1), + NAND_ECCREQ(8, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants, + &write_cache_variants, + &update_cache_variants), + SPINAND_HAS_QE_BIT, + SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, + mx35lf1ge4ab_ecc_get_status)), + SPINAND_INFO("MX35UF2GE4AC", 0xa2, + NAND_MEMORG(1, 2048, 64, 64, 2048, 1, 1, 1), + NAND_ECCREQ(4, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants, + &write_cache_variants, + &update_cache_variants), + SPINAND_HAS_QE_BIT, + SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, + mx35lf1ge4ab_ecc_get_status)), + SPINAND_INFO("MX35UF1GE4AD", 0x96, + NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1), + NAND_ECCREQ(8, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants, + &write_cache_variants, + &update_cache_variants), + SPINAND_HAS_QE_BIT, + SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, + mx35lf1ge4ab_ecc_get_status)), + SPINAND_INFO("MX35UF1GE4AC", 0x92, + NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1), + NAND_ECCREQ(4, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants, + &write_cache_variants, + &update_cache_variants), + SPINAND_HAS_QE_BIT, + SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, + mx35lf1ge4ab_ecc_get_status)), + }; static int macronix_spinand_detect(struct spinand_device *spinand) From 31a7b719d07ccb11950f423b5f1195375109b5fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Wed, 26 May 2021 14:08:17 +0200 Subject: [PATCH 03/12] dm: core: add non-translating version of ofnode_get_addr_size_index() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add functions ofnode_get_addr_size_index_notrans(), which is a non-translating version of ofnode_get_addr_size_index(). Some addresses are not meant to be translated, for example those of MTD fixed-partitions. Signed-off-by: Marek Behún Reviewed-by: Simon Glass Reviewed-by: Miquel Raynal Tested-by: Patrice Chotard Reviewed-by: Jagan Teki --- drivers/core/ofnode.c | 19 ++++++++++++++++--- include/dm/ofnode.h | 17 +++++++++++++++++ test/dm/ofnode.c | 5 +++++ 3 files changed, 38 insertions(+), 3 deletions(-) diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c index 6c771e364f..dd34cf8ca3 100644 --- a/drivers/core/ofnode.c +++ b/drivers/core/ofnode.c @@ -299,7 +299,8 @@ ofnode ofnode_get_by_phandle(uint phandle) return node; } -fdt_addr_t ofnode_get_addr_size_index(ofnode node, int index, fdt_size_t *size) +static fdt_addr_t __ofnode_get_addr_size_index(ofnode node, int index, + fdt_size_t *size, bool translate) { int na, ns; @@ -319,7 +320,7 @@ fdt_addr_t ofnode_get_addr_size_index(ofnode node, int index, fdt_size_t *size) ns = of_n_size_cells(ofnode_to_np(node)); - if (IS_ENABLED(CONFIG_OF_TRANSLATE) && ns > 0) { + if (translate && IS_ENABLED(CONFIG_OF_TRANSLATE) && ns > 0) { return of_translate_address(ofnode_to_np(node), prop_val); } else { na = of_n_addr_cells(ofnode_to_np(node)); @@ -330,12 +331,24 @@ fdt_addr_t ofnode_get_addr_size_index(ofnode node, int index, fdt_size_t *size) ns = ofnode_read_simple_size_cells(ofnode_get_parent(node)); return fdtdec_get_addr_size_fixed(gd->fdt_blob, ofnode_to_offset(node), "reg", - index, na, ns, size, true); + index, na, ns, size, + translate); } return FDT_ADDR_T_NONE; } +fdt_addr_t ofnode_get_addr_size_index(ofnode node, int index, fdt_size_t *size) +{ + return __ofnode_get_addr_size_index(node, index, size, true); +} + +fdt_addr_t ofnode_get_addr_size_index_notrans(ofnode node, int index, + fdt_size_t *size) +{ + return __ofnode_get_addr_size_index(node, index, size, false); +} + fdt_addr_t ofnode_get_addr_index(ofnode node, int index) { fdt_size_t size; diff --git a/include/dm/ofnode.h b/include/dm/ofnode.h index 8a69fd87da..e3fccb506e 100644 --- a/include/dm/ofnode.h +++ b/include/dm/ofnode.h @@ -489,6 +489,23 @@ int ofnode_read_size(ofnode node, const char *propname); phys_addr_t ofnode_get_addr_size_index(ofnode node, int index, fdt_size_t *size); +/** + * ofnode_get_addr_size_index_notrans() - get an address/size from a node + * based on index, without address + * translation + * + * This reads the register address/size from a node based on index. + * The resulting address is not translated. Useful for example for on-disk + * addresses. + * + * @node: node to read from + * @index: Index of address to read (0 for first) + * @size: Pointer to size of the address + * @return address, or FDT_ADDR_T_NONE if not present or invalid + */ +phys_addr_t ofnode_get_addr_size_index_notrans(ofnode node, int index, + fdt_size_t *size); + /** * ofnode_get_addr_index() - get an address from a node * diff --git a/test/dm/ofnode.c b/test/dm/ofnode.c index e0b525eeb1..9a69cf70c1 100644 --- a/test/dm/ofnode.c +++ b/test/dm/ofnode.c @@ -289,6 +289,11 @@ static int dm_test_ofnode_get_reg(struct unit_test_state *uts) ut_asserteq(FDT_ADDR_T_NONE, addr); ut_asserteq(FDT_SIZE_T_NONE, size); + node = ofnode_path("/translation-test@8000/noxlatebus@3,300/dev@42"); + ut_assert(ofnode_valid(node)); + addr = ofnode_get_addr_size_index_notrans(node, 0, &size); + ut_asserteq_64(0x42, addr); + return 0; } DM_TEST(dm_test_ofnode_get_reg, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); From 0e116bea52af1b665a656d49c328468e976be913 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Wed, 26 May 2021 14:08:18 +0200 Subject: [PATCH 04/12] dm: core: add ofnode_get_path() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add function for retrieving full node path of a given ofnode. This uses np->full_name if OF is live, otherwise a call to fdt_get_path() is made. Signed-off-by: Marek Behún Reviewed-by: Simon Glass Reviewed-by: Miquel Raynal Tested-by: Patrice Chotard Reviewed-by: Jagan Teki --- drivers/core/ofnode.c | 25 +++++++++++++++++++++++++ include/dm/ofnode.h | 10 ++++++++++ test/dm/ofnode.c | 21 +++++++++++++++++++++ 3 files changed, 56 insertions(+) diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c index dd34cf8ca3..eeeccfb446 100644 --- a/drivers/core/ofnode.c +++ b/drivers/core/ofnode.c @@ -286,6 +286,31 @@ const char *ofnode_get_name(ofnode node) return fdt_get_name(gd->fdt_blob, ofnode_to_offset(node), NULL); } +int ofnode_get_path(ofnode node, char *buf, int buflen) +{ + assert(ofnode_valid(node)); + + if (ofnode_is_np(node)) { + if (strlen(node.np->full_name) >= buflen) + return -ENOSPC; + + strcpy(buf, node.np->full_name); + + return 0; + } else { + int res; + + res = fdt_get_path(gd->fdt_blob, ofnode_to_offset(node), buf, + buflen); + if (!res) + return res; + else if (res == -FDT_ERR_NOSPACE) + return -ENOSPC; + else + return -EINVAL; + } +} + ofnode ofnode_get_by_phandle(uint phandle) { ofnode node; diff --git a/include/dm/ofnode.h b/include/dm/ofnode.h index e3fccb506e..3da05d8b21 100644 --- a/include/dm/ofnode.h +++ b/include/dm/ofnode.h @@ -458,6 +458,16 @@ ofnode ofnode_get_parent(ofnode node); */ const char *ofnode_get_name(ofnode node); +/** + * ofnode_get_path() - get the full path of a node + * + * @node: valid node to look up + * @buf: buffer to write the node path into + * @buflen: buffer size + * @return 0 if OK, -ve on error + */ +int ofnode_get_path(ofnode node, char *buf, int buflen); + /** * ofnode_get_by_phandle() - get ofnode from phandle * diff --git a/test/dm/ofnode.c b/test/dm/ofnode.c index 9a69cf70c1..94a4d2189e 100644 --- a/test/dm/ofnode.c +++ b/test/dm/ofnode.c @@ -297,3 +297,24 @@ static int dm_test_ofnode_get_reg(struct unit_test_state *uts) return 0; } DM_TEST(dm_test_ofnode_get_reg, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); + +static int dm_test_ofnode_get_path(struct unit_test_state *uts) +{ + const char *path = "/translation-test@8000/noxlatebus@3,300/dev@42"; + char buf[64]; + ofnode node; + int res; + + node = ofnode_path(path); + ut_assert(ofnode_valid(node)); + + res = ofnode_get_path(node, buf, 64); + ut_asserteq(0, res); + ut_asserteq_str(path, buf); + + res = ofnode_get_path(node, buf, 32); + ut_asserteq(-ENOSPC, res); + + return 0; +} +DM_TEST(dm_test_ofnode_get_path, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); From dc339bf784f08707583a5b6465381354f48d4fa8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Wed, 26 May 2021 14:08:19 +0200 Subject: [PATCH 05/12] mtd: add support for parsing partitions defined in OF MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for parsing partitions defined in device-trees via the `partitions` node with `fixed-partitions` compatible. The `mtdparts`/`mtdids` mechanism takes precedence. If some partitions are defined for a MTD device via this mechanism, the code won't register partitions for that MTD device from OF, even if they are defined. Signed-off-by: Marek Behún Reviewed-by: Miquel Raynal Tested-by: Patrice Chotard Reviewed-by: Jagan Teki Cc: Simon Glass Cc: Heiko Schocher Cc: Patrick Delaunay --- drivers/mtd/mtd_uboot.c | 106 +++++++++++++++++++++++----------------- drivers/mtd/mtdpart.c | 63 ++++++++++++++++++++++++ include/linux/mtd/mtd.h | 10 ++++ 3 files changed, 135 insertions(+), 44 deletions(-) diff --git a/drivers/mtd/mtd_uboot.c b/drivers/mtd/mtd_uboot.c index c53ec657a3..4843cf1b84 100644 --- a/drivers/mtd/mtd_uboot.c +++ b/drivers/mtd/mtd_uboot.c @@ -198,53 +198,11 @@ static void mtd_del_all_parts(void) } while (ret > 0); } -int mtd_probe_devices(void) +static int parse_mtdparts(const char *mtdparts, const char *mtdids) { - static char *old_mtdparts; - static char *old_mtdids; - const char *mtdparts = get_mtdparts(); - const char *mtdids = get_mtdids(); - const char *mtdparts_next = mtdparts; + const char *mtdparts_next; struct mtd_info *mtd; - mtd_probe_uclass_mtd_devs(); - - /* - * Check if mtdparts/mtdids changed, if the MTD dev list was updated - * or if our previous attempt to delete existing partititions failed. - * In any of these cases we want to update the partitions, otherwise, - * everything is up-to-date and we can return 0 directly. - */ - if ((!mtdparts && !old_mtdparts && !mtdids && !old_mtdids) || - (mtdparts && old_mtdparts && mtdids && old_mtdids && - !mtd_dev_list_updated() && !mtd_del_all_parts_failed && - !strcmp(mtdparts, old_mtdparts) && - !strcmp(mtdids, old_mtdids))) - return 0; - - /* Update the local copy of mtdparts */ - free(old_mtdparts); - free(old_mtdids); - old_mtdparts = strdup(mtdparts); - old_mtdids = strdup(mtdids); - - /* - * Remove all old parts. Note that partition removal can fail in case - * one of the partition is still being used by an MTD user, so this - * does not guarantee that all old partitions are gone. - */ - mtd_del_all_parts(); - - /* - * Call mtd_dev_list_updated() to clear updates generated by our own - * parts removal loop. - */ - mtd_dev_list_updated(); - - /* If either mtdparts or mtdids is empty, then exit */ - if (!mtdparts || !mtdids) - return 0; - /* Start the parsing by ignoring the extra 'mtdparts=' prefix, if any */ if (!strncmp(mtdparts, "mtdparts=", sizeof("mtdparts=") - 1)) mtdparts += 9; @@ -343,6 +301,66 @@ int mtd_probe_devices(void) put_mtd_device(mtd); } + return 0; +} + +int mtd_probe_devices(void) +{ + static char *old_mtdparts; + static char *old_mtdids; + const char *mtdparts = get_mtdparts(); + const char *mtdids = get_mtdids(); + struct mtd_info *mtd; + + mtd_probe_uclass_mtd_devs(); + + /* + * Check if mtdparts/mtdids changed, if the MTD dev list was updated + * or if our previous attempt to delete existing partititions failed. + * In any of these cases we want to update the partitions, otherwise, + * everything is up-to-date and we can return 0 directly. + */ + if ((!mtdparts && !old_mtdparts && !mtdids && !old_mtdids) || + (mtdparts && old_mtdparts && mtdids && old_mtdids && + !mtd_dev_list_updated() && !mtd_del_all_parts_failed && + !strcmp(mtdparts, old_mtdparts) && + !strcmp(mtdids, old_mtdids))) + return 0; + + /* Update the local copy of mtdparts */ + free(old_mtdparts); + free(old_mtdids); + old_mtdparts = strdup(mtdparts); + old_mtdids = strdup(mtdids); + + /* + * Remove all old parts. Note that partition removal can fail in case + * one of the partition is still being used by an MTD user, so this + * does not guarantee that all old partitions are gone. + */ + mtd_del_all_parts(); + + /* + * Call mtd_dev_list_updated() to clear updates generated by our own + * parts removal loop. + */ + mtd_dev_list_updated(); + + /* If both mtdparts and mtdids are non-empty, parse */ + if (mtdparts && mtdids) { + if (parse_mtdparts(mtdparts, mtdids) < 0) + printf("Failed parsing MTD partitions from mtdparts!\n"); + } + + /* Fallback to OF partitions */ + mtd_for_each_device(mtd) { + if (list_empty(&mtd->partitions)) { + if (add_mtd_partitions_of(mtd) < 0) + printf("Failed parsing MTD %s OF partitions!\n", + mtd->name); + } + } + /* * Call mtd_dev_list_updated() to clear updates generated by our own * parts registration loop. diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index d064ac3048..aa58f722da 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c @@ -892,6 +892,69 @@ int add_mtd_partitions(struct mtd_info *master, return 0; } +#if CONFIG_IS_ENABLED(DM) && CONFIG_IS_ENABLED(OF_CONTROL) +int add_mtd_partitions_of(struct mtd_info *master) +{ + ofnode parts, child; + int i = 0; + + if (!master->dev) + return 0; + + parts = ofnode_find_subnode(mtd_get_ofnode(master), "partitions"); + if (!ofnode_valid(parts) || !ofnode_is_available(parts) || + !ofnode_device_is_compatible(parts, "fixed-partitions")) + return 0; + + ofnode_for_each_subnode(child, parts) { + struct mtd_partition part = { 0 }; + struct mtd_info *slave; + fdt_addr_t offset, size; + + if (!ofnode_is_available(child)) + continue; + + offset = ofnode_get_addr_size_index_notrans(child, 0, &size); + if (offset == FDT_ADDR_T_NONE || !size) { + debug("Missing partition offset/size on \"%s\" partition\n", + master->name); + continue; + } + + part.name = ofnode_read_string(child, "label"); + if (!part.name) + part.name = ofnode_read_string(child, "name"); + + /* + * .mask_flags is used to remove flags in allocate_partition(), + * so when "read-only" is present, we add MTD_WRITABLE to the + * mask, and so MTD_WRITABLE will be removed on partition + * allocation + */ + if (ofnode_read_bool(child, "read-only")) + part.mask_flags |= MTD_WRITEABLE; + if (ofnode_read_bool(child, "lock")) + part.mask_flags |= MTD_POWERUP_LOCK; + + part.offset = offset; + part.size = size; + part.ecclayout = master->ecclayout; + + slave = allocate_partition(master, &part, i++, 0); + if (IS_ERR(slave)) + return PTR_ERR(slave); + + mutex_lock(&mtd_partitions_mutex); + list_add_tail(&slave->node, &master->partitions); + mutex_unlock(&mtd_partitions_mutex); + + add_mtd_device(slave); + } + + return 0; +} +#endif /* CONFIG_IS_ENABLED(DM) && CONFIG_IS_ENABLED(OF_CONTROL) */ + #ifndef __UBOOT__ static DEFINE_SPINLOCK(part_parser_lock); static LIST_HEAD(part_parsers); diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h index 927854950a..3b302fb8c3 100644 --- a/include/linux/mtd/mtd.h +++ b/include/linux/mtd/mtd.h @@ -581,6 +581,16 @@ static inline int del_mtd_partitions(struct mtd_info *mtd) } #endif +#if defined(CONFIG_MTD_PARTITIONS) && CONFIG_IS_ENABLED(DM) && \ + CONFIG_IS_ENABLED(OF_CONTROL) +int add_mtd_partitions_of(struct mtd_info *master); +#else +static inline int add_mtd_partitions_of(struct mtd_info *master) +{ + return 0; +} +#endif + struct mtd_info *__mtd_next_device(int i); #define mtd_for_each_device(mtd) \ for ((mtd) = __mtd_next_device(0); \ From b7f060565e3161f8977a3a93e4b31ed6031af874 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Wed, 26 May 2021 14:08:20 +0200 Subject: [PATCH 06/12] mtd: spi-nor: allow registering multiple MTDs when DM is enabled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently when the SPI_FLASH_MTD config option is enabled, only one SPI can be registered as MTD at any time - it is the last one probed (since with old non-DM model only one SPI NOR could be probed at any time). When DM is enabled, allow for registering multiple SPI NORs as MTDs by utilizing the nor->mtd structure, which is filled in by spi_nor_scan anyway, instead of filling a separate struct mtd_info. Signed-off-by: Marek Behún Reviewed-by: Pali Rohár Reviewed-by: Miquel Raynal Tested-by: Patrice Chotard Reviewed-by: Jagan Teki Cc: Priyanka Jain Cc: Simon Glass Cc: Heiko Schocher Cc: Patrick Delaunay --- drivers/mtd/spi/sf_internal.h | 4 ++-- drivers/mtd/spi/sf_mtd.c | 18 +++++++++++++++++- drivers/mtd/spi/sf_probe.c | 6 ++++-- 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h index 786301ba4a..0b63e1bfc2 100644 --- a/drivers/mtd/spi/sf_internal.h +++ b/drivers/mtd/spi/sf_internal.h @@ -81,14 +81,14 @@ int spi_flash_cmd_get_sw_write_prot(struct spi_flash *flash); #if CONFIG_IS_ENABLED(SPI_FLASH_MTD) int spi_flash_mtd_register(struct spi_flash *flash); -void spi_flash_mtd_unregister(void); +void spi_flash_mtd_unregister(struct spi_flash *flash); #else static inline int spi_flash_mtd_register(struct spi_flash *flash) { return 0; } -static inline void spi_flash_mtd_unregister(void) +static inline void spi_flash_mtd_unregister(struct spi_flash *flash) { } #endif diff --git a/drivers/mtd/spi/sf_mtd.c b/drivers/mtd/spi/sf_mtd.c index 987fac2501..94854fbfc4 100644 --- a/drivers/mtd/spi/sf_mtd.c +++ b/drivers/mtd/spi/sf_mtd.c @@ -10,6 +10,20 @@ #include #include +#if CONFIG_IS_ENABLED(DM_SPI_FLASH) + +int spi_flash_mtd_register(struct spi_flash *flash) +{ + return add_mtd_device(&flash->mtd); +} + +void spi_flash_mtd_unregister(struct spi_flash *flash) +{ + del_mtd_device(&flash->mtd); +} + +#else /* !CONFIG_IS_ENABLED(DM_SPI_FLASH) */ + static struct mtd_info sf_mtd_info; static bool sf_mtd_registered; static char sf_mtd_name[8]; @@ -123,7 +137,7 @@ int spi_flash_mtd_register(struct spi_flash *flash) return ret; } -void spi_flash_mtd_unregister(void) +void spi_flash_mtd_unregister(struct spi_flash *flash) { int ret; @@ -146,3 +160,5 @@ void spi_flash_mtd_unregister(void) printf("Failed to unregister MTD %s and the spi_flash object is going away: you're in deep trouble!", sf_mtd_info.name); } + +#endif /* !CONFIG_IS_ENABLED(DM_SPI_FLASH) */ diff --git a/drivers/mtd/spi/sf_probe.c b/drivers/mtd/spi/sf_probe.c index 3befbe91ca..7edb8759fd 100644 --- a/drivers/mtd/spi/sf_probe.c +++ b/drivers/mtd/spi/sf_probe.c @@ -84,7 +84,7 @@ struct spi_flash *spi_flash_probe(unsigned int busnum, unsigned int cs, void spi_flash_free(struct spi_flash *flash) { if (CONFIG_IS_ENABLED(SPI_FLASH_MTD)) - spi_flash_mtd_unregister(); + spi_flash_mtd_unregister(flash); spi_free_slave(flash->spi); free(flash); @@ -150,8 +150,10 @@ int spi_flash_std_probe(struct udevice *dev) static int spi_flash_std_remove(struct udevice *dev) { + struct spi_flash *flash = dev_get_uclass_priv(dev); + if (CONFIG_IS_ENABLED(SPI_FLASH_MTD)) - spi_flash_mtd_unregister(); + spi_flash_mtd_unregister(flash); return 0; } From 2d1a9a6b265f79be495201dadf7f3aa315b8a5e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Wed, 26 May 2021 14:08:21 +0200 Subject: [PATCH 07/12] mtd: spi-nor: fill-in mtd->dev member MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fill in mtd->dev member with nor->dev. This can be used by MTD OF partition parser. Signed-off-by: Marek Behún Reviewed-by: Pali Rohár Reviewed-by: Miquel Raynal Tested-by: Patrice Chotard Reviewed-by: Jagan Teki Cc: Priyanka Jain Cc: Simon Glass Cc: Heiko Schocher Cc: Patrick Delaunay --- drivers/mtd/spi/sf_mtd.c | 1 + drivers/mtd/spi/spi-nor-core.c | 1 + drivers/mtd/spi/spi-nor-tiny.c | 1 + 3 files changed, 3 insertions(+) diff --git a/drivers/mtd/spi/sf_mtd.c b/drivers/mtd/spi/sf_mtd.c index 94854fbfc4..04de868080 100644 --- a/drivers/mtd/spi/sf_mtd.c +++ b/drivers/mtd/spi/sf_mtd.c @@ -125,6 +125,7 @@ int spi_flash_mtd_register(struct spi_flash *flash) sf_mtd_info.size = flash->size; sf_mtd_info.priv = flash; + sf_mtd_info.dev = flash->dev; /* Only uniform flash devices for now */ sf_mtd_info.numeraseregions = 0; diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c index a6625535a7..6af9c675a4 100644 --- a/drivers/mtd/spi/spi-nor-core.c +++ b/drivers/mtd/spi/spi-nor-core.c @@ -2535,6 +2535,7 @@ int spi_nor_scan(struct spi_nor *nor) if (!mtd->name) mtd->name = info->name; + mtd->dev = nor->dev; mtd->priv = nor; mtd->type = MTD_NORFLASH; mtd->writesize = 1; diff --git a/drivers/mtd/spi/spi-nor-tiny.c b/drivers/mtd/spi/spi-nor-tiny.c index 1d5861d55c..b0aa97d324 100644 --- a/drivers/mtd/spi/spi-nor-tiny.c +++ b/drivers/mtd/spi/spi-nor-tiny.c @@ -751,6 +751,7 @@ int spi_nor_scan(struct spi_nor *nor) return ret; mtd->name = "spi-flash"; + mtd->dev = nor->dev; mtd->priv = nor; mtd->type = MTD_NORFLASH; mtd->writesize = 1; From 69e57c4753dd5428e9e5ed6d1399c8532f744efc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Wed, 26 May 2021 14:08:22 +0200 Subject: [PATCH 08/12] mtd: remove mtd_probe() function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The device_probe() function does the same thing as mtd_probe() and mtd_probe() is only used in mtd_probe_uclass_mtd_devs(), where the probing can be made simpler by using uclass_foreach_dev_probe macro. Signed-off-by: Marek Behún Reviewed-by: Pali Rohár Reviewed-by: Miquel Raynal Tested-by: Patrice Chotard Reviewed-by: Jagan Teki Cc: Priyanka Jain Cc: Simon Glass Cc: Heiko Schocher Cc: Patrick Delaunay --- drivers/mtd/mtd-uclass.c | 15 --------------- drivers/mtd/mtd_uboot.c | 9 +++------ include/mtd.h | 1 - 3 files changed, 3 insertions(+), 22 deletions(-) diff --git a/drivers/mtd/mtd-uclass.c b/drivers/mtd/mtd-uclass.c index 9f5f672ba3..4ab84de553 100644 --- a/drivers/mtd/mtd-uclass.c +++ b/drivers/mtd/mtd-uclass.c @@ -9,21 +9,6 @@ #include #include -/** - * mtd_probe - Probe the device @dev if not already done - * - * @dev: U-Boot device to probe - * - * @return 0 on success, an error otherwise. - */ -int mtd_probe(struct udevice *dev) -{ - if (device_active(dev)) - return 0; - - return device_probe(dev); -} - /* * Implement a MTD uclass which should include most flash drivers. * The uclass private is pointed to mtd_info. diff --git a/drivers/mtd/mtd_uboot.c b/drivers/mtd/mtd_uboot.c index 4843cf1b84..a652d431ba 100644 --- a/drivers/mtd/mtd_uboot.c +++ b/drivers/mtd/mtd_uboot.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -106,13 +107,9 @@ int mtd_search_alternate_name(const char *mtdname, char *altname, static void mtd_probe_uclass_mtd_devs(void) { struct udevice *dev; - int idx = 0; - /* Probe devices with DM compliant drivers */ - while (!uclass_find_device(UCLASS_MTD, idx, &dev) && dev) { - mtd_probe(dev); - idx++; - } + uclass_foreach_dev_probe(UCLASS_MTD, dev) + ; } #else static void mtd_probe_uclass_mtd_devs(void) { } diff --git a/include/mtd.h b/include/mtd.h index b0f8693386..b569331edb 100644 --- a/include/mtd.h +++ b/include/mtd.h @@ -8,7 +8,6 @@ #include -int mtd_probe(struct udevice *dev); int mtd_probe_devices(void); void board_mtdparts_default(const char **mtdids, const char **mtdparts); From 3c58c79b5ff1fb75780be18b86d1ae64b19c2136 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Wed, 26 May 2021 14:08:23 +0200 Subject: [PATCH 09/12] mtd: probe SPI NOR devices in mtd_probe_devices() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In order for `mtd list` U-Boot command to list SPI NOR devices without the need to run `sf probe` before, we have to probe SPI NOR devices in mtd_probe_devices(). Signed-off-by: Marek Behún Reviewed-by: Pali Rohár Reviewed-by: Miquel Raynal Tested-by: Patrice Chotard Reviewed-by: Jagan Teki Cc: Priyanka Jain Cc: Simon Glass Cc: Heiko Schocher Cc: Patrick Delaunay --- drivers/mtd/mtd_uboot.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/mtd/mtd_uboot.c b/drivers/mtd/mtd_uboot.c index a652d431ba..90767ec417 100644 --- a/drivers/mtd/mtd_uboot.c +++ b/drivers/mtd/mtd_uboot.c @@ -115,6 +115,18 @@ static void mtd_probe_uclass_mtd_devs(void) static void mtd_probe_uclass_mtd_devs(void) { } #endif +#if IS_ENABLED(CONFIG_DM_SPI_FLASH) && IS_ENABLED(CONFIG_SPI_FLASH_MTD) +static void mtd_probe_uclass_spi_nor_devs(void) +{ + struct udevice *dev; + + uclass_foreach_dev_probe(UCLASS_SPI_FLASH, dev) + ; +} +#else +static void mtd_probe_uclass_spi_nor_devs(void) { } +#endif + #if defined(CONFIG_MTD_PARTITIONS) #define MTDPARTS_MAXLEN 512 @@ -310,6 +322,7 @@ int mtd_probe_devices(void) struct mtd_info *mtd; mtd_probe_uclass_mtd_devs(); + mtd_probe_uclass_spi_nor_devs(); /* * Check if mtdparts/mtdids changed, if the MTD dev list was updated @@ -370,6 +383,7 @@ int mtd_probe_devices(void) int mtd_probe_devices(void) { mtd_probe_uclass_mtd_devs(); + mtd_probe_uclass_spi_nor_devs(); return 0; } From 0b6f907d1543f1670460a797d62f49231b92ca98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Wed, 26 May 2021 14:08:24 +0200 Subject: [PATCH 10/12] cmd: mtd: print device OF path in listing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Print MTD's device OF path in the output of `mtd list` command. Signed-off-by: Marek Behún Reviewed-by: Miquel Raynal Tested-by: Patrice Chotard Reviewed-by: Jagan Teki Cc: Priyanka Jain Cc: Simon Glass Cc: Heiko Schocher Cc: Patrick Delaunay --- cmd/mtd.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/cmd/mtd.c b/cmd/mtd.c index 485a963bdd..2aabfd4d29 100644 --- a/cmd/mtd.c +++ b/cmd/mtd.c @@ -126,6 +126,13 @@ static void mtd_show_device(struct mtd_info *mtd) printf(" - driver: %s\n", mtd->dev->driver->name); } #endif + if (IS_ENABLED(CONFIG_OF_CONTROL) && mtd->dev) { + char buf[256]; + int res; + + res = ofnode_get_path(mtd_get_ofnode(mtd), buf, 256); + printf(" - path: %s\n", res == 0 ? buf : "unavailable"); + } /* MTD device information */ printf(" - type: "); From dcb9a80359d699cf659c95b9b6e6604e2d68adb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Wed, 26 May 2021 14:08:25 +0200 Subject: [PATCH 11/12] mtd: compare also with OF path and device name in get_mtd_device_nm() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The get_mtd_device_nm() function (code imported from Linux) simply iterates all registered MTD devices and compares the given name with all MTDs' names. With SPI_FLASH_MTD enabled U-Boot registers a SPI-NOR as a MTD device with name identical to the SPI flash chip name (from SPI ID table). Thus for a board with multiple same SPI-NORs it registers multiple MTDs, but all with the same name (such as "s25fl164k"). We do not want to change this behaviour, since such a change could break existing boot scripts, which can rely on a hardcoded name. In order to allow somehow to uniqely select a MTD device, change get_mtd_device_nm() function as such: - if first character of name is '/', try interpreting it as OF path - otherwise compare the name with MTDs name and MTDs device name. In the following example a board has two "s25fl164k" SPI-NORs. They both have name "s25fl164k", thus cannot be uniquely selected via this name. With this change, the user can select the second SPI-NOR either with "spi-nor@1" or "/soc/spi@10600/spi-nor@1". Example: => mtd list List of MTD devices: * s25fl164k - device: spi-nor@0 - parent: spi@10600 - driver: jedec_spi_nor - path: /soc/spi@10600/spi-nor@0 - type: NOR flash - block size: 0x1000 bytes - min I/O: 0x1 bytes - 0x000000000000-0x000000800000 : "s25fl164k" * s25fl164k - device: spi-nor@1 - parent: spi@10600 - driver: jedec_spi_nor - path: /soc/spi@10600/spi-nor@1 - type: NOR flash - block size: 0x1000 bytes - min I/O: 0x1 bytes - 0x000000000000-0x000000800000 : "s25fl164k" Signed-off-by: Marek Behún Reviewed-by: Miquel Raynal Tested-by: Patrice Chotard Reviewed-by: Jagan Teki Cc: Priyanka Jain Cc: Simon Glass Cc: Heiko Schocher Cc: Patrick Delaunay --- drivers/mtd/mtdcore.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index 0d1f94c6cb..582129d0df 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -768,6 +768,32 @@ int __get_mtd_device(struct mtd_info *mtd) } EXPORT_SYMBOL_GPL(__get_mtd_device); +#if CONFIG_IS_ENABLED(DM) && CONFIG_IS_ENABLED(OF_CONTROL) +static bool mtd_device_matches_name(struct mtd_info *mtd, const char *name) +{ + struct udevice *dev = NULL; + bool is_part; + + /* + * If the first character of mtd name is '/', try interpreting as OF + * path. Otherwise try comparing by mtd->name and mtd->dev->name. + */ + if (*name == '/') + device_get_global_by_ofnode(ofnode_path(name), &dev); + + is_part = mtd_is_partition(mtd); + + return (!is_part && dev && mtd->dev == dev) || + !strcmp(name, mtd->name) || + (is_part && mtd->dev && !strcmp(name, mtd->dev->name)); +} +#else +static bool mtd_device_matches_name(struct mtd_info *mtd, const char *name) +{ + return !strcmp(name, mtd->name); +} +#endif + /** * get_mtd_device_nm - obtain a validated handle for an MTD device by * device name @@ -784,10 +810,19 @@ struct mtd_info *get_mtd_device_nm(const char *name) mutex_lock(&mtd_table_mutex); mtd_for_each_device(other) { +#ifdef __UBOOT__ + if (mtd_device_matches_name(other, name)) { + if (mtd) + printf("\nWarning: MTD name \"%s\" is not unique!\n\n", + name); + mtd = other; + } +#else /* !__UBOOT__ */ if (!strcmp(name, other->name)) { mtd = other; break; } +#endif /* !__UBOOT__ */ } if (!mtd) From e41a2bc6b87397ef0aeda4132a8227d164cd592b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Wed, 26 May 2021 14:08:26 +0200 Subject: [PATCH 12/12] cmd: mtd: expand argument definition in command help MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The argument can now also be MTD's DM device name or OF path. Mention this is command help. Signed-off-by: Marek Behún Reviewed-by: Miquel Raynal Tested-by: Patrice Chotard Reviewed-by: Jagan Teki Cc: Priyanka Jain Cc: Simon Glass Cc: Heiko Schocher Cc: Patrick Delaunay --- cmd/mtd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/mtd.c b/cmd/mtd.c index 2aabfd4d29..c22478c152 100644 --- a/cmd/mtd.c +++ b/cmd/mtd.c @@ -542,7 +542,7 @@ static char mtd_help_text[] = "mtd bad \n" "\n" "With:\n" - "\t: NAND partition/chip name\n" + "\t: NAND partition/chip name (or corresponding DM device name or OF path)\n" "\t: user address from/to which data will be retrieved/stored\n" "\t: offset in in bytes (default: start of the part)\n" "\t\t* must be block-aligned for erase\n"