Skip to contentSkip to conversation

SPI-NAND support

PATCH Superseded Miquel Raynal 3 participants 32 messages Jul 11, 2018 – Jul 12, 2018

Subsystems (12)

v2 of 13 Superseded Latest is v13 →

lore
Share & tools
lore

Miquel Raynal

author maintainer
#0 lore raw

v2 cover SPI-NAND support

During the last months, Boris Brezillon shared his work to support serial flashes within Linux. First, he delivered (and merged) a new layer called spi-mem. He also initiated in Linux MTD subsystem the move of all 'raw' NAND related code to a raw/ subdirectory, adding at the same time a NAND core that would be shared with all NAND devices. Then, he contributed a generic SPI-NAND driver, making use of this NAND core, as well as some vendor code to drive a few chips.

On top of this work, I added an 'mtd' U-Boot command to handle all sort of MTD devices. This should become the default command instead of having one per flash flavor ('sf', 'nand', 'spi-nand' ?).

The series has been tested on an Ocelot board PCB123 (VSC7514), featuring a Macronix SPI NAND chip.

TL;DR: the series contains:
- A few patches from Linux to resynchronize some areas of the MTD layer.
- Various fixes and re-organization of the MTD subsystem.
- The introduction of the SPI-mem interface.
- The addition of the generic SPI-NAND driver (and its bindings).
- Several SPI NAND chip drivers (Macronix, Micron, Winbond).
- A new 'mtd' command.

Any comments on the code, the organization and the respect of U-Boot driver model will be welcome.

Thanks,
Miquèl

Changes since v1:
-----------------
* Fixed the nand_memorg structure of the MX35LF2GE4AB chip.
* Added Reviewed-by tags from Jagan.
* Backported and squashed two patches fixing things in the SPI NAND core received on the Linux ML.
* Backported more changes in mtdcore.c from Linux.
* Added a patch to add a fallback on mtd->_read/_write() in mtdcore.c when mtd->_read/write_oob() is not supported.
* Removed the DT changes, useless as the DTs are not available in mainline yet.
* Addressed Boris/Stefan comments on the 'mtd' command.
* Added support for multi-pages OOB read/write.

Boris Brezillon (7):
mtd: Fallback to ->_read/write_oob() when ->_read/write() is missing
mtd: Add sanity checks in mtd_write/read_oob()
mtd: nand: Add core infrastructure to deal with NAND devices
mtd: nand: Pass mode information to nand_page_io_req
spi: Extend the core to ease integration of SPI memory controllers
mtd: spinand: Add initial support for the MX35LF1GE4AB chip
dt-bindings: Add bindings for SPI NAND devices

Brian Norris (1):
mtd: add get/set of_node/flash_node helpers

Ezequiel Garcia (1):
mtd: Uninline mtd_write_oob and move it to mtdcore.c

Frieder Schrempf (1):
mtd: spinand: Add initial support for Winbond W25M02GV

Miquel Raynal (9):
mtd: Fallback to ->_read/write() when ->_read/write_oob() is missing
mtd: fix build issue with includes
mtd: move definitions to enlarge their range
mtd: move all flash categories inside MTD submenu
mtd: move NAND fiels into a raw/ subdirectory
mtd: rename nand into rawnand in Kconfig prompt
mtd: spinand: Add initial support for the MX35LF2GE4AB chip
mtd: uclass: add probe function
cmd: mtd: add 'mtd' command

Peter Pan (2):
mtd: nand: Add core infrastructure to support SPI NANDs
mtd: spinand: Add initial support for Micron MT29F2G01ABAGD

 cmd/Kconfig                                   |    5 +
 cmd/Makefile                                  |    1 +
 cmd/mtd.c                                     |  287 ++++++
 doc/device-tree-bindings/mtd/spi-nand.txt     |   27 +
 drivers/mtd/Kconfig                           |    4 +-
 drivers/mtd/Makefile                          |    4 +-
 drivers/mtd/mtd-uclass.c                      |    9 +
 drivers/mtd/mtdcore.c                         |  106 ++-
 drivers/mtd/mtdcore.h                         |    6 -
 drivers/mtd/mtdpart.c                         |    6 +-
 drivers/mtd/nand/Kconfig                      |  241 +----
 drivers/mtd/nand/Makefile                     |   81 +-
 drivers/mtd/nand/bbt.c                        |  132 +++
 drivers/mtd/nand/core.c                       |  243 +++++
 drivers/mtd/nand/raw/Kconfig                  |  239 +++++
 drivers/mtd/nand/raw/Makefile                 |   78 ++
 drivers/mtd/nand/{ => raw}/am335x_spl_bch.c   |    0
 drivers/mtd/nand/{ => raw}/arasan_nfc.c       |    0
 drivers/mtd/nand/{ => raw}/atmel_nand.c       |    0
 drivers/mtd/nand/{ => raw}/atmel_nand_ecc.h   |    0
 drivers/mtd/nand/{ => raw}/davinci_nand.c     |    0
 drivers/mtd/nand/{ => raw}/denali.c           |    0
 drivers/mtd/nand/{ => raw}/denali.h           |    0
 drivers/mtd/nand/{ => raw}/denali_dt.c        |    0
 drivers/mtd/nand/{ => raw}/denali_spl.c       |    0
 drivers/mtd/nand/{ => raw}/fsl_elbc_nand.c    |    0
 drivers/mtd/nand/{ => raw}/fsl_elbc_spl.c     |    0
 drivers/mtd/nand/{ => raw}/fsl_ifc_nand.c     |    0
 drivers/mtd/nand/{ => raw}/fsl_ifc_spl.c      |    0
 drivers/mtd/nand/{ => raw}/fsl_upm.c          |    0
 drivers/mtd/nand/{ => raw}/fsmc_nand.c        |    0
 drivers/mtd/nand/{ => raw}/kb9202_nand.c      |    0
 drivers/mtd/nand/{ => raw}/kirkwood_nand.c    |    0
 drivers/mtd/nand/{ => raw}/kmeter1_nand.c     |    0
 drivers/mtd/nand/{ => raw}/lpc32xx_nand_mlc.c |    0
 drivers/mtd/nand/{ => raw}/lpc32xx_nand_slc.c |    0
 drivers/mtd/nand/{ => raw}/mxc_nand.c         |    0
 drivers/mtd/nand/{ => raw}/mxc_nand.h         |    0
 drivers/mtd/nand/{ => raw}/mxc_nand_spl.c     |    0
 drivers/mtd/nand/{ => raw}/mxs_nand.c         |    0
 drivers/mtd/nand/{ => raw}/mxs_nand_spl.c     |    0
 drivers/mtd/nand/{ => raw}/nand.c             |    0
 drivers/mtd/nand/{ => raw}/nand_base.c        |   56 --
 drivers/mtd/nand/{ => raw}/nand_bbt.c         |    0
 drivers/mtd/nand/{ => raw}/nand_bch.c         |    0
 drivers/mtd/nand/{ => raw}/nand_ecc.c         |    0
 drivers/mtd/nand/{ => raw}/nand_ids.c         |    0
 drivers/mtd/nand/{ => raw}/nand_plat.c        |    0
 drivers/mtd/nand/{ => raw}/nand_spl_load.c    |    0
 drivers/mtd/nand/{ => raw}/nand_spl_loaders.c |    0
 drivers/mtd/nand/{ => raw}/nand_spl_simple.c  |    0
 drivers/mtd/nand/{ => raw}/nand_timings.c     |    0
 drivers/mtd/nand/{ => raw}/nand_util.c        |    0
 drivers/mtd/nand/{ => raw}/ndfc.c             |    0
 drivers/mtd/nand/{ => raw}/omap_elm.c         |    0
 drivers/mtd/nand/{ => raw}/omap_gpmc.c        |    0
 drivers/mtd/nand/{ => raw}/pxa3xx_nand.c      |    0
 drivers/mtd/nand/{ => raw}/pxa3xx_nand.h      |    0
 drivers/mtd/nand/{ => raw}/sunxi_nand.c       |    0
 drivers/mtd/nand/{ => raw}/sunxi_nand_spl.c   |    0
 drivers/mtd/nand/{ => raw}/tegra_nand.c       |    0
 drivers/mtd/nand/{ => raw}/tegra_nand.h       |    0
 drivers/mtd/nand/{ => raw}/vf610_nfc.c        |    0
 drivers/mtd/nand/{ => raw}/zynq_nand.c        |    0
 drivers/mtd/nand/spi/Kconfig                  |    7 +
 drivers/mtd/nand/spi/Makefile                 |    4 +
 drivers/mtd/nand/spi/core.c                   | 1254 +++++++++++++++++++++++++
 drivers/mtd/nand/spi/macronix.c               |  146 +++
 drivers/mtd/nand/spi/micron.c                 |  135 +++
 drivers/mtd/nand/spi/winbond.c                |  143 +++
 drivers/mtd/onenand/onenand_base.c            |   60 --
 drivers/spi/Kconfig                           |    7 +
 drivers/spi/Makefile                          |    1 +
 drivers/spi/spi-mem.c                         |  500 ++++++++++
 include/linux/mtd/mtd.h                       |   33 +-
 include/linux/mtd/nand.h                      |  734 +++++++++++++++
 include/linux/mtd/spinand.h                   |  432 +++++++++
 include/spi-mem.h                             |  258 +++++
 include/spi.h                                 |   11 +
 79 files changed, 4795 insertions(+), 455 deletions(-)
 create mode 100644 cmd/mtd.c
 create mode 100644 doc/device-tree-bindings/mtd/spi-nand.txt
 create mode 100644 drivers/mtd/nand/bbt.c
 create mode 100644 drivers/mtd/nand/core.c
 create mode 100644 drivers/mtd/nand/raw/Kconfig
 create mode 100644 drivers/mtd/nand/raw/Makefile
 rename drivers/mtd/nand/{ => raw}/am335x_spl_bch.c (100%)
 rename drivers/mtd/nand/{ => raw}/arasan_nfc.c (100%)
 rename drivers/mtd/nand/{ => raw}/atmel_nand.c (100%)
 rename drivers/mtd/nand/{ => raw}/atmel_nand_ecc.h (100%)
 rename drivers/mtd/nand/{ => raw}/davinci_nand.c (100%)
 rename drivers/mtd/nand/{ => raw}/denali.c (100%)
 rename drivers/mtd/nand/{ => raw}/denali.h (100%)
 rename drivers/mtd/nand/{ => raw}/denali_dt.c (100%)
 rename drivers/mtd/nand/{ => raw}/denali_spl.c (100%)
 rename drivers/mtd/nand/{ => raw}/fsl_elbc_nand.c (100%)
 rename drivers/mtd/nand/{ => raw}/fsl_elbc_spl.c (100%)
 rename drivers/mtd/nand/{ => raw}/fsl_ifc_nand.c (100%)
 rename drivers/mtd/nand/{ => raw}/fsl_ifc_spl.c (100%)
 rename drivers/mtd/nand/{ => raw}/fsl_upm.c (100%)
 rename drivers/mtd/nand/{ => raw}/fsmc_nand.c (100%)
 rename drivers/mtd/nand/{ => raw}/kb9202_nand.c (100%)
 rename drivers/mtd/nand/{ => raw}/kirkwood_nand.c (100%)
 rename drivers/mtd/nand/{ => raw}/kmeter1_nand.c (100%)
 rename drivers/mtd/nand/{ => raw}/lpc32xx_nand_mlc.c (100%)
 rename drivers/mtd/nand/{ => raw}/lpc32xx_nand_slc.c (100%)
 rename drivers/mtd/nand/{ => raw}/mxc_nand.c (100%)
 rename drivers/mtd/nand/{ => raw}/mxc_nand.h (100%)
 rename drivers/mtd/nand/{ => raw}/mxc_nand_spl.c (100%)
 rename drivers/mtd/nand/{ => raw}/mxs_nand.c (100%)
 rename drivers/mtd/nand/{ => raw}/mxs_nand_spl.c (100%)
 rename drivers/mtd/nand/{ => raw}/nand.c (100%)
 rename drivers/mtd/nand/{ => raw}/nand_base.c (98%)
 rename drivers/mtd/nand/{ => raw}/nand_bbt.c (100%)
 rename drivers/mtd/nand/{ => raw}/nand_bch.c (100%)
 rename drivers/mtd/nand/{ => raw}/nand_ecc.c (100%)
 rename drivers/mtd/nand/{ => raw}/nand_ids.c (100%)
 rename drivers/mtd/nand/{ => raw}/nand_plat.c (100%)
 rename drivers/mtd/nand/{ => raw}/nand_spl_load.c (100%)
 rename drivers/mtd/nand/{ => raw}/nand_spl_loaders.c (100%)
 rename drivers/mtd/nand/{ => raw}/nand_spl_simple.c (100%)
 rename drivers/mtd/nand/{ => raw}/nand_timings.c (100%)
 rename drivers/mtd/nand/{ => raw}/nand_util.c (100%)
 rename drivers/mtd/nand/{ => raw}/ndfc.c (100%)
 rename drivers/mtd/nand/{ => raw}/omap_elm.c (100%)
 rename drivers/mtd/nand/{ => raw}/omap_gpmc.c (100%)
 rename drivers/mtd/nand/{ => raw}/pxa3xx_nand.c (100%)
 rename drivers/mtd/nand/{ => raw}/pxa3xx_nand.h (100%)
 rename drivers/mtd/nand/{ => raw}/sunxi_nand.c (100%)
 rename drivers/mtd/nand/{ => raw}/sunxi_nand_spl.c (100%)
 rename drivers/mtd/nand/{ => raw}/tegra_nand.c (100%)
 rename drivers/mtd/nand/{ => raw}/tegra_nand.h (100%)
 rename drivers/mtd/nand/{ => raw}/vf610_nfc.c (100%)
 rename drivers/mtd/nand/{ => raw}/zynq_nand.c (100%)
 create mode 100644 drivers/mtd/nand/spi/Kconfig
 create mode 100644 drivers/mtd/nand/spi/Makefile
 create mode 100644 drivers/mtd/nand/spi/core.c
 create mode 100644 drivers/mtd/nand/spi/macronix.c
 create mode 100644 drivers/mtd/nand/spi/micron.c
 create mode 100644 drivers/mtd/nand/spi/winbond.c
 create mode 100644 drivers/spi/spi-mem.c
 create mode 100644 include/linux/mtd/nand.h
 create mode 100644 include/linux/mtd/spinand.h
 create mode 100644 include/spi-mem.h
Signature · 1 line
2.14.1
author maintainer
#1 lore raw

PATCH v2 1/21 mtd: Fallback to ->_read/write_oob() when ->_read/write() is missing

From: Boris Brezillon <[email protected]>

Some MTD sublayers/drivers are implementing ->_read/write_oob() and provide dummy wrappers for their ->_read/write() implementations. Let the core handle this case instead of duplicating the logic.

---
 drivers/mtd/mtdcore.c              | 31 ++++++++++++++++++--
 drivers/mtd/mtdpart.c              |  6 ++--
 drivers/mtd/nand/nand_base.c       | 56 -----------------------------------
 drivers/mtd/onenand/onenand_base.c | 60 --------------------------------------
 4 files changed, 33 insertions(+), 120 deletions(-)
drivers/mtd/mtdcore.c +29 -2
index 2cda0511e8..15e0ac2f3e 100644
@@ -938,7 +938,20 @@ int mtd_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen,
 	 * representing the maximum number of bitflips that were corrected on
 	 * any one ecc region (if applicable; zero otherwise).
 	 */
-	ret_code = mtd->_read(mtd, from, len, retlen, buf);
+	if (mtd->_read) {
+		ret_code = mtd->_read(mtd, from, len, retlen, buf);
+	} else if (mtd->_read_oob) {
+		struct mtd_oob_ops ops = {
+			.len = len,
+			.datbuf = buf,
+		};
+
+		ret_code = mtd->_read_oob(mtd, from, &ops);
+		*retlen = ops.retlen;
+	} else {
+		return -ENOTSUPP;
+	}
+
 	if (unlikely(ret_code < 0))
 		return ret_code;
 	if (mtd->ecc_strength == 0)
@@ -953,10 +966,24 @@ int mtd_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen,
 	*retlen = 0;
 	if (to < 0 || to > mtd->size || len > mtd->size - to)
 		return -EINVAL;
-	if (!mtd->_write || !(mtd->flags & MTD_WRITEABLE))
+	if ((!mtd->_write && !mtd->_write_oob) ||
+	    !(mtd->flags & MTD_WRITEABLE))
 		return -EROFS;
 	if (!len)
 		return 0;
+
+	if (!mtd->_write) {
+		struct mtd_oob_ops ops = {
+			.len = len,
+			.datbuf = (u8 *)buf,
+		};
+		int ret;
+
+		ret = mtd->_write_oob(mtd, to, &ops);
+		*retlen = ops.retlen;
+		return ret;
+	}
+
 	return mtd->_write(mtd, to, len, retlen, buf);
 }
 EXPORT_SYMBOL_GPL(mtd_write);
drivers/mtd/mtdpart.c +4 -2
index 5e42c4b833..3a3f2a1717 100644
@@ -418,8 +418,10 @@ static struct mtd_part *allocate_partition(struct mtd_info *master,
 	slave->mtd.dev.parent = master->dev.parent;
 #endif
 
-	slave->mtd._read = part_read;
-	slave->mtd._write = part_write;
+	if (parent->_read)
+		slave->mtd._read = part_read;
+	if (parent->_write)
+		slave->mtd._write = part_write;
 
 	if (master->_panic_write)
 		slave->mtd._panic_write = part_panic_write;
drivers/mtd/nand/nand_base.c +0 -56

74 lines not on this page · raw message

drivers/mtd/onenand/onenand_base.c +0 -60

78 lines not on this page · raw message

Signature · 1 line
2.14.1
author maintainer
#2 lore raw

PATCH v2 2/21 mtd: Uninline mtd_write_oob and move it to mtdcore.c

In reply to Miquel Raynal

From: Ezequiel Garcia <[email protected]>

There's no reason for having mtd_write_oob inlined in mtd.h header. Move it to mtdcore.c where it belongs.

---
 drivers/mtd/mtdcore.c   | 12 ++++++++++++
 include/linux/mtd/mtd.h | 12 +-----------
 2 files changed, 13 insertions(+), 11 deletions(-)
drivers/mtd/mtdcore.c +12 -0
index 15e0ac2f3e..c22ca20368 100644
@@ -1032,6 +1032,18 @@ int mtd_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops)
 }
 EXPORT_SYMBOL_GPL(mtd_read_oob);
 
+int mtd_write_oob(struct mtd_info *mtd, loff_t to,
+				struct mtd_oob_ops *ops)
+{
+	ops->retlen = ops->oobretlen = 0;
+	if (!mtd->_write_oob)
+		return -EOPNOTSUPP;
+	if (!(mtd->flags & MTD_WRITEABLE))
+		return -EROFS;
+	return mtd->_write_oob(mtd, to, ops);
+}
+EXPORT_SYMBOL_GPL(mtd_write_oob);
+
 /**
  * mtd_ooblayout_ecc - Get the OOB region definition of a specific ECC section
  * @mtd: MTD device structure
include/linux/mtd/mtd.h +1 -11
index ba4cbba949..13455e0d24 100644
@@ -356,17 +356,7 @@ int mtd_panic_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen,
 		    const u_char *buf);
 
 int mtd_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops);
-
-static inline int mtd_write_oob(struct mtd_info *mtd, loff_t to,
-				struct mtd_oob_ops *ops)
-{
-	ops->retlen = ops->oobretlen = 0;
-	if (!mtd->_write_oob)
-		return -EOPNOTSUPP;
-	if (!(mtd->flags & MTD_WRITEABLE))
-		return -EROFS;
-	return mtd->_write_oob(mtd, to, ops);
-}
+int mtd_write_oob(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops);
 
 int mtd_get_fact_prot_info(struct mtd_info *mtd, size_t len, size_t *retlen,
 			   struct otp_info *buf);
Signature · 1 line
2.14.1
author maintainer
#3 lore raw

PATCH v2 3/21 mtd: Add sanity checks in mtd_write/read_oob()

In reply to Miquel Raynal

From: Boris Brezillon <[email protected]>

Unlike what's done in mtd_read/write(), there are no checks to make sure the parameters passed to mtd_read/write_oob() are consistent, which forces implementers of ->_read/write_oob() to do it, which in turn leads to code duplication and possibly errors in the logic.

Do general sanity checks, like ops fields consistency and range checking.

Cc Peter Pan <[email protected]>
[Miquel: squashed the fix about the chip's size check]
---
 drivers/mtd/mtdcore.c | 45 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 45 insertions(+)
drivers/mtd/mtdcore.c +45 -0
index c22ca20368..ba170f212e 100644
@@ -1011,12 +1011,50 @@ int mtd_panic_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen,
 }
 EXPORT_SYMBOL_GPL(mtd_panic_write);
 
+static int mtd_check_oob_ops(struct mtd_info *mtd, loff_t offs,
+			     struct mtd_oob_ops *ops)
+{
+	/*
+	 * Some users are setting ->datbuf or ->oobbuf to NULL, but are leaving
+	 * ->len or ->ooblen uninitialized. Force ->len and ->ooblen to 0 in
+	 *  this case.
+	 */
+	if (!ops->datbuf)
+		ops->len = 0;
+
+	if (!ops->oobbuf)
+		ops->ooblen = 0;
+
+	if (offs < 0 || offs + ops->len > mtd->size)
+		return -EINVAL;
+
+	if (ops->ooblen) {
+		u64 maxooblen;
+
+		if (ops->ooboffs >= mtd_oobavail(mtd, ops))
+			return -EINVAL;
+
+		maxooblen = ((mtd_div_by_ws(mtd->size, mtd) -
+			      mtd_div_by_ws(offs, mtd)) *
+			     mtd_oobavail(mtd, ops)) - ops->ooboffs;
+		if (ops->ooblen > maxooblen)
+			return -EINVAL;
+	}
+
+	return 0;
+}
+
 int mtd_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops)
 {
 	int ret_code;
 	ops->retlen = ops->oobretlen = 0;
 	if (!mtd->_read_oob)
 		return -EOPNOTSUPP;
+
+	ret_code = mtd_check_oob_ops(mtd, from, ops);
+	if (ret_code)
+		return ret_code;
+
 	/*
 	 * In cases where ops->datbuf != NULL, mtd->_read_oob() has semantics
 	 * similar to mtd->_read(), returning a non-negative integer
@@ -1035,11 +1073,18 @@ EXPORT_SYMBOL_GPL(mtd_read_oob);
 int mtd_write_oob(struct mtd_info *mtd, loff_t to,
 				struct mtd_oob_ops *ops)
 {
+	int ret;
+
 	ops->retlen = ops->oobretlen = 0;
 	if (!mtd->_write_oob)
 		return -EOPNOTSUPP;
 	if (!(mtd->flags & MTD_WRITEABLE))
 		return -EROFS;
+
+	ret = mtd_check_oob_ops(mtd, to, ops);
+	if (ret)
+		return ret;
+
 	return mtd->_write_oob(mtd, to, ops);
 }
 EXPORT_SYMBOL_GPL(mtd_write_oob);
Signature · 1 line
2.14.1
author maintainer
#4 lore raw

PATCH v2 4/21 mtd: Fallback to ->_read/write() when ->_read/write_oob() is missing

In reply to Miquel Raynal

Some MTD sublayers/drivers are implementing ->_read/write() and not ->_read/write_oob().

While for NAND devices both are usually valid, for NOR devices, using the _oob variant has no real meaning. But, as the MTD layer is supposed to hide as much as possible the flash complexity to the user, there is no reason to error out while it is just a matter of rewritting things internally.

Add a fallback on mtd->_read() (resp. mtd->_write()) when the user calls mtd_read_oob() (resp. mtd_write_oob()) while mtd->_read_oob() (resp. mtd->_write_oob) is not implemented. There is already a fallback on the _oob variant if the former is used.

---
 drivers/mtd/mtdcore.c | 26 ++++++++++++++++++++------
 1 file changed, 20 insertions(+), 6 deletions(-)
drivers/mtd/mtdcore.c +20 -6
index ba170f212e..095c58cf8c 100644
@@ -1048,20 +1048,27 @@ int mtd_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops)
 {
 	int ret_code;
 	ops->retlen = ops->oobretlen = 0;
-	if (!mtd->_read_oob)
-		return -EOPNOTSUPP;
 
 	ret_code = mtd_check_oob_ops(mtd, from, ops);
 	if (ret_code)
 		return ret_code;
 
+	/* Check the validity of a potential fallback on mtd->_read */
+	if ((!mtd->_read_oob) && (!mtd->_read || ops->oobbuf))
+		return -EOPNOTSUPP;
+
+	if (mtd->_read_oob)
+		ret_code = mtd->_read_oob(mtd, from, ops);
+	else
+		ret_code = mtd->_read(mtd, from, ops->len, &ops->retlen,
+				      ops->datbuf);
+
 	/*
 	 * In cases where ops->datbuf != NULL, mtd->_read_oob() has semantics
 	 * similar to mtd->_read(), returning a non-negative integer
 	 * representing max bitflips. In other cases, mtd->_read_oob() may
 	 * return -EUCLEAN. In all cases, perform similar logic to mtd_read().
 	 */
-	ret_code = mtd->_read_oob(mtd, from, ops);
 	if (unlikely(ret_code < 0))
 		return ret_code;
 	if (mtd->ecc_strength == 0)
@@ -1076,8 +1083,7 @@ int mtd_write_oob(struct mtd_info *mtd, loff_t to,
 	int ret;
 
 	ops->retlen = ops->oobretlen = 0;
-	if (!mtd->_write_oob)
-		return -EOPNOTSUPP;
+
 	if (!(mtd->flags & MTD_WRITEABLE))
 		return -EROFS;
 
@@ -1085,7 +1091,15 @@ int mtd_write_oob(struct mtd_info *mtd, loff_t to,
 	if (ret)
 		return ret;
 
-	return mtd->_write_oob(mtd, to, ops);
+	/* Check the validity of a potential fallback on mtd->_write */
+	if ((!mtd->_write_oob) && (!mtd->_write || ops->oobbuf))
+		return -EOPNOTSUPP;
+
+	if (mtd->_write_oob)
+		return mtd->_write_oob(mtd, to, ops);
+	else
+		return mtd->_write(mtd, to, ops->len, &ops->retlen,
+				   ops->datbuf);
 }
 EXPORT_SYMBOL_GPL(mtd_write_oob);
 
Signature · 1 line
2.14.1
#5 lore raw

PATCH v2 4/21 mtd: Fallback to ->_read/write() when ->_read/write_oob() is missing

Quoted 9 lines · On Wed, 11 Jul 2018 17:25:12 +0200 Miquel Raynal <[email protected]>…

Some MTD sublayers/drivers are implementing ->_read/write() and not ->_read/write_oob().

While for NAND devices both are usually valid, for NOR devices, using the _oob variant has no real meaning. But, as the MTD layer is supposed to hide as much as possible the flash complexity to the user, there is no reason to error out while it is just a matter of rewritting things internally.

Quoted 4 lines

Add a fallback on mtd->_read() (resp. mtd->_write()) when the user calls mtd_read_oob() (resp. mtd_write_oob()) while mtd->_read_oob() (resp. mtd->_write_oob) is not implemented. There is already a fallback on the _oob variant if the former is used.

Now I'm jealous. Can we have the same thing Linux :-).

Quoted 13 lines
---
 drivers/mtd/mtdcore.c | 26 ++++++++++++++++++++------
 1 file changed, 20 insertions(+), 6 deletions(-)
drivers/mtd/mtdcore.c +0 -0
index ba170f212e..095c58cf8c 100644
@@ -1048,20 +1048,27 @@ int mtd_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops)
 {
 	int ret_code;

drivers/mtd/mtdcore.c int mtd_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops) · line 1057

Quoted 10 lines
drivers/mtd/mtdcore.c +2 -2
 	ops->retlen = ops->oobretlen = 0;
-	if (!mtd->_read_oob)
-		return -EOPNOTSUPP;
 
 	ret_code = mtd_check_oob_ops(mtd, from, ops);
 	if (ret_code)
 		return ret_code;
 
+	/* Check the validity of a potential fallback on mtd->_read */
+	if ((!mtd->_read_oob) && (!mtd->_read || ops->oobbuf))

Parens around !mtd->_read_oob are not needed.

Quoted 29 lines
drivers/mtd/mtdcore.c +9 -3
+		return -EOPNOTSUPP;
+
+	if (mtd->_read_oob)
+		ret_code = mtd->_read_oob(mtd, from, ops);
+	else
+		ret_code = mtd->_read(mtd, from, ops->len, &ops->retlen,
+				      ops->datbuf);
+
 	/*
 	 * In cases where ops->datbuf != NULL, mtd->_read_oob() has semantics
 	 * similar to mtd->_read(), returning a non-negative integer
 	 * representing max bitflips. In other cases, mtd->_read_oob() may
 	 * return -EUCLEAN. In all cases, perform similar logic to mtd_read().
 	 */
-	ret_code = mtd->_read_oob(mtd, from, ops);
 	if (unlikely(ret_code < 0))
 		return ret_code;
 	if (mtd->ecc_strength == 0)
@@ -1076,8 +1083,7 @@ int mtd_write_oob(struct mtd_info *mtd, loff_t to,
 	int ret;
 
 	ops->retlen = ops->oobretlen = 0;
-	if (!mtd->_write_oob)
-		return -EOPNOTSUPP;
+
 	if (!(mtd->flags & MTD_WRITEABLE))
 		return -EROFS;
 

drivers/mtd/mtdcore.c int mtd_write_oob(struct mtd_info *mtd, loff_t to, · line 1095

Quoted 6 lines
drivers/mtd/mtdcore.c +2 -1
@@ -1085,7 +1091,15 @@ int mtd_write_oob(struct mtd_info *mtd, loff_t to,
 	if (ret)
 		return ret;
 
-	return mtd->_write_oob(mtd, to, ops);
+	/* Check the validity of a potential fallback on mtd->_write */
+	if ((!mtd->_write_oob) && (!mtd->_write || ops->oobbuf))

Ditto.

Quoted 10 lines
drivers/mtd/mtdcore.c +7 -0
+		return -EOPNOTSUPP;
+
+	if (mtd->_write_oob)
+		return mtd->_write_oob(mtd, to, ops);
+	else
+		return mtd->_write(mtd, to, ops->len, &ops->retlen,
+				   ops->datbuf);
 }
 EXPORT_SYMBOL_GPL(mtd_write_oob);
 
author maintainer
#6 lore raw

PATCH v2 4/21 mtd: Fallback to ->_read/write() when ->_read/write_oob() is missing

Hi Boris,

Boris Brezillon <[email protected]> wrote on Thu, 12 Jul 2018 00:20:52 +0200:

Quoted 12 lines
Quoted 9 lines · On Wed, 11 Jul 2018 17:25:12 +0200 Miquel Raynal <[email protected]>…

Some MTD sublayers/drivers are implementing ->_read/write() and not ->_read/write_oob().

While for NAND devices both are usually valid, for NOR devices, using the _oob variant has no real meaning. But, as the MTD layer is supposed to hide as much as possible the flash complexity to the user, there is no reason to error out while it is just a matter of rewritting things internally.

Quoted 6 lines
Quoted 4 lines

Add a fallback on mtd->_read() (resp. mtd->_write()) when the user calls mtd_read_oob() (resp. mtd_write_oob()) while mtd->_read_oob() (resp. mtd->_write_oob) is not implemented. There is already a fallback on the _oob variant if the former is used.

Now I'm jealous. Can we have the same thing Linux :-).

U-Boot, one step ahead ;)

Quoted 26 lines
Quoted 14 lines
---
 drivers/mtd/mtdcore.c | 26 ++++++++++++++++++++------
 1 file changed, 20 insertions(+), 6 deletions(-)
drivers/mtd/mtdcore.c +0 -0
index ba170f212e..095c58cf8c 100644
@@ -1048,20 +1048,27 @@ int mtd_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops)
 {
 	int ret_code;

drivers/mtd/mtdcore.c int mtd_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops) · line 1057

Quoted 10 lines
drivers/mtd/mtdcore.c +2 -2
 	ops->retlen = ops->oobretlen = 0;
-	if (!mtd->_read_oob)
-		return -EOPNOTSUPP;
 
 	ret_code = mtd_check_oob_ops(mtd, from, ops);
 	if (ret_code)
 		return ret_code;
 
+	/* Check the validity of a potential fallback on mtd->_read */
+	if ((!mtd->_read_oob) && (!mtd->_read || ops->oobbuf))  

Parens around !mtd->_read_oob are not needed.

[...]

Quoted 6 lines

drivers/mtd/mtdcore.c int mtd_write_oob(struct mtd_info *mtd, loff_t to, · line 1095

Quoted 3 lines
drivers/mtd/mtdcore.c +2 -1
-	return mtd->_write_oob(mtd, to, ops);
+	/* Check the validity of a potential fallback on mtd->_write */
+	if ((!mtd->_write_oob) && (!mtd->_write || ops->oobbuf))  

Ditto.

Right!

Thanks,
Miquèl

author maintainer
#7 lore raw

PATCH v2 5/21 mtd: add get/set of_node/flash_node helpers

In reply to Miquel Raynal

From: Brian Norris <[email protected]>

We are going to begin using the mtd->dev.of_node field for MTD device nodes, so let's add helpers for it. Also, we'll be making some conversions on spi_nor (and nand_chip eventually) too, so get that ready with their own helpers.

---
 include/linux/mtd/mtd.h | 11 +++++++++++
 1 file changed, 11 insertions(+)
include/linux/mtd/mtd.h +11 -0
index 13455e0d24..5b110ec873 100644
@@ -311,6 +311,17 @@ struct mtd_info {
 	int usecount;
 };
 
+static inline void mtd_set_of_node(struct mtd_info *mtd,
+				   const struct device_node *np)
+{
+	mtd->dev->node.np = np;
+}
+
+static inline const struct device_node *mtd_get_of_node(struct mtd_info *mtd)
+{
+	return mtd->dev->node.np;
+}
+
 int mtd_ooblayout_ecc(struct mtd_info *mtd, int section,
 		      struct mtd_oob_region *oobecc);
 int mtd_ooblayout_find_eccregion(struct mtd_info *mtd, int eccbyte,
Signature · 1 line
2.14.1
author maintainer
#8 lore raw

PATCH v2 6/21 mtd: fix build issue with includes

In reply to Miquel Raynal

Fix build errors produced by mtd.h and dm/device.h if not included in the right order.

---
 include/linux/mtd/mtd.h | 1 +
 1 file changed, 1 insertion(+)
include/linux/mtd/mtd.h +1 -0
index 5b110ec873..8ffc33b0cc 100644
@@ -22,6 +22,7 @@
 #include <mtd/mtd-abi.h>
 #include <linux/errno.h>
 #include <div64.h>
+#include <dm/device.h>
 
 #define MAX_MTD_DEVICES 32
 #endif
Signature · 1 line
2.14.1
author maintainer
#9 lore raw

PATCH v2 7/21 mtd: move definitions to enlarge their range

In reply to Miquel Raynal

Some helpers might be useful in a future 'mtd' U-Boot command to parse MTD device list.

---
 drivers/mtd/mtdcore.h   | 6 ------
 include/linux/mtd/mtd.h | 6 ++++++
 2 files changed, 6 insertions(+), 6 deletions(-)
drivers/mtd/mtdcore.h +0 -6
index 7b0353399a..1d181a1045 100644
@@ -5,7 +5,6 @@
 
 extern struct mutex mtd_table_mutex;
 
-struct mtd_info *__mtd_next_device(int i);
 int add_mtd_device(struct mtd_info *mtd);
 int del_mtd_device(struct mtd_info *mtd);
 int add_mtd_partitions(struct mtd_info *, const struct mtd_partition *, int);
@@ -16,8 +15,3 @@ int parse_mtd_partitions(struct mtd_info *master, const char * const *types,
 
 int __init init_mtdchar(void);
 void __exit cleanup_mtdchar(void);
-
-#define mtd_for_each_device(mtd)			\
-	for ((mtd) = __mtd_next_device(0);		\
-	     (mtd) != NULL;				\
-	     (mtd) = __mtd_next_device(mtd->index + 1))
include/linux/mtd/mtd.h +6 -0
index 8ffc33b0cc..9a63bf4a49 100644
@@ -522,6 +522,12 @@ int del_mtd_device(struct mtd_info *mtd);
 int add_mtd_partitions(struct mtd_info *, const struct mtd_partition *, int);
 int del_mtd_partitions(struct mtd_info *);
 
+struct mtd_info *__mtd_next_device(int i);
+#define mtd_for_each_device(mtd)			\
+	for ((mtd) = __mtd_next_device(0);		\
+	     (mtd) != NULL;				\
+	     (mtd) = __mtd_next_device(mtd->index + 1))
+
 int mtd_arg_off(const char *arg, int *idx, loff_t *off, loff_t *size,
 		loff_t *maxsize, int devtype, uint64_t chipsize);
 int mtd_arg_off_size(int argc, char *const argv[], int *idx, loff_t *off,
Signature · 1 line
2.14.1
author maintainer
#10 lore raw

PATCH v2 8/21 mtd: move all flash categories inside MTD submenu

In reply to Miquel Raynal

There is no reason to have NAND, SPI flashes and UBI sections outside of the MTD submenu in Kconfig.

---
 drivers/mtd/Kconfig | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/mtd/Kconfig +2 -2
index 19579801d2..d21b0920dc 100644
@@ -40,10 +40,10 @@ config FLASH_PIC32
 	  This enables access to Microchip PIC32 internal non-CFI flash
 	  chips through PIC32 Non-Volatile-Memory Controller.
 
-endmenu
-
 source "drivers/mtd/nand/Kconfig"
 
 source "drivers/mtd/spi/Kconfig"
 
 source "drivers/mtd/ubi/Kconfig"
+
+endmenu
Signature · 1 line
2.14.1
author maintainer
#11 lore raw

PATCH v2 9/21 mtd: move NAND fiels into a raw/ subdirectory

In reply to Miquel Raynal

NAND flavors, like serial and parallel, have a lot in common and would benefit to share code. Let's move raw (parallel) NAND specific code in a raw/ subdirectory, to ease the addition of a core file in nand/ and the introduction of a spi/ subdirectory specific to SPI NANDs.

---
 drivers/mtd/Makefile                          |   2 +
 drivers/mtd/nand/Kconfig                      | 240 +-------------------------
 drivers/mtd/nand/Makefile                     |  79 +--------
 drivers/mtd/nand/raw/Kconfig                  | 239 +++++++++++++++++++++++++
 drivers/mtd/nand/raw/Makefile                 |  78 +++++++++
 drivers/mtd/nand/{ => raw}/am335x_spl_bch.c   |   0
 drivers/mtd/nand/{ => raw}/arasan_nfc.c       |   0
 drivers/mtd/nand/{ => raw}/atmel_nand.c       |   0
 drivers/mtd/nand/{ => raw}/atmel_nand_ecc.h   |   0
 drivers/mtd/nand/{ => raw}/davinci_nand.c     |   0
 drivers/mtd/nand/{ => raw}/denali.c           |   0
 drivers/mtd/nand/{ => raw}/denali.h           |   0
 drivers/mtd/nand/{ => raw}/denali_dt.c        |   0
 drivers/mtd/nand/{ => raw}/denali_spl.c       |   0
 drivers/mtd/nand/{ => raw}/fsl_elbc_nand.c    |   0
 drivers/mtd/nand/{ => raw}/fsl_elbc_spl.c     |   0
 drivers/mtd/nand/{ => raw}/fsl_ifc_nand.c     |   0
 drivers/mtd/nand/{ => raw}/fsl_ifc_spl.c      |   0
 drivers/mtd/nand/{ => raw}/fsl_upm.c          |   0
 drivers/mtd/nand/{ => raw}/fsmc_nand.c        |   0
 drivers/mtd/nand/{ => raw}/kb9202_nand.c      |   0
 drivers/mtd/nand/{ => raw}/kirkwood_nand.c    |   0
 drivers/mtd/nand/{ => raw}/kmeter1_nand.c     |   0
 drivers/mtd/nand/{ => raw}/lpc32xx_nand_mlc.c |   0
 drivers/mtd/nand/{ => raw}/lpc32xx_nand_slc.c |   0
 drivers/mtd/nand/{ => raw}/mxc_nand.c         |   0
 drivers/mtd/nand/{ => raw}/mxc_nand.h         |   0
 drivers/mtd/nand/{ => raw}/mxc_nand_spl.c     |   0
 drivers/mtd/nand/{ => raw}/mxs_nand.c         |   0
 drivers/mtd/nand/{ => raw}/mxs_nand_spl.c     |   0
 drivers/mtd/nand/{ => raw}/nand.c             |   0
 drivers/mtd/nand/{ => raw}/nand_base.c        |   0
 drivers/mtd/nand/{ => raw}/nand_bbt.c         |   0
 drivers/mtd/nand/{ => raw}/nand_bch.c         |   0
 drivers/mtd/nand/{ => raw}/nand_ecc.c         |   0
 drivers/mtd/nand/{ => raw}/nand_ids.c         |   0
 drivers/mtd/nand/{ => raw}/nand_plat.c        |   0
 drivers/mtd/nand/{ => raw}/nand_spl_load.c    |   0
 drivers/mtd/nand/{ => raw}/nand_spl_loaders.c |   0
 drivers/mtd/nand/{ => raw}/nand_spl_simple.c  |   0
 drivers/mtd/nand/{ => raw}/nand_timings.c     |   0
 drivers/mtd/nand/{ => raw}/nand_util.c        |   0
 drivers/mtd/nand/{ => raw}/ndfc.c             |   0
 drivers/mtd/nand/{ => raw}/omap_elm.c         |   0
 drivers/mtd/nand/{ => raw}/omap_gpmc.c        |   0
 drivers/mtd/nand/{ => raw}/pxa3xx_nand.c      |   0
 drivers/mtd/nand/{ => raw}/pxa3xx_nand.h      |   0
 drivers/mtd/nand/{ => raw}/sunxi_nand.c       |   0
 drivers/mtd/nand/{ => raw}/sunxi_nand_spl.c   |   0
 drivers/mtd/nand/{ => raw}/tegra_nand.c       |   0
 drivers/mtd/nand/{ => raw}/tegra_nand.h       |   0
 drivers/mtd/nand/{ => raw}/vf610_nfc.c        |   0
 drivers/mtd/nand/{ => raw}/zynq_nand.c        |   0
 53 files changed, 322 insertions(+), 316 deletions(-)
 create mode 100644 drivers/mtd/nand/raw/Kconfig
 create mode 100644 drivers/mtd/nand/raw/Makefile
 rename drivers/mtd/nand/{ => raw}/am335x_spl_bch.c (100%)
 rename drivers/mtd/nand/{ => raw}/arasan_nfc.c (100%)
 rename drivers/mtd/nand/{ => raw}/atmel_nand.c (100%)
 rename drivers/mtd/nand/{ => raw}/atmel_nand_ecc.h (100%)
 rename drivers/mtd/nand/{ => raw}/davinci_nand.c (100%)
 rename drivers/mtd/nand/{ => raw}/denali.c (100%)
 rename drivers/mtd/nand/{ => raw}/denali.h (100%)
 rename drivers/mtd/nand/{ => raw}/denali_dt.c (100%)
 rename drivers/mtd/nand/{ => raw}/denali_spl.c (100%)
 rename drivers/mtd/nand/{ => raw}/fsl_elbc_nand.c (100%)
 rename drivers/mtd/nand/{ => raw}/fsl_elbc_spl.c (100%)
 rename drivers/mtd/nand/{ => raw}/fsl_ifc_nand.c (100%)
 rename drivers/mtd/nand/{ => raw}/fsl_ifc_spl.c (100%)
 rename drivers/mtd/nand/{ => raw}/fsl_upm.c (100%)
 rename drivers/mtd/nand/{ => raw}/fsmc_nand.c (100%)
 rename drivers/mtd/nand/{ => raw}/kb9202_nand.c (100%)
 rename drivers/mtd/nand/{ => raw}/kirkwood_nand.c (100%)
 rename drivers/mtd/nand/{ => raw}/kmeter1_nand.c (100%)
 rename drivers/mtd/nand/{ => raw}/lpc32xx_nand_mlc.c (100%)
 rename drivers/mtd/nand/{ => raw}/lpc32xx_nand_slc.c (100%)
 rename drivers/mtd/nand/{ => raw}/mxc_nand.c (100%)
 rename drivers/mtd/nand/{ => raw}/mxc_nand.h (100%)
 rename drivers/mtd/nand/{ => raw}/mxc_nand_spl.c (100%)
 rename drivers/mtd/nand/{ => raw}/mxs_nand.c (100%)
 rename drivers/mtd/nand/{ => raw}/mxs_nand_spl.c (100%)
 rename drivers/mtd/nand/{ => raw}/nand.c (100%)
 rename drivers/mtd/nand/{ => raw}/nand_base.c (100%)
 rename drivers/mtd/nand/{ => raw}/nand_bbt.c (100%)
 rename drivers/mtd/nand/{ => raw}/nand_bch.c (100%)
 rename drivers/mtd/nand/{ => raw}/nand_ecc.c (100%)
 rename drivers/mtd/nand/{ => raw}/nand_ids.c (100%)
 rename drivers/mtd/nand/{ => raw}/nand_plat.c (100%)
 rename drivers/mtd/nand/{ => raw}/nand_spl_load.c (100%)
 rename drivers/mtd/nand/{ => raw}/nand_spl_loaders.c (100%)
 rename drivers/mtd/nand/{ => raw}/nand_spl_simple.c (100%)
 rename drivers/mtd/nand/{ => raw}/nand_timings.c (100%)
 rename drivers/mtd/nand/{ => raw}/nand_util.c (100%)
 rename drivers/mtd/nand/{ => raw}/ndfc.c (100%)
 rename drivers/mtd/nand/{ => raw}/omap_elm.c (100%)
 rename drivers/mtd/nand/{ => raw}/omap_gpmc.c (100%)
 rename drivers/mtd/nand/{ => raw}/pxa3xx_nand.c (100%)
 rename drivers/mtd/nand/{ => raw}/pxa3xx_nand.h (100%)
 rename drivers/mtd/nand/{ => raw}/sunxi_nand.c (100%)
 rename drivers/mtd/nand/{ => raw}/sunxi_nand_spl.c (100%)
 rename drivers/mtd/nand/{ => raw}/tegra_nand.c (100%)
 rename drivers/mtd/nand/{ => raw}/tegra_nand.h (100%)
 rename drivers/mtd/nand/{ => raw}/vf610_nfc.c (100%)
 rename drivers/mtd/nand/{ => raw}/zynq_nand.c (100%)
drivers/mtd/Makefile +2 -0
index 20c0d0af44..eb0e7264ab 100644
@@ -20,3 +20,5 @@ obj-$(CONFIG_MW_EEPROM) += mw_eeprom.o
 obj-$(CONFIG_FLASH_PIC32) += pic32_flash.o
 obj-$(CONFIG_ST_SMI) += st_smi.o
 obj-$(CONFIG_STM32_FLASH) += stm32_flash.o
+
+obj-y += nand/
drivers/mtd/nand/Kconfig +1 -239

240 lines not on this page · raw message

drivers/mtd/nand/Makefile +2 -77

80 lines not on this page · raw message

drivers/mtd/nand/raw/Kconfig new file +239 -0

239 lines not on this page · raw message

drivers/mtd/nand/raw/Makefile new file +78 -0

78 lines not on this page · raw message

drivers/mtd/nand/raw/am335x_spl_bch.c renamed from drivers/mtd/nand/am335x_spl_bch.c +0 -0
similarity index 100%
rename from drivers/mtd/nand/am335x_spl_bch.c
rename to drivers/mtd/nand/raw/am335x_spl_bch.c
drivers/mtd/nand/raw/arasan_nfc.c renamed from drivers/mtd/nand/arasan_nfc.c +0 -0
similarity index 100%
rename from drivers/mtd/nand/arasan_nfc.c
rename to drivers/mtd/nand/raw/arasan_nfc.c
drivers/mtd/nand/raw/atmel_nand.c renamed from drivers/mtd/nand/atmel_nand.c +0 -0
similarity index 100%
rename from drivers/mtd/nand/atmel_nand.c
rename to drivers/mtd/nand/raw/atmel_nand.c
drivers/mtd/nand/raw/atmel_nand_ecc.h renamed from drivers/mtd/nand/atmel_nand_ecc.h +0 -0
similarity index 100%
rename from drivers/mtd/nand/atmel_nand_ecc.h
rename to drivers/mtd/nand/raw/atmel_nand_ecc.h
drivers/mtd/nand/raw/davinci_nand.c renamed from drivers/mtd/nand/davinci_nand.c +0 -0
similarity index 100%
rename from drivers/mtd/nand/davinci_nand.c
rename to drivers/mtd/nand/raw/davinci_nand.c
drivers/mtd/nand/raw/denali.c renamed from drivers/mtd/nand/denali.c +0 -0
similarity index 100%
rename from drivers/mtd/nand/denali.c
rename to drivers/mtd/nand/raw/denali.c
drivers/mtd/nand/raw/denali.h renamed from drivers/mtd/nand/denali.h +0 -0
similarity index 100%
rename from drivers/mtd/nand/denali.h
rename to drivers/mtd/nand/raw/denali.h
drivers/mtd/nand/raw/denali_dt.c renamed from drivers/mtd/nand/denali_dt.c +0 -0
similarity index 100%
rename from drivers/mtd/nand/denali_dt.c
rename to drivers/mtd/nand/raw/denali_dt.c
drivers/mtd/nand/raw/denali_spl.c renamed from drivers/mtd/nand/denali_spl.c +0 -0
similarity index 100%
rename from drivers/mtd/nand/denali_spl.c
rename to drivers/mtd/nand/raw/denali_spl.c
drivers/mtd/nand/raw/fsl_elbc_nand.c renamed from drivers/mtd/nand/fsl_elbc_nand.c +0 -0
similarity index 100%
rename from drivers/mtd/nand/fsl_elbc_nand.c
rename to drivers/mtd/nand/raw/fsl_elbc_nand.c
drivers/mtd/nand/raw/fsl_elbc_spl.c renamed from drivers/mtd/nand/fsl_elbc_spl.c +0 -0
similarity index 100%
rename from drivers/mtd/nand/fsl_elbc_spl.c
rename to drivers/mtd/nand/raw/fsl_elbc_spl.c
drivers/mtd/nand/raw/fsl_ifc_nand.c renamed from drivers/mtd/nand/fsl_ifc_nand.c +0 -0
similarity index 100%
rename from drivers/mtd/nand/fsl_ifc_nand.c
rename to drivers/mtd/nand/raw/fsl_ifc_nand.c
drivers/mtd/nand/raw/fsl_ifc_spl.c renamed from drivers/mtd/nand/fsl_ifc_spl.c +0 -0
similarity index 100%
rename from drivers/mtd/nand/fsl_ifc_spl.c
rename to drivers/mtd/nand/raw/fsl_ifc_spl.c
drivers/mtd/nand/raw/fsl_upm.c renamed from drivers/mtd/nand/fsl_upm.c +0 -0
similarity index 100%
rename from drivers/mtd/nand/fsl_upm.c
rename to drivers/mtd/nand/raw/fsl_upm.c
drivers/mtd/nand/raw/fsmc_nand.c renamed from drivers/mtd/nand/fsmc_nand.c +0 -0
similarity index 100%
rename from drivers/mtd/nand/fsmc_nand.c
rename to drivers/mtd/nand/raw/fsmc_nand.c
drivers/mtd/nand/raw/kb9202_nand.c renamed from drivers/mtd/nand/kb9202_nand.c +0 -0
similarity index 100%
rename from drivers/mtd/nand/kb9202_nand.c
rename to drivers/mtd/nand/raw/kb9202_nand.c
drivers/mtd/nand/raw/kirkwood_nand.c renamed from drivers/mtd/nand/kirkwood_nand.c +0 -0
similarity index 100%
rename from drivers/mtd/nand/kirkwood_nand.c
rename to drivers/mtd/nand/raw/kirkwood_nand.c
drivers/mtd/nand/raw/kmeter1_nand.c renamed from drivers/mtd/nand/kmeter1_nand.c +0 -0
similarity index 100%
rename from drivers/mtd/nand/kmeter1_nand.c
rename to drivers/mtd/nand/raw/kmeter1_nand.c
drivers/mtd/nand/raw/lpc32xx_nand_mlc.c renamed from drivers/mtd/nand/lpc32xx_nand_mlc.c +0 -0
similarity index 100%
rename from drivers/mtd/nand/lpc32xx_nand_mlc.c
rename to drivers/mtd/nand/raw/lpc32xx_nand_mlc.c
drivers/mtd/nand/raw/lpc32xx_nand_slc.c renamed from drivers/mtd/nand/lpc32xx_nand_slc.c +0 -0
similarity index 100%
rename from drivers/mtd/nand/lpc32xx_nand_slc.c
rename to drivers/mtd/nand/raw/lpc32xx_nand_slc.c
drivers/mtd/nand/raw/mxc_nand.c renamed from drivers/mtd/nand/mxc_nand.c +0 -0
similarity index 100%
rename from drivers/mtd/nand/mxc_nand.c
rename to drivers/mtd/nand/raw/mxc_nand.c
drivers/mtd/nand/raw/mxc_nand.h renamed from drivers/mtd/nand/mxc_nand.h +0 -0
similarity index 100%
rename from drivers/mtd/nand/mxc_nand.h
rename to drivers/mtd/nand/raw/mxc_nand.h
drivers/mtd/nand/raw/mxc_nand_spl.c renamed from drivers/mtd/nand/mxc_nand_spl.c +0 -0
similarity index 100%
rename from drivers/mtd/nand/mxc_nand_spl.c
rename to drivers/mtd/nand/raw/mxc_nand_spl.c
drivers/mtd/nand/raw/mxs_nand.c renamed from drivers/mtd/nand/mxs_nand.c +0 -0
similarity index 100%
rename from drivers/mtd/nand/mxs_nand.c
rename to drivers/mtd/nand/raw/mxs_nand.c
drivers/mtd/nand/raw/mxs_nand_spl.c renamed from drivers/mtd/nand/mxs_nand_spl.c +0 -0
similarity index 100%
rename from drivers/mtd/nand/mxs_nand_spl.c
rename to drivers/mtd/nand/raw/mxs_nand_spl.c
drivers/mtd/nand/raw/nand.c renamed from drivers/mtd/nand/nand.c +0 -0
similarity index 100%
rename from drivers/mtd/nand/nand.c
rename to drivers/mtd/nand/raw/nand.c
drivers/mtd/nand/raw/nand_base.c renamed from drivers/mtd/nand/nand_base.c +0 -0
similarity index 100%
rename from drivers/mtd/nand/nand_base.c
rename to drivers/mtd/nand/raw/nand_base.c
drivers/mtd/nand/raw/nand_bbt.c renamed from drivers/mtd/nand/nand_bbt.c +0 -0
similarity index 100%
rename from drivers/mtd/nand/nand_bbt.c
rename to drivers/mtd/nand/raw/nand_bbt.c
drivers/mtd/nand/raw/nand_bch.c renamed from drivers/mtd/nand/nand_bch.c +0 -0
similarity index 100%
rename from drivers/mtd/nand/nand_bch.c
rename to drivers/mtd/nand/raw/nand_bch.c
drivers/mtd/nand/raw/nand_ecc.c renamed from drivers/mtd/nand/nand_ecc.c +0 -0
similarity index 100%
rename from drivers/mtd/nand/nand_ecc.c
rename to drivers/mtd/nand/raw/nand_ecc.c
drivers/mtd/nand/raw/nand_ids.c renamed from drivers/mtd/nand/nand_ids.c +0 -0
similarity index 100%
rename from drivers/mtd/nand/nand_ids.c
rename to drivers/mtd/nand/raw/nand_ids.c
drivers/mtd/nand/raw/nand_plat.c renamed from drivers/mtd/nand/nand_plat.c +0 -0
similarity index 100%
rename from drivers/mtd/nand/nand_plat.c
rename to drivers/mtd/nand/raw/nand_plat.c
drivers/mtd/nand/raw/nand_spl_load.c renamed from drivers/mtd/nand/nand_spl_load.c +0 -0
similarity index 100%
rename from drivers/mtd/nand/nand_spl_load.c
rename to drivers/mtd/nand/raw/nand_spl_load.c
drivers/mtd/nand/raw/nand_spl_loaders.c renamed from drivers/mtd/nand/nand_spl_loaders.c +0 -0
similarity index 100%
rename from drivers/mtd/nand/nand_spl_loaders.c
rename to drivers/mtd/nand/raw/nand_spl_loaders.c
drivers/mtd/nand/raw/nand_spl_simple.c renamed from drivers/mtd/nand/nand_spl_simple.c +0 -0
similarity index 100%
rename from drivers/mtd/nand/nand_spl_simple.c
rename to drivers/mtd/nand/raw/nand_spl_simple.c
drivers/mtd/nand/raw/nand_timings.c renamed from drivers/mtd/nand/nand_timings.c +0 -0
similarity index 100%
rename from drivers/mtd/nand/nand_timings.c
rename to drivers/mtd/nand/raw/nand_timings.c
drivers/mtd/nand/raw/nand_util.c renamed from drivers/mtd/nand/nand_util.c +0 -0
similarity index 100%
rename from drivers/mtd/nand/nand_util.c
rename to drivers/mtd/nand/raw/nand_util.c
drivers/mtd/nand/raw/ndfc.c renamed from drivers/mtd/nand/ndfc.c +0 -0
similarity index 100%
rename from drivers/mtd/nand/ndfc.c
rename to drivers/mtd/nand/raw/ndfc.c
drivers/mtd/nand/raw/omap_elm.c renamed from drivers/mtd/nand/omap_elm.c +0 -0
similarity index 100%
rename from drivers/mtd/nand/omap_elm.c
rename to drivers/mtd/nand/raw/omap_elm.c
drivers/mtd/nand/raw/omap_gpmc.c renamed from drivers/mtd/nand/omap_gpmc.c +0 -0
similarity index 100%
rename from drivers/mtd/nand/omap_gpmc.c
rename to drivers/mtd/nand/raw/omap_gpmc.c
drivers/mtd/nand/raw/pxa3xx_nand.c renamed from drivers/mtd/nand/pxa3xx_nand.c +0 -0
similarity index 100%
rename from drivers/mtd/nand/pxa3xx_nand.c
rename to drivers/mtd/nand/raw/pxa3xx_nand.c
drivers/mtd/nand/raw/pxa3xx_nand.h renamed from drivers/mtd/nand/pxa3xx_nand.h +0 -0
similarity index 100%
rename from drivers/mtd/nand/pxa3xx_nand.h
rename to drivers/mtd/nand/raw/pxa3xx_nand.h
drivers/mtd/nand/raw/sunxi_nand.c renamed from drivers/mtd/nand/sunxi_nand.c +0 -0
similarity index 100%
rename from drivers/mtd/nand/sunxi_nand.c
rename to drivers/mtd/nand/raw/sunxi_nand.c
drivers/mtd/nand/raw/sunxi_nand_spl.c renamed from drivers/mtd/nand/sunxi_nand_spl.c +0 -0
similarity index 100%
rename from drivers/mtd/nand/sunxi_nand_spl.c
rename to drivers/mtd/nand/raw/sunxi_nand_spl.c
drivers/mtd/nand/raw/tegra_nand.c renamed from drivers/mtd/nand/tegra_nand.c +0 -0
similarity index 100%
rename from drivers/mtd/nand/tegra_nand.c
rename to drivers/mtd/nand/raw/tegra_nand.c
drivers/mtd/nand/raw/tegra_nand.h renamed from drivers/mtd/nand/tegra_nand.h +0 -0
similarity index 100%
rename from drivers/mtd/nand/tegra_nand.h
rename to drivers/mtd/nand/raw/tegra_nand.h
drivers/mtd/nand/raw/vf610_nfc.c renamed from drivers/mtd/nand/vf610_nfc.c +0 -0
similarity index 100%
rename from drivers/mtd/nand/vf610_nfc.c
rename to drivers/mtd/nand/raw/vf610_nfc.c
drivers/mtd/nand/raw/zynq_nand.c renamed from drivers/mtd/nand/zynq_nand.c +0 -0
similarity index 100%
rename from drivers/mtd/nand/zynq_nand.c
rename to drivers/mtd/nand/raw/zynq_nand.c
Signature · 1 line
2.14.1
#12 lore raw

PATCH v2 9/21 mtd: move NAND fiels into a raw/ subdirectory

In your subject: s/fiels/files/

Quoted 6 lines · On Wed, 11 Jul 2018 17:25:17 +0200 Miquel Raynal <[email protected]>…

NAND flavors, like serial and parallel, have a lot in common and would benefit to share code. Let's move raw (parallel) NAND specific code in a raw/ subdirectory, to ease the addition of a core file in nand/ and the introduction of a spi/ subdirectory specific to SPI NANDs.

author maintainer
#13 lore raw

PATCH v2 10/21 mtd: rename nand into rawnand in Kconfig prompt

In reply to Miquel Raynal

Sync the Kconfig raw NAND entry title with the code architecture.

---
 drivers/mtd/nand/raw/Kconfig | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/mtd/nand/raw/Kconfig +1 -1
index a820af61ce..6ef82cab88 100644
@@ -1,6 +1,6 @@
 
 menuconfig NAND
-	bool "NAND Device Support"
+	bool "Raw NAND Device Support"
 if NAND
 
 config SYS_NAND_SELF_INIT
Signature · 1 line
2.14.1
author maintainer
#14 lore raw

PATCH v2 11/21 mtd: nand: Add core infrastructure to deal with NAND devices

In reply to Miquel Raynal

From: Boris Brezillon <[email protected]>

Add an intermediate layer to abstract NAND device interface so that some logic can be shared between SPI NANDs, parallel/raw NANDs, OneNANDs, ...

---
 drivers/mtd/nand/Kconfig  |   3 +
 drivers/mtd/nand/Makefile |   3 +
 drivers/mtd/nand/bbt.c    | 132 +++++++++
 drivers/mtd/nand/core.c   | 243 +++++++++++++++
 include/linux/mtd/nand.h  | 731 ++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 1112 insertions(+)
 create mode 100644 drivers/mtd/nand/bbt.c
 create mode 100644 drivers/mtd/nand/core.c
 create mode 100644 include/linux/mtd/nand.h
drivers/mtd/nand/Kconfig +3 -0
index 6d53734718..1c1a1f487e 100644
@@ -1 +1,4 @@
+config MTD_NAND_CORE
+	tristate
+
 source "drivers/mtd/nand/raw/Kconfig"
drivers/mtd/nand/Makefile +3 -0
index d1c3f93047..69c80ea252 100644
@@ -1,3 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0
 
+nandcore-objs := core.o bbt.o
+obj-$(CONFIG_MTD_NAND_CORE) += nandcore.o
+
 obj-$(CONFIG_MTD_NAND) += raw/
drivers/mtd/nand/bbt.c new file +132 -0

132 lines not on this page · raw message

drivers/mtd/nand/core.c new file +243 -0

243 lines not on this page · raw message

include/linux/mtd/nand.h new file +731 -0

731 lines not on this page · raw message

Signature · 1 line
2.14.1
author maintainer
#15 lore raw

PATCH v2 12/21 mtd: nand: Pass mode information to nand_page_io_req

In reply to Miquel Raynal

From: Boris Brezillon <[email protected]>

The NAND sub-layers are likely to need the MTD_OPS_XXX mode information in order to decide if they should enable/disable ECC or how they should place the OOB bytes in the provided OOB buffer.

Add a field to nand_page_io_req to pass this information.

---
 include/linux/mtd/nand.h | 3 +++
 1 file changed, 3 insertions(+)
include/linux/mtd/nand.h +3 -0
index ada7af4a41..13e8dd1103 100644
@@ -86,6 +86,7 @@ struct nand_pos {
  * @ooboffs: the OOB offset within the page
  * @ooblen: the number of OOB bytes to read from/write to this page
  * @oobbuf: buffer to store OOB data in or get OOB data from
+ * @mode: one of the %MTD_OPS_XXX mode
  *
  * This object is used to pass per-page I/O requests to NAND sub-layers. This
  * way all useful information are already formatted in a useful way and
@@ -106,6 +107,7 @@ struct nand_page_io_req {
 		const void *out;
 		void *in;
 	} oobbuf;
+	int mode;
 };
 
 /**
@@ -599,6 +601,7 @@ static inline void nanddev_io_iter_init(struct nand_device *nand,
 {
 	struct mtd_info *mtd = nanddev_to_mtd(nand);
 
+	iter->req.mode = req->mode;
 	iter->req.dataoffs = nanddev_offs_to_pos(nand, offs, &iter->req.pos);
 	iter->req.ooboffs = req->ooboffs;
 	iter->oobbytes_per_page = mtd_oobavail(mtd, req);
Signature · 1 line
2.14.1
author maintainer
#16 lore raw

PATCH v2 13/21 spi: Extend the core to ease integration of SPI memory controllers

In reply to Miquel Raynal

From: Boris Brezillon <[email protected]>

Some controllers are exposing high-level interfaces to access various kind of SPI memories. Unfortunately they do not fit in the current spi_controller model and usually have drivers placed in drivers/mtd/spi-nor which are only supporting SPI NORs and not SPI memories in general.

This is an attempt at defining a SPI memory interface which works for all kinds of SPI memories (NORs, NANDs, SRAMs).

---
 drivers/spi/Kconfig   |   7 +
 drivers/spi/Makefile  |   1 +
 drivers/spi/spi-mem.c | 500 ++++++++++++++++++++++++++++++++++++++++++++++++++
 include/spi-mem.h     | 258 ++++++++++++++++++++++++++
 include/spi.h         |  11 ++
 5 files changed, 777 insertions(+)
 create mode 100644 drivers/spi/spi-mem.c
 create mode 100644 include/spi-mem.h
drivers/spi/Kconfig +7 -0
index 235a8c7d73..0ee371b2d9 100644
@@ -15,6 +15,13 @@ config DM_SPI
 
 if DM_SPI
 
+config SPI_MEM
+	bool "SPI memory extension"
+	help
+	  Enable this option if you want to enable the SPI memory extension.
+	  This extension is meant to simplify interaction with SPI memories
+	  by providing an high-level interface to send memory-like commands.
+
 config ALTERA_SPI
 	bool "Altera SPI driver"
 	help
drivers/spi/Makefile +1 -0
index 4b6000fd9a..982529a0e6 100644
@@ -10,6 +10,7 @@ ifdef CONFIG_DM_SPI
 obj-y += spi-uclass.o
 obj-$(CONFIG_SANDBOX) += spi-emul-uclass.o
 obj-$(CONFIG_SOFT_SPI) += soft_spi.o
+obj-$(CONFIG_SPI_MEM) += spi-mem.o
 else
 obj-y += spi.o
 obj-$(CONFIG_SOFT_SPI) += soft_spi_legacy.o
drivers/spi/spi-mem.c new file +500 -0

500 lines not on this page · raw message

include/spi-mem.h new file +258 -0

258 lines not on this page · raw message

include/spi.h +11 -0
index f5bac8d002..12587ffeb0 100644
@@ -10,6 +10,8 @@
 #ifndef _SPI_H_
 #define _SPI_H_
 
+#include <common.h>
+
 /* SPI mode flags */
 #define SPI_CPHA	BIT(0)			/* clock phase */
 #define SPI_CPOL	BIT(1)			/* clock polarity */
@@ -403,6 +405,15 @@ struct dm_spi_ops {
 	int (*xfer)(struct udevice *dev, unsigned int bitlen, const void *dout,
 		    void *din, unsigned long flags);
 
+	/**
+	 * Optimized handlers for SPI memory-like operations.
+	 *
+	 * 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.
+	 */
+	const struct spi_controller_mem_ops *mem_ops;
+
 	/**
 	 * Set transfer speed.
 	 * This sets a new speed to be applied for next spi_xfer().
Signature · 1 line
2.14.1
#17 lore raw

PATCH v2 13/21 spi: Extend the core to ease integration of SPI memory controllers

Hi Miquel,

just a quick comment below (something I stumbled upon while testing).

Quoted 432 lines · Miquel Raynal

From: Boris Brezillon <[email protected]>

Some controllers are exposing high-level interfaces to access various kind of SPI memories. Unfortunately they do not fit in the current spi_controller model and usually have drivers placed in drivers/mtd/spi-nor which are only supporting SPI NORs and not SPI memories in general.

This is an attempt at defining a SPI memory interface which works for all kinds of SPI memories (NORs, NANDs, SRAMs).

---
  drivers/spi/Kconfig   |   7 +
  drivers/spi/Makefile  |   1 +
  drivers/spi/spi-mem.c | 500 ++++++++++++++++++++++++++++++++++++++++++++++++++
  include/spi-mem.h     | 258 ++++++++++++++++++++++++++
  include/spi.h         |  11 ++
  5 files changed, 777 insertions(+)

create mode 100644 drivers/spi/spi-mem.c
create mode 100644 include/spi-mem.h

drivers/spi/Kconfig +7 -0
index 235a8c7d73..0ee371b2d9 100644
@@ -15,6 +15,13 @@ config DM_SPI
 
  if DM_SPI
 
+config SPI_MEM
+	bool "SPI memory extension"
+	help
+	  Enable this option if you want to enable the SPI memory extension.
+	  This extension is meant to simplify interaction with SPI memories
+	  by providing an high-level interface to send memory-like commands.
+
  config ALTERA_SPI
  	bool "Altera SPI driver"
  	help
drivers/spi/Makefile +1 -0
index 4b6000fd9a..982529a0e6 100644
@@ -10,6 +10,7 @@ ifdef CONFIG_DM_SPI
  obj-y += spi-uclass.o
  obj-$(CONFIG_SANDBOX) += spi-emul-uclass.o
  obj-$(CONFIG_SOFT_SPI) += soft_spi.o
+obj-$(CONFIG_SPI_MEM) += spi-mem.o
  else
  obj-y += spi.o
  obj-$(CONFIG_SOFT_SPI) += soft_spi_legacy.o
drivers/spi/spi-mem.c new file +373 -0
new file mode 100644
index 0000000000..1aabe56819
@@ -0,0 +1,500 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018 Exceet Electronics GmbH
+ * Copyright (C) 2018 Bootlin
+ *
+ * Author: Boris Brezillon <[email protected]>
+ */
+
+#ifndef __UBOOT__
+#include <linux/dmaengine.h>
+#include <linux/pm_runtime.h>
+#include "internals.h"
+#else
+#include <spi.h>
+#include <spi-mem.h>
+#endif
+
+#ifndef __UBOOT__
+/**
+ * spi_controller_dma_map_mem_op_data() - DMA-map the buffer attached to a
+ *					  memory operation
+ * @ctlr: the SPI controller requesting this dma_map()
+ * @op: the memory operation containing the buffer to map
+ * @sgt: a pointer to a non-initialized sg_table that will be filled by this
+ *	 function
+ *
+ * Some controllers might want to do DMA on the data buffer embedded in @op.
+ * This helper prepares everything for you and provides a ready-to-use
+ * sg_table. This function is not intended to be called from spi drivers.
+ * Only SPI controller drivers should use it.
+ * Note that the caller must ensure the memory region pointed by
+ * op->data.buf.{in,out} is DMA-able before calling this function.
+ *
+ * Return: 0 in case of success, a negative error code otherwise.
+ */
+int spi_controller_dma_map_mem_op_data(struct spi_controller *ctlr,
+				       const struct spi_mem_op *op,
+				       struct sg_table *sgt)
+{
+	struct device *dmadev;
+
+	if (!op->data.nbytes)
+		return -EINVAL;
+
+	if (op->data.dir == SPI_MEM_DATA_OUT && ctlr->dma_tx)
+		dmadev = ctlr->dma_tx->device->dev;
+	else if (op->data.dir == SPI_MEM_DATA_IN && ctlr->dma_rx)
+		dmadev = ctlr->dma_rx->device->dev;
+	else
+		dmadev = ctlr->dev.parent;
+
+	if (!dmadev)
+		return -EINVAL;
+
+	return spi_map_buf(ctlr, dmadev, sgt, op->data.buf.in, op->data.nbytes,
+			   op->data.dir == SPI_MEM_DATA_IN ?
+			   DMA_FROM_DEVICE : DMA_TO_DEVICE);
+}
+EXPORT_SYMBOL_GPL(spi_controller_dma_map_mem_op_data);
+
+/**
+ * spi_controller_dma_unmap_mem_op_data() - DMA-unmap the buffer attached to a
+ *					    memory operation
+ * @ctlr: the SPI controller requesting this dma_unmap()
+ * @op: the memory operation containing the buffer to unmap
+ * @sgt: a pointer to an sg_table previously initialized by
+ *	 spi_controller_dma_map_mem_op_data()
+ *
+ * Some controllers might want to do DMA on the data buffer embedded in @op.
+ * This helper prepares things so that the CPU can access the
+ * op->data.buf.{in,out} buffer again.
+ *
+ * This function is not intended to be called from SPI drivers. Only SPI
+ * controller drivers should use it.
+ *
+ * This function should be called after the DMA operation has finished and is
+ * only valid if the previous spi_controller_dma_map_mem_op_data() call
+ * returned 0.
+ *
+ * Return: 0 in case of success, a negative error code otherwise.
+ */
+void spi_controller_dma_unmap_mem_op_data(struct spi_controller *ctlr,
+					  const struct spi_mem_op *op,
+					  struct sg_table *sgt)
+{
+	struct device *dmadev;
+
+	if (!op->data.nbytes)
+		return;
+
+	if (op->data.dir == SPI_MEM_DATA_OUT && ctlr->dma_tx)
+		dmadev = ctlr->dma_tx->device->dev;
+	else if (op->data.dir == SPI_MEM_DATA_IN && ctlr->dma_rx)
+		dmadev = ctlr->dma_rx->device->dev;
+	else
+		dmadev = ctlr->dev.parent;
+
+	spi_unmap_buf(ctlr, dmadev, sgt,
+		      op->data.dir == SPI_MEM_DATA_IN ?
+		      DMA_FROM_DEVICE : DMA_TO_DEVICE);
+}
+EXPORT_SYMBOL_GPL(spi_controller_dma_unmap_mem_op_data);
+#endif /* __UBOOT__ */
+
+static int spi_check_buswidth_req(struct spi_slave *slave, u8 buswidth, bool tx)
+{
+	u32 mode = slave->mode;
+
+	switch (buswidth) {
+	case 1:
+		return 0;
+
+	case 2:
+		if ((tx && (mode & (SPI_TX_DUAL | SPI_TX_QUAD))) ||
+		    (!tx && (mode & (SPI_RX_DUAL | SPI_RX_QUAD))))
+			return 0;
+
+		break;
+
+	case 4:
+		if ((tx && (mode & SPI_TX_QUAD)) ||
+		    (!tx && (mode & SPI_RX_QUAD)))
+			return 0;
+
+		break;
+
+	default:
+		break;
+	}
+
+	return -ENOTSUPP;
+}
+
+bool spi_mem_default_supports_op(struct spi_slave *slave,
+				 const struct spi_mem_op *op)
+{
+	if (spi_check_buswidth_req(slave, op->cmd.buswidth, true))
+		return false;
+
+	if (op->addr.nbytes &&
+	    spi_check_buswidth_req(slave, op->addr.buswidth, true))
+		return false;
+
+	if (op->dummy.nbytes &&
+	    spi_check_buswidth_req(slave, op->dummy.buswidth, true))
+		return false;
+
+	if (op->data.nbytes &&
+	    spi_check_buswidth_req(slave, op->data.buswidth,
+				   op->data.dir == SPI_MEM_DATA_OUT))
+		return false;
+
+	return true;
+}
+EXPORT_SYMBOL_GPL(spi_mem_default_supports_op);
+
+/**
+ * spi_mem_supports_op() - Check if a memory device and the controller it is
+ *			   connected to support a specific memory operation
+ * @slave: the SPI device
+ * @op: the memory operation to check
+ *
+ * Some controllers are only supporting Single or Dual IOs, others might only
+ * support specific opcodes, or it can even be that the controller and device
+ * both support Quad IOs but the hardware prevents you from using it because
+ * only 2 IO lines are connected.
+ *
+ * This function checks whether a specific operation is supported.
+ *
+ * Return: true if @op is supported, false otherwise.
+ */
+bool spi_mem_supports_op(struct spi_slave *slave,
+			 const struct spi_mem_op *op)
+{
+	struct udevice *bus = slave->dev->parent;
+	struct dm_spi_ops *ops = spi_get_ops(bus);
+
+	if (ops->mem_ops && ops->mem_ops->supports_op)
+		return ops->mem_ops->supports_op(slave, op);
+
+	return spi_mem_default_supports_op(slave, op);
+}
+EXPORT_SYMBOL_GPL(spi_mem_supports_op);
+
+/**
+ * spi_mem_exec_op() - Execute a memory operation
+ * @slave: the SPI device
+ * @op: the memory operation to execute
+ *
+ * Executes a memory operation.
+ *
+ * This function first checks that @op is supported and then tries to execute
+ * it.
+ *
+ * Return: 0 in case of success, a negative error code otherwise.
+ */
+int spi_mem_exec_op(struct spi_slave *slave, const struct spi_mem_op *op)
+{
+	bool rx_data = op->data.nbytes && (op->data.dir == SPI_MEM_DATA_IN);
+	bool tx_data = op->data.nbytes && (op->data.dir == SPI_MEM_DATA_OUT);
+	struct udevice *bus = slave->dev->parent;
+	struct dm_spi_ops *ops = spi_get_ops(bus);
+	unsigned int xfer_len, pos = 0;
+	u8 *tx_buf, *rx_buf = NULL;
+	int ret;
+	int i;
+
+	if (!spi_mem_supports_op(slave, op))
+		return -ENOTSUPP;
+
+	if (ops->mem_ops) {
+#ifndef __UBOOT__
+		/*
+		 * Flush the message queue before executing our SPI memory
+		 * operation to prevent preemption of regular SPI transfers.
+		 */
+		spi_flush_queue(ctlr);
+
+		if (ctlr->auto_runtime_pm) {
+			ret = pm_runtime_get_sync(ctlr->dev.parent);
+			if (ret < 0) {
+				dev_err(&ctlr->dev,
+					"Failed to power device: %d\n",
+					ret);
+				return ret;
+			}
+		}
+
+		mutex_lock(&ctlr->bus_lock_mutex);
+		mutex_lock(&ctlr->io_mutex);
+#endif
+		ret = ops->mem_ops->exec_op(slave, op);
+#ifndef __UBOOT__
+		mutex_unlock(&ctlr->io_mutex);
+		mutex_unlock(&ctlr->bus_lock_mutex);
+
+		if (ctlr->auto_runtime_pm)
+			pm_runtime_put(ctlr->dev.parent);
+#endif
+
+		/*
+		 * Some controllers only optimize specific paths (typically the
+		 * read path) and expect the core to use the regular SPI
+		 * interface in other cases.
+		 */
+		if (!ret || ret != -ENOTSUPP)
+			return ret;
+	}
+
+#ifndef __UBOOT__
+	tmpbufsize = sizeof(op->cmd.opcode) + op->addr.nbytes +
+		     op->dummy.nbytes;
+
+	/*
+	 * Allocate a buffer to transmit the CMD, ADDR cycles with kmalloc() so
+	 * we're guaranteed that this buffer is DMA-able, as required by the
+	 * SPI layer.
+	 */
+	tmpbuf = kzalloc(tmpbufsize, GFP_KERNEL | GFP_DMA);
+	if (!tmpbuf)
+		return -ENOMEM;
+
+	spi_message_init(&msg);
+
+	tmpbuf[0] = op->cmd.opcode;
+	xfers[xferpos].tx_buf = tmpbuf;
+	xfers[xferpos].len = sizeof(op->cmd.opcode);
+	xfers[xferpos].tx_nbits = op->cmd.buswidth;
+	spi_message_add_tail(&xfers[xferpos], &msg);
+	xferpos++;
+	totalxferlen++;
+
+	if (op->addr.nbytes) {
+		int i;
+
+		for (i = 0; i < op->addr.nbytes; i++)
+			tmpbuf[i + 1] = op->addr.val >>
+					(8 * (op->addr.nbytes - i - 1));
+
+		xfers[xferpos].tx_buf = tmpbuf + 1;
+		xfers[xferpos].len = op->addr.nbytes;
+		xfers[xferpos].tx_nbits = op->addr.buswidth;
+		spi_message_add_tail(&xfers[xferpos], &msg);
+		xferpos++;
+		totalxferlen += op->addr.nbytes;
+	}
+
+	if (op->dummy.nbytes) {
+		memset(tmpbuf + op->addr.nbytes + 1, 0xff, op->dummy.nbytes);
+		xfers[xferpos].tx_buf = tmpbuf + op->addr.nbytes + 1;
+		xfers[xferpos].len = op->dummy.nbytes;
+		xfers[xferpos].tx_nbits = op->dummy.buswidth;
+		spi_message_add_tail(&xfers[xferpos], &msg);
+		xferpos++;
+		totalxferlen += op->dummy.nbytes;
+	}
+
+	if (op->data.nbytes) {
+		if (op->data.dir == SPI_MEM_DATA_IN) {
+			xfers[xferpos].rx_buf = op->data.buf.in;
+			xfers[xferpos].rx_nbits = op->data.buswidth;
+		} else {
+			xfers[xferpos].tx_buf = op->data.buf.out;
+			xfers[xferpos].tx_nbits = op->data.buswidth;
+		}
+
+		xfers[xferpos].len = op->data.nbytes;
+		spi_message_add_tail(&xfers[xferpos], &msg);
+		xferpos++;
+		totalxferlen += op->data.nbytes;
+	}
+
+	ret = spi_sync(slave, &msg);
+
+	kfree(tmpbuf);
+
+	if (ret)
+		return ret;
+
+	if (msg.actual_length != totalxferlen)
+		return -EIO;
+#else
+
+	/* U-Boot does not support parallel SPI data lanes */
+	if ((op->cmd.buswidth != 1) ||
+	    (op->addr.nbytes && op->addr.buswidth != 1) ||
+	    (op->dummy.nbytes && op->dummy.buswidth != 1) ||
+	    (op->data.nbytes && op->data.buswidth != 1)) {
+		printf("Dual/Quad raw SPI transfers not supported\n");
+		return -ENOTSUPP;
+	}
+
+	xfer_len = sizeof(op->cmd.opcode) + op->addr.nbytes +
+		   op->dummy.nbytes + op->data.nbytes;
+
+	/*
+	 * Allocate a buffer to transmit the CMD, ADDR cycles with kmalloc() so
+	 * we're guaranteed that this buffer is DMA-able, as required by the
+	 * SPI layer.
+	 */
+	tx_buf = kzalloc(xfer_len, GFP_KERNEL);
+	if (!tx_buf)
+		return -ENOMEM;
+
+	if (rx_data) {
+		rx_buf = kzalloc(xfer_len, GFP_KERNEL);
+		if (!rx_buf)
+			return -ENOMEM;
+	}
+
+	ret = spi_claim_bus(slave);
+	if (ret < 0)
+		return ret;
+
+	tx_buf[pos++] = op->cmd.opcode;
+
+	if (op->addr.nbytes) {
+		for (i = 0; i < op->addr.nbytes; i++)
+			tx_buf[pos + i] = op->addr.val >>
+					 (8 * (op->addr.nbytes - i - 1));
+
+		pos += op->addr.nbytes;
+	}
+
+	if (op->dummy.nbytes) {
+		memset(tx_buf + pos, 0xff, op->dummy.nbytes);
+		pos += op->dummy.nbytes;
+	}
+
+	if (tx_data)
+		memcpy(tx_buf + pos, op->data.buf.out, op->data.nbytes);
+
+	ret = spi_xfer(slave, xfer_len * 8, tx_buf, rx_buf,

drivers/spi/spi-mem.c line 383

Quoted 10 lines
drivers/spi/spi-mem.c new file +10 -0
+		       SPI_XFER_BEGIN | SPI_XFER_END);
+	spi_release_bus(slave);
+
+	for (i = 0; i < pos; i++)
+		debug("%02x ", tx_buf[i]);
+	debug("| [%dB %s] ",
+	      tx_data || rx_data ? op->data.nbytes : 0,
+	      tx_data || rx_data ? (tx_data ? "out" : "in") : "-");
+	for (; i < xfer_len; i++)
+		debug("%02x ", rx_buf[i]);
		debug("%02x ", tx_data ? tx_buf[i] : rx_buf[i]);

I won't have much more time today. Will get back to this in ~2 weeks.

Thanks,
Stefan

author maintainer
#18 lore raw

PATCH v2 13/21 spi: Extend the core to ease integration of SPI memory controllers

Hi Stefan,

Quoted 21 lines
Quoted 8 lines
drivers/spi/spi-mem.c new file +8 -0
+		memset(tx_buf + pos, 0xff, op->dummy.nbytes);
+		pos += op->dummy.nbytes;
+	}
+
+	if (tx_data)
+		memcpy(tx_buf + pos, op->data.buf.out, op->data.nbytes);
+
+	ret = spi_xfer(slave, xfer_len * 8, tx_buf, rx_buf,

drivers/spi/spi-mem.c line 383

Quoted 10 lines
drivers/spi/spi-mem.c new file +10 -0
+		       SPI_XFER_BEGIN | SPI_XFER_END);
+	spi_release_bus(slave);
+
+	for (i = 0; i < pos; i++)
+		debug("%02x ", tx_buf[i]);
+	debug("| [%dB %s] ",
+	      tx_data || rx_data ? op->data.nbytes : 0,
+	      tx_data || rx_data ? (tx_data ? "out" : "in") : "-");
+	for (; i < xfer_len; i++)
+		debug("%02x ", rx_buf[i]);  
		debug("%02x ", tx_data ? tx_buf[i] : rx_buf[i]);
Quoted 1 line

I won't have much more time today. Will get back to this in ~2 weeks.

Sure!

Debug line changed.

Thanks,
Miquèl

author maintainer
#19 lore raw

PATCH v2 14/21 mtd: nand: Add core infrastructure to support SPI NANDs

In reply to Miquel Raynal

From: Peter Pan <[email protected]>

Add a SPI NAND framework based on the generic NAND framework and the spi-mem infrastructure.

In its current state, this framework supports the following features:

- single/dual/quad IO modes
- on-die ECC

---
 drivers/mtd/nand/Kconfig      |    2 +
 drivers/mtd/nand/Makefile     |    1 +
 drivers/mtd/nand/spi/Kconfig  |    7 +
 drivers/mtd/nand/spi/Makefile |    4 +
 drivers/mtd/nand/spi/core.c   | 1235 +++++++++++++++++++++++++++++++++++++++++
 include/linux/mtd/spinand.h   |  427 ++++++++++++++
 6 files changed, 1676 insertions(+)
 create mode 100644 drivers/mtd/nand/spi/Kconfig
 create mode 100644 drivers/mtd/nand/spi/Makefile
 create mode 100644 drivers/mtd/nand/spi/core.c
 create mode 100644 include/linux/mtd/spinand.h
drivers/mtd/nand/Kconfig +2 -0
index 1c1a1f487e..78ae04bdcb 100644
@@ -2,3 +2,5 @@ config MTD_NAND_CORE
 	tristate
 
 source "drivers/mtd/nand/raw/Kconfig"
+
+source "drivers/mtd/nand/spi/Kconfig"
drivers/mtd/nand/Makefile +1 -0
index 69c80ea252..cbac19b38a 100644
@@ -4,3 +4,4 @@ nandcore-objs := core.o bbt.o
 obj-$(CONFIG_MTD_NAND_CORE) += nandcore.o
 
 obj-$(CONFIG_MTD_NAND) += raw/
+obj-$(CONFIG_MTD_SPI_NAND) += spi/
drivers/mtd/nand/spi/Kconfig new file +7 -0
new file mode 100644
index 0000000000..2197cb531f
@@ -0,0 +1,7 @@
+menuconfig MTD_SPI_NAND
+	bool "SPI NAND device Support"
+	depends on MTD && DM_SPI
+	select MTD_NAND_CORE
+	select SPI_MEM
+	help
+	  This is the framework for the SPI NAND device drivers.
drivers/mtd/nand/spi/Makefile new file +4 -0
new file mode 100644
index 0000000000..f0c6e69d2e
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0
+
+spinand-objs := core.o
+obj-$(CONFIG_MTD_SPI_NAND) += spinand.o
drivers/mtd/nand/spi/core.c new file +1235 -0

1,235 lines not on this page · raw message

include/linux/mtd/spinand.h new file +427 -0

427 lines not on this page · raw message

Signature · 1 line
2.14.1
author maintainer
#20 lore raw

PATCH v2 15/21 mtd: spinand: Add initial support for Micron MT29F2G01ABAGD

In reply to Miquel Raynal

From: Peter Pan <[email protected]>

Add a basic driver for Micron SPI NANDs. Only one device is supported right now, but the driver will be extended to support more devices afterwards.

---
 drivers/mtd/nand/spi/Makefile |   2 +-
 drivers/mtd/nand/spi/core.c   |  17 ++++++
 drivers/mtd/nand/spi/micron.c | 135 ++++++++++++++++++++++++++++++++++++++++++
 include/linux/mtd/spinand.h   |   3 +
 4 files changed, 156 insertions(+), 1 deletion(-)
 create mode 100644 drivers/mtd/nand/spi/micron.c
drivers/mtd/nand/spi/Makefile +1 -1
index f0c6e69d2e..4eb745abd4 100644
@@ -1,4 +1,4 @@
 # SPDX-License-Identifier: GPL-2.0
 
-spinand-objs := core.o
+spinand-objs := core.o micron.o
 obj-$(CONFIG_MTD_SPI_NAND) += spinand.o
drivers/mtd/nand/spi/core.c +17 -0
index 08f853ae11..36b8b52bc2 100644
@@ -829,8 +829,25 @@ static const struct nand_ops spinand_ops = {
 	.isbad = spinand_isbad,
 };
 
+static const struct spinand_manufacturer *spinand_manufacturers[] = {
+	&micron_spinand_manufacturer,
+};
+
 static int spinand_manufacturer_detect(struct spinand_device *spinand)
 {
+	unsigned int i;
+	int ret;
+
+	for (i = 0; i < ARRAY_SIZE(spinand_manufacturers); i++) {
+		ret = spinand_manufacturers[i]->ops->detect(spinand);
+		if (ret > 0) {
+			spinand->manufacturer = spinand_manufacturers[i];
+			return 0;
+		} else if (ret < 0) {
+			return ret;
+		}
+	}
+
 	return -ENOTSUPP;
 }
 
drivers/mtd/nand/spi/micron.c new file +135 -0

135 lines not on this page · raw message

include/linux/mtd/spinand.h +3 -0
index ad59fc01ef..5302d38de8 100644
@@ -200,6 +200,9 @@ struct spinand_manufacturer {
 	const struct spinand_manufacturer_ops *ops;
 };
 
+/* SPI NAND manufacturers */
+extern const struct spinand_manufacturer micron_spinand_manufacturer;
+
 /**
  * struct spinand_op_variants - SPI NAND operation variants
  * @ops: the list of variants for a given operation
Signature · 1 line
2.14.1
author maintainer
#21 lore raw

PATCH v2 16/21 mtd: spinand: Add initial support for Winbond W25M02GV

In reply to Miquel Raynal

From: Frieder Schrempf <[email protected]>

Add support for the W25M02GV chip.

---
 drivers/mtd/nand/spi/Makefile  |   2 +-
 drivers/mtd/nand/spi/core.c    |   1 +
 drivers/mtd/nand/spi/winbond.c | 143 +++++++++++++++++++++++++++++++++++++++++
 include/linux/mtd/spinand.h    |   1 +
 4 files changed, 146 insertions(+), 1 deletion(-)
 create mode 100644 drivers/mtd/nand/spi/winbond.c
drivers/mtd/nand/spi/Makefile +1 -1
index 4eb745abd4..11ba5de68b 100644
@@ -1,4 +1,4 @@
 # SPDX-License-Identifier: GPL-2.0
 
-spinand-objs := core.o micron.o
+spinand-objs := core.o micron.o winbond.o
 obj-$(CONFIG_MTD_SPI_NAND) += spinand.o
drivers/mtd/nand/spi/core.c +1 -0
index 36b8b52bc2..ef3e6445d8 100644
@@ -831,6 +831,7 @@ static const struct nand_ops spinand_ops = {
 
 static const struct spinand_manufacturer *spinand_manufacturers[] = {
 	&micron_spinand_manufacturer,
+	&winbond_spinand_manufacturer,
 };
 
 static int spinand_manufacturer_detect(struct spinand_device *spinand)
drivers/mtd/nand/spi/winbond.c new file +143 -0

143 lines not on this page · raw message

include/linux/mtd/spinand.h +1 -0
index 5302d38de8..d40a7c8f4e 100644
@@ -202,6 +202,7 @@ struct spinand_manufacturer {
 
 /* SPI NAND manufacturers */
 extern const struct spinand_manufacturer micron_spinand_manufacturer;
+extern const struct spinand_manufacturer winbond_spinand_manufacturer;
 
 /**
  * struct spinand_op_variants - SPI NAND operation variants
Signature · 1 line
2.14.1
author maintainer
#22 lore raw

PATCH v2 17/21 mtd: spinand: Add initial support for the MX35LF1GE4AB chip

In reply to Miquel Raynal

From: Boris Brezillon <[email protected]>

Add minimal support for the MX35LF1GE4AB SPI NAND chip.

---
 drivers/mtd/nand/spi/Makefile   |   2 +-
 drivers/mtd/nand/spi/core.c     |   1 +
 drivers/mtd/nand/spi/macronix.c | 138 ++++++++++++++++++++++++++++++++++++++++
 include/linux/mtd/spinand.h     |   1 +
 4 files changed, 141 insertions(+), 1 deletion(-)
 create mode 100644 drivers/mtd/nand/spi/macronix.c
drivers/mtd/nand/spi/Makefile +1 -1
index 11ba5de68b..a66edd9199 100644
@@ -1,4 +1,4 @@
 # SPDX-License-Identifier: GPL-2.0
 
-spinand-objs := core.o micron.o winbond.o
+spinand-objs := core.o macronix.o micron.o winbond.o
 obj-$(CONFIG_MTD_SPI_NAND) += spinand.o
drivers/mtd/nand/spi/core.c +1 -0
index ef3e6445d8..362d104846 100644
@@ -830,6 +830,7 @@ static const struct nand_ops spinand_ops = {
 };
 
 static const struct spinand_manufacturer *spinand_manufacturers[] = {
+	&macronix_spinand_manufacturer,
 	&micron_spinand_manufacturer,
 	&winbond_spinand_manufacturer,
 };
drivers/mtd/nand/spi/macronix.c new file +138 -0

138 lines not on this page · raw message

include/linux/mtd/spinand.h +1 -0
index d40a7c8f4e..8c9c756179 100644
@@ -201,6 +201,7 @@ struct spinand_manufacturer {
 };
 
 /* SPI NAND manufacturers */
+extern const struct spinand_manufacturer macronix_spinand_manufacturer;
 extern const struct spinand_manufacturer micron_spinand_manufacturer;
 extern const struct spinand_manufacturer winbond_spinand_manufacturer;
 
Signature · 1 line
2.14.1
author maintainer
#23 lore raw

PATCH v2 18/21 mtd: spinand: Add initial support for the MX35LF2GE4AB chip

In reply to Miquel Raynal

Add support for the MX35LF2GE4AB chip, which is similar to its cousin MX35LF1GE4AB, with two planes instead of one.

---
 drivers/mtd/nand/spi/macronix.c | 20 ++++++++++++++------
 1 file changed, 14 insertions(+), 6 deletions(-)
drivers/mtd/nand/spi/macronix.c +14 -6
index dd351dcb6c..662c561e50 100644
@@ -27,13 +27,13 @@ static SPINAND_OP_VARIANTS(update_cache_variants,
 		SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
 		SPINAND_PROG_LOAD(false, 0, NULL, 0));
 
-static int mx35lf1ge4ab_ooblayout_ecc(struct mtd_info *mtd, int section,
+static int mx35lfxge4ab_ooblayout_ecc(struct mtd_info *mtd, int section,
 				      struct mtd_oob_region *region)
 {
 	return -ERANGE;
 }
 
-static int mx35lf1ge4ab_ooblayout_free(struct mtd_info *mtd, int section,
+static int mx35lfxge4ab_ooblayout_free(struct mtd_info *mtd, int section,
 				       struct mtd_oob_region *region)
 {
 	if (section)
@@ -45,9 +45,9 @@ static int mx35lf1ge4ab_ooblayout_free(struct mtd_info *mtd, int section,
 	return 0;
 }
 
-static const struct mtd_ooblayout_ops mx35lf1ge4ab_ooblayout = {
-	.ecc = mx35lf1ge4ab_ooblayout_ecc,
-	.free = mx35lf1ge4ab_ooblayout_free,
+static const struct mtd_ooblayout_ops mx35lfxge4ab_ooblayout = {
+	.ecc = mx35lfxge4ab_ooblayout_ecc,
+	.free = mx35lfxge4ab_ooblayout_free,
 };
 
 static int mx35lf1ge4ab_get_eccsr(struct spinand_device *spinand, u8 *eccsr)
@@ -102,8 +102,16 @@ static const struct spinand_info macronix_spinand_table[] = {
 					      &write_cache_variants,
 					      &update_cache_variants),
 		     SPINAND_HAS_QE_BIT,
-		     SPINAND_ECCINFO(&mx35lf1ge4ab_ooblayout,
+		     SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
 				     mx35lf1ge4ab_ecc_get_status)),
+	SPINAND_INFO("MX35LF2GE4AB", 0x22,
+		     NAND_MEMORG(1, 2048, 64, 64, 2048, 2, 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, NULL)),
 };
 
 static int macronix_spinand_detect(struct spinand_device *spinand)
Signature · 1 line
2.14.1
author maintainer
#24 lore raw

PATCH v2 19/21 mtd: uclass: add probe function

In reply to Miquel Raynal

The user might want to trigger the probe of any MTD device, export these functions so they can be called from a command source file.

---
 drivers/mtd/mtd-uclass.c | 9 +++++++++
 include/linux/mtd/mtd.h  | 3 +++
 2 files changed, 12 insertions(+)
drivers/mtd/mtd-uclass.c +9 -0
index 7b7c48ec5a..1b6533829c 100644
@@ -6,6 +6,7 @@
 
 #include <common.h>
 #include <dm.h>
+#include <dm/device-internal.h>
 #include <errno.h>
 #include <mtd.h>
 
@@ -14,6 +15,14 @@
  * The uclass private is pointed to mtd_info.
  */
 
+int mtd_probe(struct udevice *dev)
+{
+	if (device_active(dev))
+		return 0;
+
+	return device_probe(dev);
+}
+
 UCLASS_DRIVER(mtd) = {
 	.id		= UCLASS_MTD,
 	.name		= "mtd",
include/linux/mtd/mtd.h +3 -0
index 9a63bf4a49..7dfcaadf50 100644
@@ -538,5 +538,8 @@ int mtd_arg_off_size(int argc, char *const argv[], int *idx, loff_t *off,
 void mtd_get_len_incl_bad(struct mtd_info *mtd, uint64_t offset,
 			  const uint64_t length, uint64_t *len_incl_bad,
 			  int *truncated);
+
+int mtd_probe(struct udevice *dev);
+
 #endif
 #endif /* __MTD_MTD_H__ */
Signature · 1 line
2.14.1
author maintainer
#25 lore raw

PATCH v2 20/21 cmd: mtd: add 'mtd' command

In reply to Miquel Raynal

There should not be a 'nand' command, a 'sf' command and certainly not another 'spi-nand'. Write a 'mtd' command instead to manage all MTD devices at once. This should be the preferred way to access any MTD device.

---
 cmd/Kconfig          |   5 +
 cmd/Makefile         |   1 +
 cmd/mtd.c            | 287 +++++++++++++++++++++++++++++++++++++++++++++++++++
 drivers/mtd/Makefile |   2 +-
 4 files changed, 294 insertions(+), 1 deletion(-)
 create mode 100644 cmd/mtd.c
cmd/Kconfig +5 -0
index 136836d146..6e9b629e1c 100644
@@ -797,6 +797,11 @@ config CMD_MMC
 	help
 	  MMC memory mapped support.
 
+config CMD_MTD
+	bool "mtd"
+	help
+	  MTD commands support.
+
 config CMD_NAND
 	bool "nand"
 	default y if NAND_SUNXI
cmd/Makefile +1 -0
index 9a358e4801..e42db12e1d 100644
@@ -88,6 +88,7 @@ obj-$(CONFIG_CMD_MISC) += misc.o
 obj-$(CONFIG_CMD_MMC) += mmc.o
 obj-$(CONFIG_CMD_MMC_SPI) += mmc_spi.o
 obj-$(CONFIG_MP) += mp.o
+obj-$(CONFIG_CMD_MTD) += mtd.o
 obj-$(CONFIG_CMD_MTDPARTS) += mtdparts.o
 obj-$(CONFIG_CMD_NAND) += nand.o
 obj-$(CONFIG_CMD_NET) += net.o
cmd/mtd.c new file +287 -0

287 lines not on this page · raw message

drivers/mtd/Makefile +1 -1
index eb0e7264ab..95b5f25fef 100644
@@ -5,7 +5,7 @@
 # SPDX-License-Identifier:	GPL-2.0+
 #
 
-ifneq (,$(findstring y,$(CONFIG_MTD_DEVICE)$(CONFIG_CMD_NAND)$(CONFIG_CMD_ONENAND)$(CONFIG_CMD_SF)))
+ifneq (,$(findstring y,$(CONFIG_MTD_DEVICE)$(CONFIG_CMD_NAND)$(CONFIG_CMD_ONENAND)$(CONFIG_CMD_SF)$(CONFIG_CMD_MTD)))
 obj-y += mtdcore.o mtd_uboot.o
 endif
 obj-$(CONFIG_MTD) += mtd-uclass.o
Signature · 1 line
2.14.1
#26 lore raw

PATCH v2 20/21 cmd: mtd: add 'mtd' command

cmd/mtd.c line 40

Quoted 4 lines · On Wed, 11 Jul 2018 17:25:28 +0200 Miquel Raynal <[email protected]>…
cmd/mtd.c new file +4 -0
+
+static void mtd_show_device(struct mtd_info *mtd)
+{
+	printf("* %s", mtd->name);

Printing the device type might be interesting? And maybe also the size, writesize, oobsize and erasesize?

Quoted 139 lines
cmd/mtd.c new file +137 -0
+	if (mtd->dev)
+		printf(" [device: %s] [parent: %s] [driver: %s]",
+		       mtd->dev->name, mtd->dev->parent->name,
+		       mtd->dev->driver->name);
+
+	printf("\n");
+}
 
 
+static int do_mtd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	struct mtd_info *mtd;
+	const char *cmd;
+	char *mtdname;
+	int ret;
+
+	/* All MTD commands need at least two arguments */
+	if (argc < 2)
+		return CMD_RET_USAGE;
+
+	/* Parse the command name and its optional suffixes */
+	cmd = argv[1];
+
+	/* List the MTD devices if that is what the user wants */
+	if (strcmp(cmd, "list") == 0)
+		return do_mtd_list();
+
+	/*
+	 * The remaining commands require also at least a device ID.
+	 * Check the selected device is valid. Ensure it is probed.
+	 */
+	if (argc < 3)
+		return CMD_RET_USAGE;
+
+	mtdname = argv[2];
+	mtd = get_mtd_device_nm(mtdname);
+	if (IS_ERR_OR_NULL(mtd)) {
+		mtd_probe_devices_dm();
+		mtd = get_mtd_device_nm(mtdname);
+		if (IS_ERR_OR_NULL(mtd)) {
+			printf("MTD device %s not found, ret %ld\n",
+			       mtdname, PTR_ERR(mtd));
+			return 1;
+		}
+	}
+
+	argc -= 3;
+	argv += 3;
+
+	/* Do the parsing */
+	if (!strncmp(cmd, "read", 4) || !strncmp(cmd, "dump", 4) ||
+	    !strncmp(cmd, "write", 5)) {
+		struct mtd_oob_ops io_op = {};
+		bool dump, read, raw, woob;
+		uint user_addr = 0;
+		uint nb_pages;
+		u8 *buf;
+		u64 off, len;
+		u32 oob_len;
+
+		dump = !strncmp(cmd, "dump", 4);
+		read = dump || !strncmp(cmd, "read", 4);
+		raw = strstr(cmd, ".raw");
+		woob = strstr(cmd, ".oob");
+
+		if (!dump) {
+			if (!argc)
+				return CMD_RET_USAGE;
+
+			user_addr = simple_strtoul(argv[0], NULL, 16);
+			argc--;
+			argv++;
+		}
+
+		off = argc > 0 ? simple_strtoul(argv[0], NULL, 16) : 0;
+		len = argc > 1 ? simple_strtoul(argv[1], NULL, 16) : mtd->writesize;
+		nb_pages = mtd_len_to_pages(mtd, len);
+		oob_len = woob ? nb_pages * mtd->oobsize : 0;
+
+		if ((u32)off % mtd->writesize) {
+			printf("Offset not aligned with a page (0x%x)\n",
+			       mtd->writesize);
+			return -EINVAL;
+		}
+
+		if ((u32)len % mtd->writesize) {
+			printf("Size not a multiple of a page (0x%x)\n",
+			       mtd->writesize);
+			return -EINVAL;
+		}
+
+		if (dump)
+			buf = kmalloc(len + oob_len, GFP_KERNEL);
+		else
+			buf = map_sysmem(user_addr, 0);
+
+		if (!buf) {
+			printf("Could not map/allocate the user buffer\n");
+			return -ENOMEM;
+		}
+
+		printf("%s %lldB (%d page(s)) at offset 0x%08llx%s%s\n",
+		       read ? "Reading" : "Writing", len, nb_pages, off,
+		       raw ? " [raw]" : "", woob ? " [oob]" : "");
+
+		io_op.mode = raw ? MTD_OPS_RAW : MTD_OPS_AUTO_OOB;
+		io_op.len = len;
+		io_op.ooblen = oob_len;
+		io_op.datbuf = buf;
+		io_op.oobbuf = woob ? &buf[len] : NULL;
+
+		if (read)
+			ret = mtd_read_oob(mtd, off, &io_op);
+		else
+			ret = mtd_write_oob(mtd, off, &io_op);
+
+		if (ret) {
+			printf("%s on %s failed with error %d\n",
+			       read ? "Read" : "Write", mtd->name, ret);
+			return ret;
+		}
+
+		if (dump) {
+			uint page;
+
+			for (page = 0; page < nb_pages; page++) {
+				u64 data_off = page * mtd->writesize;
+				printf("\nDump %d data bytes from 0x%08llx:\n",
+				       mtd->writesize, data_off);
+				mtd_dump_buf(buf, mtd->writesize, data_off);
+
+				if (woob) {
+					u64 oob_off = page * mtd->oobsize;
+					printf("Dump %d OOB bytes from page at 0x%08llx:\n",
+					       mtd->oobsize, data_off);
+					mtd_dump_buf(&buf[len + oob_off],
+						     mtd->oobsize, 0);
+				}
+			}

cmd/mtd.c line 229

Quoted 10 lines
cmd/mtd.c new file +10 -0
+		}
+
+		if (dump)
+			kfree(buf);
+		else
+			unmap_sysmem(buf);
+
+	} else if (!strcmp(cmd, "erase")) {
+		bool scrub = strstr(cmd, ".dontskipbad");
+		bool full_erase = strstr(cmd, ".chip");

Again, I think .chip extension is not needed. Just consider a full erase is requested when offset and length are not provided. Plus, chip is misleading since I guess mtd partitions are also exposed as mtd devices, and could thus be erased with the .chip extension as well.

cmd/mtd.c line 234

Quoted 5 lines
cmd/mtd.c new file +5 -0
+		struct erase_info erase_op = {};
+		u64 off, len;
+
+		off = argc > 0 ? simple_strtoul(argv[0], NULL, 16) : 0;
+		len = argc > 1 ? simple_strtoul(argv[1], NULL, 16) : mtd->erasesize;

Hm. Are we sure we want the default to be 1 eraseblock? Shouldn't we consider that missing size means "erase up to the MTD device end". Same goes for the read/write accesses, but maybe not for dump where dumping a single page makes more sense.

cmd/mtd.c line 241

Quoted 7 lines
cmd/mtd.c new file +7 -0
+
+		if (full_erase) {
+			off = 0;
+			len = mtd->size;
+		}
+
+		if ((u32)off % mtd->erasesize) {

Sounds dangerous. We have 8GB NANDs on sunxi platforms...

cmd/mtd.c line 247

Quoted 6 lines
cmd/mtd.c new file +6 -0
+			printf("Offset not aligned with a block (0x%x)\n",
+			       mtd->erasesize);
+			return -EINVAL;
+		}
+
+		if ((u32)len % mtd->erasesize) {

Same here. I guess there's a do_div() in uboot.

Quoted 40 lines
cmd/mtd.c new file +40 -0
+			printf("Size not a multiple of a block (0x%x)\n",
+			       mtd->erasesize);
+			return -EINVAL;
+		}
+
+		erase_op.mtd = mtd;
+		erase_op.addr = off;
+		erase_op.len = len;
+		erase_op.scrub = scrub;
+
+		ret = mtd_erase(mtd, &erase_op);
+	} else {
+		return CMD_RET_USAGE;
+	}
+
+	return ret;
+}
+
+static char mtd_help_text[] =
+#ifdef CONFIG_SYS_LONGHELP
+	"- generic operations on memory technology devices\n\n"
+	"mtd list\n"
+	"mtd read[.raw][.oob]           <name> <addr> [<off> [<size>]]\n"
+	"mtd dump[.raw][.oob]           <name>        [<off> [<size>]]\n"
+	"mtd write[.raw][.oob]          <name> <addr> [<off> [<size>]]\n"
+	"mtd erase[.chip][.dontskipbad] <name>        [<off> [<size>]]\n"
+	"\n"
+	"With:\n"
+	"\t<name>: NAND partition/chip name\n"
+	"\t<addr>: user address from/to which data will be retrieved/stored\n"
+	"\t<off>: offset in <name> in bytes (default: start of the part)\n"
+	"\t\t* must be block-aligned for erase\n"
+	"\t\t* must be page-aligned otherwise\n"
+	"\t<size>: length of the operation in bytes\n"
+	"\t\t* must be a multiple of a block for erase (default: 1 block)\n"
+	"\t\t* must be a multiple of a page otherwise (default: 1 page)\n"
+#endif
+	"";
+
+U_BOOT_CMD(mtd, 10, 1, do_mtd, "MTD utils", mtd_help_text);
author maintainer
#27 lore raw

PATCH v2 20/21 cmd: mtd: add 'mtd' command

Hi Boris,

Boris Brezillon <[email protected]> wrote on Thu, 12 Jul 2018 00:42:13 +0200:

Quoted 10 lines

cmd/mtd.c line 40

Quoted 4 lines · On Wed, 11 Jul 2018 17:25:28 +0200 Miquel Raynal <[email protected]>…
cmd/mtd.c new file +4 -0
+
+static void mtd_show_device(struct mtd_info *mtd)
+{
+	printf("* %s", mtd->name);  

Printing the device type might be interesting? And maybe also the size, writesize, oobsize and erasesize?

Absolutely.

Quoted 8 lines
Quoted 8 lines
cmd/mtd.c new file +7 -0
+	if (mtd->dev)
+		printf(" [device: %s] [parent: %s] [driver: %s]",
+		       mtd->dev->name, mtd->dev->parent->name,
+		       mtd->dev->driver->name);
+
+	printf("\n");
+}  

[...]

Quoted 8 lines

cmd/mtd.c line 229

Quoted 3 lines
cmd/mtd.c new file +3 -0
+	} else if (!strcmp(cmd, "erase")) {
+		bool scrub = strstr(cmd, ".dontskipbad");
+		bool full_erase = strstr(cmd, ".chip");  

Again, I think .chip extension is not needed. Just consider a full erase is requested when offset and length are not provided. Plus, chip is misleading since I guess mtd partitions are also exposed as mtd devices, and could thus be erased with the .chip extension as well.

".chip" removed.

Default now is mtd->size (the entire MTD device) for erase/read/write, and mtd->writesize (a page) for a dump.

Quoted 11 lines

cmd/mtd.c line 234

Quoted 6 lines
cmd/mtd.c new file +5 -0
+		struct erase_info erase_op = {};
+		u64 off, len;
+
+		off = argc > 0 ? simple_strtoul(argv[0], NULL, 16) : 0;
+		len = argc > 1 ? simple_strtoul(argv[1], NULL, 16) : mtd->erasesize;  

Hm. Are we sure we want the default to be 1 eraseblock? Shouldn't we consider that missing size means "erase up to the MTD device end". Same goes for the read/write accesses, but maybe not for dump where dumping a single page makes more sense.

See above.

Quoted 10 lines

cmd/mtd.c line 241

Quoted 8 lines
cmd/mtd.c new file +7 -0
+
+		if (full_erase) {
+			off = 0;
+			len = mtd->size;
+		}
+
+		if ((u32)off % mtd->erasesize) {  

Sounds dangerous. We have 8GB NANDs on sunxi platforms...

[...]

Quoted 4 lines

cmd/mtd.c line 247

Quoted 2 lines
cmd/mtd.c new file +2 -0
+
+		if ((u32)len % mtd->erasesize) {  

Same here. I guess there's a do_div() in uboot.

In both cases I take the less significant bytes of a 64-bit value. The modulo operation is safe as long as mtd->erasesize is a 32-bit value too. I don't think there is any danger?

[...]

Thanks,
Miquèl

author maintainer
#28 lore raw

PATCH v2 20/21 cmd: mtd: add 'mtd' command

Hi Boris,

Quoted 12 lines
Quoted 9 lines

cmd/mtd.c line 241

Quoted 7 lines
cmd/mtd.c new file +7 -0
+
+		if (full_erase) {
+			off = 0;
+			len = mtd->size;
+		}
+
+		if ((u32)off % mtd->erasesize) {    

Sounds dangerous. We have 8GB NANDs on sunxi platforms...

[...]

Quoted 8 lines
Quoted 4 lines

cmd/mtd.c line 247

Quoted 2 lines
cmd/mtd.c new file +2 -0
+
+		if ((u32)len % mtd->erasesize) {    

Same here. I guess there's a do_div() in uboot.

In both cases I take the less significant bytes of a 64-bit value. The modulo operation is safe as long as mtd->erasesize is a 32-bit value too. I don't think there is any danger?

As discussed out of this thread, this works because mtd->erasesize is always a power of 2. Erase sizes not being a power of 2 do not exist but it will be safer to switch to do_div().

Thanks,
Miquèl

author maintainer
#29 lore raw

PATCH v2 21/21 dt-bindings: Add bindings for SPI NAND devices

In reply to Miquel Raynal

From: Boris Brezillon <[email protected]>

Add bindings for SPI NAND chips.

---
 doc/device-tree-bindings/mtd/spi-nand.txt | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)
 create mode 100644 doc/device-tree-bindings/mtd/spi-nand.txt
doc/device-tree-bindings/mtd/spi-nand.txt new file +27 -0
new file mode 100644
index 0000000000..d55f80196c
@@ -0,0 +1,27 @@
+SPI NAND flash
+
+Required properties:
+- compatible: should be "spi-nand"
+- reg: should encode the chip-select line used to access the NAND chip
+
+Optional properties
+- spi-max-frequency: maximum frequency of the SPI bus the chip can operate at.
+		     This should encode board limitations (i.e. max freq can't
+		     be achieved due to crosstalk on IO lines).
+		     When unspecified, the driver assumes the chip can run at
+		     the max frequency defined in the spec (information
+		     extracted chip detection time).
+- spi-tx-bus-width: The bus width (number of data wires) that is used for MOSI.
+		    Only encodes the board constraints (i.e. when not all IO
+		    signals are routed on the board). Device constraints are
+		    extracted when detecting the chip, and controller
+		    constraints are exposed by the SPI mem controller. If this
+		    property is missing that means no constraint at the board
+		    level.
+- spi-rx-bus-width: The bus width (number of data wires) that is used for MISO.
+		    Only encodes the board constraints (i.e. when not all IO
+		    signals are routed on the board). Device constraints are
+		    extracted when detecting the chip, and controller
+		    constraints are exposed by the SPI mem controller. If this
+		    property is missing that means no constraint at the board
+		    level.
Signature · 1 line
2.14.1
#30 lore raw

PATCH v2 21/21 dt-bindings: Add bindings for SPI NAND devices

Quoted 34 lines · On Wed, 11 Jul 2018 17:25:29 +0200 Miquel Raynal <[email protected]>…

From: Boris Brezillon <[email protected]>

Add bindings for SPI NAND chips.

---
 doc/device-tree-bindings/mtd/spi-nand.txt | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)
 create mode 100644 doc/device-tree-bindings/mtd/spi-nand.txt
doc/device-tree-bindings/mtd/spi-nand.txt new file +17 -0
new file mode 100644
index 0000000000..d55f80196c
@@ -0,0 +1,27 @@
+SPI NAND flash
+
+Required properties:
+- compatible: should be "spi-nand"
+- reg: should encode the chip-select line used to access the NAND chip
+
+Optional properties
+- spi-max-frequency: maximum frequency of the SPI bus the chip can operate at.
+		     This should encode board limitations (i.e. max freq can't
+		     be achieved due to crosstalk on IO lines).
+		     When unspecified, the driver assumes the chip can run at
+		     the max frequency defined in the spec (information
+		     extracted chip detection time).
+- spi-tx-bus-width: The bus width (number of data wires) that is used for MOSI.
+		    Only encodes the board constraints (i.e. when not all IO
+		    signals are routed on the board). Device constraints are
+		    extracted when detecting the chip, and controller

doc/device-tree-bindings/mtd/spi-nand.txt line 27

Quoted 10 lines
doc/device-tree-bindings/mtd/spi-nand.txt new file +10 -0
+		    constraints are exposed by the SPI mem controller. If this
+		    property is missing that means no constraint at the board
+		    level.
+- spi-rx-bus-width: The bus width (number of data wires) that is used for MISO.
+		    Only encodes the board constraints (i.e. when not all IO
+		    signals are routed on the board). Device constraints are
+		    extracted when detecting the chip, and controller
+		    constraints are exposed by the SPI mem controller. If this
+		    property is missing that means no constraint at the board
+		    level.

This section has been dropped from the Linux doc.

author maintainer
#31 lore raw

PATCH v2 21/21 dt-bindings: Add bindings for SPI NAND devices

Hi Boris,

Boris Brezillon <[email protected]> wrote on Thu, 12 Jul 2018 00:44:44 +0200:

Quoted 41 lines
Quoted 38 lines · On Wed, 11 Jul 2018 17:25:29 +0200 Miquel Raynal <[email protected]>…

From: Boris Brezillon <[email protected]>

Add bindings for SPI NAND chips.

---
 doc/device-tree-bindings/mtd/spi-nand.txt | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)
 create mode 100644 doc/device-tree-bindings/mtd/spi-nand.txt
doc/device-tree-bindings/mtd/spi-nand.txt new file +21 -0
new file mode 100644
index 0000000000..d55f80196c
@@ -0,0 +1,27 @@
+SPI NAND flash
+
+Required properties:
+- compatible: should be "spi-nand"
+- reg: should encode the chip-select line used to access the NAND chip
+
+Optional properties
+- spi-max-frequency: maximum frequency of the SPI bus the chip can operate at.
+		     This should encode board limitations (i.e. max freq can't
+		     be achieved due to crosstalk on IO lines).
+		     When unspecified, the driver assumes the chip can run at
+		     the max frequency defined in the spec (information
+		     extracted chip detection time).
+- spi-tx-bus-width: The bus width (number of data wires) that is used for MOSI.
+		    Only encodes the board constraints (i.e. when not all IO
+		    signals are routed on the board). Device constraints are
+		    extracted when detecting the chip, and controller
+		    constraints are exposed by the SPI mem controller. If this
+		    property is missing that means no constraint at the board
+		    level.
+- spi-rx-bus-width: The bus width (number of data wires) that is used for MISO.
Quoted 8 lines

doc/device-tree-bindings/mtd/spi-nand.txt line 20

Quoted 6 lines
doc/device-tree-bindings/mtd/spi-nand.txt new file +6 -0
+		    Only encodes the board constraints (i.e. when not all IO
+		    signals are routed on the board). Device constraints are
+		    extracted when detecting the chip, and controller
+		    constraints are exposed by the SPI mem controller. If this
+		    property is missing that means no constraint at the board
+		    level.  

This section has been dropped from the Linux doc.

Removed.

Thanks,
Miquèl