All of lore.kernel.org
 help / color / mirror / Atom feed
* [U-Boot] [RFC PATCH 00/20] SPI-NAND support
@ 2018-06-06 15:30 Miquel Raynal
  2018-06-06 15:30 ` [U-Boot] [RFC PATCH 01/20] mtd: Fallback to ->_read/write_oob() when ->_read/write() is missing Miquel Raynal
                   ` (22 more replies)
  0 siblings, 23 replies; 65+ messages in thread
From: Miquel Raynal @ 2018-06-06 15:30 UTC (permalink / raw)
  To: u-boot

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:
- 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.
- DT changes to make use of a SPI NAND on the Ocelot board.

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

Thanks,
Miquèl


Boris Brezillon (6):
  mtd: Fallback to ->_read/write_oob() when ->_read/write() is missing
  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

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

Miquel Raynal (10):
  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
  mips: dts: ocelot: describe SPI CS pins
  mips: dts: ocelot: add the SPI NAND node

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

 arch/mips/dts/mscc,ocelot.dtsi                |   20 +
 arch/mips/dts/mscc,ocelot_pcb.dtsi            |    9 +
 cmd/Kconfig                                   |    5 +
 cmd/Makefile                                  |    1 +
 cmd/mtd.c                                     |  280 ++++++
 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                         |   31 +-
 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                   | 1252 +++++++++++++++++++++++++
 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                       |   21 +
 include/linux/mtd/nand.h                      |  734 +++++++++++++++
 include/linux/mtd/spinand.h                   |  432 +++++++++
 include/spi-mem.h                             |  258 +++++
 include/spi.h                                 |   11 +
 81 files changed, 4741 insertions(+), 442 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

-- 
2.14.1

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [U-Boot] [RFC PATCH 01/20] mtd: Fallback to ->_read/write_oob() when ->_read/write() is missing
  2018-06-06 15:30 [U-Boot] [RFC PATCH 00/20] SPI-NAND support Miquel Raynal
@ 2018-06-06 15:30 ` Miquel Raynal
  2018-06-27 10:52   ` Jagan Teki
  2018-06-06 15:30 ` [U-Boot] [RFC PATCH 02/20] mtd: add get/set of_node/flash_node helpers Miquel Raynal
                   ` (21 subsequent siblings)
  22 siblings, 1 reply; 65+ messages in thread
From: Miquel Raynal @ 2018-06-06 15:30 UTC (permalink / raw)
  To: u-boot

From: Boris Brezillon <boris.brezillon@free-electrons.com>

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.

Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
Acked-by: Robert Jarzmik <robert.jarzmik@free.fr>
Acked-by: Brian Norris <computersforpeace@gmail.com>
Reviewed-by: Miquel Raynal <miquel.raynal@free-electrons.com>
Tested-by: Ladislav Michl <ladis@linux-mips.org>
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 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(-)

diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
index 2cda0511e8..15e0ac2f3e 100644
--- a/drivers/mtd/mtdcore.c
+++ b/drivers/mtd/mtdcore.c
@@ -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);
diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c
index 5e42c4b833..3a3f2a1717 100644
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -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;
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index eb9f121f81..8ebe85057d 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -1863,33 +1863,6 @@ read_retry:
 	return max_bitflips;
 }
 
-/**
- * nand_read - [MTD Interface] MTD compatibility function for nand_do_read_ecc
- * @mtd: MTD device structure
- * @from: offset to read from
- * @len: number of bytes to read
- * @retlen: pointer to variable to store the number of read bytes
- * @buf: the databuffer to put data
- *
- * Get hold of the chip and call nand_do_read.
- */
-static int nand_read(struct mtd_info *mtd, loff_t from, size_t len,
-		     size_t *retlen, uint8_t *buf)
-{
-	struct mtd_oob_ops ops;
-	int ret;
-
-	nand_get_device(mtd, FL_READING);
-	memset(&ops, 0, sizeof(ops));
-	ops.len = len;
-	ops.datbuf = buf;
-	ops.mode = MTD_OPS_PLACE_OOB;
-	ret = nand_do_read_ops(mtd, from, &ops);
-	*retlen = ops.retlen;
-	nand_release_device(mtd);
-	return ret;
-}
-
 /**
  * nand_read_oob_std - [REPLACEABLE] the most common OOB data read function
  * @mtd: mtd info structure
@@ -2674,33 +2647,6 @@ static int panic_nand_write(struct mtd_info *mtd, loff_t to, size_t len,
 	return ret;
 }
 
-/**
- * nand_write - [MTD Interface] NAND write with ECC
- * @mtd: MTD device structure
- * @to: offset to write to
- * @len: number of bytes to write
- * @retlen: pointer to variable to store the number of written bytes
- * @buf: the data to write
- *
- * NAND write with ECC.
- */
-static int nand_write(struct mtd_info *mtd, loff_t to, size_t len,
-			  size_t *retlen, const uint8_t *buf)
-{
-	struct mtd_oob_ops ops;
-	int ret;
-
-	nand_get_device(mtd, FL_WRITING);
-	memset(&ops, 0, sizeof(ops));
-	ops.len = len;
-	ops.datbuf = (uint8_t *)buf;
-	ops.mode = MTD_OPS_PLACE_OOB;
-	ret = nand_do_write_ops(mtd, to, &ops);
-	*retlen = ops.retlen;
-	nand_release_device(mtd);
-	return ret;
-}
-
 /**
  * nand_do_write_oob - [MTD Interface] NAND write out-of-band
  * @mtd: MTD device structure
@@ -4619,8 +4565,6 @@ int nand_scan_tail(struct mtd_info *mtd)
 	mtd->flags = (chip->options & NAND_ROM) ? MTD_CAP_ROM :
 						MTD_CAP_NANDFLASH;
 	mtd->_erase = nand_erase;
-	mtd->_read = nand_read;
-	mtd->_write = nand_write;
 	mtd->_panic_write = panic_nand_write;
 	mtd->_read_oob = nand_read_oob;
 	mtd->_write_oob = nand_write_oob;
diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c
index 86b1640357..080d8f0d94 100644
--- a/drivers/mtd/onenand/onenand_base.c
+++ b/drivers/mtd/onenand/onenand_base.c
@@ -1088,35 +1088,6 @@ static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from,
 	return 0;
 }
 
-/**
- * onenand_read - [MTD Interface] MTD compability function for onenand_read_ecc
- * @param mtd		MTD device structure
- * @param from		offset to read from
- * @param len		number of bytes to read
- * @param retlen	pointer to variable to store the number of read bytes
- * @param buf		the databuffer to put data
- *
- * This function simply calls onenand_read_ecc with oob buffer and oobsel = NULL
-*/
-int onenand_read(struct mtd_info *mtd, loff_t from, size_t len,
-		 size_t * retlen, u_char * buf)
-{
-	struct mtd_oob_ops ops = {
-		.len    = len,
-		.ooblen = 0,
-		.datbuf = buf,
-		.oobbuf = NULL,
-	};
-	int ret;
-
-	onenand_get_device(mtd, FL_READING);
-	ret = onenand_read_ops_nolock(mtd, from, &ops);
-	onenand_release_device(mtd);
-
-	*retlen = ops.retlen;
-	return ret;
-}
-
 /**
  * onenand_read_oob - [MTD Interface] OneNAND read out-of-band
  * @param mtd		MTD device structure
@@ -1636,35 +1607,6 @@ static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to,
 	return ret;
 }
 
-/**
- * onenand_write - [MTD Interface] compability function for onenand_write_ecc
- * @param mtd		MTD device structure
- * @param to		offset to write to
- * @param len		number of bytes to write
- * @param retlen	pointer to variable to store the number of written bytes
- * @param buf		the data to write
- *
- * Write with ECC
- */
-int onenand_write(struct mtd_info *mtd, loff_t to, size_t len,
-		  size_t * retlen, const u_char * buf)
-{
-	struct mtd_oob_ops ops = {
-		.len    = len,
-		.ooblen = 0,
-		.datbuf = (u_char *) buf,
-		.oobbuf = NULL,
-	};
-	int ret;
-
-	onenand_get_device(mtd, FL_WRITING);
-	ret = onenand_write_ops_nolock(mtd, to, &ops);
-	onenand_release_device(mtd);
-
-	*retlen = ops.retlen;
-	return ret;
-}
-
 /**
  * onenand_write_oob - [MTD Interface] OneNAND write out-of-band
  * @param mtd		MTD device structure
@@ -2656,8 +2598,6 @@ int onenand_probe(struct mtd_info *mtd)
 
 	mtd->flags = MTD_CAP_NANDFLASH;
 	mtd->_erase = onenand_erase;
-	mtd->_read = onenand_read;
-	mtd->_write = onenand_write;
 	mtd->_read_oob = onenand_read_oob;
 	mtd->_write_oob = onenand_write_oob;
 	mtd->_sync = onenand_sync;
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [U-Boot] [RFC PATCH 02/20] mtd: add get/set of_node/flash_node helpers
  2018-06-06 15:30 [U-Boot] [RFC PATCH 00/20] SPI-NAND support Miquel Raynal
  2018-06-06 15:30 ` [U-Boot] [RFC PATCH 01/20] mtd: Fallback to ->_read/write_oob() when ->_read/write() is missing Miquel Raynal
@ 2018-06-06 15:30 ` Miquel Raynal
  2018-06-27 10:53   ` Jagan Teki
  2018-06-06 15:30 ` [U-Boot] [RFC PATCH 03/20] mtd: fix build issue with includes Miquel Raynal
                   ` (20 subsequent siblings)
  22 siblings, 1 reply; 65+ messages in thread
From: Miquel Raynal @ 2018-06-06 15:30 UTC (permalink / raw)
  To: u-boot

From: Brian Norris <computersforpeace@gmail.com>

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.

Signed-off-by: Brian Norris <computersforpeace@gmail.com>
Reviewed-by: Boris Brezillon <boris.brezillon@free-electrons.com>
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 include/linux/mtd/mtd.h | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
index ba4cbba949..777a926623 100644
--- a/include/linux/mtd/mtd.h
+++ b/include/linux/mtd/mtd.h
@@ -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,
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [U-Boot] [RFC PATCH 03/20] mtd: fix build issue with includes
  2018-06-06 15:30 [U-Boot] [RFC PATCH 00/20] SPI-NAND support Miquel Raynal
  2018-06-06 15:30 ` [U-Boot] [RFC PATCH 01/20] mtd: Fallback to ->_read/write_oob() when ->_read/write() is missing Miquel Raynal
  2018-06-06 15:30 ` [U-Boot] [RFC PATCH 02/20] mtd: add get/set of_node/flash_node helpers Miquel Raynal
@ 2018-06-06 15:30 ` Miquel Raynal
  2018-06-27 10:53   ` Jagan Teki
  2018-06-06 15:30 ` [U-Boot] [RFC PATCH 04/20] mtd: move definitions to enlarge their range Miquel Raynal
                   ` (19 subsequent siblings)
  22 siblings, 1 reply; 65+ messages in thread
From: Miquel Raynal @ 2018-06-06 15:30 UTC (permalink / raw)
  To: u-boot

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

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 include/linux/mtd/mtd.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
index 777a926623..52d1afb5b8 100644
--- a/include/linux/mtd/mtd.h
+++ b/include/linux/mtd/mtd.h
@@ -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
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [U-Boot] [RFC PATCH 04/20] mtd: move definitions to enlarge their range
  2018-06-06 15:30 [U-Boot] [RFC PATCH 00/20] SPI-NAND support Miquel Raynal
                   ` (2 preceding siblings ...)
  2018-06-06 15:30 ` [U-Boot] [RFC PATCH 03/20] mtd: fix build issue with includes Miquel Raynal
@ 2018-06-06 15:30 ` Miquel Raynal
  2018-06-06 15:30 ` [U-Boot] [RFC PATCH 05/20] mtd: move all flash categories inside MTD submenu Miquel Raynal
                   ` (18 subsequent siblings)
  22 siblings, 0 replies; 65+ messages in thread
From: Miquel Raynal @ 2018-06-06 15:30 UTC (permalink / raw)
  To: u-boot

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

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 drivers/mtd/mtdcore.h   | 6 ------
 include/linux/mtd/mtd.h | 6 ++++++
 2 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/drivers/mtd/mtdcore.h b/drivers/mtd/mtdcore.h
index 7b0353399a..1d181a1045 100644
--- a/drivers/mtd/mtdcore.h
+++ b/drivers/mtd/mtdcore.h
@@ -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))
diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
index 52d1afb5b8..b5f9151a70 100644
--- a/include/linux/mtd/mtd.h
+++ b/include/linux/mtd/mtd.h
@@ -532,6 +532,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,
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [U-Boot] [RFC PATCH 05/20] mtd: move all flash categories inside MTD submenu
  2018-06-06 15:30 [U-Boot] [RFC PATCH 00/20] SPI-NAND support Miquel Raynal
                   ` (3 preceding siblings ...)
  2018-06-06 15:30 ` [U-Boot] [RFC PATCH 04/20] mtd: move definitions to enlarge their range Miquel Raynal
@ 2018-06-06 15:30 ` Miquel Raynal
  2018-06-27 10:56   ` Jagan Teki
  2018-06-06 15:30 ` [U-Boot] [RFC PATCH 06/20] mtd: move NAND fiels into a raw/ subdirectory Miquel Raynal
                   ` (17 subsequent siblings)
  22 siblings, 1 reply; 65+ messages in thread
From: Miquel Raynal @ 2018-06-06 15:30 UTC (permalink / raw)
  To: u-boot

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

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 drivers/mtd/Kconfig | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig
index 19579801d2..d21b0920dc 100644
--- a/drivers/mtd/Kconfig
+++ b/drivers/mtd/Kconfig
@@ -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
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [U-Boot] [RFC PATCH 06/20] mtd: move NAND fiels into a raw/ subdirectory
  2018-06-06 15:30 [U-Boot] [RFC PATCH 00/20] SPI-NAND support Miquel Raynal
                   ` (4 preceding siblings ...)
  2018-06-06 15:30 ` [U-Boot] [RFC PATCH 05/20] mtd: move all flash categories inside MTD submenu Miquel Raynal
@ 2018-06-06 15:30 ` Miquel Raynal
  2018-06-06 15:30 ` [U-Boot] [RFC PATCH 07/20] mtd: rename nand into rawnand in Kconfig prompt Miquel Raynal
                   ` (16 subsequent siblings)
  22 siblings, 0 replies; 65+ messages in thread
From: Miquel Raynal @ 2018-06-06 15:30 UTC (permalink / raw)
  To: u-boot

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.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 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%)

diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile
index 20c0d0af44..eb0e7264ab 100644
--- a/drivers/mtd/Makefile
+++ b/drivers/mtd/Makefile
@@ -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/
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index a820af61ce..6d53734718 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -1,239 +1 @@
-
-menuconfig NAND
-	bool "NAND Device Support"
-if NAND
-
-config SYS_NAND_SELF_INIT
-	bool
-	help
-	  This option, if enabled, provides more flexible and linux-like
-	  NAND initialization process.
-
-config NAND_DENALI
-	bool
-	select SYS_NAND_SELF_INIT
-	imply CMD_NAND
-
-config NAND_DENALI_DT
-	bool "Support Denali NAND controller as a DT device"
-	select NAND_DENALI
-	depends on OF_CONTROL && DM
-	help
-	  Enable the driver for NAND flash on platforms using a Denali NAND
-	  controller as a DT device.
-
-config NAND_DENALI_SPARE_AREA_SKIP_BYTES
-	int "Number of bytes skipped in OOB area"
-	depends on NAND_DENALI
-	range 0 63
-	help
-	  This option specifies the number of bytes to skip from the beginning
-	  of OOB area before last ECC sector data starts.  This is potentially
-	  used to preserve the bad block marker in the OOB area.
-
-config NAND_OMAP_GPMC
-	bool "Support OMAP GPMC NAND controller"
-	depends on ARCH_OMAP2PLUS
-	help
-	  Enables omap_gpmc.c driver for OMAPx and AMxxxx platforms.
-	  GPMC controller is used for parallel NAND flash devices, and can
-	  do ECC calculation (not ECC error detection) for HAM1, BCH4, BCH8
-	  and BCH16 ECC algorithms.
-
-config NAND_OMAP_GPMC_PREFETCH
-	bool "Enable GPMC Prefetch"
-	depends on NAND_OMAP_GPMC
-	default y
-	help
-	  On OMAP platforms that use the GPMC controller
-	  (CONFIG_NAND_OMAP_GPMC_PREFETCH), this options enables the code that
-	  uses the prefetch mode to speed up read operations.
-
-config NAND_OMAP_ELM
-	bool "Enable ELM driver for OMAPxx and AMxx platforms."
-	depends on NAND_OMAP_GPMC && !OMAP34XX
-	help
-	  ELM controller is used for ECC error detection (not ECC calculation)
-	  of BCH4, BCH8 and BCH16 ECC algorithms.
-	  Some legacy platforms like OMAP3xx do not have in-built ELM h/w engine,
-	  thus such SoC platforms need to depend on software library for ECC error
-	  detection. However ECC calculation on such plaforms would still be
-	  done by GPMC controller.
-
-config NAND_VF610_NFC
-	bool "Support for Freescale NFC for VF610"
-	select SYS_NAND_SELF_INIT
-	imply CMD_NAND
-	help
-	  Enables support for NAND Flash Controller on some Freescale
-	  processors like the VF610, MCF54418 or Kinetis K70.
-	  The driver supports a maximum 2k page size. The driver
-	  currently does not support hardware ECC.
-
-choice
-	prompt "Hardware ECC strength"
-	depends on NAND_VF610_NFC
-	default SYS_NAND_VF610_NFC_45_ECC_BYTES
-	help
-	  Select the ECC strength used in the hardware BCH ECC block.
-
-config SYS_NAND_VF610_NFC_45_ECC_BYTES
-	bool "24-error correction (45 ECC bytes)"
-
-config SYS_NAND_VF610_NFC_60_ECC_BYTES
-	bool "32-error correction (60 ECC bytes)"
-
-endchoice
-
-config NAND_PXA3XX
-	bool "Support for NAND on PXA3xx and Armada 370/XP/38x"
-	select SYS_NAND_SELF_INIT
-	imply CMD_NAND
-	help
-	  This enables the driver for the NAND flash device found on
-	  PXA3xx processors (NFCv1) and also on Armada 370/XP (NFCv2).
-
-config NAND_SUNXI
-	bool "Support for NAND on Allwinner SoCs"
-	depends on MACH_SUN4I || MACH_SUN5I || MACH_SUN7I
-	select SYS_NAND_SELF_INIT
-	select SYS_NAND_U_BOOT_LOCATIONS
-	imply CMD_NAND
-	---help---
-	Enable support for NAND. This option enables the standard and
-	SPL drivers.
-	The SPL driver only supports reading from the NAND using DMA
-	transfers.
-
-if NAND_SUNXI
-
-config NAND_SUNXI_SPL_ECC_STRENGTH
-	int "Allwinner NAND SPL ECC Strength"
-	default 64
-
-config NAND_SUNXI_SPL_ECC_SIZE
-	int "Allwinner NAND SPL ECC Step Size"
-	default 1024
-
-config NAND_SUNXI_SPL_USABLE_PAGE_SIZE
-	int "Allwinner NAND SPL Usable Page Size"
-	default 1024
-
-endif
-
-config NAND_ARASAN
-	bool "Configure Arasan Nand"
-	select SYS_NAND_SELF_INIT
-	imply CMD_NAND
-	help
-	  This enables Nand driver support for Arasan nand flash
-	  controller. This uses the hardware ECC for read and
-	  write operations.
-
-config NAND_MXC
-	bool "MXC NAND support"
-	depends on CPU_ARM926EJS || CPU_ARM1136 || MX5
-	imply CMD_NAND
-	help
-	  This enables the NAND driver for the NAND flash controller on the
-	  i.MX27 / i.MX31 / i.MX5 rocessors.
-
-config NAND_MXS
-	bool "MXS NAND support"
-	depends on MX23 || MX28 || MX6 || MX7
-	imply CMD_NAND
-	select APBH_DMA
-	select APBH_DMA_BURST if ARCH_MX6 || ARCH_MX7
-	select APBH_DMA_BURST8 if ARCH_MX6 || ARCH_MX7
-	help
-	  This enables NAND driver for the NAND flash controller on the
-	  MXS processors.
-
-config NAND_ZYNQ
-	bool "Support for Zynq Nand controller"
-	select SYS_NAND_SELF_INIT
-	imply CMD_NAND
-	help
-	  This enables Nand driver support for Nand flash controller
-	  found on Zynq SoC.
-
-config NAND_ZYNQ_USE_BOOTLOADER1_TIMINGS
-	bool "Enable use of 1st stage bootloader timing for NAND"
-	depends on NAND_ZYNQ
-	help
-	  This flag prevent U-boot reconfigure NAND flash controller and reuse
-	  the NAND timing from 1st stage bootloader.
-
-comment "Generic NAND options"
-
-# Enhance depends when converting drivers to Kconfig which use this config
-# option (mxc_nand, ndfc, omap_gpmc).
-config SYS_NAND_BUSWIDTH_16BIT
-	bool "Use 16-bit NAND interface"
-	depends on NAND_VF610_NFC || NAND_OMAP_GPMC || NAND_MXC || ARCH_DAVINCI
-	help
-	  Indicates that NAND device has 16-bit wide data-bus. In absence of this
-	  config, bus-width of NAND device is assumed to be either 8-bit and later
-	  determined by reading ONFI params.
-	  Above config is useful when NAND device's bus-width information cannot
-	  be determined from on-chip ONFI params, like in following scenarios:
-	  - SPL boot does not support reading of ONFI parameters. This is done to
-	    keep SPL code foot-print small.
-	  - In current U-Boot flow using nand_init(), driver initialization
-	    happens in board_nand_init() which is called before any device probe
-	    (nand_scan_ident + nand_scan_tail), thus device's ONFI parameters are
-	    not available while configuring controller. So a static CONFIG_NAND_xx
-	    is needed to know the device's bus-width in advance.
-
-if SPL
-
-config SYS_NAND_U_BOOT_LOCATIONS
-	bool "Define U-boot binaries locations in NAND"
-	help
-	Enable CONFIG_SYS_NAND_U_BOOT_OFFS though Kconfig.
-	This option should not be enabled when compiling U-boot for boards
-	defining CONFIG_SYS_NAND_U_BOOT_OFFS in their include/configs/<board>.h
-	file.
-
-config SYS_NAND_U_BOOT_OFFS
-	hex "Location in NAND to read U-Boot from"
-	default 0x800000 if NAND_SUNXI
-	depends on SYS_NAND_U_BOOT_LOCATIONS
-	help
-	Set the offset from the start of the nand where u-boot should be
-	loaded from.
-
-config SYS_NAND_U_BOOT_OFFS_REDUND
-	hex "Location in NAND to read U-Boot from"
-	default SYS_NAND_U_BOOT_OFFS
-	depends on SYS_NAND_U_BOOT_LOCATIONS
-	help
-	Set the offset from the start of the nand where the redundant u-boot
-	should be loaded from.
-
-config SPL_NAND_AM33XX_BCH
-	bool "Enables SPL-NAND driver which supports ELM based"
-	depends on NAND_OMAP_GPMC && !OMAP34XX
-	default y
-        help
-	  Hardware ECC correction. This is useful for platforms which have ELM
-	  hardware engine and use NAND boot mode.
-	  Some legacy platforms like OMAP3xx do not have in-built ELM h/w engine,
-	  so those platforms should use CONFIG_SPL_NAND_SIMPLE for enabling
-          SPL-NAND driver with software ECC correction support.
-
-config SPL_NAND_DENALI
-	bool "Support Denali NAND controller for SPL"
-	help
-	  This is a small implementation of the Denali NAND controller
-	  for use on SPL.
-
-config SPL_NAND_SIMPLE
-	bool "Use simple SPL NAND driver"
-	depends on !SPL_NAND_AM33XX_BCH
-	help
-	  Support for NAND boot using simple NAND drivers that
-	  expose the cmd_ctrl() interface.
-endif
-
-endif   # if NAND
+source "drivers/mtd/nand/raw/Kconfig"
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index 9f7d9d6ff7..d1c3f93047 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -1,78 +1,3 @@
-#
-# (C) Copyright 2006
-# Wolfgang Denk, DENX Software Engineering, wd at denx.de.
-#
-# SPDX-License-Identifier:	GPL-2.0+
-#
+# SPDX-License-Identifier: GPL-2.0
 
-ifdef CONFIG_SPL_BUILD
-
-ifdef CONFIG_SPL_NAND_DRIVERS
-NORMAL_DRIVERS=y
-endif
-
-obj-$(CONFIG_SPL_NAND_AM33XX_BCH) += am335x_spl_bch.o
-obj-$(CONFIG_SPL_NAND_DENALI) += denali_spl.o
-obj-$(CONFIG_SPL_NAND_SIMPLE) += nand_spl_simple.o
-obj-$(CONFIG_SPL_NAND_LOAD) += nand_spl_load.o
-obj-$(CONFIG_SPL_NAND_ECC) += nand_ecc.o
-obj-$(CONFIG_SPL_NAND_BASE) += nand_base.o
-obj-$(CONFIG_SPL_NAND_INIT) += nand.o
-ifeq ($(CONFIG_SPL_ENV_SUPPORT),y)
-obj-$(CONFIG_ENV_IS_IN_NAND) += nand_util.o
-endif
-
-else # not spl
-
-NORMAL_DRIVERS=y
-
-obj-y += nand.o
-obj-y += nand_bbt.o
-obj-y += nand_ids.o
-obj-y += nand_util.o
-obj-y += nand_ecc.o
-obj-y += nand_base.o
-obj-y += nand_timings.o
-
-endif # not spl
-
-ifdef NORMAL_DRIVERS
-
-obj-$(CONFIG_NAND_ECC_BCH) += nand_bch.o
-
-obj-$(CONFIG_NAND_ATMEL) += atmel_nand.o
-obj-$(CONFIG_NAND_ARASAN) += arasan_nfc.o
-obj-$(CONFIG_NAND_DAVINCI) += davinci_nand.o
-obj-$(CONFIG_NAND_DENALI) += denali.o
-obj-$(CONFIG_NAND_DENALI_DT) += denali_dt.o
-obj-$(CONFIG_NAND_FSL_ELBC) += fsl_elbc_nand.o
-obj-$(CONFIG_NAND_FSL_IFC) += fsl_ifc_nand.o
-obj-$(CONFIG_NAND_FSL_UPM) += fsl_upm.o
-obj-$(CONFIG_NAND_FSMC) += fsmc_nand.o
-obj-$(CONFIG_NAND_KB9202) += kb9202_nand.o
-obj-$(CONFIG_NAND_KIRKWOOD) += kirkwood_nand.o
-obj-$(CONFIG_NAND_KMETER1) += kmeter1_nand.o
-obj-$(CONFIG_NAND_LPC32XX_MLC) += lpc32xx_nand_mlc.o
-obj-$(CONFIG_NAND_LPC32XX_SLC) += lpc32xx_nand_slc.o
-obj-$(CONFIG_NAND_VF610_NFC) += vf610_nfc.o
-obj-$(CONFIG_NAND_MXC) += mxc_nand.o
-obj-$(CONFIG_NAND_MXS) += mxs_nand.o
-obj-$(CONFIG_NAND_NDFC) += ndfc.o
-obj-$(CONFIG_NAND_PXA3XX) += pxa3xx_nand.o
-obj-$(CONFIG_NAND_SPEAR) += spr_nand.o
-obj-$(CONFIG_TEGRA_NAND) += tegra_nand.o
-obj-$(CONFIG_NAND_OMAP_GPMC) += omap_gpmc.o
-obj-$(CONFIG_NAND_OMAP_ELM) += omap_elm.o
-obj-$(CONFIG_NAND_PLAT) += nand_plat.o
-obj-$(CONFIG_NAND_SUNXI) += sunxi_nand.o
-obj-$(CONFIG_NAND_ZYNQ) += zynq_nand.o
-
-else  # minimal SPL drivers
-
-obj-$(CONFIG_NAND_FSL_ELBC) += fsl_elbc_spl.o
-obj-$(CONFIG_NAND_FSL_IFC) += fsl_ifc_spl.o
-obj-$(CONFIG_NAND_MXC) += mxc_nand_spl.o
-obj-$(CONFIG_NAND_MXS) += mxs_nand_spl.o mxs_nand.o
-obj-$(CONFIG_NAND_SUNXI) += sunxi_nand_spl.o
-
-endif # drivers
+obj-$(CONFIG_MTD_NAND) += raw/
diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig
new file mode 100644
index 0000000000..a820af61ce
--- /dev/null
+++ b/drivers/mtd/nand/raw/Kconfig
@@ -0,0 +1,239 @@
+
+menuconfig NAND
+	bool "NAND Device Support"
+if NAND
+
+config SYS_NAND_SELF_INIT
+	bool
+	help
+	  This option, if enabled, provides more flexible and linux-like
+	  NAND initialization process.
+
+config NAND_DENALI
+	bool
+	select SYS_NAND_SELF_INIT
+	imply CMD_NAND
+
+config NAND_DENALI_DT
+	bool "Support Denali NAND controller as a DT device"
+	select NAND_DENALI
+	depends on OF_CONTROL && DM
+	help
+	  Enable the driver for NAND flash on platforms using a Denali NAND
+	  controller as a DT device.
+
+config NAND_DENALI_SPARE_AREA_SKIP_BYTES
+	int "Number of bytes skipped in OOB area"
+	depends on NAND_DENALI
+	range 0 63
+	help
+	  This option specifies the number of bytes to skip from the beginning
+	  of OOB area before last ECC sector data starts.  This is potentially
+	  used to preserve the bad block marker in the OOB area.
+
+config NAND_OMAP_GPMC
+	bool "Support OMAP GPMC NAND controller"
+	depends on ARCH_OMAP2PLUS
+	help
+	  Enables omap_gpmc.c driver for OMAPx and AMxxxx platforms.
+	  GPMC controller is used for parallel NAND flash devices, and can
+	  do ECC calculation (not ECC error detection) for HAM1, BCH4, BCH8
+	  and BCH16 ECC algorithms.
+
+config NAND_OMAP_GPMC_PREFETCH
+	bool "Enable GPMC Prefetch"
+	depends on NAND_OMAP_GPMC
+	default y
+	help
+	  On OMAP platforms that use the GPMC controller
+	  (CONFIG_NAND_OMAP_GPMC_PREFETCH), this options enables the code that
+	  uses the prefetch mode to speed up read operations.
+
+config NAND_OMAP_ELM
+	bool "Enable ELM driver for OMAPxx and AMxx platforms."
+	depends on NAND_OMAP_GPMC && !OMAP34XX
+	help
+	  ELM controller is used for ECC error detection (not ECC calculation)
+	  of BCH4, BCH8 and BCH16 ECC algorithms.
+	  Some legacy platforms like OMAP3xx do not have in-built ELM h/w engine,
+	  thus such SoC platforms need to depend on software library for ECC error
+	  detection. However ECC calculation on such plaforms would still be
+	  done by GPMC controller.
+
+config NAND_VF610_NFC
+	bool "Support for Freescale NFC for VF610"
+	select SYS_NAND_SELF_INIT
+	imply CMD_NAND
+	help
+	  Enables support for NAND Flash Controller on some Freescale
+	  processors like the VF610, MCF54418 or Kinetis K70.
+	  The driver supports a maximum 2k page size. The driver
+	  currently does not support hardware ECC.
+
+choice
+	prompt "Hardware ECC strength"
+	depends on NAND_VF610_NFC
+	default SYS_NAND_VF610_NFC_45_ECC_BYTES
+	help
+	  Select the ECC strength used in the hardware BCH ECC block.
+
+config SYS_NAND_VF610_NFC_45_ECC_BYTES
+	bool "24-error correction (45 ECC bytes)"
+
+config SYS_NAND_VF610_NFC_60_ECC_BYTES
+	bool "32-error correction (60 ECC bytes)"
+
+endchoice
+
+config NAND_PXA3XX
+	bool "Support for NAND on PXA3xx and Armada 370/XP/38x"
+	select SYS_NAND_SELF_INIT
+	imply CMD_NAND
+	help
+	  This enables the driver for the NAND flash device found on
+	  PXA3xx processors (NFCv1) and also on Armada 370/XP (NFCv2).
+
+config NAND_SUNXI
+	bool "Support for NAND on Allwinner SoCs"
+	depends on MACH_SUN4I || MACH_SUN5I || MACH_SUN7I
+	select SYS_NAND_SELF_INIT
+	select SYS_NAND_U_BOOT_LOCATIONS
+	imply CMD_NAND
+	---help---
+	Enable support for NAND. This option enables the standard and
+	SPL drivers.
+	The SPL driver only supports reading from the NAND using DMA
+	transfers.
+
+if NAND_SUNXI
+
+config NAND_SUNXI_SPL_ECC_STRENGTH
+	int "Allwinner NAND SPL ECC Strength"
+	default 64
+
+config NAND_SUNXI_SPL_ECC_SIZE
+	int "Allwinner NAND SPL ECC Step Size"
+	default 1024
+
+config NAND_SUNXI_SPL_USABLE_PAGE_SIZE
+	int "Allwinner NAND SPL Usable Page Size"
+	default 1024
+
+endif
+
+config NAND_ARASAN
+	bool "Configure Arasan Nand"
+	select SYS_NAND_SELF_INIT
+	imply CMD_NAND
+	help
+	  This enables Nand driver support for Arasan nand flash
+	  controller. This uses the hardware ECC for read and
+	  write operations.
+
+config NAND_MXC
+	bool "MXC NAND support"
+	depends on CPU_ARM926EJS || CPU_ARM1136 || MX5
+	imply CMD_NAND
+	help
+	  This enables the NAND driver for the NAND flash controller on the
+	  i.MX27 / i.MX31 / i.MX5 rocessors.
+
+config NAND_MXS
+	bool "MXS NAND support"
+	depends on MX23 || MX28 || MX6 || MX7
+	imply CMD_NAND
+	select APBH_DMA
+	select APBH_DMA_BURST if ARCH_MX6 || ARCH_MX7
+	select APBH_DMA_BURST8 if ARCH_MX6 || ARCH_MX7
+	help
+	  This enables NAND driver for the NAND flash controller on the
+	  MXS processors.
+
+config NAND_ZYNQ
+	bool "Support for Zynq Nand controller"
+	select SYS_NAND_SELF_INIT
+	imply CMD_NAND
+	help
+	  This enables Nand driver support for Nand flash controller
+	  found on Zynq SoC.
+
+config NAND_ZYNQ_USE_BOOTLOADER1_TIMINGS
+	bool "Enable use of 1st stage bootloader timing for NAND"
+	depends on NAND_ZYNQ
+	help
+	  This flag prevent U-boot reconfigure NAND flash controller and reuse
+	  the NAND timing from 1st stage bootloader.
+
+comment "Generic NAND options"
+
+# Enhance depends when converting drivers to Kconfig which use this config
+# option (mxc_nand, ndfc, omap_gpmc).
+config SYS_NAND_BUSWIDTH_16BIT
+	bool "Use 16-bit NAND interface"
+	depends on NAND_VF610_NFC || NAND_OMAP_GPMC || NAND_MXC || ARCH_DAVINCI
+	help
+	  Indicates that NAND device has 16-bit wide data-bus. In absence of this
+	  config, bus-width of NAND device is assumed to be either 8-bit and later
+	  determined by reading ONFI params.
+	  Above config is useful when NAND device's bus-width information cannot
+	  be determined from on-chip ONFI params, like in following scenarios:
+	  - SPL boot does not support reading of ONFI parameters. This is done to
+	    keep SPL code foot-print small.
+	  - In current U-Boot flow using nand_init(), driver initialization
+	    happens in board_nand_init() which is called before any device probe
+	    (nand_scan_ident + nand_scan_tail), thus device's ONFI parameters are
+	    not available while configuring controller. So a static CONFIG_NAND_xx
+	    is needed to know the device's bus-width in advance.
+
+if SPL
+
+config SYS_NAND_U_BOOT_LOCATIONS
+	bool "Define U-boot binaries locations in NAND"
+	help
+	Enable CONFIG_SYS_NAND_U_BOOT_OFFS though Kconfig.
+	This option should not be enabled when compiling U-boot for boards
+	defining CONFIG_SYS_NAND_U_BOOT_OFFS in their include/configs/<board>.h
+	file.
+
+config SYS_NAND_U_BOOT_OFFS
+	hex "Location in NAND to read U-Boot from"
+	default 0x800000 if NAND_SUNXI
+	depends on SYS_NAND_U_BOOT_LOCATIONS
+	help
+	Set the offset from the start of the nand where u-boot should be
+	loaded from.
+
+config SYS_NAND_U_BOOT_OFFS_REDUND
+	hex "Location in NAND to read U-Boot from"
+	default SYS_NAND_U_BOOT_OFFS
+	depends on SYS_NAND_U_BOOT_LOCATIONS
+	help
+	Set the offset from the start of the nand where the redundant u-boot
+	should be loaded from.
+
+config SPL_NAND_AM33XX_BCH
+	bool "Enables SPL-NAND driver which supports ELM based"
+	depends on NAND_OMAP_GPMC && !OMAP34XX
+	default y
+        help
+	  Hardware ECC correction. This is useful for platforms which have ELM
+	  hardware engine and use NAND boot mode.
+	  Some legacy platforms like OMAP3xx do not have in-built ELM h/w engine,
+	  so those platforms should use CONFIG_SPL_NAND_SIMPLE for enabling
+          SPL-NAND driver with software ECC correction support.
+
+config SPL_NAND_DENALI
+	bool "Support Denali NAND controller for SPL"
+	help
+	  This is a small implementation of the Denali NAND controller
+	  for use on SPL.
+
+config SPL_NAND_SIMPLE
+	bool "Use simple SPL NAND driver"
+	depends on !SPL_NAND_AM33XX_BCH
+	help
+	  Support for NAND boot using simple NAND drivers that
+	  expose the cmd_ctrl() interface.
+endif
+
+endif   # if NAND
diff --git a/drivers/mtd/nand/raw/Makefile b/drivers/mtd/nand/raw/Makefile
new file mode 100644
index 0000000000..9f7d9d6ff7
--- /dev/null
+++ b/drivers/mtd/nand/raw/Makefile
@@ -0,0 +1,78 @@
+#
+# (C) Copyright 2006
+# Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+ifdef CONFIG_SPL_BUILD
+
+ifdef CONFIG_SPL_NAND_DRIVERS
+NORMAL_DRIVERS=y
+endif
+
+obj-$(CONFIG_SPL_NAND_AM33XX_BCH) += am335x_spl_bch.o
+obj-$(CONFIG_SPL_NAND_DENALI) += denali_spl.o
+obj-$(CONFIG_SPL_NAND_SIMPLE) += nand_spl_simple.o
+obj-$(CONFIG_SPL_NAND_LOAD) += nand_spl_load.o
+obj-$(CONFIG_SPL_NAND_ECC) += nand_ecc.o
+obj-$(CONFIG_SPL_NAND_BASE) += nand_base.o
+obj-$(CONFIG_SPL_NAND_INIT) += nand.o
+ifeq ($(CONFIG_SPL_ENV_SUPPORT),y)
+obj-$(CONFIG_ENV_IS_IN_NAND) += nand_util.o
+endif
+
+else # not spl
+
+NORMAL_DRIVERS=y
+
+obj-y += nand.o
+obj-y += nand_bbt.o
+obj-y += nand_ids.o
+obj-y += nand_util.o
+obj-y += nand_ecc.o
+obj-y += nand_base.o
+obj-y += nand_timings.o
+
+endif # not spl
+
+ifdef NORMAL_DRIVERS
+
+obj-$(CONFIG_NAND_ECC_BCH) += nand_bch.o
+
+obj-$(CONFIG_NAND_ATMEL) += atmel_nand.o
+obj-$(CONFIG_NAND_ARASAN) += arasan_nfc.o
+obj-$(CONFIG_NAND_DAVINCI) += davinci_nand.o
+obj-$(CONFIG_NAND_DENALI) += denali.o
+obj-$(CONFIG_NAND_DENALI_DT) += denali_dt.o
+obj-$(CONFIG_NAND_FSL_ELBC) += fsl_elbc_nand.o
+obj-$(CONFIG_NAND_FSL_IFC) += fsl_ifc_nand.o
+obj-$(CONFIG_NAND_FSL_UPM) += fsl_upm.o
+obj-$(CONFIG_NAND_FSMC) += fsmc_nand.o
+obj-$(CONFIG_NAND_KB9202) += kb9202_nand.o
+obj-$(CONFIG_NAND_KIRKWOOD) += kirkwood_nand.o
+obj-$(CONFIG_NAND_KMETER1) += kmeter1_nand.o
+obj-$(CONFIG_NAND_LPC32XX_MLC) += lpc32xx_nand_mlc.o
+obj-$(CONFIG_NAND_LPC32XX_SLC) += lpc32xx_nand_slc.o
+obj-$(CONFIG_NAND_VF610_NFC) += vf610_nfc.o
+obj-$(CONFIG_NAND_MXC) += mxc_nand.o
+obj-$(CONFIG_NAND_MXS) += mxs_nand.o
+obj-$(CONFIG_NAND_NDFC) += ndfc.o
+obj-$(CONFIG_NAND_PXA3XX) += pxa3xx_nand.o
+obj-$(CONFIG_NAND_SPEAR) += spr_nand.o
+obj-$(CONFIG_TEGRA_NAND) += tegra_nand.o
+obj-$(CONFIG_NAND_OMAP_GPMC) += omap_gpmc.o
+obj-$(CONFIG_NAND_OMAP_ELM) += omap_elm.o
+obj-$(CONFIG_NAND_PLAT) += nand_plat.o
+obj-$(CONFIG_NAND_SUNXI) += sunxi_nand.o
+obj-$(CONFIG_NAND_ZYNQ) += zynq_nand.o
+
+else  # minimal SPL drivers
+
+obj-$(CONFIG_NAND_FSL_ELBC) += fsl_elbc_spl.o
+obj-$(CONFIG_NAND_FSL_IFC) += fsl_ifc_spl.o
+obj-$(CONFIG_NAND_MXC) += mxc_nand_spl.o
+obj-$(CONFIG_NAND_MXS) += mxs_nand_spl.o mxs_nand.o
+obj-$(CONFIG_NAND_SUNXI) += sunxi_nand_spl.o
+
+endif # drivers
diff --git a/drivers/mtd/nand/am335x_spl_bch.c b/drivers/mtd/nand/raw/am335x_spl_bch.c
similarity index 100%
rename from drivers/mtd/nand/am335x_spl_bch.c
rename to drivers/mtd/nand/raw/am335x_spl_bch.c
diff --git a/drivers/mtd/nand/arasan_nfc.c b/drivers/mtd/nand/raw/arasan_nfc.c
similarity index 100%
rename from drivers/mtd/nand/arasan_nfc.c
rename to drivers/mtd/nand/raw/arasan_nfc.c
diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/raw/atmel_nand.c
similarity index 100%
rename from drivers/mtd/nand/atmel_nand.c
rename to drivers/mtd/nand/raw/atmel_nand.c
diff --git a/drivers/mtd/nand/atmel_nand_ecc.h b/drivers/mtd/nand/raw/atmel_nand_ecc.h
similarity index 100%
rename from drivers/mtd/nand/atmel_nand_ecc.h
rename to drivers/mtd/nand/raw/atmel_nand_ecc.h
diff --git a/drivers/mtd/nand/davinci_nand.c b/drivers/mtd/nand/raw/davinci_nand.c
similarity index 100%
rename from drivers/mtd/nand/davinci_nand.c
rename to drivers/mtd/nand/raw/davinci_nand.c
diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/raw/denali.c
similarity index 100%
rename from drivers/mtd/nand/denali.c
rename to drivers/mtd/nand/raw/denali.c
diff --git a/drivers/mtd/nand/denali.h b/drivers/mtd/nand/raw/denali.h
similarity index 100%
rename from drivers/mtd/nand/denali.h
rename to drivers/mtd/nand/raw/denali.h
diff --git a/drivers/mtd/nand/denali_dt.c b/drivers/mtd/nand/raw/denali_dt.c
similarity index 100%
rename from drivers/mtd/nand/denali_dt.c
rename to drivers/mtd/nand/raw/denali_dt.c
diff --git a/drivers/mtd/nand/denali_spl.c b/drivers/mtd/nand/raw/denali_spl.c
similarity index 100%
rename from drivers/mtd/nand/denali_spl.c
rename to drivers/mtd/nand/raw/denali_spl.c
diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/raw/fsl_elbc_nand.c
similarity index 100%
rename from drivers/mtd/nand/fsl_elbc_nand.c
rename to drivers/mtd/nand/raw/fsl_elbc_nand.c
diff --git a/drivers/mtd/nand/fsl_elbc_spl.c b/drivers/mtd/nand/raw/fsl_elbc_spl.c
similarity index 100%
rename from drivers/mtd/nand/fsl_elbc_spl.c
rename to drivers/mtd/nand/raw/fsl_elbc_spl.c
diff --git a/drivers/mtd/nand/fsl_ifc_nand.c b/drivers/mtd/nand/raw/fsl_ifc_nand.c
similarity index 100%
rename from drivers/mtd/nand/fsl_ifc_nand.c
rename to drivers/mtd/nand/raw/fsl_ifc_nand.c
diff --git a/drivers/mtd/nand/fsl_ifc_spl.c b/drivers/mtd/nand/raw/fsl_ifc_spl.c
similarity index 100%
rename from drivers/mtd/nand/fsl_ifc_spl.c
rename to drivers/mtd/nand/raw/fsl_ifc_spl.c
diff --git a/drivers/mtd/nand/fsl_upm.c b/drivers/mtd/nand/raw/fsl_upm.c
similarity index 100%
rename from drivers/mtd/nand/fsl_upm.c
rename to drivers/mtd/nand/raw/fsl_upm.c
diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/raw/fsmc_nand.c
similarity index 100%
rename from drivers/mtd/nand/fsmc_nand.c
rename to drivers/mtd/nand/raw/fsmc_nand.c
diff --git a/drivers/mtd/nand/kb9202_nand.c b/drivers/mtd/nand/raw/kb9202_nand.c
similarity index 100%
rename from drivers/mtd/nand/kb9202_nand.c
rename to drivers/mtd/nand/raw/kb9202_nand.c
diff --git a/drivers/mtd/nand/kirkwood_nand.c b/drivers/mtd/nand/raw/kirkwood_nand.c
similarity index 100%
rename from drivers/mtd/nand/kirkwood_nand.c
rename to drivers/mtd/nand/raw/kirkwood_nand.c
diff --git a/drivers/mtd/nand/kmeter1_nand.c b/drivers/mtd/nand/raw/kmeter1_nand.c
similarity index 100%
rename from drivers/mtd/nand/kmeter1_nand.c
rename to drivers/mtd/nand/raw/kmeter1_nand.c
diff --git a/drivers/mtd/nand/lpc32xx_nand_mlc.c b/drivers/mtd/nand/raw/lpc32xx_nand_mlc.c
similarity index 100%
rename from drivers/mtd/nand/lpc32xx_nand_mlc.c
rename to drivers/mtd/nand/raw/lpc32xx_nand_mlc.c
diff --git a/drivers/mtd/nand/lpc32xx_nand_slc.c b/drivers/mtd/nand/raw/lpc32xx_nand_slc.c
similarity index 100%
rename from drivers/mtd/nand/lpc32xx_nand_slc.c
rename to drivers/mtd/nand/raw/lpc32xx_nand_slc.c
diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/raw/mxc_nand.c
similarity index 100%
rename from drivers/mtd/nand/mxc_nand.c
rename to drivers/mtd/nand/raw/mxc_nand.c
diff --git a/drivers/mtd/nand/mxc_nand.h b/drivers/mtd/nand/raw/mxc_nand.h
similarity index 100%
rename from drivers/mtd/nand/mxc_nand.h
rename to drivers/mtd/nand/raw/mxc_nand.h
diff --git a/drivers/mtd/nand/mxc_nand_spl.c b/drivers/mtd/nand/raw/mxc_nand_spl.c
similarity index 100%
rename from drivers/mtd/nand/mxc_nand_spl.c
rename to drivers/mtd/nand/raw/mxc_nand_spl.c
diff --git a/drivers/mtd/nand/mxs_nand.c b/drivers/mtd/nand/raw/mxs_nand.c
similarity index 100%
rename from drivers/mtd/nand/mxs_nand.c
rename to drivers/mtd/nand/raw/mxs_nand.c
diff --git a/drivers/mtd/nand/mxs_nand_spl.c b/drivers/mtd/nand/raw/mxs_nand_spl.c
similarity index 100%
rename from drivers/mtd/nand/mxs_nand_spl.c
rename to drivers/mtd/nand/raw/mxs_nand_spl.c
diff --git a/drivers/mtd/nand/nand.c b/drivers/mtd/nand/raw/nand.c
similarity index 100%
rename from drivers/mtd/nand/nand.c
rename to drivers/mtd/nand/raw/nand.c
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/raw/nand_base.c
similarity index 100%
rename from drivers/mtd/nand/nand_base.c
rename to drivers/mtd/nand/raw/nand_base.c
diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/raw/nand_bbt.c
similarity index 100%
rename from drivers/mtd/nand/nand_bbt.c
rename to drivers/mtd/nand/raw/nand_bbt.c
diff --git a/drivers/mtd/nand/nand_bch.c b/drivers/mtd/nand/raw/nand_bch.c
similarity index 100%
rename from drivers/mtd/nand/nand_bch.c
rename to drivers/mtd/nand/raw/nand_bch.c
diff --git a/drivers/mtd/nand/nand_ecc.c b/drivers/mtd/nand/raw/nand_ecc.c
similarity index 100%
rename from drivers/mtd/nand/nand_ecc.c
rename to drivers/mtd/nand/raw/nand_ecc.c
diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/raw/nand_ids.c
similarity index 100%
rename from drivers/mtd/nand/nand_ids.c
rename to drivers/mtd/nand/raw/nand_ids.c
diff --git a/drivers/mtd/nand/nand_plat.c b/drivers/mtd/nand/raw/nand_plat.c
similarity index 100%
rename from drivers/mtd/nand/nand_plat.c
rename to drivers/mtd/nand/raw/nand_plat.c
diff --git a/drivers/mtd/nand/nand_spl_load.c b/drivers/mtd/nand/raw/nand_spl_load.c
similarity index 100%
rename from drivers/mtd/nand/nand_spl_load.c
rename to drivers/mtd/nand/raw/nand_spl_load.c
diff --git a/drivers/mtd/nand/nand_spl_loaders.c b/drivers/mtd/nand/raw/nand_spl_loaders.c
similarity index 100%
rename from drivers/mtd/nand/nand_spl_loaders.c
rename to drivers/mtd/nand/raw/nand_spl_loaders.c
diff --git a/drivers/mtd/nand/nand_spl_simple.c b/drivers/mtd/nand/raw/nand_spl_simple.c
similarity index 100%
rename from drivers/mtd/nand/nand_spl_simple.c
rename to drivers/mtd/nand/raw/nand_spl_simple.c
diff --git a/drivers/mtd/nand/nand_timings.c b/drivers/mtd/nand/raw/nand_timings.c
similarity index 100%
rename from drivers/mtd/nand/nand_timings.c
rename to drivers/mtd/nand/raw/nand_timings.c
diff --git a/drivers/mtd/nand/nand_util.c b/drivers/mtd/nand/raw/nand_util.c
similarity index 100%
rename from drivers/mtd/nand/nand_util.c
rename to drivers/mtd/nand/raw/nand_util.c
diff --git a/drivers/mtd/nand/ndfc.c b/drivers/mtd/nand/raw/ndfc.c
similarity index 100%
rename from drivers/mtd/nand/ndfc.c
rename to drivers/mtd/nand/raw/ndfc.c
diff --git a/drivers/mtd/nand/omap_elm.c b/drivers/mtd/nand/raw/omap_elm.c
similarity index 100%
rename from drivers/mtd/nand/omap_elm.c
rename to drivers/mtd/nand/raw/omap_elm.c
diff --git a/drivers/mtd/nand/omap_gpmc.c b/drivers/mtd/nand/raw/omap_gpmc.c
similarity index 100%
rename from drivers/mtd/nand/omap_gpmc.c
rename to drivers/mtd/nand/raw/omap_gpmc.c
diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/raw/pxa3xx_nand.c
similarity index 100%
rename from drivers/mtd/nand/pxa3xx_nand.c
rename to drivers/mtd/nand/raw/pxa3xx_nand.c
diff --git a/drivers/mtd/nand/pxa3xx_nand.h b/drivers/mtd/nand/raw/pxa3xx_nand.h
similarity index 100%
rename from drivers/mtd/nand/pxa3xx_nand.h
rename to drivers/mtd/nand/raw/pxa3xx_nand.h
diff --git a/drivers/mtd/nand/sunxi_nand.c b/drivers/mtd/nand/raw/sunxi_nand.c
similarity index 100%
rename from drivers/mtd/nand/sunxi_nand.c
rename to drivers/mtd/nand/raw/sunxi_nand.c
diff --git a/drivers/mtd/nand/sunxi_nand_spl.c b/drivers/mtd/nand/raw/sunxi_nand_spl.c
similarity index 100%
rename from drivers/mtd/nand/sunxi_nand_spl.c
rename to drivers/mtd/nand/raw/sunxi_nand_spl.c
diff --git a/drivers/mtd/nand/tegra_nand.c b/drivers/mtd/nand/raw/tegra_nand.c
similarity index 100%
rename from drivers/mtd/nand/tegra_nand.c
rename to drivers/mtd/nand/raw/tegra_nand.c
diff --git a/drivers/mtd/nand/tegra_nand.h b/drivers/mtd/nand/raw/tegra_nand.h
similarity index 100%
rename from drivers/mtd/nand/tegra_nand.h
rename to drivers/mtd/nand/raw/tegra_nand.h
diff --git a/drivers/mtd/nand/vf610_nfc.c b/drivers/mtd/nand/raw/vf610_nfc.c
similarity index 100%
rename from drivers/mtd/nand/vf610_nfc.c
rename to drivers/mtd/nand/raw/vf610_nfc.c
diff --git a/drivers/mtd/nand/zynq_nand.c b/drivers/mtd/nand/raw/zynq_nand.c
similarity index 100%
rename from drivers/mtd/nand/zynq_nand.c
rename to drivers/mtd/nand/raw/zynq_nand.c
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [U-Boot] [RFC PATCH 07/20] mtd: rename nand into rawnand in Kconfig prompt
  2018-06-06 15:30 [U-Boot] [RFC PATCH 00/20] SPI-NAND support Miquel Raynal
                   ` (5 preceding siblings ...)
  2018-06-06 15:30 ` [U-Boot] [RFC PATCH 06/20] mtd: move NAND fiels into a raw/ subdirectory Miquel Raynal
@ 2018-06-06 15:30 ` Miquel Raynal
  2018-06-06 15:30 ` [U-Boot] [RFC PATCH 08/20] mtd: nand: Add core infrastructure to deal with NAND devices Miquel Raynal
                   ` (15 subsequent siblings)
  22 siblings, 0 replies; 65+ messages in thread
From: Miquel Raynal @ 2018-06-06 15:30 UTC (permalink / raw)
  To: u-boot

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

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 drivers/mtd/nand/raw/Kconfig | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig
index a820af61ce..6ef82cab88 100644
--- a/drivers/mtd/nand/raw/Kconfig
+++ b/drivers/mtd/nand/raw/Kconfig
@@ -1,6 +1,6 @@
 
 menuconfig NAND
-	bool "NAND Device Support"
+	bool "Raw NAND Device Support"
 if NAND
 
 config SYS_NAND_SELF_INIT
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [U-Boot] [RFC PATCH 08/20] mtd: nand: Add core infrastructure to deal with NAND devices
  2018-06-06 15:30 [U-Boot] [RFC PATCH 00/20] SPI-NAND support Miquel Raynal
                   ` (6 preceding siblings ...)
  2018-06-06 15:30 ` [U-Boot] [RFC PATCH 07/20] mtd: rename nand into rawnand in Kconfig prompt Miquel Raynal
@ 2018-06-06 15:30 ` Miquel Raynal
  2018-06-27 11:08   ` Jagan Teki
  2018-06-06 15:30 ` [U-Boot] [RFC PATCH 09/20] mtd: nand: Pass mode information to nand_page_io_req Miquel Raynal
                   ` (14 subsequent siblings)
  22 siblings, 1 reply; 65+ messages in thread
From: Miquel Raynal @ 2018-06-06 15:30 UTC (permalink / raw)
  To: u-boot

From: Boris Brezillon <boris.brezillon@bootlin.com>

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

Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 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

diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index 6d53734718..1c1a1f487e 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -1 +1,4 @@
+config MTD_NAND_CORE
+	tristate
+
 source "drivers/mtd/nand/raw/Kconfig"
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index d1c3f93047..69c80ea252 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -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/
diff --git a/drivers/mtd/nand/bbt.c b/drivers/mtd/nand/bbt.c
new file mode 100644
index 0000000000..7e0ad3190c
--- /dev/null
+++ b/drivers/mtd/nand/bbt.c
@@ -0,0 +1,132 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2017 Free Electrons
+ *
+ * Authors:
+ *	Boris Brezillon <boris.brezillon@free-electrons.com>
+ *	Peter Pan <peterpandong@micron.com>
+ */
+
+#define pr_fmt(fmt)	"nand-bbt: " fmt
+
+#include <linux/mtd/nand.h>
+#ifndef __UBOOT__
+#include <linux/slab.h>
+#endif
+
+/**
+ * nanddev_bbt_init() - Initialize the BBT (Bad Block Table)
+ * @nand: NAND device
+ *
+ * Initialize the in-memory BBT.
+ *
+ * Return: 0 in case of success, a negative error code otherwise.
+ */
+int nanddev_bbt_init(struct nand_device *nand)
+{
+	unsigned int bits_per_block = fls(NAND_BBT_BLOCK_NUM_STATUS);
+	unsigned int nblocks = nanddev_neraseblocks(nand);
+	unsigned int nwords = DIV_ROUND_UP(nblocks * bits_per_block,
+					   BITS_PER_LONG);
+
+	nand->bbt.cache = kzalloc(nwords, GFP_KERNEL);
+	if (!nand->bbt.cache)
+		return -ENOMEM;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(nanddev_bbt_init);
+
+/**
+ * nanddev_bbt_cleanup() - Cleanup the BBT (Bad Block Table)
+ * @nand: NAND device
+ *
+ * Undoes what has been done in nanddev_bbt_init()
+ */
+void nanddev_bbt_cleanup(struct nand_device *nand)
+{
+	kfree(nand->bbt.cache);
+}
+EXPORT_SYMBOL_GPL(nanddev_bbt_cleanup);
+
+/**
+ * nanddev_bbt_update() - Update a BBT
+ * @nand: nand device
+ *
+ * Update the BBT. Currently a NOP function since on-flash bbt is not yet
+ * supported.
+ *
+ * Return: 0 in case of success, a negative error code otherwise.
+ */
+int nanddev_bbt_update(struct nand_device *nand)
+{
+	return 0;
+}
+EXPORT_SYMBOL_GPL(nanddev_bbt_update);
+
+/**
+ * nanddev_bbt_get_block_status() - Return the status of an eraseblock
+ * @nand: nand device
+ * @entry: the BBT entry
+ *
+ * Return: a positive number nand_bbt_block_status status or -%ERANGE if @entry
+ *	   is bigger than the BBT size.
+ */
+int nanddev_bbt_get_block_status(const struct nand_device *nand,
+				 unsigned int entry)
+{
+	unsigned int bits_per_block = fls(NAND_BBT_BLOCK_NUM_STATUS);
+	unsigned long *pos = nand->bbt.cache +
+			     ((entry * bits_per_block) / BITS_PER_LONG);
+	unsigned int offs = (entry * bits_per_block) % BITS_PER_LONG;
+	unsigned long status;
+
+	if (entry >= nanddev_neraseblocks(nand))
+		return -ERANGE;
+
+	status = pos[0] >> offs;
+	if (bits_per_block + offs > BITS_PER_LONG)
+		status |= pos[1] << (BITS_PER_LONG - offs);
+
+	return status & GENMASK(bits_per_block - 1, 0);
+}
+EXPORT_SYMBOL_GPL(nanddev_bbt_get_block_status);
+
+/**
+ * nanddev_bbt_set_block_status() - Update the status of an eraseblock in the
+ *				    in-memory BBT
+ * @nand: nand device
+ * @entry: the BBT entry to update
+ * @status: the new status
+ *
+ * Update an entry of the in-memory BBT. If you want to push the updated BBT
+ * the NAND you should call nanddev_bbt_update().
+ *
+ * Return: 0 in case of success or -%ERANGE if @entry is bigger than the BBT
+ *	   size.
+ */
+int nanddev_bbt_set_block_status(struct nand_device *nand, unsigned int entry,
+				 enum nand_bbt_block_status status)
+{
+	unsigned int bits_per_block = fls(NAND_BBT_BLOCK_NUM_STATUS);
+	unsigned long *pos = nand->bbt.cache +
+			     ((entry * bits_per_block) / BITS_PER_LONG);
+	unsigned int offs = (entry * bits_per_block) % BITS_PER_LONG;
+	unsigned long val = status & GENMASK(bits_per_block - 1, 0);
+
+	if (entry >= nanddev_neraseblocks(nand))
+		return -ERANGE;
+
+	pos[0] &= ~GENMASK(offs + bits_per_block - 1, offs);
+	pos[0] |= val << offs;
+
+	if (bits_per_block + offs > BITS_PER_LONG) {
+		unsigned int rbits = bits_per_block + offs - BITS_PER_LONG;
+
+		pos[1] &= ~GENMASK(rbits - 1, 0);
+		pos[1] |= val >> rbits;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(nanddev_bbt_set_block_status);
diff --git a/drivers/mtd/nand/core.c b/drivers/mtd/nand/core.c
new file mode 100644
index 0000000000..0b793695cc
--- /dev/null
+++ b/drivers/mtd/nand/core.c
@@ -0,0 +1,243 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2017 Free Electrons
+ *
+ * Authors:
+ *	Boris Brezillon <boris.brezillon@free-electrons.com>
+ *	Peter Pan <peterpandong@micron.com>
+ */
+
+#define pr_fmt(fmt)	"nand: " fmt
+
+#ifndef __UBOOT__
+#include <linux/module.h>
+#endif
+#include <linux/mtd/nand.h>
+
+/**
+ * nanddev_isbad() - Check if a block is bad
+ * @nand: NAND device
+ * @pos: position pointing to the block we want to check
+ *
+ * Return: true if the block is bad, false otherwise.
+ */
+bool nanddev_isbad(struct nand_device *nand, const struct nand_pos *pos)
+{
+	if (nanddev_bbt_is_initialized(nand)) {
+		unsigned int entry;
+		int status;
+
+		entry = nanddev_bbt_pos_to_entry(nand, pos);
+		status = nanddev_bbt_get_block_status(nand, entry);
+		/* Lazy block status retrieval */
+		if (status == NAND_BBT_BLOCK_STATUS_UNKNOWN) {
+			if (nand->ops->isbad(nand, pos))
+				status = NAND_BBT_BLOCK_FACTORY_BAD;
+			else
+				status = NAND_BBT_BLOCK_GOOD;
+
+			nanddev_bbt_set_block_status(nand, entry, status);
+		}
+
+		if (status == NAND_BBT_BLOCK_WORN ||
+		    status == NAND_BBT_BLOCK_FACTORY_BAD)
+			return true;
+
+		return false;
+	}
+
+	return nand->ops->isbad(nand, pos);
+}
+EXPORT_SYMBOL_GPL(nanddev_isbad);
+
+/**
+ * nanddev_markbad() - Mark a block as bad
+ * @nand: NAND device
+ * @pos: position of the block to mark bad
+ *
+ * Mark a block bad. This function is updating the BBT if available and
+ * calls the low-level markbad hook (nand->ops->markbad()).
+ *
+ * Return: 0 in case of success, a negative error code otherwise.
+ */
+int nanddev_markbad(struct nand_device *nand, const struct nand_pos *pos)
+{
+	struct mtd_info *mtd = nanddev_to_mtd(nand);
+	unsigned int entry;
+	int ret = 0;
+
+	if (nanddev_isbad(nand, pos))
+		return 0;
+
+	ret = nand->ops->markbad(nand, pos);
+	if (ret)
+		pr_warn("failed to write BBM to block @%llx (err = %d)\n",
+			nanddev_pos_to_offs(nand, pos), ret);
+
+	if (!nanddev_bbt_is_initialized(nand))
+		goto out;
+
+	entry = nanddev_bbt_pos_to_entry(nand, pos);
+	ret = nanddev_bbt_set_block_status(nand, entry, NAND_BBT_BLOCK_WORN);
+	if (ret)
+		goto out;
+
+	ret = nanddev_bbt_update(nand);
+
+out:
+	if (!ret)
+		mtd->ecc_stats.badblocks++;
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(nanddev_markbad);
+
+/**
+ * nanddev_isreserved() - Check whether an eraseblock is reserved or not
+ * @nand: NAND device
+ * @pos: NAND position to test
+ *
+ * Checks whether the eraseblock pointed by @pos is reserved or not.
+ *
+ * Return: true if the eraseblock is reserved, false otherwise.
+ */
+bool nanddev_isreserved(struct nand_device *nand, const struct nand_pos *pos)
+{
+	unsigned int entry;
+	int status;
+
+	if (!nanddev_bbt_is_initialized(nand))
+		return false;
+
+	/* Return info from the table */
+	entry = nanddev_bbt_pos_to_entry(nand, pos);
+	status = nanddev_bbt_get_block_status(nand, entry);
+	return status == NAND_BBT_BLOCK_RESERVED;
+}
+EXPORT_SYMBOL_GPL(nanddev_isreserved);
+
+/**
+ * nanddev_erase() - Erase a NAND portion
+ * @nand: NAND device
+ * @pos: position of the block to erase
+ *
+ * Erases the block if it's not bad.
+ *
+ * Return: 0 in case of success, a negative error code otherwise.
+ */
+int nanddev_erase(struct nand_device *nand, const struct nand_pos *pos)
+{
+	if (nanddev_isbad(nand, pos) || nanddev_isreserved(nand, pos)) {
+		pr_warn("attempt to erase a bad/reserved block @%llx\n",
+			nanddev_pos_to_offs(nand, pos));
+		return -EIO;
+	}
+
+	return nand->ops->erase(nand, pos);
+}
+EXPORT_SYMBOL_GPL(nanddev_erase);
+
+/**
+ * nanddev_mtd_erase() - Generic mtd->_erase() implementation for NAND devices
+ * @mtd: MTD device
+ * @einfo: erase request
+ *
+ * This is a simple mtd->_erase() implementation iterating over all blocks
+ * concerned by @einfo and calling nand->ops->erase() on each of them.
+ *
+ * Note that mtd->_erase should not be directly assigned to this helper,
+ * because there's no locking here. NAND specialized layers should instead
+ * implement there own wrapper around nanddev_mtd_erase() taking the
+ * appropriate lock before calling nanddev_mtd_erase().
+ *
+ * Return: 0 in case of success, a negative error code otherwise.
+ */
+int nanddev_mtd_erase(struct mtd_info *mtd, struct erase_info *einfo)
+{
+	struct nand_device *nand = mtd_to_nanddev(mtd);
+	struct nand_pos pos, last;
+	int ret;
+
+	nanddev_offs_to_pos(nand, einfo->addr, &pos);
+	nanddev_offs_to_pos(nand, einfo->addr + einfo->len - 1, &last);
+	while (nanddev_pos_cmp(&pos, &last) <= 0) {
+		ret = nanddev_erase(nand, &pos);
+		if (ret) {
+			einfo->fail_addr = nanddev_pos_to_offs(nand, &pos);
+
+			return ret;
+		}
+
+		nanddev_pos_next_eraseblock(nand, &pos);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(nanddev_mtd_erase);
+
+/**
+ * nanddev_init() - Initialize a NAND device
+ * @nand: NAND device
+ * @ops: NAND device operations
+ * @owner: NAND device owner
+ *
+ * Initializes a NAND device object. Consistency checks are done on @ops and
+ * @nand->memorg. Also takes care of initializing the BBT.
+ *
+ * Return: 0 in case of success, a negative error code otherwise.
+ */
+int nanddev_init(struct nand_device *nand, const struct nand_ops *ops,
+		 struct module *owner)
+{
+	struct mtd_info *mtd = nanddev_to_mtd(nand);
+	struct nand_memory_organization *memorg = nanddev_get_memorg(nand);
+
+	if (!nand || !ops)
+		return -EINVAL;
+
+	if (!ops->erase || !ops->markbad || !ops->isbad)
+		return -EINVAL;
+
+	if (!memorg->bits_per_cell || !memorg->pagesize ||
+	    !memorg->pages_per_eraseblock || !memorg->eraseblocks_per_lun ||
+	    !memorg->planes_per_lun || !memorg->luns_per_target ||
+	    !memorg->ntargets)
+		return -EINVAL;
+
+	nand->rowconv.eraseblock_addr_shift =
+					fls(memorg->pages_per_eraseblock - 1);
+	nand->rowconv.lun_addr_shift = fls(memorg->eraseblocks_per_lun - 1) +
+				       nand->rowconv.eraseblock_addr_shift;
+
+	nand->ops = ops;
+
+	mtd->type = memorg->bits_per_cell == 1 ?
+		    MTD_NANDFLASH : MTD_MLCNANDFLASH;
+	mtd->flags = MTD_CAP_NANDFLASH;
+	mtd->erasesize = memorg->pagesize * memorg->pages_per_eraseblock;
+	mtd->writesize = memorg->pagesize;
+	mtd->writebufsize = memorg->pagesize;
+	mtd->oobsize = memorg->oobsize;
+	mtd->size = nanddev_size(nand);
+	mtd->owner = owner;
+
+	return nanddev_bbt_init(nand);
+}
+EXPORT_SYMBOL_GPL(nanddev_init);
+
+/**
+ * nanddev_cleanup() - Release resources allocated in nanddev_init()
+ * @nand: NAND device
+ *
+ * Basically undoes what has been done in nanddev_init().
+ */
+void nanddev_cleanup(struct nand_device *nand)
+{
+	if (nanddev_bbt_is_initialized(nand))
+		nanddev_bbt_cleanup(nand);
+}
+EXPORT_SYMBOL_GPL(nanddev_cleanup);
+
+MODULE_DESCRIPTION("Generic NAND framework");
+MODULE_AUTHOR("Boris Brezillon <boris.brezillon@free-electrons.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
new file mode 100644
index 0000000000..ada7af4a41
--- /dev/null
+++ b/include/linux/mtd/nand.h
@@ -0,0 +1,731 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ *  Copyright 2017 - Free Electrons
+ *
+ *  Authors:
+ *	Boris Brezillon <boris.brezillon@free-electrons.com>
+ *	Peter Pan <peterpandong@micron.com>
+ */
+
+#ifndef __LINUX_MTD_NAND_H
+#define __LINUX_MTD_NAND_H
+
+#include <linux/mtd/mtd.h>
+
+/**
+ * struct nand_memory_organization - Memory organization structure
+ * @bits_per_cell: number of bits per NAND cell
+ * @pagesize: page size
+ * @oobsize: OOB area size
+ * @pages_per_eraseblock: number of pages per eraseblock
+ * @eraseblocks_per_lun: number of eraseblocks per LUN (Logical Unit Number)
+ * @planes_per_lun: number of planes per LUN
+ * @luns_per_target: number of LUN per target (target is a synonym for die)
+ * @ntargets: total number of targets exposed by the NAND device
+ */
+struct nand_memory_organization {
+	unsigned int bits_per_cell;
+	unsigned int pagesize;
+	unsigned int oobsize;
+	unsigned int pages_per_eraseblock;
+	unsigned int eraseblocks_per_lun;
+	unsigned int planes_per_lun;
+	unsigned int luns_per_target;
+	unsigned int ntargets;
+};
+
+#define NAND_MEMORG(bpc, ps, os, ppe, epl, ppl, lpt, nt)	\
+	{							\
+		.bits_per_cell = (bpc),				\
+		.pagesize = (ps),				\
+		.oobsize = (os),				\
+		.pages_per_eraseblock = (ppe),			\
+		.eraseblocks_per_lun = (epl),			\
+		.planes_per_lun = (ppl),			\
+		.luns_per_target = (lpt),			\
+		.ntargets = (nt),				\
+	}
+
+/**
+ * struct nand_row_converter - Information needed to convert an absolute offset
+ *			       into a row address
+ * @lun_addr_shift: position of the LUN identifier in the row address
+ * @eraseblock_addr_shift: position of the eraseblock identifier in the row
+ *			   address
+ */
+struct nand_row_converter {
+	unsigned int lun_addr_shift;
+	unsigned int eraseblock_addr_shift;
+};
+
+/**
+ * struct nand_pos - NAND position object
+ * @target: the NAND target/die
+ * @lun: the LUN identifier
+ * @plane: the plane within the LUN
+ * @eraseblock: the eraseblock within the LUN
+ * @page: the page within the LUN
+ *
+ * These information are usually used by specific sub-layers to select the
+ * appropriate target/die and generate a row address to pass to the device.
+ */
+struct nand_pos {
+	unsigned int target;
+	unsigned int lun;
+	unsigned int plane;
+	unsigned int eraseblock;
+	unsigned int page;
+};
+
+/**
+ * struct nand_page_io_req - NAND I/O request object
+ * @pos: the position this I/O request is targeting
+ * @dataoffs: the offset within the page
+ * @datalen: number of data bytes to read from/write to this page
+ * @databuf: buffer to store data in or get data from
+ * @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
+ *
+ * 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
+ * specific NAND layers can focus on translating these information into
+ * specific commands/operations.
+ */
+struct nand_page_io_req {
+	struct nand_pos pos;
+	unsigned int dataoffs;
+	unsigned int datalen;
+	union {
+		const void *out;
+		void *in;
+	} databuf;
+	unsigned int ooboffs;
+	unsigned int ooblen;
+	union {
+		const void *out;
+		void *in;
+	} oobbuf;
+};
+
+/**
+ * struct nand_ecc_req - NAND ECC requirements
+ * @strength: ECC strength
+ * @step_size: ECC step/block size
+ */
+struct nand_ecc_req {
+	unsigned int strength;
+	unsigned int step_size;
+};
+
+#define NAND_ECCREQ(str, stp) { .strength = (str), .step_size = (stp) }
+
+/**
+ * struct nand_bbt - bad block table object
+ * @cache: in memory BBT cache
+ */
+struct nand_bbt {
+	unsigned long *cache;
+};
+
+struct nand_device;
+
+/**
+ * struct nand_ops - NAND operations
+ * @erase: erase a specific block. No need to check if the block is bad before
+ *	   erasing, this has been taken care of by the generic NAND layer
+ * @markbad: mark a specific block bad. No need to check if the block is
+ *	     already marked bad, this has been taken care of by the generic
+ *	     NAND layer. This method should just write the BBM (Bad Block
+ *	     Marker) so that future call to struct_nand_ops->isbad() return
+ *	     true
+ * @isbad: check whether a block is bad or not. This method should just read
+ *	   the BBM and return whether the block is bad or not based on what it
+ *	   reads
+ *
+ * These are all low level operations that should be implemented by specialized
+ * NAND layers (SPI NAND, raw NAND, ...).
+ */
+struct nand_ops {
+	int (*erase)(struct nand_device *nand, const struct nand_pos *pos);
+	int (*markbad)(struct nand_device *nand, const struct nand_pos *pos);
+	bool (*isbad)(struct nand_device *nand, const struct nand_pos *pos);
+};
+
+/**
+ * struct nand_device - NAND device
+ * @mtd: MTD instance attached to the NAND device
+ * @memorg: memory layout
+ * @eccreq: ECC requirements
+ * @rowconv: position to row address converter
+ * @bbt: bad block table info
+ * @ops: NAND operations attached to the NAND device
+ *
+ * Generic NAND object. Specialized NAND layers (raw NAND, SPI NAND, OneNAND)
+ * should declare their own NAND object embedding a nand_device struct (that's
+ * how inheritance is done).
+ * struct_nand_device->memorg and struct_nand_device->eccreq should be filled
+ * at device detection time to reflect the NAND device
+ * capabilities/requirements. Once this is done nanddev_init() can be called.
+ * It will take care of converting NAND information into MTD ones, which means
+ * the specialized NAND layers should never manually tweak
+ * struct_nand_device->mtd except for the ->_read/write() hooks.
+ */
+struct nand_device {
+	struct mtd_info *mtd;
+	struct nand_memory_organization memorg;
+	struct nand_ecc_req eccreq;
+	struct nand_row_converter rowconv;
+	struct nand_bbt bbt;
+	const struct nand_ops *ops;
+};
+
+/**
+ * struct nand_io_iter - NAND I/O iterator
+ * @req: current I/O request
+ * @oobbytes_per_page: maximum number of OOB bytes per page
+ * @dataleft: remaining number of data bytes to read/write
+ * @oobleft: remaining number of OOB bytes to read/write
+ *
+ * Can be used by specialized NAND layers to iterate over all pages covered
+ * by an MTD I/O request, which should greatly simplifies the boiler-plate
+ * code needed to read/write data from/to a NAND device.
+ */
+struct nand_io_iter {
+	struct nand_page_io_req req;
+	unsigned int oobbytes_per_page;
+	unsigned int dataleft;
+	unsigned int oobleft;
+};
+
+/**
+ * mtd_to_nanddev() - Get the NAND device attached to the MTD instance
+ * @mtd: MTD instance
+ *
+ * Return: the NAND device embedding @mtd.
+ */
+static inline struct nand_device *mtd_to_nanddev(struct mtd_info *mtd)
+{
+	return mtd->priv;
+}
+
+/**
+ * nanddev_to_mtd() - Get the MTD device attached to a NAND device
+ * @nand: NAND device
+ *
+ * Return: the MTD device embedded in @nand.
+ */
+static inline struct mtd_info *nanddev_to_mtd(struct nand_device *nand)
+{
+	return nand->mtd;
+}
+
+/*
+ * nanddev_bits_per_cell() - Get the number of bits per cell
+ * @nand: NAND device
+ *
+ * Return: the number of bits per cell.
+ */
+static inline unsigned int nanddev_bits_per_cell(const struct nand_device *nand)
+{
+	return nand->memorg.bits_per_cell;
+}
+
+/**
+ * nanddev_page_size() - Get NAND page size
+ * @nand: NAND device
+ *
+ * Return: the page size.
+ */
+static inline size_t nanddev_page_size(const struct nand_device *nand)
+{
+	return nand->memorg.pagesize;
+}
+
+/**
+ * nanddev_per_page_oobsize() - Get NAND OOB size
+ * @nand: NAND device
+ *
+ * Return: the OOB size.
+ */
+static inline unsigned int
+nanddev_per_page_oobsize(const struct nand_device *nand)
+{
+	return nand->memorg.oobsize;
+}
+
+/**
+ * nanddev_pages_per_eraseblock() - Get the number of pages per eraseblock
+ * @nand: NAND device
+ *
+ * Return: the number of pages per eraseblock.
+ */
+static inline unsigned int
+nanddev_pages_per_eraseblock(const struct nand_device *nand)
+{
+	return nand->memorg.pages_per_eraseblock;
+}
+
+/**
+ * nanddev_per_page_oobsize() - Get NAND erase block size
+ * @nand: NAND device
+ *
+ * Return: the eraseblock size.
+ */
+static inline size_t nanddev_eraseblock_size(const struct nand_device *nand)
+{
+	return nand->memorg.pagesize * nand->memorg.pages_per_eraseblock;
+}
+
+/**
+ * nanddev_eraseblocks_per_lun() - Get the number of eraseblocks per LUN
+ * @nand: NAND device
+ *
+ * Return: the number of eraseblocks per LUN.
+ */
+static inline unsigned int
+nanddev_eraseblocks_per_lun(const struct nand_device *nand)
+{
+	return nand->memorg.eraseblocks_per_lun;
+}
+
+/**
+ * nanddev_target_size() - Get the total size provided by a single target/die
+ * @nand: NAND device
+ *
+ * Return: the total size exposed by a single target/die in bytes.
+ */
+static inline u64 nanddev_target_size(const struct nand_device *nand)
+{
+	return (u64)nand->memorg.luns_per_target *
+	       nand->memorg.eraseblocks_per_lun *
+	       nand->memorg.pages_per_eraseblock *
+	       nand->memorg.pagesize;
+}
+
+/**
+ * nanddev_ntarget() - Get the total of targets
+ * @nand: NAND device
+ *
+ * Return: the number of targets/dies exposed by @nand.
+ */
+static inline unsigned int nanddev_ntargets(const struct nand_device *nand)
+{
+	return nand->memorg.ntargets;
+}
+
+/**
+ * nanddev_neraseblocks() - Get the total number of erasablocks
+ * @nand: NAND device
+ *
+ * Return: the total number of eraseblocks exposed by @nand.
+ */
+static inline unsigned int nanddev_neraseblocks(const struct nand_device *nand)
+{
+	return (u64)nand->memorg.luns_per_target *
+	       nand->memorg.eraseblocks_per_lun *
+	       nand->memorg.pages_per_eraseblock;
+}
+
+/**
+ * nanddev_size() - Get NAND size
+ * @nand: NAND device
+ *
+ * Return: the total size (in bytes) exposed by @nand.
+ */
+static inline u64 nanddev_size(const struct nand_device *nand)
+{
+	return nanddev_target_size(nand) * nanddev_ntargets(nand);
+}
+
+/**
+ * nanddev_get_memorg() - Extract memory organization info from a NAND device
+ * @nand: NAND device
+ *
+ * This can be used by the upper layer to fill the memorg info before calling
+ * nanddev_init().
+ *
+ * Return: the memorg object embedded in the NAND device.
+ */
+static inline struct nand_memory_organization *
+nanddev_get_memorg(struct nand_device *nand)
+{
+	return &nand->memorg;
+}
+
+int nanddev_init(struct nand_device *nand, const struct nand_ops *ops,
+		 struct module *owner);
+void nanddev_cleanup(struct nand_device *nand);
+
+/**
+ * nanddev_register() - Register a NAND device
+ * @nand: NAND device
+ *
+ * Register a NAND device.
+ * This function is just a wrapper around mtd_device_register()
+ * registering the MTD device embedded in @nand.
+ *
+ * Return: 0 in case of success, a negative error code otherwise.
+ */
+static inline int nanddev_register(struct nand_device *nand)
+{
+	return mtd_device_register(nand->mtd, NULL, 0);
+}
+
+/**
+ * nanddev_unregister() - Unregister a NAND device
+ * @nand: NAND device
+ *
+ * Unregister a NAND device.
+ * This function is just a wrapper around mtd_device_unregister()
+ * unregistering the MTD device embedded in @nand.
+ *
+ * Return: 0 in case of success, a negative error code otherwise.
+ */
+static inline int nanddev_unregister(struct nand_device *nand)
+{
+	return mtd_device_unregister(nand->mtd);
+}
+
+/**
+ * nanddev_set_of_node() - Attach a DT node to a NAND device
+ * @nand: NAND device
+ * @np: DT node
+ *
+ * Attach a DT node to a NAND device.
+ */
+static inline void nanddev_set_of_node(struct nand_device *nand,
+				       const struct device_node *np)
+{
+	mtd_set_of_node(nand->mtd, np);
+}
+
+/**
+ * nanddev_get_of_node() - Retrieve the DT node attached to a NAND device
+ * @nand: NAND device
+ *
+ * Return: the DT node attached to @nand.
+ */
+static inline const struct device_node *nanddev_get_of_node(struct nand_device *nand)
+{
+	return mtd_get_of_node(nand->mtd);
+}
+
+/**
+ * nanddev_offs_to_pos() - Convert an absolute NAND offset into a NAND position
+ * @nand: NAND device
+ * @offs: absolute NAND offset (usually passed by the MTD layer)
+ * @pos: a NAND position object to fill in
+ *
+ * Converts @offs into a nand_pos representation.
+ *
+ * Return: the offset within the NAND page pointed by @pos.
+ */
+static inline unsigned int nanddev_offs_to_pos(struct nand_device *nand,
+					       loff_t offs,
+					       struct nand_pos *pos)
+{
+	unsigned int pageoffs;
+	u64 tmp = offs;
+
+	pageoffs = do_div(tmp, nand->memorg.pagesize);
+	pos->page = do_div(tmp, nand->memorg.pages_per_eraseblock);
+	pos->eraseblock = do_div(tmp, nand->memorg.eraseblocks_per_lun);
+	pos->plane = pos->eraseblock % nand->memorg.planes_per_lun;
+	pos->lun = do_div(tmp, nand->memorg.luns_per_target);
+	pos->target = tmp;
+
+	return pageoffs;
+}
+
+/**
+ * nanddev_pos_cmp() - Compare two NAND positions
+ * @a: First NAND position
+ * @b: Second NAND position
+ *
+ * Compares two NAND positions.
+ *
+ * Return: -1 if @a < @b, 0 if @a == @b and 1 if @a > @b.
+ */
+static inline int nanddev_pos_cmp(const struct nand_pos *a,
+				  const struct nand_pos *b)
+{
+	if (a->target != b->target)
+		return a->target < b->target ? -1 : 1;
+
+	if (a->lun != b->lun)
+		return a->lun < b->lun ? -1 : 1;
+
+	if (a->eraseblock != b->eraseblock)
+		return a->eraseblock < b->eraseblock ? -1 : 1;
+
+	if (a->page != b->page)
+		return a->page < b->page ? -1 : 1;
+
+	return 0;
+}
+
+/**
+ * nanddev_pos_to_offs() - Convert a NAND position into an absolute offset
+ * @nand: NAND device
+ * @pos: the NAND position to convert
+ *
+ * Converts @pos NAND position into an absolute offset.
+ *
+ * Return: the absolute offset. Note that @pos points to the beginning of a
+ *	   page, if one wants to point to a specific offset within this page
+ *	   the returned offset has to be adjusted manually.
+ */
+static inline loff_t nanddev_pos_to_offs(struct nand_device *nand,
+					 const struct nand_pos *pos)
+{
+	unsigned int npages;
+
+	npages = pos->page +
+		 ((pos->eraseblock +
+		   (pos->lun +
+		    (pos->target * nand->memorg.luns_per_target)) *
+		   nand->memorg.eraseblocks_per_lun) *
+		  nand->memorg.pages_per_eraseblock);
+
+	return (loff_t)npages * nand->memorg.pagesize;
+}
+
+/**
+ * nanddev_pos_to_row() - Extract a row address from a NAND position
+ * @nand: NAND device
+ * @pos: the position to convert
+ *
+ * Converts a NAND position into a row address that can then be passed to the
+ * device.
+ *
+ * Return: the row address extracted from @pos.
+ */
+static inline unsigned int nanddev_pos_to_row(struct nand_device *nand,
+					      const struct nand_pos *pos)
+{
+	return (pos->lun << nand->rowconv.lun_addr_shift) |
+	       (pos->eraseblock << nand->rowconv.eraseblock_addr_shift) |
+	       pos->page;
+}
+
+/**
+ * nanddev_pos_next_target() - Move a position to the next target/die
+ * @nand: NAND device
+ * @pos: the position to update
+ *
+ * Updates @pos to point to the start of the next target/die. Useful when you
+ * want to iterate over all targets/dies of a NAND device.
+ */
+static inline void nanddev_pos_next_target(struct nand_device *nand,
+					   struct nand_pos *pos)
+{
+	pos->page = 0;
+	pos->plane = 0;
+	pos->eraseblock = 0;
+	pos->lun = 0;
+	pos->target++;
+}
+
+/**
+ * nanddev_pos_next_lun() - Move a position to the next LUN
+ * @nand: NAND device
+ * @pos: the position to update
+ *
+ * Updates @pos to point to the start of the next LUN. Useful when you want to
+ * iterate over all LUNs of a NAND device.
+ */
+static inline void nanddev_pos_next_lun(struct nand_device *nand,
+					struct nand_pos *pos)
+{
+	if (pos->lun >= nand->memorg.luns_per_target - 1)
+		return nanddev_pos_next_target(nand, pos);
+
+	pos->lun++;
+	pos->page = 0;
+	pos->plane = 0;
+	pos->eraseblock = 0;
+}
+
+/**
+ * nanddev_pos_next_eraseblock() - Move a position to the next eraseblock
+ * @nand: NAND device
+ * @pos: the position to update
+ *
+ * Updates @pos to point to the start of the next eraseblock. Useful when you
+ * want to iterate over all eraseblocks of a NAND device.
+ */
+static inline void nanddev_pos_next_eraseblock(struct nand_device *nand,
+					       struct nand_pos *pos)
+{
+	if (pos->eraseblock >= nand->memorg.eraseblocks_per_lun - 1)
+		return nanddev_pos_next_lun(nand, pos);
+
+	pos->eraseblock++;
+	pos->page = 0;
+	pos->plane = pos->eraseblock % nand->memorg.planes_per_lun;
+}
+
+/**
+ * nanddev_pos_next_eraseblock() - Move a position to the next page
+ * @nand: NAND device
+ * @pos: the position to update
+ *
+ * Updates @pos to point to the start of the next page. Useful when you want to
+ * iterate over all pages of a NAND device.
+ */
+static inline void nanddev_pos_next_page(struct nand_device *nand,
+					 struct nand_pos *pos)
+{
+	if (pos->page >= nand->memorg.pages_per_eraseblock - 1)
+		return nanddev_pos_next_eraseblock(nand, pos);
+
+	pos->page++;
+}
+
+/**
+ * nand_io_iter_init - Initialize a NAND I/O iterator
+ * @nand: NAND device
+ * @offs: absolute offset
+ * @req: MTD request
+ * @iter: NAND I/O iterator
+ *
+ * Initializes a NAND iterator based on the information passed by the MTD
+ * layer.
+ */
+static inline void nanddev_io_iter_init(struct nand_device *nand,
+					loff_t offs, struct mtd_oob_ops *req,
+					struct nand_io_iter *iter)
+{
+	struct mtd_info *mtd = nanddev_to_mtd(nand);
+
+	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);
+	iter->dataleft = req->len;
+	iter->oobleft = req->ooblen;
+	iter->req.databuf.in = req->datbuf;
+	iter->req.datalen = min_t(unsigned int,
+				  nand->memorg.pagesize - iter->req.dataoffs,
+				  iter->dataleft);
+	iter->req.oobbuf.in = req->oobbuf;
+	iter->req.ooblen = min_t(unsigned int,
+				 iter->oobbytes_per_page - iter->req.ooboffs,
+				 iter->oobleft);
+}
+
+/**
+ * nand_io_iter_next_page - Move to the next page
+ * @nand: NAND device
+ * @iter: NAND I/O iterator
+ *
+ * Updates the @iter to point to the next page.
+ */
+static inline void nanddev_io_iter_next_page(struct nand_device *nand,
+					     struct nand_io_iter *iter)
+{
+	nanddev_pos_next_page(nand, &iter->req.pos);
+	iter->dataleft -= iter->req.datalen;
+	iter->req.databuf.in += iter->req.datalen;
+	iter->oobleft -= iter->req.ooblen;
+	iter->req.oobbuf.in += iter->req.ooblen;
+	iter->req.dataoffs = 0;
+	iter->req.ooboffs = 0;
+	iter->req.datalen = min_t(unsigned int, nand->memorg.pagesize,
+				  iter->dataleft);
+	iter->req.ooblen = min_t(unsigned int, iter->oobbytes_per_page,
+				 iter->oobleft);
+}
+
+/**
+ * nand_io_iter_end - Should end iteration or not
+ * @nand: NAND device
+ * @iter: NAND I/O iterator
+ *
+ * Check whether @iter has reached the end of the NAND portion it was asked to
+ * iterate on or not.
+ *
+ * Return: true if @iter has reached the end of the iteration request, false
+ *	   otherwise.
+ */
+static inline bool nanddev_io_iter_end(struct nand_device *nand,
+				       const struct nand_io_iter *iter)
+{
+	if (iter->dataleft || iter->oobleft)
+		return false;
+
+	return true;
+}
+
+/**
+ * nand_io_for_each_page - Iterate over all NAND pages contained in an MTD I/O
+ *			   request
+ * @nand: NAND device
+ * @start: start address to read/write from
+ * @req: MTD I/O request
+ * @iter: NAND I/O iterator
+ *
+ * Should be used for iterate over pages that are contained in an MTD request.
+ */
+#define nanddev_io_for_each_page(nand, start, req, iter)		\
+	for (nanddev_io_iter_init(nand, start, req, iter);		\
+	     !nanddev_io_iter_end(nand, iter);				\
+	     nanddev_io_iter_next_page(nand, iter))
+
+bool nanddev_isbad(struct nand_device *nand, const struct nand_pos *pos);
+bool nanddev_isreserved(struct nand_device *nand, const struct nand_pos *pos);
+int nanddev_erase(struct nand_device *nand, const struct nand_pos *pos);
+int nanddev_markbad(struct nand_device *nand, const struct nand_pos *pos);
+
+/* BBT related functions */
+enum nand_bbt_block_status {
+	NAND_BBT_BLOCK_STATUS_UNKNOWN,
+	NAND_BBT_BLOCK_GOOD,
+	NAND_BBT_BLOCK_WORN,
+	NAND_BBT_BLOCK_RESERVED,
+	NAND_BBT_BLOCK_FACTORY_BAD,
+	NAND_BBT_BLOCK_NUM_STATUS,
+};
+
+int nanddev_bbt_init(struct nand_device *nand);
+void nanddev_bbt_cleanup(struct nand_device *nand);
+int nanddev_bbt_update(struct nand_device *nand);
+int nanddev_bbt_get_block_status(const struct nand_device *nand,
+				 unsigned int entry);
+int nanddev_bbt_set_block_status(struct nand_device *nand, unsigned int entry,
+				 enum nand_bbt_block_status status);
+int nanddev_bbt_markbad(struct nand_device *nand, unsigned int block);
+
+/**
+ * nanddev_bbt_pos_to_entry() - Convert a NAND position into a BBT entry
+ * @nand: NAND device
+ * @pos: the NAND position we want to get BBT entry for
+ *
+ * Return the BBT entry used to store information about the eraseblock pointed
+ * by @pos.
+ *
+ * Return: the BBT entry storing information about eraseblock pointed by @pos.
+ */
+static inline unsigned int nanddev_bbt_pos_to_entry(struct nand_device *nand,
+						    const struct nand_pos *pos)
+{
+	return pos->eraseblock +
+	       ((pos->lun + (pos->target * nand->memorg.luns_per_target)) *
+		nand->memorg.eraseblocks_per_lun);
+}
+
+/**
+ * nanddev_bbt_is_initialized() - Check if the BBT has been initialized
+ * @nand: NAND device
+ *
+ * Return: true if the BBT has been initialized, false otherwise.
+ */
+static inline bool nanddev_bbt_is_initialized(struct nand_device *nand)
+{
+	return !!nand->bbt.cache;
+}
+
+/* MTD -> NAND helper functions. */
+int nanddev_mtd_erase(struct mtd_info *mtd, struct erase_info *einfo);
+
+#endif /* __LINUX_MTD_NAND_H */
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [U-Boot] [RFC PATCH 09/20] mtd: nand: Pass mode information to nand_page_io_req
  2018-06-06 15:30 [U-Boot] [RFC PATCH 00/20] SPI-NAND support Miquel Raynal
                   ` (7 preceding siblings ...)
  2018-06-06 15:30 ` [U-Boot] [RFC PATCH 08/20] mtd: nand: Add core infrastructure to deal with NAND devices Miquel Raynal
@ 2018-06-06 15:30 ` Miquel Raynal
  2018-06-06 15:30 ` [U-Boot] [RFC PATCH 10/20] spi: Extend the core to ease integration of SPI memory controllers Miquel Raynal
                   ` (13 subsequent siblings)
  22 siblings, 0 replies; 65+ messages in thread
From: Miquel Raynal @ 2018-06-06 15:30 UTC (permalink / raw)
  To: u-boot

From: Boris Brezillon <boris.brezillon@bootlin.com>

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.

Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 include/linux/mtd/nand.h | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index ada7af4a41..13e8dd1103 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -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);
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [U-Boot] [RFC PATCH 10/20] spi: Extend the core to ease integration of SPI memory controllers
  2018-06-06 15:30 [U-Boot] [RFC PATCH 00/20] SPI-NAND support Miquel Raynal
                   ` (8 preceding siblings ...)
  2018-06-06 15:30 ` [U-Boot] [RFC PATCH 09/20] mtd: nand: Pass mode information to nand_page_io_req Miquel Raynal
@ 2018-06-06 15:30 ` Miquel Raynal
  2018-07-06 11:32   ` Jagan Teki
  2018-06-06 15:30 ` [U-Boot] [RFC PATCH 11/20] mtd: nand: Add core infrastructure to support SPI NANDs Miquel Raynal
                   ` (12 subsequent siblings)
  22 siblings, 1 reply; 65+ messages in thread
From: Miquel Raynal @ 2018-06-06 15:30 UTC (permalink / raw)
  To: u-boot

From: Boris Brezillon <boris.brezillon@bootlin.com>

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).

Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 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

diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 235a8c7d73..0ee371b2d9 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -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
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 4b6000fd9a..982529a0e6 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -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
diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c
new file mode 100644
index 0000000000..1aabe56819
--- /dev/null
+++ b/drivers/spi/spi-mem.c
@@ -0,0 +1,500 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018 Exceet Electronics GmbH
+ * Copyright (C) 2018 Bootlin
+ *
+ * Author: Boris Brezillon <boris.brezillon@bootlin.com>
+ */
+
+#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,
+		       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("[ret %d]\n", ret);
+
+	if (ret < 0)
+		return ret;
+
+	if (rx_data)
+		memcpy(op->data.buf.in, rx_buf + pos, op->data.nbytes);
+
+	kfree(tx_buf);
+	kfree(rx_buf);
+#endif /* __UBOOT__ */
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(spi_mem_exec_op);
+
+/**
+ * spi_mem_adjust_op_size() - Adjust the data size of a SPI mem operation to
+ *				 match controller limitations
+ * @slave: the SPI device
+ * @op: the operation to adjust
+ *
+ * Some controllers have FIFO limitations and must split a data transfer
+ * operation into multiple ones, others require a specific alignment for
+ * optimized accesses. This function allows SPI mem drivers to split a single
+ * operation into multiple sub-operations when required.
+ *
+ * Return: a negative error code if the controller can't properly adjust @op,
+ *	   0 otherwise. Note that @op->data.nbytes will be updated if @op
+ *	   can't be handled in a single step.
+ */
+int spi_mem_adjust_op_size(struct spi_slave *slave, 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->adjust_op_size)
+		return ops->mem_ops->adjust_op_size(slave, op);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(spi_mem_adjust_op_size);
+
+#ifndef __UBOOT__
+static inline struct spi_mem_driver *to_spi_mem_drv(struct device_driver *drv)
+{
+	return container_of(drv, struct spi_mem_driver, spidrv.driver);
+}
+
+static int spi_mem_probe(struct spi_device *spi)
+{
+	struct spi_mem_driver *memdrv = to_spi_mem_drv(spi->dev.driver);
+	struct spi_mem *mem;
+
+	mem = devm_kzalloc(&spi->dev, sizeof(*mem), GFP_KERNEL);
+	if (!mem)
+		return -ENOMEM;
+
+	mem->spi = spi;
+	spi_set_drvdata(spi, mem);
+
+	return memdrv->probe(mem);
+}
+
+static int spi_mem_remove(struct spi_device *spi)
+{
+	struct spi_mem_driver *memdrv = to_spi_mem_drv(spi->dev.driver);
+	struct spi_mem *mem = spi_get_drvdata(spi);
+
+	if (memdrv->remove)
+		return memdrv->remove(mem);
+
+	return 0;
+}
+
+static void spi_mem_shutdown(struct spi_device *spi)
+{
+	struct spi_mem_driver *memdrv = to_spi_mem_drv(spi->dev.driver);
+	struct spi_mem *mem = spi_get_drvdata(spi);
+
+	if (memdrv->shutdown)
+		memdrv->shutdown(mem);
+}
+
+/**
+ * spi_mem_driver_register_with_owner() - Register a SPI memory driver
+ * @memdrv: the SPI memory driver to register
+ * @owner: the owner of this driver
+ *
+ * Registers a SPI memory driver.
+ *
+ * Return: 0 in case of success, a negative error core otherwise.
+ */
+
+int spi_mem_driver_register_with_owner(struct spi_mem_driver *memdrv,
+				       struct module *owner)
+{
+	memdrv->spidrv.probe = spi_mem_probe;
+	memdrv->spidrv.remove = spi_mem_remove;
+	memdrv->spidrv.shutdown = spi_mem_shutdown;
+
+	return __spi_register_driver(owner, &memdrv->spidrv);
+}
+EXPORT_SYMBOL_GPL(spi_mem_driver_register_with_owner);
+
+/**
+ * spi_mem_driver_unregister_with_owner() - Unregister a SPI memory driver
+ * @memdrv: the SPI memory driver to unregister
+ *
+ * Unregisters a SPI memory driver.
+ */
+void spi_mem_driver_unregister(struct spi_mem_driver *memdrv)
+{
+	spi_unregister_driver(&memdrv->spidrv);
+}
+EXPORT_SYMBOL_GPL(spi_mem_driver_unregister);
+#endif /* __UBOOT__ */
diff --git a/include/spi-mem.h b/include/spi-mem.h
new file mode 100644
index 0000000000..36814efa86
--- /dev/null
+++ b/include/spi-mem.h
@@ -0,0 +1,258 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2018 Exceet Electronics GmbH
+ * Copyright (C) 2018 Bootlin
+ *
+ * Author:
+ *	Peter Pan <peterpandong@micron.com>
+ *	Boris Brezillon <boris.brezillon@bootlin.com>
+ */
+
+#ifndef __UBOOT_SPI_MEM_H
+#define __UBOOT_SPI_MEM_H
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <spi.h>
+
+#define SPI_MEM_OP_CMD(__opcode, __buswidth)			\
+	{							\
+		.buswidth = __buswidth,				\
+		.opcode = __opcode,				\
+	}
+
+#define SPI_MEM_OP_ADDR(__nbytes, __val, __buswidth)		\
+	{							\
+		.nbytes = __nbytes,				\
+		.val = __val,					\
+		.buswidth = __buswidth,				\
+	}
+
+#define SPI_MEM_OP_NO_ADDR	{ }
+
+#define SPI_MEM_OP_DUMMY(__nbytes, __buswidth)			\
+	{							\
+		.nbytes = __nbytes,				\
+		.buswidth = __buswidth,				\
+	}
+
+#define SPI_MEM_OP_NO_DUMMY	{ }
+
+#define SPI_MEM_OP_DATA_IN(__nbytes, __buf, __buswidth)		\
+	{							\
+		.dir = SPI_MEM_DATA_IN,				\
+		.nbytes = __nbytes,				\
+		.buf.in = __buf,				\
+		.buswidth = __buswidth,				\
+	}
+
+#define SPI_MEM_OP_DATA_OUT(__nbytes, __buf, __buswidth)	\
+	{							\
+		.dir = SPI_MEM_DATA_OUT,			\
+		.nbytes = __nbytes,				\
+		.buf.out = __buf,				\
+		.buswidth = __buswidth,				\
+	}
+
+#define SPI_MEM_OP_NO_DATA	{ }
+
+/**
+ * enum spi_mem_data_dir - describes the direction of a SPI memory data
+ *			   transfer from the controller perspective
+ * @SPI_MEM_DATA_IN: data coming from the SPI memory
+ * @SPI_MEM_DATA_OUT: data sent the SPI memory
+ */
+enum spi_mem_data_dir {
+	SPI_MEM_DATA_IN,
+	SPI_MEM_DATA_OUT,
+};
+
+/**
+ * struct spi_mem_op - describes a SPI memory operation
+ * @cmd.buswidth: number of IO lines used to transmit the command
+ * @cmd.opcode: operation opcode
+ * @addr.nbytes: number of address bytes to send. Can be zero if the operation
+ *		 does not need to send an address
+ * @addr.buswidth: number of IO lines used to transmit the address cycles
+ * @addr.val: address value. This value is always sent MSB first on the bus.
+ *	      Note that only @addr.nbytes are taken into account in this
+ *	      address value, so users should make sure the value fits in the
+ *	      assigned number of bytes.
+ * @dummy.nbytes: number of dummy bytes to send after an opcode or address. Can
+ *		  be zero if the operation does not require dummy bytes
+ * @dummy.buswidth: number of IO lanes used to transmit the dummy bytes
+ * @data.buswidth: number of IO lanes used to send/receive the data
+ * @data.dir: direction of the transfer
+ * @data.buf.in: input buffer
+ * @data.buf.out: output buffer
+ */
+struct spi_mem_op {
+	struct {
+		u8 buswidth;
+		u8 opcode;
+	} cmd;
+
+	struct {
+		u8 nbytes;
+		u8 buswidth;
+		u64 val;
+	} addr;
+
+	struct {
+		u8 nbytes;
+		u8 buswidth;
+	} dummy;
+
+	struct {
+		u8 buswidth;
+		enum spi_mem_data_dir dir;
+		unsigned int nbytes;
+		/* buf.{in,out} must be DMA-able. */
+		union {
+			void *in;
+			const void *out;
+		} buf;
+	} data;
+};
+
+#define SPI_MEM_OP(__cmd, __addr, __dummy, __data)		\
+	{							\
+		.cmd = __cmd,					\
+		.addr = __addr,					\
+		.dummy = __dummy,				\
+		.data = __data,					\
+	}
+
+#ifndef __UBOOT__
+/**
+ * struct spi_mem - describes a SPI memory device
+ * @spi: the underlying SPI device
+ * @drvpriv: spi_mem_driver private data
+ *
+ * Extra information that describe the SPI memory device and may be needed by
+ * the controller to properly handle this device should be placed here.
+ *
+ * One example would be the device size since some controller expose their SPI
+ * mem devices through a io-mapped region.
+ */
+struct spi_mem {
+	struct udevice *dev;
+	void *drvpriv;
+};
+
+/**
+ * struct spi_mem_set_drvdata() - attach driver private data to a SPI mem
+ *				  device
+ * @mem: memory device
+ * @data: data to attach to the memory device
+ */
+static inline void spi_mem_set_drvdata(struct spi_mem *mem, void *data)
+{
+	mem->drvpriv = data;
+}
+
+/**
+ * struct spi_mem_get_drvdata() - get driver private data attached to a SPI mem
+ *				  device
+ * @mem: memory device
+ *
+ * Return: the data attached to the mem device.
+ */
+static inline void *spi_mem_get_drvdata(struct spi_mem *mem)
+{
+	return mem->drvpriv;
+}
+#endif /* __UBOOT__ */
+
+/**
+ * struct spi_controller_mem_ops - SPI memory operations
+ * @adjust_op_size: shrink the data xfer of an operation to match controller's
+ *		    limitations (can be alignment of max RX/TX size
+ *		    limitations)
+ * @supports_op: check if an operation is supported by the controller
+ * @exec_op: execute a SPI memory operation
+ *
+ * This interface should be implemented by SPI controllers providing an
+ * high-level interface to execute SPI memory operation, which is usually the
+ * case for QSPI controllers.
+ */
+struct spi_controller_mem_ops {
+	int (*adjust_op_size)(struct spi_slave *slave, struct spi_mem_op *op);
+	bool (*supports_op)(struct spi_slave *slave,
+			    const struct spi_mem_op *op);
+	int (*exec_op)(struct spi_slave *slave,
+		       const struct spi_mem_op *op);
+};
+
+#ifndef __UBOOT__
+/**
+ * struct spi_mem_driver - SPI memory driver
+ * @spidrv: inherit from a SPI driver
+ * @probe: probe a SPI memory. Usually where detection/initialization takes
+ *	   place
+ * @remove: remove a SPI memory
+ * @shutdown: take appropriate action when the system is shutdown
+ *
+ * This is just a thin wrapper around a spi_driver. The core takes care of
+ * allocating the spi_mem object and forwarding the probe/remove/shutdown
+ * request to the spi_mem_driver. The reason we use this wrapper is because
+ * we might have to stuff more information into the spi_mem struct to let
+ * SPI controllers know more about the SPI memory they interact with, and
+ * having this intermediate layer allows us to do that without adding more
+ * useless fields to the spi_device object.
+ */
+struct spi_mem_driver {
+	struct spi_driver spidrv;
+	int (*probe)(struct spi_mem *mem);
+	int (*remove)(struct spi_mem *mem);
+	void (*shutdown)(struct spi_mem *mem);
+};
+
+#if IS_ENABLED(CONFIG_SPI_MEM)
+int spi_controller_dma_map_mem_op_data(struct spi_controller *ctlr,
+				       const struct spi_mem_op *op,
+				       struct sg_table *sg);
+
+void spi_controller_dma_unmap_mem_op_data(struct spi_controller *ctlr,
+					  const struct spi_mem_op *op,
+					  struct sg_table *sg);
+#else
+static inline int
+spi_controller_dma_map_mem_op_data(struct spi_controller *ctlr,
+				   const struct spi_mem_op *op,
+				   struct sg_table *sg)
+{
+	return -ENOTSUPP;
+}
+
+static inline void
+spi_controller_dma_unmap_mem_op_data(struct spi_controller *ctlr,
+				     const struct spi_mem_op *op,
+				     struct sg_table *sg)
+{
+}
+#endif /* CONFIG_SPI_MEM */
+#endif /* __UBOOT__ */
+
+int spi_mem_adjust_op_size(struct spi_slave *slave, struct spi_mem_op *op);
+
+bool spi_mem_supports_op(struct spi_slave *slave, const struct spi_mem_op *op);
+
+int spi_mem_exec_op(struct spi_slave *slave, const struct spi_mem_op *op);
+
+#ifndef __UBOOT__
+int spi_mem_driver_register_with_owner(struct spi_mem_driver *drv,
+				       struct module *owner);
+
+void spi_mem_driver_unregister(struct spi_mem_driver *drv);
+
+#define spi_mem_driver_register(__drv)                                  \
+	spi_mem_driver_register_with_owner(__drv, THIS_MODULE)
+
+#define module_spi_mem_driver(__drv)                                    \
+	module_driver(__drv, spi_mem_driver_register,                   \
+		      spi_mem_driver_unregister)
+#endif
+
+#endif /* __LINUX_SPI_MEM_H */
diff --git a/include/spi.h b/include/spi.h
index f5bac8d002..12587ffeb0 100644
--- a/include/spi.h
+++ b/include/spi.h
@@ -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().
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [U-Boot] [RFC PATCH 11/20] mtd: nand: Add core infrastructure to support SPI NANDs
  2018-06-06 15:30 [U-Boot] [RFC PATCH 00/20] SPI-NAND support Miquel Raynal
                   ` (9 preceding siblings ...)
  2018-06-06 15:30 ` [U-Boot] [RFC PATCH 10/20] spi: Extend the core to ease integration of SPI memory controllers Miquel Raynal
@ 2018-06-06 15:30 ` Miquel Raynal
  2018-06-06 15:30 ` [U-Boot] [RFC PATCH 12/20] mtd: spinand: Add initial support for Micron MT29F2G01ABAGD Miquel Raynal
                   ` (11 subsequent siblings)
  22 siblings, 0 replies; 65+ messages in thread
From: Miquel Raynal @ 2018-06-06 15:30 UTC (permalink / raw)
  To: u-boot

From: Peter Pan <peterpandong@micron.com>

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

Signed-off-by: Peter Pan <peterpandong@micron.com>
Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 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   | 1233 +++++++++++++++++++++++++++++++++++++++++
 include/linux/mtd/spinand.h   |  427 ++++++++++++++
 6 files changed, 1674 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

diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index 1c1a1f487e..78ae04bdcb 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -2,3 +2,5 @@ config MTD_NAND_CORE
 	tristate
 
 source "drivers/mtd/nand/raw/Kconfig"
+
+source "drivers/mtd/nand/spi/Kconfig"
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index 69c80ea252..cbac19b38a 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -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/
diff --git a/drivers/mtd/nand/spi/Kconfig b/drivers/mtd/nand/spi/Kconfig
new file mode 100644
index 0000000000..2197cb531f
--- /dev/null
+++ b/drivers/mtd/nand/spi/Kconfig
@@ -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.
diff --git a/drivers/mtd/nand/spi/Makefile b/drivers/mtd/nand/spi/Makefile
new file mode 100644
index 0000000000..f0c6e69d2e
--- /dev/null
+++ b/drivers/mtd/nand/spi/Makefile
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0
+
+spinand-objs := core.o
+obj-$(CONFIG_MTD_SPI_NAND) += spinand.o
diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
new file mode 100644
index 0000000000..d2e912aeb5
--- /dev/null
+++ b/drivers/mtd/nand/spi/core.c
@@ -0,0 +1,1233 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2016-2017 Micron Technology, Inc.
+ *
+ * Authors:
+ *	Peter Pan <peterpandong@micron.com>
+ *	Boris Brezillon <boris.brezillon@bootlin.com>
+ */
+
+#define pr_fmt(fmt)	"spi-nand: " fmt
+
+#ifndef __UBOOT__
+#include <linux/device.h>
+#include <linux/jiffies.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mtd/spinand.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/spi-mem.h>
+#else
+#include <common.h>
+#include <errno.h>
+#include <spi.h>
+#include <spi-mem.h>
+#include <linux/mtd/spinand.h>
+#endif
+
+/* SPI NAND index visible in MTD names */
+static int spi_nand_idx;
+
+static void spinand_cache_op_adjust_colum(struct spinand_device *spinand,
+					  const struct nand_page_io_req *req,
+					  u16 *column)
+{
+	struct nand_device *nand = spinand_to_nand(spinand);
+	unsigned int shift;
+
+	if (nand->memorg.planes_per_lun < 2)
+		return;
+
+	/* The plane number is passed in MSB just above the column address */
+	shift = fls(nand->memorg.pagesize);
+	*column |= req->pos.plane << shift;
+}
+
+static int spinand_read_reg_op(struct spinand_device *spinand, u8 reg, u8 *val)
+{
+	struct spi_mem_op op = SPINAND_GET_FEATURE_OP(reg,
+						      spinand->scratchbuf);
+	int ret;
+
+	ret = spi_mem_exec_op(spinand->slave, &op);
+	if (ret)
+		return ret;
+
+	*val = *spinand->scratchbuf;
+	return 0;
+}
+
+static int spinand_write_reg_op(struct spinand_device *spinand, u8 reg, u8 val)
+{
+	struct spi_mem_op op = SPINAND_SET_FEATURE_OP(reg,
+						      spinand->scratchbuf);
+
+	*spinand->scratchbuf = val;
+	return spi_mem_exec_op(spinand->slave, &op);
+}
+
+static int spinand_read_status(struct spinand_device *spinand, u8 *status)
+{
+	return spinand_read_reg_op(spinand, REG_STATUS, status);
+}
+
+static int spinand_get_cfg(struct spinand_device *spinand, u8 *cfg)
+{
+	struct nand_device *nand = spinand_to_nand(spinand);
+
+	if (WARN_ON(spinand->cur_target < 0 ||
+		    spinand->cur_target >= nand->memorg.ntargets))
+		return -EINVAL;
+
+	*cfg = spinand->cfg_cache[spinand->cur_target];
+	return 0;
+}
+
+static int spinand_set_cfg(struct spinand_device *spinand, u8 cfg)
+{
+	struct nand_device *nand = spinand_to_nand(spinand);
+	int ret;
+
+	if (WARN_ON(spinand->cur_target < 0 ||
+		    spinand->cur_target >= nand->memorg.ntargets))
+		return -EINVAL;
+
+	if (spinand->cfg_cache[spinand->cur_target] == cfg)
+		return 0;
+
+	ret = spinand_write_reg_op(spinand, REG_CFG, cfg);
+	if (ret)
+		return ret;
+
+	spinand->cfg_cache[spinand->cur_target] = cfg;
+	return 0;
+}
+
+/**
+ * spinand_upd_cfg() - Update the configuration register
+ * @spinand: the spinand device
+ * @mask: the mask encoding the bits to update in the config reg
+ * @val: the new value to apply
+ *
+ * Update the configuration register.
+ *
+ * Return: 0 on success, a negative error code otherwise.
+ */
+int spinand_upd_cfg(struct spinand_device *spinand, u8 mask, u8 val)
+{
+	int ret;
+	u8 cfg;
+
+	ret = spinand_get_cfg(spinand, &cfg);
+	if (ret)
+		return ret;
+
+	cfg &= ~mask;
+	cfg |= val;
+
+	return spinand_set_cfg(spinand, cfg);
+}
+
+/**
+ * spinand_select_target() - Select a specific NAND target/die
+ * @spinand: the spinand device
+ * @target: the target/die to select
+ *
+ * Select a new target/die. If chip only has one die, this function is a NOOP.
+ *
+ * Return: 0 on success, a negative error code otherwise.
+ */
+int spinand_select_target(struct spinand_device *spinand, unsigned int target)
+{
+	struct nand_device *nand = spinand_to_nand(spinand);
+	int ret;
+
+	if (WARN_ON(target >= nand->memorg.ntargets))
+		return -EINVAL;
+
+	if (spinand->cur_target == target)
+		return 0;
+
+	if (nand->memorg.ntargets == 1) {
+		spinand->cur_target = target;
+		return 0;
+	}
+
+	ret = spinand->select_target(spinand, target);
+	if (ret)
+		return ret;
+
+	spinand->cur_target = target;
+	return 0;
+}
+
+static int spinand_init_cfg_cache(struct spinand_device *spinand)
+{
+	struct nand_device *nand = spinand_to_nand(spinand);
+	struct udevice *dev = spinand->slave->dev;
+	unsigned int target;
+	int ret;
+
+	spinand->cfg_cache = devm_kzalloc(dev,
+					  sizeof(*spinand->cfg_cache) *
+					  nand->memorg.ntargets,
+					  GFP_KERNEL);
+	if (!spinand->cfg_cache)
+		return -ENOMEM;
+
+	for (target = 0; target < nand->memorg.ntargets; target++) {
+		ret = spinand_select_target(spinand, target);
+		if (ret)
+			return ret;
+
+		/*
+		 * We use spinand_read_reg_op() instead of spinand_get_cfg()
+		 * here to bypass the config cache.
+		 */
+		ret = spinand_read_reg_op(spinand, REG_CFG,
+					  &spinand->cfg_cache[target]);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int spinand_init_quad_enable(struct spinand_device *spinand)
+{
+	bool enable = false;
+
+	if (!(spinand->flags & SPINAND_HAS_QE_BIT))
+		return 0;
+
+	if (spinand->op_templates.read_cache->data.buswidth == 4 ||
+	    spinand->op_templates.write_cache->data.buswidth == 4 ||
+	    spinand->op_templates.update_cache->data.buswidth == 4)
+		enable = true;
+
+	return spinand_upd_cfg(spinand, CFG_QUAD_ENABLE,
+			       enable ? CFG_QUAD_ENABLE : 0);
+}
+
+static int spinand_ecc_enable(struct spinand_device *spinand,
+			      bool enable)
+{
+	return spinand_upd_cfg(spinand, CFG_ECC_ENABLE,
+			       enable ? CFG_ECC_ENABLE : 0);
+}
+
+static int spinand_write_enable_op(struct spinand_device *spinand)
+{
+	struct spi_mem_op op = SPINAND_WR_EN_DIS_OP(true);
+
+	return spi_mem_exec_op(spinand->slave, &op);
+}
+
+static int spinand_load_page_op(struct spinand_device *spinand,
+				const struct nand_page_io_req *req)
+{
+	struct nand_device *nand = spinand_to_nand(spinand);
+	unsigned int row = nanddev_pos_to_row(nand, &req->pos);
+	struct spi_mem_op op = SPINAND_PAGE_READ_OP(row);
+
+	return spi_mem_exec_op(spinand->slave, &op);
+}
+
+static int spinand_read_from_cache_op(struct spinand_device *spinand,
+				      const struct nand_page_io_req *req)
+{
+	struct spi_mem_op op = *spinand->op_templates.read_cache;
+	struct nand_device *nand = spinand_to_nand(spinand);
+	struct mtd_info *mtd = nanddev_to_mtd(nand);
+	struct nand_page_io_req adjreq = *req;
+	unsigned int nbytes = 0;
+	void *buf = NULL;
+	u16 column = 0;
+	int ret;
+
+	if (req->datalen) {
+		adjreq.datalen = nanddev_page_size(nand);
+		adjreq.dataoffs = 0;
+		adjreq.databuf.in = spinand->databuf;
+		buf = spinand->databuf;
+		nbytes = adjreq.datalen;
+	}
+
+	if (req->ooblen) {
+		adjreq.ooblen = nanddev_per_page_oobsize(nand);
+		adjreq.ooboffs = 0;
+		adjreq.oobbuf.in = spinand->oobbuf;
+		nbytes += nanddev_per_page_oobsize(nand);
+		if (!buf) {
+			buf = spinand->oobbuf;
+			column = nanddev_page_size(nand);
+		}
+	}
+
+	spinand_cache_op_adjust_colum(spinand, &adjreq, &column);
+	op.addr.val = column;
+
+	/*
+	 * Some controllers are limited in term of max RX data size. In this
+	 * case, just repeat the READ_CACHE operation after updating the
+	 * column.
+	 */
+	while (nbytes) {
+		op.data.buf.in = buf;
+		op.data.nbytes = nbytes;
+		ret = spi_mem_adjust_op_size(spinand->slave, &op);
+		if (ret)
+			return ret;
+
+		ret = spi_mem_exec_op(spinand->slave, &op);
+		if (ret)
+			return ret;
+
+		buf += op.data.nbytes;
+		nbytes -= op.data.nbytes;
+		op.addr.val += op.data.nbytes;
+	}
+
+	if (req->datalen)
+		memcpy(req->databuf.in, spinand->databuf + req->dataoffs,
+		       req->datalen);
+
+	if (req->ooblen) {
+		if (req->mode == MTD_OPS_AUTO_OOB)
+			mtd_ooblayout_get_databytes(mtd, req->oobbuf.in,
+						    spinand->oobbuf,
+						    req->ooboffs,
+						    req->ooblen);
+		else
+			memcpy(req->oobbuf.in, spinand->oobbuf + req->ooboffs,
+			       req->ooblen);
+	}
+
+	return 0;
+}
+
+static int spinand_write_to_cache_op(struct spinand_device *spinand,
+				     const struct nand_page_io_req *req)
+{
+	struct spi_mem_op op = *spinand->op_templates.write_cache;
+	struct nand_device *nand = spinand_to_nand(spinand);
+	struct mtd_info *mtd = nanddev_to_mtd(nand);
+	struct nand_page_io_req adjreq = *req;
+	unsigned int nbytes = 0;
+	void *buf = NULL;
+	u16 column = 0;
+	int ret;
+
+	memset(spinand->databuf, 0xff,
+	       nanddev_page_size(nand) +
+	       nanddev_per_page_oobsize(nand));
+
+	if (req->datalen) {
+		memcpy(spinand->databuf + req->dataoffs, req->databuf.out,
+		       req->datalen);
+		adjreq.dataoffs = 0;
+		adjreq.datalen = nanddev_page_size(nand);
+		adjreq.databuf.out = spinand->databuf;
+		nbytes = adjreq.datalen;
+		buf = spinand->databuf;
+	}
+
+	if (req->ooblen) {
+		if (req->mode == MTD_OPS_AUTO_OOB)
+			mtd_ooblayout_set_databytes(mtd, req->oobbuf.out,
+						    spinand->oobbuf,
+						    req->ooboffs,
+						    req->ooblen);
+		else
+			memcpy(spinand->oobbuf + req->ooboffs, req->oobbuf.out,
+			       req->ooblen);
+
+		adjreq.ooblen = nanddev_per_page_oobsize(nand);
+		adjreq.ooboffs = 0;
+		nbytes += nanddev_per_page_oobsize(nand);
+		if (!buf) {
+			buf = spinand->oobbuf;
+			column = nanddev_page_size(nand);
+		}
+	}
+
+	spinand_cache_op_adjust_colum(spinand, &adjreq, &column);
+
+	op = *spinand->op_templates.write_cache;
+	op.addr.val = column;
+
+	/*
+	 * Some controllers are limited in term of max TX data size. In this
+	 * case, split the operation into one LOAD CACHE and one or more
+	 * LOAD RANDOM CACHE.
+	 */
+	while (nbytes) {
+		op.data.buf.out = buf;
+		op.data.nbytes = nbytes;
+
+		ret = spi_mem_adjust_op_size(spinand->slave, &op);
+		if (ret)
+			return ret;
+
+		ret = spi_mem_exec_op(spinand->slave, &op);
+		if (ret)
+			return ret;
+
+		buf += op.data.nbytes;
+		nbytes -= op.data.nbytes;
+		op.addr.val += op.data.nbytes;
+
+		/*
+		 * We need to use the RANDOM LOAD CACHE operation if there's
+		 * more than one iteration, because the LOAD operation resets
+		 * the cache to 0xff.
+		 */
+		if (nbytes) {
+			column = op.addr.val;
+			op = *spinand->op_templates.update_cache;
+			op.addr.val = column;
+		}
+	}
+
+	return 0;
+}
+
+static int spinand_program_op(struct spinand_device *spinand,
+			      const struct nand_page_io_req *req)
+{
+	struct nand_device *nand = spinand_to_nand(spinand);
+	unsigned int row = nanddev_pos_to_row(nand, &req->pos);
+	struct spi_mem_op op = SPINAND_PROG_EXEC_OP(row);
+
+	return spi_mem_exec_op(spinand->slave, &op);
+}
+
+static int spinand_erase_op(struct spinand_device *spinand,
+			    const struct nand_pos *pos)
+{
+	struct nand_device *nand = &spinand->base;
+	unsigned int row = nanddev_pos_to_row(nand, pos);
+	struct spi_mem_op op = SPINAND_BLK_ERASE_OP(row);
+
+	return spi_mem_exec_op(spinand->slave, &op);
+}
+
+static int spinand_wait(struct spinand_device *spinand, u8 *s)
+{
+	unsigned long start, stop;
+	u8 status;
+	int ret;
+
+	start = get_timer(0);
+	stop = 400;
+	do {
+		ret = spinand_read_status(spinand, &status);
+		if (ret)
+			return ret;
+
+		if (!(status & STATUS_BUSY))
+			goto out;
+	} while (get_timer(start) < stop);
+
+	/*
+	 * Extra read, just in case the STATUS_READY bit has changed
+	 * since our last check
+	 */
+	ret = spinand_read_status(spinand, &status);
+	if (ret)
+		return ret;
+
+out:
+	if (s)
+		*s = status;
+
+	return status & STATUS_BUSY ? -ETIMEDOUT : 0;
+}
+
+static int spinand_read_id_op(struct spinand_device *spinand, u8 *buf)
+{
+	struct spi_mem_op op = SPINAND_READID_OP(0, spinand->scratchbuf,
+						 SPINAND_MAX_ID_LEN);
+	int ret;
+
+	ret = spi_mem_exec_op(spinand->slave, &op);
+	if (!ret)
+		memcpy(buf, spinand->scratchbuf, SPINAND_MAX_ID_LEN);
+
+	return ret;
+}
+
+static int spinand_reset_op(struct spinand_device *spinand)
+{
+	struct spi_mem_op op = SPINAND_RESET_OP;
+	int ret;
+
+	ret = spi_mem_exec_op(spinand->slave, &op);
+	if (ret)
+		return ret;
+
+	return spinand_wait(spinand, NULL);
+}
+
+static int spinand_lock_block(struct spinand_device *spinand, u8 lock)
+{
+	return spinand_write_reg_op(spinand, REG_BLOCK_LOCK, lock);
+}
+
+static int spinand_check_ecc_status(struct spinand_device *spinand, u8 status)
+{
+	struct nand_device *nand = spinand_to_nand(spinand);
+
+	if (spinand->eccinfo.get_status)
+		return spinand->eccinfo.get_status(spinand, status);
+
+	switch (status & STATUS_ECC_MASK) {
+	case STATUS_ECC_NO_BITFLIPS:
+		return 0;
+
+	case STATUS_ECC_HAS_BITFLIPS:
+		/*
+		 * We have no way to know exactly how many bitflips have been
+		 * fixed, so let's return the maximum possible value so that
+		 * wear-leveling layers move the data immediately.
+		 */
+		return nand->eccreq.strength;
+
+	case STATUS_ECC_UNCOR_ERROR:
+		return -EBADMSG;
+
+	default:
+		break;
+	}
+
+	return -EINVAL;
+}
+
+static int spinand_read_page(struct spinand_device *spinand,
+			     const struct nand_page_io_req *req,
+			     bool ecc_enabled)
+{
+	u8 status;
+	int ret;
+
+	ret = spinand_load_page_op(spinand, req);
+	if (ret)
+		return ret;
+
+	ret = spinand_wait(spinand, &status);
+	if (ret < 0)
+		return ret;
+
+	ret = spinand_read_from_cache_op(spinand, req);
+	if (ret)
+		return ret;
+
+	if (!ecc_enabled)
+		return 0;
+
+	return spinand_check_ecc_status(spinand, status);
+}
+
+static int spinand_write_page(struct spinand_device *spinand,
+			      const struct nand_page_io_req *req)
+{
+	u8 status;
+	int ret;
+
+	ret = spinand_write_enable_op(spinand);
+	if (ret)
+		return ret;
+
+	ret = spinand_write_to_cache_op(spinand, req);
+	if (ret)
+		return ret;
+
+	ret = spinand_program_op(spinand, req);
+	if (ret)
+		return ret;
+
+	ret = spinand_wait(spinand, &status);
+	if (!ret && (status & STATUS_PROG_FAILED))
+		ret = -EIO;
+
+	return ret;
+}
+
+static int spinand_mtd_read(struct mtd_info *mtd, loff_t from,
+			    struct mtd_oob_ops *ops)
+{
+	struct spinand_device *spinand = mtd_to_spinand(mtd);
+	struct nand_device *nand = mtd_to_nanddev(mtd);
+	unsigned int max_bitflips = 0;
+	struct nand_io_iter iter;
+	bool enable_ecc = false;
+	bool ecc_failed = false;
+	int ret = 0;
+
+	if (ops->mode != MTD_OPS_RAW && spinand->eccinfo.ooblayout)
+		enable_ecc = true;
+
+#ifndef __UBOOT__
+	mutex_lock(&spinand->lock);
+#endif
+
+	nanddev_io_for_each_page(nand, from, ops, &iter) {
+		ret = spinand_select_target(spinand, iter.req.pos.target);
+		if (ret)
+			return ret;
+
+		ret = spinand_ecc_enable(spinand, enable_ecc);
+		if (ret)
+			return ret;
+
+		ret = spinand_read_page(spinand, &iter.req, enable_ecc);
+		if (ret < 0 && ret != -EBADMSG)
+			break;
+
+		if (ret == -EBADMSG) {
+			ecc_failed = true;
+			mtd->ecc_stats.failed++;
+			ret = 0;
+		} else {
+			mtd->ecc_stats.corrected += ret;
+			max_bitflips = max_t(unsigned int, max_bitflips, ret);
+		}
+
+		ops->retlen += iter.req.datalen;
+		ops->oobretlen += iter.req.ooblen;
+	}
+
+#ifndef __UBOOT__
+	mutex_unlock(&spinand->lock);
+#endif
+	if (ecc_failed && !ret)
+		ret = -EBADMSG;
+
+	return ret ? ret : max_bitflips;
+}
+
+static int spinand_mtd_write(struct mtd_info *mtd, loff_t to,
+			     struct mtd_oob_ops *ops)
+{
+	struct spinand_device *spinand = mtd_to_spinand(mtd);
+	struct nand_device *nand = mtd_to_nanddev(mtd);
+	struct nand_io_iter iter;
+	bool enable_ecc = false;
+	int ret = 0;
+
+	if (ops->mode != MTD_OPS_RAW && mtd->ooblayout)
+		enable_ecc = true;
+
+#ifndef __UBOOT__
+	mutex_lock(&spinand->lock);
+#endif
+
+	nanddev_io_for_each_page(nand, to, ops, &iter) {
+		ret = spinand_select_target(spinand, iter.req.pos.target);
+		if (ret)
+			return ret;
+
+		ret = spinand_ecc_enable(spinand, enable_ecc);
+		if (ret)
+			return ret;
+
+		ret = spinand_write_page(spinand, &iter.req);
+		if (ret)
+			break;
+
+		ops->retlen += iter.req.datalen;
+		ops->oobretlen += iter.req.ooblen;
+	}
+
+#ifndef __UBOOT__
+	mutex_unlock(&spinand->lock);
+#endif
+
+	return ret;
+}
+
+static bool spinand_isbad(struct nand_device *nand, const struct nand_pos *pos)
+{
+	struct spinand_device *spinand = nand_to_spinand(nand);
+	struct nand_page_io_req req = {
+		.pos = *pos,
+		.ooblen = 2,
+		.ooboffs = 0,
+		.oobbuf.in = spinand->oobbuf,
+		.mode = MTD_OPS_RAW,
+	};
+	int ret;
+
+	memset(spinand->oobbuf, 0, 2);
+	ret = spinand_select_target(spinand, pos->target);
+	if (ret)
+		return ret;
+
+	ret = spinand_read_page(spinand, &req, false);
+	if (ret)
+		return ret;
+
+	if (spinand->oobbuf[0] != 0xff || spinand->oobbuf[1] != 0xff)
+		return true;
+
+	return false;
+}
+
+static int spinand_mtd_block_isbad(struct mtd_info *mtd, loff_t offs)
+{
+	struct nand_device *nand = mtd_to_nanddev(mtd);
+#ifndef __UBOOT__
+	struct spinand_device *spinand = nand_to_spinand(nand);
+#endif
+	struct nand_pos pos;
+	int ret;
+
+	nanddev_offs_to_pos(nand, offs, &pos);
+#ifndef __UBOOT__
+	mutex_lock(&spinand->lock);
+#endif
+	ret = nanddev_isbad(nand, &pos);
+#ifndef __UBOOT__
+	mutex_unlock(&spinand->lock);
+#endif
+	return ret;
+}
+
+static int spinand_markbad(struct nand_device *nand, const struct nand_pos *pos)
+{
+	struct spinand_device *spinand = nand_to_spinand(nand);
+	struct nand_page_io_req req = {
+		.pos = *pos,
+		.ooboffs = 0,
+		.ooblen = 2,
+		.oobbuf.out = spinand->oobbuf,
+	};
+	int ret;
+
+	/* Erase block before marking it bad. */
+	ret = spinand_select_target(spinand, pos->target);
+	if (ret)
+		return ret;
+
+	ret = spinand_write_enable_op(spinand);
+	if (ret)
+		return ret;
+
+	ret = spinand_erase_op(spinand, pos);
+	if (ret)
+		return ret;
+
+	memset(spinand->oobbuf, 0, 2);
+	return spinand_write_page(spinand, &req);
+}
+
+static int spinand_mtd_block_markbad(struct mtd_info *mtd, loff_t offs)
+{
+	struct nand_device *nand = mtd_to_nanddev(mtd);
+#ifndef __UBOOT__
+	struct spinand_device *spinand = nand_to_spinand(nand);
+#endif
+	struct nand_pos pos;
+	int ret;
+
+	nanddev_offs_to_pos(nand, offs, &pos);
+#ifndef __UBOOT__
+	mutex_lock(&spinand->lock);
+#endif
+	ret = nanddev_markbad(nand, &pos);
+#ifndef __UBOOT__
+	mutex_unlock(&spinand->lock);
+#endif
+	return ret;
+}
+
+static int spinand_erase(struct nand_device *nand, const struct nand_pos *pos)
+{
+	struct spinand_device *spinand = nand_to_spinand(nand);
+	u8 status;
+	int ret;
+
+	ret = spinand_select_target(spinand, pos->target);
+	if (ret)
+		return ret;
+
+	ret = spinand_write_enable_op(spinand);
+	if (ret)
+		return ret;
+
+	ret = spinand_erase_op(spinand, pos);
+	if (ret)
+		return ret;
+
+	ret = spinand_wait(spinand, &status);
+	if (!ret && (status & STATUS_ERASE_FAILED))
+		ret = -EIO;
+
+	return ret;
+}
+
+static int spinand_mtd_erase(struct mtd_info *mtd,
+			     struct erase_info *einfo)
+{
+#ifndef __UBOOT__
+	struct spinand_device *spinand = mtd_to_spinand(mtd);
+#endif
+	int ret;
+
+#ifndef __UBOOT__
+	mutex_lock(&spinand->lock);
+#endif
+	ret = nanddev_mtd_erase(mtd, einfo);
+#ifndef __UBOOT__
+	mutex_unlock(&spinand->lock);
+#endif
+
+	return ret;
+}
+
+static int spinand_mtd_block_isreserved(struct mtd_info *mtd, loff_t offs)
+{
+#ifndef __UBOOT__
+	struct spinand_device *spinand = mtd_to_spinand(mtd);
+#endif
+	struct nand_device *nand = mtd_to_nanddev(mtd);
+	struct nand_pos pos;
+	int ret;
+
+	nanddev_offs_to_pos(nand, offs, &pos);
+#ifndef __UBOOT__
+	mutex_lock(&spinand->lock);
+#endif
+	ret = nanddev_isreserved(nand, &pos);
+#ifndef __UBOOT__
+	mutex_unlock(&spinand->lock);
+#endif
+
+	return ret;
+}
+
+const struct spi_mem_op *
+spinand_find_supported_op(struct spinand_device *spinand,
+			  const struct spi_mem_op *ops,
+			  unsigned int nops)
+{
+	unsigned int i;
+
+	for (i = 0; i < nops; i++) {
+		if (spi_mem_supports_op(spinand->slave, &ops[i]))
+			return &ops[i];
+	}
+
+	return NULL;
+}
+
+static const struct nand_ops spinand_ops = {
+	.erase = spinand_erase,
+	.markbad = spinand_markbad,
+	.isbad = spinand_isbad,
+};
+
+static int spinand_manufacturer_detect(struct spinand_device *spinand)
+{
+	return -ENOTSUPP;
+}
+
+static int spinand_manufacturer_init(struct spinand_device *spinand)
+{
+	if (spinand->manufacturer->ops->init)
+		return spinand->manufacturer->ops->init(spinand);
+
+	return 0;
+}
+
+static void spinand_manufacturer_cleanup(struct spinand_device *spinand)
+{
+	/* Release manufacturer private data */
+	if (spinand->manufacturer->ops->cleanup)
+		return spinand->manufacturer->ops->cleanup(spinand);
+}
+
+static const struct spi_mem_op *
+spinand_select_op_variant(struct spinand_device *spinand,
+			  const struct spinand_op_variants *variants)
+{
+	struct nand_device *nand = spinand_to_nand(spinand);
+	unsigned int i;
+
+	for (i = 0; i < variants->nops; i++) {
+		struct spi_mem_op op = variants->ops[i];
+		unsigned int nbytes;
+		int ret;
+
+		nbytes = nanddev_per_page_oobsize(nand) +
+			 nanddev_page_size(nand);
+
+		while (nbytes) {
+			op.data.nbytes = nbytes;
+			ret = spi_mem_adjust_op_size(spinand->slave, &op);
+			if (ret)
+				break;
+
+			if (!spi_mem_supports_op(spinand->slave, &op))
+				break;
+
+			nbytes -= op.data.nbytes;
+		}
+
+		if (!nbytes)
+			return &variants->ops[i];
+	}
+
+	return NULL;
+}
+
+/**
+ * spinand_match_and_init() - Try to find a match between a device ID and an
+ *			      entry in a spinand_info table
+ * @spinand: SPI NAND object
+ * @table: SPI NAND device description table
+ * @table_size: size of the device description table
+ *
+ * Should be used by SPI NAND manufacturer drivers when they want to find a
+ * match between a device ID retrieved through the READ_ID command and an
+ * entry in the SPI NAND description table. If a match is found, the spinand
+ * object will be initialized with information provided by the matching
+ * spinand_info entry.
+ *
+ * Return: 0 on success, a negative error code otherwise.
+ */
+int spinand_match_and_init(struct spinand_device *spinand,
+			   const struct spinand_info *table,
+			   unsigned int table_size, u8 devid)
+{
+	struct nand_device *nand = spinand_to_nand(spinand);
+	unsigned int i;
+
+	for (i = 0; i < table_size; i++) {
+		const struct spinand_info *info = &table[i];
+		const struct spi_mem_op *op;
+
+		if (devid != info->devid)
+			continue;
+
+		nand->memorg = table[i].memorg;
+		nand->eccreq = table[i].eccreq;
+		spinand->eccinfo = table[i].eccinfo;
+		spinand->flags = table[i].flags;
+		spinand->select_target = table[i].select_target;
+
+		op = spinand_select_op_variant(spinand,
+					       info->op_variants.read_cache);
+		if (!op)
+			return -ENOTSUPP;
+
+		spinand->op_templates.read_cache = op;
+
+		op = spinand_select_op_variant(spinand,
+					       info->op_variants.write_cache);
+		if (!op)
+			return -ENOTSUPP;
+
+		spinand->op_templates.write_cache = op;
+
+		op = spinand_select_op_variant(spinand,
+					       info->op_variants.update_cache);
+		spinand->op_templates.update_cache = op;
+
+		return 0;
+	}
+
+	return -ENOTSUPP;
+}
+
+static int spinand_detect(struct spinand_device *spinand)
+{
+	struct nand_device *nand = spinand_to_nand(spinand);
+	int ret;
+
+	ret = spinand_reset_op(spinand);
+	if (ret)
+		return ret;
+
+	ret = spinand_read_id_op(spinand, spinand->id.data);
+	if (ret)
+		return ret;
+
+	spinand->id.len = SPINAND_MAX_ID_LEN;
+
+	ret = spinand_manufacturer_detect(spinand);
+	if (ret) {
+		dev_err(dev, "unknown raw ID %*phN\n", SPINAND_MAX_ID_LEN,
+			spinand->id.data);
+		return ret;
+	}
+
+	if (nand->memorg.ntargets > 1 && !spinand->select_target) {
+		dev_err(dev,
+			"SPI NANDs with more than one die must implement ->select_target()\n");
+		return -EINVAL;
+	}
+
+	dev_info(spinand->slave->dev,
+		 "%s SPI NAND was found.\n", spinand->manufacturer->name);
+	dev_info(spinand->slave->dev,
+		 "%llu MiB, block size: %zu KiB, page size: %zu, OOB size: %u\n",
+		 nanddev_size(nand) >> 20, nanddev_eraseblock_size(nand) >> 10,
+		 nanddev_page_size(nand), nanddev_per_page_oobsize(nand));
+
+	return 0;
+}
+
+static int spinand_noecc_ooblayout_ecc(struct mtd_info *mtd, int section,
+				       struct mtd_oob_region *region)
+{
+	return -ERANGE;
+}
+
+static int spinand_noecc_ooblayout_free(struct mtd_info *mtd, int section,
+					struct mtd_oob_region *region)
+{
+	if (section)
+		return -ERANGE;
+
+	/* Reserve 2 bytes for the BBM. */
+	region->offset = 2;
+	region->length = 62;
+
+	return 0;
+}
+
+static const struct mtd_ooblayout_ops spinand_noecc_ooblayout = {
+	.ecc = spinand_noecc_ooblayout_ecc,
+	.free = spinand_noecc_ooblayout_free,
+};
+
+static int spinand_init(struct spinand_device *spinand)
+{
+	struct mtd_info *mtd = spinand_to_mtd(spinand);
+	struct nand_device *nand = mtd_to_nanddev(mtd);
+	int ret, i;
+
+	/*
+	 * We need a scratch buffer because the spi_mem interface requires that
+	 * buf passed in spi_mem_op->data.buf be DMA-able.
+	 */
+	spinand->scratchbuf = kzalloc(SPINAND_MAX_ID_LEN, GFP_KERNEL);
+	if (!spinand->scratchbuf)
+		return -ENOMEM;
+
+	ret = spinand_detect(spinand);
+	if (ret)
+		goto err_free_bufs;
+
+	/*
+	 * Use kzalloc() instead of devm_kzalloc() here, because some drivers
+	 * may use this buffer for DMA access.
+	 * Memory allocated by devm_ does not guarantee DMA-safe alignment.
+	 */
+	spinand->databuf = kzalloc(nanddev_page_size(nand) +
+			       nanddev_per_page_oobsize(nand),
+			       GFP_KERNEL);
+	if (!spinand->databuf)
+		goto err_free_bufs;
+
+	spinand->oobbuf = spinand->databuf + nanddev_page_size(nand);
+
+	ret = spinand_init_cfg_cache(spinand);
+	if (ret)
+		goto err_free_bufs;
+
+	ret = spinand_init_quad_enable(spinand);
+	if (ret)
+		goto err_free_bufs;
+
+	ret = spinand_upd_cfg(spinand, CFG_OTP_ENABLE, 0);
+	if (ret)
+		goto err_free_bufs;
+
+	ret = spinand_manufacturer_init(spinand);
+	if (ret) {
+		dev_err(dev,
+			"Failed to initialize the SPI NAND chip (err = %d)\n",
+			ret);
+		goto err_free_bufs;
+	}
+
+	/* After power up, all blocks are locked, so unlock them here. */
+	for (i = 0; i < nand->memorg.ntargets; i++) {
+		ret = spinand_select_target(spinand, i);
+		if (ret)
+			goto err_free_bufs;
+
+		ret = spinand_lock_block(spinand, BL_ALL_UNLOCKED);
+		if (ret)
+			goto err_free_bufs;
+	}
+
+	ret = nanddev_init(nand, &spinand_ops, THIS_MODULE);
+	if (ret)
+		goto err_manuf_cleanup;
+
+	/*
+	 * Right now, we don't support ECC, so let the whole oob
+	 * area is available for user.
+	 */
+	mtd->_read_oob = spinand_mtd_read;
+	mtd->_write_oob = spinand_mtd_write;
+	mtd->_block_isbad = spinand_mtd_block_isbad;
+	mtd->_block_markbad = spinand_mtd_block_markbad;
+	mtd->_block_isreserved = spinand_mtd_block_isreserved;
+	mtd->_erase = spinand_mtd_erase;
+
+	if (spinand->eccinfo.ooblayout)
+		mtd_set_ooblayout(mtd, spinand->eccinfo.ooblayout);
+	else
+		mtd_set_ooblayout(mtd, &spinand_noecc_ooblayout);
+
+	ret = mtd_ooblayout_count_freebytes(mtd);
+	if (ret < 0)
+		goto err_cleanup_nanddev;
+
+	mtd->oobavail = ret;
+
+	return 0;
+
+err_cleanup_nanddev:
+	nanddev_cleanup(nand);
+
+err_manuf_cleanup:
+	spinand_manufacturer_cleanup(spinand);
+
+err_free_bufs:
+	kfree(spinand->databuf);
+	kfree(spinand->scratchbuf);
+	return ret;
+}
+
+static void spinand_cleanup(struct spinand_device *spinand)
+{
+	struct nand_device *nand = spinand_to_nand(spinand);
+
+	nanddev_cleanup(nand);
+	spinand_manufacturer_cleanup(spinand);
+	kfree(spinand->databuf);
+	kfree(spinand->scratchbuf);
+}
+
+static int spinand_probe(struct udevice *dev)
+{
+	struct spinand_device *spinand = dev_get_priv(dev);
+	struct spi_slave *slave = dev_get_parent_priv(dev);
+	struct mtd_info *mtd = dev_get_uclass_priv(dev);
+	struct nand_device *nand = spinand_to_nand(spinand);
+	int ret;
+
+#ifndef __UBOOT__
+	spinand = devm_kzalloc(&mem->spi->dev, sizeof(*spinand),
+			       GFP_KERNEL);
+	if (!spinand)
+		return -ENOMEM;
+
+	spinand->spimem = mem;
+	spi_mem_set_drvdata(mem, spinand);
+	spinand_set_of_node(spinand, mem->spi->dev.of_node);
+	mutex_init(&spinand->lock);
+
+	mtd = spinand_to_mtd(spinand);
+	mtd->dev.parent = &mem->spi->dev;
+#else
+	nand->mtd = mtd;
+	mtd->priv = nand;
+	mtd->dev = dev;
+	mtd->name = malloc(20);
+	if (!mtd->name)
+		return -ENOMEM;
+	sprintf(mtd->name, "spi-nand%d", spi_nand_idx++);
+	spinand->slave = slave;
+	spinand_set_of_node(spinand, dev->node.np);
+#endif
+
+	ret = spinand_init(spinand);
+	if (ret)
+		return ret;
+
+#ifndef __UBOOT__
+	ret = mtd_device_register(mtd, NULL, 0);
+#else
+	ret = add_mtd_device(mtd);
+#endif
+	if (ret)
+		goto err_spinand_cleanup;
+
+	return 0;
+
+err_spinand_cleanup:
+	spinand_cleanup(spinand);
+
+	return ret;
+}
+
+#ifndef __UBOOT__
+static int spinand_remove(struct udevice *slave)
+{
+	struct spinand_device *spinand;
+	struct mtd_info *mtd;
+	int ret;
+
+	spinand = spi_mem_get_drvdata(slave);
+	mtd = spinand_to_mtd(spinand);
+	free(mtd->name);
+
+	ret = mtd_device_unregister(mtd);
+	if (ret)
+		return ret;
+
+	spinand_cleanup(spinand);
+
+	return 0;
+}
+
+static const struct spi_device_id spinand_ids[] = {
+	{ .name = "spi-nand" },
+	{ /* sentinel */ },
+};
+
+#ifdef CONFIG_OF
+static const struct of_device_id spinand_of_ids[] = {
+	{ .compatible = "spi-nand" },
+	{ /* sentinel */ },
+};
+#endif
+
+static struct spi_mem_driver spinand_drv = {
+	.spidrv = {
+		.id_table = spinand_ids,
+		.driver = {
+			.name = "spi-nand",
+			.of_match_table = of_match_ptr(spinand_of_ids),
+		},
+	},
+	.probe = spinand_probe,
+	.remove = spinand_remove,
+};
+module_spi_mem_driver(spinand_drv);
+
+MODULE_DESCRIPTION("SPI NAND framework");
+MODULE_AUTHOR("Peter Pan<peterpandong@micron.com>");
+MODULE_LICENSE("GPL v2");
+#endif /* __UBOOT__ */
+
+static const struct udevice_id spinand_ids[] = {
+	{ .compatible = "spi-nand" },
+	{ /* sentinel */ },
+};
+
+U_BOOT_DRIVER(spinand) = {
+	.name = "spi_nand",
+	.id = UCLASS_MTD,
+	.of_match = spinand_ids,
+	.priv_auto_alloc_size = sizeof(struct spinand_device),
+	.probe = spinand_probe,
+};
diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
new file mode 100644
index 0000000000..ad59fc01ef
--- /dev/null
+++ b/include/linux/mtd/spinand.h
@@ -0,0 +1,427 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2016-2017 Micron Technology, Inc.
+ *
+ *  Authors:
+ *	Peter Pan <peterpandong@micron.com>
+ */
+#ifndef __LINUX_MTD_SPINAND_H
+#define __LINUX_MTD_SPINAND_H
+
+#ifndef __UBOOT__
+#include <linux/mutex.h>
+#include <linux/bitops.h>
+#include <linux/device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/spi-mem.h>
+#else
+#include <common.h>
+#include <spi.h>
+#include <spi-mem.h>
+#include <linux/mtd/nand.h>
+#endif
+
+/**
+ * Standard SPI NAND flash operations
+ */
+
+#define SPINAND_RESET_OP						\
+	SPI_MEM_OP(SPI_MEM_OP_CMD(0xff, 1),				\
+		   SPI_MEM_OP_NO_ADDR,					\
+		   SPI_MEM_OP_NO_DUMMY,					\
+		   SPI_MEM_OP_NO_DATA)
+
+#define SPINAND_WR_EN_DIS_OP(enable)					\
+	SPI_MEM_OP(SPI_MEM_OP_CMD((enable) ? 0x06 : 0x04, 1),		\
+		   SPI_MEM_OP_NO_ADDR,					\
+		   SPI_MEM_OP_NO_DUMMY,					\
+		   SPI_MEM_OP_NO_DATA)
+
+#define SPINAND_READID_OP(ndummy, buf, len)				\
+	SPI_MEM_OP(SPI_MEM_OP_CMD(0x9f, 1),				\
+		   SPI_MEM_OP_NO_ADDR,					\
+		   SPI_MEM_OP_DUMMY(ndummy, 1),				\
+		   SPI_MEM_OP_DATA_IN(len, buf, 1))
+
+#define SPINAND_SET_FEATURE_OP(reg, valptr)				\
+	SPI_MEM_OP(SPI_MEM_OP_CMD(0x1f, 1),				\
+		   SPI_MEM_OP_ADDR(1, reg, 1),				\
+		   SPI_MEM_OP_NO_DUMMY,					\
+		   SPI_MEM_OP_DATA_OUT(1, valptr, 1))
+
+#define SPINAND_GET_FEATURE_OP(reg, valptr)				\
+	SPI_MEM_OP(SPI_MEM_OP_CMD(0x0f, 1),				\
+		   SPI_MEM_OP_ADDR(1, reg, 1),				\
+		   SPI_MEM_OP_NO_DUMMY,					\
+		   SPI_MEM_OP_DATA_IN(1, valptr, 1))
+
+#define SPINAND_BLK_ERASE_OP(addr)					\
+	SPI_MEM_OP(SPI_MEM_OP_CMD(0xd8, 1),				\
+		   SPI_MEM_OP_ADDR(3, addr, 1),				\
+		   SPI_MEM_OP_NO_DUMMY,					\
+		   SPI_MEM_OP_NO_DATA)
+
+#define SPINAND_PAGE_READ_OP(addr)					\
+	SPI_MEM_OP(SPI_MEM_OP_CMD(0x13, 1),				\
+		   SPI_MEM_OP_ADDR(3, addr, 1),				\
+		   SPI_MEM_OP_NO_DUMMY,					\
+		   SPI_MEM_OP_NO_DATA)
+
+#define SPINAND_PAGE_READ_FROM_CACHE_OP(fast, addr, ndummy, buf, len)	\
+	SPI_MEM_OP(SPI_MEM_OP_CMD(fast ? 0x0b : 0x03, 1),		\
+		   SPI_MEM_OP_ADDR(2, addr, 1),				\
+		   SPI_MEM_OP_DUMMY(ndummy, 1),				\
+		   SPI_MEM_OP_DATA_IN(len, buf, 1))
+
+#define SPINAND_PAGE_READ_FROM_CACHE_X2_OP(addr, ndummy, buf, len)	\
+	SPI_MEM_OP(SPI_MEM_OP_CMD(0x3b, 1),				\
+		   SPI_MEM_OP_ADDR(2, addr, 1),				\
+		   SPI_MEM_OP_DUMMY(ndummy, 1),				\
+		   SPI_MEM_OP_DATA_IN(len, buf, 2))
+
+#define SPINAND_PAGE_READ_FROM_CACHE_X4_OP(addr, ndummy, buf, len)	\
+	SPI_MEM_OP(SPI_MEM_OP_CMD(0x6b, 1),				\
+		   SPI_MEM_OP_ADDR(2, addr, 1),				\
+		   SPI_MEM_OP_DUMMY(ndummy, 1),				\
+		   SPI_MEM_OP_DATA_IN(len, buf, 4))
+
+#define SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(addr, ndummy, buf, len)	\
+	SPI_MEM_OP(SPI_MEM_OP_CMD(0xbb, 1),				\
+		   SPI_MEM_OP_ADDR(2, addr, 2),				\
+		   SPI_MEM_OP_DUMMY(ndummy, 2),				\
+		   SPI_MEM_OP_DATA_IN(len, buf, 2))
+
+#define SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(addr, ndummy, buf, len)	\
+	SPI_MEM_OP(SPI_MEM_OP_CMD(0xeb, 1),				\
+		   SPI_MEM_OP_ADDR(2, addr, 4),				\
+		   SPI_MEM_OP_DUMMY(ndummy, 4),				\
+		   SPI_MEM_OP_DATA_IN(len, buf, 4))
+
+#define SPINAND_PROG_EXEC_OP(addr)					\
+	SPI_MEM_OP(SPI_MEM_OP_CMD(0x10, 1),				\
+		   SPI_MEM_OP_ADDR(3, addr, 1),				\
+		   SPI_MEM_OP_NO_DUMMY,					\
+		   SPI_MEM_OP_NO_DATA)
+
+#define SPINAND_PROG_LOAD(reset, addr, buf, len)			\
+	SPI_MEM_OP(SPI_MEM_OP_CMD(reset ? 0x02 : 0x84, 1),		\
+		   SPI_MEM_OP_ADDR(2, addr, 1),				\
+		   SPI_MEM_OP_NO_DUMMY,					\
+		   SPI_MEM_OP_DATA_OUT(len, buf, 1))
+
+#define SPINAND_PROG_LOAD_X4(reset, addr, buf, len)			\
+	SPI_MEM_OP(SPI_MEM_OP_CMD(reset ? 0x32 : 0x34, 1),		\
+		   SPI_MEM_OP_ADDR(2, addr, 1),				\
+		   SPI_MEM_OP_NO_DUMMY,					\
+		   SPI_MEM_OP_DATA_OUT(len, buf, 4))
+
+/**
+ * Standard SPI NAND flash commands
+ */
+#define SPINAND_CMD_PROG_LOAD_X4		0x32
+#define SPINAND_CMD_PROG_LOAD_RDM_DATA_X4	0x34
+
+/* feature register */
+#define REG_BLOCK_LOCK		0xa0
+#define BL_ALL_UNLOCKED		0x00
+
+/* configuration register */
+#define REG_CFG			0xb0
+#define CFG_OTP_ENABLE		BIT(6)
+#define CFG_ECC_ENABLE		BIT(4)
+#define CFG_QUAD_ENABLE		BIT(0)
+
+/* status register */
+#define REG_STATUS		0xc0
+#define STATUS_BUSY		BIT(0)
+#define STATUS_ERASE_FAILED	BIT(2)
+#define STATUS_PROG_FAILED	BIT(3)
+#define STATUS_ECC_MASK		GENMASK(5, 4)
+#define STATUS_ECC_NO_BITFLIPS	(0 << 4)
+#define STATUS_ECC_HAS_BITFLIPS	(1 << 4)
+#define STATUS_ECC_UNCOR_ERROR	(2 << 4)
+
+struct spinand_op;
+struct spinand_device;
+
+#define SPINAND_MAX_ID_LEN	4
+
+/**
+ * struct spinand_id - SPI NAND id structure
+ * @data: buffer containing the id bytes. Currently 4 bytes large, but can
+ *	  be extended if required
+ * @len: ID length
+ *
+ * struct_spinand_id->data contains all bytes returned after a READ_ID command,
+ * including dummy bytes if the chip does not emit ID bytes right after the
+ * READ_ID command. The responsibility to extract real ID bytes is left to
+ * struct_manufacurer_ops->detect().
+ */
+struct spinand_id {
+	u8 data[SPINAND_MAX_ID_LEN];
+	int len;
+};
+
+/**
+ * struct manufacurer_ops - SPI NAND manufacturer specific operations
+ * @detect: detect a SPI NAND device. Every time a SPI NAND device is probed
+ *	    the core calls the struct_manufacurer_ops->detect() hook of each
+ *	    registered manufacturer until one of them return 1. Note that
+ *	    the first thing to check in this hook is that the manufacturer ID
+ *	    in struct_spinand_device->id matches the manufacturer whose
+ *	    ->detect() hook has been called. Should return 1 if there's a
+ *	    match, 0 if the manufacturer ID does not match and a negative
+ *	    error code otherwise. When true is returned, the core assumes
+ *	    that properties of the NAND chip (spinand->base.memorg and
+ *	    spinand->base.eccreq) have been filled
+ * @init: initialize a SPI NAND device
+ * @cleanup: cleanup a SPI NAND device
+ *
+ * Each SPI NAND manufacturer driver should implement this interface so that
+ * NAND chips coming from this vendor can be detected and initialized properly.
+ */
+struct spinand_manufacturer_ops {
+	int (*detect)(struct spinand_device *spinand);
+	int (*init)(struct spinand_device *spinand);
+	void (*cleanup)(struct spinand_device *spinand);
+};
+
+/**
+ * struct spinand_manufacturer - SPI NAND manufacturer instance
+ * @id: manufacturer ID
+ * @name: manufacturer name
+ * @ops: manufacturer operations
+ */
+struct spinand_manufacturer {
+	u8 id;
+	char *name;
+	const struct spinand_manufacturer_ops *ops;
+};
+
+/**
+ * struct spinand_op_variants - SPI NAND operation variants
+ * @ops: the list of variants for a given operation
+ * @nops: the number of variants
+ *
+ * Some operations like read-from-cache/write-to-cache have several variants
+ * depending on the number of IO lines you use to transfer data or address
+ * cycles. This structure is a way to describe the different variants supported
+ * by a chip and let the core pick the best one based on the SPI mem controller
+ * capabilities.
+ */
+struct spinand_op_variants {
+	const struct spi_mem_op *ops;
+	unsigned int nops;
+};
+
+#define SPINAND_OP_VARIANTS(name, ...)					\
+	const struct spinand_op_variants name = {			\
+		.ops = (struct spi_mem_op[]) { __VA_ARGS__ },		\
+		.nops = sizeof((struct spi_mem_op[]){ __VA_ARGS__ }) /	\
+			sizeof(struct spi_mem_op),			\
+	}
+
+/**
+ * spinand_ecc_info - description of the on-die ECC implemented by a SPI NAND
+ *		      chip
+ * @get_status: get the ECC status. Should return a positive number encoding
+ *		the number of corrected bitflips if correction was possible or
+ *		-EBADMSG if there are uncorrectable errors. I can also return
+ *		other negative error codes if the error is not caused by
+ *		uncorrectable bitflips
+ * @ooblayout: the OOB layout used by the on-die ECC implementation
+ */
+struct spinand_ecc_info {
+	int (*get_status)(struct spinand_device *spinand, u8 status);
+	const struct mtd_ooblayout_ops *ooblayout;
+};
+
+#define SPINAND_HAS_QE_BIT		BIT(0)
+
+/**
+ * struct spinand_info - Structure used to describe SPI NAND chips
+ * @model: model name
+ * @devid: device ID
+ * @flags: OR-ing of the SPINAND_XXX flags
+ * @memorg: memory organization
+ * @eccreq: ECC requirements
+ * @eccinfo: on-die ECC info
+ * @op_variants: operations variants
+ * @op_variants.read_cache: variants of the read-cache operation
+ * @op_variants.write_cache: variants of the write-cache operation
+ * @op_variants.update_cache: variants of the update-cache operation
+ * @select_target: function used to select a target/die. Required only for
+ *		   multi-die chips
+ *
+ * Each SPI NAND manufacturer driver should have a spinand_info table
+ * describing all the chips supported by the driver.
+ */
+struct spinand_info {
+	const char *model;
+	u8 devid;
+	u32 flags;
+	struct nand_memory_organization memorg;
+	struct nand_ecc_req eccreq;
+	struct spinand_ecc_info eccinfo;
+	struct {
+		const struct spinand_op_variants *read_cache;
+		const struct spinand_op_variants *write_cache;
+		const struct spinand_op_variants *update_cache;
+	} op_variants;
+	int (*select_target)(struct spinand_device *spinand,
+			     unsigned int target);
+};
+
+#define SPINAND_INFO_OP_VARIANTS(__read, __write, __update)		\
+	{								\
+		.read_cache = __read,					\
+		.write_cache = __write,					\
+		.update_cache = __update,				\
+	}
+
+#define SPINAND_ECCINFO(__ooblayout, __get_status)			\
+	.eccinfo = {							\
+		.ooblayout = __ooblayout,				\
+		.get_status = __get_status,				\
+	}
+
+#define SPINAND_SELECT_TARGET(__func)					\
+	.select_target = __func,
+
+#define SPINAND_INFO(__model, __id, __memorg, __eccreq, __op_variants,	\
+		     __flags, ...)					\
+	{								\
+		.model = __model,					\
+		.devid = __id,						\
+		.memorg = __memorg,					\
+		.eccreq = __eccreq,					\
+		.op_variants = __op_variants,				\
+		.flags = __flags,					\
+		__VA_ARGS__						\
+	}
+
+/**
+ * struct spinand_device - SPI NAND device instance
+ * @base: NAND device instance
+ * @slave: pointer to the SPI slave object
+ * @lock: lock used to serialize accesses to the NAND
+ * @id: NAND ID as returned by READ_ID
+ * @flags: NAND flags
+ * @op_templates: various SPI mem op templates
+ * @op_templates.read_cache: read cache op template
+ * @op_templates.write_cache: write cache op template
+ * @op_templates.update_cache: update cache op template
+ * @select_target: select a specific target/die. Usually called before sending
+ *		   a command addressing a page or an eraseblock embedded in
+ *		   this die. Only required if your chip exposes several dies
+ * @cur_target: currently selected target/die
+ * @eccinfo: on-die ECC information
+ * @cfg_cache: config register cache. One entry per die
+ * @databuf: bounce buffer for data
+ * @oobbuf: bounce buffer for OOB data
+ * @scratchbuf: buffer used for everything but page accesses. This is needed
+ *		because the spi-mem interface explicitly requests that buffers
+ *		passed in spi_mem_op be DMA-able, so we can't based the bufs on
+ *		the stack
+ * @manufacturer: SPI NAND manufacturer information
+ * @priv: manufacturer private data
+ */
+struct spinand_device {
+	struct nand_device base;
+#ifndef __UBOOT__
+	struct spi_mem *spimem;
+	struct mutex lock;
+#else
+	struct spi_slave *slave;
+#endif
+	struct spinand_id id;
+	u32 flags;
+
+	struct {
+		const struct spi_mem_op *read_cache;
+		const struct spi_mem_op *write_cache;
+		const struct spi_mem_op *update_cache;
+	} op_templates;
+
+	int (*select_target)(struct spinand_device *spinand,
+			     unsigned int target);
+	unsigned int cur_target;
+
+	struct spinand_ecc_info eccinfo;
+
+	u8 *cfg_cache;
+	u8 *databuf;
+	u8 *oobbuf;
+	u8 *scratchbuf;
+	const struct spinand_manufacturer *manufacturer;
+	void *priv;
+};
+
+/**
+ * mtd_to_spinand() - Get the SPI NAND device attached to an MTD instance
+ * @mtd: MTD instance
+ *
+ * Return: the SPI NAND device attached to @mtd.
+ */
+static inline struct spinand_device *mtd_to_spinand(struct mtd_info *mtd)
+{
+	return container_of(mtd_to_nanddev(mtd), struct spinand_device, base);
+}
+
+/**
+ * spinand_to_mtd() - Get the MTD device embedded in a SPI NAND device
+ * @spinand: SPI NAND device
+ *
+ * Return: the MTD device embedded in @spinand.
+ */
+static inline struct mtd_info *spinand_to_mtd(struct spinand_device *spinand)
+{
+	return nanddev_to_mtd(&spinand->base);
+}
+
+/**
+ * nand_to_spinand() - Get the SPI NAND device embedding an NAND object
+ * @nand: NAND object
+ *
+ * Return: the SPI NAND device embedding @nand.
+ */
+static inline struct spinand_device *nand_to_spinand(struct nand_device *nand)
+{
+	return container_of(nand, struct spinand_device, base);
+}
+
+/**
+ * spinand_to_nand() - Get the NAND device embedded in a SPI NAND object
+ * @spinand: SPI NAND device
+ *
+ * Return: the NAND device embedded in @spinand.
+ */
+static inline struct nand_device *
+spinand_to_nand(struct spinand_device *spinand)
+{
+	return &spinand->base;
+}
+
+/**
+ * spinand_set_of_node - Attach a DT node to a SPI NAND device
+ * @spinand: SPI NAND device
+ * @np: DT node
+ *
+ * Attach a DT node to a SPI NAND device.
+ */
+static inline void spinand_set_of_node(struct spinand_device *spinand,
+				       const struct device_node *np)
+{
+	nanddev_set_of_node(&spinand->base, np);
+}
+
+int spinand_match_and_init(struct spinand_device *dev,
+			   const struct spinand_info *table,
+			   unsigned int table_size, u8 devid);
+
+int spinand_upd_cfg(struct spinand_device *spinand, u8 mask, u8 val);
+int spinand_select_target(struct spinand_device *spinand, unsigned int target);
+
+#endif /* __LINUX_MTD_SPINAND_H */
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [U-Boot] [RFC PATCH 12/20] mtd: spinand: Add initial support for Micron MT29F2G01ABAGD
  2018-06-06 15:30 [U-Boot] [RFC PATCH 00/20] SPI-NAND support Miquel Raynal
                   ` (10 preceding siblings ...)
  2018-06-06 15:30 ` [U-Boot] [RFC PATCH 11/20] mtd: nand: Add core infrastructure to support SPI NANDs Miquel Raynal
@ 2018-06-06 15:30 ` Miquel Raynal
  2018-06-06 15:30 ` [U-Boot] [RFC PATCH 13/20] mtd: spinand: Add initial support for Winbond W25M02GV Miquel Raynal
                   ` (10 subsequent siblings)
  22 siblings, 0 replies; 65+ messages in thread
From: Miquel Raynal @ 2018-06-06 15:30 UTC (permalink / raw)
  To: u-boot

From: Peter Pan <peterpandong@micron.com>

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.

Signed-off-by: Peter Pan <peterpandong@micron.com>
Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 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

diff --git a/drivers/mtd/nand/spi/Makefile b/drivers/mtd/nand/spi/Makefile
index f0c6e69d2e..4eb745abd4 100644
--- a/drivers/mtd/nand/spi/Makefile
+++ b/drivers/mtd/nand/spi/Makefile
@@ -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
diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
index d2e912aeb5..8b01aeb7e7 100644
--- a/drivers/mtd/nand/spi/core.c
+++ b/drivers/mtd/nand/spi/core.c
@@ -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;
 }
 
diff --git a/drivers/mtd/nand/spi/micron.c b/drivers/mtd/nand/spi/micron.c
new file mode 100644
index 0000000000..83951c5d0f
--- /dev/null
+++ b/drivers/mtd/nand/spi/micron.c
@@ -0,0 +1,135 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2016-2017 Micron Technology, Inc.
+ *
+ * Authors:
+ *	Peter Pan <peterpandong@micron.com>
+ */
+
+#ifndef __UBOOT__
+#include <linux/device.h>
+#include <linux/kernel.h>
+#endif
+#include <linux/mtd/spinand.h>
+
+#define SPINAND_MFR_MICRON		0x2c
+
+#define MICRON_STATUS_ECC_MASK		GENMASK(7, 4)
+#define MICRON_STATUS_ECC_NO_BITFLIPS	(0 << 4)
+#define MICRON_STATUS_ECC_1TO3_BITFLIPS	(1 << 4)
+#define MICRON_STATUS_ECC_4TO6_BITFLIPS	(3 << 4)
+#define MICRON_STATUS_ECC_7TO8_BITFLIPS	(5 << 4)
+
+static SPINAND_OP_VARIANTS(read_cache_variants,
+		SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
+		SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
+		SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
+		SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
+		SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
+		SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
+
+static SPINAND_OP_VARIANTS(write_cache_variants,
+		SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
+		SPINAND_PROG_LOAD(true, 0, NULL, 0));
+
+static SPINAND_OP_VARIANTS(update_cache_variants,
+		SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
+		SPINAND_PROG_LOAD(false, 0, NULL, 0));
+
+static int mt29f2g01abagd_ooblayout_ecc(struct mtd_info *mtd, int section,
+					struct mtd_oob_region *region)
+{
+	if (section)
+		return -ERANGE;
+
+	region->offset = 64;
+	region->length = 64;
+
+	return 0;
+}
+
+static int mt29f2g01abagd_ooblayout_free(struct mtd_info *mtd, int section,
+					 struct mtd_oob_region *region)
+{
+	if (section)
+		return -ERANGE;
+
+	/* Reserve 2 bytes for the BBM. */
+	region->offset = 2;
+	region->length = 62;
+
+	return 0;
+}
+
+static const struct mtd_ooblayout_ops mt29f2g01abagd_ooblayout = {
+	.ecc = mt29f2g01abagd_ooblayout_ecc,
+	.free = mt29f2g01abagd_ooblayout_free,
+};
+
+static int mt29f2g01abagd_ecc_get_status(struct spinand_device *spinand,
+					 u8 status)
+{
+	switch (status & MICRON_STATUS_ECC_MASK) {
+	case STATUS_ECC_NO_BITFLIPS:
+		return 0;
+
+	case STATUS_ECC_UNCOR_ERROR:
+		return -EBADMSG;
+
+	case MICRON_STATUS_ECC_1TO3_BITFLIPS:
+		return 3;
+
+	case MICRON_STATUS_ECC_4TO6_BITFLIPS:
+		return 6;
+
+	case MICRON_STATUS_ECC_7TO8_BITFLIPS:
+		return 8;
+
+	default:
+		break;
+	}
+
+	return -EINVAL;
+}
+
+static const struct spinand_info micron_spinand_table[] = {
+	SPINAND_INFO("MT29F2G01ABAGD", 0x24,
+		     NAND_MEMORG(1, 2048, 128, 64, 2048, 2, 1, 1),
+		     NAND_ECCREQ(8, 512),
+		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+					      &write_cache_variants,
+					      &update_cache_variants),
+		     0,
+		     SPINAND_ECCINFO(&mt29f2g01abagd_ooblayout,
+				     mt29f2g01abagd_ecc_get_status)),
+};
+
+static int micron_spinand_detect(struct spinand_device *spinand)
+{
+	u8 *id = spinand->id.data;
+	int ret;
+
+	/*
+	 * Micron SPI NAND read ID need a dummy byte,
+	 * so the first byte in raw_id is dummy.
+	 */
+	if (id[1] != SPINAND_MFR_MICRON)
+		return 0;
+
+	ret = spinand_match_and_init(spinand, micron_spinand_table,
+				     ARRAY_SIZE(micron_spinand_table), id[2]);
+	if (ret)
+		return ret;
+
+	return 1;
+}
+
+static const struct spinand_manufacturer_ops micron_spinand_manuf_ops = {
+	.detect = micron_spinand_detect,
+};
+
+const struct spinand_manufacturer micron_spinand_manufacturer = {
+	.id = SPINAND_MFR_MICRON,
+	.name = "Micron",
+	.ops = &micron_spinand_manuf_ops,
+};
diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
index ad59fc01ef..5302d38de8 100644
--- a/include/linux/mtd/spinand.h
+++ b/include/linux/mtd/spinand.h
@@ -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
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [U-Boot] [RFC PATCH 13/20] mtd: spinand: Add initial support for Winbond W25M02GV
  2018-06-06 15:30 [U-Boot] [RFC PATCH 00/20] SPI-NAND support Miquel Raynal
                   ` (11 preceding siblings ...)
  2018-06-06 15:30 ` [U-Boot] [RFC PATCH 12/20] mtd: spinand: Add initial support for Micron MT29F2G01ABAGD Miquel Raynal
@ 2018-06-06 15:30 ` Miquel Raynal
  2018-06-06 15:30 ` [U-Boot] [RFC PATCH 14/20] mtd: spinand: Add initial support for the MX35LF1GE4AB chip Miquel Raynal
                   ` (9 subsequent siblings)
  22 siblings, 0 replies; 65+ messages in thread
From: Miquel Raynal @ 2018-06-06 15:30 UTC (permalink / raw)
  To: u-boot

From: Frieder Schrempf <frieder.schrempf@exceet.de>

Add support for the W25M02GV chip.

Signed-off-by: Frieder Schrempf <frieder.schrempf@exceet.de>
Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 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

diff --git a/drivers/mtd/nand/spi/Makefile b/drivers/mtd/nand/spi/Makefile
index 4eb745abd4..11ba5de68b 100644
--- a/drivers/mtd/nand/spi/Makefile
+++ b/drivers/mtd/nand/spi/Makefile
@@ -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
diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
index 8b01aeb7e7..f151f671fa 100644
--- a/drivers/mtd/nand/spi/core.c
+++ b/drivers/mtd/nand/spi/core.c
@@ -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)
diff --git a/drivers/mtd/nand/spi/winbond.c b/drivers/mtd/nand/spi/winbond.c
new file mode 100644
index 0000000000..eac811d97c
--- /dev/null
+++ b/drivers/mtd/nand/spi/winbond.c
@@ -0,0 +1,143 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2017 exceet electronics GmbH
+ *
+ * Authors:
+ *	Frieder Schrempf <frieder.schrempf@exceet.de>
+ *	Boris Brezillon <boris.brezillon@bootlin.com>
+ */
+
+#ifndef __UBOOT__
+#include <linux/device.h>
+#include <linux/kernel.h>
+#endif
+#include <linux/mtd/spinand.h>
+
+#define SPINAND_MFR_WINBOND		0xEF
+
+#define WINBOND_CFG_BUF_READ		BIT(3)
+
+static SPINAND_OP_VARIANTS(read_cache_variants,
+		SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
+		SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
+		SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
+		SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
+		SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
+		SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
+
+static SPINAND_OP_VARIANTS(write_cache_variants,
+		SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
+		SPINAND_PROG_LOAD(true, 0, NULL, 0));
+
+static SPINAND_OP_VARIANTS(update_cache_variants,
+		SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
+		SPINAND_PROG_LOAD(false, 0, NULL, 0));
+
+static int w25m02gv_ooblayout_ecc(struct mtd_info *mtd, int section,
+				  struct mtd_oob_region *region)
+{
+	if (section > 3)
+		return -ERANGE;
+
+	region->offset = (16 * section) + 8;
+	region->length = 8;
+
+	return 0;
+}
+
+static int w25m02gv_ooblayout_free(struct mtd_info *mtd, int section,
+				   struct mtd_oob_region *region)
+{
+	if (section > 3)
+		return -ERANGE;
+
+	region->offset = (16 * section) + 2;
+	region->length = 6;
+
+	return 0;
+}
+
+static const struct mtd_ooblayout_ops w25m02gv_ooblayout = {
+	.ecc = w25m02gv_ooblayout_ecc,
+	.free = w25m02gv_ooblayout_free,
+};
+
+static int w25m02gv_select_target(struct spinand_device *spinand,
+				  unsigned int target)
+{
+	struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(0xc2, 1),
+					  SPI_MEM_OP_NO_ADDR,
+					  SPI_MEM_OP_NO_DUMMY,
+					  SPI_MEM_OP_DATA_OUT(1,
+							spinand->scratchbuf,
+							1));
+
+	*spinand->scratchbuf = target;
+	return spi_mem_exec_op(spinand->slave, &op);
+}
+
+static const struct spinand_info winbond_spinand_table[] = {
+	SPINAND_INFO("W25M02GV", 0xAB,
+		     NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 2),
+		     NAND_ECCREQ(1, 512),
+		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+					      &write_cache_variants,
+					      &update_cache_variants),
+		     0,
+		     SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL),
+		     SPINAND_SELECT_TARGET(w25m02gv_select_target)),
+};
+
+/**
+ * winbond_spinand_detect - initialize device related part in spinand_device
+ * struct if it is a Winbond device.
+ * @spinand: SPI NAND device structure
+ */
+static int winbond_spinand_detect(struct spinand_device *spinand)
+{
+	u8 *id = spinand->id.data;
+	int ret;
+
+	/*
+	 * Winbond SPI NAND read ID need a dummy byte,
+	 * so the first byte in raw_id is dummy.
+	 */
+	if (id[1] != SPINAND_MFR_WINBOND)
+		return 0;
+
+	ret = spinand_match_and_init(spinand, winbond_spinand_table,
+				     ARRAY_SIZE(winbond_spinand_table), id[2]);
+	if (ret)
+		return ret;
+
+	return 1;
+}
+
+static int winbond_spinand_init(struct spinand_device *spinand)
+{
+	struct nand_device *nand = spinand_to_nand(spinand);
+	unsigned int i;
+
+	/*
+	 * Make sure all dies are in buffer read mode and not continuous read
+	 * mode.
+	 */
+	for (i = 0; i < nand->memorg.ntargets; i++) {
+		spinand_select_target(spinand, i);
+		spinand_upd_cfg(spinand, WINBOND_CFG_BUF_READ,
+				WINBOND_CFG_BUF_READ);
+	}
+
+	return 0;
+}
+
+static const struct spinand_manufacturer_ops winbond_spinand_manuf_ops = {
+	.detect = winbond_spinand_detect,
+	.init = winbond_spinand_init,
+};
+
+const struct spinand_manufacturer winbond_spinand_manufacturer = {
+	.id = SPINAND_MFR_WINBOND,
+	.name = "Winbond",
+	.ops = &winbond_spinand_manuf_ops,
+};
diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
index 5302d38de8..d40a7c8f4e 100644
--- a/include/linux/mtd/spinand.h
+++ b/include/linux/mtd/spinand.h
@@ -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
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [U-Boot] [RFC PATCH 14/20] mtd: spinand: Add initial support for the MX35LF1GE4AB chip
  2018-06-06 15:30 [U-Boot] [RFC PATCH 00/20] SPI-NAND support Miquel Raynal
                   ` (12 preceding siblings ...)
  2018-06-06 15:30 ` [U-Boot] [RFC PATCH 13/20] mtd: spinand: Add initial support for Winbond W25M02GV Miquel Raynal
@ 2018-06-06 15:30 ` Miquel Raynal
  2018-06-06 15:30 ` [U-Boot] [RFC PATCH 15/20] mtd: spinand: Add initial support for the MX35LF2GE4AB chip Miquel Raynal
                   ` (8 subsequent siblings)
  22 siblings, 0 replies; 65+ messages in thread
From: Miquel Raynal @ 2018-06-06 15:30 UTC (permalink / raw)
  To: u-boot

From: Boris Brezillon <boris.brezillon@bootlin.com>

Add minimal support for the MX35LF1GE4AB SPI NAND chip.

Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>
---
 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

diff --git a/drivers/mtd/nand/spi/Makefile b/drivers/mtd/nand/spi/Makefile
index 11ba5de68b..a66edd9199 100644
--- a/drivers/mtd/nand/spi/Makefile
+++ b/drivers/mtd/nand/spi/Makefile
@@ -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
diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
index f151f671fa..6f383852d9 100644
--- a/drivers/mtd/nand/spi/core.c
+++ b/drivers/mtd/nand/spi/core.c
@@ -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,
 };
diff --git a/drivers/mtd/nand/spi/macronix.c b/drivers/mtd/nand/spi/macronix.c
new file mode 100644
index 0000000000..dd351dcb6c
--- /dev/null
+++ b/drivers/mtd/nand/spi/macronix.c
@@ -0,0 +1,138 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018 Macronix
+ *
+ * Author: Boris Brezillon <boris.brezillon@bootlin.com>
+ */
+
+#ifndef __UBOOT__
+#include <linux/device.h>
+#include <linux/kernel.h>
+#endif
+#include <linux/mtd/spinand.h>
+
+#define SPINAND_MFR_MACRONIX		0xC2
+
+static SPINAND_OP_VARIANTS(read_cache_variants,
+		SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
+		SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
+		SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
+		SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
+
+static SPINAND_OP_VARIANTS(write_cache_variants,
+		SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
+		SPINAND_PROG_LOAD(true, 0, NULL, 0));
+
+static SPINAND_OP_VARIANTS(update_cache_variants,
+		SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
+		SPINAND_PROG_LOAD(false, 0, NULL, 0));
+
+static int mx35lf1ge4ab_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,
+				       struct mtd_oob_region *region)
+{
+	if (section)
+		return -ERANGE;
+
+	region->offset = 2;
+	region->length = mtd->oobsize - 2;
+
+	return 0;
+}
+
+static const struct mtd_ooblayout_ops mx35lf1ge4ab_ooblayout = {
+	.ecc = mx35lf1ge4ab_ooblayout_ecc,
+	.free = mx35lf1ge4ab_ooblayout_free,
+};
+
+static int mx35lf1ge4ab_get_eccsr(struct spinand_device *spinand, u8 *eccsr)
+{
+	struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(0x7c, 1),
+					  SPI_MEM_OP_NO_ADDR,
+					  SPI_MEM_OP_DUMMY(1, 1),
+					  SPI_MEM_OP_DATA_IN(1, eccsr, 1));
+
+	return spi_mem_exec_op(spinand->slave, &op);
+}
+
+static int mx35lf1ge4ab_ecc_get_status(struct spinand_device *spinand,
+				       u8 status)
+{
+	struct nand_device *nand = spinand_to_nand(spinand);
+	u8 eccsr;
+
+	switch (status & STATUS_ECC_MASK) {
+	case STATUS_ECC_NO_BITFLIPS:
+		return 0;
+
+	case STATUS_ECC_UNCOR_ERROR:
+		return -EBADMSG;
+
+	case STATUS_ECC_HAS_BITFLIPS:
+		/*
+		 * Let's try to retrieve the real maximum number of bitflips
+		 * in order to avoid forcing the wear-leveling layer to move
+		 * data around if it's not necessary.
+		 */
+		if (mx35lf1ge4ab_get_eccsr(spinand, &eccsr))
+			return nand->eccreq.strength;
+
+		if (WARN_ON(eccsr > nand->eccreq.strength || !eccsr))
+			return nand->eccreq.strength;
+
+		return eccsr;
+
+	default:
+		break;
+	}
+
+	return -EINVAL;
+}
+
+static const struct spinand_info macronix_spinand_table[] = {
+	SPINAND_INFO("MX35LF1GE4AB", 0x12,
+		     NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1),
+		     NAND_ECCREQ(4, 512),
+		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+					      &write_cache_variants,
+					      &update_cache_variants),
+		     SPINAND_HAS_QE_BIT,
+		     SPINAND_ECCINFO(&mx35lf1ge4ab_ooblayout,
+				     mx35lf1ge4ab_ecc_get_status)),
+};
+
+static int macronix_spinand_detect(struct spinand_device *spinand)
+{
+	u8 *id = spinand->id.data;
+	int ret;
+
+	/*
+	 * Macronix SPI NAND read ID needs a dummy byte, so the first byte in
+	 * raw_id is garbage.
+	 */
+	if (id[1] != SPINAND_MFR_MACRONIX)
+		return 0;
+
+	ret = spinand_match_and_init(spinand, macronix_spinand_table,
+				     ARRAY_SIZE(macronix_spinand_table),
+				     id[2]);
+	if (ret)
+		return ret;
+
+	return 1;
+}
+
+static const struct spinand_manufacturer_ops macronix_spinand_manuf_ops = {
+	.detect = macronix_spinand_detect,
+};
+
+const struct spinand_manufacturer macronix_spinand_manufacturer = {
+	.id = SPINAND_MFR_MACRONIX,
+	.name = "Macronix",
+	.ops = &macronix_spinand_manuf_ops,
+};
diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
index d40a7c8f4e..8c9c756179 100644
--- a/include/linux/mtd/spinand.h
+++ b/include/linux/mtd/spinand.h
@@ -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;
 
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [U-Boot] [RFC PATCH 15/20] mtd: spinand: Add initial support for the MX35LF2GE4AB chip
  2018-06-06 15:30 [U-Boot] [RFC PATCH 00/20] SPI-NAND support Miquel Raynal
                   ` (13 preceding siblings ...)
  2018-06-06 15:30 ` [U-Boot] [RFC PATCH 14/20] mtd: spinand: Add initial support for the MX35LF1GE4AB chip Miquel Raynal
@ 2018-06-06 15:30 ` Miquel Raynal
  2018-06-22 12:03   ` Boris Brezillon
  2018-06-06 15:30 ` [U-Boot] [RFC PATCH 16/20] mtd: uclass: add probe function Miquel Raynal
                   ` (7 subsequent siblings)
  22 siblings, 1 reply; 65+ messages in thread
From: Miquel Raynal @ 2018-06-06 15:30 UTC (permalink / raw)
  To: u-boot

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

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 drivers/mtd/nand/spi/macronix.c | 20 ++++++++++++++------
 1 file changed, 14 insertions(+), 6 deletions(-)

diff --git a/drivers/mtd/nand/spi/macronix.c b/drivers/mtd/nand/spi/macronix.c
index dd351dcb6c..d761b99d26 100644
--- a/drivers/mtd/nand/spi/macronix.c
+++ b/drivers/mtd/nand/spi/macronix.c
@@ -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, 1024, 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)
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [U-Boot] [RFC PATCH 16/20] mtd: uclass: add probe function
  2018-06-06 15:30 [U-Boot] [RFC PATCH 00/20] SPI-NAND support Miquel Raynal
                   ` (14 preceding siblings ...)
  2018-06-06 15:30 ` [U-Boot] [RFC PATCH 15/20] mtd: spinand: Add initial support for the MX35LF2GE4AB chip Miquel Raynal
@ 2018-06-06 15:30 ` Miquel Raynal
  2018-06-06 15:30 ` [U-Boot] [RFC PATCH 17/20] cmd: mtd: add 'mtd' command Miquel Raynal
                   ` (6 subsequent siblings)
  22 siblings, 0 replies; 65+ messages in thread
From: Miquel Raynal @ 2018-06-06 15:30 UTC (permalink / raw)
  To: u-boot

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.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 drivers/mtd/mtd-uclass.c | 9 +++++++++
 include/linux/mtd/mtd.h  | 3 +++
 2 files changed, 12 insertions(+)

diff --git a/drivers/mtd/mtd-uclass.c b/drivers/mtd/mtd-uclass.c
index 7b7c48ec5a..1b6533829c 100644
--- a/drivers/mtd/mtd-uclass.c
+++ b/drivers/mtd/mtd-uclass.c
@@ -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",
diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
index b5f9151a70..f89a32ae36 100644
--- a/include/linux/mtd/mtd.h
+++ b/include/linux/mtd/mtd.h
@@ -548,5 +548,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__ */
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [U-Boot] [RFC PATCH 17/20] cmd: mtd: add 'mtd' command
  2018-06-06 15:30 [U-Boot] [RFC PATCH 00/20] SPI-NAND support Miquel Raynal
                   ` (15 preceding siblings ...)
  2018-06-06 15:30 ` [U-Boot] [RFC PATCH 16/20] mtd: uclass: add probe function Miquel Raynal
@ 2018-06-06 15:30 ` Miquel Raynal
  2018-06-06 19:45   ` Boris Brezillon
  2018-07-06 11:38   ` Jagan Teki
  2018-06-06 15:30 ` [U-Boot] [RFC PATCH 18/20] dt-bindings: Add bindings for SPI NAND devices Miquel Raynal
                   ` (5 subsequent siblings)
  22 siblings, 2 replies; 65+ messages in thread
From: Miquel Raynal @ 2018-06-06 15:30 UTC (permalink / raw)
  To: u-boot

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.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 cmd/Kconfig          |   5 +
 cmd/Makefile         |   1 +
 cmd/mtd.c            | 280 +++++++++++++++++++++++++++++++++++++++++++++++++++
 drivers/mtd/Makefile |   2 +-
 4 files changed, 287 insertions(+), 1 deletion(-)
 create mode 100644 cmd/mtd.c

diff --git a/cmd/Kconfig b/cmd/Kconfig
index 136836d146..6e9b629e1c 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -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
diff --git a/cmd/Makefile b/cmd/Makefile
index 9a358e4801..e42db12e1d 100644
--- a/cmd/Makefile
+++ b/cmd/Makefile
@@ -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
diff --git a/cmd/mtd.c b/cmd/mtd.c
new file mode 100644
index 0000000000..fe48378bd0
--- /dev/null
+++ b/cmd/mtd.c
@@ -0,0 +1,280 @@
+// SPDX-License-Identifier:  GPL-2.0+
+/*
+ * mtd.c
+ *
+ * Generic command to handle basic operations on any memory device.
+ *
+ * Copyright: Bootlin, 2018
+ * Author: Miquèl Raynal <miquel.raynal@bootlin.com>
+ */
+
+#include <common.h>
+#include <linux/mtd/mtd.h>
+#include <command.h>
+#include <console.h>
+#include <malloc.h>
+#include <mtd.h>
+#include <mapmem.h>
+#include <dm/device.h>
+#include <dm/uclass-internal.h>
+
+static void mtd_dump_buf(u8 *buf, uint len)
+{
+	int i, j;
+
+	for (i = 0; i < len; ) {
+		printf("0x%08x:\t", i);
+		for (j = 0; j < 8; j++)
+			printf("%02x ", buf[i + j]);
+		printf(" ");
+		i += 8;
+		for (j = 0; j < 8; j++)
+			printf("%02x ", buf[i + j]);
+		printf("\n");
+		i += 8;
+	}
+}
+
+static void mtd_show_device(struct mtd_info *mtd)
+{
+	printf("* %s", mtd->name);
+	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_list(void)
+{
+	struct mtd_info *mtd;
+	struct udevice *dev;
+	int dm_idx = 0, idx = 0;
+
+	/* Ensure all devices compliants with U-Boot driver model are probed */
+	while (!uclass_find_device(UCLASS_MTD, dm_idx, &dev) && dev) {
+		mtd_probe(dev);
+		dm_idx++;
+	}
+
+	printf("MTD devices list (%d DM compliant):\n", dm_idx);
+
+	mtd_for_each_device(mtd) {
+		mtd_show_device(mtd);
+		idx++;
+	}
+
+	if (!idx)
+		printf("No MTD device found\n");
+
+	return 0;
+}
+
+static int do_mtd_read_write(struct mtd_info *mtd, bool read, uint *waddr,
+			     bool raw, bool woob, u64 from, u64 len)
+{
+	u32 buf_len = woob ? mtd->writesize + mtd->oobsize :
+			     ROUND(len, mtd->writesize);
+	u8 *buf = malloc(buf_len);
+	struct mtd_oob_ops ops = {
+		.mode = raw ? MTD_OPS_RAW : 0,
+		.len = len,
+		.ooblen = woob ? mtd->oobsize : 0,
+		.datbuf = buf,
+		.oobbuf = woob ? &buf[mtd->writesize] : NULL,
+	};
+	int ret;
+
+	if (!buf)
+		return -ENOMEM;
+
+	memset(buf, 0xFF, buf_len);
+
+	if (read) {
+		ret = mtd_read_oob(mtd, from, &ops);
+	} else {
+		memcpy(buf, waddr, ops.len + ops.ooblen);
+		ret = mtd_write_oob(mtd, from, &ops);
+	}
+
+	if (ret) {
+		printf("Could not handle %lldB from 0x%08llx on %s, ret %d\n",
+		       len, from, mtd->name, ret);
+		return ret;
+	}
+
+	if (read) {
+		printf("Dump %lld data bytes from 0x%08llx:\n", len, from);
+		mtd_dump_buf(buf, len);
+
+		if (woob) {
+			printf("\nDump %d OOB bytes from 0x%08llx:\n",
+			       mtd->oobsize, from);
+			mtd_dump_buf(&buf[len], mtd->oobsize);
+		}
+	}
+
+	kfree(buf);
+
+	return 0;
+}
+
+static int do_mtd_erase(struct mtd_info *mtd, bool scrub, u64 from, u64 len)
+{
+	struct erase_info erase_infos = {
+		.mtd = mtd,
+		.addr = from,
+		.len = len,
+		.scrub = scrub,
+	};
+
+	return mtd_erase(mtd, &erase_infos);
+}
+
+static int do_mtd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	struct mtd_info *mtd;
+	struct udevice *dev;
+	const char *cmd;
+	char *part;
+	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@least a device ID.
+	 * Check the selected device is valid. Ensure it is probed.
+	 */
+	if (argc < 3)
+		return CMD_RET_USAGE;
+
+	part = argv[2];
+	ret = uclass_find_device_by_name(UCLASS_MTD, part, &dev);
+	if (!ret && dev) {
+		mtd_probe(dev);
+		mtd = (struct mtd_info *)dev_get_uclass_priv(dev);
+		if (!mtd) {
+			printf("Could not retrieve MTD data\n");
+			return -ENODEV;
+		}
+	} else {
+		mtd = get_mtd_device_nm(part);
+		if (IS_ERR_OR_NULL(mtd)) {
+			printf("MTD device %s not found, ret %ld\n", part,
+			       PTR_ERR(mtd));
+			return 1;
+		}
+	}
+
+	argc -= 3;
+	argv += 3;
+
+	/* Do the parsing */
+	if (!strncmp(cmd, "read", 4) || !strncmp(cmd, "write", 5)) {
+		bool read, raw, woob;
+		uint *waddr = NULL;
+		u64 off, len;
+
+		read = !strncmp(cmd, "read", 4);
+		raw = strstr(cmd, ".raw");
+		woob = strstr(cmd, ".oob");
+
+		if (!read) {
+			if (argc < 1)
+				return CMD_RET_USAGE;
+
+			waddr = map_sysmem(simple_strtoul(argv[0], NULL, 10),
+					   0);
+			argc--;
+			argv++;
+		}
+
+		off = argc > 0 ? simple_strtoul(argv[0], NULL, 10) : 0;
+		len = argc > 1 ? simple_strtoul(argv[1], NULL, 10) :
+				 mtd->writesize + (woob ? mtd->oobsize : 0);
+
+		if ((u32)off % mtd->writesize) {
+			printf("Section not page-aligned (0x%x)\n",
+			       mtd->writesize);
+			return -EINVAL;
+		}
+
+		if (woob && (len != (mtd->writesize + mtd->oobsize))) {
+			printf("OOB operations are limited to single pages\n");
+			return -EINVAL;
+		}
+
+		if ((off + len) >= mtd->size) {
+			printf("Access location beyond the end of the chip\n");
+			return -EINVAL;
+		}
+
+		printf("%s (from %p) %lldB at 0x%08llx [%s %s]\n",
+		       read ? "read" : "write", read ? 0 : waddr, len, off,
+		       raw ? "raw" : "", woob ? "oob" : "");
+
+		ret = do_mtd_read_write(mtd, read, waddr, raw, woob, off, len);
+
+		if (!read)
+			unmap_sysmem(waddr);
+
+	} else if (!strcmp(cmd, "erase") || !strcmp(cmd, "scrub")) {
+		bool scrub = !strcmp(cmd, "scrub");
+		bool full_erase = !strncmp(&cmd[5], ".chip", 4);
+		u64 off, len;
+
+		off = argc > 0 ? simple_strtoul(argv[0], NULL, 10) : 0;
+		len = argc > 1 ? simple_strtoul(argv[1], NULL, 10) :
+				 mtd->erasesize;
+		if (full_erase) {
+			off = 0;
+			len = mtd->size;
+		}
+
+		if ((u32)off % mtd->erasesize) {
+			printf("Section not erase-block-aligned (0x%x)\n",
+			       mtd->erasesize);
+			return -EINVAL;
+		}
+
+		if ((u32)len % mtd->erasesize) {
+			printf("Size not aligned with an erase block (%dB)\n",
+			       mtd->erasesize);
+			return -EINVAL;
+		}
+
+		if ((off + len) >= mtd->size) {
+			printf("Cannot read beyond end of chip\n");
+			return -EINVAL;
+		}
+
+		ret = do_mtd_erase(mtd, scrub, off, len);
+	} 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> [<off> [<size>]]\n"
+	"mtd write[.raw][.oob] <name> <addr> [<off> [<size>]]\n"
+	"mtd erase[.chip] <name> [<off> [<size>]]\n"
+	"mtd scrub[.chip] <name> [<off> [<size>]]\n"
+#endif
+	"";
+
+U_BOOT_CMD(mtd, 10, 1, do_mtd, "MTD utils", mtd_help_text);
diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile
index eb0e7264ab..95b5f25fef 100644
--- a/drivers/mtd/Makefile
+++ b/drivers/mtd/Makefile
@@ -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
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [U-Boot] [RFC PATCH 18/20] dt-bindings: Add bindings for SPI NAND devices
  2018-06-06 15:30 [U-Boot] [RFC PATCH 00/20] SPI-NAND support Miquel Raynal
                   ` (16 preceding siblings ...)
  2018-06-06 15:30 ` [U-Boot] [RFC PATCH 17/20] cmd: mtd: add 'mtd' command Miquel Raynal
@ 2018-06-06 15:30 ` Miquel Raynal
  2018-06-06 15:30 ` [U-Boot] [RFC PATCH 19/20] mips: dts: ocelot: describe SPI CS pins Miquel Raynal
                   ` (4 subsequent siblings)
  22 siblings, 0 replies; 65+ messages in thread
From: Miquel Raynal @ 2018-06-06 15:30 UTC (permalink / raw)
  To: u-boot

From: Boris Brezillon <boris.brezillon@bootlin.com>

Add bindings for SPI NAND chips.

Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 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

diff --git a/doc/device-tree-bindings/mtd/spi-nand.txt b/doc/device-tree-bindings/mtd/spi-nand.txt
new file mode 100644
index 0000000000..d55f80196c
--- /dev/null
+++ b/doc/device-tree-bindings/mtd/spi-nand.txt
@@ -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.
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [U-Boot] [RFC PATCH 19/20] mips: dts: ocelot: describe SPI CS pins
  2018-06-06 15:30 [U-Boot] [RFC PATCH 00/20] SPI-NAND support Miquel Raynal
                   ` (17 preceding siblings ...)
  2018-06-06 15:30 ` [U-Boot] [RFC PATCH 18/20] dt-bindings: Add bindings for SPI NAND devices Miquel Raynal
@ 2018-06-06 15:30 ` Miquel Raynal
  2018-06-06 15:30 ` [U-Boot] [RFC PATCH 20/20] mips: dts: ocelot: add the SPI NAND node Miquel Raynal
                   ` (3 subsequent siblings)
  22 siblings, 0 replies; 65+ messages in thread
From: Miquel Raynal @ 2018-06-06 15:30 UTC (permalink / raw)
  To: u-boot

Describe all SPI CS pins that are not part of the SoC. CS0 can only be
used as SPI CS, while CS1, CS2 and CS3 defaults as GPIOs.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 arch/mips/dts/mscc,ocelot.dtsi | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/arch/mips/dts/mscc,ocelot.dtsi b/arch/mips/dts/mscc,ocelot.dtsi
index d1b8868194..8b04f76ed4 100644
--- a/arch/mips/dts/mscc,ocelot.dtsi
+++ b/arch/mips/dts/mscc,ocelot.dtsi
@@ -135,6 +135,26 @@
 				pins = "GPIO_12", "GPIO_13";
 				function = "uart2";
 			};
+
+			spi_cs1_pin: spi-cs1-pin {
+				pins = "GPIO_8";
+				function = "si";
+			};
+
+			spi_cs2_pin: spi-cs2-pin {
+				pins = "GPIO_9";
+				function = "si";
+			};
+
+			spi_cs3_pin: spi-cs3-pin {
+				pins = "GPIO_16";
+				function = "si";
+			};
+
+			spi_cs4_pin: spi-cs4-pin {
+				pins = "GPIO_17";
+				function = "si";
+			};
 		};
 	};
 };
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [U-Boot] [RFC PATCH 20/20] mips: dts: ocelot: add the SPI NAND node
  2018-06-06 15:30 [U-Boot] [RFC PATCH 00/20] SPI-NAND support Miquel Raynal
                   ` (18 preceding siblings ...)
  2018-06-06 15:30 ` [U-Boot] [RFC PATCH 19/20] mips: dts: ocelot: describe SPI CS pins Miquel Raynal
@ 2018-06-06 15:30 ` Miquel Raynal
  2018-06-07  5:51 ` [U-Boot] [RFC PATCH 00/20] SPI-NAND support Jagan Teki
                   ` (2 subsequent siblings)
  22 siblings, 0 replies; 65+ messages in thread
From: Miquel Raynal @ 2018-06-06 15:30 UTC (permalink / raw)
  To: u-boot

Declare the SPI NAND device accessible on the SPI bus with CS1.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 arch/mips/dts/mscc,ocelot_pcb.dtsi | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/arch/mips/dts/mscc,ocelot_pcb.dtsi b/arch/mips/dts/mscc,ocelot_pcb.dtsi
index 4e532363c3..2f37ef92f9 100644
--- a/arch/mips/dts/mscc,ocelot_pcb.dtsi
+++ b/arch/mips/dts/mscc,ocelot_pcb.dtsi
@@ -25,11 +25,20 @@
 
 &spi0 {
 	status = "okay";
+	pinctrl-0 = <&spi_cs1_pin>;
+	pinctrl-names = "default";
+
 	spi-flash at 0 {
 		compatible = "spi-flash";
                 spi-max-frequency = <18000000>; /* input clock */
                 reg = <0>; /* CS0 */
 	};
+
+	spi-nand at 1 {
+		compatible = "spi-nand";
+		spi-max-frequency = <18000000>; /* input clock */
+		reg = <1>; /* CS1 */
+	};
 };
 
 &ethernet {
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [U-Boot] [RFC PATCH 17/20] cmd: mtd: add 'mtd' command
  2018-06-06 15:30 ` [U-Boot] [RFC PATCH 17/20] cmd: mtd: add 'mtd' command Miquel Raynal
@ 2018-06-06 19:45   ` Boris Brezillon
  2018-07-11 13:51     ` Miquel Raynal
  2018-07-06 11:38   ` Jagan Teki
  1 sibling, 1 reply; 65+ messages in thread
From: Boris Brezillon @ 2018-06-06 19:45 UTC (permalink / raw)
  To: u-boot

Hi Miquel,

On Wed,  6 Jun 2018 17:30:37 +0200
Miquel Raynal <miquel.raynal@bootlin.com> wrote:

> 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.

Just a few comments below, but overall, I'm really happy with this new
set of commands and the fact that we'll soon be able to replace custom
MTD accessors (nand, onenand, sf, cp.b+erase, ...) by these ones.

> 
> Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> ---
>  cmd/Kconfig          |   5 +
>  cmd/Makefile         |   1 +
>  cmd/mtd.c            | 280 +++++++++++++++++++++++++++++++++++++++++++++++++++
>  drivers/mtd/Makefile |   2 +-
>  4 files changed, 287 insertions(+), 1 deletion(-)
>  create mode 100644 cmd/mtd.c
> 
> diff --git a/cmd/Kconfig b/cmd/Kconfig
> index 136836d146..6e9b629e1c 100644
> --- a/cmd/Kconfig
> +++ b/cmd/Kconfig
> @@ -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
> diff --git a/cmd/Makefile b/cmd/Makefile
> index 9a358e4801..e42db12e1d 100644
> --- a/cmd/Makefile
> +++ b/cmd/Makefile
> @@ -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
> diff --git a/cmd/mtd.c b/cmd/mtd.c
> new file mode 100644
> index 0000000000..fe48378bd0
> --- /dev/null
> +++ b/cmd/mtd.c
> @@ -0,0 +1,280 @@
> +// SPDX-License-Identifier:  GPL-2.0+
> +/*
> + * mtd.c
> + *
> + * Generic command to handle basic operations on any memory device.
> + *
> + * Copyright: Bootlin, 2018
> + * Author: Miquèl Raynal <miquel.raynal@bootlin.com>
> + */
> +
> +#include <common.h>
> +#include <linux/mtd/mtd.h>
> +#include <command.h>
> +#include <console.h>
> +#include <malloc.h>
> +#include <mtd.h>
> +#include <mapmem.h>
> +#include <dm/device.h>
> +#include <dm/uclass-internal.h>
> +
> +static void mtd_dump_buf(u8 *buf, uint len)
> +{
> +	int i, j;
> +
> +	for (i = 0; i < len; ) {
> +		printf("0x%08x:\t", i);
> +		for (j = 0; j < 8; j++)
> +			printf("%02x ", buf[i + j]);
> +		printf(" ");
> +		i += 8;
> +		for (j = 0; j < 8; j++)
> +			printf("%02x ", buf[i + j]);
> +		printf("\n");
> +		i += 8;
> +	}
> +}
> +
> +static void mtd_show_device(struct mtd_info *mtd)
> +{
> +	printf("* %s", mtd->name);
> +	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_list(void)
> +{
> +	struct mtd_info *mtd;
> +	struct udevice *dev;
> +	int dm_idx = 0, idx = 0;
> +
> +	/* Ensure all devices compliants with U-Boot driver model are probed */
> +	while (!uclass_find_device(UCLASS_MTD, dm_idx, &dev) && dev) {
> +		mtd_probe(dev);
> +		dm_idx++;
> +	}
> +
> +	printf("MTD devices list (%d DM compliant):\n", dm_idx);

Do we really want to say how many of them are exported by DM compliant
drivers? I mean, the user doesn't care about that. If you want to force
people to convert their drivers, we should probably complain at MTD
device registration time when the mtd_info struct is not backed by an
udevice.

> +
> +	mtd_for_each_device(mtd) {
> +		mtd_show_device(mtd);
> +		idx++;
> +	}
> +
> +	if (!idx)
> +		printf("No MTD device found\n");
> +
> +	return 0;
> +}
> +
> +static int do_mtd_read_write(struct mtd_info *mtd, bool read, uint *waddr,
> +			     bool raw, bool woob, u64 from, u64 len)

s/do_mtd_read_write/do_mtd_io/ ? And why not passing an mtd_oob_ops
object directly? That would reduce the number of parameters you pass to
this function.

> +{
> +	u32 buf_len = woob ? mtd->writesize + mtd->oobsize :
> +			     ROUND(len, mtd->writesize);
> +	u8 *buf = malloc(buf_len);

It's probably worth a comment explaining why you allocate a bounce
buffer here (i.e. to make sure len not aligned on a page size are padded
with 0xff).

Maybe a simpler solution would be to simply refuse such unaligned
accesses.

> +	struct mtd_oob_ops ops = {
> +		.mode = raw ? MTD_OPS_RAW : 0,
> +		.len = len,
> +		.ooblen = woob ? mtd->oobsize : 0,
> +		.datbuf = buf,
> +		.oobbuf = woob ? &buf[mtd->writesize] : NULL,
> +	};
> +	int ret;
> +
> +	if (!buf)
> +		return -ENOMEM;
> +
> +	memset(buf, 0xFF, buf_len);
> +
> +	if (read) {
> +		ret = mtd_read_oob(mtd, from, &ops);
> +	} else {
> +		memcpy(buf, waddr, ops.len + ops.ooblen);
> +		ret = mtd_write_oob(mtd, from, &ops);
> +	}
> +
> +	if (ret) {
> +		printf("Could not handle %lldB from 0x%08llx on %s, ret %d\n",
> +		       len, from, mtd->name, ret);
> +		return ret;
> +	}
> +
> +	if (read) {
> +		printf("Dump %lld data bytes from 0x%08llx:\n", len, from);
> +		mtd_dump_buf(buf, len);

Read and dump are 2 different things: one might want to read an MTD
device and store the result in RAM without dumping it on the console. 

> +
> +		if (woob) {
> +			printf("\nDump %d OOB bytes from 0x%08llx:\n",
> +			       mtd->oobsize, from);
> +			mtd_dump_buf(&buf[len], mtd->oobsize);
> +		}

Looks like you're never copying the data back to waddr.

> +	}
> +
> +	kfree(buf);
> +
> +	return 0;
> +}
> +
> +static int do_mtd_erase(struct mtd_info *mtd, bool scrub, u64 from, u64 len)
> +{
> +	struct erase_info erase_infos = {
> +		.mtd = mtd,
> +		.addr = from,
> +		.len = len,
> +		.scrub = scrub,
> +	};
> +
> +	return mtd_erase(mtd, &erase_infos);
> +}
> +
> +static int do_mtd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
> +{
> +	struct mtd_info *mtd;
> +	struct udevice *dev;
> +	const char *cmd;
> +	char *part;
> +	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;
> +
> +	part = argv[2];

Why part. The MTD object can be a partition or the device itself. How
about renaming it mtdname?

> +	ret = uclass_find_device_by_name(UCLASS_MTD, part, &dev);
> +	if (!ret && dev) {
> +		mtd_probe(dev);
> +		mtd = (struct mtd_info *)dev_get_uclass_priv(dev);
> +		if (!mtd) {
> +			printf("Could not retrieve MTD data\n");
> +			return -ENODEV;
> +		}
> +	} else {
> +		mtd = get_mtd_device_nm(part);
> +		if (IS_ERR_OR_NULL(mtd)) {
> +			printf("MTD device %s not found, ret %ld\n", part,
> +			       PTR_ERR(mtd));
> +			return 1;
> +		}
> +	}

Hm, I'd do it the other way around: first call get_mtd_device_nm() and
if you don't find the device trigger the probe of all UCLASS_MTD devs,
and then search again with get_mtd_device_nm(). Note that
mtd->dev->name and mtd->name are 2 different things, and they won't
match most of the time.

> +
> +	argc -= 3;
> +	argv += 3;
> +
> +	/* Do the parsing */
> +	if (!strncmp(cmd, "read", 4) || !strncmp(cmd, "write", 5)) {
> +		bool read, raw, woob;
> +		uint *waddr = NULL;
> +		u64 off, len;
> +
> +		read = !strncmp(cmd, "read", 4);
> +		raw = strstr(cmd, ".raw");
> +		woob = strstr(cmd, ".oob");
> +
> +		if (!read) {
> +			if (argc < 1)
> +				return CMD_RET_USAGE;
> +
> +			waddr = map_sysmem(simple_strtoul(argv[0], NULL, 10),
> +					   0);
> +			argc--;
> +			argv++;
> +		}
> +
> +		off = argc > 0 ? simple_strtoul(argv[0], NULL, 10) : 0;
> +		len = argc > 1 ? simple_strtoul(argv[1], NULL, 10) :
> +				 mtd->writesize + (woob ? mtd->oobsize : 0);
> +
> +		if ((u32)off % mtd->writesize) {
> +			printf("Section not page-aligned (0x%x)\n",
> +			       mtd->writesize);
> +			return -EINVAL;
> +		}
> +
> +		if (woob && (len != (mtd->writesize + mtd->oobsize))) {
> +			printf("OOB operations are limited to single pages\n");
> +			return -EINVAL;
> +		}

Is this a uboot limitation? I don't think you have such a limitation in
Linux.

> +
> +		if ((off + len) >= mtd->size) {

That doesn't work when reading the last page of the MTD device with
woob = true. See how Linux handle that here [1]. BTW, why don't you let
mtdcore.c do these checks for you (that's also true for unaligned
accesses)?

> +			printf("Access location beyond the end of the chip\n");
> +			return -EINVAL;
> +		}
> +
> +		printf("%s (from %p) %lldB at 0x%08llx [%s %s]\n",
> +		       read ? "read" : "write", read ? 0 : waddr, len, off,
> +		       raw ? "raw" : "", woob ? "oob" : "");
> +
> +		ret = do_mtd_read_write(mtd, read, waddr, raw, woob, off, len);
> +
> +		if (!read)
> +			unmap_sysmem(waddr);
> +
> +	} else if (!strcmp(cmd, "erase") || !strcmp(cmd, "scrub")) {
> +		bool scrub = !strcmp(cmd, "scrub");
> +		bool full_erase = !strncmp(&cmd[5], ".chip", 4);
> +		u64 off, len;
> +
> +		off = argc > 0 ? simple_strtoul(argv[0], NULL, 10) : 0;
> +		len = argc > 1 ? simple_strtoul(argv[1], NULL, 10) :
> +				 mtd->erasesize;
> +		if (full_erase) {
> +			off = 0;
> +			len = mtd->size;
> +		}
> +
> +		if ((u32)off % mtd->erasesize) {
> +			printf("Section not erase-block-aligned (0x%x)\n",
> +			       mtd->erasesize);
> +			return -EINVAL;
> +		}
> +
> +		if ((u32)len % mtd->erasesize) {
> +			printf("Size not aligned with an erase block (%dB)\n",
> +			       mtd->erasesize);
> +			return -EINVAL;
> +		}
> +
> +		if ((off + len) >= mtd->size) {
> +			printf("Cannot read beyond end of chip\n");
> +			return -EINVAL;
> +		}
> +
> +		ret = do_mtd_erase(mtd, scrub, off, len);
> +	} 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> [<off> [<size>]]\n"

I guess this one should be

	"mtd read[.raw][.oob] <name> <addr> [<off> [<size>]]\n"

and then, you should have

	"mtd dump[.raw][.oob] <name> [<off> [<size>]]\n"

> +	"mtd write[.raw][.oob] <name> <addr> [<off> [<size>]]\n"
> +	"mtd erase[.chip] <name> [<off> [<size>]]\n"
> +	"mtd scrub[.chip] <name> [<off> [<size>]]\n"

Hm, maybe it's time to simplify that. mtd.scrub is just an option of mtd
erase, so maybe we should just have:

	mtd erase[.force] or erase[.dontskipbad]

Also, [.chip] can be extracted from the number of parameters. If you
just have <name> passed, that means the callers wants to erase the
whole chip.

Regards,

Boris

> +#endif
> +	"";
> +
> +U_BOOT_CMD(mtd, 10, 1, do_mtd, "MTD utils", mtd_help_text);

[1]https://elixir.bootlin.com/linux/latest/source/drivers/mtd/mtdcore.c#L1117

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [U-Boot] [RFC PATCH 00/20] SPI-NAND support
  2018-06-06 15:30 [U-Boot] [RFC PATCH 00/20] SPI-NAND support Miquel Raynal
                   ` (19 preceding siblings ...)
  2018-06-06 15:30 ` [U-Boot] [RFC PATCH 20/20] mips: dts: ocelot: add the SPI NAND node Miquel Raynal
@ 2018-06-07  5:51 ` Jagan Teki
  2018-06-07  8:41   ` Miquel Raynal
  2018-06-12 14:14 ` Stefan Roese
  2018-07-06 11:43 ` Jagan Teki
  22 siblings, 1 reply; 65+ messages in thread
From: Jagan Teki @ 2018-06-07  5:51 UTC (permalink / raw)
  To: u-boot

+ Boris
+ Suneel (who helped in DM MTD)
+ Siva, Michal  (zynq qspi)

On Wed, Jun 6, 2018 at 9:00 PM, Miquel Raynal <miquel.raynal@bootlin.com> wrote:
> 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.

1) Can you pointed us the Linux changes along with discussion thread
about spi-mem, and spi-nand.

2) If my understanding was correct, spi-mem is replacement for spi-nor
controller drivers from driver/mtd/spi-nor in Linux.

3) If so is fsl_qspi spi-nor driver moves to drivers/spi area? yes
then how does flash changes handled by spi-mem.

4) we have zynq qspi controller which has extensive features like dual
flash(stacked and parallel) does spi-mem support these flash specific
changes?

5) Better to send spi-mem and spi-nand changes separately, for better reviewing.

6) We have DM MTD layer in ML, better to send the changes on-top [1]

[1] https://patchwork.ozlabs.org/project/uboot/list/?series=20450

Jagan.

-- 
Jagan Teki
Free Software Engineer | www.openedev.com
U-Boot, Linux | Upstream Maintainer
Hyderabad, India.

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [U-Boot] [RFC PATCH 00/20] SPI-NAND support
  2018-06-07  5:51 ` [U-Boot] [RFC PATCH 00/20] SPI-NAND support Jagan Teki
@ 2018-06-07  8:41   ` Miquel Raynal
  2018-06-18  8:07     ` Boris Brezillon
  2018-06-25  8:29     ` Jagan Teki
  0 siblings, 2 replies; 65+ messages in thread
From: Miquel Raynal @ 2018-06-07  8:41 UTC (permalink / raw)
  To: u-boot

Hi Jagan,

On Thu, 7 Jun 2018 11:21:22 +0530, Jagan Teki
<jagannadh.teki@gmail.com> wrote:

> + Boris
> + Suneel (who helped in DM MTD)
> + Siva, Michal  (zynq qspi)
> 
> On Wed, Jun 6, 2018 at 9:00 PM, Miquel Raynal <miquel.raynal@bootlin.com> wrote:
> > 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.  
> 
> 1) Can you pointed us the Linux changes along with discussion thread
> about spi-mem, and spi-nand.

Sure, you can have a look there:

SPI-mem:
http://lists.infradead.org/pipermail/linux-mtd/2018-April/080225.html

SPI-NAND:
http://lists.infradead.org/pipermail/linux-mtd/2018-May/081005.html

> 
> 2) If my understanding was correct, spi-mem is replacement for spi-nor
> controller drivers from driver/mtd/spi-nor in Linux.

It is not 'exactly' a replacement for spi-nor controller drivers but
that's the idea. I suggest you to have a look at Boris' blog post about
it:
https://bootlin.com/blog/spi-mem-bringing-some-consistency-to-the-spi-memory-ecosystem/

> 
> 3) If so is fsl_qspi spi-nor driver moves to drivers/spi area? yes
> then how does flash changes handled by spi-mem.

This series does not migrate the SPI-NOR stack to spi-mem. It focuses
on SPI-NAND for now. And I don't understand the second sentence.

> 
> 4) we have zynq qspi controller which has extensive features like dual
> flash(stacked and parallel) does spi-mem support these flash specific
> changes?

This controller is very specific and such support has not yet been
added.

> 
> 5) Better to send spi-mem and spi-nand changes separately, for better reviewing.

It would mean sending 3 or 4 distinct series, I thought better to give
the whole picture but that's your choice.

> 
> 6) We have DM MTD layer in ML, better to send the changes on-top [1]
> 
> [1] https://patchwork.ozlabs.org/project/uboot/list/?series=20450

This is great to see such effort being made to develop U-Boot
driver-model but is there a real need for yet another layer on top of
the MTD stack?

I'm looking at mtd-uclass.c for instance, I don't get the need for a
mtd_dread() function, all the operations in the mtd_d*() helpers are
already handled by mtd/mtdcore.c, no?

And the mtd_ops structure does not bring a lot. Should not we keep it
simple and avoid such intermediate layer?

Also, there is the introduction of a spinor command (what about the
existing 'sf'?), which is exactly the opposite of what the MTD
abstraction would told us to do (thus, the 'mtd' generic command).

Regards,
Miquèl

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [U-Boot] [RFC PATCH 00/20] SPI-NAND support
  2018-06-06 15:30 [U-Boot] [RFC PATCH 00/20] SPI-NAND support Miquel Raynal
                   ` (20 preceding siblings ...)
  2018-06-07  5:51 ` [U-Boot] [RFC PATCH 00/20] SPI-NAND support Jagan Teki
@ 2018-06-12 14:14 ` Stefan Roese
  2018-06-18  8:13   ` Miquel Raynal
  2018-07-06 11:43 ` Jagan Teki
  22 siblings, 1 reply; 65+ messages in thread
From: Stefan Roese @ 2018-06-12 14:14 UTC (permalink / raw)
  To: u-boot

Hi Miquèl,

On 06.06.2018 17:30, Miquel Raynal wrote:
> 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' ?).

Interesting. I like this idea.

BTW: I also would like to see the ubifs commands being supported
by the common file commands, like "ls" and "load". But this just
came to my mind right now (again) and definitely has nothing to
do with your current work on SPI NAND.

> The series has been tested on an Ocelot board PCB123 (VSC7514),
> featuring a Macronix SPI NAND chip.
> 
> TL;DR: the series contains:
> - 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.
> - DT changes to make use of a SPI NAND on the Ocelot board.
> 
> Any comments on the code, the organization and the respect of U-Boot
> driver model will be welcome.

Many thanks for working on this. I might get access to a new
platform in a few days, requiring SPI NAND support. So I tried to
apply your patches on top of current mainline, which unfortunately
fails with some patches.

Would it be possible for you to rebase your patches on top
of current mainline U-Boot? Best would be to also push a git
branch with your patches / changes. This way you don't need
to re-send all those patches to the list, without any real
changes done.

Thanks,
Stefan

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [U-Boot] [RFC PATCH 00/20] SPI-NAND support
  2018-06-07  8:41   ` Miquel Raynal
@ 2018-06-18  8:07     ` Boris Brezillon
  2018-06-25  8:29     ` Jagan Teki
  1 sibling, 0 replies; 65+ messages in thread
From: Boris Brezillon @ 2018-06-18  8:07 UTC (permalink / raw)
  To: u-boot

Hi Jagan,

On Thu, 7 Jun 2018 10:41:35 +0200
Miquel Raynal <miquel.raynal@bootlin.com> wrote:

> Hi Jagan,
> 
> On Thu, 7 Jun 2018 11:21:22 +0530, Jagan Teki
> <jagannadh.teki@gmail.com> wrote:
> 
> > + Boris
> > + Suneel (who helped in DM MTD)
> > + Siva, Michal  (zynq qspi)
> > 
> > On Wed, Jun 6, 2018 at 9:00 PM, Miquel Raynal <miquel.raynal@bootlin.com> wrote:  
> > > 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.    
> > 
> > 1) Can you pointed us the Linux changes along with discussion thread
> > about spi-mem, and spi-nand.  
> 
> Sure, you can have a look there:
> 
> SPI-mem:
> http://lists.infradead.org/pipermail/linux-mtd/2018-April/080225.html
> 
> SPI-NAND:
> http://lists.infradead.org/pipermail/linux-mtd/2018-May/081005.html
> 
> > 
> > 2) If my understanding was correct, spi-mem is replacement for spi-nor
> > controller drivers from driver/mtd/spi-nor in Linux.  
> 
> It is not 'exactly' a replacement for spi-nor controller drivers but
> that's the idea. I suggest you to have a look at Boris' blog post about
> it:
> https://bootlin.com/blog/spi-mem-bringing-some-consistency-to-the-spi-memory-ecosystem/
> 
> > 
> > 3) If so is fsl_qspi spi-nor driver moves to drivers/spi area? yes
> > then how does flash changes handled by spi-mem.  
> 
> This series does not migrate the SPI-NOR stack to spi-mem. It focuses
> on SPI-NAND for now. And I don't understand the second sentence.
> 
> > 
> > 4) we have zynq qspi controller which has extensive features like dual
> > flash(stacked and parallel) does spi-mem support these flash specific
> > changes?  
> 
> This controller is very specific and such support has not yet been
> added.
> 
> > 
> > 5) Better to send spi-mem and spi-nand changes separately, for better reviewing.  
> 
> It would mean sending 3 or 4 distinct series, I thought better to give
> the whole picture but that's your choice.
> 
> > 
> > 6) We have DM MTD layer in ML, better to send the changes on-top [1]
> > 
> > [1] https://patchwork.ozlabs.org/project/uboot/list/?series=20450  
> 
> This is great to see such effort being made to develop U-Boot
> driver-model but is there a real need for yet another layer on top of
> the MTD stack?
> 
> I'm looking at mtd-uclass.c for instance, I don't get the need for a
> mtd_dread() function, all the operations in the mtd_d*() helpers are
> already handled by mtd/mtdcore.c, no?
> 
> And the mtd_ops structure does not bring a lot. Should not we keep it
> simple and avoid such intermediate layer?
> 
> Also, there is the introduction of a spinor command (what about the
> existing 'sf'?), which is exactly the opposite of what the MTD
> abstraction would told us to do (thus, the 'mtd' generic command).

Any chance you can comment on Miquel's reply?

That's really important to have your feedback on these questions since
your answers might heavily impact the work we'll have to do to get
things merged (especially question #6).

Thanks,

Boris

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [U-Boot] [RFC PATCH 00/20] SPI-NAND support
  2018-06-12 14:14 ` Stefan Roese
@ 2018-06-18  8:13   ` Miquel Raynal
  0 siblings, 0 replies; 65+ messages in thread
From: Miquel Raynal @ 2018-06-18  8:13 UTC (permalink / raw)
  To: u-boot

Hi Stefan,

On Tue, 12 Jun 2018 16:14:19 +0200, Stefan Roese <sr@denx.de> wrote:

> Hi Miquèl,
> 
> On 06.06.2018 17:30, Miquel Raynal wrote:
> > 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' ?).  
> 
> Interesting. I like this idea.
> 
> BTW: I also would like to see the ubifs commands being supported
> by the common file commands, like "ls" and "load". But this just
> came to my mind right now (again) and definitely has nothing to
> do with your current work on SPI NAND.
> 
> > The series has been tested on an Ocelot board PCB123 (VSC7514),
> > featuring a Macronix SPI NAND chip.  
> > > TL;DR: the series contains:  
> > - 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.
> > - DT changes to make use of a SPI NAND on the Ocelot board.  
> > > Any comments on the code, the organization and the respect of U-Boot  
> > driver model will be welcome.  
> 
> Many thanks for working on this. I might get access to a new
> platform in a few days, requiring SPI NAND support. So I tried to

Thanks, testing will be appreciated!

> apply your patches on top of current mainline, which unfortunately
> fails with some patches.
> 
> Would it be possible for you to rebase your patches on top
> of current mainline U-Boot? Best would be to also push a git
> branch with your patches / changes. This way you don't need
> to re-send all those patches to the list, without any real
> changes done.

Mmmh. Sorry for that. Please have a look at this branch, the work is
based on top of v2018.03:

https://github.com/miquelraynal/u-boot/commits/public/spi-nand

> 
> Thanks,
> Stefan

Thanks,
Miquèl

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [U-Boot] [RFC PATCH 15/20] mtd: spinand: Add initial support for the MX35LF2GE4AB chip
  2018-06-06 15:30 ` [U-Boot] [RFC PATCH 15/20] mtd: spinand: Add initial support for the MX35LF2GE4AB chip Miquel Raynal
@ 2018-06-22 12:03   ` Boris Brezillon
  2018-06-26  7:54     ` Miquel Raynal
  0 siblings, 1 reply; 65+ messages in thread
From: Boris Brezillon @ 2018-06-22 12:03 UTC (permalink / raw)
  To: u-boot

On Wed,  6 Jun 2018 17:30:35 +0200
Miquel Raynal <miquel.raynal@bootlin.com> wrote:

> Add support for the MX35LF2GE4AB chip, which is similar to its cousin
> MX35LF1GE4AB, with two planes instead of one.
> 
> Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> ---
>  drivers/mtd/nand/spi/macronix.c | 20 ++++++++++++++------
>  1 file changed, 14 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/mtd/nand/spi/macronix.c b/drivers/mtd/nand/spi/macronix.c
> index dd351dcb6c..d761b99d26 100644
> --- a/drivers/mtd/nand/spi/macronix.c
> +++ b/drivers/mtd/nand/spi/macronix.c
> @@ -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, 1024, 2, 1, 1),

		    I think it should be 2048 here ^.

> +		     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)

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [U-Boot] [RFC PATCH 00/20] SPI-NAND support
  2018-06-07  8:41   ` Miquel Raynal
  2018-06-18  8:07     ` Boris Brezillon
@ 2018-06-25  8:29     ` Jagan Teki
  2018-06-25  9:09       ` Boris Brezillon
  1 sibling, 1 reply; 65+ messages in thread
From: Jagan Teki @ 2018-06-25  8:29 UTC (permalink / raw)
  To: u-boot

Miquel and Brois, thanks for working on this.

On Thu, Jun 7, 2018 at 2:11 PM, Miquel Raynal <miquel.raynal@bootlin.com> wrote:
> Hi Jagan,
>
> On Thu, 7 Jun 2018 11:21:22 +0530, Jagan Teki
> <jagannadh.teki@gmail.com> wrote:
>
>> + Boris
>> + Suneel (who helped in DM MTD)
>> + Siva, Michal  (zynq qspi)
>>
>> On Wed, Jun 6, 2018 at 9:00 PM, Miquel Raynal <miquel.raynal@bootlin.com> wrote:
>> > 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.
>>
>> 1) Can you pointed us the Linux changes along with discussion thread
>> about spi-mem, and spi-nand.
>
> Sure, you can have a look there:
>
> SPI-mem:
> http://lists.infradead.org/pipermail/linux-mtd/2018-April/080225.html
>
> SPI-NAND:
> http://lists.infradead.org/pipermail/linux-mtd/2018-May/081005.html

This is really nice, look like this design handling any kind of
controller features by abstracting spi core so-that controller hacks
shouldn't touch the common core code. unfortunately I missed Linux ML
during submission.

>
>>
>> 2) If my understanding was correct, spi-mem is replacement for spi-nor
>> controller drivers from driver/mtd/spi-nor in Linux.
>
> It is not 'exactly' a replacement for spi-nor controller drivers but
> that's the idea. I suggest you to have a look at Boris' blog post about
> it:
> https://bootlin.com/blog/spi-mem-bringing-some-consistency-to-the-spi-memory-ecosystem/
>
>>
>> 3) If so is fsl_qspi spi-nor driver moves to drivers/spi area? yes
>> then how does flash changes handled by spi-mem.
>
> This series does not migrate the SPI-NOR stack to spi-mem. It focuses
> on SPI-NAND for now. And I don't understand the second sentence.
>
>>
>> 4) we have zynq qspi controller which has extensive features like dual
>> flash(stacked and parallel) does spi-mem support these flash specific
>> changes?
>
> This controller is very specific and such support has not yet been
> added.
>
>>
>> 5) Better to send spi-mem and spi-nand changes separately, for better reviewing.
>
> It would mean sending 3 or 4 distinct series, I thought better to give
> the whole picture but that's your choice.
>
>>
>> 6) We have DM MTD layer in ML, better to send the changes on-top [1]
>>
>> [1] https://patchwork.ozlabs.org/project/uboot/list/?series=20450
>
> This is great to see such effort being made to develop U-Boot
> driver-model but is there a real need for yet another layer on top of
> the MTD stack?
>
> I'm looking at mtd-uclass.c for instance, I don't get the need for a
> mtd_dread() function, all the operations in the mtd_d*() helpers are
> already handled by mtd/mtdcore.c, no?
>
> And the mtd_ops structure does not bring a lot. Should not we keep it
> simple and avoid such intermediate layer?
>
> Also, there is the introduction of a spinor command (what about the
> existing 'sf'?), which is exactly the opposite of what the MTD
> abstraction would told us to do (thus, the 'mtd' generic command).

I've looked the code on the respective patches, look like most of the
code copy from Linux by adding __UBOOT__. I have no issue with Linux
copy but we need to structure the code according to U-Boot in the form
of driver-model (this series lack with that).

Here are my suggestions, based the MTD work so-far

First we need to design MTD driver-model which can capable to drive
one driver from each interface. (not converting all interface drivers
at once, that is taking more time and other issues)

Like Linux MTD, U-Boot should have MTD dm for underlying flash devices
like nand, parallel nor, spinor etc. So to drive this theory with
driver model(with an example of block layer) mtd is common device
interaction for most of  memory technology  flashes like nand,
parallel nor, spinor etc, these are treated as interface types wrt
u-boot driver model.

Once the respective interface driver bind happen, the uclass driver
will pass an 'interface type' to mtd layer to create device for it,
for example once spinor ULASS_SPI_NOR driver bind happen, the uclass
driver of spinor will pass MTD_IF_TYPE_SPI_NOR
interface type to create mtd device for spinor devices.

So If we add this design to SPI-NAND changes, we need to implement
- MTD dm core that can driver all interfaces
- one driver for raw nand
- one driver for spinand
- spi-mem
- convert fsl-qspi to spi-mem
- implement command to handle

For spi-nor interface design, we have an example code here[2]

I've paused this [2] series because of dm conversion of spi-drivers
otherwise I need add legacy code like mmc-legacy.c, so if we really
move to spi-mem design and okay with above design. I will try to move
the current spi flash to add MTD driver-model so-that we can add
spi-mem, spi-nand on top of it or we can work together to convert them
all.

[2] https://patchwork.ozlabs.org/project/uboot/list/?series=20450

Jagan.

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [U-Boot] [RFC PATCH 00/20] SPI-NAND support
  2018-06-25  8:29     ` Jagan Teki
@ 2018-06-25  9:09       ` Boris Brezillon
  2018-06-25 12:38         ` Richard Weinberger
  2018-06-25 14:27         ` Jagan Teki
  0 siblings, 2 replies; 65+ messages in thread
From: Boris Brezillon @ 2018-06-25  9:09 UTC (permalink / raw)
  To: u-boot

+Richard to comment on the MTD abstraction stuff and how uboot port
of UBI might be impacted by some changes requested here.

Hi Jagan,

On Mon, 25 Jun 2018 13:59:37 +0530
Jagan Teki <jagannadh.teki@gmail.com> wrote:

> 
> I've looked the code on the respective patches, look like most of the
> code copy from Linux by adding __UBOOT__. I have no issue with Linux
> copy but we need to structure the code according to U-Boot in the form
> of driver-model (this series lack with that).
> 
> Here are my suggestions, based the MTD work so-far
> 
> First we need to design MTD driver-model which can capable to drive
> one driver from each interface. (not converting all interface drivers
> at once, that is taking more time and other issues)
> 
> Like Linux MTD, U-Boot should have MTD dm for underlying flash devices
> like nand, parallel nor, spinor etc. So to drive this theory with
> driver model(with an example of block layer) mtd is common device
> interaction for most of  memory technology  flashes like nand,
> parallel nor, spinor etc, these are treated as interface types wrt
> u-boot driver model.
> 
> Once the respective interface driver bind happen, the uclass driver
> will pass an 'interface type' to mtd layer to create device for it,
> for example once spinor ULASS_SPI_NOR driver bind happen, the uclass
> driver of spinor will pass MTD_IF_TYPE_SPI_NOR
> interface type to create mtd device for spinor devices.
> 
> So If we add this design to SPI-NAND changes, we need to implement
> - MTD dm core that can driver all interfaces

That's already what the MTD framework provides, and Miquel even added
some stuff to integrate the MTD layer even further in the DM. It's
probably not perfect yet, but the changes are, IMHO, going in the right
direction.

Now, if you're talking about the new MTD API that creates helper
functions prefixed with dm_, sorry, but I don't see the point. We
already have plenty of MTD users in u-boot, they all manipulate MTD
objects and go through the standard MTD API to do that. What you
suggest would make things messier for several reasons:

1/ we won't be able to easily port Linux code to u-boot. Look at the
   JFFS2 UBI support. They all use mtd_info objects. What's the point of
   changing that except making things harder to port.

2/ Not all MTD providers will be converted to the device model at once,
   so how do you plan to deal with that?

3/ What's the benefit of exposing yet another way to manipulate MTD
   devices?

> - one driver for raw nand

Unfortunately, that's not how it works right now, and clearly, we
don't have time to work on this raw NAND rework right now.

> - one driver for spinand

I think that's already the case.

> - spi-mem

It's also what Miquel is doing in this series.

> - convert fsl-qspi to spi-mem

We're not targeting the fsl-qspi controller here but a simple SPI
controller that is already upstreamed. But yes, the fsl-qspi driver
will have to be patched to support the spi-mem interface at some point.

> - implement command to handle

This I don't get. What do you mean by "implement command to handle"?
Are we talking about cmd/mtd.c? I think the work Miquel has done is
already a good start, what's missing in there?

> 
> For spi-nor interface design, we have an example code here[2]
> 
> I've paused this [2] series because of dm conversion of spi-drivers
> otherwise I need add legacy code like mmc-legacy.c, so if we really
> move to spi-mem design and okay with above design. I will try to move
> the current spi flash to add MTD driver-model so-that we can add
> spi-mem, spi-nand on top of it or we can work together to convert them
> all.

Why can't we do things iteratively. I mean, if the long term goal is to
convert everything to the driver model, then this patchset is going in
the right direction:
 - addition of DM helpers to the MTD_UCLASS
 - addition of the spi-mem interface properly integrated in the DM
   model of the SPI framework
 - addition of a SPI NAND driver, again properly integrated in the DM
 - integration of DM-ready MTD drivers and old MTD drivers in a single
   view exposed by the cmd/mtd.c command set

I'd really like to limit the scope of this development to these topics,
which doesn't prevent you from converting other part of u-boot to the
spi-mem approach (SPI NOR is one example).

I hope you understand our concerns and the fact that what you're asking
us to do as a dependency of getting SPI NAND support + cmd/mtd.c merged
is way more than we can actually provide.

Regards,

Boris

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [U-Boot] [RFC PATCH 00/20] SPI-NAND support
  2018-06-25  9:09       ` Boris Brezillon
@ 2018-06-25 12:38         ` Richard Weinberger
  2018-06-25 14:27         ` Jagan Teki
  1 sibling, 0 replies; 65+ messages in thread
From: Richard Weinberger @ 2018-06-25 12:38 UTC (permalink / raw)
  To: u-boot

Am Montag, 25. Juni 2018, 11:09:41 CEST schrieb Boris Brezillon:
> +Richard to comment on the MTD abstraction stuff and how uboot port
> of UBI might be impacted by some changes requested here.
> 
> Hi Jagan,
> 
> On Mon, 25 Jun 2018 13:59:37 +0530
> Jagan Teki <jagannadh.teki@gmail.com> wrote:
> 
> > 
> > I've looked the code on the respective patches, look like most of the
> > code copy from Linux by adding __UBOOT__. I have no issue with Linux
> > copy but we need to structure the code according to U-Boot in the form
> > of driver-model (this series lack with that).
> > 
> > Here are my suggestions, based the MTD work so-far
> > 
> > First we need to design MTD driver-model which can capable to drive
> > one driver from each interface. (not converting all interface drivers
> > at once, that is taking more time and other issues)
> > 
> > Like Linux MTD, U-Boot should have MTD dm for underlying flash devices
> > like nand, parallel nor, spinor etc. So to drive this theory with
> > driver model(with an example of block layer) mtd is common device
> > interaction for most of  memory technology  flashes like nand,
> > parallel nor, spinor etc, these are treated as interface types wrt
> > u-boot driver model.
> > 
> > Once the respective interface driver bind happen, the uclass driver
> > will pass an 'interface type' to mtd layer to create device for it,
> > for example once spinor ULASS_SPI_NOR driver bind happen, the uclass
> > driver of spinor will pass MTD_IF_TYPE_SPI_NOR
> > interface type to create mtd device for spinor devices.
> > 
> > So If we add this design to SPI-NAND changes, we need to implement
> > - MTD dm core that can driver all interfaces
> 
> That's already what the MTD framework provides, and Miquel even added
> some stuff to integrate the MTD layer even further in the DM. It's
> probably not perfect yet, but the changes are, IMHO, going in the right
> direction.
> 
> Now, if you're talking about the new MTD API that creates helper
> functions prefixed with dm_, sorry, but I don't see the point. We
> already have plenty of MTD users in u-boot, they all manipulate MTD
> objects and go through the standard MTD API to do that. What you
> suggest would make things messier for several reasons:
> 
> 1/ we won't be able to easily port Linux code to u-boot. Look at the
>    JFFS2 UBI support. They all use mtd_info objects. What's the point of
>    changing that except making things harder to port.
> 
> 2/ Not all MTD providers will be converted to the device model at once,
>    so how do you plan to deal with that?
> 
> 3/ What's the benefit of exposing yet another way to manipulate MTD
>    devices?
> 
> > - one driver for raw nand
> 
> Unfortunately, that's not how it works right now, and clearly, we
> don't have time to work on this raw NAND rework right now.
> 
> > - one driver for spinand
> 
> I think that's already the case.
> 
> > - spi-mem
> 
> It's also what Miquel is doing in this series.
> 
> > - convert fsl-qspi to spi-mem
> 
> We're not targeting the fsl-qspi controller here but a simple SPI
> controller that is already upstreamed. But yes, the fsl-qspi driver
> will have to be patched to support the spi-mem interface at some point.
> 
> > - implement command to handle
> 
> This I don't get. What do you mean by "implement command to handle"?
> Are we talking about cmd/mtd.c? I think the work Miquel has done is
> already a good start, what's missing in there?
> 
> > 
> > For spi-nor interface design, we have an example code here[2]
> > 
> > I've paused this [2] series because of dm conversion of spi-drivers
> > otherwise I need add legacy code like mmc-legacy.c, so if we really
> > move to spi-mem design and okay with above design. I will try to move
> > the current spi flash to add MTD driver-model so-that we can add
> > spi-mem, spi-nand on top of it or we can work together to convert them
> > all.
> 
> Why can't we do things iteratively. I mean, if the long term goal is to
> convert everything to the driver model, then this patchset is going in
> the right direction:
>  - addition of DM helpers to the MTD_UCLASS
>  - addition of the spi-mem interface properly integrated in the DM
>    model of the SPI framework
>  - addition of a SPI NAND driver, again properly integrated in the DM
>  - integration of DM-ready MTD drivers and old MTD drivers in a single
>    view exposed by the cmd/mtd.c command set
> 
> I'd really like to limit the scope of this development to these topics,
> which doesn't prevent you from converting other part of u-boot to the
> spi-mem approach (SPI NOR is one example).
> 
> I hope you understand our concerns and the fact that what you're asking
> us to do as a dependency of getting SPI NAND support + cmd/mtd.c merged
> is way more than we can actually provide.

+1

As someone who is concerned that UBI and UBIFS are sane within u-boot
I'm not at all in favor of adding such a layer. The current MTD framework
does not need another abstraction level.
It will make keeping u-boot in sync with Linux more complicated that it
is already.

Thanks,
//richard

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [U-Boot] [RFC PATCH 00/20] SPI-NAND support
  2018-06-25  9:09       ` Boris Brezillon
  2018-06-25 12:38         ` Richard Weinberger
@ 2018-06-25 14:27         ` Jagan Teki
  2018-06-25 14:28           ` Jagan Teki
  2018-06-25 14:36           ` Richard Weinberger
  1 sibling, 2 replies; 65+ messages in thread
From: Jagan Teki @ 2018-06-25 14:27 UTC (permalink / raw)
  To: u-boot

+ Simon
+ Tom
(suggesting MTD driver model abstraction layer)

On Mon, Jun 25, 2018 at 2:39 PM, Boris Brezillon
<boris.brezillon@bootlin.com> wrote:
> +Richard to comment on the MTD abstraction stuff and how uboot port
> of UBI might be impacted by some changes requested here.
>
> Hi Jagan,
>
> On Mon, 25 Jun 2018 13:59:37 +0530
> Jagan Teki <jagannadh.teki@gmail.com> wrote:
>
>>
>> I've looked the code on the respective patches, look like most of the
>> code copy from Linux by adding __UBOOT__. I have no issue with Linux
>> copy but we need to structure the code according to U-Boot in the form
>> of driver-model (this series lack with that).
>>
>> Here are my suggestions, based the MTD work so-far
>>
>> First we need to design MTD driver-model which can capable to drive
>> one driver from each interface. (not converting all interface drivers
>> at once, that is taking more time and other issues)
>>
>> Like Linux MTD, U-Boot should have MTD dm for underlying flash devices
>> like nand, parallel nor, spinor etc. So to drive this theory with
>> driver model(with an example of block layer) mtd is common device
>> interaction for most of  memory technology  flashes like nand,
>> parallel nor, spinor etc, these are treated as interface types wrt
>> u-boot driver model.
>>
>> Once the respective interface driver bind happen, the uclass driver
>> will pass an 'interface type' to mtd layer to create device for it,
>> for example once spinor ULASS_SPI_NOR driver bind happen, the uclass
>> driver of spinor will pass MTD_IF_TYPE_SPI_NOR
>> interface type to create mtd device for spinor devices.
>>
>> So If we add this design to SPI-NAND changes, we need to implement
>> - MTD dm core that can driver all interfaces
>
> That's already what the MTD framework provides, and Miquel even added
> some stuff to integrate the MTD layer even further in the DM. It's
> probably not perfect yet, but the changes are, IMHO, going in the right
> direction.
>
> Now, if you're talking about the new MTD API that creates helper
> functions prefixed with dm_, sorry, but I don't see the point. We
> already have plenty of MTD users in u-boot, they all manipulate MTD
> objects and go through the standard MTD API to do that. What you
> suggest would make things messier for several reasons:
>
> 1/ we won't be able to easily port Linux code to u-boot. Look at the
>    JFFS2 UBI support. They all use mtd_info objects. What's the point of
>    changing that except making things harder to port.
>
> 2/ Not all MTD providers will be converted to the device model at once,
>    so how do you plan to deal with that?
>
> 3/ What's the benefit of exposing yet another way to manipulate MTD
>    devices?
>
>> - one driver for raw nand
>
> Unfortunately, that's not how it works right now, and clearly, we
> don't have time to work on this raw NAND rework right now.
>
>> - one driver for spinand
>
> I think that's already the case.
>
>> - spi-mem
>
> It's also what Miquel is doing in this series.
>
>> - convert fsl-qspi to spi-mem
>
> We're not targeting the fsl-qspi controller here but a simple SPI
> controller that is already upstreamed. But yes, the fsl-qspi driver
> will have to be patched to support the spi-mem interface at some point.

Can you point me that simple spi-mem controller driver?

>
>> - implement command to handle
>
> This I don't get. What do you mean by "implement command to handle"?
> Are we talking about cmd/mtd.c? I think the work Miquel has done is
> already a good start, what's missing in there?
>
>>
>> For spi-nor interface design, we have an example code here[2]
>>
>> I've paused this [2] series because of dm conversion of spi-drivers
>> otherwise I need add legacy code like mmc-legacy.c, so if we really
>> move to spi-mem design and okay with above design. I will try to move
>> the current spi flash to add MTD driver-model so-that we can add
>> spi-mem, spi-nand on top of it or we can work together to convert them
>> all.
>
> Why can't we do things iteratively. I mean, if the long term goal is to
> convert everything to the driver model, then this patchset is going in
> the right direction:
>  - addition of DM helpers to the MTD_UCLASS
>  - addition of the spi-mem interface properly integrated in the DM
>    model of the SPI framework
>  - addition of a SPI NAND driver, again properly integrated in the DM
>  - integration of DM-ready MTD drivers and old MTD drivers in a single
>    view exposed by the cmd/mtd.c command set
>
> I'd really like to limit the scope of this development to these topics,
> which doesn't prevent you from converting other part of u-boot to the
> spi-mem approach (SPI NOR is one example).
>
> I hope you understand our concerns and the fact that what you're asking
> us to do as a dependency of getting SPI NAND support + cmd/mtd.c merged
> is way more than we can actually provide.

To answer all these questions, I think we need to decide whether we go
for MTD dm abstraction or existing MTD layer.

When I say MTD dm abstraction, all mtd operation prototypes are in the
form of udevice unlike existing MTD has mtd_info. when I initially
supporting spi-nor (during Linux early spi-nor) I've reused existing
MTD and written something like what Miquel did using mtd_info ops [3].
but then developers on ML, proposed the new drivers should be form of
driver-model abstraction, so I've added mtd driver model ops [4].

I understand the new MTD dm abstraction in U-Boot is not possible for
direct syncing from Linux, but we really want the u-boot way of
handling drivers and trying to copy code from Linux by removing
__UBOOT__ or any Linux specific macros. Since this is pretty much big
task, ie the reason I'm asking for single driver from each MTD device
so-that once the clear stack is ready other drivers can convert
one-by-one.

[3] http://git.denx.de/?p=u-boot-spi.git;a=commitdiff;h=d297949cd3f44278f109dff42fb88a879722121c
[4] https://patchwork.ozlabs.org/patch/853337/

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [U-Boot] [RFC PATCH 00/20] SPI-NAND support
  2018-06-25 14:27         ` Jagan Teki
@ 2018-06-25 14:28           ` Jagan Teki
  2018-06-25 14:46             ` Boris Brezillon
  2018-06-25 14:36           ` Richard Weinberger
  1 sibling, 1 reply; 65+ messages in thread
From: Jagan Teki @ 2018-06-25 14:28 UTC (permalink / raw)
  To: u-boot

+ Simon
+ Tom

On Mon, Jun 25, 2018 at 7:57 PM, Jagan Teki <jagan@amarulasolutions.com> wrote:
> + Simon
> + Tom
> (suggesting MTD driver model abstraction layer)
>
> On Mon, Jun 25, 2018 at 2:39 PM, Boris Brezillon
> <boris.brezillon@bootlin.com> wrote:
>> +Richard to comment on the MTD abstraction stuff and how uboot port
>> of UBI might be impacted by some changes requested here.
>>
>> Hi Jagan,
>>
>> On Mon, 25 Jun 2018 13:59:37 +0530
>> Jagan Teki <jagannadh.teki@gmail.com> wrote:
>>
>>>
>>> I've looked the code on the respective patches, look like most of the
>>> code copy from Linux by adding __UBOOT__. I have no issue with Linux
>>> copy but we need to structure the code according to U-Boot in the form
>>> of driver-model (this series lack with that).
>>>
>>> Here are my suggestions, based the MTD work so-far
>>>
>>> First we need to design MTD driver-model which can capable to drive
>>> one driver from each interface. (not converting all interface drivers
>>> at once, that is taking more time and other issues)
>>>
>>> Like Linux MTD, U-Boot should have MTD dm for underlying flash devices
>>> like nand, parallel nor, spinor etc. So to drive this theory with
>>> driver model(with an example of block layer) mtd is common device
>>> interaction for most of  memory technology  flashes like nand,
>>> parallel nor, spinor etc, these are treated as interface types wrt
>>> u-boot driver model.
>>>
>>> Once the respective interface driver bind happen, the uclass driver
>>> will pass an 'interface type' to mtd layer to create device for it,
>>> for example once spinor ULASS_SPI_NOR driver bind happen, the uclass
>>> driver of spinor will pass MTD_IF_TYPE_SPI_NOR
>>> interface type to create mtd device for spinor devices.
>>>
>>> So If we add this design to SPI-NAND changes, we need to implement
>>> - MTD dm core that can driver all interfaces
>>
>> That's already what the MTD framework provides, and Miquel even added
>> some stuff to integrate the MTD layer even further in the DM. It's
>> probably not perfect yet, but the changes are, IMHO, going in the right
>> direction.
>>
>> Now, if you're talking about the new MTD API that creates helper
>> functions prefixed with dm_, sorry, but I don't see the point. We
>> already have plenty of MTD users in u-boot, they all manipulate MTD
>> objects and go through the standard MTD API to do that. What you
>> suggest would make things messier for several reasons:
>>
>> 1/ we won't be able to easily port Linux code to u-boot. Look at the
>>    JFFS2 UBI support. They all use mtd_info objects. What's the point of
>>    changing that except making things harder to port.
>>
>> 2/ Not all MTD providers will be converted to the device model at once,
>>    so how do you plan to deal with that?
>>
>> 3/ What's the benefit of exposing yet another way to manipulate MTD
>>    devices?
>>
>>> - one driver for raw nand
>>
>> Unfortunately, that's not how it works right now, and clearly, we
>> don't have time to work on this raw NAND rework right now.
>>
>>> - one driver for spinand
>>
>> I think that's already the case.
>>
>>> - spi-mem
>>
>> It's also what Miquel is doing in this series.
>>
>>> - convert fsl-qspi to spi-mem
>>
>> We're not targeting the fsl-qspi controller here but a simple SPI
>> controller that is already upstreamed. But yes, the fsl-qspi driver
>> will have to be patched to support the spi-mem interface at some point.
>
> Can you point me that simple spi-mem controller driver?
>
>>
>>> - implement command to handle
>>
>> This I don't get. What do you mean by "implement command to handle"?
>> Are we talking about cmd/mtd.c? I think the work Miquel has done is
>> already a good start, what's missing in there?
>>
>>>
>>> For spi-nor interface design, we have an example code here[2]
>>>
>>> I've paused this [2] series because of dm conversion of spi-drivers
>>> otherwise I need add legacy code like mmc-legacy.c, so if we really
>>> move to spi-mem design and okay with above design. I will try to move
>>> the current spi flash to add MTD driver-model so-that we can add
>>> spi-mem, spi-nand on top of it or we can work together to convert them
>>> all.
>>
>> Why can't we do things iteratively. I mean, if the long term goal is to
>> convert everything to the driver model, then this patchset is going in
>> the right direction:
>>  - addition of DM helpers to the MTD_UCLASS
>>  - addition of the spi-mem interface properly integrated in the DM
>>    model of the SPI framework
>>  - addition of a SPI NAND driver, again properly integrated in the DM
>>  - integration of DM-ready MTD drivers and old MTD drivers in a single
>>    view exposed by the cmd/mtd.c command set
>>
>> I'd really like to limit the scope of this development to these topics,
>> which doesn't prevent you from converting other part of u-boot to the
>> spi-mem approach (SPI NOR is one example).
>>
>> I hope you understand our concerns and the fact that what you're asking
>> us to do as a dependency of getting SPI NAND support + cmd/mtd.c merged
>> is way more than we can actually provide.
>
> To answer all these questions, I think we need to decide whether we go
> for MTD dm abstraction or existing MTD layer.
>
> When I say MTD dm abstraction, all mtd operation prototypes are in the
> form of udevice unlike existing MTD has mtd_info. when I initially
> supporting spi-nor (during Linux early spi-nor) I've reused existing
> MTD and written something like what Miquel did using mtd_info ops [3].
> but then developers on ML, proposed the new drivers should be form of
> driver-model abstraction, so I've added mtd driver model ops [4].
>
> I understand the new MTD dm abstraction in U-Boot is not possible for
> direct syncing from Linux, but we really want the u-boot way of
> handling drivers and trying to copy code from Linux by removing
> __UBOOT__ or any Linux specific macros. Since this is pretty much big
> task, ie the reason I'm asking for single driver from each MTD device
> so-that once the clear stack is ready other drivers can convert
> one-by-one.
>
> [3] http://git.denx.de/?p=u-boot-spi.git;a=commitdiff;h=d297949cd3f44278f109dff42fb88a879722121c
> [4] https://patchwork.ozlabs.org/patch/853337/



-- 
Jagan Teki
Senior Linux Kernel Engineer | Amarula Solutions
U-Boot, Linux | Upstream Maintainer
Hyderabad, India.

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [U-Boot] [RFC PATCH 00/20] SPI-NAND support
  2018-06-25 14:27         ` Jagan Teki
  2018-06-25 14:28           ` Jagan Teki
@ 2018-06-25 14:36           ` Richard Weinberger
  1 sibling, 0 replies; 65+ messages in thread
From: Richard Weinberger @ 2018-06-25 14:36 UTC (permalink / raw)
  To: u-boot

Am Montag, 25. Juni 2018, 16:27:45 CEST schrieb Jagan Teki:
> I understand the new MTD dm abstraction in U-Boot is not possible for
> direct syncing from Linux, but we really want the u-boot way of
> handling drivers and trying to copy code from Linux by removing
> __UBOOT__ or any Linux specific macros. Since this is pretty much big
> task, ie the reason I'm asking for single driver from each MTD device
> so-that once the clear stack is ready other drivers can convert
> one-by-one.

Do you have the man power to massage/backport all Linux changes/fixes to
u-boot?

Thanks,
//richard

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [U-Boot] [RFC PATCH 00/20] SPI-NAND support
  2018-06-25 14:28           ` Jagan Teki
@ 2018-06-25 14:46             ` Boris Brezillon
  2018-06-25 14:55               ` Tom Rini
  0 siblings, 1 reply; 65+ messages in thread
From: Boris Brezillon @ 2018-06-25 14:46 UTC (permalink / raw)
  To: u-boot

On Mon, 25 Jun 2018 19:58:37 +0530
Jagan Teki <jagan@amarulasolutions.com> wrote:

> >>> - convert fsl-qspi to spi-mem  
> >>
> >> We're not targeting the fsl-qspi controller here but a simple SPI
> >> controller that is already upstreamed. But yes, the fsl-qspi driver
> >> will have to be patched to support the spi-mem interface at some point.  
> >
> > Can you point me that simple spi-mem controller driver?

It's not a controller that implements spi-mem operations but a simple
SPI controller (one that knows how to do regular SPI transfers and
nothing more). But the spi-mem layer knows how to send spi_mem_op using
regular transfer and that's why it works without any modification at
the driver level.


> >>>
> >>> For spi-nor interface design, we have an example code here[2]
> >>>
> >>> I've paused this [2] series because of dm conversion of spi-drivers
> >>> otherwise I need add legacy code like mmc-legacy.c, so if we really
> >>> move to spi-mem design and okay with above design. I will try to move
> >>> the current spi flash to add MTD driver-model so-that we can add
> >>> spi-mem, spi-nand on top of it or we can work together to convert them
> >>> all.  
> >>
> >> Why can't we do things iteratively. I mean, if the long term goal is to
> >> convert everything to the driver model, then this patchset is going in
> >> the right direction:
> >>  - addition of DM helpers to the MTD_UCLASS
> >>  - addition of the spi-mem interface properly integrated in the DM
> >>    model of the SPI framework
> >>  - addition of a SPI NAND driver, again properly integrated in the DM
> >>  - integration of DM-ready MTD drivers and old MTD drivers in a single
> >>    view exposed by the cmd/mtd.c command set
> >>
> >> I'd really like to limit the scope of this development to these topics,
> >> which doesn't prevent you from converting other part of u-boot to the
> >> spi-mem approach (SPI NOR is one example).
> >>
> >> I hope you understand our concerns and the fact that what you're asking
> >> us to do as a dependency of getting SPI NAND support + cmd/mtd.c merged
> >> is way more than we can actually provide.  
> >
> > To answer all these questions, I think we need to decide whether we go
> > for MTD dm abstraction or existing MTD layer.
> >
> > When I say MTD dm abstraction, all mtd operation prototypes are in the
> > form of udevice unlike existing MTD has mtd_info. when I initially
> > supporting spi-nor (during Linux early spi-nor) I've reused existing
> > MTD and written something like what Miquel did using mtd_info ops [3].
> > but then developers on ML, proposed the new drivers should be form of
> > driver-model abstraction, so I've added mtd driver model ops [4].
> >
> > I understand the new MTD dm abstraction in U-Boot is not possible for
> > direct syncing from Linux, but we really want the u-boot way of
> > handling drivers and trying to copy code from Linux by removing
> > __UBOOT__ or any Linux specific macros. Since this is pretty much big
> > task, ie the reason I'm asking for single driver from each MTD device
> > so-that once the clear stack is ready other drivers can convert
> > one-by-one.

I think I have to repeat my previous statement here. It would be very
unfortunate if u-boot decides to take this direction (see Richard's
reply), especially since I see absolutely no benefit in doing what you
suggest. Having MTD devices registered to the uboot DM is something I
can understand, deciding to no longer support the standard MTD API is
something I don't.

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [U-Boot] [RFC PATCH 00/20] SPI-NAND support
  2018-06-25 14:46             ` Boris Brezillon
@ 2018-06-25 14:55               ` Tom Rini
  2018-06-25 14:59                 ` Stefan Roese
  2018-06-25 18:37                 ` Jagan Teki
  0 siblings, 2 replies; 65+ messages in thread
From: Tom Rini @ 2018-06-25 14:55 UTC (permalink / raw)
  To: u-boot

On Mon, Jun 25, 2018 at 04:46:56PM +0200, Boris Brezillon wrote:
> On Mon, 25 Jun 2018 19:58:37 +0530
> Jagan Teki <jagan@amarulasolutions.com> wrote:
> 
> > >>> - convert fsl-qspi to spi-mem  
> > >>
> > >> We're not targeting the fsl-qspi controller here but a simple SPI
> > >> controller that is already upstreamed. But yes, the fsl-qspi driver
> > >> will have to be patched to support the spi-mem interface at some point.  
> > >
> > > Can you point me that simple spi-mem controller driver?
> 
> It's not a controller that implements spi-mem operations but a simple
> SPI controller (one that knows how to do regular SPI transfers and
> nothing more). But the spi-mem layer knows how to send spi_mem_op using
> regular transfer and that's why it works without any modification at
> the driver level.
> 
> 
> > >>>
> > >>> For spi-nor interface design, we have an example code here[2]
> > >>>
> > >>> I've paused this [2] series because of dm conversion of spi-drivers
> > >>> otherwise I need add legacy code like mmc-legacy.c, so if we really
> > >>> move to spi-mem design and okay with above design. I will try to move
> > >>> the current spi flash to add MTD driver-model so-that we can add
> > >>> spi-mem, spi-nand on top of it or we can work together to convert them
> > >>> all.  
> > >>
> > >> Why can't we do things iteratively. I mean, if the long term goal is to
> > >> convert everything to the driver model, then this patchset is going in
> > >> the right direction:
> > >>  - addition of DM helpers to the MTD_UCLASS
> > >>  - addition of the spi-mem interface properly integrated in the DM
> > >>    model of the SPI framework
> > >>  - addition of a SPI NAND driver, again properly integrated in the DM
> > >>  - integration of DM-ready MTD drivers and old MTD drivers in a single
> > >>    view exposed by the cmd/mtd.c command set
> > >>
> > >> I'd really like to limit the scope of this development to these topics,
> > >> which doesn't prevent you from converting other part of u-boot to the
> > >> spi-mem approach (SPI NOR is one example).
> > >>
> > >> I hope you understand our concerns and the fact that what you're asking
> > >> us to do as a dependency of getting SPI NAND support + cmd/mtd.c merged
> > >> is way more than we can actually provide.  
> > >
> > > To answer all these questions, I think we need to decide whether we go
> > > for MTD dm abstraction or existing MTD layer.
> > >
> > > When I say MTD dm abstraction, all mtd operation prototypes are in the
> > > form of udevice unlike existing MTD has mtd_info. when I initially
> > > supporting spi-nor (during Linux early spi-nor) I've reused existing
> > > MTD and written something like what Miquel did using mtd_info ops [3].
> > > but then developers on ML, proposed the new drivers should be form of
> > > driver-model abstraction, so I've added mtd driver model ops [4].
> > >
> > > I understand the new MTD dm abstraction in U-Boot is not possible for
> > > direct syncing from Linux, but we really want the u-boot way of
> > > handling drivers and trying to copy code from Linux by removing
> > > __UBOOT__ or any Linux specific macros. Since this is pretty much big
> > > task, ie the reason I'm asking for single driver from each MTD device
> > > so-that once the clear stack is ready other drivers can convert
> > > one-by-one.
> 
> I think I have to repeat my previous statement here. It would be very
> unfortunate if u-boot decides to take this direction (see Richard's
> reply), especially since I see absolutely no benefit in doing what you
> suggest. Having MTD devices registered to the uboot DM is something I
> can understand, deciding to no longer support the standard MTD API is
> something I don't.

I agree.  We want U-Boot to be able to leverage as much as possible from
the Linux kernel with as little re-working as possible.

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20180625/aa2bbc35/attachment.sig>

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [U-Boot] [RFC PATCH 00/20] SPI-NAND support
  2018-06-25 14:55               ` Tom Rini
@ 2018-06-25 14:59                 ` Stefan Roese
  2018-06-25 18:37                 ` Jagan Teki
  1 sibling, 0 replies; 65+ messages in thread
From: Stefan Roese @ 2018-06-25 14:59 UTC (permalink / raw)
  To: u-boot

On 25.06.2018 16:55, Tom Rini wrote:
> On Mon, Jun 25, 2018 at 04:46:56PM +0200, Boris Brezillon wrote:
>> On Mon, 25 Jun 2018 19:58:37 +0530
>> Jagan Teki <jagan@amarulasolutions.com> wrote:
>>
>>>>>> - convert fsl-qspi to spi-mem
>>>>>
>>>>> We're not targeting the fsl-qspi controller here but a simple SPI
>>>>> controller that is already upstreamed. But yes, the fsl-qspi driver
>>>>> will have to be patched to support the spi-mem interface at some point.
>>>>
>>>> Can you point me that simple spi-mem controller driver?
>>
>> It's not a controller that implements spi-mem operations but a simple
>> SPI controller (one that knows how to do regular SPI transfers and
>> nothing more). But the spi-mem layer knows how to send spi_mem_op using
>> regular transfer and that's why it works without any modification at
>> the driver level.
>>
>>
>>>>>>
>>>>>> For spi-nor interface design, we have an example code here[2]
>>>>>>
>>>>>> I've paused this [2] series because of dm conversion of spi-drivers
>>>>>> otherwise I need add legacy code like mmc-legacy.c, so if we really
>>>>>> move to spi-mem design and okay with above design. I will try to move
>>>>>> the current spi flash to add MTD driver-model so-that we can add
>>>>>> spi-mem, spi-nand on top of it or we can work together to convert them
>>>>>> all.
>>>>>
>>>>> Why can't we do things iteratively. I mean, if the long term goal is to
>>>>> convert everything to the driver model, then this patchset is going in
>>>>> the right direction:
>>>>>   - addition of DM helpers to the MTD_UCLASS
>>>>>   - addition of the spi-mem interface properly integrated in the DM
>>>>>     model of the SPI framework
>>>>>   - addition of a SPI NAND driver, again properly integrated in the DM
>>>>>   - integration of DM-ready MTD drivers and old MTD drivers in a single
>>>>>     view exposed by the cmd/mtd.c command set
>>>>>
>>>>> I'd really like to limit the scope of this development to these topics,
>>>>> which doesn't prevent you from converting other part of u-boot to the
>>>>> spi-mem approach (SPI NOR is one example).
>>>>>
>>>>> I hope you understand our concerns and the fact that what you're asking
>>>>> us to do as a dependency of getting SPI NAND support + cmd/mtd.c merged
>>>>> is way more than we can actually provide.
>>>>
>>>> To answer all these questions, I think we need to decide whether we go
>>>> for MTD dm abstraction or existing MTD layer.
>>>>
>>>> When I say MTD dm abstraction, all mtd operation prototypes are in the
>>>> form of udevice unlike existing MTD has mtd_info. when I initially
>>>> supporting spi-nor (during Linux early spi-nor) I've reused existing
>>>> MTD and written something like what Miquel did using mtd_info ops [3].
>>>> but then developers on ML, proposed the new drivers should be form of
>>>> driver-model abstraction, so I've added mtd driver model ops [4].
>>>>
>>>> I understand the new MTD dm abstraction in U-Boot is not possible for
>>>> direct syncing from Linux, but we really want the u-boot way of
>>>> handling drivers and trying to copy code from Linux by removing
>>>> __UBOOT__ or any Linux specific macros. Since this is pretty much big
>>>> task, ie the reason I'm asking for single driver from each MTD device
>>>> so-that once the clear stack is ready other drivers can convert
>>>> one-by-one.
>>
>> I think I have to repeat my previous statement here. It would be very
>> unfortunate if u-boot decides to take this direction (see Richard's
>> reply), especially since I see absolutely no benefit in doing what you
>> suggest. Having MTD devices registered to the uboot DM is something I
>> can understand, deciding to no longer support the standard MTD API is
>> something I don't.
> 
> I agree.  We want U-Boot to be able to leverage as much as possible from
> the Linux kernel with as little re-working as possible.

I wholeheartedly agree on this.

Thanks,
Stefan

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [U-Boot] [RFC PATCH 00/20] SPI-NAND support
  2018-06-25 14:55               ` Tom Rini
  2018-06-25 14:59                 ` Stefan Roese
@ 2018-06-25 18:37                 ` Jagan Teki
  2018-06-25 19:58                   ` Boris Brezillon
  1 sibling, 1 reply; 65+ messages in thread
From: Jagan Teki @ 2018-06-25 18:37 UTC (permalink / raw)
  To: u-boot

On Mon, Jun 25, 2018 at 8:25 PM, Tom Rini <trini@konsulko.com> wrote:
> On Mon, Jun 25, 2018 at 04:46:56PM +0200, Boris Brezillon wrote:
>> On Mon, 25 Jun 2018 19:58:37 +0530
>> Jagan Teki <jagan@amarulasolutions.com> wrote:
>>
>> > >>> - convert fsl-qspi to spi-mem
>> > >>
>> > >> We're not targeting the fsl-qspi controller here but a simple SPI
>> > >> controller that is already upstreamed. But yes, the fsl-qspi driver
>> > >> will have to be patched to support the spi-mem interface at some point.
>> > >
>> > > Can you point me that simple spi-mem controller driver?
>>
>> It's not a controller that implements spi-mem operations but a simple
>> SPI controller (one that knows how to do regular SPI transfers and
>> nothing more). But the spi-mem layer knows how to send spi_mem_op using
>> regular transfer and that's why it works without any modification at
>> the driver level.
>>
>>
>> > >>>
>> > >>> For spi-nor interface design, we have an example code here[2]
>> > >>>
>> > >>> I've paused this [2] series because of dm conversion of spi-drivers
>> > >>> otherwise I need add legacy code like mmc-legacy.c, so if we really
>> > >>> move to spi-mem design and okay with above design. I will try to move
>> > >>> the current spi flash to add MTD driver-model so-that we can add
>> > >>> spi-mem, spi-nand on top of it or we can work together to convert them
>> > >>> all.
>> > >>
>> > >> Why can't we do things iteratively. I mean, if the long term goal is to
>> > >> convert everything to the driver model, then this patchset is going in
>> > >> the right direction:
>> > >>  - addition of DM helpers to the MTD_UCLASS
>> > >>  - addition of the spi-mem interface properly integrated in the DM
>> > >>    model of the SPI framework
>> > >>  - addition of a SPI NAND driver, again properly integrated in the DM
>> > >>  - integration of DM-ready MTD drivers and old MTD drivers in a single
>> > >>    view exposed by the cmd/mtd.c command set
>> > >>
>> > >> I'd really like to limit the scope of this development to these topics,
>> > >> which doesn't prevent you from converting other part of u-boot to the
>> > >> spi-mem approach (SPI NOR is one example).
>> > >>
>> > >> I hope you understand our concerns and the fact that what you're asking
>> > >> us to do as a dependency of getting SPI NAND support + cmd/mtd.c merged
>> > >> is way more than we can actually provide.
>> > >
>> > > To answer all these questions, I think we need to decide whether we go
>> > > for MTD dm abstraction or existing MTD layer.
>> > >
>> > > When I say MTD dm abstraction, all mtd operation prototypes are in the
>> > > form of udevice unlike existing MTD has mtd_info. when I initially
>> > > supporting spi-nor (during Linux early spi-nor) I've reused existing
>> > > MTD and written something like what Miquel did using mtd_info ops [3].
>> > > but then developers on ML, proposed the new drivers should be form of
>> > > driver-model abstraction, so I've added mtd driver model ops [4].
>> > >
>> > > I understand the new MTD dm abstraction in U-Boot is not possible for
>> > > direct syncing from Linux, but we really want the u-boot way of
>> > > handling drivers and trying to copy code from Linux by removing
>> > > __UBOOT__ or any Linux specific macros. Since this is pretty much big
>> > > task, ie the reason I'm asking for single driver from each MTD device
>> > > so-that once the clear stack is ready other drivers can convert
>> > > one-by-one.
>>
>> I think I have to repeat my previous statement here. It would be very
>> unfortunate if u-boot decides to take this direction (see Richard's
>> reply), especially since I see absolutely no benefit in doing what you
>> suggest. Having MTD devices registered to the uboot DM is something I
>> can understand, deciding to no longer support the standard MTD API is
>> something I don't.
>
> I agree.  We want U-Boot to be able to leverage as much as possible from
> the Linux kernel with as little re-working as possible.

I'm not denying that, but the basic design flow must follow u-boot
driver model. this is what everyone told from the beginning when I
started spi-nor work. Initially I did the design like this and
leverage with existing MTD, everyone NAK and suggested to use
driver-model on each stage with MTD dm abstraction.
So
- After 2 years of work
- With nearly 10 versions [4]
- Adding MIGRATION expire date for spi drivers dm conversion
- Simon Reviewed-by and
- Planning to apply after v2018.09.

but now all want the existing MTD, I don't understand what I can do
further on this?

[4] https://patchwork.ozlabs.org/user/todo/uboot/?series=20450

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [U-Boot] [RFC PATCH 00/20] SPI-NAND support
  2018-06-25 18:37                 ` Jagan Teki
@ 2018-06-25 19:58                   ` Boris Brezillon
  2018-06-25 20:01                     ` Tom Rini
  2018-06-27 11:43                     ` Jagan Teki
  0 siblings, 2 replies; 65+ messages in thread
From: Boris Brezillon @ 2018-06-25 19:58 UTC (permalink / raw)
  To: u-boot

On Tue, 26 Jun 2018 00:07:10 +0530
Jagan Teki <jagan@amarulasolutions.com> wrote:

> >> I think I have to repeat my previous statement here. It would be very
> >> unfortunate if u-boot decides to take this direction (see Richard's
> >> reply), especially since I see absolutely no benefit in doing what you
> >> suggest. Having MTD devices registered to the uboot DM is something I
> >> can understand, deciding to no longer support the standard MTD API is
> >> something I don't.  
> 
> > I agree.  We want U-Boot to be able to leverage as much as possible from
> > the Linux kernel with as little re-working as possible.  
> 
> I'm not denying that, but the basic design flow must follow u-boot
> driver model. this is what everyone told from the beginning when I
> started spi-nor work. Initially I did the design like this and
> leverage with existing MTD, everyone NAK and suggested to use
> driver-model on each stage with MTD dm abstraction.
> So
> - After 2 years of work
> - With nearly 10 versions [4]
> - Adding MIGRATION expire date for spi drivers dm conversion
> - Simon Reviewed-by and
> - Planning to apply after v2018.09.
> 
> but now all want the existing MTD, I don't understand what I can do
> further on this?

I didn't follow the initial discussion, but I can understand your
frustration. Still, I think there's a misunderstanding here. I recommend
that you have a second look at the different patches in this series.
You'll see that everything Miquel did complies with the DM, and that
the thing you're complaining about (MTD API not using udevice and not
prefixed with dm_) is just a tiny detail compared to the rest.

Keeping the MTD API is not incompatible with the conversion of
all MTD provider drivers to the DM. I think we all agree on that MTD
providers should be converted to the DM progressively, and the work
Miquel did allows such a smooth transition because both non-DM drivers
and DM-compliant drivers can co-exist without impacting MTD users.

Sorry to say that, but your approach based on full-conversion is just an
utopia. There's no way we can do that in a single step.

So the question here is more, should we block all developments until we
have a perfect solution (I don't think perfection can be achieved
without trying things and making mistake), or should we move forward,
one step after the other and keep the "conversion of all MTD
drivers to the DM" as a long term goal?

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [U-Boot] [RFC PATCH 00/20] SPI-NAND support
  2018-06-25 19:58                   ` Boris Brezillon
@ 2018-06-25 20:01                     ` Tom Rini
  2018-06-27 11:43                     ` Jagan Teki
  1 sibling, 0 replies; 65+ messages in thread
From: Tom Rini @ 2018-06-25 20:01 UTC (permalink / raw)
  To: u-boot

On Mon, Jun 25, 2018 at 09:58:39PM +0200, Boris Brezillon wrote:
> On Tue, 26 Jun 2018 00:07:10 +0530
> Jagan Teki <jagan@amarulasolutions.com> wrote:
> 
> > >> I think I have to repeat my previous statement here. It would be very
> > >> unfortunate if u-boot decides to take this direction (see Richard's
> > >> reply), especially since I see absolutely no benefit in doing what you
> > >> suggest. Having MTD devices registered to the uboot DM is something I
> > >> can understand, deciding to no longer support the standard MTD API is
> > >> something I don't.  
> > 
> > > I agree.  We want U-Boot to be able to leverage as much as possible from
> > > the Linux kernel with as little re-working as possible.  
> > 
> > I'm not denying that, but the basic design flow must follow u-boot
> > driver model. this is what everyone told from the beginning when I
> > started spi-nor work. Initially I did the design like this and
> > leverage with existing MTD, everyone NAK and suggested to use
> > driver-model on each stage with MTD dm abstraction.
> > So
> > - After 2 years of work
> > - With nearly 10 versions [4]
> > - Adding MIGRATION expire date for spi drivers dm conversion
> > - Simon Reviewed-by and
> > - Planning to apply after v2018.09.
> > 
> > but now all want the existing MTD, I don't understand what I can do
> > further on this?
> 
> I didn't follow the initial discussion, but I can understand your
> frustration. Still, I think there's a misunderstanding here. I recommend
> that you have a second look at the different patches in this series.
> You'll see that everything Miquel did complies with the DM, and that
> the thing you're complaining about (MTD API not using udevice and not
> prefixed with dm_) is just a tiny detail compared to the rest.
> 
> Keeping the MTD API is not incompatible with the conversion of
> all MTD provider drivers to the DM. I think we all agree on that MTD
> providers should be converted to the DM progressively, and the work
> Miquel did allows such a smooth transition because both non-DM drivers
> and DM-compliant drivers can co-exist without impacting MTD users.
> 
> Sorry to say that, but your approach based on full-conversion is just an
> utopia. There's no way we can do that in a single step.
> 
> So the question here is more, should we block all developments until we
> have a perfect solution (I don't think perfection can be achieved
> without trying things and making mistake), or should we move forward,
> one step after the other and keep the "conversion of all MTD
> drivers to the DM" as a long term goal?

And furthermore, we _really_ need to get this area un-blocked.  I feel
bad that Jagan's series went on for so long, but I think it also
highlights the problem with a
convert-everything-at-once-try-and-be-perfect approach.

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20180625/58f2d972/attachment.sig>

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [U-Boot] [RFC PATCH 15/20] mtd: spinand: Add initial support for the MX35LF2GE4AB chip
  2018-06-22 12:03   ` Boris Brezillon
@ 2018-06-26  7:54     ` Miquel Raynal
  0 siblings, 0 replies; 65+ messages in thread
From: Miquel Raynal @ 2018-06-26  7:54 UTC (permalink / raw)
  To: u-boot

Hi Boris,

On Fri, 22 Jun 2018 14:03:36 +0200, Boris Brezillon
<boris.brezillon@bootlin.com> wrote:

> On Wed,  6 Jun 2018 17:30:35 +0200
> Miquel Raynal <miquel.raynal@bootlin.com> wrote:
> 
> > Add support for the MX35LF2GE4AB chip, which is similar to its cousin
> > MX35LF1GE4AB, with two planes instead of one.
> > 
> > Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> > ---
> >  drivers/mtd/nand/spi/macronix.c | 20 ++++++++++++++------
> >  1 file changed, 14 insertions(+), 6 deletions(-)
> > 
> > diff --git a/drivers/mtd/nand/spi/macronix.c b/drivers/mtd/nand/spi/macronix.c
> > index dd351dcb6c..d761b99d26 100644
> > --- a/drivers/mtd/nand/spi/macronix.c
> > +++ b/drivers/mtd/nand/spi/macronix.c
> > @@ -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, 1024, 2, 1, 1),  
> 
> 		    I think it should be 2048 here ^.

I just checked, I think you are right. I'll edit this for the next
version.

Thanks,
Miquèl

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [U-Boot] [RFC PATCH 01/20] mtd: Fallback to ->_read/write_oob() when ->_read/write() is missing
  2018-06-06 15:30 ` [U-Boot] [RFC PATCH 01/20] mtd: Fallback to ->_read/write_oob() when ->_read/write() is missing Miquel Raynal
@ 2018-06-27 10:52   ` Jagan Teki
  0 siblings, 0 replies; 65+ messages in thread
From: Jagan Teki @ 2018-06-27 10:52 UTC (permalink / raw)
  To: u-boot

On Wed, Jun 6, 2018 at 9:00 PM, Miquel Raynal <miquel.raynal@bootlin.com> wrote:
> From: Boris Brezillon <boris.brezillon@free-electrons.com>
>
> 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.
>
> Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
> Acked-by: Robert Jarzmik <robert.jarzmik@free.fr>
> Acked-by: Brian Norris <computersforpeace@gmail.com>
> Reviewed-by: Miquel Raynal <miquel.raynal@free-electrons.com>
> Tested-by: Ladislav Michl <ladis@linux-mips.org>
> Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> ---

Reviewed-by: Jagan Teki <jagan@openedev.com>

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [U-Boot] [RFC PATCH 02/20] mtd: add get/set of_node/flash_node helpers
  2018-06-06 15:30 ` [U-Boot] [RFC PATCH 02/20] mtd: add get/set of_node/flash_node helpers Miquel Raynal
@ 2018-06-27 10:53   ` Jagan Teki
  0 siblings, 0 replies; 65+ messages in thread
From: Jagan Teki @ 2018-06-27 10:53 UTC (permalink / raw)
  To: u-boot

On Wed, Jun 6, 2018 at 9:00 PM, Miquel Raynal <miquel.raynal@bootlin.com> wrote:
> From: Brian Norris <computersforpeace@gmail.com>
>
> 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.
>
> Signed-off-by: Brian Norris <computersforpeace@gmail.com>
> Reviewed-by: Boris Brezillon <boris.brezillon@free-electrons.com>
> Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> ---

Reviewed-by: Jagan Teki <jagan@openedev.com>

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [U-Boot] [RFC PATCH 03/20] mtd: fix build issue with includes
  2018-06-06 15:30 ` [U-Boot] [RFC PATCH 03/20] mtd: fix build issue with includes Miquel Raynal
@ 2018-06-27 10:53   ` Jagan Teki
  0 siblings, 0 replies; 65+ messages in thread
From: Jagan Teki @ 2018-06-27 10:53 UTC (permalink / raw)
  To: u-boot

On Wed, Jun 6, 2018 at 9:00 PM, Miquel Raynal <miquel.raynal@bootlin.com> wrote:
> Fix build errors produced by mtd.h and dm/device.h if not included in
> the right order.
>
> Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> ---

Reviewed-by: Jagan Teki <jagan@openedev.com>

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [U-Boot] [RFC PATCH 05/20] mtd: move all flash categories inside MTD submenu
  2018-06-06 15:30 ` [U-Boot] [RFC PATCH 05/20] mtd: move all flash categories inside MTD submenu Miquel Raynal
@ 2018-06-27 10:56   ` Jagan Teki
  0 siblings, 0 replies; 65+ messages in thread
From: Jagan Teki @ 2018-06-27 10:56 UTC (permalink / raw)
  To: u-boot

On Wed, Jun 6, 2018 at 9:00 PM, Miquel Raynal <miquel.raynal@bootlin.com> wrote:
> There is no reason to have NAND, SPI flashes and UBI sections outside of
> the MTD submenu in Kconfig.
>
> Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> ---

Reviewed-by: Jagan Teki <jagan@openedev.com>

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [U-Boot] [RFC PATCH 08/20] mtd: nand: Add core infrastructure to deal with NAND devices
  2018-06-06 15:30 ` [U-Boot] [RFC PATCH 08/20] mtd: nand: Add core infrastructure to deal with NAND devices Miquel Raynal
@ 2018-06-27 11:08   ` Jagan Teki
  2018-06-27 12:48     ` Miquel Raynal
  0 siblings, 1 reply; 65+ messages in thread
From: Jagan Teki @ 2018-06-27 11:08 UTC (permalink / raw)
  To: u-boot

On Wed, Jun 6, 2018 at 9:00 PM, Miquel Raynal <miquel.raynal@bootlin.com> wrote:
> From: Boris Brezillon <boris.brezillon@bootlin.com>
>
> Add an intermediate layer to abstract NAND device interface so that
> some logic can be shared between SPI NANDs, parallel/raw NANDs,
> OneNANDs, ...
>
> Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>
> Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> ---
>  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
>
> diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
> index 6d53734718..1c1a1f487e 100644
> --- a/drivers/mtd/nand/Kconfig
> +++ b/drivers/mtd/nand/Kconfig
> @@ -1 +1,4 @@
> +config MTD_NAND_CORE
> +       tristate
> +
>  source "drivers/mtd/nand/raw/Kconfig"
> diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
> index d1c3f93047..69c80ea252 100644
> --- a/drivers/mtd/nand/Makefile
> +++ b/drivers/mtd/nand/Makefile
> @@ -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/
> diff --git a/drivers/mtd/nand/bbt.c b/drivers/mtd/nand/bbt.c
> new file mode 100644
> index 0000000000..7e0ad3190c
> --- /dev/null
> +++ b/drivers/mtd/nand/bbt.c
> @@ -0,0 +1,132 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (c) 2017 Free Electrons
> + *
> + * Authors:
> + *     Boris Brezillon <boris.brezillon@free-electrons.com>
> + *     Peter Pan <peterpandong@micron.com>
> + */
> +
> +#define pr_fmt(fmt)    "nand-bbt: " fmt
> +
> +#include <linux/mtd/nand.h>
> +#ifndef __UBOOT__
> +#include <linux/slab.h>
> +#endif
> +
> +/**
> + * nanddev_bbt_init() - Initialize the BBT (Bad Block Table)
> + * @nand: NAND device
> + *
> + * Initialize the in-memory BBT.
> + *
> + * Return: 0 in case of success, a negative error code otherwise.
> + */
> +int nanddev_bbt_init(struct nand_device *nand)
> +{
> +       unsigned int bits_per_block = fls(NAND_BBT_BLOCK_NUM_STATUS);
> +       unsigned int nblocks = nanddev_neraseblocks(nand);
> +       unsigned int nwords = DIV_ROUND_UP(nblocks * bits_per_block,
> +                                          BITS_PER_LONG);
> +
> +       nand->bbt.cache = kzalloc(nwords, GFP_KERNEL);
> +       if (!nand->bbt.cache)
> +               return -ENOMEM;
> +
> +       return 0;
> +}
> +EXPORT_SYMBOL_GPL(nanddev_bbt_init);

Can't we skip __UBOOT__ and EXPORT_SYMBOL_GPL ?

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [U-Boot] [RFC PATCH 00/20] SPI-NAND support
  2018-06-25 19:58                   ` Boris Brezillon
  2018-06-25 20:01                     ` Tom Rini
@ 2018-06-27 11:43                     ` Jagan Teki
  1 sibling, 0 replies; 65+ messages in thread
From: Jagan Teki @ 2018-06-27 11:43 UTC (permalink / raw)
  To: u-boot

On Tue, Jun 26, 2018 at 1:28 AM, Boris Brezillon
<boris.brezillon@bootlin.com> wrote:
> On Tue, 26 Jun 2018 00:07:10 +0530
> Jagan Teki <jagan@amarulasolutions.com> wrote:
>
>> >> I think I have to repeat my previous statement here. It would be very
>> >> unfortunate if u-boot decides to take this direction (see Richard's
>> >> reply), especially since I see absolutely no benefit in doing what you
>> >> suggest. Having MTD devices registered to the uboot DM is something I
>> >> can understand, deciding to no longer support the standard MTD API is
>> >> something I don't.
>>
>> > I agree.  We want U-Boot to be able to leverage as much as possible from
>> > the Linux kernel with as little re-working as possible.
>>
>> I'm not denying that, but the basic design flow must follow u-boot
>> driver model. this is what everyone told from the beginning when I
>> started spi-nor work. Initially I did the design like this and
>> leverage with existing MTD, everyone NAK and suggested to use
>> driver-model on each stage with MTD dm abstraction.
>> So
>> - After 2 years of work
>> - With nearly 10 versions [4]
>> - Adding MIGRATION expire date for spi drivers dm conversion
>> - Simon Reviewed-by and
>> - Planning to apply after v2018.09.
>>
>> but now all want the existing MTD, I don't understand what I can do
>> further on this?
>
> I didn't follow the initial discussion, but I can understand your
> frustration. Still, I think there's a misunderstanding here. I recommend
> that you have a second look at the different patches in this series.
> You'll see that everything Miquel did complies with the DM, and that
> the thing you're complaining about (MTD API not using udevice and not
> prefixed with dm_) is just a tiny detail compared to the rest.
>
> Keeping the MTD API is not incompatible with the conversion of
> all MTD provider drivers to the DM. I think we all agree on that MTD
> providers should be converted to the DM progressively, and the work
> Miquel did allows such a smooth transition because both non-DM drivers
> and DM-compliant drivers can co-exist without impacting MTD users.
>
> Sorry to say that, but your approach based on full-conversion is just an
> utopia. There's no way we can do that in a single step.
>
> So the question here is more, should we block all developments until we
> have a perfect solution (I don't think perfection can be achieved
> without trying things and making mistake), or should we move forward,
> one step after the other and keep the "conversion of all MTD
> drivers to the DM" as a long term goal?

Thanks for explaining all these Boris.

I agree on the context of "not to block the development" for the sake
of new improvement solution. Yes I will start reviewing these stuff,
even thought these are not compatible with MTD DM providers. Mean
while I will keep moving spi-nor development with MTD DM providers
along with Linux changes and it should be a starting point for full DM
conversion for MTD layer.

Jagan.

-- 
Jagan Teki
Senior Linux Kernel Engineer | Amarula Solutions
U-Boot, Linux | Upstream Maintainer
Hyderabad, India.

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [U-Boot] [RFC PATCH 08/20] mtd: nand: Add core infrastructure to deal with NAND devices
  2018-06-27 11:08   ` Jagan Teki
@ 2018-06-27 12:48     ` Miquel Raynal
  2018-06-27 21:35       ` Tom Rini
  0 siblings, 1 reply; 65+ messages in thread
From: Miquel Raynal @ 2018-06-27 12:48 UTC (permalink / raw)
  To: u-boot

Hi Jagan,

On Wed, 27 Jun 2018 16:38:26 +0530, Jagan Teki
<jagan@amarulasolutions.com> wrote:

> On Wed, Jun 6, 2018 at 9:00 PM, Miquel Raynal <miquel.raynal@bootlin.com> wrote:
> > From: Boris Brezillon <boris.brezillon@bootlin.com>
> >
> > Add an intermediate layer to abstract NAND device interface so that
> > some logic can be shared between SPI NANDs, parallel/raw NANDs,
> > OneNANDs, ...
> >
> > Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>
> > Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> > ---
> >  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
> >
> > diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
> > index 6d53734718..1c1a1f487e 100644
> > --- a/drivers/mtd/nand/Kconfig
> > +++ b/drivers/mtd/nand/Kconfig
> > @@ -1 +1,4 @@
> > +config MTD_NAND_CORE
> > +       tristate
> > +
> >  source "drivers/mtd/nand/raw/Kconfig"
> > diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
> > index d1c3f93047..69c80ea252 100644
> > --- a/drivers/mtd/nand/Makefile
> > +++ b/drivers/mtd/nand/Makefile
> > @@ -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/
> > diff --git a/drivers/mtd/nand/bbt.c b/drivers/mtd/nand/bbt.c
> > new file mode 100644
> > index 0000000000..7e0ad3190c
> > --- /dev/null
> > +++ b/drivers/mtd/nand/bbt.c
> > @@ -0,0 +1,132 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * Copyright (c) 2017 Free Electrons
> > + *
> > + * Authors:
> > + *     Boris Brezillon <boris.brezillon@free-electrons.com>
> > + *     Peter Pan <peterpandong@micron.com>
> > + */
> > +
> > +#define pr_fmt(fmt)    "nand-bbt: " fmt
> > +
> > +#include <linux/mtd/nand.h>
> > +#ifndef __UBOOT__
> > +#include <linux/slab.h>
> > +#endif
> > +
> > +/**
> > + * nanddev_bbt_init() - Initialize the BBT (Bad Block Table)
> > + * @nand: NAND device
> > + *
> > + * Initialize the in-memory BBT.
> > + *
> > + * Return: 0 in case of success, a negative error code otherwise.
> > + */
> > +int nanddev_bbt_init(struct nand_device *nand)
> > +{
> > +       unsigned int bits_per_block = fls(NAND_BBT_BLOCK_NUM_STATUS);
> > +       unsigned int nblocks = nanddev_neraseblocks(nand);
> > +       unsigned int nwords = DIV_ROUND_UP(nblocks * bits_per_block,
> > +                                          BITS_PER_LONG);
> > +
> > +       nand->bbt.cache = kzalloc(nwords, GFP_KERNEL);
> > +       if (!nand->bbt.cache)
> > +               return -ENOMEM;
> > +
> > +       return 0;
> > +}
> > +EXPORT_SYMBOL_GPL(nanddev_bbt_init);  
> 
> Can't we skip __UBOOT__ and EXPORT_SYMBOL_GPL ?

Do you mean that you want me to delete all the #ifndef __UBOOT__/#endif
sections?

They are present only to ease the patch backporting process from
Linux. It was very useful during the development, I don't have a
strong opinion on whether we should keep them or not, yet. 

Thanks for reviewing!
Miquèl

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [U-Boot] [RFC PATCH 08/20] mtd: nand: Add core infrastructure to deal with NAND devices
  2018-06-27 12:48     ` Miquel Raynal
@ 2018-06-27 21:35       ` Tom Rini
  0 siblings, 0 replies; 65+ messages in thread
From: Tom Rini @ 2018-06-27 21:35 UTC (permalink / raw)
  To: u-boot

On Wed, Jun 27, 2018 at 02:48:23PM +0200, Miquel Raynal wrote:
> Hi Jagan,
> 
> On Wed, 27 Jun 2018 16:38:26 +0530, Jagan Teki
> <jagan@amarulasolutions.com> wrote:
> 
> > On Wed, Jun 6, 2018 at 9:00 PM, Miquel Raynal <miquel.raynal@bootlin.com> wrote:
> > > From: Boris Brezillon <boris.brezillon@bootlin.com>
> > >
> > > Add an intermediate layer to abstract NAND device interface so that
> > > some logic can be shared between SPI NANDs, parallel/raw NANDs,
> > > OneNANDs, ...
> > >
> > > Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>
> > > Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> > > ---
> > >  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
> > >
> > > diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
> > > index 6d53734718..1c1a1f487e 100644
> > > --- a/drivers/mtd/nand/Kconfig
> > > +++ b/drivers/mtd/nand/Kconfig
> > > @@ -1 +1,4 @@
> > > +config MTD_NAND_CORE
> > > +       tristate
> > > +
> > >  source "drivers/mtd/nand/raw/Kconfig"
> > > diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
> > > index d1c3f93047..69c80ea252 100644
> > > --- a/drivers/mtd/nand/Makefile
> > > +++ b/drivers/mtd/nand/Makefile
> > > @@ -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/
> > > diff --git a/drivers/mtd/nand/bbt.c b/drivers/mtd/nand/bbt.c
> > > new file mode 100644
> > > index 0000000000..7e0ad3190c
> > > --- /dev/null
> > > +++ b/drivers/mtd/nand/bbt.c
> > > @@ -0,0 +1,132 @@
> > > +// SPDX-License-Identifier: GPL-2.0
> > > +/*
> > > + * Copyright (c) 2017 Free Electrons
> > > + *
> > > + * Authors:
> > > + *     Boris Brezillon <boris.brezillon@free-electrons.com>
> > > + *     Peter Pan <peterpandong@micron.com>
> > > + */
> > > +
> > > +#define pr_fmt(fmt)    "nand-bbt: " fmt
> > > +
> > > +#include <linux/mtd/nand.h>
> > > +#ifndef __UBOOT__
> > > +#include <linux/slab.h>
> > > +#endif
> > > +
> > > +/**
> > > + * nanddev_bbt_init() - Initialize the BBT (Bad Block Table)
> > > + * @nand: NAND device
> > > + *
> > > + * Initialize the in-memory BBT.
> > > + *
> > > + * Return: 0 in case of success, a negative error code otherwise.
> > > + */
> > > +int nanddev_bbt_init(struct nand_device *nand)
> > > +{
> > > +       unsigned int bits_per_block = fls(NAND_BBT_BLOCK_NUM_STATUS);
> > > +       unsigned int nblocks = nanddev_neraseblocks(nand);
> > > +       unsigned int nwords = DIV_ROUND_UP(nblocks * bits_per_block,
> > > +                                          BITS_PER_LONG);
> > > +
> > > +       nand->bbt.cache = kzalloc(nwords, GFP_KERNEL);
> > > +       if (!nand->bbt.cache)
> > > +               return -ENOMEM;
> > > +
> > > +       return 0;
> > > +}
> > > +EXPORT_SYMBOL_GPL(nanddev_bbt_init);  
> > 
> > Can't we skip __UBOOT__ and EXPORT_SYMBOL_GPL ?
> 
> Do you mean that you want me to delete all the #ifndef __UBOOT__/#endif
> sections?
> 
> They are present only to ease the patch backporting process from
> Linux. It was very useful during the development, I don't have a
> strong opinion on whether we should keep them or not, yet. 

The general rule here is we do whatever makes life easiest on the people
that are doing the periodic re-syncs.  Thanks!

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20180627/06c706c8/attachment.sig>

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [U-Boot] [RFC PATCH 10/20] spi: Extend the core to ease integration of SPI memory controllers
  2018-06-06 15:30 ` [U-Boot] [RFC PATCH 10/20] spi: Extend the core to ease integration of SPI memory controllers Miquel Raynal
@ 2018-07-06 11:32   ` Jagan Teki
  2018-07-11 13:55     ` Miquel Raynal
  0 siblings, 1 reply; 65+ messages in thread
From: Jagan Teki @ 2018-07-06 11:32 UTC (permalink / raw)
  To: u-boot

On Wed, Jun 6, 2018 at 9:00 PM, Miquel Raynal <miquel.raynal@bootlin.com> wrote:
> From: Boris Brezillon <boris.brezillon@bootlin.com>
>
> 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).
>
> Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>
> Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> ---
>  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
>
> diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
> index 235a8c7d73..0ee371b2d9 100644
> --- a/drivers/spi/Kconfig
> +++ b/drivers/spi/Kconfig
> @@ -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
> diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
> index 4b6000fd9a..982529a0e6 100644
> --- a/drivers/spi/Makefile
> +++ b/drivers/spi/Makefile
> @@ -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
> diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c
> new file mode 100644
> index 0000000000..1aabe56819
> --- /dev/null
> +++ b/drivers/spi/spi-mem.c
> @@ -0,0 +1,500 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * Copyright (C) 2018 Exceet Electronics GmbH
> + * Copyright (C) 2018 Bootlin
> + *
> + * Author: Boris Brezillon <boris.brezillon@bootlin.com>
> + */
> +
> +#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__

I would like remove Linux stuff atleast on this file becuase it's
difficult for me to read or review the code and also driver/spi have
fully u-boot dm stuff. I know it's easy for Linux sync but for this we
can do manual sync what ever need. I'm on something what from Linux.

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [U-Boot] [RFC PATCH 17/20] cmd: mtd: add 'mtd' command
  2018-06-06 15:30 ` [U-Boot] [RFC PATCH 17/20] cmd: mtd: add 'mtd' command Miquel Raynal
  2018-06-06 19:45   ` Boris Brezillon
@ 2018-07-06 11:38   ` Jagan Teki
  2018-07-06 12:26     ` Miquel Raynal
  1 sibling, 1 reply; 65+ messages in thread
From: Jagan Teki @ 2018-07-06 11:38 UTC (permalink / raw)
  To: u-boot

On Wed, Jun 6, 2018 at 9:00 PM, Miquel Raynal <miquel.raynal@bootlin.com> wrote:
> 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.

So are you planning to integrate sf, nand command in future, adding
them dm conversion of many stuff. I would like to reommend to go with
spinand command. I have been through this and finally added spinor
command, which I will going to in soon. once all are converted to dm,
it would be easy and meaningfull to have common command.

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [U-Boot] [RFC PATCH 00/20] SPI-NAND support
  2018-06-06 15:30 [U-Boot] [RFC PATCH 00/20] SPI-NAND support Miquel Raynal
                   ` (21 preceding siblings ...)
  2018-06-12 14:14 ` Stefan Roese
@ 2018-07-06 11:43 ` Jagan Teki
  2018-07-06 12:06   ` Miquel Raynal
  22 siblings, 1 reply; 65+ messages in thread
From: Jagan Teki @ 2018-07-06 11:43 UTC (permalink / raw)
  To: u-boot

On Wed, Jun 6, 2018 at 9:00 PM, Miquel Raynal <miquel.raynal@bootlin.com> wrote:
> 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:
> - 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.
> - DT changes to make use of a SPI NAND on the Ocelot board.
>
> Any comments on the code, the organization and the respect of U-Boot
> driver model will be welcome.
>
> Thanks,
> Miquèl
>
>
> Boris Brezillon (6):
>   mtd: Fallback to ->_read/write_oob() when ->_read/write() is missing
>   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
>
> Frieder Schrempf (1):
>   mtd: spinand: Add initial support for Winbond W25M02GV
>
> Miquel Raynal (10):
>   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
>   mips: dts: ocelot: describe SPI CS pins
>   mips: dts: ocelot: add the SPI NAND node
>
> Peter Pan (2):
>   mtd: nand: Add core infrastructure to support SPI NANDs
>   mtd: spinand: Add initial support for Micron MT29F2G01ABAGD

I have reviewed and commented most of the stuff that are in my
control, except few spi-nand code, which I would like to give a try to
other people in the list. Hope to seen the fine-tuning patches on next
version.

Jagan.

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [U-Boot] [RFC PATCH 00/20] SPI-NAND support
  2018-07-06 11:43 ` Jagan Teki
@ 2018-07-06 12:06   ` Miquel Raynal
  2018-07-06 12:15     ` Jagan Teki
  0 siblings, 1 reply; 65+ messages in thread
From: Miquel Raynal @ 2018-07-06 12:06 UTC (permalink / raw)
  To: u-boot

Hi Jagan,

Jagan Teki <jagan@amarulasolutions.com> wrote on Fri, 6 Jul 2018
17:13:21 +0530:

> On Wed, Jun 6, 2018 at 9:00 PM, Miquel Raynal <miquel.raynal@bootlin.com> wrote:
> > 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:
> > - 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.
> > - DT changes to make use of a SPI NAND on the Ocelot board.
> >
> > Any comments on the code, the organization and the respect of U-Boot
> > driver model will be welcome.
> >
> > Thanks,
> > Miquèl
> >
> >
> > Boris Brezillon (6):
> >   mtd: Fallback to ->_read/write_oob() when ->_read/write() is missing
> >   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
> >
> > Frieder Schrempf (1):
> >   mtd: spinand: Add initial support for Winbond W25M02GV
> >
> > Miquel Raynal (10):
> >   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
> >   mips: dts: ocelot: describe SPI CS pins
> >   mips: dts: ocelot: add the SPI NAND node
> >
> > Peter Pan (2):
> >   mtd: nand: Add core infrastructure to support SPI NANDs
> >   mtd: spinand: Add initial support for Micron MT29F2G01ABAGD  
> 
> I have reviewed and commented most of the stuff that are in my
> control, except few spi-nand code, which I would like to give a try to
> other people in the list. Hope to seen the fine-tuning patches on next
> version.

Thanks for taking the time to review all this; I'm on it.

About spi-nand, reviews from other contributors are welcome, but it's
mostly a copy from Linux framework that I just applied to nand/next.
There have been 9 versions of it before that so I think it's pretty
well reviewed.

Thanks,
Miquèl

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [U-Boot] [RFC PATCH 00/20] SPI-NAND support
  2018-07-06 12:06   ` Miquel Raynal
@ 2018-07-06 12:15     ` Jagan Teki
  2018-07-06 17:48       ` Tom Rini
  0 siblings, 1 reply; 65+ messages in thread
From: Jagan Teki @ 2018-07-06 12:15 UTC (permalink / raw)
  To: u-boot

On Fri, Jul 6, 2018 at 5:36 PM, Miquel Raynal <miquel.raynal@bootlin.com> wrote:
> Hi Jagan,
>
> Jagan Teki <jagan@amarulasolutions.com> wrote on Fri, 6 Jul 2018
> 17:13:21 +0530:
>
>> On Wed, Jun 6, 2018 at 9:00 PM, Miquel Raynal <miquel.raynal@bootlin.com> wrote:
>> > 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:
>> > - 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.
>> > - DT changes to make use of a SPI NAND on the Ocelot board.
>> >
>> > Any comments on the code, the organization and the respect of U-Boot
>> > driver model will be welcome.
>> >
>> > Thanks,
>> > Miquèl
>> >
>> >
>> > Boris Brezillon (6):
>> >   mtd: Fallback to ->_read/write_oob() when ->_read/write() is missing
>> >   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
>> >
>> > Frieder Schrempf (1):
>> >   mtd: spinand: Add initial support for Winbond W25M02GV
>> >
>> > Miquel Raynal (10):
>> >   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
>> >   mips: dts: ocelot: describe SPI CS pins
>> >   mips: dts: ocelot: add the SPI NAND node
>> >
>> > Peter Pan (2):
>> >   mtd: nand: Add core infrastructure to support SPI NANDs
>> >   mtd: spinand: Add initial support for Micron MT29F2G01ABAGD
>>
>> I have reviewed and commented most of the stuff that are in my
>> control, except few spi-nand code, which I would like to give a try to
>> other people in the list. Hope to seen the fine-tuning patches on next
>> version.
>
> Thanks for taking the time to review all this; I'm on it.
>
> About spi-nand, reviews from other contributors are welcome, but it's
> mostly a copy from Linux framework that I just applied to nand/next.
> There have been 9 versions of it before that so I think it's pretty
> well reviewed.

OK, that's fine then.

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [U-Boot] [RFC PATCH 17/20] cmd: mtd: add 'mtd' command
  2018-07-06 11:38   ` Jagan Teki
@ 2018-07-06 12:26     ` Miquel Raynal
  2018-07-06 13:21       ` Stefan Roese
  0 siblings, 1 reply; 65+ messages in thread
From: Miquel Raynal @ 2018-07-06 12:26 UTC (permalink / raw)
  To: u-boot

Hi Jagan,

Jagan Teki <jagannadh.teki@gmail.com> wrote on Fri, 6 Jul 2018 17:08:57
+0530:

> On Wed, Jun 6, 2018 at 9:00 PM, Miquel Raynal <miquel.raynal@bootlin.com> wrote:
> > 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.  
> 
> So are you planning to integrate sf, nand command in future, adding
> them dm conversion of many stuff. I would like to reommend to go with
> spinand command. I have been through this and finally added spinor
> command, which I will going to in soon. once all are converted to dm,
> it would be easy and meaningfull to have common command.

I'm not sure we are in sync about this. The whole point of the previous
discussion was to decide whether or not we should make full use of
the MTD stack or not. I think it was pretty clear on the fact that
people prefer to be close to Linux's architecture on this regard.

MTD being an abstraction of the type of memory, I don't get the
point in creating yet another command each time a new type of
device is supported. The fact that all the drivers of these devices
register to the MTD layer makes it trivial to interact with. So why
should we wait?


Thanks,
Miquèl

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [U-Boot] [RFC PATCH 17/20] cmd: mtd: add 'mtd' command
  2018-07-06 12:26     ` Miquel Raynal
@ 2018-07-06 13:21       ` Stefan Roese
  2018-07-06 13:42         ` Miquel Raynal
  0 siblings, 1 reply; 65+ messages in thread
From: Stefan Roese @ 2018-07-06 13:21 UTC (permalink / raw)
  To: u-boot

Hi Miquel,

On 06.07.2018 14:26, Miquel Raynal wrote:
> Jagan Teki <jagannadh.teki@gmail.com> wrote on Fri, 6 Jul 2018 17:08:57
> +0530:
> 
>> On Wed, Jun 6, 2018 at 9:00 PM, Miquel Raynal <miquel.raynal@bootlin.com> wrote:
>>> 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.
>>
>> So are you planning to integrate sf, nand command in future, adding
>> them dm conversion of many stuff. I would like to reommend to go with
>> spinand command. I have been through this and finally added spinor
>> command, which I will going to in soon. once all are converted to dm,
>> it would be easy and meaningfull to have common command.
> 
> I'm not sure we are in sync about this. The whole point of the previous
> discussion was to decide whether or not we should make full use of
> the MTD stack or not. I think it was pretty clear on the fact that
> people prefer to be close to Linux's architecture on this regard.
> 
> MTD being an abstraction of the type of memory, I don't get the
> point in creating yet another command each time a new type of
> device is supported. The fact that all the drivers of these devices
> register to the MTD layer makes it trivial to interact with. So why
> should we wait?

Yes, please don't add new commands for each subsystem / device-type.
I like the idea of adding one new command-set (your mtd command) and
extending this one to all other device-types over the time.

BTW: I'm testing your SPI NAND patches right now (still struggling
with some Gigadevice SPI NAND) and found that the "mtd" command is
not really in-line with the usual U-Boot commands. Here some
comments:

- Use hex values per default (addresses, sizes and soffset)
- "mtd read" just prints the read values. It makes more sense
   to read into memory instead (similar to the "mtd write")

I have some patches to address these issues in the queue (still
need some massaging), which you can fold into your patchset, once
we agree on this.

Thanks,
Stefan

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [U-Boot] [RFC PATCH 17/20] cmd: mtd: add 'mtd' command
  2018-07-06 13:21       ` Stefan Roese
@ 2018-07-06 13:42         ` Miquel Raynal
  2018-07-06 13:51           ` Stefan Roese
  0 siblings, 1 reply; 65+ messages in thread
From: Miquel Raynal @ 2018-07-06 13:42 UTC (permalink / raw)
  To: u-boot

Hi Stefan,

Stefan Roese <sr@denx.de> wrote on Fri, 6 Jul 2018 15:21:20 +0200:

> Hi Miquel,
> 
> On 06.07.2018 14:26, Miquel Raynal wrote:
> > Jagan Teki <jagannadh.teki@gmail.com> wrote on Fri, 6 Jul 2018 17:08:57
> > +0530:  
> > >> On Wed, Jun 6, 2018 at 9:00 PM, Miquel Raynal <miquel.raynal@bootlin.com> wrote:
> >>> 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.  
> >>
> >> So are you planning to integrate sf, nand command in future, adding
> >> them dm conversion of many stuff. I would like to reommend to go with
> >> spinand command. I have been through this and finally added spinor
> >> command, which I will going to in soon. once all are converted to dm,
> >> it would be easy and meaningfull to have common command.
> > > I'm not sure we are in sync about this. The whole point of the previous  
> > discussion was to decide whether or not we should make full use of
> > the MTD stack or not. I think it was pretty clear on the fact that
> > people prefer to be close to Linux's architecture on this regard.  
> > > MTD being an abstraction of the type of memory, I don't get the  
> > point in creating yet another command each time a new type of
> > device is supported. The fact that all the drivers of these devices
> > register to the MTD layer makes it trivial to interact with. So why
> > should we wait?  
> 
> Yes, please don't add new commands for each subsystem / device-type.
> I like the idea of adding one new command-set (your mtd command) and
> extending this one to all other device-types over the time.
> 
> BTW: I'm testing your SPI NAND patches right now (still struggling
> with some Gigadevice SPI NAND) and found that the "mtd" command is
> not really in-line with the usual U-Boot commands. Here some
> comments:
> 
> - Use hex values per default (addresses, sizes and soffset)
> - "mtd read" just prints the read values. It makes more sense
>    to read into memory instead (similar to the "mtd write")

I absolutely agree with this! I sent this series to show people what I
planned to contribute but this mtd command is still a WIP and there are
plenty of things to address.

> 
> I have some patches to address these issues in the queue (still
> need some massaging), which you can fold into your patchset, once
> we agree on this.

I am currently working on a new iteration of this series in which the
mtd.c file will change quite a bit. I plan to send a new version early
next week. I suppose this one will be much more stable to base your
fixes/enhancements on.

Thanks,
Miquèl

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [U-Boot] [RFC PATCH 17/20] cmd: mtd: add 'mtd' command
  2018-07-06 13:42         ` Miquel Raynal
@ 2018-07-06 13:51           ` Stefan Roese
  0 siblings, 0 replies; 65+ messages in thread
From: Stefan Roese @ 2018-07-06 13:51 UTC (permalink / raw)
  To: u-boot

Hi Miquel,

On 06.07.2018 15:42, Miquel Raynal wrote:
> Hi Stefan,
> 
> Stefan Roese <sr@denx.de> wrote on Fri, 6 Jul 2018 15:21:20 +0200:
> 
>> Hi Miquel,
>>
>> On 06.07.2018 14:26, Miquel Raynal wrote:
>>> Jagan Teki <jagannadh.teki@gmail.com> wrote on Fri, 6 Jul 2018 17:08:57
>>> +0530:
>>>>> On Wed, Jun 6, 2018 at 9:00 PM, Miquel Raynal <miquel.raynal@bootlin.com> wrote:
>>>>> 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.
>>>>
>>>> So are you planning to integrate sf, nand command in future, adding
>>>> them dm conversion of many stuff. I would like to reommend to go with
>>>> spinand command. I have been through this and finally added spinor
>>>> command, which I will going to in soon. once all are converted to dm,
>>>> it would be easy and meaningfull to have common command.
>>>> I'm not sure we are in sync about this. The whole point of the previous
>>> discussion was to decide whether or not we should make full use of
>>> the MTD stack or not. I think it was pretty clear on the fact that
>>> people prefer to be close to Linux's architecture on this regard.
>>>> MTD being an abstraction of the type of memory, I don't get the
>>> point in creating yet another command each time a new type of
>>> device is supported. The fact that all the drivers of these devices
>>> register to the MTD layer makes it trivial to interact with. So why
>>> should we wait?
>>
>> Yes, please don't add new commands for each subsystem / device-type.
>> I like the idea of adding one new command-set (your mtd command) and
>> extending this one to all other device-types over the time.
>>
>> BTW: I'm testing your SPI NAND patches right now (still struggling
>> with some Gigadevice SPI NAND) and found that the "mtd" command is
>> not really in-line with the usual U-Boot commands. Here some
>> comments:
>>
>> - Use hex values per default (addresses, sizes and soffset)
>> - "mtd read" just prints the read values. It makes more sense
>>     to read into memory instead (similar to the "mtd write")
> 
> I absolutely agree with this! I sent this series to show people what I
> planned to contribute but this mtd command is still a WIP and there are
> plenty of things to address.
> 
>>
>> I have some patches to address these issues in the queue (still
>> need some massaging), which you can fold into your patchset, once
>> we agree on this.
> 
> I am currently working on a new iteration of this series in which the
> mtd.c file will change quite a bit. I plan to send a new version early
> next week. I suppose this one will be much more stable to base your
> fixes/enhancements on.

That sound really great. Looking forward to seeing the new version
next week. :)

Thanks,
Stefan

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [U-Boot] [RFC PATCH 00/20] SPI-NAND support
  2018-07-06 12:15     ` Jagan Teki
@ 2018-07-06 17:48       ` Tom Rini
  0 siblings, 0 replies; 65+ messages in thread
From: Tom Rini @ 2018-07-06 17:48 UTC (permalink / raw)
  To: u-boot

On Fri, Jul 06, 2018 at 05:45:02PM +0530, Jagan Teki wrote:
> On Fri, Jul 6, 2018 at 5:36 PM, Miquel Raynal <miquel.raynal@bootlin.com> wrote:
> > Hi Jagan,
> >
> > Jagan Teki <jagan@amarulasolutions.com> wrote on Fri, 6 Jul 2018
> > 17:13:21 +0530:
> >
> >> On Wed, Jun 6, 2018 at 9:00 PM, Miquel Raynal <miquel.raynal@bootlin.com> wrote:
> >> > 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:
> >> > - 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.
> >> > - DT changes to make use of a SPI NAND on the Ocelot board.
> >> >
> >> > Any comments on the code, the organization and the respect of U-Boot
> >> > driver model will be welcome.
> >> >
> >> > Thanks,
> >> > Miquèl
> >> >
> >> >
> >> > Boris Brezillon (6):
> >> >   mtd: Fallback to ->_read/write_oob() when ->_read/write() is missing
> >> >   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
> >> >
> >> > Frieder Schrempf (1):
> >> >   mtd: spinand: Add initial support for Winbond W25M02GV
> >> >
> >> > Miquel Raynal (10):
> >> >   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
> >> >   mips: dts: ocelot: describe SPI CS pins
> >> >   mips: dts: ocelot: add the SPI NAND node
> >> >
> >> > Peter Pan (2):
> >> >   mtd: nand: Add core infrastructure to support SPI NANDs
> >> >   mtd: spinand: Add initial support for Micron MT29F2G01ABAGD
> >>
> >> I have reviewed and commented most of the stuff that are in my
> >> control, except few spi-nand code, which I would like to give a try to
> >> other people in the list. Hope to seen the fine-tuning patches on next
> >> version.
> >
> > Thanks for taking the time to review all this; I'm on it.
> >
> > About spi-nand, reviews from other contributors are welcome, but it's
> > mostly a copy from Linux framework that I just applied to nand/next.
> > There have been 9 versions of it before that so I think it's pretty
> > well reviewed.
> 
> OK, that's fine then.

If everyone is agreeable I would like to see this in the v2018.09
release.  Thanks!

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20180706/8daf333b/attachment.sig>

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [U-Boot] [RFC PATCH 17/20] cmd: mtd: add 'mtd' command
  2018-06-06 19:45   ` Boris Brezillon
@ 2018-07-11 13:51     ` Miquel Raynal
  2018-07-11 14:01       ` Boris Brezillon
  0 siblings, 1 reply; 65+ messages in thread
From: Miquel Raynal @ 2018-07-11 13:51 UTC (permalink / raw)
  To: u-boot

Hi Boris,

Boris Brezillon <boris.brezillon@bootlin.com> wrote on Wed, 6 Jun 2018
21:45:24 +0200:

> Hi Miquel,
> 
> On Wed,  6 Jun 2018 17:30:37 +0200
> Miquel Raynal <miquel.raynal@bootlin.com> wrote:
> 
> > 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.  
> 
> Just a few comments below, but overall, I'm really happy with this new
> set of commands and the fact that we'll soon be able to replace custom
> MTD accessors (nand, onenand, sf, cp.b+erase, ...) by these ones.
> 
> > 
> > Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> > ---
> >  cmd/Kconfig          |   5 +
> >  cmd/Makefile         |   1 +
> >  cmd/mtd.c            | 280 +++++++++++++++++++++++++++++++++++++++++++++++++++
> >  drivers/mtd/Makefile |   2 +-
> >  4 files changed, 287 insertions(+), 1 deletion(-)
> >  create mode 100644 cmd/mtd.c
> > 
> > diff --git a/cmd/Kconfig b/cmd/Kconfig
> > index 136836d146..6e9b629e1c 100644
> > --- a/cmd/Kconfig
> > +++ b/cmd/Kconfig
> > @@ -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
> > diff --git a/cmd/Makefile b/cmd/Makefile
> > index 9a358e4801..e42db12e1d 100644
> > --- a/cmd/Makefile
> > +++ b/cmd/Makefile
> > @@ -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
> > diff --git a/cmd/mtd.c b/cmd/mtd.c
> > new file mode 100644
> > index 0000000000..fe48378bd0
> > --- /dev/null
> > +++ b/cmd/mtd.c
> > @@ -0,0 +1,280 @@
> > +// SPDX-License-Identifier:  GPL-2.0+
> > +/*
> > + * mtd.c
> > + *
> > + * Generic command to handle basic operations on any memory device.
> > + *
> > + * Copyright: Bootlin, 2018
> > + * Author: Miquèl Raynal <miquel.raynal@bootlin.com>
> > + */
> > +
> > +#include <common.h>
> > +#include <linux/mtd/mtd.h>
> > +#include <command.h>
> > +#include <console.h>
> > +#include <malloc.h>
> > +#include <mtd.h>
> > +#include <mapmem.h>
> > +#include <dm/device.h>
> > +#include <dm/uclass-internal.h>
> > +
> > +static void mtd_dump_buf(u8 *buf, uint len)
> > +{
> > +	int i, j;
> > +
> > +	for (i = 0; i < len; ) {
> > +		printf("0x%08x:\t", i);
> > +		for (j = 0; j < 8; j++)
> > +			printf("%02x ", buf[i + j]);
> > +		printf(" ");
> > +		i += 8;
> > +		for (j = 0; j < 8; j++)
> > +			printf("%02x ", buf[i + j]);
> > +		printf("\n");
> > +		i += 8;
> > +	}
> > +}
> > +
> > +static void mtd_show_device(struct mtd_info *mtd)
> > +{
> > +	printf("* %s", mtd->name);
> > +	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_list(void)
> > +{
> > +	struct mtd_info *mtd;
> > +	struct udevice *dev;
> > +	int dm_idx = 0, idx = 0;
> > +
> > +	/* Ensure all devices compliants with U-Boot driver model are probed */
> > +	while (!uclass_find_device(UCLASS_MTD, dm_idx, &dev) && dev) {
> > +		mtd_probe(dev);
> > +		dm_idx++;
> > +	}
> > +
> > +	printf("MTD devices list (%d DM compliant):\n", dm_idx);  
> 
> Do we really want to say how many of them are exported by DM compliant
> drivers? I mean, the user doesn't care about that. If you want to force
> people to convert their drivers, we should probably complain at MTD
> device registration time when the mtd_info struct is not backed by an
> udevice.

It was more like a small debug value but I don't really care about it.

Parenthesis removed.

> 
> > +
> > +	mtd_for_each_device(mtd) {
> > +		mtd_show_device(mtd);
> > +		idx++;
> > +	}
> > +
> > +	if (!idx)
> > +		printf("No MTD device found\n");
> > +
> > +	return 0;
> > +}
> > +
> > +static int do_mtd_read_write(struct mtd_info *mtd, bool read, uint *waddr,
> > +			     bool raw, bool woob, u64 from, u64 len)  
> 
> s/do_mtd_read_write/do_mtd_io/ ?

+1 for the artistic name :) -> renamed

> And why not passing an mtd_oob_ops
> object directly? That would reduce the number of parameters you pass to
> this function.

Good point actually. While rewriting the function I figured out there
was no "reusable code" nor any "logicial split" with this do_mtd_io()
helper so I just moved the code from it into the main do_mtd(). If you
find it unclear please tell me where 

> 
> > +{
> > +	u32 buf_len = woob ? mtd->writesize + mtd->oobsize :
> > +			     ROUND(len, mtd->writesize);
> > +	u8 *buf = malloc(buf_len);  
> 
> It's probably worth a comment explaining why you allocate a bounce
> buffer here (i.e. to make sure len not aligned on a page size are padded
> with 0xff).
> 
> Maybe a simpler solution would be to simply refuse such unaligned
> accesses.

Agreed.

> 
> > +	struct mtd_oob_ops ops = {
> > +		.mode = raw ? MTD_OPS_RAW : 0,
> > +		.len = len,
> > +		.ooblen = woob ? mtd->oobsize : 0,
> > +		.datbuf = buf,
> > +		.oobbuf = woob ? &buf[mtd->writesize] : NULL,
> > +	};
> > +	int ret;
> > +
> > +	if (!buf)
> > +		return -ENOMEM;
> > +
> > +	memset(buf, 0xFF, buf_len);
> > +
> > +	if (read) {
> > +		ret = mtd_read_oob(mtd, from, &ops);
> > +	} else {
> > +		memcpy(buf, waddr, ops.len + ops.ooblen);
> > +		ret = mtd_write_oob(mtd, from, &ops);
> > +	}
> > +
> > +	if (ret) {
> > +		printf("Could not handle %lldB from 0x%08llx on %s, ret %d\n",
> > +		       len, from, mtd->name, ret);
> > +		return ret;
> > +	}
> > +
> > +	if (read) {
> > +		printf("Dump %lld data bytes from 0x%08llx:\n", len, from);
> > +		mtd_dump_buf(buf, len);  
> 
> Read and dump are 2 different things: one might want to read an MTD
> device and store the result in RAM without dumping it on the console.

Sure. Made a difference between read and dump.

> 
> > +
> > +		if (woob) {
> > +			printf("\nDump %d OOB bytes from 0x%08llx:\n",
> > +			       mtd->oobsize, from);
> > +			mtd_dump_buf(&buf[len], mtd->oobsize);
> > +		}  
> 
> Looks like you're never copying the data back to waddr.

Fixed as there is no more bounce buffer.

> 
> > +	}
> > +
> > +	kfree(buf);
> > +
> > +	return 0;
> > +}
> > +
> > +static int do_mtd_erase(struct mtd_info *mtd, bool scrub, u64 from, u64 len)
> > +{
> > +	struct erase_info erase_infos = {
> > +		.mtd = mtd,
> > +		.addr = from,
> > +		.len = len,
> > +		.scrub = scrub,
> > +	};
> > +
> > +	return mtd_erase(mtd, &erase_infos);
> > +}
> > +
> > +static int do_mtd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
> > +{
> > +	struct mtd_info *mtd;
> > +	struct udevice *dev;
> > +	const char *cmd;
> > +	char *part;
> > +	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;
> > +
> > +	part = argv[2];  
> 
> Why part. The MTD object can be a partition or the device itself. How
> about renaming it mtdname?

Ok.

> 
> > +	ret = uclass_find_device_by_name(UCLASS_MTD, part, &dev);
> > +	if (!ret && dev) {
> > +		mtd_probe(dev);
> > +		mtd = (struct mtd_info *)dev_get_uclass_priv(dev);
> > +		if (!mtd) {
> > +			printf("Could not retrieve MTD data\n");
> > +			return -ENODEV;
> > +		}
> > +	} else {
> > +		mtd = get_mtd_device_nm(part);
> > +		if (IS_ERR_OR_NULL(mtd)) {
> > +			printf("MTD device %s not found, ret %ld\n", part,
> > +			       PTR_ERR(mtd));
> > +			return 1;
> > +		}
> > +	}  
> 
> Hm, I'd do it the other way around: first call get_mtd_device_nm() and
> if you don't find the device trigger the probe of all UCLASS_MTD devs,
> and then search again with get_mtd_device_nm(). Note that
> mtd->dev->name and mtd->name are 2 different things, and they won't
> match most of the time.

Actually the logic above was broken in the sense that an 'mtd list'
was necessary prior to using any DM-compliant driven device.

Edited.

> 
> > +
> > +	argc -= 3;
> > +	argv += 3;
> > +
> > +	/* Do the parsing */
> > +	if (!strncmp(cmd, "read", 4) || !strncmp(cmd, "write", 5)) {
> > +		bool read, raw, woob;
> > +		uint *waddr = NULL;
> > +		u64 off, len;
> > +
> > +		read = !strncmp(cmd, "read", 4);
> > +		raw = strstr(cmd, ".raw");
> > +		woob = strstr(cmd, ".oob");
> > +
> > +		if (!read) {
> > +			if (argc < 1)
> > +				return CMD_RET_USAGE;
> > +
> > +			waddr = map_sysmem(simple_strtoul(argv[0], NULL, 10),
> > +					   0);
> > +			argc--;
> > +			argv++;
> > +		}
> > +
> > +		off = argc > 0 ? simple_strtoul(argv[0], NULL, 10) : 0;
> > +		len = argc > 1 ? simple_strtoul(argv[1], NULL, 10) :
> > +				 mtd->writesize + (woob ? mtd->oobsize : 0);
> > +
> > +		if ((u32)off % mtd->writesize) {
> > +			printf("Section not page-aligned (0x%x)\n",
> > +			       mtd->writesize);
> > +			return -EINVAL;
> > +		}
> > +
> > +		if (woob && (len != (mtd->writesize + mtd->oobsize))) {
> > +			printf("OOB operations are limited to single pages\n");
> > +			return -EINVAL;
> > +		}  
> 
> Is this a uboot limitation? I don't think you have such a limitation in
> Linux.

Kind of, only one single page write with OOB at a time is possible
says a comment on mtd_oob_ops in mtd.h in Linux. Reads are actually not
limited. But I really prefer to keep this limitation that simplifies _a
lot_ the logic and is not really useful to a u-boot user I suppose.

> 
> > +
> > +		if ((off + len) >= mtd->size) {  
> 
> That doesn't work when reading the last page of the MTD device with
> woob = true. See how Linux handle that here [1]. BTW, why don't you let
> mtdcore.c do these checks for you (that's also true for unaligned
> accesses)?

Because the relevant patch (and its fix :) ) has not been backported
yet.

And now I understand your voice in my ears "do it".

Okay.

> 
> > +			printf("Access location beyond the end of the chip\n");
> > +			return -EINVAL;
> > +		}
> > +
> > +		printf("%s (from %p) %lldB at 0x%08llx [%s %s]\n",
> > +		       read ? "read" : "write", read ? 0 : waddr, len, off,
> > +		       raw ? "raw" : "", woob ? "oob" : "");
> > +
> > +		ret = do_mtd_read_write(mtd, read, waddr, raw, woob, off, len);
> > +
> > +		if (!read)
> > +			unmap_sysmem(waddr);
> > +
> > +	} else if (!strcmp(cmd, "erase") || !strcmp(cmd, "scrub")) {
> > +		bool scrub = !strcmp(cmd, "scrub");
> > +		bool full_erase = !strncmp(&cmd[5], ".chip", 4);
> > +		u64 off, len;
> > +
> > +		off = argc > 0 ? simple_strtoul(argv[0], NULL, 10) : 0;
> > +		len = argc > 1 ? simple_strtoul(argv[1], NULL, 10) :
> > +				 mtd->erasesize;
> > +		if (full_erase) {
> > +			off = 0;
> > +			len = mtd->size;
> > +		}
> > +
> > +		if ((u32)off % mtd->erasesize) {
> > +			printf("Section not erase-block-aligned (0x%x)\n",
> > +			       mtd->erasesize);
> > +			return -EINVAL;
> > +		}
> > +
> > +		if ((u32)len % mtd->erasesize) {
> > +			printf("Size not aligned with an erase block (%dB)\n",
> > +			       mtd->erasesize);
> > +			return -EINVAL;
> > +		}
> > +
> > +		if ((off + len) >= mtd->size) {
> > +			printf("Cannot read beyond end of chip\n");
> > +			return -EINVAL;
> > +		}
> > +
> > +		ret = do_mtd_erase(mtd, scrub, off, len);
> > +	} 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> [<off> [<size>]]\n"  
> 
> I guess this one should be
> 
> 	"mtd read[.raw][.oob] <name> <addr> [<off> [<size>]]\n"
> 
> and then, you should have
> 
> 	"mtd dump[.raw][.oob] <name> [<off> [<size>]]\n"
> 
> > +	"mtd write[.raw][.oob] <name> <addr> [<off> [<size>]]\n"
> > +	"mtd erase[.chip] <name> [<off> [<size>]]\n"
> > +	"mtd scrub[.chip] <name> [<off> [<size>]]\n"  
> 
> Hm, maybe it's time to simplify that. mtd.scrub is just an option of mtd
> erase, so maybe we should just have:
> 
> 	mtd erase[.force] or erase[.dontskipbad]
> 
> Also, [.chip] can be extracted from the number of parameters. If you
> just have <name> passed, that means the callers wants to erase the
> whole chip.

I prefer .dontskipbad for the sake of clarity. Updated accordingly.


Also updated the code following Stefan comments: all the numbers
(addresses, lengths) are hexadecimal + creation of a dump command.

Thanks for the review!
Miquèl

> 
> Regards,
> 
> Boris
> 
> > +#endif
> > +	"";
> > +
> > +U_BOOT_CMD(mtd, 10, 1, do_mtd, "MTD utils", mtd_help_text);  
> 
> [1]https://elixir.bootlin.com/linux/latest/source/drivers/mtd/mtdcore.c#L1117



-- 
Miquel Raynal, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [U-Boot] [RFC PATCH 10/20] spi: Extend the core to ease integration of SPI memory controllers
  2018-07-06 11:32   ` Jagan Teki
@ 2018-07-11 13:55     ` Miquel Raynal
  2018-07-11 14:37       ` Jagan Teki
  0 siblings, 1 reply; 65+ messages in thread
From: Miquel Raynal @ 2018-07-11 13:55 UTC (permalink / raw)
  To: u-boot

Hi Jagan,

Jagan Teki <jagannadh.teki@gmail.com> wrote on Fri, 6 Jul 2018 17:02:22
+0530:

> On Wed, Jun 6, 2018 at 9:00 PM, Miquel Raynal <miquel.raynal@bootlin.com> wrote:
> > From: Boris Brezillon <boris.brezillon@bootlin.com>
> >
> > 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).
> >
> > Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>
> > Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> > ---
> >  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
> >
> > diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
> > index 235a8c7d73..0ee371b2d9 100644
> > --- a/drivers/spi/Kconfig
> > +++ b/drivers/spi/Kconfig
> > @@ -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
> > diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
> > index 4b6000fd9a..982529a0e6 100644
> > --- a/drivers/spi/Makefile
> > +++ b/drivers/spi/Makefile
> > @@ -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
> > diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c
> > new file mode 100644
> > index 0000000000..1aabe56819
> > --- /dev/null
> > +++ b/drivers/spi/spi-mem.c
> > @@ -0,0 +1,500 @@
> > +// SPDX-License-Identifier: GPL-2.0+
> > +/*
> > + * Copyright (C) 2018 Exceet Electronics GmbH
> > + * Copyright (C) 2018 Bootlin
> > + *
> > + * Author: Boris Brezillon <boris.brezillon@bootlin.com>
> > + */
> > +
> > +#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__  
> 
> I would like remove Linux stuff atleast on this file becuase it's
> difficult for me to read or review the code and also driver/spi have
> fully u-boot dm stuff. I know it's easy for Linux sync but for this we
> can do manual sync what ever need. I'm on something what from Linux.

I'm not sure this is a wise idea.

And I don't understand how "driver/spi have fully u-boot dm stuff" is
related in any manner to this request.

But okay, if you commit to backport the changes/fixes on spi-mem from
Linux yourself, let's remove them.

Thanks,
Miquèl

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [U-Boot] [RFC PATCH 17/20] cmd: mtd: add 'mtd' command
  2018-07-11 13:51     ` Miquel Raynal
@ 2018-07-11 14:01       ` Boris Brezillon
  2018-07-11 14:17         ` Miquel Raynal
  0 siblings, 1 reply; 65+ messages in thread
From: Boris Brezillon @ 2018-07-11 14:01 UTC (permalink / raw)
  To: u-boot

On Wed, 11 Jul 2018 15:51:39 +0200
Miquel Raynal <miquel.raynal@bootlin.com> wrote:

> > > +
> > > +	argc -= 3;
> > > +	argv += 3;
> > > +
> > > +	/* Do the parsing */
> > > +	if (!strncmp(cmd, "read", 4) || !strncmp(cmd, "write", 5)) {
> > > +		bool read, raw, woob;
> > > +		uint *waddr = NULL;
> > > +		u64 off, len;
> > > +
> > > +		read = !strncmp(cmd, "read", 4);
> > > +		raw = strstr(cmd, ".raw");
> > > +		woob = strstr(cmd, ".oob");
> > > +
> > > +		if (!read) {
> > > +			if (argc < 1)
> > > +				return CMD_RET_USAGE;
> > > +
> > > +			waddr = map_sysmem(simple_strtoul(argv[0], NULL, 10),
> > > +					   0);
> > > +			argc--;
> > > +			argv++;
> > > +		}
> > > +
> > > +		off = argc > 0 ? simple_strtoul(argv[0], NULL, 10) : 0;
> > > +		len = argc > 1 ? simple_strtoul(argv[1], NULL, 10) :
> > > +				 mtd->writesize + (woob ? mtd->oobsize : 0);
> > > +
> > > +		if ((u32)off % mtd->writesize) {
> > > +			printf("Section not page-aligned (0x%x)\n",
> > > +			       mtd->writesize);
> > > +			return -EINVAL;
> > > +		}
> > > +
> > > +		if (woob && (len != (mtd->writesize + mtd->oobsize))) {
> > > +			printf("OOB operations are limited to single pages\n");
> > > +			return -EINVAL;
> > > +		}    
> > 
> > Is this a uboot limitation? I don't think you have such a limitation in
> > Linux.  
> 
> Kind of, only one single page write with OOB at a time is possible
> says a comment on mtd_oob_ops in mtd.h in Linux. Reads are actually not
> limited. But I really prefer to keep this limitation that simplifies _a
> lot_ the logic and is not really useful to a u-boot user I suppose.

It is useful when you write things in raw mode and the image you write
contains OOB (which in turn contains pre-generated ECC bytes). I know we
do such things on sunxi when writing the SPL.

> 
> >   
> > > +
> > > +		if ((off + len) >= mtd->size) {    
> > 
> > That doesn't work when reading the last page of the MTD device with
> > woob = true. See how Linux handle that here [1]. BTW, why don't you let
> > mtdcore.c do these checks for you (that's also true for unaligned
> > accesses)?  
> 
> Because the relevant patch (and its fix :) ) has not been backported
> yet.
> 
> And now I understand your voice in my ears "do it".

Hehe. So I guess I'll see this patch in your v2 :-).

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [U-Boot] [RFC PATCH 17/20] cmd: mtd: add 'mtd' command
  2018-07-11 14:01       ` Boris Brezillon
@ 2018-07-11 14:17         ` Miquel Raynal
  0 siblings, 0 replies; 65+ messages in thread
From: Miquel Raynal @ 2018-07-11 14:17 UTC (permalink / raw)
  To: u-boot

Hi Boris,

Boris Brezillon <boris.brezillon@bootlin.com> wrote on Wed, 11 Jul 2018
16:01:09 +0200:

> On Wed, 11 Jul 2018 15:51:39 +0200
> Miquel Raynal <miquel.raynal@bootlin.com> wrote:
> 
> > > > +
> > > > +	argc -= 3;
> > > > +	argv += 3;
> > > > +
> > > > +	/* Do the parsing */
> > > > +	if (!strncmp(cmd, "read", 4) || !strncmp(cmd, "write", 5)) {
> > > > +		bool read, raw, woob;
> > > > +		uint *waddr = NULL;
> > > > +		u64 off, len;
> > > > +
> > > > +		read = !strncmp(cmd, "read", 4);
> > > > +		raw = strstr(cmd, ".raw");
> > > > +		woob = strstr(cmd, ".oob");
> > > > +
> > > > +		if (!read) {
> > > > +			if (argc < 1)
> > > > +				return CMD_RET_USAGE;
> > > > +
> > > > +			waddr = map_sysmem(simple_strtoul(argv[0], NULL, 10),
> > > > +					   0);
> > > > +			argc--;
> > > > +			argv++;
> > > > +		}
> > > > +
> > > > +		off = argc > 0 ? simple_strtoul(argv[0], NULL, 10) : 0;
> > > > +		len = argc > 1 ? simple_strtoul(argv[1], NULL, 10) :
> > > > +				 mtd->writesize + (woob ? mtd->oobsize : 0);
> > > > +
> > > > +		if ((u32)off % mtd->writesize) {
> > > > +			printf("Section not page-aligned (0x%x)\n",
> > > > +			       mtd->writesize);
> > > > +			return -EINVAL;
> > > > +		}
> > > > +
> > > > +		if (woob && (len != (mtd->writesize + mtd->oobsize))) {
> > > > +			printf("OOB operations are limited to single pages\n");
> > > > +			return -EINVAL;
> > > > +		}      
> > > 
> > > Is this a uboot limitation? I don't think you have such a limitation in
> > > Linux.    
> > 
> > Kind of, only one single page write with OOB at a time is possible
> > says a comment on mtd_oob_ops in mtd.h in Linux. Reads are actually not
> > limited. But I really prefer to keep this limitation that simplifies _a
> > lot_ the logic and is not really useful to a u-boot user I suppose.  
> 
> It is useful when you write things in raw mode and the image you write
> contains OOB (which in turn contains pre-generated ECC bytes). I know we
> do such things on sunxi when writing the SPL.

:'(

Ok.

> 
> >   
> > >     
> > > > +
> > > > +		if ((off + len) >= mtd->size) {      
> > > 
> > > That doesn't work when reading the last page of the MTD device with
> > > woob = true. See how Linux handle that here [1]. BTW, why don't you let
> > > mtdcore.c do these checks for you (that's also true for unaligned
> > > accesses)?    
> > 
> > Because the relevant patch (and its fix :) ) has not been backported
> > yet.
> > 
> > And now I understand your voice in my ears "do it".  
> 
> Hehe. So I guess I'll see this patch in your v2 :-).

Indeed ;)

Cheers,
Miquèl

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [U-Boot] [RFC PATCH 10/20] spi: Extend the core to ease integration of SPI memory controllers
  2018-07-11 13:55     ` Miquel Raynal
@ 2018-07-11 14:37       ` Jagan Teki
  2018-07-11 15:10         ` Miquel Raynal
  0 siblings, 1 reply; 65+ messages in thread
From: Jagan Teki @ 2018-07-11 14:37 UTC (permalink / raw)
  To: u-boot

On Wed, Jul 11, 2018 at 7:25 PM, Miquel Raynal
<miquel.raynal@bootlin.com> wrote:
> Hi Jagan,
>
> Jagan Teki <jagannadh.teki@gmail.com> wrote on Fri, 6 Jul 2018 17:02:22
> +0530:
>
>> On Wed, Jun 6, 2018 at 9:00 PM, Miquel Raynal <miquel.raynal@bootlin.com> wrote:
>> > From: Boris Brezillon <boris.brezillon@bootlin.com>
>> >
>> > 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).
>> >
>> > Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>
>> > Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
>> > ---
>> >  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
>> >
>> > diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
>> > index 235a8c7d73..0ee371b2d9 100644
>> > --- a/drivers/spi/Kconfig
>> > +++ b/drivers/spi/Kconfig
>> > @@ -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
>> > diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
>> > index 4b6000fd9a..982529a0e6 100644
>> > --- a/drivers/spi/Makefile
>> > +++ b/drivers/spi/Makefile
>> > @@ -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
>> > diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c
>> > new file mode 100644
>> > index 0000000000..1aabe56819
>> > --- /dev/null
>> > +++ b/drivers/spi/spi-mem.c
>> > @@ -0,0 +1,500 @@
>> > +// SPDX-License-Identifier: GPL-2.0+
>> > +/*
>> > + * Copyright (C) 2018 Exceet Electronics GmbH
>> > + * Copyright (C) 2018 Bootlin
>> > + *
>> > + * Author: Boris Brezillon <boris.brezillon@bootlin.com>
>> > + */
>> > +
>> > +#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__
>>
>> I would like remove Linux stuff atleast on this file becuase it's
>> difficult for me to read or review the code and also driver/spi have
>> fully u-boot dm stuff. I know it's easy for Linux sync but for this we
>> can do manual sync what ever need. I'm on something what from Linux.
>
> I'm not sure this is a wise idea.
>
> And I don't understand how "driver/spi have fully u-boot dm stuff" is
> related in any manner to this request.

The code in driver/spi is more or less u-boot code it doesn't have
Linux sync. ie reason I want to maintain the similar integrity here,
but on the other-side spi-mem depend more on Linux like MTD. OK let's
move as-it-is like what you added, may be we can simulate if require
in future need.

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [U-Boot] [RFC PATCH 10/20] spi: Extend the core to ease integration of SPI memory controllers
  2018-07-11 14:37       ` Jagan Teki
@ 2018-07-11 15:10         ` Miquel Raynal
  0 siblings, 0 replies; 65+ messages in thread
From: Miquel Raynal @ 2018-07-11 15:10 UTC (permalink / raw)
  To: u-boot

Hi Jagan,

Jagan Teki <jagannadh.teki@gmail.com> wrote on Wed, 11 Jul 2018
20:07:19 +0530:

> On Wed, Jul 11, 2018 at 7:25 PM, Miquel Raynal
> <miquel.raynal@bootlin.com> wrote:
> > Hi Jagan,
> >
> > Jagan Teki <jagannadh.teki@gmail.com> wrote on Fri, 6 Jul 2018 17:02:22
> > +0530:
> >  
> >> On Wed, Jun 6, 2018 at 9:00 PM, Miquel Raynal <miquel.raynal@bootlin.com> wrote:  
> >> > From: Boris Brezillon <boris.brezillon@bootlin.com>
> >> >
> >> > 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).
> >> >
> >> > Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>
> >> > Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> >> > ---
> >> >  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
> >> >
> >> > diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
> >> > index 235a8c7d73..0ee371b2d9 100644
> >> > --- a/drivers/spi/Kconfig
> >> > +++ b/drivers/spi/Kconfig
> >> > @@ -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
> >> > diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
> >> > index 4b6000fd9a..982529a0e6 100644
> >> > --- a/drivers/spi/Makefile
> >> > +++ b/drivers/spi/Makefile
> >> > @@ -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
> >> > diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c
> >> > new file mode 100644
> >> > index 0000000000..1aabe56819
> >> > --- /dev/null
> >> > +++ b/drivers/spi/spi-mem.c
> >> > @@ -0,0 +1,500 @@
> >> > +// SPDX-License-Identifier: GPL-2.0+
> >> > +/*
> >> > + * Copyright (C) 2018 Exceet Electronics GmbH
> >> > + * Copyright (C) 2018 Bootlin
> >> > + *
> >> > + * Author: Boris Brezillon <boris.brezillon@bootlin.com>
> >> > + */
> >> > +
> >> > +#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__  
> >>
> >> I would like remove Linux stuff atleast on this file becuase it's
> >> difficult for me to read or review the code and also driver/spi have
> >> fully u-boot dm stuff. I know it's easy for Linux sync but for this we
> >> can do manual sync what ever need. I'm on something what from Linux.  
> >
> > I'm not sure this is a wise idea.
> >
> > And I don't understand how "driver/spi have fully u-boot dm stuff" is
> > related in any manner to this request.  
> 
> The code in driver/spi is more or less u-boot code it doesn't have
> Linux sync. ie reason I want to maintain the similar integrity here,
> but on the other-side spi-mem depend more on Linux like MTD. OK let's
> move as-it-is like what you added, may be we can simulate if require
> in future need.

I understand better your POV, OK then, let met re-add these portions.

Thanks,
Miquèl

^ permalink raw reply	[flat|nested] 65+ messages in thread

end of thread, other threads:[~2018-07-11 15:10 UTC | newest]

Thread overview: 65+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-06-06 15:30 [U-Boot] [RFC PATCH 00/20] SPI-NAND support Miquel Raynal
2018-06-06 15:30 ` [U-Boot] [RFC PATCH 01/20] mtd: Fallback to ->_read/write_oob() when ->_read/write() is missing Miquel Raynal
2018-06-27 10:52   ` Jagan Teki
2018-06-06 15:30 ` [U-Boot] [RFC PATCH 02/20] mtd: add get/set of_node/flash_node helpers Miquel Raynal
2018-06-27 10:53   ` Jagan Teki
2018-06-06 15:30 ` [U-Boot] [RFC PATCH 03/20] mtd: fix build issue with includes Miquel Raynal
2018-06-27 10:53   ` Jagan Teki
2018-06-06 15:30 ` [U-Boot] [RFC PATCH 04/20] mtd: move definitions to enlarge their range Miquel Raynal
2018-06-06 15:30 ` [U-Boot] [RFC PATCH 05/20] mtd: move all flash categories inside MTD submenu Miquel Raynal
2018-06-27 10:56   ` Jagan Teki
2018-06-06 15:30 ` [U-Boot] [RFC PATCH 06/20] mtd: move NAND fiels into a raw/ subdirectory Miquel Raynal
2018-06-06 15:30 ` [U-Boot] [RFC PATCH 07/20] mtd: rename nand into rawnand in Kconfig prompt Miquel Raynal
2018-06-06 15:30 ` [U-Boot] [RFC PATCH 08/20] mtd: nand: Add core infrastructure to deal with NAND devices Miquel Raynal
2018-06-27 11:08   ` Jagan Teki
2018-06-27 12:48     ` Miquel Raynal
2018-06-27 21:35       ` Tom Rini
2018-06-06 15:30 ` [U-Boot] [RFC PATCH 09/20] mtd: nand: Pass mode information to nand_page_io_req Miquel Raynal
2018-06-06 15:30 ` [U-Boot] [RFC PATCH 10/20] spi: Extend the core to ease integration of SPI memory controllers Miquel Raynal
2018-07-06 11:32   ` Jagan Teki
2018-07-11 13:55     ` Miquel Raynal
2018-07-11 14:37       ` Jagan Teki
2018-07-11 15:10         ` Miquel Raynal
2018-06-06 15:30 ` [U-Boot] [RFC PATCH 11/20] mtd: nand: Add core infrastructure to support SPI NANDs Miquel Raynal
2018-06-06 15:30 ` [U-Boot] [RFC PATCH 12/20] mtd: spinand: Add initial support for Micron MT29F2G01ABAGD Miquel Raynal
2018-06-06 15:30 ` [U-Boot] [RFC PATCH 13/20] mtd: spinand: Add initial support for Winbond W25M02GV Miquel Raynal
2018-06-06 15:30 ` [U-Boot] [RFC PATCH 14/20] mtd: spinand: Add initial support for the MX35LF1GE4AB chip Miquel Raynal
2018-06-06 15:30 ` [U-Boot] [RFC PATCH 15/20] mtd: spinand: Add initial support for the MX35LF2GE4AB chip Miquel Raynal
2018-06-22 12:03   ` Boris Brezillon
2018-06-26  7:54     ` Miquel Raynal
2018-06-06 15:30 ` [U-Boot] [RFC PATCH 16/20] mtd: uclass: add probe function Miquel Raynal
2018-06-06 15:30 ` [U-Boot] [RFC PATCH 17/20] cmd: mtd: add 'mtd' command Miquel Raynal
2018-06-06 19:45   ` Boris Brezillon
2018-07-11 13:51     ` Miquel Raynal
2018-07-11 14:01       ` Boris Brezillon
2018-07-11 14:17         ` Miquel Raynal
2018-07-06 11:38   ` Jagan Teki
2018-07-06 12:26     ` Miquel Raynal
2018-07-06 13:21       ` Stefan Roese
2018-07-06 13:42         ` Miquel Raynal
2018-07-06 13:51           ` Stefan Roese
2018-06-06 15:30 ` [U-Boot] [RFC PATCH 18/20] dt-bindings: Add bindings for SPI NAND devices Miquel Raynal
2018-06-06 15:30 ` [U-Boot] [RFC PATCH 19/20] mips: dts: ocelot: describe SPI CS pins Miquel Raynal
2018-06-06 15:30 ` [U-Boot] [RFC PATCH 20/20] mips: dts: ocelot: add the SPI NAND node Miquel Raynal
2018-06-07  5:51 ` [U-Boot] [RFC PATCH 00/20] SPI-NAND support Jagan Teki
2018-06-07  8:41   ` Miquel Raynal
2018-06-18  8:07     ` Boris Brezillon
2018-06-25  8:29     ` Jagan Teki
2018-06-25  9:09       ` Boris Brezillon
2018-06-25 12:38         ` Richard Weinberger
2018-06-25 14:27         ` Jagan Teki
2018-06-25 14:28           ` Jagan Teki
2018-06-25 14:46             ` Boris Brezillon
2018-06-25 14:55               ` Tom Rini
2018-06-25 14:59                 ` Stefan Roese
2018-06-25 18:37                 ` Jagan Teki
2018-06-25 19:58                   ` Boris Brezillon
2018-06-25 20:01                     ` Tom Rini
2018-06-27 11:43                     ` Jagan Teki
2018-06-25 14:36           ` Richard Weinberger
2018-06-12 14:14 ` Stefan Roese
2018-06-18  8:13   ` Miquel Raynal
2018-07-06 11:43 ` Jagan Teki
2018-07-06 12:06   ` Miquel Raynal
2018-07-06 12:15     ` Jagan Teki
2018-07-06 17:48       ` Tom Rini

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.