mediatek: v5.15: backport spi-mem ecc support
authorChuanhong Guo <gch981213@gmail.com>
Thu, 7 Apr 2022 02:05:25 +0000 (10:05 +0800)
committerChuanhong Guo <gch981213@gmail.com>
Thu, 28 Apr 2022 10:06:00 +0000 (18:06 +0800)
Signed-off-by: Chuanhong Guo <gch981213@gmail.com>
target/linux/mediatek/patches-5.15/120-01-v5.18-mtd-nand-ecc-Add-infrastructure-to-support-hardware-.patch [new file with mode: 0644]
target/linux/mediatek/patches-5.15/120-02-v5.18-mtd-nand-Add-a-new-helper-to-retrieve-the-ECC-contex.patch [new file with mode: 0644]
target/linux/mediatek/patches-5.15/120-03-v5.18-mtd-nand-ecc-Provide-a-helper-to-retrieve-a-pileline.patch [new file with mode: 0644]
target/linux/mediatek/patches-5.15/120-04-v5.18-spi-spi-mem-Introduce-a-capability-structure.patch [new file with mode: 0644]
target/linux/mediatek/patches-5.15/120-05-v5.18-spi-spi-mem-Check-the-controller-extra-capabilities.patch [new file with mode: 0644]
target/linux/mediatek/patches-5.15/120-06-v5.18-spi-spi-mem-Kill-the-spi_mem_dtr_supports_op-helper.patch [new file with mode: 0644]
target/linux/mediatek/patches-5.15/120-07-v5.18-spi-spi-mem-Add-an-ecc-parameter-to-the-spi_mem_op-s.patch [new file with mode: 0644]
target/linux/mediatek/patches-5.15/120-08-v5.18-mtd-spinand-Delay-a-little-bit-the-dirmap-creation.patch [new file with mode: 0644]
target/linux/mediatek/patches-5.15/120-09-v5.18-mtd-spinand-Create-direct-mapping-descriptors-for-EC.patch [new file with mode: 0644]
target/linux/mediatek/patches-5.15/120-10-v5.18-mtd-nand-fix-ecc-parameters-for-mt7622.patch [new file with mode: 0644]

diff --git a/target/linux/mediatek/patches-5.15/120-01-v5.18-mtd-nand-ecc-Add-infrastructure-to-support-hardware-.patch b/target/linux/mediatek/patches-5.15/120-01-v5.18-mtd-nand-ecc-Add-infrastructure-to-support-hardware-.patch
new file mode 100644 (file)
index 0000000..b6b069d
--- /dev/null
@@ -0,0 +1,224 @@
+From ad4944aa0b02cb043afe20bc2a018c161e65c992 Mon Sep 17 00:00:00 2001
+From: Miquel Raynal <miquel.raynal@bootlin.com>
+Date: Thu, 16 Dec 2021 12:16:38 +0100
+Subject: [PATCH 01/15] mtd: nand: ecc: Add infrastructure to support hardware
+ engines
+
+Add the necessary helpers to register/unregister hardware ECC engines
+that will be called from ECC engine drivers.
+
+Also add helpers to get the right engine from the user
+perspective. Keep a reference of the in use ECC engine in order to
+prevent modules to be unloaded. Put the reference when the engine gets
+retired.
+
+A static list of hardware (only) ECC engines is setup to keep track of
+the registered engines.
+
+Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
+Link: https://lore.kernel.org/linux-mtd/20211216111654.238086-13-miquel.raynal@bootlin.com
+(cherry picked from commit 96489c1c0b53131b0e1ec33e2060538379ad6152)
+---
+ drivers/mtd/nand/core.c  | 10 +++--
+ drivers/mtd/nand/ecc.c   | 88 ++++++++++++++++++++++++++++++++++++++++
+ include/linux/mtd/nand.h | 28 +++++++++++++
+ 3 files changed, 123 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/mtd/nand/core.c b/drivers/mtd/nand/core.c
+index 5e13a03d2b32..b228b4d13b7a 100644
+--- a/drivers/mtd/nand/core.c
++++ b/drivers/mtd/nand/core.c
+@@ -232,7 +232,9 @@ static int nanddev_get_ecc_engine(struct nand_device *nand)
+               nand->ecc.engine = nand_ecc_get_on_die_hw_engine(nand);
+               break;
+       case NAND_ECC_ENGINE_TYPE_ON_HOST:
+-              pr_err("On-host hardware ECC engines not supported yet\n");
++              nand->ecc.engine = nand_ecc_get_on_host_hw_engine(nand);
++              if (PTR_ERR(nand->ecc.engine) == -EPROBE_DEFER)
++                      return -EPROBE_DEFER;
+               break;
+       default:
+               pr_err("Missing ECC engine type\n");
+@@ -252,7 +254,7 @@ static int nanddev_put_ecc_engine(struct nand_device *nand)
+ {
+       switch (nand->ecc.ctx.conf.engine_type) {
+       case NAND_ECC_ENGINE_TYPE_ON_HOST:
+-              pr_err("On-host hardware ECC engines not supported yet\n");
++              nand_ecc_put_on_host_hw_engine(nand);
+               break;
+       case NAND_ECC_ENGINE_TYPE_NONE:
+       case NAND_ECC_ENGINE_TYPE_SOFT:
+@@ -297,7 +299,9 @@ int nanddev_ecc_engine_init(struct nand_device *nand)
+       /* Look for the ECC engine to use */
+       ret = nanddev_get_ecc_engine(nand);
+       if (ret) {
+-              pr_err("No ECC engine found\n");
++              if (ret != -EPROBE_DEFER)
++                      pr_err("No ECC engine found\n");
++
+               return ret;
+       }
+diff --git a/drivers/mtd/nand/ecc.c b/drivers/mtd/nand/ecc.c
+index 6c43dfda01d4..078f5ec38de3 100644
+--- a/drivers/mtd/nand/ecc.c
++++ b/drivers/mtd/nand/ecc.c
+@@ -96,6 +96,12 @@
+ #include <linux/module.h>
+ #include <linux/mtd/nand.h>
+ #include <linux/slab.h>
++#include <linux/of.h>
++#include <linux/of_device.h>
++#include <linux/of_platform.h>
++
++static LIST_HEAD(on_host_hw_engines);
++static DEFINE_MUTEX(on_host_hw_engines_mutex);
+ /**
+  * nand_ecc_init_ctx - Init the ECC engine context
+@@ -611,6 +617,88 @@ struct nand_ecc_engine *nand_ecc_get_on_die_hw_engine(struct nand_device *nand)
+ }
+ EXPORT_SYMBOL(nand_ecc_get_on_die_hw_engine);
++int nand_ecc_register_on_host_hw_engine(struct nand_ecc_engine *engine)
++{
++      struct nand_ecc_engine *item;
++
++      if (!engine)
++              return -EINVAL;
++
++      /* Prevent multiple registrations of one engine */
++      list_for_each_entry(item, &on_host_hw_engines, node)
++              if (item == engine)
++                      return 0;
++
++      mutex_lock(&on_host_hw_engines_mutex);
++      list_add_tail(&engine->node, &on_host_hw_engines);
++      mutex_unlock(&on_host_hw_engines_mutex);
++
++      return 0;
++}
++EXPORT_SYMBOL(nand_ecc_register_on_host_hw_engine);
++
++int nand_ecc_unregister_on_host_hw_engine(struct nand_ecc_engine *engine)
++{
++      if (!engine)
++              return -EINVAL;
++
++      mutex_lock(&on_host_hw_engines_mutex);
++      list_del(&engine->node);
++      mutex_unlock(&on_host_hw_engines_mutex);
++
++      return 0;
++}
++EXPORT_SYMBOL(nand_ecc_unregister_on_host_hw_engine);
++
++static struct nand_ecc_engine *nand_ecc_match_on_host_hw_engine(struct device *dev)
++{
++      struct nand_ecc_engine *item;
++
++      list_for_each_entry(item, &on_host_hw_engines, node)
++              if (item->dev == dev)
++                      return item;
++
++      return NULL;
++}
++
++struct nand_ecc_engine *nand_ecc_get_on_host_hw_engine(struct nand_device *nand)
++{
++      struct nand_ecc_engine *engine = NULL;
++      struct device *dev = &nand->mtd.dev;
++      struct platform_device *pdev;
++      struct device_node *np;
++
++      if (list_empty(&on_host_hw_engines))
++              return NULL;
++
++      /* Check for an explicit nand-ecc-engine property */
++      np = of_parse_phandle(dev->of_node, "nand-ecc-engine", 0);
++      if (np) {
++              pdev = of_find_device_by_node(np);
++              if (!pdev)
++                      return ERR_PTR(-EPROBE_DEFER);
++
++              engine = nand_ecc_match_on_host_hw_engine(&pdev->dev);
++              platform_device_put(pdev);
++              of_node_put(np);
++
++              if (!engine)
++                      return ERR_PTR(-EPROBE_DEFER);
++      }
++
++      if (engine)
++              get_device(engine->dev);
++
++      return engine;
++}
++EXPORT_SYMBOL(nand_ecc_get_on_host_hw_engine);
++
++void nand_ecc_put_on_host_hw_engine(struct nand_device *nand)
++{
++      put_device(nand->ecc.engine->dev);
++}
++EXPORT_SYMBOL(nand_ecc_put_on_host_hw_engine);
++
+ MODULE_LICENSE("GPL");
+ MODULE_AUTHOR("Miquel Raynal <miquel.raynal@bootlin.com>");
+ MODULE_DESCRIPTION("Generic ECC engine");
+diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
+index 32fc7edf65b3..4ddd20fe9c9e 100644
+--- a/include/linux/mtd/nand.h
++++ b/include/linux/mtd/nand.h
+@@ -263,12 +263,36 @@ struct nand_ecc_engine_ops {
+                            struct nand_page_io_req *req);
+ };
++/**
++ * enum nand_ecc_engine_integration - How the NAND ECC engine is integrated
++ * @NAND_ECC_ENGINE_INTEGRATION_INVALID: Invalid value
++ * @NAND_ECC_ENGINE_INTEGRATION_PIPELINED: Pipelined engine, performs on-the-fly
++ *                                         correction, does not need to copy
++ *                                         data around
++ * @NAND_ECC_ENGINE_INTEGRATION_EXTERNAL: External engine, needs to bring the
++ *                                        data into its own area before use
++ */
++enum nand_ecc_engine_integration {
++      NAND_ECC_ENGINE_INTEGRATION_INVALID,
++      NAND_ECC_ENGINE_INTEGRATION_PIPELINED,
++      NAND_ECC_ENGINE_INTEGRATION_EXTERNAL,
++};
++
+ /**
+  * struct nand_ecc_engine - ECC engine abstraction for NAND devices
++ * @dev: Host device
++ * @node: Private field for registration time
+  * @ops: ECC engine operations
++ * @integration: How the engine is integrated with the host
++ *               (only relevant on %NAND_ECC_ENGINE_TYPE_ON_HOST engines)
++ * @priv: Private data
+  */
+ struct nand_ecc_engine {
++      struct device *dev;
++      struct list_head node;
+       struct nand_ecc_engine_ops *ops;
++      enum nand_ecc_engine_integration integration;
++      void *priv;
+ };
+ void of_get_nand_ecc_user_config(struct nand_device *nand);
+@@ -279,8 +303,12 @@ int nand_ecc_prepare_io_req(struct nand_device *nand,
+ int nand_ecc_finish_io_req(struct nand_device *nand,
+                          struct nand_page_io_req *req);
+ bool nand_ecc_is_strong_enough(struct nand_device *nand);
++int nand_ecc_register_on_host_hw_engine(struct nand_ecc_engine *engine);
++int nand_ecc_unregister_on_host_hw_engine(struct nand_ecc_engine *engine);
+ struct nand_ecc_engine *nand_ecc_get_sw_engine(struct nand_device *nand);
+ struct nand_ecc_engine *nand_ecc_get_on_die_hw_engine(struct nand_device *nand);
++struct nand_ecc_engine *nand_ecc_get_on_host_hw_engine(struct nand_device *nand);
++void nand_ecc_put_on_host_hw_engine(struct nand_device *nand);
+ #if IS_ENABLED(CONFIG_MTD_NAND_ECC_SW_HAMMING)
+ struct nand_ecc_engine *nand_ecc_sw_hamming_get_engine(void);
+-- 
+2.35.1
+
diff --git a/target/linux/mediatek/patches-5.15/120-02-v5.18-mtd-nand-Add-a-new-helper-to-retrieve-the-ECC-contex.patch b/target/linux/mediatek/patches-5.15/120-02-v5.18-mtd-nand-Add-a-new-helper-to-retrieve-the-ECC-contex.patch
new file mode 100644 (file)
index 0000000..6522507
--- /dev/null
@@ -0,0 +1,36 @@
+From 840b2f8dd2d0579e517140e1f9bbc482eaf4ed07 Mon Sep 17 00:00:00 2001
+From: Miquel Raynal <miquel.raynal@bootlin.com>
+Date: Thu, 16 Dec 2021 12:16:39 +0100
+Subject: [PATCH 02/15] mtd: nand: Add a new helper to retrieve the ECC context
+
+Introduce nand_to_ecc_ctx() which will allow to easily jump to the
+private pointer of an ECC context given a NAND device. This is very
+handy, from the prepare or finish ECC hook, to get the internal context
+out of the NAND device object.
+
+Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
+Link: https://lore.kernel.org/linux-mtd/20211216111654.238086-14-miquel.raynal@bootlin.com
+(cherry picked from commit cda32a618debd3fad8e42757b198719ae180f8f4)
+---
+ include/linux/mtd/nand.h | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
+index 4ddd20fe9c9e..b617efa0a881 100644
+--- a/include/linux/mtd/nand.h
++++ b/include/linux/mtd/nand.h
+@@ -990,6 +990,11 @@ int nanddev_markbad(struct nand_device *nand, const struct nand_pos *pos);
+ int nanddev_ecc_engine_init(struct nand_device *nand);
+ void nanddev_ecc_engine_cleanup(struct nand_device *nand);
++static inline void *nand_to_ecc_ctx(struct nand_device *nand)
++{
++      return nand->ecc.ctx.priv;
++}
++
+ /* BBT related functions */
+ enum nand_bbt_block_status {
+       NAND_BBT_BLOCK_STATUS_UNKNOWN,
+-- 
+2.35.1
+
diff --git a/target/linux/mediatek/patches-5.15/120-03-v5.18-mtd-nand-ecc-Provide-a-helper-to-retrieve-a-pileline.patch b/target/linux/mediatek/patches-5.15/120-03-v5.18-mtd-nand-ecc-Provide-a-helper-to-retrieve-a-pileline.patch
new file mode 100644 (file)
index 0000000..ce353a9
--- /dev/null
@@ -0,0 +1,80 @@
+From 784866bc4f9f25e0494b77750f95af2a2619e498 Mon Sep 17 00:00:00 2001
+From: Miquel Raynal <miquel.raynal@bootlin.com>
+Date: Thu, 16 Dec 2021 12:16:41 +0100
+Subject: [PATCH 03/15] mtd: nand: ecc: Provide a helper to retrieve a
+ pilelined engine device
+
+In a pipelined engine situation, we might either have the host which
+internally has support for error correction, or have it using an
+external hardware block for this purpose. In the former case, the host
+is also the ECC engine. In the latter case, it is not. In order to get
+the right pointers on the right devices (for example: in order to devm_*
+allocate variables), let's introduce this helper which can safely be
+called by pipelined ECC engines in order to retrieve the right device
+structure.
+
+Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
+Link: https://lore.kernel.org/linux-mtd/20211216111654.238086-16-miquel.raynal@bootlin.com
+(cherry picked from commit 5145abeb0649acf810a32e63bd762e617a9b3309)
+---
+ drivers/mtd/nand/ecc.c   | 31 +++++++++++++++++++++++++++++++
+ include/linux/mtd/nand.h |  1 +
+ 2 files changed, 32 insertions(+)
+
+diff --git a/drivers/mtd/nand/ecc.c b/drivers/mtd/nand/ecc.c
+index 078f5ec38de3..5250764cedee 100644
+--- a/drivers/mtd/nand/ecc.c
++++ b/drivers/mtd/nand/ecc.c
+@@ -699,6 +699,37 @@ void nand_ecc_put_on_host_hw_engine(struct nand_device *nand)
+ }
+ EXPORT_SYMBOL(nand_ecc_put_on_host_hw_engine);
++/*
++ * In the case of a pipelined engine, the device registering the ECC
++ * engine is not necessarily the ECC engine itself but may be a host controller.
++ * It is then useful to provide a helper to retrieve the right device object
++ * which actually represents the ECC engine.
++ */
++struct device *nand_ecc_get_engine_dev(struct device *host)
++{
++      struct platform_device *ecc_pdev;
++      struct device_node *np;
++
++      /*
++       * If the device node contains this property, it means we need to follow
++       * it in order to get the right ECC engine device we are looking for.
++       */
++      np = of_parse_phandle(host->of_node, "nand-ecc-engine", 0);
++      if (!np)
++              return host;
++
++      ecc_pdev = of_find_device_by_node(np);
++      if (!ecc_pdev) {
++              of_node_put(np);
++              return NULL;
++      }
++
++      platform_device_put(ecc_pdev);
++      of_node_put(np);
++
++      return &ecc_pdev->dev;
++}
++
+ MODULE_LICENSE("GPL");
+ MODULE_AUTHOR("Miquel Raynal <miquel.raynal@bootlin.com>");
+ MODULE_DESCRIPTION("Generic ECC engine");
+diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
+index b617efa0a881..615b3e3a3920 100644
+--- a/include/linux/mtd/nand.h
++++ b/include/linux/mtd/nand.h
+@@ -309,6 +309,7 @@ struct nand_ecc_engine *nand_ecc_get_sw_engine(struct nand_device *nand);
+ struct nand_ecc_engine *nand_ecc_get_on_die_hw_engine(struct nand_device *nand);
+ struct nand_ecc_engine *nand_ecc_get_on_host_hw_engine(struct nand_device *nand);
+ void nand_ecc_put_on_host_hw_engine(struct nand_device *nand);
++struct device *nand_ecc_get_engine_dev(struct device *host);
+ #if IS_ENABLED(CONFIG_MTD_NAND_ECC_SW_HAMMING)
+ struct nand_ecc_engine *nand_ecc_sw_hamming_get_engine(void);
+-- 
+2.35.1
+
diff --git a/target/linux/mediatek/patches-5.15/120-04-v5.18-spi-spi-mem-Introduce-a-capability-structure.patch b/target/linux/mediatek/patches-5.15/120-04-v5.18-spi-spi-mem-Introduce-a-capability-structure.patch
new file mode 100644 (file)
index 0000000..bcd2ee8
--- /dev/null
@@ -0,0 +1,78 @@
+From 3e45577e70cbf8fdc5c13033114989794a3797d5 Mon Sep 17 00:00:00 2001
+From: Miquel Raynal <miquel.raynal@bootlin.com>
+Date: Thu, 27 Jan 2022 10:17:56 +0100
+Subject: [PATCH 04/15] spi: spi-mem: Introduce a capability structure
+
+Create a spi_controller_mem_caps structure and put it within the
+spi_controller structure close to the spi_controller_mem_ops
+strucure. So far the only field in this structure is the support for dtr
+operations, but soon we will add another parameter.
+
+Also create a helper to parse the capabilities and check if the
+requested capability has been set or not.
+
+Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
+Reviewed-by: Pratyush Yadav <p.yadav@ti.com>
+Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com>
+Reviewed-by: Tudor Ambarus <tudor.ambarus@microchip.com>
+Reviewed-by: Mark Brown <broonie@kernel.org>
+Link: https://lore.kernel.org/linux-mtd/20220127091808.1043392-2-miquel.raynal@bootlin.com
+(cherry picked from commit 4a3cc7fb6e63bcfdedec25364738f1493345bd20)
+---
+ include/linux/spi/spi-mem.h | 11 +++++++++++
+ include/linux/spi/spi.h     |  3 +++
+ 2 files changed, 14 insertions(+)
+
+diff --git a/include/linux/spi/spi-mem.h b/include/linux/spi/spi-mem.h
+index 85e2ff7b840d..38e5d45c9842 100644
+--- a/include/linux/spi/spi-mem.h
++++ b/include/linux/spi/spi-mem.h
+@@ -285,6 +285,17 @@ struct spi_controller_mem_ops {
+                          unsigned long timeout_ms);
+ };
++/**
++ * struct spi_controller_mem_caps - SPI memory controller capabilities
++ * @dtr: Supports DTR operations
++ */
++struct spi_controller_mem_caps {
++      bool dtr;
++};
++
++#define spi_mem_controller_is_capable(ctlr, cap)      \
++      ((ctlr)->mem_caps && (ctlr)->mem_caps->cap)
++
+ /**
+  * struct spi_mem_driver - SPI memory driver
+  * @spidrv: inherit from a SPI driver
+diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h
+index 6b0b686f6f90..8ac58b1a2a9f 100644
+--- a/include/linux/spi/spi.h
++++ b/include/linux/spi/spi.h
+@@ -23,6 +23,7 @@ struct software_node;
+ struct spi_controller;
+ struct spi_transfer;
+ struct spi_controller_mem_ops;
++struct spi_controller_mem_caps;
+ /*
+  * INTERFACES between SPI master-side drivers and SPI slave protocol handlers,
+@@ -419,6 +420,7 @@ extern struct spi_device *spi_new_ancillary_device(struct spi_device *spi, u8 ch
+  * @mem_ops: optimized/dedicated operations for interactions with SPI memory.
+  *         This field is optional and should only be implemented if the
+  *         controller has native support for memory like operations.
++ * @mem_caps: controller capabilities for the handling of memory operations.
+  * @unprepare_message: undo any work done by prepare_message().
+  * @slave_abort: abort the ongoing transfer request on an SPI slave controller
+  * @cs_gpios: LEGACY: array of GPIO descs to use as chip select lines; one per
+@@ -643,6 +645,7 @@ struct spi_controller {
+       /* Optimized handlers for SPI memory-like operations. */
+       const struct spi_controller_mem_ops *mem_ops;
++      const struct spi_controller_mem_caps *mem_caps;
+       /* gpio chip select */
+       int                     *cs_gpios;
+-- 
+2.35.1
+
diff --git a/target/linux/mediatek/patches-5.15/120-05-v5.18-spi-spi-mem-Check-the-controller-extra-capabilities.patch b/target/linux/mediatek/patches-5.15/120-05-v5.18-spi-spi-mem-Check-the-controller-extra-capabilities.patch
new file mode 100644 (file)
index 0000000..20e7bac
--- /dev/null
@@ -0,0 +1,56 @@
+From c9cae7e1e5c87d0aa76b7bededa5191a0c8cf25a Mon Sep 17 00:00:00 2001
+From: Miquel Raynal <miquel.raynal@bootlin.com>
+Date: Thu, 27 Jan 2022 10:17:57 +0100
+Subject: [PATCH 05/15] spi: spi-mem: Check the controller extra capabilities
+
+Controllers can now provide a spi-mem capabilities structure. Let's make
+use of it in spi_mem_controller_default_supports_op(). As we want to
+check for DTR operations as well as normal operations in a single
+helper, let's pull the necessary checks from spi_mem_dtr_supports_op()
+for now.
+
+However, because no controller provide these extra capabilities, this
+change has no effect so far.
+
+Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
+Reviewed-by: Pratyush Yadav <p.yadav@ti.com>
+Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com>
+Reviewed-by: Tudor Ambarus <tudor.ambarus@microchip.com>
+Link: https://lore.kernel.org/linux-mtd/20220127091808.1043392-3-miquel.raynal@bootlin.com
+(cherry picked from commit cb7e96ee81edaa48c67d84c14df2cbe464391c37)
+---
+ drivers/spi/spi-mem.c | 17 +++++++++++++----
+ 1 file changed, 13 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c
+index 37f4443ce9a0..86e6597bc3dc 100644
+--- a/drivers/spi/spi-mem.c
++++ b/drivers/spi/spi-mem.c
+@@ -173,11 +173,20 @@ EXPORT_SYMBOL_GPL(spi_mem_dtr_supports_op);
+ bool spi_mem_default_supports_op(struct spi_mem *mem,
+                                const struct spi_mem_op *op)
+ {
+-      if (op->cmd.dtr || op->addr.dtr || op->dummy.dtr || op->data.dtr)
+-              return false;
++      struct spi_controller *ctlr = mem->spi->controller;
++      bool op_is_dtr =
++              op->cmd.dtr || op->addr.dtr || op->dummy.dtr || op->data.dtr;
+-      if (op->cmd.nbytes != 1)
+-              return false;
++      if (op_is_dtr) {
++              if (!spi_mem_controller_is_capable(ctlr, dtr))
++                      return false;
++
++              if (op->cmd.nbytes != 2)
++                      return false;
++      } else {
++              if (op->cmd.nbytes != 1)
++                      return false;
++      }
+       return spi_mem_check_buswidth(mem, op);
+ }
+-- 
+2.35.1
+
diff --git a/target/linux/mediatek/patches-5.15/120-06-v5.18-spi-spi-mem-Kill-the-spi_mem_dtr_supports_op-helper.patch b/target/linux/mediatek/patches-5.15/120-06-v5.18-spi-spi-mem-Kill-the-spi_mem_dtr_supports_op-helper.patch
new file mode 100644 (file)
index 0000000..efc0ed5
--- /dev/null
@@ -0,0 +1,122 @@
+From 2e5fba82e4aeb72d71230eef2541881615aaf7cf Mon Sep 17 00:00:00 2001
+From: Miquel Raynal <miquel.raynal@bootlin.com>
+Date: Thu, 27 Jan 2022 10:18:00 +0100
+Subject: [PATCH 06/15] spi: spi-mem: Kill the spi_mem_dtr_supports_op() helper
+
+Now that spi_mem_default_supports_op() has access to the static
+controller capabilities (relating to memory operations), and now that
+these capabilities have been filled by the relevant controllers, there
+is no need for a specific helper checking only DTR operations, so let's
+just kill spi_mem_dtr_supports_op() and simply use
+spi_mem_default_supports_op() instead.
+
+Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
+Reviewed-by: Pratyush Yadav <p.yadav@ti.com>
+Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com>
+Reviewed-by: Tudor Ambarus <tudor.ambarus@microchip.com>
+Link: https://lore.kernel.org/linux-mtd/20220127091808.1043392-6-miquel.raynal@bootlin.com
+(cherry picked from commit 9a15efc5d5e6b5beaed0883e5bdcd0b1384c1b20)
+---
+ drivers/spi/spi-cadence-quadspi.c |  5 +----
+ drivers/spi/spi-mem.c             | 10 ----------
+ drivers/spi/spi-mxic.c            | 10 +---------
+ include/linux/spi/spi-mem.h       | 11 -----------
+ 4 files changed, 2 insertions(+), 34 deletions(-)
+
+diff --git a/drivers/spi/spi-cadence-quadspi.c b/drivers/spi/spi-cadence-quadspi.c
+index 101cc71bffa7..2c98d6a9a2aa 100644
+--- a/drivers/spi/spi-cadence-quadspi.c
++++ b/drivers/spi/spi-cadence-quadspi.c
+@@ -1252,10 +1252,7 @@ static bool cqspi_supports_mem_op(struct spi_mem *mem,
+       if (!(all_true || all_false))
+               return false;
+-      if (all_true)
+-              return spi_mem_dtr_supports_op(mem, op);
+-      else
+-              return spi_mem_default_supports_op(mem, op);
++      return spi_mem_default_supports_op(mem, op);
+ }
+ static int cqspi_of_get_flash_pdata(struct platform_device *pdev,
+diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c
+index 86e6597bc3dc..ed966d8129eb 100644
+--- a/drivers/spi/spi-mem.c
++++ b/drivers/spi/spi-mem.c
+@@ -160,16 +160,6 @@ static bool spi_mem_check_buswidth(struct spi_mem *mem,
+       return true;
+ }
+-bool spi_mem_dtr_supports_op(struct spi_mem *mem,
+-                           const struct spi_mem_op *op)
+-{
+-      if (op->cmd.nbytes != 2)
+-              return false;
+-
+-      return spi_mem_check_buswidth(mem, op);
+-}
+-EXPORT_SYMBOL_GPL(spi_mem_dtr_supports_op);
+-
+ bool spi_mem_default_supports_op(struct spi_mem *mem,
+                                const struct spi_mem_op *op)
+ {
+diff --git a/drivers/spi/spi-mxic.c b/drivers/spi/spi-mxic.c
+index 45889947afed..e895df09896a 100644
+--- a/drivers/spi/spi-mxic.c
++++ b/drivers/spi/spi-mxic.c
+@@ -335,8 +335,6 @@ static int mxic_spi_data_xfer(struct mxic_spi *mxic, const void *txbuf,
+ static bool mxic_spi_mem_supports_op(struct spi_mem *mem,
+                                    const struct spi_mem_op *op)
+ {
+-      bool all_false;
+-
+       if (op->data.buswidth > 8 || op->addr.buswidth > 8 ||
+           op->dummy.buswidth > 8 || op->cmd.buswidth > 8)
+               return false;
+@@ -348,13 +346,7 @@ static bool mxic_spi_mem_supports_op(struct spi_mem *mem,
+       if (op->addr.nbytes > 7)
+               return false;
+-      all_false = !op->cmd.dtr && !op->addr.dtr && !op->dummy.dtr &&
+-                  !op->data.dtr;
+-
+-      if (all_false)
+-              return spi_mem_default_supports_op(mem, op);
+-      else
+-              return spi_mem_dtr_supports_op(mem, op);
++      return spi_mem_default_supports_op(mem, op);
+ }
+ static int mxic_spi_mem_exec_op(struct spi_mem *mem,
+diff --git a/include/linux/spi/spi-mem.h b/include/linux/spi/spi-mem.h
+index 38e5d45c9842..4a1bfe689872 100644
+--- a/include/linux/spi/spi-mem.h
++++ b/include/linux/spi/spi-mem.h
+@@ -330,10 +330,6 @@ void spi_controller_dma_unmap_mem_op_data(struct spi_controller *ctlr,
+ bool spi_mem_default_supports_op(struct spi_mem *mem,
+                                const struct spi_mem_op *op);
+-
+-bool spi_mem_dtr_supports_op(struct spi_mem *mem,
+-                           const struct spi_mem_op *op);
+-
+ #else
+ static inline int
+ spi_controller_dma_map_mem_op_data(struct spi_controller *ctlr,
+@@ -356,13 +352,6 @@ bool spi_mem_default_supports_op(struct spi_mem *mem,
+ {
+       return false;
+ }
+-
+-static inline
+-bool spi_mem_dtr_supports_op(struct spi_mem *mem,
+-                           const struct spi_mem_op *op)
+-{
+-      return false;
+-}
+ #endif /* CONFIG_SPI_MEM */
+ int spi_mem_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op);
+-- 
+2.35.1
+
diff --git a/target/linux/mediatek/patches-5.15/120-07-v5.18-spi-spi-mem-Add-an-ecc-parameter-to-the-spi_mem_op-s.patch b/target/linux/mediatek/patches-5.15/120-07-v5.18-spi-spi-mem-Add-an-ecc-parameter-to-the-spi_mem_op-s.patch
new file mode 100644 (file)
index 0000000..fd9e9e2
--- /dev/null
@@ -0,0 +1,79 @@
+From 9e7eb0ea442ecb1c3fe443289e288694f10c5148 Mon Sep 17 00:00:00 2001
+From: Miquel Raynal <miquel.raynal@bootlin.com>
+Date: Thu, 27 Jan 2022 10:18:01 +0100
+Subject: [PATCH 07/15] spi: spi-mem: Add an ecc parameter to the spi_mem_op
+ structure
+
+Soon the SPI-NAND core will need a way to request a SPI controller to
+enable ECC support for a given operation. This is because of the
+pipelined integration of certain ECC engines, which are directly managed
+by the SPI controller itself.
+
+Introduce a spi_mem_op additional field for this purpose: ecc.
+
+So far this field is left unset and checked to be false by all
+the SPI controller drivers in their ->supports_op() hook, as they all
+call spi_mem_default_supports_op().
+
+Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
+Acked-by: Pratyush Yadav <p.yadav@ti.com>
+Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com>
+Reviewed-by: Tudor Ambarus <tudor.ambarus@microchip.com>
+Link: https://lore.kernel.org/linux-mtd/20220127091808.1043392-7-miquel.raynal@bootlin.com
+(cherry picked from commit a433c2cbd75ab76f277364f44e76f32c7df306e7)
+---
+ drivers/spi/spi-mem.c       | 5 +++++
+ include/linux/spi/spi-mem.h | 4 ++++
+ 2 files changed, 9 insertions(+)
+
+diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c
+index ed966d8129eb..f38ac31961c9 100644
+--- a/drivers/spi/spi-mem.c
++++ b/drivers/spi/spi-mem.c
+@@ -178,6 +178,11 @@ bool spi_mem_default_supports_op(struct spi_mem *mem,
+                       return false;
+       }
++      if (op->data.ecc) {
++              if (!spi_mem_controller_is_capable(ctlr, ecc))
++                      return false;
++      }
++
+       return spi_mem_check_buswidth(mem, op);
+ }
+ EXPORT_SYMBOL_GPL(spi_mem_default_supports_op);
+diff --git a/include/linux/spi/spi-mem.h b/include/linux/spi/spi-mem.h
+index 4a1bfe689872..2ba044d0d5e5 100644
+--- a/include/linux/spi/spi-mem.h
++++ b/include/linux/spi/spi-mem.h
+@@ -89,6 +89,7 @@ enum spi_mem_data_dir {
+  * @dummy.dtr: whether the dummy bytes should be sent in DTR mode or not
+  * @data.buswidth: number of IO lanes used to send/receive the data
+  * @data.dtr: whether the data should be sent in DTR mode or not
++ * @data.ecc: whether error correction is required or not
+  * @data.dir: direction of the transfer
+  * @data.nbytes: number of data bytes to send/receive. Can be zero if the
+  *             operation does not involve transferring data
+@@ -119,6 +120,7 @@ struct spi_mem_op {
+       struct {
+               u8 buswidth;
+               u8 dtr : 1;
++              u8 ecc : 1;
+               enum spi_mem_data_dir dir;
+               unsigned int nbytes;
+               union {
+@@ -288,9 +290,11 @@ struct spi_controller_mem_ops {
+ /**
+  * struct spi_controller_mem_caps - SPI memory controller capabilities
+  * @dtr: Supports DTR operations
++ * @ecc: Supports operations with error correction
+  */
+ struct spi_controller_mem_caps {
+       bool dtr;
++      bool ecc;
+ };
+ #define spi_mem_controller_is_capable(ctlr, cap)      \
+-- 
+2.35.1
+
diff --git a/target/linux/mediatek/patches-5.15/120-08-v5.18-mtd-spinand-Delay-a-little-bit-the-dirmap-creation.patch b/target/linux/mediatek/patches-5.15/120-08-v5.18-mtd-spinand-Delay-a-little-bit-the-dirmap-creation.patch
new file mode 100644 (file)
index 0000000..d8c0e1b
--- /dev/null
@@ -0,0 +1,55 @@
+From 94ef3c35b935a63f6c156957c92f6cf33c9a8dae Mon Sep 17 00:00:00 2001
+From: Miquel Raynal <miquel.raynal@bootlin.com>
+Date: Thu, 27 Jan 2022 10:18:02 +0100
+Subject: [PATCH 08/15] mtd: spinand: Delay a little bit the dirmap creation
+
+As we will soon tweak the dirmap creation to act a little bit
+differently depending on the picked ECC engine, we need to initialize
+dirmaps after ECC engines. This should not have any effect as dirmaps
+are not yet used at this point.
+
+Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
+Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com>
+Link: https://lore.kernel.org/linux-mtd/20220127091808.1043392-8-miquel.raynal@bootlin.com
+(cherry picked from commit dc4c2cbf0be2d4a8e2a65013ea2815bb2c8ba949)
+---
+ drivers/mtd/nand/spi/core.c | 16 ++++++++--------
+ 1 file changed, 8 insertions(+), 8 deletions(-)
+
+diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
+index 2c8685f1f2fa..bb6b026b558b 100644
+--- a/drivers/mtd/nand/spi/core.c
++++ b/drivers/mtd/nand/spi/core.c
+@@ -1208,14 +1208,6 @@ static int spinand_init(struct spinand_device *spinand)
+       if (ret)
+               goto err_free_bufs;
+-      ret = spinand_create_dirmaps(spinand);
+-      if (ret) {
+-              dev_err(dev,
+-                      "Failed to create direct mappings for read/write operations (err = %d)\n",
+-                      ret);
+-              goto err_manuf_cleanup;
+-      }
+-
+       ret = nanddev_init(nand, &spinand_ops, THIS_MODULE);
+       if (ret)
+               goto err_manuf_cleanup;
+@@ -1250,6 +1242,14 @@ static int spinand_init(struct spinand_device *spinand)
+       mtd->ecc_strength = nanddev_get_ecc_conf(nand)->strength;
+       mtd->ecc_step_size = nanddev_get_ecc_conf(nand)->step_size;
++      ret = spinand_create_dirmaps(spinand);
++      if (ret) {
++              dev_err(dev,
++                      "Failed to create direct mappings for read/write operations (err = %d)\n",
++                      ret);
++              goto err_cleanup_ecc_engine;
++      }
++
+       return 0;
+ err_cleanup_ecc_engine:
+-- 
+2.35.1
+
diff --git a/target/linux/mediatek/patches-5.15/120-09-v5.18-mtd-spinand-Create-direct-mapping-descriptors-for-EC.patch b/target/linux/mediatek/patches-5.15/120-09-v5.18-mtd-spinand-Create-direct-mapping-descriptors-for-EC.patch
new file mode 100644 (file)
index 0000000..ee3a6d3
--- /dev/null
@@ -0,0 +1,105 @@
+From eb4a2d282c3c5752211d69be6dff2674119e5583 Mon Sep 17 00:00:00 2001
+From: Miquel Raynal <miquel.raynal@bootlin.com>
+Date: Thu, 27 Jan 2022 10:18:03 +0100
+Subject: [PATCH 09/15] mtd: spinand: Create direct mapping descriptors for ECC
+ operations
+
+In order for pipelined ECC engines to be able to enable/disable the ECC
+engine only when needed and avoid races when future parallel-operations
+will be supported, we need to provide the information about the use of
+the ECC engine in the direct mapping hooks. As direct mapping
+configurations are meant to be static, it is best to create two new
+mappings: one for regular 'raw' accesses and one for accesses involving
+correction. It is up to the driver to use or not the new ECC enable
+boolean contained in the spi-mem operation.
+
+As dirmaps are not free (they consume a few pages of MMIO address space)
+and because these extra entries are only meant to be used by pipelined
+engines, let's limit their use to this specific type of engine and save
+a bit of memory with all the other setups.
+
+Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
+Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com>
+Link: https://lore.kernel.org/linux-mtd/20220127091808.1043392-9-miquel.raynal@bootlin.com
+(cherry picked from commit f9d7c7265bcff7d9a17425a8cddf702e8fe159c2)
+---
+ drivers/mtd/nand/spi/core.c | 35 +++++++++++++++++++++++++++++++++--
+ include/linux/mtd/spinand.h |  2 ++
+ 2 files changed, 35 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
+index bb6b026b558b..ff8336870bc0 100644
+--- a/drivers/mtd/nand/spi/core.c
++++ b/drivers/mtd/nand/spi/core.c
+@@ -381,7 +381,10 @@ static int spinand_read_from_cache_op(struct spinand_device *spinand,
+               }
+       }
+-      rdesc = spinand->dirmaps[req->pos.plane].rdesc;
++      if (req->mode == MTD_OPS_RAW)
++              rdesc = spinand->dirmaps[req->pos.plane].rdesc;
++      else
++              rdesc = spinand->dirmaps[req->pos.plane].rdesc_ecc;
+       while (nbytes) {
+               ret = spi_mem_dirmap_read(rdesc, column, nbytes, buf);
+@@ -452,7 +455,10 @@ static int spinand_write_to_cache_op(struct spinand_device *spinand,
+                              req->ooblen);
+       }
+-      wdesc = spinand->dirmaps[req->pos.plane].wdesc;
++      if (req->mode == MTD_OPS_RAW)
++              wdesc = spinand->dirmaps[req->pos.plane].wdesc;
++      else
++              wdesc = spinand->dirmaps[req->pos.plane].wdesc_ecc;
+       while (nbytes) {
+               ret = spi_mem_dirmap_write(wdesc, column, nbytes, buf);
+@@ -865,6 +871,31 @@ static int spinand_create_dirmap(struct spinand_device *spinand,
+       spinand->dirmaps[plane].rdesc = desc;
++      if (nand->ecc.engine->integration != NAND_ECC_ENGINE_INTEGRATION_PIPELINED) {
++              spinand->dirmaps[plane].wdesc_ecc = spinand->dirmaps[plane].wdesc;
++              spinand->dirmaps[plane].rdesc_ecc = spinand->dirmaps[plane].rdesc;
++
++              return 0;
++      }
++
++      info.op_tmpl = *spinand->op_templates.update_cache;
++      info.op_tmpl.data.ecc = true;
++      desc = devm_spi_mem_dirmap_create(&spinand->spimem->spi->dev,
++                                        spinand->spimem, &info);
++      if (IS_ERR(desc))
++              return PTR_ERR(desc);
++
++      spinand->dirmaps[plane].wdesc_ecc = desc;
++
++      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);
++      if (IS_ERR(desc))
++              return PTR_ERR(desc);
++
++      spinand->dirmaps[plane].rdesc_ecc = desc;
++
+       return 0;
+ }
+diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
+index 6988956b8492..3aa28240a77f 100644
+--- a/include/linux/mtd/spinand.h
++++ b/include/linux/mtd/spinand.h
+@@ -389,6 +389,8 @@ struct spinand_info {
+ struct spinand_dirmap {
+       struct spi_mem_dirmap_desc *wdesc;
+       struct spi_mem_dirmap_desc *rdesc;
++      struct spi_mem_dirmap_desc *wdesc_ecc;
++      struct spi_mem_dirmap_desc *rdesc_ecc;
+ };
+ /**
+-- 
+2.35.1
+
diff --git a/target/linux/mediatek/patches-5.15/120-10-v5.18-mtd-nand-fix-ecc-parameters-for-mt7622.patch b/target/linux/mediatek/patches-5.15/120-10-v5.18-mtd-nand-fix-ecc-parameters-for-mt7622.patch
new file mode 100644 (file)
index 0000000..7dbcf2f
--- /dev/null
@@ -0,0 +1,93 @@
+From 41825166744c6e5664281611f5e6d9a2e9333c2b Mon Sep 17 00:00:00 2001
+From: Chuanhong Guo <gch981213@gmail.com>
+Date: Sat, 2 Apr 2022 22:31:20 +0800
+Subject: [PATCH 10/15] mtd: nand: fix ecc parameters for mt7622
+
+According to the datasheet, mt7622 only has 5 ECC capabilities instead
+of 7, and the decoding error register is arranged  as follows:
++------+---------+---------+---------+---------+
+| Bits |  19:15  |  14:10  |   9:5   |   4:0   |
++------+---------+---------+---------+---------+
+| Name | ERRNUM3 | ERRNUM2 | ERRNUM1 | ERRNUM0 |
++------+---------+---------+---------+---------+
+This means err_mask should be 0x1f instead of 0x3f and the number of
+bits shifted in mtk_ecc_get_stats should be 5 instead of 8.
+
+This commit introduces err_shift for the difference in this register
+and fix other existing parameters.
+
+Public MT7622 reference manual can be found on [0] and the info this
+commit is based on is from page 656 and page 660.
+
+[0]: https://wiki.banana-pi.org/Banana_Pi_BPI-R64#Documents
+
+Fixes: 98dea8d71931 ("mtd: nand: mtk: Support MT7622 NAND flash controller.")
+Signed-off-by: Chuanhong Guo <gch981213@gmail.com>
+(cherry picked from commit 088b769abd1bd21753002b17b696ae1778b16e8c)
+---
+ drivers/mtd/nand/raw/mtk_ecc.c | 12 ++++++++----
+ 1 file changed, 8 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/mtd/nand/raw/mtk_ecc.c b/drivers/mtd/nand/raw/mtk_ecc.c
+index c437d97debb8..ec9d1fb07006 100644
+--- a/drivers/mtd/nand/raw/mtk_ecc.c
++++ b/drivers/mtd/nand/raw/mtk_ecc.c
+@@ -43,6 +43,7 @@
+ struct mtk_ecc_caps {
+       u32 err_mask;
++      u32 err_shift;
+       const u8 *ecc_strength;
+       const u32 *ecc_regs;
+       u8 num_ecc_strength;
+@@ -76,7 +77,7 @@ static const u8 ecc_strength_mt2712[] = {
+ };
+ static const u8 ecc_strength_mt7622[] = {
+-      4, 6, 8, 10, 12, 14, 16
++      4, 6, 8, 10, 12
+ };
+ enum mtk_ecc_regs {
+@@ -221,7 +222,7 @@ void mtk_ecc_get_stats(struct mtk_ecc *ecc, struct mtk_ecc_stats *stats,
+       for (i = 0; i < sectors; i++) {
+               offset = (i >> 2) << 2;
+               err = readl(ecc->regs + ECC_DECENUM0 + offset);
+-              err = err >> ((i % 4) * 8);
++              err = err >> ((i % 4) * ecc->caps->err_shift);
+               err &= ecc->caps->err_mask;
+               if (err == ecc->caps->err_mask) {
+                       /* uncorrectable errors */
+@@ -449,6 +450,7 @@ EXPORT_SYMBOL(mtk_ecc_get_parity_bits);
+ static const struct mtk_ecc_caps mtk_ecc_caps_mt2701 = {
+       .err_mask = 0x3f,
++      .err_shift = 8,
+       .ecc_strength = ecc_strength_mt2701,
+       .ecc_regs = mt2701_ecc_regs,
+       .num_ecc_strength = 20,
+@@ -459,6 +461,7 @@ static const struct mtk_ecc_caps mtk_ecc_caps_mt2701 = {
+ static const struct mtk_ecc_caps mtk_ecc_caps_mt2712 = {
+       .err_mask = 0x7f,
++      .err_shift = 8,
+       .ecc_strength = ecc_strength_mt2712,
+       .ecc_regs = mt2712_ecc_regs,
+       .num_ecc_strength = 23,
+@@ -468,10 +471,11 @@ static const struct mtk_ecc_caps mtk_ecc_caps_mt2712 = {
+ };
+ static const struct mtk_ecc_caps mtk_ecc_caps_mt7622 = {
+-      .err_mask = 0x3f,
++      .err_mask = 0x1f,
++      .err_shift = 5,
+       .ecc_strength = ecc_strength_mt7622,
+       .ecc_regs = mt7622_ecc_regs,
+-      .num_ecc_strength = 7,
++      .num_ecc_strength = 5,
+       .ecc_mode_shift = 4,
+       .parity_bits = 13,
+       .pg_irq_sel = 0,
+-- 
+2.35.1
+