diff --git a/target/linux/airoha/patches-6.12/901-snand-mtk-bmt-support.patch b/target/linux/airoha/patches-6.12/901-snand-mtk-bmt-support.patch index f715652319..eb77fde066 100644 --- a/target/linux/airoha/patches-6.12/901-snand-mtk-bmt-support.patch +++ b/target/linux/airoha/patches-6.12/901-snand-mtk-bmt-support.patch @@ -8,7 +8,7 @@ static int spinand_read_reg_op(struct spinand_device *spinand, u8 reg, u8 *val) { -@@ -1530,6 +1531,7 @@ static int spinand_probe(struct spi_mem +@@ -1574,6 +1575,7 @@ static int spinand_probe(struct spi_mem if (ret) return ret; @@ -16,7 +16,7 @@ ret = mtd_device_register(mtd, NULL, 0); if (ret) goto err_spinand_cleanup; -@@ -1537,6 +1539,7 @@ static int spinand_probe(struct spi_mem +@@ -1581,6 +1583,7 @@ static int spinand_probe(struct spi_mem return 0; err_spinand_cleanup: @@ -24,7 +24,7 @@ spinand_cleanup(spinand); return ret; -@@ -1555,6 +1558,7 @@ static int spinand_remove(struct spi_mem +@@ -1599,6 +1602,7 @@ static int spinand_remove(struct spi_mem if (ret) return ret; diff --git a/target/linux/generic/pending-6.12/405-01-mtd-spinand-fix-direct-mapping-creation-sizes.patch b/target/linux/generic/pending-6.12/405-01-mtd-spinand-fix-direct-mapping-creation-sizes.patch new file mode 100644 index 0000000000..3cb7844800 --- /dev/null +++ b/target/linux/generic/pending-6.12/405-01-mtd-spinand-fix-direct-mapping-creation-sizes.patch @@ -0,0 +1,62 @@ +From 5eea4228aaa3c5aeba843d8ea2a60993c268419d Mon Sep 17 00:00:00 2001 +From: Mikhail Kshevetskiy +Date: Sun, 3 Aug 2025 17:23:27 +0300 +Subject: [PATCH RESEND v5 1/3] mtd: spinand: fix direct mapping creation sizes + +Continuous mode is only supported for data reads, thus writing +requires only single flash page mapping. + +Signed-off-by: Mikhail Kshevetskiy +--- + drivers/mtd/nand/spi/core.c | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +--- a/drivers/mtd/nand/spi/core.c ++++ b/drivers/mtd/nand/spi/core.c +@@ -1028,18 +1028,13 @@ static int spinand_create_dirmap(struct + unsigned int plane) + { + struct nand_device *nand = spinand_to_nand(spinand); +- struct spi_mem_dirmap_info info = { +- .length = nanddev_page_size(nand) + +- nanddev_per_page_oobsize(nand), +- }; ++ struct spi_mem_dirmap_info info = { 0 }; + struct spi_mem_dirmap_desc *desc; + +- if (spinand->cont_read_possible) +- info.length = nanddev_eraseblock_size(nand); +- + /* The plane number is passed in MSB just above the column address */ + info.offset = plane << fls(nand->memorg.pagesize); + ++ info.length = nanddev_page_size(nand) + nanddev_per_page_oobsize(nand); + info.op_tmpl = *spinand->op_templates.update_cache; + desc = devm_spi_mem_dirmap_create(&spinand->spimem->spi->dev, + spinand->spimem, &info); +@@ -1048,6 +1043,8 @@ static int spinand_create_dirmap(struct + + spinand->dirmaps[plane].wdesc = desc; + ++ if (spinand->cont_read_possible) ++ info.length = nanddev_eraseblock_size(nand); + info.op_tmpl = *spinand->op_templates.read_cache; + desc = devm_spi_mem_dirmap_create(&spinand->spimem->spi->dev, + spinand->spimem, &info); +@@ -1063,6 +1060,7 @@ static int spinand_create_dirmap(struct + return 0; + } + ++ info.length = nanddev_page_size(nand) + nanddev_per_page_oobsize(nand); + info.op_tmpl = *spinand->op_templates.update_cache; + info.op_tmpl.data.ecc = true; + desc = devm_spi_mem_dirmap_create(&spinand->spimem->spi->dev, +@@ -1072,6 +1070,8 @@ static int spinand_create_dirmap(struct + + spinand->dirmaps[plane].wdesc_ecc = desc; + ++ if (spinand->cont_read_possible) ++ info.length = nanddev_eraseblock_size(nand); + info.op_tmpl = *spinand->op_templates.read_cache; + info.op_tmpl.data.ecc = true; + desc = devm_spi_mem_dirmap_create(&spinand->spimem->spi->dev, diff --git a/target/linux/generic/pending-6.12/405-02-mtd-spinand-try-a-regular-dirmap-if-creating-a-di.patch b/target/linux/generic/pending-6.12/405-02-mtd-spinand-try-a-regular-dirmap-if-creating-a-di.patch new file mode 100644 index 0000000000..5c54a9116c --- /dev/null +++ b/target/linux/generic/pending-6.12/405-02-mtd-spinand-try-a-regular-dirmap-if-creating-a-di.patch @@ -0,0 +1,97 @@ +From 9d13b7857de8834c6246fa5bc83f767675360240 Mon Sep 17 00:00:00 2001 +From: Mikhail Kshevetskiy +Date: Sun, 3 Aug 2025 19:06:40 +0300 +Subject: [PATCH RESEND v5 2/3] mtd: spinand: try a regular dirmap if creating + a dirmap for continuous reading fails + +Continuous reading may result in multiple flash pages reading in one +operation. Typically only one flash page has read/written (a little bit +more than 2-4 Kb), but continuous reading requires the spi controller +to read up to 512 Kb in one operation without toggling CS in beetween. + +Roughly speaking spi controllers can be divided on 2 categories: + * spi controllers without dirmap acceleration support + * spi controllers with dirmap acceleration support + +Firt of them will have issues with continuous reading if restriction on +the transfer length is implemented in the adjust_op_size() handler. +Second group often supports acceleration of single page only reading. +Thus enabling of continuous reading can break flash reading. + +This patch tries to create dirmap for continuous reading first and +fallback to regular reading if spi controller refuses to create it. + +Signed-off-by: Mikhail Kshevetskiy +--- + drivers/mtd/nand/spi/core.c | 43 ++++++++++++++++++++++++++++++------- + 1 file changed, 35 insertions(+), 8 deletions(-) + +--- a/drivers/mtd/nand/spi/core.c ++++ b/drivers/mtd/nand/spi/core.c +@@ -1024,6 +1024,39 @@ static int spinand_mtd_block_isreserved( + return ret; + } + ++static struct spi_mem_dirmap_desc *spinand_create_rdesc( ++ struct spinand_device *spinand, ++ struct spi_mem_dirmap_info *info) ++{ ++ struct nand_device *nand = spinand_to_nand(spinand); ++ struct spi_mem_dirmap_desc *desc = NULL; ++ ++ if (spinand->cont_read_possible) { ++ /* ++ * spi controller may return an error if info->length is ++ * too large ++ */ ++ info->length = nanddev_eraseblock_size(nand); ++ desc = devm_spi_mem_dirmap_create(&spinand->spimem->spi->dev, ++ spinand->spimem, info); ++ } ++ ++ if (IS_ERR_OR_NULL(desc)) { ++ /* ++ * continuous reading is not supported by flash or ++ * its spi controller, use regular reading ++ */ ++ spinand->cont_read_possible = false; ++ ++ info->length = nanddev_page_size(nand) + ++ nanddev_per_page_oobsize(nand); ++ desc = devm_spi_mem_dirmap_create(&spinand->spimem->spi->dev, ++ spinand->spimem, info); ++ } ++ ++ return desc; ++} ++ + static int spinand_create_dirmap(struct spinand_device *spinand, + unsigned int plane) + { +@@ -1043,11 +1076,8 @@ static int spinand_create_dirmap(struct + + spinand->dirmaps[plane].wdesc = desc; + +- if (spinand->cont_read_possible) +- info.length = nanddev_eraseblock_size(nand); + info.op_tmpl = *spinand->op_templates.read_cache; +- desc = devm_spi_mem_dirmap_create(&spinand->spimem->spi->dev, +- spinand->spimem, &info); ++ desc = spinand_create_rdesc(spinand, &info); + if (IS_ERR(desc)) + return PTR_ERR(desc); + +@@ -1070,12 +1100,9 @@ static int spinand_create_dirmap(struct + + spinand->dirmaps[plane].wdesc_ecc = desc; + +- if (spinand->cont_read_possible) +- info.length = nanddev_eraseblock_size(nand); + info.op_tmpl = *spinand->op_templates.read_cache; + info.op_tmpl.data.ecc = true; +- desc = devm_spi_mem_dirmap_create(&spinand->spimem->spi->dev, +- spinand->spimem, &info); ++ desc = spinand_create_rdesc(spinand, &info); + if (IS_ERR(desc)) + return PTR_ERR(desc); + diff --git a/target/linux/generic/pending-6.12/405-03-mtd-spinand-repeat-reading-in-regular-mode-if-con.patch b/target/linux/generic/pending-6.12/405-03-mtd-spinand-repeat-reading-in-regular-mode-if-con.patch new file mode 100644 index 0000000000..ad13fbafc3 --- /dev/null +++ b/target/linux/generic/pending-6.12/405-03-mtd-spinand-repeat-reading-in-regular-mode-if-con.patch @@ -0,0 +1,63 @@ +From 6ffbbe473b98e3944d4cb9379bf725b374e587a9 Mon Sep 17 00:00:00 2001 +From: Mikhail Kshevetskiy +Date: Sun, 3 Aug 2025 17:54:17 +0300 +Subject: [PATCH RESEND v5 3/3] mtd: spinand: repeat reading in regular mode if + continuous reading fails + +Continuous reading may result in multiple flash pages reading in one +operation. Unfortunately, not all spinand controllers support such +large reading. They will read less data. Unfortunately, the operation +can't be continued. + +In this case: + * disable continuous reading on this (not good enough) spi controller + * repeat reading in regular mode. + +Signed-off-by: Mikhail Kshevetskiy +--- + drivers/mtd/nand/spi/core.c | 25 +++++++++++++++++++++---- + 1 file changed, 21 insertions(+), 4 deletions(-) + +--- a/drivers/mtd/nand/spi/core.c ++++ b/drivers/mtd/nand/spi/core.c +@@ -427,8 +427,16 @@ static int spinand_read_from_cache_op(st + * Dirmap accesses are allowed to toggle the CS. + * Toggling the CS during a continuous read is forbidden. + */ +- if (nbytes && req->continuous) +- return -EIO; ++ if (nbytes && req->continuous) { ++ /* ++ * Spi controller with broken support of continuous ++ * reading was detected. Disable future use of ++ * continuous reading and return -EAGAIN to retry ++ * reading within regular mode. ++ */ ++ spinand->cont_read_possible = false; ++ return -EAGAIN; ++ } + } + + if (req->datalen) +@@ -841,10 +849,19 @@ static int spinand_mtd_read(struct mtd_i + + old_stats = mtd->ecc_stats; + +- if (spinand_use_cont_read(mtd, from, ops)) ++ if (spinand_use_cont_read(mtd, from, ops)) { + ret = spinand_mtd_continuous_page_read(mtd, from, ops, &max_bitflips); +- else ++ if (ret == -EAGAIN && !spinand->cont_read_possible) { ++ /* ++ * Spi controller with broken support of continuous ++ * reading was detected (see spinand_read_from_cache_op()), ++ * repeat reading in regular mode. ++ */ ++ ret = spinand_mtd_regular_page_read(mtd, from, ops, &max_bitflips); ++ } ++ } else { + ret = spinand_mtd_regular_page_read(mtd, from, ops, &max_bitflips); ++ } + + if (ops->stats) { + ops->stats->uncorrectable_errors += diff --git a/target/linux/generic/pending-6.12/487-mtd-spinand-Add-support-for-Etron-EM73D044VCx.patch b/target/linux/generic/pending-6.12/487-mtd-spinand-Add-support-for-Etron-EM73D044VCx.patch index df22fda59c..34fb47a5fb 100644 --- a/target/linux/generic/pending-6.12/487-mtd-spinand-Add-support-for-Etron-EM73D044VCx.patch +++ b/target/linux/generic/pending-6.12/487-mtd-spinand-Add-support-for-Etron-EM73D044VCx.patch @@ -49,7 +49,7 @@ Submitted-by: Daniel Danzberger obj-$(CONFIG_MTD_SPI_NAND) += spinand.o --- a/drivers/mtd/nand/spi/core.c +++ b/drivers/mtd/nand/spi/core.c -@@ -1115,6 +1115,7 @@ static const struct spinand_manufacturer +@@ -1159,6 +1159,7 @@ static const struct spinand_manufacturer &alliancememory_spinand_manufacturer, &ato_spinand_manufacturer, &esmt_c8_spinand_manufacturer, diff --git a/target/linux/mediatek/patches-6.12/121-hack-spi-nand-1b-bbm.patch b/target/linux/mediatek/patches-6.12/121-hack-spi-nand-1b-bbm.patch index df29ec91d1..cc2410e352 100644 --- a/target/linux/mediatek/patches-6.12/121-hack-spi-nand-1b-bbm.patch +++ b/target/linux/mediatek/patches-6.12/121-hack-spi-nand-1b-bbm.patch @@ -1,6 +1,6 @@ --- a/drivers/mtd/nand/spi/core.c +++ b/drivers/mtd/nand/spi/core.c -@@ -896,7 +896,7 @@ static int spinand_mtd_write(struct mtd_ +@@ -913,7 +913,7 @@ static int spinand_mtd_write(struct mtd_ static bool spinand_isbad(struct nand_device *nand, const struct nand_pos *pos) { struct spinand_device *spinand = nand_to_spinand(nand); @@ -9,7 +9,7 @@ struct nand_page_io_req req = { .pos = *pos, .ooblen = sizeof(marker), -@@ -907,7 +907,7 @@ static bool spinand_isbad(struct nand_de +@@ -924,7 +924,7 @@ static bool spinand_isbad(struct nand_de spinand_select_target(spinand, pos->target); spinand_read_page(spinand, &req); diff --git a/target/linux/mediatek/patches-6.12/330-snand-mtk-bmt-support.patch b/target/linux/mediatek/patches-6.12/330-snand-mtk-bmt-support.patch index f715652319..eb77fde066 100644 --- a/target/linux/mediatek/patches-6.12/330-snand-mtk-bmt-support.patch +++ b/target/linux/mediatek/patches-6.12/330-snand-mtk-bmt-support.patch @@ -8,7 +8,7 @@ static int spinand_read_reg_op(struct spinand_device *spinand, u8 reg, u8 *val) { -@@ -1530,6 +1531,7 @@ static int spinand_probe(struct spi_mem +@@ -1574,6 +1575,7 @@ static int spinand_probe(struct spi_mem if (ret) return ret; @@ -16,7 +16,7 @@ ret = mtd_device_register(mtd, NULL, 0); if (ret) goto err_spinand_cleanup; -@@ -1537,6 +1539,7 @@ static int spinand_probe(struct spi_mem +@@ -1581,6 +1583,7 @@ static int spinand_probe(struct spi_mem return 0; err_spinand_cleanup: @@ -24,7 +24,7 @@ spinand_cleanup(spinand); return ret; -@@ -1555,6 +1558,7 @@ static int spinand_remove(struct spi_mem +@@ -1599,6 +1602,7 @@ static int spinand_remove(struct spi_mem if (ret) return ret; diff --git a/target/linux/mediatek/patches-6.12/340-mtd-spinand-Add-support-for-the-Fidelix-FM35X1GA.patch b/target/linux/mediatek/patches-6.12/340-mtd-spinand-Add-support-for-the-Fidelix-FM35X1GA.patch index a7dc5105f5..7857f4c6aa 100644 --- a/target/linux/mediatek/patches-6.12/340-mtd-spinand-Add-support-for-the-Fidelix-FM35X1GA.patch +++ b/target/linux/mediatek/patches-6.12/340-mtd-spinand-Add-support-for-the-Fidelix-FM35X1GA.patch @@ -24,7 +24,7 @@ Signed-off-by: Davide Fioravanti obj-$(CONFIG_MTD_SPI_NAND) += spinand.o --- a/drivers/mtd/nand/spi/core.c +++ b/drivers/mtd/nand/spi/core.c -@@ -1118,6 +1118,7 @@ static const struct spinand_manufacturer +@@ -1162,6 +1162,7 @@ static const struct spinand_manufacturer &esmt_c8_spinand_manufacturer, &etron_spinand_manufacturer, &fmsh_spinand_manufacturer, diff --git a/target/linux/mediatek/patches-6.12/435-drivers-mtd-spinand-Add-calibration-support-for-spin.patch b/target/linux/mediatek/patches-6.12/435-drivers-mtd-spinand-Add-calibration-support-for-spin.patch index 676ddec61e..258b8e19a3 100644 --- a/target/linux/mediatek/patches-6.12/435-drivers-mtd-spinand-Add-calibration-support-for-spin.patch +++ b/target/linux/mediatek/patches-6.12/435-drivers-mtd-spinand-Add-calibration-support-for-spin.patch @@ -11,7 +11,7 @@ Signed-off-by: SkyLake.Huang --- a/drivers/mtd/nand/spi/core.c +++ b/drivers/mtd/nand/spi/core.c -@@ -1156,6 +1156,56 @@ static int spinand_manufacturer_match(st +@@ -1200,6 +1200,56 @@ static int spinand_manufacturer_match(st return -EOPNOTSUPP; } @@ -68,7 +68,7 @@ Signed-off-by: SkyLake.Huang static int spinand_id_detect(struct spinand_device *spinand) { u8 *id = spinand->id.data; -@@ -1407,6 +1457,10 @@ static int spinand_init(struct spinand_d +@@ -1451,6 +1501,10 @@ static int spinand_init(struct spinand_d if (!spinand->scratchbuf) return -ENOMEM; diff --git a/target/linux/mediatek/patches-6.12/436-drivers-mtd-spi-nor-Add-calibration-support-for-spi-.patch b/target/linux/mediatek/patches-6.12/436-drivers-mtd-spi-nor-Add-calibration-support-for-spi-.patch index 4626a86e99..b55f76eed7 100644 --- a/target/linux/mediatek/patches-6.12/436-drivers-mtd-spi-nor-Add-calibration-support-for-spi-.patch +++ b/target/linux/mediatek/patches-6.12/436-drivers-mtd-spi-nor-Add-calibration-support-for-spi-.patch @@ -12,7 +12,7 @@ Signed-off-by: SkyLake.Huang --- a/drivers/mtd/nand/spi/core.c +++ b/drivers/mtd/nand/spi/core.c -@@ -1197,7 +1197,10 @@ static int spinand_cal_read(void *priv, +@@ -1241,7 +1241,10 @@ static int spinand_cal_read(void *priv, if (ret) return ret; diff --git a/target/linux/mediatek/patches-6.12/960-asus-hack-u-boot-ignore-mtdparts.patch b/target/linux/mediatek/patches-6.12/960-asus-hack-u-boot-ignore-mtdparts.patch index 07d067125a..8d1680d5d4 100644 --- a/target/linux/mediatek/patches-6.12/960-asus-hack-u-boot-ignore-mtdparts.patch +++ b/target/linux/mediatek/patches-6.12/960-asus-hack-u-boot-ignore-mtdparts.patch @@ -29,7 +29,7 @@ Signed-off-by: Daniel Golle --- a/drivers/mtd/nand/spi/core.c +++ b/drivers/mtd/nand/spi/core.c -@@ -1624,6 +1624,7 @@ static int spinand_remove(struct spi_mem +@@ -1668,6 +1668,7 @@ static int spinand_remove(struct spi_mem static const struct spi_device_id spinand_ids[] = { { .name = "spi-nand" }, @@ -37,7 +37,7 @@ Signed-off-by: Daniel Golle { /* sentinel */ }, }; MODULE_DEVICE_TABLE(spi, spinand_ids); -@@ -1631,6 +1632,7 @@ MODULE_DEVICE_TABLE(spi, spinand_ids); +@@ -1675,6 +1676,7 @@ MODULE_DEVICE_TABLE(spi, spinand_ids); #ifdef CONFIG_OF static const struct of_device_id spinand_of_ids[] = { { .compatible = "spi-nand" },