All of lore.kernel.org
 help / color / mirror / Atom feed
* [U-Boot] [PATCH v6 00/27] SPI-NAND support
@ 2018-08-01  8:18 Miquel Raynal
  2018-08-01  8:18 ` [U-Boot] [PATCH v6 01/27] mtd: Fallback to ->_read/write_oob() when ->_read/write() is missing Miquel Raynal
                   ` (28 more replies)
  0 siblings, 29 replies; 41+ messages in thread
From: Miquel Raynal @ 2018-08-01  8:18 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:
- A few patches from Linux to resynchronize some areas of the MTD layer.
- Various fixes and re-organization of the MTD subsystem.
- The introduction of the SPI-mem interface.
- The addition of the generic SPI-NAND driver (and its bindings).
- Several SPI NAND chip drivers (Macronix, Micron, Winbond).
- A new 'mtd' command.
- Support for spi-nand devices in mtdparts.

To test your SPI-NAND device with U-Boot simply follow these lines:

> setenv mtdparts mtdparts=spi-nand0:1m(foo),-(bar)
> setenv mtdids spi-nand0=spi-nand0
> mtdparts             # show the spi-nand device partitions
> ubi part bar         # create a static UBI volume in the bar partition

Thanks,
Miquèl

Changes since v5:
-----------------
* Included Boris fixup about the build issues.
* Added Rb/Ab tags from Jagan on patchs 20/21.

Changes since v4:
-----------------
* Added Jagan's Acked-by tags to every patch related to the
  SPI-mem/SPI-NAND addition.
* Rebased on top of master.

Changes since v3:
-----------------
* Fixed the debug messages in spi-mem to print either Rx or Tx data.
* Fixed a Kconfig error that prevented to build mtdparts with plain
  defconfig.
* Fixed a compilation error due to the above error that prevented one
  file to be compiled.
* Adapted the mtd command to probe MTD partitions also.
* Declared mtd_probe_devices() in a header so mtdparts or UBI could
  use it too (to probe all devices and MTD partitions in a clean way).
* As I worked on mtdparts, I found annoying and completely useless the
  fact that we need to prefix the environment variable with
  "mtdparts=". Canceled this obligation.
* Added one patch to allow spi-nand devices to be recognized by mtdparts
  (this is purely useless but needed to be done in order to use this
  command).
* Removed useless definitions of MTD device types in UBI code.
* Wrote a generic mtdparts environment variable parser, used by the mtd
  command.
* Used the mtd_probe_devices() function from get_mtd_info() in
  cmd/mtdparts.c to be sure the desired partition really does not exist
  (otherwise it will be probed and then found).

Changes since v2:
-----------------
* Rebased on u-boot master branch.
* Removed extra-parenthesis in
  "mtd: Fallback to ->_read/write() when ->_read/write_oob() is missing"
* s/fiels/files/ in "mtd: move NAND fiels into a raw/ subdirectory"
* Do not describe generic SPI device properties in SPI NAND bindings.
* Changes in the mtd command:
  * Printing more information in 'mtd list' (device type, device
    characteristics)
  * Switch to do_div() instead of '(u32)value64b % value32b' which only
    worked because value32b was a power of 2.
  * Removed erase.chip option.
  * By default, erase/read/write happen on the full MTD device while a
    dump will only work on a single page.

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


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

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

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

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

Miquel Raynal (15):
  mtd: Fallback to ->_read/write() when ->_read/write_oob() is missing
  mtd: fix build issue with includes
  mtd: move definitions to enlarge their range
  mtd: move all flash categories inside MTD submenu
  mtd: move NAND files into a raw/ subdirectory
  mtd: rename nand into rawnand in Kconfig prompt
  mtd: spinand: Add initial support for the MX35LF2GE4AB chip
  mtd: declare MTD_PARTITIONS symbol in Kconfig
  cmd: ubi: delete useless and misleading definitions
  cmd: mtdparts: accept spi-nand devices
  cmd: mtdparts: add a generic 'mtdparts' parser
  cmd: mtdparts: remove useless 'mtdparts=' prefix
  mtd: uclass: add probe function
  cmd: mtd: add 'mtd' command
  cmd: mtdparts: try to probe the MTD devices as a fallback

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

 MAINTAINERS                                   |    6 +-
 Makefile                                      |    2 +-
 README                                        |    6 +-
 arch/arm/mach-uniphier/board_late_init.c      |    2 +-
 cmd/Kconfig                                   |    7 +
 cmd/Makefile                                  |    1 +
 cmd/mtd.c                                     |  392 ++++++++
 cmd/mtdparts.c                                |  113 ++-
 cmd/ubi.c                                     |    5 -
 common/spl/Kconfig                            |    2 +-
 common/spl/spl_spi.c                          |    2 +-
 doc/README.SPL                                |    4 +-
 doc/README.arm-relocation                     |    2 +-
 doc/README.nand                               |    6 +-
 doc/README.zynq                               |    2 +-
 doc/device-tree-bindings/mtd/spi-nand.txt     |    5 +
 drivers/Makefile                              |    2 +-
 drivers/mtd/Kconfig                           |    7 +-
 drivers/mtd/Makefile                          |    4 +-
 drivers/mtd/mtd-uclass.c                      |    9 +
 drivers/mtd/mtdcore.c                         |  106 ++-
 drivers/mtd/mtdcore.h                         |    6 -
 drivers/mtd/mtdpart.c                         |    6 +-
 drivers/mtd/nand/Kconfig                      |  299 +-----
 drivers/mtd/nand/Makefile                     |   78 +-
 drivers/mtd/nand/bbt.c                        |  132 +++
 drivers/mtd/nand/core.c                       |  243 +++++
 drivers/mtd/nand/raw/Kconfig                  |  297 ++++++
 drivers/mtd/nand/raw/Makefile                 |   77 ++
 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     |    2 +-
 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.h         |    0
 drivers/mtd/nand/{ => raw}/mxs_nand_dt.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         |    2 +-
 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        |    2 +-
 drivers/mtd/nand/{ => raw}/omap_elm.c         |    0
 drivers/mtd/nand/{ => raw}/omap_gpmc.c        |    0
 drivers/mtd/nand/{ => raw}/pxa3xx_nand.c      |    2 +-
 drivers/mtd/nand/{ => raw}/pxa3xx_nand.h      |    0
 drivers/mtd/nand/{ => raw}/sunxi_nand.c       |    0
 drivers/mtd/nand/{ => raw}/sunxi_nand_spl.c   |    0
 drivers/mtd/nand/{ => raw}/tegra_nand.c       |    0
 drivers/mtd/nand/{ => raw}/tegra_nand.h       |    0
 drivers/mtd/nand/{ => raw}/vf610_nfc.c        |    0
 drivers/mtd/nand/{ => raw}/zynq_nand.c        |    0
 drivers/mtd/nand/spi/Kconfig                  |    7 +
 drivers/mtd/nand/spi/Makefile                 |    4 +
 drivers/mtd/nand/spi/core.c                   | 1254 +++++++++++++++++++++++++
 drivers/mtd/nand/spi/macronix.c               |  146 +++
 drivers/mtd/nand/spi/micron.c                 |  135 +++
 drivers/mtd/nand/spi/winbond.c                |  143 +++
 drivers/mtd/onenand/onenand_base.c            |   60 --
 drivers/spi/Kconfig                           |    7 +
 drivers/spi/Makefile                          |    1 +
 drivers/spi/spi-mem.c                         |  500 ++++++++++
 include/configs/MPC8313ERDB.h                 |    2 +-
 include/jffs2/load_kernel.h                   |    7 +-
 include/linux/mtd/mtd.h                       |   34 +-
 include/linux/mtd/nand.h                      |  734 +++++++++++++++
 include/linux/mtd/partitions.h                |    3 +
 include/linux/mtd/spinand.h                   |  432 +++++++++
 include/spi-mem.h                             |  258 +++++
 include/spi.h                                 |   11 +
 96 files changed, 5064 insertions(+), 561 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 (99%)
 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.h (100%)
 rename drivers/mtd/nand/{ => raw}/mxs_nand_dt.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 (99%)
 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 (99%)
 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 (99%)
 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] 41+ messages in thread

* [U-Boot] [PATCH v6 01/27] mtd: Fallback to ->_read/write_oob() when ->_read/write() is missing
  2018-08-01  8:18 [U-Boot] [PATCH v6 00/27] SPI-NAND support Miquel Raynal
@ 2018-08-01  8:18 ` Miquel Raynal
  2018-08-01  8:18 ` [U-Boot] [PATCH v6 02/27] mtd: Uninline mtd_write_oob and move it to mtdcore.c Miquel Raynal
                   ` (27 subsequent siblings)
  28 siblings, 0 replies; 41+ messages in thread
From: Miquel Raynal @ 2018-08-01  8:18 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>
Reviewed-by: Jagan Teki <jagan@openedev.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 6217be2352..60ad28efd4 100644
--- a/drivers/mtd/mtdcore.c
+++ b/drivers/mtd/mtdcore.c
@@ -937,7 +937,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)
@@ -952,10 +965,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 f87c962205..ccbb1757ea 100644
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -417,8 +417,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 (master->_read)
+		slave->mtd._read = part_read;
+	if (master->_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 64e4621aaa..0b58e15b03 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
@@ -4620,8 +4566,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] 41+ messages in thread

* [U-Boot] [PATCH v6 02/27] mtd: Uninline mtd_write_oob and move it to mtdcore.c
  2018-08-01  8:18 [U-Boot] [PATCH v6 00/27] SPI-NAND support Miquel Raynal
  2018-08-01  8:18 ` [U-Boot] [PATCH v6 01/27] mtd: Fallback to ->_read/write_oob() when ->_read/write() is missing Miquel Raynal
@ 2018-08-01  8:18 ` Miquel Raynal
  2018-08-01  8:18 ` [U-Boot] [PATCH v6 03/27] mtd: Add sanity checks in mtd_write/read_oob() Miquel Raynal
                   ` (26 subsequent siblings)
  28 siblings, 0 replies; 41+ messages in thread
From: Miquel Raynal @ 2018-08-01  8:18 UTC (permalink / raw)
  To: u-boot

From: Ezequiel Garcia <ezequiel@vanguardiasur.com.ar>

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

Signed-off-by: Ezequiel Garcia <ezequiel@vanguardiasur.com.ar>
Acked-by: Boris Brezillon <boris.brezillon@free-electrons.com>
Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 drivers/mtd/mtdcore.c   | 12 ++++++++++++
 include/linux/mtd/mtd.h | 12 +-----------
 2 files changed, 13 insertions(+), 11 deletions(-)

diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
index 60ad28efd4..ad61406dac 100644
--- a/drivers/mtd/mtdcore.c
+++ b/drivers/mtd/mtdcore.c
@@ -1031,6 +1031,18 @@ int mtd_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops)
 }
 EXPORT_SYMBOL_GPL(mtd_read_oob);
 
+int mtd_write_oob(struct mtd_info *mtd, loff_t to,
+				struct mtd_oob_ops *ops)
+{
+	ops->retlen = ops->oobretlen = 0;
+	if (!mtd->_write_oob)
+		return -EOPNOTSUPP;
+	if (!(mtd->flags & MTD_WRITEABLE))
+		return -EROFS;
+	return mtd->_write_oob(mtd, to, ops);
+}
+EXPORT_SYMBOL_GPL(mtd_write_oob);
+
 /**
  * mtd_ooblayout_ecc - Get the OOB region definition of a specific ECC section
  * @mtd: MTD device structure
diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
index 823e535b82..eb39f38887 100644
--- a/include/linux/mtd/mtd.h
+++ b/include/linux/mtd/mtd.h
@@ -351,17 +351,7 @@ int mtd_panic_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen,
 		    const u_char *buf);
 
 int mtd_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops);
-
-static inline int mtd_write_oob(struct mtd_info *mtd, loff_t to,
-				struct mtd_oob_ops *ops)
-{
-	ops->retlen = ops->oobretlen = 0;
-	if (!mtd->_write_oob)
-		return -EOPNOTSUPP;
-	if (!(mtd->flags & MTD_WRITEABLE))
-		return -EROFS;
-	return mtd->_write_oob(mtd, to, ops);
-}
+int mtd_write_oob(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops);
 
 int mtd_get_fact_prot_info(struct mtd_info *mtd, size_t len, size_t *retlen,
 			   struct otp_info *buf);
-- 
2.14.1

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

* [U-Boot] [PATCH v6 03/27] mtd: Add sanity checks in mtd_write/read_oob()
  2018-08-01  8:18 [U-Boot] [PATCH v6 00/27] SPI-NAND support Miquel Raynal
  2018-08-01  8:18 ` [U-Boot] [PATCH v6 01/27] mtd: Fallback to ->_read/write_oob() when ->_read/write() is missing Miquel Raynal
  2018-08-01  8:18 ` [U-Boot] [PATCH v6 02/27] mtd: Uninline mtd_write_oob and move it to mtdcore.c Miquel Raynal
@ 2018-08-01  8:18 ` Miquel Raynal
  2018-08-01  8:18 ` [U-Boot] [PATCH v6 04/27] mtd: Fallback to ->_read/write() when ->_read/write_oob() is missing Miquel Raynal
                   ` (25 subsequent siblings)
  28 siblings, 0 replies; 41+ messages in thread
From: Miquel Raynal @ 2018-08-01  8:18 UTC (permalink / raw)
  To: u-boot

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

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

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

Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
Cc: Peter Pan <peterpandong@micron.com>
Signed-off-by: Richard Weinberger <richard@nod.at>
[Miquel: squashed the fix about the chip's size check]
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 drivers/mtd/mtdcore.c | 45 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 45 insertions(+)

diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
index ad61406dac..9a3efe95df 100644
--- a/drivers/mtd/mtdcore.c
+++ b/drivers/mtd/mtdcore.c
@@ -1010,12 +1010,50 @@ int mtd_panic_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen,
 }
 EXPORT_SYMBOL_GPL(mtd_panic_write);
 
+static int mtd_check_oob_ops(struct mtd_info *mtd, loff_t offs,
+			     struct mtd_oob_ops *ops)
+{
+	/*
+	 * Some users are setting ->datbuf or ->oobbuf to NULL, but are leaving
+	 * ->len or ->ooblen uninitialized. Force ->len and ->ooblen to 0 in
+	 *  this case.
+	 */
+	if (!ops->datbuf)
+		ops->len = 0;
+
+	if (!ops->oobbuf)
+		ops->ooblen = 0;
+
+	if (offs < 0 || offs + ops->len > mtd->size)
+		return -EINVAL;
+
+	if (ops->ooblen) {
+		u64 maxooblen;
+
+		if (ops->ooboffs >= mtd_oobavail(mtd, ops))
+			return -EINVAL;
+
+		maxooblen = ((mtd_div_by_ws(mtd->size, mtd) -
+			      mtd_div_by_ws(offs, mtd)) *
+			     mtd_oobavail(mtd, ops)) - ops->ooboffs;
+		if (ops->ooblen > maxooblen)
+			return -EINVAL;
+	}
+
+	return 0;
+}
+
 int mtd_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops)
 {
 	int ret_code;
 	ops->retlen = ops->oobretlen = 0;
 	if (!mtd->_read_oob)
 		return -EOPNOTSUPP;
+
+	ret_code = mtd_check_oob_ops(mtd, from, ops);
+	if (ret_code)
+		return ret_code;
+
 	/*
 	 * In cases where ops->datbuf != NULL, mtd->_read_oob() has semantics
 	 * similar to mtd->_read(), returning a non-negative integer
@@ -1034,11 +1072,18 @@ EXPORT_SYMBOL_GPL(mtd_read_oob);
 int mtd_write_oob(struct mtd_info *mtd, loff_t to,
 				struct mtd_oob_ops *ops)
 {
+	int ret;
+
 	ops->retlen = ops->oobretlen = 0;
 	if (!mtd->_write_oob)
 		return -EOPNOTSUPP;
 	if (!(mtd->flags & MTD_WRITEABLE))
 		return -EROFS;
+
+	ret = mtd_check_oob_ops(mtd, to, ops);
+	if (ret)
+		return ret;
+
 	return mtd->_write_oob(mtd, to, ops);
 }
 EXPORT_SYMBOL_GPL(mtd_write_oob);
-- 
2.14.1

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

* [U-Boot] [PATCH v6 04/27] mtd: Fallback to ->_read/write() when ->_read/write_oob() is missing
  2018-08-01  8:18 [U-Boot] [PATCH v6 00/27] SPI-NAND support Miquel Raynal
                   ` (2 preceding siblings ...)
  2018-08-01  8:18 ` [U-Boot] [PATCH v6 03/27] mtd: Add sanity checks in mtd_write/read_oob() Miquel Raynal
@ 2018-08-01  8:18 ` Miquel Raynal
  2018-08-01  8:18 ` [U-Boot] [PATCH v6 05/27] mtd: add get/set of_node/flash_node helpers Miquel Raynal
                   ` (24 subsequent siblings)
  28 siblings, 0 replies; 41+ messages in thread
From: Miquel Raynal @ 2018-08-01  8:18 UTC (permalink / raw)
  To: u-boot

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

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

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

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

diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
index 9a3efe95df..fb1d68d5e2 100644
--- a/drivers/mtd/mtdcore.c
+++ b/drivers/mtd/mtdcore.c
@@ -1047,20 +1047,27 @@ int mtd_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops)
 {
 	int ret_code;
 	ops->retlen = ops->oobretlen = 0;
-	if (!mtd->_read_oob)
-		return -EOPNOTSUPP;
 
 	ret_code = mtd_check_oob_ops(mtd, from, ops);
 	if (ret_code)
 		return ret_code;
 
+	/* Check the validity of a potential fallback on mtd->_read */
+	if (!mtd->_read_oob && (!mtd->_read || ops->oobbuf))
+		return -EOPNOTSUPP;
+
+	if (mtd->_read_oob)
+		ret_code = mtd->_read_oob(mtd, from, ops);
+	else
+		ret_code = mtd->_read(mtd, from, ops->len, &ops->retlen,
+				      ops->datbuf);
+
 	/*
 	 * In cases where ops->datbuf != NULL, mtd->_read_oob() has semantics
 	 * similar to mtd->_read(), returning a non-negative integer
 	 * representing max bitflips. In other cases, mtd->_read_oob() may
 	 * return -EUCLEAN. In all cases, perform similar logic to mtd_read().
 	 */
-	ret_code = mtd->_read_oob(mtd, from, ops);
 	if (unlikely(ret_code < 0))
 		return ret_code;
 	if (mtd->ecc_strength == 0)
@@ -1075,8 +1082,7 @@ int mtd_write_oob(struct mtd_info *mtd, loff_t to,
 	int ret;
 
 	ops->retlen = ops->oobretlen = 0;
-	if (!mtd->_write_oob)
-		return -EOPNOTSUPP;
+
 	if (!(mtd->flags & MTD_WRITEABLE))
 		return -EROFS;
 
@@ -1084,7 +1090,15 @@ int mtd_write_oob(struct mtd_info *mtd, loff_t to,
 	if (ret)
 		return ret;
 
-	return mtd->_write_oob(mtd, to, ops);
+	/* Check the validity of a potential fallback on mtd->_write */
+	if (!mtd->_write_oob && (!mtd->_write || ops->oobbuf))
+		return -EOPNOTSUPP;
+
+	if (mtd->_write_oob)
+		return mtd->_write_oob(mtd, to, ops);
+	else
+		return mtd->_write(mtd, to, ops->len, &ops->retlen,
+				   ops->datbuf);
 }
 EXPORT_SYMBOL_GPL(mtd_write_oob);
 
-- 
2.14.1

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

* [U-Boot] [PATCH v6 05/27] mtd: add get/set of_node/flash_node helpers
  2018-08-01  8:18 [U-Boot] [PATCH v6 00/27] SPI-NAND support Miquel Raynal
                   ` (3 preceding siblings ...)
  2018-08-01  8:18 ` [U-Boot] [PATCH v6 04/27] mtd: Fallback to ->_read/write() when ->_read/write_oob() is missing Miquel Raynal
@ 2018-08-01  8:18 ` Miquel Raynal
  2018-08-01  8:18 ` [U-Boot] [PATCH v6 06/27] mtd: fix build issue with includes Miquel Raynal
                   ` (23 subsequent siblings)
  28 siblings, 0 replies; 41+ messages in thread
From: Miquel Raynal @ 2018-08-01  8:18 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>
Reviewed-by: Jagan Teki <jagan@openedev.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 eb39f38887..ea659c354b 100644
--- a/include/linux/mtd/mtd.h
+++ b/include/linux/mtd/mtd.h
@@ -306,6 +306,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] 41+ messages in thread

* [U-Boot] [PATCH v6 06/27] mtd: fix build issue with includes
  2018-08-01  8:18 [U-Boot] [PATCH v6 00/27] SPI-NAND support Miquel Raynal
                   ` (4 preceding siblings ...)
  2018-08-01  8:18 ` [U-Boot] [PATCH v6 05/27] mtd: add get/set of_node/flash_node helpers Miquel Raynal
@ 2018-08-01  8:18 ` Miquel Raynal
  2018-08-01  8:18 ` [U-Boot] [PATCH v6 07/27] mtd: move definitions to enlarge their range Miquel Raynal
                   ` (22 subsequent siblings)
  28 siblings, 0 replies; 41+ messages in thread
From: Miquel Raynal @ 2018-08-01  8:18 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>
Reviewed-by: Jagan Teki <jagan@openedev.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 ea659c354b..8def104627 100644
--- a/include/linux/mtd/mtd.h
+++ b/include/linux/mtd/mtd.h
@@ -21,6 +21,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] 41+ messages in thread

* [U-Boot] [PATCH v6 07/27] mtd: move definitions to enlarge their range
  2018-08-01  8:18 [U-Boot] [PATCH v6 00/27] SPI-NAND support Miquel Raynal
                   ` (5 preceding siblings ...)
  2018-08-01  8:18 ` [U-Boot] [PATCH v6 06/27] mtd: fix build issue with includes Miquel Raynal
@ 2018-08-01  8:18 ` Miquel Raynal
  2018-08-01  8:18 ` [U-Boot] [PATCH v6 08/27] mtd: move all flash categories inside MTD submenu Miquel Raynal
                   ` (21 subsequent siblings)
  28 siblings, 0 replies; 41+ messages in thread
From: Miquel Raynal @ 2018-08-01  8:18 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 8def104627..6771ee2586 100644
--- a/include/linux/mtd/mtd.h
+++ b/include/linux/mtd/mtd.h
@@ -517,6 +517,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] 41+ messages in thread

* [U-Boot] [PATCH v6 08/27] mtd: move all flash categories inside MTD submenu
  2018-08-01  8:18 [U-Boot] [PATCH v6 00/27] SPI-NAND support Miquel Raynal
                   ` (6 preceding siblings ...)
  2018-08-01  8:18 ` [U-Boot] [PATCH v6 07/27] mtd: move definitions to enlarge their range Miquel Raynal
@ 2018-08-01  8:18 ` Miquel Raynal
  2018-08-01  8:18 ` [U-Boot] [PATCH v6 09/27] mtd: move NAND files into a raw/ subdirectory Miquel Raynal
                   ` (20 subsequent siblings)
  28 siblings, 0 replies; 41+ messages in thread
From: Miquel Raynal @ 2018-08-01  8:18 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>
Reviewed-by: Jagan Teki <jagan@openedev.com>
---
 drivers/mtd/Kconfig | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig
index 41f8883ec2..9341d518f3 100644
--- a/drivers/mtd/Kconfig
+++ b/drivers/mtd/Kconfig
@@ -59,10 +59,10 @@ config RENESAS_RPC_HF
 	  This enables access to Hyperflash memory through the Renesas
 	  RCar Gen3 RPC 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] 41+ messages in thread

* [U-Boot] [PATCH v6 09/27] mtd: move NAND files into a raw/ subdirectory
  2018-08-01  8:18 [U-Boot] [PATCH v6 00/27] SPI-NAND support Miquel Raynal
                   ` (7 preceding siblings ...)
  2018-08-01  8:18 ` [U-Boot] [PATCH v6 08/27] mtd: move all flash categories inside MTD submenu Miquel Raynal
@ 2018-08-01  8:18 ` Miquel Raynal
  2018-08-01  8:18 ` [U-Boot] [PATCH v6 10/27] mtd: rename nand into rawnand in Kconfig prompt Miquel Raynal
                   ` (19 subsequent siblings)
  28 siblings, 0 replies; 41+ messages in thread
From: Miquel Raynal @ 2018-08-01  8:18 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.

Documentation, README*, and MAINTAINERS files are updated accordingly.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 MAINTAINERS                                   |   6 +-
 Makefile                                      |   2 +-
 README                                        |   6 +-
 arch/arm/mach-uniphier/board_late_init.c      |   2 +-
 common/spl/Kconfig                            |   2 +-
 common/spl/spl_spi.c                          |   2 +-
 doc/README.SPL                                |   4 +-
 doc/README.arm-relocation                     |   2 +-
 doc/README.nand                               |   6 +-
 doc/README.zynq                               |   2 +-
 drivers/Makefile                              |   2 +-
 drivers/mtd/Makefile                          |   2 +
 drivers/mtd/nand/Kconfig                      | 298 +-------------------------
 drivers/mtd/nand/Makefile                     |  75 -------
 drivers/mtd/nand/raw/Kconfig                  | 297 +++++++++++++++++++++++++
 drivers/mtd/nand/raw/Makefile                 |  77 +++++++
 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     |   2 +-
 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.h         |   0
 drivers/mtd/nand/{ => raw}/mxs_nand_dt.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         |   2 +-
 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        |   2 +-
 drivers/mtd/nand/{ => raw}/omap_elm.c         |   0
 drivers/mtd/nand/{ => raw}/omap_gpmc.c        |   0
 drivers/mtd/nand/{ => raw}/pxa3xx_nand.c      |   2 +-
 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
 include/configs/MPC8313ERDB.h                 |   2 +-
 66 files changed, 400 insertions(+), 395 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 (99%)
 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.h (100%)
 rename drivers/mtd/nand/{ => raw}/mxs_nand_dt.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 (99%)
 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 (99%)
 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 (99%)
 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/MAINTAINERS b/MAINTAINERS
index e44280ceb6..63f2457494 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -281,7 +281,7 @@ F:	drivers/i2c/i2c-cdns.c
 F:	drivers/i2c/muxes/pca954x.c
 F:	drivers/i2c/zynq_i2c.c
 F:	drivers/mmc/zynq_sdhci.c
-F:	drivers/mtd/nand/zynq_nand.c
+F:	drivers/mtd/nand/raw/zynq_nand.c
 F:	drivers/net/phy/xilinx_phy.c
 F:	drivers/net/zynq_gem.c
 F:	drivers/serial/serial_zynq.c
@@ -305,7 +305,7 @@ F:	drivers/i2c/i2c-cdns.c
 F:	drivers/i2c/muxes/pca954x.c
 F:	drivers/i2c/zynq_i2c.c
 F:	drivers/mmc/zynq_sdhci.c
-F:	drivers/mtd/nand/zynq_nand.c
+F:	drivers/mtd/nand/raw/zynq_nand.c
 F:	drivers/net/phy/xilinx_phy.c
 F:	drivers/net/zynq_gem.c
 F:	drivers/serial/serial_zynq.c
@@ -440,7 +440,7 @@ NAND FLASH
 #M:	Scott Wood <oss@buserror.net>
 S:	Orphaned (Since 2018-07)
 T:	git git://git.denx.de/u-boot-nand-flash.git
-F:	drivers/mtd/nand/
+F:	drivers/mtd/nand/raw/
 
 NDS32
 M:	Macpaul Lin <macpaul@andestech.com>
diff --git a/Makefile b/Makefile
index 675d011c95..a54bffb3ef 100644
--- a/Makefile
+++ b/Makefile
@@ -685,7 +685,7 @@ libs-y += drivers/dma/
 libs-y += drivers/gpio/
 libs-y += drivers/i2c/
 libs-y += drivers/mtd/
-libs-$(CONFIG_CMD_NAND) += drivers/mtd/nand/
+libs-$(CONFIG_CMD_NAND) += drivers/mtd/nand/raw/
 libs-y += drivers/mtd/onenand/
 libs-$(CONFIG_CMD_UBI) += drivers/mtd/ubi/
 libs-y += drivers/mtd/spi/
diff --git a/README b/README
index aee0f7371c..fd5034ce91 100644
--- a/README
+++ b/README
@@ -3264,8 +3264,8 @@ Low Level (hardware related) configuration options:
 		a 16 bit bus.
 		Not all NAND drivers use this symbol.
 		Example of drivers that use it:
-		- drivers/mtd/nand/ndfc.c
-		- drivers/mtd/nand/mxc_nand.c
+		- drivers/mtd/nand/raw/ndfc.c
+		- drivers/mtd/nand/raw/mxc_nand.c
 
 - CONFIG_SYS_NDFC_EBC0_CFG
 		Sets the EBC0_CFG register for the NDFC. If not defined
@@ -3382,7 +3382,7 @@ Low Level (hardware related) configuration options:
 - CONFIG_SYS_NAND_NO_SUBPAGE_WRITE
 		Option to disable subpage write in NAND driver
 		driver that uses this:
-		drivers/mtd/nand/davinci_nand.c
+		drivers/mtd/nand/raw/davinci_nand.c
 
 Freescale QE/FMAN Firmware Support:
 -----------------------------------
diff --git a/arch/arm/mach-uniphier/board_late_init.c b/arch/arm/mach-uniphier/board_late_init.c
index 8ffb9a8d3c..1b871c62ce 100644
--- a/arch/arm/mach-uniphier/board_late_init.c
+++ b/arch/arm/mach-uniphier/board_late_init.c
@@ -12,7 +12,7 @@
 #include <stdio.h>
 #include <linux/io.h>
 #include <linux/printk.h>
-#include <../drivers/mtd/nand/denali.h>
+#include <../drivers/mtd/nand/raw/denali.h>
 
 #include "init.h"
 
diff --git a/common/spl/Kconfig b/common/spl/Kconfig
index 2af26a881a..7bf7a23542 100644
--- a/common/spl/Kconfig
+++ b/common/spl/Kconfig
@@ -479,7 +479,7 @@ config SPL_NAND_SUPPORT
 	help
 	  Enable support for NAND (Negative AND) flash in SPL. NAND flash
 	  can be used to allow SPL to load U-Boot from supported devices.
-	  This enables the drivers in drivers/mtd/nand as part of an SPL
+	  This enables the drivers in drivers/mtd/nand/raw as part of an SPL
 	  build.
 
 config SPL_NET_SUPPORT
diff --git a/common/spl/spl_spi.c b/common/spl/spl_spi.c
index ba60a3a3c5..0016d49739 100644
--- a/common/spl/spl_spi.c
+++ b/common/spl/spl_spi.c
@@ -2,7 +2,7 @@
 /*
  * Copyright (C) 2011 OMICRON electronics GmbH
  *
- * based on drivers/mtd/nand/nand_spl_load.c
+ * based on drivers/mtd/nand/raw/nand_spl_load.c
  *
  * Copyright (C) 2011
  * Heiko Schocher, DENX Software Engineering, hs at denx.de.
diff --git a/doc/README.SPL b/doc/README.SPL
index 3ba313caa8..fc1ca1ad4f 100644
--- a/doc/README.SPL
+++ b/doc/README.SPL
@@ -57,11 +57,11 @@ CONFIG_SPL_FAT_SUPPORT (fs/fat/libfat.o)
 CONFIG_SPL_EXT_SUPPORT
 CONFIG_SPL_LIBGENERIC_SUPPORT (lib/libgeneric.o)
 CONFIG_SPL_POWER_SUPPORT (drivers/power/libpower.o)
-CONFIG_SPL_NAND_SUPPORT (drivers/mtd/nand/libnand.o)
+CONFIG_SPL_NAND_SUPPORT (drivers/mtd/nand/raw/libnand.o)
 CONFIG_SPL_DRIVERS_MISC_SUPPORT (drivers/misc)
 CONFIG_SPL_DMA_SUPPORT (drivers/dma/libdma.o)
 CONFIG_SPL_POST_MEM_SUPPORT (post/drivers/memory.o)
-CONFIG_SPL_NAND_LOAD (drivers/mtd/nand/nand_spl_load.o)
+CONFIG_SPL_NAND_LOAD (drivers/mtd/nand/raw/nand_spl_load.o)
 CONFIG_SPL_SPI_LOAD (drivers/mtd/spi/spi_spl_load.o)
 CONFIG_SPL_RAM_DEVICE (common/spl/spl.c)
 CONFIG_SPL_WATCHDOG_SUPPORT (drivers/watchdog/libwatchdog.o)
diff --git a/doc/README.arm-relocation b/doc/README.arm-relocation
index 645b3746c8..d2a7e8122e 100644
--- a/doc/README.arm-relocation
+++ b/doc/README.arm-relocation
@@ -84,7 +84,7 @@ Relocation with SPL (example for the tx25 booting from NAND Flash):
 - cpu copies the first page from NAND to 0xbb000000 (IMX_NFC_BASE)
   and start with code execution on this address.
 
-- The First page contains u-boot code from drivers/mtd/nand/mxc_nand_spl.c
+- The First page contains u-boot code from drivers/mtd/nand/raw/mxc_nand_spl.c
   which inits the dram, cpu registers, reloacte itself to CONFIG_SPL_TEXT_BASE	and loads
   the "real" u-boot to CONFIG_SYS_NAND_U_BOOT_DST and starts execution
   @CONFIG_SYS_NAND_U_BOOT_START
diff --git a/doc/README.nand b/doc/README.nand
index cda11b43ff..ec461b2dc9 100644
--- a/doc/README.nand
+++ b/doc/README.nand
@@ -116,7 +116,7 @@ Configuration Options:
       The maximum number of NAND chips per device to be supported.
 
    CONFIG_SYS_NAND_SELF_INIT
-      Traditionally, glue code in drivers/mtd/nand/nand.c has driven
+      Traditionally, glue code in drivers/mtd/nand/raw/nand.c has driven
       the initialization process -- it provides the mtd and nand
       structs, calls a board init function for a specific device,
       calls nand_scan(), and registers with mtd.
@@ -125,7 +125,7 @@ Configuration Options:
       run code between nand_scan_ident() and nand_scan_tail(), or other
       deviations from the "normal" flow.
 
-      If a board defines CONFIG_SYS_NAND_SELF_INIT, drivers/mtd/nand/nand.c
+      If a board defines CONFIG_SYS_NAND_SELF_INIT, drivers/mtd/nand/raw/nand.c
       will make one call to board_nand_init(), with no arguments.  That
       function is responsible for calling a driver init function for
       each NAND device on the board, that performs all initialization
@@ -280,7 +280,7 @@ NOTE:
 =====
 
 The Disk On Chip driver is currently broken and has been for some time.
-There is a driver in drivers/mtd/nand, taken from Linux, that works with
+There is a driver in drivers/mtd/nand/raw, taken from Linux, that works with
 the current NAND system but has not yet been adapted to the u-boot
 environment.
 
diff --git a/doc/README.zynq b/doc/README.zynq
index 5b0672c503..da977b2016 100644
--- a/doc/README.zynq
+++ b/doc/README.zynq
@@ -63,7 +63,7 @@ bootmode strings at runtime.
   spi - drivers/spi/zynq_spi.c
   qspi - drivers/spi/zynq_qspi.c
   i2c - drivers/i2c/zynq_i2c.c
-  nand - drivers/mtd/nand/zynq_nand.c
+  nand - drivers/mtd/nand/raw/zynq_nand.c
 - Done proper cleanups on board configurations
 - Added basic FDT support for zynq boards
 - d-cache support for zynq_gem.c
diff --git a/drivers/Makefile b/drivers/Makefile
index 276e5ee4d7..ccd1b648d0 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -6,7 +6,7 @@ obj-$(CONFIG_$(SPL_TPL_)DRIVERS_MISC_SUPPORT) += misc/ sysreset/ firmware/
 obj-$(CONFIG_$(SPL_TPL_)I2C_SUPPORT) += i2c/
 obj-$(CONFIG_$(SPL_TPL_)LED) += led/
 obj-$(CONFIG_$(SPL_TPL_)MMC_SUPPORT) += mmc/
-obj-$(CONFIG_$(SPL_TPL_)NAND_SUPPORT) += mtd/nand/
+obj-$(CONFIG_$(SPL_TPL_)NAND_SUPPORT) += mtd/nand/raw/
 obj-$(CONFIG_$(SPL_TPL_)PHY) += phy/
 obj-$(CONFIG_$(SPL_TPL_)PINCTRL) += pinctrl/
 obj-$(CONFIG_$(SPL_TPL_)RAM) += ram/
diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile
index 9cec06510c..cdf515256a 100644
--- a/drivers/mtd/Makefile
+++ b/drivers/mtd/Makefile
@@ -18,3 +18,5 @@ obj-$(CONFIG_FLASH_PIC32) += pic32_flash.o
 obj-$(CONFIG_ST_SMI) += st_smi.o
 obj-$(CONFIG_STM32_FLASH) += stm32_flash.o
 obj-$(CONFIG_RENESAS_RPC_HF) += renesas_rpc_hf.o
+
+obj-y += nand/
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index 1e4ea7bdd4..6d53734718 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -1,297 +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_ATMEL
-	bool "Support Atmel NAND controller"
-	imply SYS_NAND_USE_FLASH_BBT
-	help
-	  Enable this driver for NAND flash platforms using an Atmel NAND
-	  controller.
-
-config NAND_DAVINCI
-	bool "Support TI Davinci NAND controller"
-	help
-	  Enable this driver for NAND flash controllers available in TI Davinci
-	  and Keystone2 platforms
-
-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_LPC32XX_SLC
-	bool "Support LPC32XX_SLC controller"
-	help
-	  Enable the LPC32XX SLC NAND controller.
-
-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"
-	default ARCH_SUNXI
-	depends on MACH_SUN4I || MACH_SUN5I || MACH_SUN7I || MACH_SUN8I
-	select SYS_NAND_SELF_INIT
-	select SYS_NAND_U_BOOT_LOCATIONS
-	select SPL_NAND_SUPPORT
-	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
-	select SYS_NAND_SELF_INIT
-	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.
-
-if NAND_MXS
-
-config NAND_MXS_DT
-	bool "Support MXS NAND controller as a DT device"
-	depends on OF_CONTROL && MTD
-	help
-	  Enable the driver for MXS NAND flash on platforms using
-	  device tree.
-
-config NAND_MXS_USE_MINIMUM_ECC
-	bool "Use minimum ECC strength supported by the controller"
-	default false
-
-endif
-
-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"
-
-config SYS_NAND_BLOCK_SIZE
-	hex "NAND chip eraseblock size"
-	depends on ARCH_SUNXI
-	help
-	  Number of data bytes in one eraseblock for the NAND chip on the
-	  board. This is the multiple of NAND_PAGE_SIZE and the number of
-	  pages.
-
-config SYS_NAND_PAGE_SIZE
-	hex "NAND chip page size"
-	depends on ARCH_SUNXI
-	help
-	  Number of data bytes in one page for the NAND chip on the
-	  board, not including the OOB area.
-
-config SYS_NAND_OOBSIZE
-	hex "NAND chip OOB size"
-	depends on ARCH_SUNXI
-	help
-	  Number of bytes in the Out-Of-Band area for the NAND chip on
-	  the board.
-
-# 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 c61e3f3839..69f40d1563 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -1,77 +1,2 @@
 # SPDX-License-Identifier: GPL-2.0+
-#
-# (C) Copyright 2006
-# Wolfgang Denk, DENX Software Engineering, wd at denx.de.
 
-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_IDENT) += nand_ids.o nand_timings.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_MXS_DT) += mxs_nand_dt.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/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig
new file mode 100644
index 0000000000..1e4ea7bdd4
--- /dev/null
+++ b/drivers/mtd/nand/raw/Kconfig
@@ -0,0 +1,297 @@
+
+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_ATMEL
+	bool "Support Atmel NAND controller"
+	imply SYS_NAND_USE_FLASH_BBT
+	help
+	  Enable this driver for NAND flash platforms using an Atmel NAND
+	  controller.
+
+config NAND_DAVINCI
+	bool "Support TI Davinci NAND controller"
+	help
+	  Enable this driver for NAND flash controllers available in TI Davinci
+	  and Keystone2 platforms
+
+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_LPC32XX_SLC
+	bool "Support LPC32XX_SLC controller"
+	help
+	  Enable the LPC32XX SLC NAND controller.
+
+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"
+	default ARCH_SUNXI
+	depends on MACH_SUN4I || MACH_SUN5I || MACH_SUN7I || MACH_SUN8I
+	select SYS_NAND_SELF_INIT
+	select SYS_NAND_U_BOOT_LOCATIONS
+	select SPL_NAND_SUPPORT
+	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
+	select SYS_NAND_SELF_INIT
+	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.
+
+if NAND_MXS
+
+config NAND_MXS_DT
+	bool "Support MXS NAND controller as a DT device"
+	depends on OF_CONTROL && MTD
+	help
+	  Enable the driver for MXS NAND flash on platforms using
+	  device tree.
+
+config NAND_MXS_USE_MINIMUM_ECC
+	bool "Use minimum ECC strength supported by the controller"
+	default false
+
+endif
+
+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"
+
+config SYS_NAND_BLOCK_SIZE
+	hex "NAND chip eraseblock size"
+	depends on ARCH_SUNXI
+	help
+	  Number of data bytes in one eraseblock for the NAND chip on the
+	  board. This is the multiple of NAND_PAGE_SIZE and the number of
+	  pages.
+
+config SYS_NAND_PAGE_SIZE
+	hex "NAND chip page size"
+	depends on ARCH_SUNXI
+	help
+	  Number of data bytes in one page for the NAND chip on the
+	  board, not including the OOB area.
+
+config SYS_NAND_OOBSIZE
+	hex "NAND chip OOB size"
+	depends on ARCH_SUNXI
+	help
+	  Number of bytes in the Out-Of-Band area for the NAND chip on
+	  the board.
+
+# 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..c61e3f3839
--- /dev/null
+++ b/drivers/mtd/nand/raw/Makefile
@@ -0,0 +1,77 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# (C) Copyright 2006
+# Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+
+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_IDENT) += nand_ids.o nand_timings.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_MXS_DT) += mxs_nand_dt.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 99%
rename from drivers/mtd/nand/davinci_nand.c
rename to drivers/mtd/nand/raw/davinci_nand.c
index 305e68ad49..e6a84a52b4 100644
--- a/drivers/mtd/nand/davinci_nand.c
+++ b/drivers/mtd/nand/raw/davinci_nand.c
@@ -9,7 +9,7 @@
 
 /*
  *
- * linux/drivers/mtd/nand/nand_davinci.c
+ * linux/drivers/mtd/nand/raw/nand_davinci.c
  *
  * NAND Flash Driver
  *
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.h b/drivers/mtd/nand/raw/mxs_nand.h
similarity index 100%
rename from drivers/mtd/nand/mxs_nand.h
rename to drivers/mtd/nand/raw/mxs_nand.h
diff --git a/drivers/mtd/nand/mxs_nand_dt.c b/drivers/mtd/nand/raw/mxs_nand_dt.c
similarity index 100%
rename from drivers/mtd/nand/mxs_nand_dt.c
rename to drivers/mtd/nand/raw/mxs_nand_dt.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 99%
rename from drivers/mtd/nand/nand_ecc.c
rename to drivers/mtd/nand/raw/nand_ecc.c
index 05e55fce9a..2bc329be1a 100644
--- a/drivers/mtd/nand/nand_ecc.c
+++ b/drivers/mtd/nand/raw/nand_ecc.c
@@ -3,7 +3,7 @@
  * This file contains an ECC algorithm from Toshiba that detects and
  * corrects 1 bit errors in a 256 byte block of data.
  *
- * drivers/mtd/nand/nand_ecc.c
+ * drivers/mtd/nand/raw/nand_ecc.c
  *
  * Copyright (C) 2000-2004 Steven J. Hill (sjhill at realitydiluted.com)
  *                         Toshiba America Electronics Components, Inc.
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 99%
rename from drivers/mtd/nand/nand_util.c
rename to drivers/mtd/nand/raw/nand_util.c
index 1ded7aa920..fc2235c1a0 100644
--- a/drivers/mtd/nand/nand_util.c
+++ b/drivers/mtd/nand/raw/nand_util.c
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0
 /*
- * drivers/mtd/nand/nand_util.c
+ * drivers/mtd/nand/raw/nand_util.c
  *
  * Copyright (C) 2006 by Weiss-Electronic GmbH.
  * All rights reserved.
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 99%
rename from drivers/mtd/nand/pxa3xx_nand.c
rename to drivers/mtd/nand/raw/pxa3xx_nand.c
index 9d02fd8eb1..67b2b62f76 100644
--- a/drivers/mtd/nand/pxa3xx_nand.c
+++ b/drivers/mtd/nand/raw/pxa3xx_nand.c
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0
 /*
- * drivers/mtd/nand/pxa3xx_nand.c
+ * drivers/mtd/nand/raw/pxa3xx_nand.c
  *
  * Copyright © 2005 Intel Corporation
  * Copyright © 2006 Marvell International Ltd.
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
diff --git a/include/configs/MPC8313ERDB.h b/include/configs/MPC8313ERDB.h
index 1f56deb151..2a58058ebb 100644
--- a/include/configs/MPC8313ERDB.h
+++ b/include/configs/MPC8313ERDB.h
@@ -242,7 +242,7 @@
 				/* LB refresh timer prescal, 266MHz/32 */
 #define CONFIG_SYS_LBC_MRTPR	0x20000000  /*TODO */
 
-/* drivers/mtd/nand/nand.c */
+/* drivers/mtd/nand/raw/nand.c */
 #if defined(CONFIG_NAND) && defined(CONFIG_SPL_BUILD)
 #define CONFIG_SYS_NAND_BASE		0xFFF00000
 #else
-- 
2.14.1

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

* [U-Boot] [PATCH v6 10/27] mtd: rename nand into rawnand in Kconfig prompt
  2018-08-01  8:18 [U-Boot] [PATCH v6 00/27] SPI-NAND support Miquel Raynal
                   ` (8 preceding siblings ...)
  2018-08-01  8:18 ` [U-Boot] [PATCH v6 09/27] mtd: move NAND files into a raw/ subdirectory Miquel Raynal
@ 2018-08-01  8:18 ` Miquel Raynal
  2018-08-01  8:18 ` [U-Boot] [PATCH v6 11/27] mtd: nand: Add core infrastructure to deal with NAND devices Miquel Raynal
                   ` (18 subsequent siblings)
  28 siblings, 0 replies; 41+ messages in thread
From: Miquel Raynal @ 2018-08-01  8:18 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 1e4ea7bdd4..008f7b4b4b 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] 41+ messages in thread

* [U-Boot] [PATCH v6 11/27] mtd: nand: Add core infrastructure to deal with NAND devices
  2018-08-01  8:18 [U-Boot] [PATCH v6 00/27] SPI-NAND support Miquel Raynal
                   ` (9 preceding siblings ...)
  2018-08-01  8:18 ` [U-Boot] [PATCH v6 10/27] mtd: rename nand into rawnand in Kconfig prompt Miquel Raynal
@ 2018-08-01  8:18 ` Miquel Raynal
  2018-08-01  8:18 ` [U-Boot] [PATCH v6 12/27] mtd: nand: Pass mode information to nand_page_io_req Miquel Raynal
                   ` (17 subsequent siblings)
  28 siblings, 0 replies; 41+ messages in thread
From: Miquel Raynal @ 2018-08-01  8:18 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>
Acked-by: Jagan Teki <jagan@openedev.com>
---
 drivers/mtd/nand/Kconfig  |   3 +
 drivers/mtd/nand/Makefile |   2 +
 drivers/mtd/nand/bbt.c    | 132 +++++++++
 drivers/mtd/nand/core.c   | 243 +++++++++++++++
 include/linux/mtd/nand.h  | 731 ++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 1111 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 69f40d1563..cd492dbc14 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -1,2 +1,4 @@
 # SPDX-License-Identifier: GPL-2.0+
 
+nandcore-objs := core.o bbt.o
+obj-$(CONFIG_MTD_NAND_CORE) += nandcore.o
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] 41+ messages in thread

* [U-Boot] [PATCH v6 12/27] mtd: nand: Pass mode information to nand_page_io_req
  2018-08-01  8:18 [U-Boot] [PATCH v6 00/27] SPI-NAND support Miquel Raynal
                   ` (10 preceding siblings ...)
  2018-08-01  8:18 ` [U-Boot] [PATCH v6 11/27] mtd: nand: Add core infrastructure to deal with NAND devices Miquel Raynal
@ 2018-08-01  8:18 ` Miquel Raynal
  2018-08-01  8:18 ` [U-Boot] [PATCH v6 13/27] spi: Extend the core to ease integration of SPI memory controllers Miquel Raynal
                   ` (16 subsequent siblings)
  28 siblings, 0 replies; 41+ messages in thread
From: Miquel Raynal @ 2018-08-01  8:18 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] 41+ messages in thread

* [U-Boot] [PATCH v6 13/27] spi: Extend the core to ease integration of SPI memory controllers
  2018-08-01  8:18 [U-Boot] [PATCH v6 00/27] SPI-NAND support Miquel Raynal
                   ` (11 preceding siblings ...)
  2018-08-01  8:18 ` [U-Boot] [PATCH v6 12/27] mtd: nand: Pass mode information to nand_page_io_req Miquel Raynal
@ 2018-08-01  8:18 ` Miquel Raynal
  2018-08-01  8:18 ` [U-Boot] [PATCH v6 14/27] mtd: nand: Add core infrastructure to support SPI NANDs Miquel Raynal
                   ` (15 subsequent siblings)
  28 siblings, 0 replies; 41+ messages in thread
From: Miquel Raynal @ 2018-08-01  8:18 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>
Acked-by: Jagan Teki <jagan@openedev.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 b85fca5628..6286b2e234 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -18,6 +18,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 95b03a29dc..7971adeb6f 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -8,6 +8,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..07ce799170
--- /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 ", tx_data ? tx_buf[i] : 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 9754c53aa1..938627bc01 100644
--- a/include/spi.h
+++ b/include/spi.h
@@ -9,6 +9,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 */
@@ -402,6 +404,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] 41+ messages in thread

* [U-Boot] [PATCH v6 14/27] mtd: nand: Add core infrastructure to support SPI NANDs
  2018-08-01  8:18 [U-Boot] [PATCH v6 00/27] SPI-NAND support Miquel Raynal
                   ` (12 preceding siblings ...)
  2018-08-01  8:18 ` [U-Boot] [PATCH v6 13/27] spi: Extend the core to ease integration of SPI memory controllers Miquel Raynal
@ 2018-08-01  8:18 ` Miquel Raynal
  2018-08-01  8:18 ` [U-Boot] [PATCH v6 15/27] mtd: spinand: Add initial support for Micron MT29F2G01ABAGD Miquel Raynal
                   ` (14 subsequent siblings)
  28 siblings, 0 replies; 41+ messages in thread
From: Miquel Raynal @ 2018-08-01  8:18 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>
Acked-by: Jagan Teki <jagan@openedev.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   | 1235 +++++++++++++++++++++++++++++++++++++++++
 include/linux/mtd/spinand.h   |  427 ++++++++++++++
 6 files changed, 1676 insertions(+)
 create mode 100644 drivers/mtd/nand/spi/Kconfig
 create mode 100644 drivers/mtd/nand/spi/Makefile
 create mode 100644 drivers/mtd/nand/spi/core.c
 create mode 100644 include/linux/mtd/spinand.h

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 cd492dbc14..a358bc680e 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -2,3 +2,4 @@
 
 nandcore-objs := core.o bbt.o
 obj-$(CONFIG_MTD_NAND_CORE) += nandcore.o
+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..08f853ae11
--- /dev/null
+++ b/drivers/mtd/nand/spi/core.c
@@ -0,0 +1,1235 @@
+// 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)
+			break;
+
+		ret = spinand_ecc_enable(spinand, enable_ecc);
+		if (ret)
+			break;
+
+		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)
+			break;
+
+		ret = spinand_ecc_enable(spinand, enable_ecc);
+		if (ret)
+			break;
+
+		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) {
+		ret = -ENOMEM;
+		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] 41+ messages in thread

* [U-Boot] [PATCH v6 15/27] mtd: spinand: Add initial support for Micron MT29F2G01ABAGD
  2018-08-01  8:18 [U-Boot] [PATCH v6 00/27] SPI-NAND support Miquel Raynal
                   ` (13 preceding siblings ...)
  2018-08-01  8:18 ` [U-Boot] [PATCH v6 14/27] mtd: nand: Add core infrastructure to support SPI NANDs Miquel Raynal
@ 2018-08-01  8:18 ` Miquel Raynal
  2018-08-01  8:18 ` [U-Boot] [PATCH v6 16/27] mtd: spinand: Add initial support for Winbond W25M02GV Miquel Raynal
                   ` (13 subsequent siblings)
  28 siblings, 0 replies; 41+ messages in thread
From: Miquel Raynal @ 2018-08-01  8:18 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>
Acked-by: Jagan Teki <jagan@openedev.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 08f853ae11..36b8b52bc2 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] 41+ messages in thread

* [U-Boot] [PATCH v6 16/27] mtd: spinand: Add initial support for Winbond W25M02GV
  2018-08-01  8:18 [U-Boot] [PATCH v6 00/27] SPI-NAND support Miquel Raynal
                   ` (14 preceding siblings ...)
  2018-08-01  8:18 ` [U-Boot] [PATCH v6 15/27] mtd: spinand: Add initial support for Micron MT29F2G01ABAGD Miquel Raynal
@ 2018-08-01  8:18 ` Miquel Raynal
  2018-08-01  8:18 ` [U-Boot] [PATCH v6 17/27] mtd: spinand: Add initial support for the MX35LF1GE4AB chip Miquel Raynal
                   ` (12 subsequent siblings)
  28 siblings, 0 replies; 41+ messages in thread
From: Miquel Raynal @ 2018-08-01  8:18 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>
Acked-by: Jagan Teki <jagan@openedev.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 36b8b52bc2..ef3e6445d8 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] 41+ messages in thread

* [U-Boot] [PATCH v6 17/27] mtd: spinand: Add initial support for the MX35LF1GE4AB chip
  2018-08-01  8:18 [U-Boot] [PATCH v6 00/27] SPI-NAND support Miquel Raynal
                   ` (15 preceding siblings ...)
  2018-08-01  8:18 ` [U-Boot] [PATCH v6 16/27] mtd: spinand: Add initial support for Winbond W25M02GV Miquel Raynal
@ 2018-08-01  8:18 ` Miquel Raynal
  2018-08-01  8:18 ` [U-Boot] [PATCH v6 18/27] mtd: spinand: Add initial support for the MX35LF2GE4AB chip Miquel Raynal
                   ` (11 subsequent siblings)
  28 siblings, 0 replies; 41+ messages in thread
From: Miquel Raynal @ 2018-08-01  8:18 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>
Acked-by: Jagan Teki <jagan@openedev.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 ef3e6445d8..362d104846 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] 41+ messages in thread

* [U-Boot] [PATCH v6 18/27] mtd: spinand: Add initial support for the MX35LF2GE4AB chip
  2018-08-01  8:18 [U-Boot] [PATCH v6 00/27] SPI-NAND support Miquel Raynal
                   ` (16 preceding siblings ...)
  2018-08-01  8:18 ` [U-Boot] [PATCH v6 17/27] mtd: spinand: Add initial support for the MX35LF1GE4AB chip Miquel Raynal
@ 2018-08-01  8:18 ` Miquel Raynal
  2018-08-01  8:18 ` [U-Boot] [PATCH v6 19/27] dt-bindings: Add bindings for SPI NAND devices Miquel Raynal
                   ` (10 subsequent siblings)
  28 siblings, 0 replies; 41+ messages in thread
From: Miquel Raynal @ 2018-08-01  8:18 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>
Acked-by: Jagan Teki <jagan@openedev.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..662c561e50 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, 2048, 2, 1, 1),
+		     NAND_ECCREQ(4, 512),
+		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+					      &write_cache_variants,
+					      &update_cache_variants),
+		     SPINAND_HAS_QE_BIT,
+		     SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL)),
 };
 
 static int macronix_spinand_detect(struct spinand_device *spinand)
-- 
2.14.1

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

* [U-Boot] [PATCH v6 19/27] dt-bindings: Add bindings for SPI NAND devices
  2018-08-01  8:18 [U-Boot] [PATCH v6 00/27] SPI-NAND support Miquel Raynal
                   ` (17 preceding siblings ...)
  2018-08-01  8:18 ` [U-Boot] [PATCH v6 18/27] mtd: spinand: Add initial support for the MX35LF2GE4AB chip Miquel Raynal
@ 2018-08-01  8:18 ` Miquel Raynal
  2018-08-01  8:18 ` [U-Boot] [PATCH v6 20/27] mtd: declare MTD_PARTITIONS symbol in Kconfig Miquel Raynal
                   ` (9 subsequent siblings)
  28 siblings, 0 replies; 41+ messages in thread
From: Miquel Raynal @ 2018-08-01  8:18 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>
Acked-by: Jagan Teki <jagan@openedev.com>
---
 doc/device-tree-bindings/mtd/spi-nand.txt | 5 +++++
 1 file changed, 5 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..8b51f3b6d5
--- /dev/null
+++ b/doc/device-tree-bindings/mtd/spi-nand.txt
@@ -0,0 +1,5 @@
+SPI NAND flash
+
+Required properties:
+- compatible: should be "spi-nand"
+- reg: should encode the chip-select line used to access the NAND chip
-- 
2.14.1

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

* [U-Boot] [PATCH v6 20/27] mtd: declare MTD_PARTITIONS symbol in Kconfig
  2018-08-01  8:18 [U-Boot] [PATCH v6 00/27] SPI-NAND support Miquel Raynal
                   ` (18 preceding siblings ...)
  2018-08-01  8:18 ` [U-Boot] [PATCH v6 19/27] dt-bindings: Add bindings for SPI NAND devices Miquel Raynal
@ 2018-08-01  8:18 ` Miquel Raynal
  2018-08-01  8:18 ` [U-Boot] [PATCH v6 21/27] cmd: ubi: delete useless and misleading definitions Miquel Raynal
                   ` (8 subsequent siblings)
  28 siblings, 0 replies; 41+ messages in thread
From: Miquel Raynal @ 2018-08-01  8:18 UTC (permalink / raw)
  To: u-boot

UBI selects MTD_PARTITIONS which is the symbol to compile
drivers/mtd/mtdpart.c. Unfortunately, the symbol was not defined in
Kconfig and this worked only with board files defining it. Fix this by
adding a boolean in Kconfig so boards defined by defconfig files only
will work as expected.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
Reviewed-by: Jagan Teki <jagan@openedev.com>
---
 drivers/mtd/Kconfig | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig
index 9341d518f3..d98457e223 100644
--- a/drivers/mtd/Kconfig
+++ b/drivers/mtd/Kconfig
@@ -1,5 +1,8 @@
 menu "MTD Support"
 
+config MTD_PARTITIONS
+	bool
+
 config MTD
 	bool "Enable Driver Model for MTD drivers"
 	depends on DM
-- 
2.14.1

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

* [U-Boot] [PATCH v6 21/27] cmd: ubi: delete useless and misleading definitions
  2018-08-01  8:18 [U-Boot] [PATCH v6 00/27] SPI-NAND support Miquel Raynal
                   ` (19 preceding siblings ...)
  2018-08-01  8:18 ` [U-Boot] [PATCH v6 20/27] mtd: declare MTD_PARTITIONS symbol in Kconfig Miquel Raynal
@ 2018-08-01  8:18 ` Miquel Raynal
  2018-08-01  8:18 ` [U-Boot] [PATCH v6 22/27] cmd: mtdparts: accept spi-nand devices Miquel Raynal
                   ` (7 subsequent siblings)
  28 siblings, 0 replies; 41+ messages in thread
From: Miquel Raynal @ 2018-08-01  8:18 UTC (permalink / raw)
  To: u-boot

These definitions are simply not used and are misleading because similar
definitions exist in jffs2/load_kernel.h and are used widely to define
MTD device types (which is, by the way, totally redundant with what the
MTD core does). Remove these definitions.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
Acked-by: Jagan Teki <jagan@openedev.com>
---
 cmd/ubi.c | 5 -----
 1 file changed, 5 deletions(-)

diff --git a/cmd/ubi.c b/cmd/ubi.c
index 913f0f71fd..0a3405a3b1 100644
--- a/cmd/ubi.c
+++ b/cmd/ubi.c
@@ -27,11 +27,6 @@
 #undef ubi_msg
 #define ubi_msg(fmt, ...) printf("UBI: " fmt "\n", ##__VA_ARGS__)
 
-#define DEV_TYPE_NONE		0
-#define DEV_TYPE_NAND		1
-#define DEV_TYPE_ONENAND	2
-#define DEV_TYPE_NOR		3
-
 /* Private own data */
 static struct ubi_device *ubi;
 static char buffer[80];
-- 
2.14.1

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

* [U-Boot] [PATCH v6 22/27] cmd: mtdparts: accept spi-nand devices
  2018-08-01  8:18 [U-Boot] [PATCH v6 00/27] SPI-NAND support Miquel Raynal
                   ` (20 preceding siblings ...)
  2018-08-01  8:18 ` [U-Boot] [PATCH v6 21/27] cmd: ubi: delete useless and misleading definitions Miquel Raynal
@ 2018-08-01  8:18 ` Miquel Raynal
  2018-08-01  8:18 ` [U-Boot] [PATCH v6 23/27] cmd: mtdparts: add a generic 'mtdparts' parser Miquel Raynal
                   ` (6 subsequent siblings)
  28 siblings, 0 replies; 41+ messages in thread
From: Miquel Raynal @ 2018-08-01  8:18 UTC (permalink / raw)
  To: u-boot

Let spi-nand devices be recognized by mtdparts. This is superfluous
but a full mtdparts rework would be very time-consuming.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
Acked-by: Jagan Teki <jagan@openedev.com>
---
 cmd/mtdparts.c              | 13 ++++++++-----
 include/jffs2/load_kernel.h |  7 +++++--
 2 files changed, 13 insertions(+), 7 deletions(-)

diff --git a/cmd/mtdparts.c b/cmd/mtdparts.c
index 0da3afd75f..f26a761c99 100644
--- a/cmd/mtdparts.c
+++ b/cmd/mtdparts.c
@@ -37,7 +37,7 @@
  * mtdids=<idmap>[,<idmap>,...]
  *
  * <idmap>    := <dev-id>=<mtd-id>
- * <dev-id>   := 'nand'|'nor'|'onenand'<dev-num>
+ * <dev-id>   := 'nand'|'nor'|'onenand'|'spi-nand'<dev-num>
  * <dev-num>  := mtd device number, 0...
  * <mtd-id>   := unique device tag used by linux kernel to find mtd device (mtd->name)
  *
@@ -336,7 +336,7 @@ static int part_validate_eraseblock(struct mtdids *id, struct part_info *part)
 
 	if (!mtd->numeraseregions) {
 		/*
-		 * Only one eraseregion (NAND, OneNAND or uniform NOR),
+		 * Only one eraseregion (NAND, SPI-NAND, OneNAND or uniform NOR),
 		 * checking for alignment is easy here
 		 */
 		offset = part->offset;
@@ -1027,7 +1027,7 @@ static struct mtdids* id_find_by_mtd_id(const char *mtd_id, unsigned int mtd_id_
 }
 
 /**
- * Parse device id string <dev-id> := 'nand'|'nor'|'onenand'<dev-num>,
+ * Parse device id string <dev-id> := 'nand'|'nor'|'onenand'|'spi-nand'<dev-num>,
  * return device type and number.
  *
  * @param id string describing device id
@@ -1051,6 +1051,9 @@ int mtd_id_parse(const char *id, const char **ret_id, u8 *dev_type,
 	} else if (strncmp(p, "onenand", 7) == 0) {
 		*dev_type = MTD_DEV_TYPE_ONENAND;
 		p += 7;
+	} else if (strncmp(p, "spi-nand", 8) == 0) {
+		*dev_type = MTD_DEV_TYPE_SPINAND;
+		p += 8;
 	} else {
 		printf("incorrect device type in %s\n", id);
 		return 1;
@@ -1633,7 +1636,7 @@ static int parse_mtdids(const char *const ids)
 	while(p && (*p != '\0')) {
 
 		ret = 1;
-		/* parse 'nor'|'nand'|'onenand'<dev-num> */
+		/* parse 'nor'|'nand'|'onenand'|'spi-nand'<dev-num> */
 		if (mtd_id_parse(p, &p, &type, &num) != 0)
 			break;
 
@@ -2109,7 +2112,7 @@ static char mtdparts_help_text[] =
 	"'mtdids' - linux kernel mtd device id <-> u-boot device id mapping\n\n"
 	"mtdids=<idmap>[,<idmap>,...]\n\n"
 	"<idmap>    := <dev-id>=<mtd-id>\n"
-	"<dev-id>   := 'nand'|'nor'|'onenand'<dev-num>\n"
+	"<dev-id>   := 'nand'|'nor'|'onenand'|'spi-nand'<dev-num>\n"
 	"<dev-num>  := mtd device number, 0...\n"
 	"<mtd-id>   := unique device tag used by linux kernel to find mtd device (mtd->name)\n\n"
 	"'mtdparts' - partition list\n\n"
diff --git a/include/jffs2/load_kernel.h b/include/jffs2/load_kernel.h
index 1ddff062ad..9346d7ee9f 100644
--- a/include/jffs2/load_kernel.h
+++ b/include/jffs2/load_kernel.h
@@ -15,9 +15,12 @@
 #define MTD_DEV_TYPE_NOR	0x0001
 #define MTD_DEV_TYPE_NAND	0x0002
 #define MTD_DEV_TYPE_ONENAND	0x0004
+#define MTD_DEV_TYPE_SPINAND	0x0008
 
-#define MTD_DEV_TYPE(type) ((type == MTD_DEV_TYPE_NAND) ? "nand" :	\
-			(type == MTD_DEV_TYPE_ONENAND) ? "onenand" : "nor")
+#define MTD_DEV_TYPE(type) (type == MTD_DEV_TYPE_NAND ? "nand" :	\
+			    (type == MTD_DEV_TYPE_NOR ? "nor" :		\
+			     (type == MTD_DEV_TYPE_ONENAND ? "onenand" : \
+			      "spi-nand")))				\
 
 struct mtd_device {
 	struct list_head link;
-- 
2.14.1

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

* [U-Boot] [PATCH v6 23/27] cmd: mtdparts: add a generic 'mtdparts' parser
  2018-08-01  8:18 [U-Boot] [PATCH v6 00/27] SPI-NAND support Miquel Raynal
                   ` (21 preceding siblings ...)
  2018-08-01  8:18 ` [U-Boot] [PATCH v6 22/27] cmd: mtdparts: accept spi-nand devices Miquel Raynal
@ 2018-08-01  8:18 ` Miquel Raynal
  2018-08-01  8:18 ` [U-Boot] [PATCH v6 24/27] cmd: mtdparts: remove useless 'mtdparts=' prefix Miquel Raynal
                   ` (5 subsequent siblings)
  28 siblings, 0 replies; 41+ messages in thread
From: Miquel Raynal @ 2018-08-01  8:18 UTC (permalink / raw)
  To: u-boot

The current parser is very specific to U-Boot mtdparts implementation.
It does not use MTD structures like mtd_info and mtd_partition. Write
some kind of a wrapper around the current implementation to allow other
commands to benefit from this parsing in a user-friendly way.

This new command will allocate an mtd_partition array for each
successful call. This array must be freed after use by the caller.
The given 'mtdparts' buffer pointer will be moved forward to the next
MTD device (if any, it will point towards a '\0' character otherwise).

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
Acked-by: Jagan Teki <jagan@openedev.com>
---
 cmd/mtdparts.c                 | 71 ++++++++++++++++++++++++++++++++++++++++++
 include/linux/mtd/partitions.h |  3 ++
 2 files changed, 74 insertions(+)

diff --git a/cmd/mtdparts.c b/cmd/mtdparts.c
index f26a761c99..27e84db0e4 100644
--- a/cmd/mtdparts.c
+++ b/cmd/mtdparts.c
@@ -78,6 +78,7 @@
 #include <linux/ctype.h>
 #include <linux/err.h>
 #include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
 
 #if defined(CONFIG_CMD_NAND)
 #include <linux/mtd/rawnand.h>
@@ -705,6 +706,76 @@ static int part_parse(const char *const partdef, const char **ret, struct part_i
 	return 0;
 }
 
+int mtdparts_parse_part(struct mtd_info *parent, const char **_mtdparts,
+			struct mtd_partition **_parts, int *_nb_parts)
+{
+	const char *mtdparts = *_mtdparts;
+	struct part_info *part_legacy;
+	struct mtd_partition *parts;
+	int cur_off = 0, cur_sz = 0;
+	int nb_parts = 0;
+	char *names;
+	int ret, idx;
+
+	*_parts = NULL;
+	*_nb_parts = 0;
+
+	/* First, iterate over the partitions until we know their number */
+	while (mtdparts[0] != '\0' && mtdparts[0] != ';') {
+		ret = part_parse(mtdparts, &mtdparts, &part_legacy);
+		if (ret)
+			return ret;
+
+		nb_parts++;
+		free(part_legacy);
+	}
+
+	/* Allocate an array of partitions to give back to the caller */
+	parts = malloc((sizeof(*parts) + 20) * nb_parts);
+	names = (char *)&parts[nb_parts];
+	if (!parts) {
+		printf("Could not allocate enough space to save partitions meta-data\n");
+		return -ENOMEM;
+	}
+
+	/* Iterate again over each partition to save the data in our array */
+	for (idx = 0; idx < nb_parts; idx++) {
+		char *name;
+
+		ret = part_parse(*_mtdparts, _mtdparts, &part_legacy);
+		if (ret)
+			return ret;
+
+		name = &names[idx * 20];
+		strncpy(name, part_legacy->name, 20);
+		parts[idx].name = name;
+
+		parts[idx].size = part_legacy->size;
+		if (parts[idx].size == SIZE_REMAINING)
+			parts[idx].size = parent->size - cur_sz;
+		cur_sz += parts[idx].size;
+
+		parts[idx].offset = part_legacy->offset;
+		if (parts[idx].offset == OFFSET_NOT_SPECIFIED)
+			parts[idx].offset = cur_off;
+		cur_off += parts[idx].size;
+
+		parts[idx].mask_flags = part_legacy->mask_flags;
+		parts[idx].ecclayout = parent->ecclayout;
+
+		free(part_legacy);
+	}
+
+	/* Offset by one mtdparts to point to the next device if needed */
+	if (*_mtdparts[0] == ';')
+		_mtdparts++;
+
+	*_parts = parts;
+	*_nb_parts = nb_parts;
+
+	return 0;
+}
+
 /**
  * Check device number to be within valid range for given device type.
  *
diff --git a/include/linux/mtd/partitions.h b/include/linux/mtd/partitions.h
index ce0e8dbee4..0cf26ca945 100644
--- a/include/linux/mtd/partitions.h
+++ b/include/linux/mtd/partitions.h
@@ -87,4 +87,7 @@ int mtd_add_partition(struct mtd_info *master, const char *name,
 int mtd_del_partition(struct mtd_info *master, int partno);
 uint64_t mtd_get_device_size(const struct mtd_info *mtd);
 
+int mtdparts_parse_part(struct mtd_info *parent, const char **_mtdparts,
+			struct mtd_partition **_parts, int *_nb_parts);
+
 #endif
-- 
2.14.1

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

* [U-Boot] [PATCH v6 24/27] cmd: mtdparts: remove useless 'mtdparts=' prefix
  2018-08-01  8:18 [U-Boot] [PATCH v6 00/27] SPI-NAND support Miquel Raynal
                   ` (22 preceding siblings ...)
  2018-08-01  8:18 ` [U-Boot] [PATCH v6 23/27] cmd: mtdparts: add a generic 'mtdparts' parser Miquel Raynal
@ 2018-08-01  8:18 ` Miquel Raynal
  2018-08-01  8:18 ` [U-Boot] [PATCH v6 25/27] mtd: uclass: add probe function Miquel Raynal
                   ` (4 subsequent siblings)
  28 siblings, 0 replies; 41+ messages in thread
From: Miquel Raynal @ 2018-08-01  8:18 UTC (permalink / raw)
  To: u-boot

All U-Boot users must define the mtdparts environment variable with:
setenv mtdparts mtdparts=...

This is a pure software limitation and is a complete non-sense. Remove
this limitation but keep the backward compatibility.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
Acked-by: Jagan Teki <jagan@openedev.com>
---
 cmd/mtdparts.c | 17 ++++++-----------
 1 file changed, 6 insertions(+), 11 deletions(-)

diff --git a/cmd/mtdparts.c b/cmd/mtdparts.c
index 27e84db0e4..ef8588bd71 100644
--- a/cmd/mtdparts.c
+++ b/cmd/mtdparts.c
@@ -44,7 +44,7 @@
  *
  * 'mtdparts' - partition list
  *
- * mtdparts=mtdparts=<mtd-def>[;<mtd-def>...]
+ * mtdparts=[mtdparts=]<mtd-def>[;<mtd-def>...]
  *
  * <mtd-def>  := <mtd-id>:<part-def>[,<part-def>...]
  * <mtd-id>   := unique device tag used by linux kernel to find mtd device (mtd->name)
@@ -62,11 +62,11 @@
  *
  * 1 NOR Flash, with 1 single writable partition:
  * mtdids=nor0=edb7312-nor
- * mtdparts=mtdparts=edb7312-nor:-
+ * mtdparts=[mtdparts=]edb7312-nor:-
  *
  * 1 NOR Flash with 2 partitions, 1 NAND with one
  * mtdids=nor0=edb7312-nor,nand0=edb7312-nand
- * mtdparts=mtdparts=edb7312-nor:256k(ARMboot)ro,-(root);edb7312-nand:-(home)
+ * mtdparts=[mtdparts=]edb7312-nor:256k(ARMboot)ro,-(root);edb7312-nand:-(home)
  *
  */
 
@@ -1167,9 +1167,6 @@ static int generate_mtdparts(char *buf, u32 buflen)
 		return 0;
 	}
 
-	strcpy(p, "mtdparts=");
-	p += 9;
-
 	list_for_each(dentry, &devices) {
 		dev = list_entry(dentry, struct mtd_device, link);
 
@@ -1640,11 +1637,9 @@ static int parse_mtdparts(const char *const mtdparts)
 	if (!p)
 		p = mtdparts;
 
-	if (strncmp(p, "mtdparts=", 9) != 0) {
-		printf("mtdparts variable doesn't start with 'mtdparts='\n");
-		return err;
-	}
-	p += 9;
+	/* Skip the useless prefix, if any */
+	if (strncmp(p, "mtdparts=", 9) == 0)
+		p += 9;
 
 	while (*p != '\0') {
 		err = 1;
-- 
2.14.1

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

* [U-Boot] [PATCH v6 25/27] mtd: uclass: add probe function
  2018-08-01  8:18 [U-Boot] [PATCH v6 00/27] SPI-NAND support Miquel Raynal
                   ` (23 preceding siblings ...)
  2018-08-01  8:18 ` [U-Boot] [PATCH v6 24/27] cmd: mtdparts: remove useless 'mtdparts=' prefix Miquel Raynal
@ 2018-08-01  8:18 ` Miquel Raynal
  2018-08-01  8:18 ` [U-Boot] [PATCH v6 26/27] cmd: mtd: add 'mtd' command Miquel Raynal
                   ` (3 subsequent siblings)
  28 siblings, 0 replies; 41+ messages in thread
From: Miquel Raynal @ 2018-08-01  8:18 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>
Acked-by: Jagan Teki <jagan@openedev.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 9ca049c437..9a9470410c 100644
--- a/drivers/mtd/mtd-uclass.c
+++ b/drivers/mtd/mtd-uclass.c
@@ -5,6 +5,7 @@
 
 #include <common.h>
 #include <dm.h>
+#include <dm/device-internal.h>
 #include <errno.h>
 #include <mtd.h>
 
@@ -13,6 +14,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 6771ee2586..7dd45bde65 100644
--- a/include/linux/mtd/mtd.h
+++ b/include/linux/mtd/mtd.h
@@ -533,5 +533,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] 41+ messages in thread

* [U-Boot] [PATCH v6 26/27] cmd: mtd: add 'mtd' command
  2018-08-01  8:18 [U-Boot] [PATCH v6 00/27] SPI-NAND support Miquel Raynal
                   ` (24 preceding siblings ...)
  2018-08-01  8:18 ` [U-Boot] [PATCH v6 25/27] mtd: uclass: add probe function Miquel Raynal
@ 2018-08-01  8:18 ` Miquel Raynal
  2018-08-01  8:18 ` [U-Boot] [PATCH v6 27/27] cmd: mtdparts: try to probe the MTD devices as a fallback Miquel Raynal
                   ` (2 subsequent siblings)
  28 siblings, 0 replies; 41+ messages in thread
From: Miquel Raynal @ 2018-08-01  8:18 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>
Acked-by: Jagan Teki <jagan@openedev.com>
---
 cmd/Kconfig             |   7 +
 cmd/Makefile            |   1 +
 cmd/mtd.c               | 392 ++++++++++++++++++++++++++++++++++++++++++++++++
 drivers/mtd/Makefile    |   2 +-
 include/linux/mtd/mtd.h |   1 +
 5 files changed, 402 insertions(+), 1 deletion(-)
 create mode 100644 cmd/mtd.c

diff --git a/cmd/Kconfig b/cmd/Kconfig
index 0cf530d923..45ead0ffce 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -848,6 +848,13 @@ config CMD_MMC_SWRITE
 	  Enable support for the "mmc swrite" command to write Android sparse
 	  images to eMMC.
 
+config CMD_MTD
+	bool "mtd"
+	depends on CMD_MTDPARTS
+	select MTD_PARTITIONS
+	help
+	  MTD commands support.
+
 config CMD_NAND
 	bool "nand"
 	default y if NAND_SUNXI
diff --git a/cmd/Makefile b/cmd/Makefile
index 323f1fd2c7..32fd102189 100644
--- a/cmd/Makefile
+++ b/cmd/Makefile
@@ -90,6 +90,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..221b12500f
--- /dev/null
+++ b/cmd/mtd.c
@@ -0,0 +1,392 @@
+// 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 <command.h>
+#include <common.h>
+#include <console.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <malloc.h>
+#include <mapmem.h>
+#include <mtd.h>
+#include <dm/device.h>
+#include <dm/uclass-internal.h>
+
+static void mtd_dump_buf(u8 *buf, uint len, uint offset)
+{
+	int i, j;
+
+	for (i = 0; i < len; ) {
+		printf("0x%08x:\t", offset + 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)
+{
+	/* Device */
+	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");
+
+	/* MTD information */
+	printf("\t> type: ");
+	switch (mtd->type) {
+	case MTD_RAM:
+		printf("RAM\n");
+		break;
+	case MTD_ROM:
+		printf("ROM\n");
+		break;
+	case MTD_NORFLASH:
+		printf("NOR flash\n");
+		break;
+	case MTD_NANDFLASH:
+		printf("NAND flash\n");
+		break;
+	case MTD_DATAFLASH:
+		printf("Data flash\n");
+		break;
+	case MTD_UBIVOLUME:
+		printf("UBI volume\n");
+		break;
+	case MTD_MLCNANDFLASH:
+		printf("MLC NAND flash\n");
+		break;
+	case MTD_ABSENT:
+	default:
+		printf("Unknown\n");
+		break;
+	}
+
+	printf("\t> Size: 0x%llx bytes\n", mtd->size);
+	printf("\t> Block: 0x%x bytes\n", mtd->erasesize);
+	printf("\t> Min I/O: 0x%x bytes\n", mtd->writesize);
+
+	if (mtd->oobsize) {
+		printf("\t> OOB size: %u bytes\n", mtd->oobsize);
+		printf("\t> OOB available: %u bytes\n", mtd->oobavail);
+	}
+
+	if (mtd->ecc_strength) {
+		printf("\t> ECC strength: %u bits\n", mtd->ecc_strength);
+		printf("\t> ECC step size: %u bytes\n", mtd->ecc_step_size);
+		printf("\t> Bitflip threshold: %u bits\n",
+		       mtd->bitflip_threshold);
+	}
+}
+
+int mtd_probe_devices(void)
+{
+	const char *mtdparts = env_get("mtdparts");
+	struct udevice *dev;
+	int idx = 0;
+
+	/* Probe devices with DM compliant drivers */
+	while (!uclass_find_device(UCLASS_MTD, idx, &dev) && dev) {
+		mtd_probe(dev);
+		idx++;
+	}
+
+	/* Create the partitions defined in mtdparts, here the fun begins */
+
+	/* Ignore the extra 'mtdparts=' prefix if any */
+	if (strstr(mtdparts, "mtdparts="))
+		mtdparts += 9;
+
+	/* For each MTD device in mtdparts */
+	while (mtdparts[0] != '\0') {
+		struct mtd_partition *parts;
+		struct mtd_info *parent;
+		char mtdname[20];
+		int mtdname_len, len, ret;
+
+		mtdname_len = strchr(mtdparts, ':') - mtdparts;
+		strncpy(mtdname, mtdparts, mtdname_len);
+		mtdname[mtdname_len] = '\0';
+		/* Move the pointer forward (including the ':') */
+		mtdparts += mtdname_len + 1;
+		parent = get_mtd_device_nm(mtdname);
+		if (IS_ERR_OR_NULL(parent)) {
+			printf("No device named %s\n", mtdname);
+			return -EINVAL;
+		}
+
+		/*
+		 * Parse the MTD device partitions. It will update the mtdparts
+		 * pointer, create an array of parts (that must be freed), and
+		 * return the number of partition structures in the array.
+		 */
+		ret = mtdparts_parse_part(parent, &mtdparts, &parts, &len);
+		if (ret) {
+			printf("Could not parse device %s\n", mtdname);
+			return -EINVAL;
+		}
+
+		/*
+		 * If there is already an MTD device named after the first
+		 * partition name, this is probably because the registration
+		 * already happened: don't add the partitions again.
+		 */
+		if (len && !IS_ERR_OR_NULL(get_mtd_device_nm(parts[0].name)))
+			continue;
+
+		add_mtd_partitions(parent, parts, len);
+		free(parts);
+	}
+
+	return 0;
+}
+
+static uint mtd_len_to_pages(struct mtd_info *mtd, u64 len)
+{
+	do_div(len, mtd->writesize);
+
+	return len;
+}
+
+static bool mtd_is_aligned_with_min_io_size(struct mtd_info *mtd, u64 size)
+{
+	return do_div(size, mtd->writesize);
+}
+
+static bool mtd_is_aligned_with_block_size(struct mtd_info *mtd, u64 size)
+{
+	return do_div(size, mtd->erasesize);
+}
+
+static int do_mtd_list(void)
+{
+	struct mtd_info *mtd;
+	int dev_nb = 0;
+
+	/* Ensure all devices (and their partitions) are probed */
+	mtd_probe_devices();
+
+	printf("List of MTD devices:\n");
+	mtd_for_each_device(mtd) {
+		mtd_show_device(mtd);
+		dev_nb++;
+	}
+
+	if (!dev_nb) {
+		printf("No MTD device found\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int do_mtd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	struct mtd_info *mtd;
+	const char *cmd;
+	char *mtdname;
+	int ret;
+
+	/* All MTD commands need at least two arguments */
+	if (argc < 2)
+		return CMD_RET_USAGE;
+
+	/* Parse the command name and its optional suffixes */
+	cmd = argv[1];
+
+	/* List the MTD devices if that is what the user wants */
+	if (strcmp(cmd, "list") == 0)
+		return do_mtd_list();
+
+	/*
+	 * The remaining commands require also@least a device ID.
+	 * Check the selected device is valid. Ensure it is probed.
+	 */
+	if (argc < 3)
+		return CMD_RET_USAGE;
+
+	mtdname = argv[2];
+	mtd = get_mtd_device_nm(mtdname);
+	if (IS_ERR_OR_NULL(mtd)) {
+		mtd_probe_devices();
+		mtd = get_mtd_device_nm(mtdname);
+		if (IS_ERR_OR_NULL(mtd)) {
+			printf("MTD device %s not found, ret %ld\n",
+			       mtdname, PTR_ERR(mtd));
+			return 1;
+		}
+	}
+
+	argc -= 3;
+	argv += 3;
+
+	/* Do the parsing */
+	if (!strncmp(cmd, "read", 4) || !strncmp(cmd, "dump", 4) ||
+	    !strncmp(cmd, "write", 5)) {
+		struct mtd_oob_ops io_op = {};
+		bool dump, read, raw, woob;
+		uint user_addr = 0;
+		uint nb_pages;
+		u8 *buf;
+		u64 off, len, default_len;
+		u32 oob_len;
+
+		dump = !strncmp(cmd, "dump", 4);
+		read = dump || !strncmp(cmd, "read", 4);
+		raw = strstr(cmd, ".raw");
+		woob = strstr(cmd, ".oob");
+
+		if (!dump) {
+			if (!argc)
+				return CMD_RET_USAGE;
+
+			user_addr = simple_strtoul(argv[0], NULL, 16);
+			argc--;
+			argv++;
+		}
+
+		default_len = dump ? mtd->writesize : mtd->size;
+		off = argc > 0 ? simple_strtoul(argv[0], NULL, 16) : 0;
+		len = argc > 1 ? simple_strtoul(argv[1], NULL, 16) :
+				 default_len;
+		nb_pages = mtd_len_to_pages(mtd, len);
+		oob_len = woob ? nb_pages * mtd->oobsize : 0;
+
+		if (mtd_is_aligned_with_min_io_size(mtd, off)) {
+			printf("Offset not aligned with a page (0x%x)\n",
+			       mtd->writesize);
+			return -EINVAL;
+		}
+
+		if (mtd_is_aligned_with_min_io_size(mtd, len)) {
+			printf("Size not a multiple of a page (0x%x)\n",
+			       mtd->writesize);
+			return -EINVAL;
+		}
+
+		if (dump)
+			buf = kmalloc(len + oob_len, GFP_KERNEL);
+		else
+			buf = map_sysmem(user_addr, 0);
+
+		if (!buf) {
+			printf("Could not map/allocate the user buffer\n");
+			return -ENOMEM;
+		}
+
+		printf("%s %lldB (%d page(s)) at offset 0x%08llx%s%s\n",
+		       read ? "Reading" : "Writing", len, nb_pages, off,
+		       raw ? " [raw]" : "", woob ? " [oob]" : "");
+
+		io_op.mode = raw ? MTD_OPS_RAW : MTD_OPS_AUTO_OOB;
+		io_op.len = len;
+		io_op.ooblen = oob_len;
+		io_op.datbuf = buf;
+		io_op.oobbuf = woob ? &buf[len] : NULL;
+
+		if (read)
+			ret = mtd_read_oob(mtd, off, &io_op);
+		else
+			ret = mtd_write_oob(mtd, off, &io_op);
+
+		if (ret) {
+			printf("%s on %s failed with error %d\n",
+			       read ? "Read" : "Write", mtd->name, ret);
+			return ret;
+		}
+
+		if (dump) {
+			uint page;
+
+			for (page = 0; page < nb_pages; page++) {
+				u64 data_off = page * mtd->writesize;
+
+				printf("\nDump %d data bytes from 0x%08llx:\n",
+				       mtd->writesize, data_off);
+				mtd_dump_buf(buf, mtd->writesize, data_off);
+
+				if (woob) {
+					u64 oob_off = page * mtd->oobsize;
+
+					printf("Dump %d OOB bytes from page at 0x%08llx:\n",
+					       mtd->oobsize, data_off);
+					mtd_dump_buf(&buf[len + oob_off],
+						     mtd->oobsize, 0);
+				}
+			}
+		}
+
+		if (dump)
+			kfree(buf);
+		else
+			unmap_sysmem(buf);
+
+	} else if (!strcmp(cmd, "erase")) {
+		bool scrub = strstr(cmd, ".dontskipbad");
+		struct erase_info erase_op = {};
+		u64 off, len;
+
+		off = argc > 0 ? simple_strtoul(argv[0], NULL, 16) : 0;
+		len = argc > 1 ? simple_strtoul(argv[1], NULL, 16) : mtd->size;
+
+		if (mtd_is_aligned_with_block_size(mtd, off)) {
+			printf("Offset not aligned with a block (0x%x)\n",
+			       mtd->erasesize);
+			return -EINVAL;
+		}
+
+		if (mtd_is_aligned_with_block_size(mtd, len)) {
+			printf("Size not a multiple of a block (0x%x)\n",
+			       mtd->erasesize);
+			return -EINVAL;
+		}
+
+		erase_op.mtd = mtd;
+		erase_op.addr = off;
+		erase_op.len = len;
+		erase_op.scrub = scrub;
+
+		ret = mtd_erase(mtd, &erase_op);
+	} else {
+		return CMD_RET_USAGE;
+	}
+
+	return ret;
+}
+
+static char mtd_help_text[] =
+#ifdef CONFIG_SYS_LONGHELP
+	"- generic operations on memory technology devices\n\n"
+	"mtd list\n"
+	"mtd read[.raw][.oob]    <name> <addr> [<off> [<size>]]\n"
+	"mtd dump[.raw][.oob]    <name>        [<off> [<size>]]\n"
+	"mtd write[.raw][.oob]   <name> <addr> [<off> [<size>]]\n"
+	"mtd erase[.dontskipbad] <name>        [<off> [<size>]]\n"
+	"\n"
+	"With:\n"
+	"\t<name>: NAND partition/chip name\n"
+	"\t<addr>: user address from/to which data will be retrieved/stored\n"
+	"\t<off>: offset in <name> in bytes (default: start of the part)\n"
+	"\t\t* must be block-aligned for erase\n"
+	"\t\t* must be page-aligned otherwise\n"
+	"\t<size>: length of the operation in bytes (default: the entire device)\n"
+	"\t\t* must be a multiple of a block for erase\n"
+	"\t\t* must be a multiple of a page otherwise (special case: default is a page with dump)\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 cdf515256a..22ceda93c0 100644
--- a/drivers/mtd/Makefile
+++ b/drivers/mtd/Makefile
@@ -3,7 +3,7 @@
 # (C) Copyright 2000-2007
 # Wolfgang Denk, DENX Software Engineering, wd at denx.de.
 
-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
diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
index 7dd45bde65..4ca5d764d7 100644
--- a/include/linux/mtd/mtd.h
+++ b/include/linux/mtd/mtd.h
@@ -535,6 +535,7 @@ void mtd_get_len_incl_bad(struct mtd_info *mtd, uint64_t offset,
 			  int *truncated);
 
 int mtd_probe(struct udevice *dev);
+int mtd_probe_devices(void);
 
 #endif
 #endif /* __MTD_MTD_H__ */
-- 
2.14.1

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

* [U-Boot] [PATCH v6 27/27] cmd: mtdparts: try to probe the MTD devices as a fallback
  2018-08-01  8:18 [U-Boot] [PATCH v6 00/27] SPI-NAND support Miquel Raynal
                   ` (25 preceding siblings ...)
  2018-08-01  8:18 ` [U-Boot] [PATCH v6 26/27] cmd: mtd: add 'mtd' command Miquel Raynal
@ 2018-08-01  8:18 ` Miquel Raynal
  2018-08-03  8:27 ` [U-Boot] [PATCH v6 00/27] SPI-NAND support Miquel Raynal
  2018-08-06 17:45 ` Stefan Roese
  28 siblings, 0 replies; 41+ messages in thread
From: Miquel Raynal @ 2018-08-01  8:18 UTC (permalink / raw)
  To: u-boot

Current implementation of mtdparts command errors out if the desired MTD
device is not found. Fallback to the new probe function in this case
before erroring out.

This will the save the user the need to call something like 'mtd list'
before mtdparts.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
Acked-by: Jagan Teki <jagan@openedev.com>
---
 cmd/mtdparts.c | 12 +++++++++---
 1 file changed, 9 insertions(+), 3 deletions(-)

diff --git a/cmd/mtdparts.c b/cmd/mtdparts.c
index ef8588bd71..76f0138e4d 100644
--- a/cmd/mtdparts.c
+++ b/cmd/mtdparts.c
@@ -305,9 +305,15 @@ static int get_mtd_info(u8 type, u8 num, struct mtd_info **mtd)
 
 	sprintf(mtd_dev, "%s%d", MTD_DEV_TYPE(type), num);
 	*mtd = get_mtd_device_nm(mtd_dev);
-	if (IS_ERR(*mtd)) {
-		printf("Device %s not found!\n", mtd_dev);
-		return 1;
+	if (IS_ERR_OR_NULL(*mtd)) {
+#ifdef CONFIG_CMD_MTD
+		mtd_probe_devices();
+		*mtd = get_mtd_device_nm(mtd_dev);
+#endif
+		if (IS_ERR_OR_NULL(*mtd)) {
+			printf("Device %s not found!\n", mtd_dev);
+			return 1;
+		}
 	}
 	put_mtd_device(*mtd);
 
-- 
2.14.1

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

* [U-Boot] [PATCH v6 00/27] SPI-NAND support
  2018-08-01  8:18 [U-Boot] [PATCH v6 00/27] SPI-NAND support Miquel Raynal
                   ` (26 preceding siblings ...)
  2018-08-01  8:18 ` [U-Boot] [PATCH v6 27/27] cmd: mtdparts: try to probe the MTD devices as a fallback Miquel Raynal
@ 2018-08-03  8:27 ` Miquel Raynal
  2018-08-03  9:50   ` Jagan Teki
  2018-08-06 17:45 ` Stefan Roese
  28 siblings, 1 reply; 41+ messages in thread
From: Miquel Raynal @ 2018-08-03  8:27 UTC (permalink / raw)
  To: u-boot

Hi Jagan, Tom,

Miquel Raynal <miquel.raynal@bootlin.com> wrote on Wed,  1 Aug 2018
10:18:21 +0200:

> During the last months, Boris Brezillon shared his work to support
> serial flashes within Linux. First, he delivered (and merged) a new
> layer called spi-mem. He also initiated in Linux MTD subsystem the move
> of all 'raw' NAND related code to a raw/ subdirectory, adding at the
> same time a NAND core that would be shared with all NAND devices. Then,
> he contributed a generic SPI-NAND driver, making use of this NAND core,
> as well as some vendor code to drive a few chips.
> 
> On top of this work, I added an 'mtd' U-Boot command to handle all sort
> of MTD devices. This should become the default command instead of having
> one per flash flavor ('sf', 'nand', 'spi-nand' ?).
> 
> The series has been tested on an Ocelot board PCB123 (VSC7514),
> featuring a Macronix SPI NAND chip.
> 
> TL;DR: the series contains:
> - A few patches from Linux to resynchronize some areas of the MTD layer.
> - Various fixes and re-organization of the MTD subsystem.
> - The introduction of the SPI-mem interface.
> - The addition of the generic SPI-NAND driver (and its bindings).
> - Several SPI NAND chip drivers (Macronix, Micron, Winbond).
> - A new 'mtd' command.
> - Support for spi-nand devices in mtdparts.
> 
> To test your SPI-NAND device with U-Boot simply follow these lines:
> 
> > setenv mtdparts mtdparts=spi-nand0:1m(foo),-(bar)
> > setenv mtdids spi-nand0=spi-nand0
> > mtdparts             # show the spi-nand device partitions
> > ubi part bar         # create a static UBI volume in the bar partition  
> 
> Thanks,
> Miquèl
> 
> Changes since v5:
> -----------------
> * Included Boris fixup about the build issues.
> * Added Rb/Ab tags from Jagan on patchs 20/21.

I can't see a pull request flow on U-Boot ML, I suppose you use a
different mean for that purpose.

Jagan, is this version OK? Is it part of your PR?

Thanks,
Miquèl

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

* [U-Boot] [PATCH v6 00/27] SPI-NAND support
  2018-08-03  8:27 ` [U-Boot] [PATCH v6 00/27] SPI-NAND support Miquel Raynal
@ 2018-08-03  9:50   ` Jagan Teki
  2018-08-03 12:08     ` Jagan Teki
  0 siblings, 1 reply; 41+ messages in thread
From: Jagan Teki @ 2018-08-03  9:50 UTC (permalink / raw)
  To: u-boot

On Fri, Aug 3, 2018 at 1:57 PM, Miquel Raynal <miquel.raynal@bootlin.com> wrote:
> Hi Jagan, Tom,
>
> Miquel Raynal <miquel.raynal@bootlin.com> wrote on Wed,  1 Aug 2018
> 10:18:21 +0200:
>
>> During the last months, Boris Brezillon shared his work to support
>> serial flashes within Linux. First, he delivered (and merged) a new
>> layer called spi-mem. He also initiated in Linux MTD subsystem the move
>> of all 'raw' NAND related code to a raw/ subdirectory, adding at the
>> same time a NAND core that would be shared with all NAND devices. Then,
>> he contributed a generic SPI-NAND driver, making use of this NAND core,
>> as well as some vendor code to drive a few chips.
>>
>> On top of this work, I added an 'mtd' U-Boot command to handle all sort
>> of MTD devices. This should become the default command instead of having
>> one per flash flavor ('sf', 'nand', 'spi-nand' ?).
>>
>> The series has been tested on an Ocelot board PCB123 (VSC7514),
>> featuring a Macronix SPI NAND chip.
>>
>> TL;DR: the series contains:
>> - A few patches from Linux to resynchronize some areas of the MTD layer.
>> - Various fixes and re-organization of the MTD subsystem.
>> - The introduction of the SPI-mem interface.
>> - The addition of the generic SPI-NAND driver (and its bindings).
>> - Several SPI NAND chip drivers (Macronix, Micron, Winbond).
>> - A new 'mtd' command.
>> - Support for spi-nand devices in mtdparts.
>>
>> To test your SPI-NAND device with U-Boot simply follow these lines:
>>
>> > setenv mtdparts mtdparts=spi-nand0:1m(foo),-(bar)
>> > setenv mtdids spi-nand0=spi-nand0
>> > mtdparts             # show the spi-nand device partitions
>> > ubi part bar         # create a static UBI volume in the bar partition
>>
>> Thanks,
>> Miquèl
>>
>> Changes since v5:
>> -----------------
>> * Included Boris fixup about the build issues.
>> * Added Rb/Ab tags from Jagan on patchs 20/21.
>
> I can't see a pull request flow on U-Boot ML, I suppose you use a
> different mean for that purpose.
>
> Jagan, is this version OK? Is it part of your PR?

Travis is going on [1], will send PR once all fine.

[1] https://travis-ci.org/openedev/u-boot-amarula/builds/411596788

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

* [U-Boot] [PATCH v6 00/27] SPI-NAND support
  2018-08-03  9:50   ` Jagan Teki
@ 2018-08-03 12:08     ` Jagan Teki
  2018-08-04  7:23       ` Miquel Raynal
  0 siblings, 1 reply; 41+ messages in thread
From: Jagan Teki @ 2018-08-03 12:08 UTC (permalink / raw)
  To: u-boot

On Fri, Aug 3, 2018 at 3:20 PM, Jagan Teki <jagan@amarulasolutions.com> wrote:
> On Fri, Aug 3, 2018 at 1:57 PM, Miquel Raynal <miquel.raynal@bootlin.com> wrote:
>> Hi Jagan, Tom,
>>
>> Miquel Raynal <miquel.raynal@bootlin.com> wrote on Wed,  1 Aug 2018
>> 10:18:21 +0200:
>>
>>> During the last months, Boris Brezillon shared his work to support
>>> serial flashes within Linux. First, he delivered (and merged) a new
>>> layer called spi-mem. He also initiated in Linux MTD subsystem the move
>>> of all 'raw' NAND related code to a raw/ subdirectory, adding at the
>>> same time a NAND core that would be shared with all NAND devices. Then,
>>> he contributed a generic SPI-NAND driver, making use of this NAND core,
>>> as well as some vendor code to drive a few chips.
>>>
>>> On top of this work, I added an 'mtd' U-Boot command to handle all sort
>>> of MTD devices. This should become the default command instead of having
>>> one per flash flavor ('sf', 'nand', 'spi-nand' ?).
>>>
>>> The series has been tested on an Ocelot board PCB123 (VSC7514),
>>> featuring a Macronix SPI NAND chip.
>>>
>>> TL;DR: the series contains:
>>> - A few patches from Linux to resynchronize some areas of the MTD layer.
>>> - Various fixes and re-organization of the MTD subsystem.
>>> - The introduction of the SPI-mem interface.
>>> - The addition of the generic SPI-NAND driver (and its bindings).
>>> - Several SPI NAND chip drivers (Macronix, Micron, Winbond).
>>> - A new 'mtd' command.
>>> - Support for spi-nand devices in mtdparts.
>>>
>>> To test your SPI-NAND device with U-Boot simply follow these lines:
>>>
>>> > setenv mtdparts mtdparts=spi-nand0:1m(foo),-(bar)
>>> > setenv mtdids spi-nand0=spi-nand0
>>> > mtdparts             # show the spi-nand device partitions
>>> > ubi part bar         # create a static UBI volume in the bar partition
>>>
>>> Thanks,
>>> Miquèl
>>>
>>> Changes since v5:
>>> -----------------
>>> * Included Boris fixup about the build issues.
>>> * Added Rb/Ab tags from Jagan on patchs 20/21.
>>
>> I can't see a pull request flow on U-Boot ML, I suppose you use a
>> different mean for that purpose.
>>
>> Jagan, is this version OK? Is it part of your PR?
>
> Travis is going on [1], will send PR once all fine.
>
> [1] https://travis-ci.org/openedev/u-boot-amarula/builds/411596788

There are some build issues, not quite sure whether it relates. please
look into it.

[2] https://travis-ci.org/openedev/u-boot-amarula/jobs/411596814
[3] https://travis-ci.org/openedev/u-boot-amarula/jobs/411596815

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

* [U-Boot] [PATCH v6 00/27] SPI-NAND support
  2018-08-03 12:08     ` Jagan Teki
@ 2018-08-04  7:23       ` Miquel Raynal
  2018-08-04  8:34         ` Boris Brezillon
  2018-08-07 14:39         ` Daniel Schwierzeck
  0 siblings, 2 replies; 41+ messages in thread
From: Miquel Raynal @ 2018-08-04  7:23 UTC (permalink / raw)
  To: u-boot

Hi Jagan,

Jagan Teki <jagan@amarulasolutions.com> wrote on Fri, 3 Aug 2018
17:38:33 +0530:

> On Fri, Aug 3, 2018 at 3:20 PM, Jagan Teki <jagan@amarulasolutions.com> wrote:
> > On Fri, Aug 3, 2018 at 1:57 PM, Miquel Raynal <miquel.raynal@bootlin.com> wrote:  
> >> Hi Jagan, Tom,
> >>
> >> Miquel Raynal <miquel.raynal@bootlin.com> wrote on Wed,  1 Aug 2018
> >> 10:18:21 +0200:
> >>  
> >>> During the last months, Boris Brezillon shared his work to support
> >>> serial flashes within Linux. First, he delivered (and merged) a new
> >>> layer called spi-mem. He also initiated in Linux MTD subsystem the move
> >>> of all 'raw' NAND related code to a raw/ subdirectory, adding at the
> >>> same time a NAND core that would be shared with all NAND devices. Then,
> >>> he contributed a generic SPI-NAND driver, making use of this NAND core,
> >>> as well as some vendor code to drive a few chips.
> >>>
> >>> On top of this work, I added an 'mtd' U-Boot command to handle all sort
> >>> of MTD devices. This should become the default command instead of having
> >>> one per flash flavor ('sf', 'nand', 'spi-nand' ?).
> >>>
> >>> The series has been tested on an Ocelot board PCB123 (VSC7514),
> >>> featuring a Macronix SPI NAND chip.
> >>>
> >>> TL;DR: the series contains:
> >>> - A few patches from Linux to resynchronize some areas of the MTD layer.
> >>> - Various fixes and re-organization of the MTD subsystem.
> >>> - The introduction of the SPI-mem interface.
> >>> - The addition of the generic SPI-NAND driver (and its bindings).
> >>> - Several SPI NAND chip drivers (Macronix, Micron, Winbond).
> >>> - A new 'mtd' command.
> >>> - Support for spi-nand devices in mtdparts.
> >>>
> >>> To test your SPI-NAND device with U-Boot simply follow these lines:
> >>>  
> >>> > setenv mtdparts mtdparts=spi-nand0:1m(foo),-(bar)
> >>> > setenv mtdids spi-nand0=spi-nand0
> >>> > mtdparts             # show the spi-nand device partitions
> >>> > ubi part bar         # create a static UBI volume in the bar partition  
> >>>
> >>> Thanks,
> >>> Miquèl
> >>>
> >>> Changes since v5:
> >>> -----------------
> >>> * Included Boris fixup about the build issues.
> >>> * Added Rb/Ab tags from Jagan on patchs 20/21.  
> >>
> >> I can't see a pull request flow on U-Boot ML, I suppose you use a
> >> different mean for that purpose.
> >>
> >> Jagan, is this version OK? Is it part of your PR?  
> >
> > Travis is going on [1], will send PR once all fine.
> >
> > [1] https://travis-ci.org/openedev/u-boot-amarula/builds/411596788  
> 
> There are some build issues, not quite sure whether it relates. please
> look into it.

Thanks for the reports.

> 
> [2] https://travis-ci.org/openedev/u-boot-amarula/jobs/411596814
> [3] https://travis-ci.org/openedev/u-boot-amarula/jobs/411596815

Boris supposedly fixed all the build issues related to my changes (I
don't think the "missing interrupt parent" in a DTS file is related),
please pull his branch [1].

The fixes are under the form of fixups if you wanna check them.
Otherwise you can just 'rebase -i --autosquash' to automatically squash
them with the commit introducing the regression.

[1] https://travis-ci.org/openedev/u-boot-amarula/jobs/411596814


Thanks,
Miquèl

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

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

* [U-Boot] [PATCH v6 00/27] SPI-NAND support
  2018-08-04  7:23       ` Miquel Raynal
@ 2018-08-04  8:34         ` Boris Brezillon
  2018-08-04  9:59           ` Miquel Raynal
  2018-08-07 14:39         ` Daniel Schwierzeck
  1 sibling, 1 reply; 41+ messages in thread
From: Boris Brezillon @ 2018-08-04  8:34 UTC (permalink / raw)
  To: u-boot

On Sat, 4 Aug 2018 09:23:05 +0200
Miquel Raynal <miquel.raynal@bootlin.com> wrote:

> Hi Jagan,
> 
> Jagan Teki <jagan@amarulasolutions.com> wrote on Fri, 3 Aug 2018
> 17:38:33 +0530:
> 
> > On Fri, Aug 3, 2018 at 3:20 PM, Jagan Teki <jagan@amarulasolutions.com> wrote:  
> > > On Fri, Aug 3, 2018 at 1:57 PM, Miquel Raynal <miquel.raynal@bootlin.com> wrote:    
> > >> Hi Jagan, Tom,
> > >>
> > >> Miquel Raynal <miquel.raynal@bootlin.com> wrote on Wed,  1 Aug 2018
> > >> 10:18:21 +0200:
> > >>    
> > >>> During the last months, Boris Brezillon shared his work to support
> > >>> serial flashes within Linux. First, he delivered (and merged) a new
> > >>> layer called spi-mem. He also initiated in Linux MTD subsystem the move
> > >>> of all 'raw' NAND related code to a raw/ subdirectory, adding at the
> > >>> same time a NAND core that would be shared with all NAND devices. Then,
> > >>> he contributed a generic SPI-NAND driver, making use of this NAND core,
> > >>> as well as some vendor code to drive a few chips.
> > >>>
> > >>> On top of this work, I added an 'mtd' U-Boot command to handle all sort
> > >>> of MTD devices. This should become the default command instead of having
> > >>> one per flash flavor ('sf', 'nand', 'spi-nand' ?).
> > >>>
> > >>> The series has been tested on an Ocelot board PCB123 (VSC7514),
> > >>> featuring a Macronix SPI NAND chip.
> > >>>
> > >>> TL;DR: the series contains:
> > >>> - A few patches from Linux to resynchronize some areas of the MTD layer.
> > >>> - Various fixes and re-organization of the MTD subsystem.
> > >>> - The introduction of the SPI-mem interface.
> > >>> - The addition of the generic SPI-NAND driver (and its bindings).
> > >>> - Several SPI NAND chip drivers (Macronix, Micron, Winbond).
> > >>> - A new 'mtd' command.
> > >>> - Support for spi-nand devices in mtdparts.
> > >>>
> > >>> To test your SPI-NAND device with U-Boot simply follow these lines:
> > >>>    
> > >>> > setenv mtdparts mtdparts=spi-nand0:1m(foo),-(bar)
> > >>> > setenv mtdids spi-nand0=spi-nand0
> > >>> > mtdparts             # show the spi-nand device partitions
> > >>> > ubi part bar         # create a static UBI volume in the bar partition    
> > >>>
> > >>> Thanks,
> > >>> Miquèl
> > >>>
> > >>> Changes since v5:
> > >>> -----------------
> > >>> * Included Boris fixup about the build issues.
> > >>> * Added Rb/Ab tags from Jagan on patchs 20/21.    
> > >>
> > >> I can't see a pull request flow on U-Boot ML, I suppose you use a
> > >> different mean for that purpose.
> > >>
> > >> Jagan, is this version OK? Is it part of your PR?    
> > >
> > > Travis is going on [1], will send PR once all fine.
> > >
> > > [1] https://travis-ci.org/openedev/u-boot-amarula/builds/411596788    
> > 
> > There are some build issues, not quite sure whether it relates. please
> > look into it.  
> 
> Thanks for the reports.
> 
> > 
> > [2] https://travis-ci.org/openedev/u-boot-amarula/jobs/411596814
> > [3] https://travis-ci.org/openedev/u-boot-amarula/jobs/411596815  
> 
> Boris supposedly fixed all the build issues related to my changes (I
> don't think the "missing interrupt parent" in a DTS file is related),
> please pull his branch [1].
> 
> The fixes are under the form of fixups if you wanna check them.
> Otherwise you can just 'rebase -i --autosquash' to automatically squash
> them with the commit introducing the regression.

One more thing, if you want to make things bisectable patch 6 ("mtd: fix
build issue with includes") and it's fixup should be squashed in patch 5
("mtd: add get/set of_node/flash_node helpers"), because the build
failure you're fixing in patch 6 is introduced by patch 5.

> 
> [1] https://travis-ci.org/openedev/u-boot-amarula/jobs/411596814

You mean

[1]https://github.com/bbrezillon/u-boot/commits/wip-spi

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

* [U-Boot] [PATCH v6 00/27] SPI-NAND support
  2018-08-04  8:34         ` Boris Brezillon
@ 2018-08-04  9:59           ` Miquel Raynal
  2018-08-06 17:50             ` Jagan Teki
  0 siblings, 1 reply; 41+ messages in thread
From: Miquel Raynal @ 2018-08-04  9:59 UTC (permalink / raw)
  To: u-boot

Hi Boris,

Boris Brezillon <boris.brezillon@bootlin.com> wrote on Sat, 4 Aug 2018
10:34:55 +0200:

> On Sat, 4 Aug 2018 09:23:05 +0200
> Miquel Raynal <miquel.raynal@bootlin.com> wrote:
> 
> > Hi Jagan,
> > 
> > Jagan Teki <jagan@amarulasolutions.com> wrote on Fri, 3 Aug 2018
> > 17:38:33 +0530:
> >   
> > > On Fri, Aug 3, 2018 at 3:20 PM, Jagan Teki <jagan@amarulasolutions.com> wrote:    
> > > > On Fri, Aug 3, 2018 at 1:57 PM, Miquel Raynal <miquel.raynal@bootlin.com> wrote:      
> > > >> Hi Jagan, Tom,
> > > >>
> > > >> Miquel Raynal <miquel.raynal@bootlin.com> wrote on Wed,  1 Aug 2018
> > > >> 10:18:21 +0200:
> > > >>      
> > > >>> During the last months, Boris Brezillon shared his work to support
> > > >>> serial flashes within Linux. First, he delivered (and merged) a new
> > > >>> layer called spi-mem. He also initiated in Linux MTD subsystem the move
> > > >>> of all 'raw' NAND related code to a raw/ subdirectory, adding at the
> > > >>> same time a NAND core that would be shared with all NAND devices. Then,
> > > >>> he contributed a generic SPI-NAND driver, making use of this NAND core,
> > > >>> as well as some vendor code to drive a few chips.
> > > >>>
> > > >>> On top of this work, I added an 'mtd' U-Boot command to handle all sort
> > > >>> of MTD devices. This should become the default command instead of having
> > > >>> one per flash flavor ('sf', 'nand', 'spi-nand' ?).
> > > >>>
> > > >>> The series has been tested on an Ocelot board PCB123 (VSC7514),
> > > >>> featuring a Macronix SPI NAND chip.
> > > >>>
> > > >>> TL;DR: the series contains:
> > > >>> - A few patches from Linux to resynchronize some areas of the MTD layer.
> > > >>> - Various fixes and re-organization of the MTD subsystem.
> > > >>> - The introduction of the SPI-mem interface.
> > > >>> - The addition of the generic SPI-NAND driver (and its bindings).
> > > >>> - Several SPI NAND chip drivers (Macronix, Micron, Winbond).
> > > >>> - A new 'mtd' command.
> > > >>> - Support for spi-nand devices in mtdparts.
> > > >>>
> > > >>> To test your SPI-NAND device with U-Boot simply follow these lines:
> > > >>>      
> > > >>> > setenv mtdparts mtdparts=spi-nand0:1m(foo),-(bar)
> > > >>> > setenv mtdids spi-nand0=spi-nand0
> > > >>> > mtdparts             # show the spi-nand device partitions
> > > >>> > ubi part bar         # create a static UBI volume in the bar partition      
> > > >>>
> > > >>> Thanks,
> > > >>> Miquèl
> > > >>>
> > > >>> Changes since v5:
> > > >>> -----------------
> > > >>> * Included Boris fixup about the build issues.
> > > >>> * Added Rb/Ab tags from Jagan on patchs 20/21.      
> > > >>
> > > >> I can't see a pull request flow on U-Boot ML, I suppose you use a
> > > >> different mean for that purpose.
> > > >>
> > > >> Jagan, is this version OK? Is it part of your PR?      
> > > >
> > > > Travis is going on [1], will send PR once all fine.
> > > >
> > > > [1] https://travis-ci.org/openedev/u-boot-amarula/builds/411596788      
> > > 
> > > There are some build issues, not quite sure whether it relates. please
> > > look into it.    
> > 
> > Thanks for the reports.
> >   
> > > 
> > > [2] https://travis-ci.org/openedev/u-boot-amarula/jobs/411596814
> > > [3] https://travis-ci.org/openedev/u-boot-amarula/jobs/411596815    
> > 
> > Boris supposedly fixed all the build issues related to my changes (I
> > don't think the "missing interrupt parent" in a DTS file is related),
> > please pull his branch [1].
> > 
> > The fixes are under the form of fixups if you wanna check them.
> > Otherwise you can just 'rebase -i --autosquash' to automatically squash
> > them with the commit introducing the regression.  
> 
> One more thing, if you want to make things bisectable patch 6 ("mtd: fix
> build issue with includes") and it's fixup should be squashed in patch 5
> ("mtd: add get/set of_node/flash_node helpers"), because the build
> failure you're fixing in patch 6 is introduced by patch 5.
> 
> > 
> > [1] https://travis-ci.org/openedev/u-boot-amarula/jobs/411596814  
> 
> You mean
> 
> [1]https://github.com/bbrezillon/u-boot/commits/wip-spi


Oops!

Thanks,
Miquèl

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

* [U-Boot] [PATCH v6 00/27] SPI-NAND support
  2018-08-01  8:18 [U-Boot] [PATCH v6 00/27] SPI-NAND support Miquel Raynal
                   ` (27 preceding siblings ...)
  2018-08-03  8:27 ` [U-Boot] [PATCH v6 00/27] SPI-NAND support Miquel Raynal
@ 2018-08-06 17:45 ` Stefan Roese
  2018-08-06 20:43   ` Boris Brezillon
  28 siblings, 1 reply; 41+ messages in thread
From: Stefan Roese @ 2018-08-06 17:45 UTC (permalink / raw)
  To: u-boot

Hi Miquel,

I just noticed that when using this patchset version, I'm
getting oopses / crashes while trying to attach an MTD
partition to UBI using "ubi part". This did not happen
with earlier versions.

I digged a bit into it and noticed that for example mtd_read()
in mtdcore.c has some differences which are not mentioned in
the commit history. Perhaps this is some mistake, or I did
something wrong - I wanted to mention it.

Tomorrow I can dig into it a bit more if necessary.

Thanks,
Stefan

On 01.08.2018 10:18, 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' ?).
> 
> The series has been tested on an Ocelot board PCB123 (VSC7514),
> featuring a Macronix SPI NAND chip.
> 
> TL;DR: the series contains:
> - A few patches from Linux to resynchronize some areas of the MTD layer.
> - Various fixes and re-organization of the MTD subsystem.
> - The introduction of the SPI-mem interface.
> - The addition of the generic SPI-NAND driver (and its bindings).
> - Several SPI NAND chip drivers (Macronix, Micron, Winbond).
> - A new 'mtd' command.
> - Support for spi-nand devices in mtdparts.
> 
> To test your SPI-NAND device with U-Boot simply follow these lines:
> 
>> setenv mtdparts mtdparts=spi-nand0:1m(foo),-(bar)
>> setenv mtdids spi-nand0=spi-nand0
>> mtdparts             # show the spi-nand device partitions
>> ubi part bar         # create a static UBI volume in the bar partition
> 
> Thanks,
> Miquèl
> 
> Changes since v5:
> -----------------
> * Included Boris fixup about the build issues.
> * Added Rb/Ab tags from Jagan on patchs 20/21.
> 
> Changes since v4:
> -----------------
> * Added Jagan's Acked-by tags to every patch related to the
>    SPI-mem/SPI-NAND addition.
> * Rebased on top of master.
> 
> Changes since v3:
> -----------------
> * Fixed the debug messages in spi-mem to print either Rx or Tx data.
> * Fixed a Kconfig error that prevented to build mtdparts with plain
>    defconfig.
> * Fixed a compilation error due to the above error that prevented one
>    file to be compiled.
> * Adapted the mtd command to probe MTD partitions also.
> * Declared mtd_probe_devices() in a header so mtdparts or UBI could
>    use it too (to probe all devices and MTD partitions in a clean way).
> * As I worked on mtdparts, I found annoying and completely useless the
>    fact that we need to prefix the environment variable with
>    "mtdparts=". Canceled this obligation.
> * Added one patch to allow spi-nand devices to be recognized by mtdparts
>    (this is purely useless but needed to be done in order to use this
>    command).
> * Removed useless definitions of MTD device types in UBI code.
> * Wrote a generic mtdparts environment variable parser, used by the mtd
>    command.
> * Used the mtd_probe_devices() function from get_mtd_info() in
>    cmd/mtdparts.c to be sure the desired partition really does not exist
>    (otherwise it will be probed and then found).
> 
> Changes since v2:
> -----------------
> * Rebased on u-boot master branch.
> * Removed extra-parenthesis in
>    "mtd: Fallback to ->_read/write() when ->_read/write_oob() is missing"
> * s/fiels/files/ in "mtd: move NAND fiels into a raw/ subdirectory"
> * Do not describe generic SPI device properties in SPI NAND bindings.
> * Changes in the mtd command:
>    * Printing more information in 'mtd list' (device type, device
>      characteristics)
>    * Switch to do_div() instead of '(u32)value64b % value32b' which only
>      worked because value32b was a power of 2.
>    * Removed erase.chip option.
>    * By default, erase/read/write happen on the full MTD device while a
>      dump will only work on a single page.
> 
> Changes since v1:
> -----------------
> * Fixed the nand_memorg structure of the MX35LF2GE4AB chip.
> * Added Reviewed-by tags from Jagan.
> * Backported and squashed two patches fixing things in the SPI NAND core
>    received on the Linux ML.
> * Backported more changes in mtdcore.c from Linux.
> * Added a patch to add a fallback on mtd->_read/_write() in mtdcore.c
>    when mtd->_read/write_oob() is not supported.
> * Removed the DT changes, useless as the DTs are not available in
>    mainline yet.
> * Addressed Boris/Stefan comments on the 'mtd' command.
> * Added support for multi-pages OOB read/write.
> 
> 
> Boris Brezillon (7):
>    mtd: Fallback to ->_read/write_oob() when ->_read/write() is missing
>    mtd: Add sanity checks in mtd_write/read_oob()
>    mtd: nand: Add core infrastructure to deal with NAND devices
>    mtd: nand: Pass mode information to nand_page_io_req
>    spi: Extend the core to ease integration of SPI memory controllers
>    mtd: spinand: Add initial support for the MX35LF1GE4AB chip
>    dt-bindings: Add bindings for SPI NAND devices
> 
> Brian Norris (1):
>    mtd: add get/set of_node/flash_node helpers
> 
> Ezequiel Garcia (1):
>    mtd: Uninline mtd_write_oob and move it to mtdcore.c
> 
> Frieder Schrempf (1):
>    mtd: spinand: Add initial support for Winbond W25M02GV
> 
> Miquel Raynal (15):
>    mtd: Fallback to ->_read/write() when ->_read/write_oob() is missing
>    mtd: fix build issue with includes
>    mtd: move definitions to enlarge their range
>    mtd: move all flash categories inside MTD submenu
>    mtd: move NAND files into a raw/ subdirectory
>    mtd: rename nand into rawnand in Kconfig prompt
>    mtd: spinand: Add initial support for the MX35LF2GE4AB chip
>    mtd: declare MTD_PARTITIONS symbol in Kconfig
>    cmd: ubi: delete useless and misleading definitions
>    cmd: mtdparts: accept spi-nand devices
>    cmd: mtdparts: add a generic 'mtdparts' parser
>    cmd: mtdparts: remove useless 'mtdparts=' prefix
>    mtd: uclass: add probe function
>    cmd: mtd: add 'mtd' command
>    cmd: mtdparts: try to probe the MTD devices as a fallback
> 
> Peter Pan (2):
>    mtd: nand: Add core infrastructure to support SPI NANDs
>    mtd: spinand: Add initial support for Micron MT29F2G01ABAGD
> 
>   MAINTAINERS                                   |    6 +-
>   Makefile                                      |    2 +-
>   README                                        |    6 +-
>   arch/arm/mach-uniphier/board_late_init.c      |    2 +-
>   cmd/Kconfig                                   |    7 +
>   cmd/Makefile                                  |    1 +
>   cmd/mtd.c                                     |  392 ++++++++
>   cmd/mtdparts.c                                |  113 ++-
>   cmd/ubi.c                                     |    5 -
>   common/spl/Kconfig                            |    2 +-
>   common/spl/spl_spi.c                          |    2 +-
>   doc/README.SPL                                |    4 +-
>   doc/README.arm-relocation                     |    2 +-
>   doc/README.nand                               |    6 +-
>   doc/README.zynq                               |    2 +-
>   doc/device-tree-bindings/mtd/spi-nand.txt     |    5 +
>   drivers/Makefile                              |    2 +-
>   drivers/mtd/Kconfig                           |    7 +-
>   drivers/mtd/Makefile                          |    4 +-
>   drivers/mtd/mtd-uclass.c                      |    9 +
>   drivers/mtd/mtdcore.c                         |  106 ++-
>   drivers/mtd/mtdcore.h                         |    6 -
>   drivers/mtd/mtdpart.c                         |    6 +-
>   drivers/mtd/nand/Kconfig                      |  299 +-----
>   drivers/mtd/nand/Makefile                     |   78 +-
>   drivers/mtd/nand/bbt.c                        |  132 +++
>   drivers/mtd/nand/core.c                       |  243 +++++
>   drivers/mtd/nand/raw/Kconfig                  |  297 ++++++
>   drivers/mtd/nand/raw/Makefile                 |   77 ++
>   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     |    2 +-
>   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.h         |    0
>   drivers/mtd/nand/{ => raw}/mxs_nand_dt.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         |    2 +-
>   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        |    2 +-
>   drivers/mtd/nand/{ => raw}/omap_elm.c         |    0
>   drivers/mtd/nand/{ => raw}/omap_gpmc.c        |    0
>   drivers/mtd/nand/{ => raw}/pxa3xx_nand.c      |    2 +-
>   drivers/mtd/nand/{ => raw}/pxa3xx_nand.h      |    0
>   drivers/mtd/nand/{ => raw}/sunxi_nand.c       |    0
>   drivers/mtd/nand/{ => raw}/sunxi_nand_spl.c   |    0
>   drivers/mtd/nand/{ => raw}/tegra_nand.c       |    0
>   drivers/mtd/nand/{ => raw}/tegra_nand.h       |    0
>   drivers/mtd/nand/{ => raw}/vf610_nfc.c        |    0
>   drivers/mtd/nand/{ => raw}/zynq_nand.c        |    0
>   drivers/mtd/nand/spi/Kconfig                  |    7 +
>   drivers/mtd/nand/spi/Makefile                 |    4 +
>   drivers/mtd/nand/spi/core.c                   | 1254 +++++++++++++++++++++++++
>   drivers/mtd/nand/spi/macronix.c               |  146 +++
>   drivers/mtd/nand/spi/micron.c                 |  135 +++
>   drivers/mtd/nand/spi/winbond.c                |  143 +++
>   drivers/mtd/onenand/onenand_base.c            |   60 --
>   drivers/spi/Kconfig                           |    7 +
>   drivers/spi/Makefile                          |    1 +
>   drivers/spi/spi-mem.c                         |  500 ++++++++++
>   include/configs/MPC8313ERDB.h                 |    2 +-
>   include/jffs2/load_kernel.h                   |    7 +-
>   include/linux/mtd/mtd.h                       |   34 +-
>   include/linux/mtd/nand.h                      |  734 +++++++++++++++
>   include/linux/mtd/partitions.h                |    3 +
>   include/linux/mtd/spinand.h                   |  432 +++++++++
>   include/spi-mem.h                             |  258 +++++
>   include/spi.h                                 |   11 +
>   96 files changed, 5064 insertions(+), 561 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 (99%)
>   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.h (100%)
>   rename drivers/mtd/nand/{ => raw}/mxs_nand_dt.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 (99%)
>   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 (99%)
>   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 (99%)
>   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
> 

Viele Grüße,
Stefan

-- 
DENX Software Engineering GmbH,      Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-51 Fax: (+49)-8142-66989-80 Email: sr at denx.de

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

* [U-Boot] [PATCH v6 00/27] SPI-NAND support
  2018-08-04  9:59           ` Miquel Raynal
@ 2018-08-06 17:50             ` Jagan Teki
  2018-08-08 10:08               ` Miquel Raynal
  0 siblings, 1 reply; 41+ messages in thread
From: Jagan Teki @ 2018-08-06 17:50 UTC (permalink / raw)
  To: u-boot

Are you planning to send the next version?

On Sat, Aug 4, 2018 at 3:29 PM, Miquel Raynal <miquel.raynal@bootlin.com> wrote:
> Hi Boris,
>
> Boris Brezillon <boris.brezillon@bootlin.com> wrote on Sat, 4 Aug 2018
> 10:34:55 +0200:
>
>> On Sat, 4 Aug 2018 09:23:05 +0200
>> Miquel Raynal <miquel.raynal@bootlin.com> wrote:
>>
>> > Hi Jagan,
>> >
>> > Jagan Teki <jagan@amarulasolutions.com> wrote on Fri, 3 Aug 2018
>> > 17:38:33 +0530:
>> >
>> > > On Fri, Aug 3, 2018 at 3:20 PM, Jagan Teki <jagan@amarulasolutions.com> wrote:
>> > > > On Fri, Aug 3, 2018 at 1:57 PM, Miquel Raynal <miquel.raynal@bootlin.com> wrote:
>> > > >> Hi Jagan, Tom,
>> > > >>
>> > > >> Miquel Raynal <miquel.raynal@bootlin.com> wrote on Wed,  1 Aug 2018
>> > > >> 10:18:21 +0200:
>> > > >>
>> > > >>> During the last months, Boris Brezillon shared his work to support
>> > > >>> serial flashes within Linux. First, he delivered (and merged) a new
>> > > >>> layer called spi-mem. He also initiated in Linux MTD subsystem the move
>> > > >>> of all 'raw' NAND related code to a raw/ subdirectory, adding at the
>> > > >>> same time a NAND core that would be shared with all NAND devices. Then,
>> > > >>> he contributed a generic SPI-NAND driver, making use of this NAND core,
>> > > >>> as well as some vendor code to drive a few chips.
>> > > >>>
>> > > >>> On top of this work, I added an 'mtd' U-Boot command to handle all sort
>> > > >>> of MTD devices. This should become the default command instead of having
>> > > >>> one per flash flavor ('sf', 'nand', 'spi-nand' ?).
>> > > >>>
>> > > >>> The series has been tested on an Ocelot board PCB123 (VSC7514),
>> > > >>> featuring a Macronix SPI NAND chip.
>> > > >>>
>> > > >>> TL;DR: the series contains:
>> > > >>> - A few patches from Linux to resynchronize some areas of the MTD layer.
>> > > >>> - Various fixes and re-organization of the MTD subsystem.
>> > > >>> - The introduction of the SPI-mem interface.
>> > > >>> - The addition of the generic SPI-NAND driver (and its bindings).
>> > > >>> - Several SPI NAND chip drivers (Macronix, Micron, Winbond).
>> > > >>> - A new 'mtd' command.
>> > > >>> - Support for spi-nand devices in mtdparts.
>> > > >>>
>> > > >>> To test your SPI-NAND device with U-Boot simply follow these lines:
>> > > >>>
>> > > >>> > setenv mtdparts mtdparts=spi-nand0:1m(foo),-(bar)
>> > > >>> > setenv mtdids spi-nand0=spi-nand0
>> > > >>> > mtdparts             # show the spi-nand device partitions
>> > > >>> > ubi part bar         # create a static UBI volume in the bar partition
>> > > >>>
>> > > >>> Thanks,
>> > > >>> Miquèl
>> > > >>>
>> > > >>> Changes since v5:
>> > > >>> -----------------
>> > > >>> * Included Boris fixup about the build issues.
>> > > >>> * Added Rb/Ab tags from Jagan on patchs 20/21.
>> > > >>
>> > > >> I can't see a pull request flow on U-Boot ML, I suppose you use a
>> > > >> different mean for that purpose.
>> > > >>
>> > > >> Jagan, is this version OK? Is it part of your PR?
>> > > >
>> > > > Travis is going on [1], will send PR once all fine.
>> > > >
>> > > > [1] https://travis-ci.org/openedev/u-boot-amarula/builds/411596788
>> > >
>> > > There are some build issues, not quite sure whether it relates. please
>> > > look into it.
>> >
>> > Thanks for the reports.
>> >
>> > >
>> > > [2] https://travis-ci.org/openedev/u-boot-amarula/jobs/411596814
>> > > [3] https://travis-ci.org/openedev/u-boot-amarula/jobs/411596815
>> >
>> > Boris supposedly fixed all the build issues related to my changes (I
>> > don't think the "missing interrupt parent" in a DTS file is related),
>> > please pull his branch [1].
>> >
>> > The fixes are under the form of fixups if you wanna check them.
>> > Otherwise you can just 'rebase -i --autosquash' to automatically squash
>> > them with the commit introducing the regression.
>>
>> One more thing, if you want to make things bisectable patch 6 ("mtd: fix
>> build issue with includes") and it's fixup should be squashed in patch 5
>> ("mtd: add get/set of_node/flash_node helpers"), because the build
>> failure you're fixing in patch 6 is introduced by patch 5.
>>
>> >
>> > [1] https://travis-ci.org/openedev/u-boot-amarula/jobs/411596814
>>
>> You mean
>>
>> [1]https://github.com/bbrezillon/u-boot/commits/wip-spi
>
>
> Oops!
>
> Thanks,
> Miquèl



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

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

* [U-Boot] [PATCH v6 00/27] SPI-NAND support
  2018-08-06 17:45 ` Stefan Roese
@ 2018-08-06 20:43   ` Boris Brezillon
  2018-08-07  4:59     ` Stefan Roese
  0 siblings, 1 reply; 41+ messages in thread
From: Boris Brezillon @ 2018-08-06 20:43 UTC (permalink / raw)
  To: u-boot

On Mon, 6 Aug 2018 19:45:24 +0200
Stefan Roese <sr@denx.de> wrote:

> Hi Miquel,
> 
> I just noticed that when using this patchset version, I'm
> getting oopses / crashes while trying to attach an MTD
> partition to UBI using "ubi part". This did not happen
> with earlier versions.
> 
> I digged a bit into it and noticed that for example mtd_read()
> in mtdcore.c has some differences which are not mentioned in
> the commit history. Perhaps this is some mistake, or I did
> something wrong - I wanted to mention it.

I have a branch containing this patchset there [1], just in case you
want to make sure this is not a mistake you made when applying patches.

[1]https://github.com/bbrezillon/u-boot/tree/wip-spi

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

* [U-Boot] [PATCH v6 00/27] SPI-NAND support
  2018-08-06 20:43   ` Boris Brezillon
@ 2018-08-07  4:59     ` Stefan Roese
  0 siblings, 0 replies; 41+ messages in thread
From: Stefan Roese @ 2018-08-07  4:59 UTC (permalink / raw)
  To: u-boot

Hi Boris,

On 06.08.2018 22:43, Boris Brezillon wrote:
> On Mon, 6 Aug 2018 19:45:24 +0200
> Stefan Roese <sr@denx.de> wrote:
> 
>> Hi Miquel,
>>
>> I just noticed that when using this patchset version, I'm
>> getting oopses / crashes while trying to attach an MTD
>> partition to UBI using "ubi part". This did not happen
>> with earlier versions.
>>
>> I digged a bit into it and noticed that for example mtd_read()
>> in mtdcore.c has some differences which are not mentioned in
>> the commit history. Perhaps this is some mistake, or I did
>> something wrong - I wanted to mention it.
> 
> I have a branch containing this patchset there [1], just in case you
> want to make sure this is not a mistake you made when applying patches.
> 
> [1]https://github.com/bbrezillon/u-boot/tree/wip-spi

Seems that I fat-fingered here something. Applying v6 of this patchset
again, all seems fine so far. So:

Tested-by: Stefan Roese <sr@denx.de>

Thanks,
Stefan

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

* [U-Boot] [PATCH v6 00/27] SPI-NAND support
  2018-08-04  7:23       ` Miquel Raynal
  2018-08-04  8:34         ` Boris Brezillon
@ 2018-08-07 14:39         ` Daniel Schwierzeck
  2018-08-08  9:17           ` Miquel Raynal
  1 sibling, 1 reply; 41+ messages in thread
From: Daniel Schwierzeck @ 2018-08-07 14:39 UTC (permalink / raw)
  To: u-boot

2018-08-04 9:23 GMT+02:00 Miquel Raynal <miquel.raynal@bootlin.com>:
> Hi Jagan,
>
> Jagan Teki <jagan@amarulasolutions.com> wrote on Fri, 3 Aug 2018
> 17:38:33 +0530:
>
>> On Fri, Aug 3, 2018 at 3:20 PM, Jagan Teki <jagan@amarulasolutions.com> wrote:
>> > On Fri, Aug 3, 2018 at 1:57 PM, Miquel Raynal <miquel.raynal@bootlin.com> wrote:
>> >> Hi Jagan, Tom,
>> >>
>> >> Miquel Raynal <miquel.raynal@bootlin.com> wrote on Wed,  1 Aug 2018
>> >> 10:18:21 +0200:
>> >>
>> >>> During the last months, Boris Brezillon shared his work to support
>> >>> serial flashes within Linux. First, he delivered (and merged) a new
>> >>> layer called spi-mem. He also initiated in Linux MTD subsystem the move
>> >>> of all 'raw' NAND related code to a raw/ subdirectory, adding at the
>> >>> same time a NAND core that would be shared with all NAND devices. Then,
>> >>> he contributed a generic SPI-NAND driver, making use of this NAND core,
>> >>> as well as some vendor code to drive a few chips.
>> >>>
>> >>> On top of this work, I added an 'mtd' U-Boot command to handle all sort
>> >>> of MTD devices. This should become the default command instead of having
>> >>> one per flash flavor ('sf', 'nand', 'spi-nand' ?).
>> >>>
>> >>> The series has been tested on an Ocelot board PCB123 (VSC7514),
>> >>> featuring a Macronix SPI NAND chip.
>> >>>
>> >>> TL;DR: the series contains:
>> >>> - A few patches from Linux to resynchronize some areas of the MTD layer.
>> >>> - Various fixes and re-organization of the MTD subsystem.
>> >>> - The introduction of the SPI-mem interface.
>> >>> - The addition of the generic SPI-NAND driver (and its bindings).
>> >>> - Several SPI NAND chip drivers (Macronix, Micron, Winbond).
>> >>> - A new 'mtd' command.
>> >>> - Support for spi-nand devices in mtdparts.
>> >>>
>> >>> To test your SPI-NAND device with U-Boot simply follow these lines:
>> >>>
>> >>> > setenv mtdparts mtdparts=spi-nand0:1m(foo),-(bar)
>> >>> > setenv mtdids spi-nand0=spi-nand0
>> >>> > mtdparts             # show the spi-nand device partitions
>> >>> > ubi part bar         # create a static UBI volume in the bar partition
>> >>>
>> >>> Thanks,
>> >>> Miquèl
>> >>>
>> >>> Changes since v5:
>> >>> -----------------
>> >>> * Included Boris fixup about the build issues.
>> >>> * Added Rb/Ab tags from Jagan on patchs 20/21.
>> >>
>> >> I can't see a pull request flow on U-Boot ML, I suppose you use a
>> >> different mean for that purpose.
>> >>
>> >> Jagan, is this version OK? Is it part of your PR?
>> >
>> > Travis is going on [1], will send PR once all fine.
>> >
>> > [1] https://travis-ci.org/openedev/u-boot-amarula/builds/411596788
>>
>> There are some build issues, not quite sure whether it relates. please
>> look into it.
>
> Thanks for the reports.
>
>>
>> [2] https://travis-ci.org/openedev/u-boot-amarula/jobs/411596814
>> [3] https://travis-ci.org/openedev/u-boot-amarula/jobs/411596815
>
> Boris supposedly fixed all the build issues related to my changes (I
> don't think the "missing interrupt parent" in a DTS file is related),
> please pull his branch [1].

the DTS warnings are unrelated and can be ignored. Only the onenand_*
stuff seems
to be a regression.I wonder if VCT is the only board remaining with
OneNAND support?

>
> The fixes are under the form of fixups if you wanna check them.
> Otherwise you can just 'rebase -i --autosquash' to automatically squash
> them with the commit introducing the regression.
>
> [1] https://travis-ci.org/openedev/u-boot-amarula/jobs/411596814
>
>
> Thanks,
> Miquèl
>
> --
> Miquel Raynal, Bootlin (formerly Free Electrons)
> Embedded Linux and Kernel engineering
> https://bootlin.com



-- 
- Daniel

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

* [U-Boot] [PATCH v6 00/27] SPI-NAND support
  2018-08-07 14:39         ` Daniel Schwierzeck
@ 2018-08-08  9:17           ` Miquel Raynal
  0 siblings, 0 replies; 41+ messages in thread
From: Miquel Raynal @ 2018-08-08  9:17 UTC (permalink / raw)
  To: u-boot

Hi Daniel,

Daniel Schwierzeck <daniel.schwierzeck@gmail.com> wrote on Tue, 7 Aug
2018 16:39:34 +0200:

> 2018-08-04 9:23 GMT+02:00 Miquel Raynal <miquel.raynal@bootlin.com>:
> > Hi Jagan,
> >
> > Jagan Teki <jagan@amarulasolutions.com> wrote on Fri, 3 Aug 2018
> > 17:38:33 +0530:
> >  
> >> On Fri, Aug 3, 2018 at 3:20 PM, Jagan Teki <jagan@amarulasolutions.com> wrote:  
> >> > On Fri, Aug 3, 2018 at 1:57 PM, Miquel Raynal <miquel.raynal@bootlin.com> wrote:  
> >> >> Hi Jagan, Tom,
> >> >>
> >> >> Miquel Raynal <miquel.raynal@bootlin.com> wrote on Wed,  1 Aug 2018
> >> >> 10:18:21 +0200:
> >> >>  
> >> >>> During the last months, Boris Brezillon shared his work to support
> >> >>> serial flashes within Linux. First, he delivered (and merged) a new
> >> >>> layer called spi-mem. He also initiated in Linux MTD subsystem the move
> >> >>> of all 'raw' NAND related code to a raw/ subdirectory, adding at the
> >> >>> same time a NAND core that would be shared with all NAND devices. Then,
> >> >>> he contributed a generic SPI-NAND driver, making use of this NAND core,
> >> >>> as well as some vendor code to drive a few chips.
> >> >>>
> >> >>> On top of this work, I added an 'mtd' U-Boot command to handle all sort
> >> >>> of MTD devices. This should become the default command instead of having
> >> >>> one per flash flavor ('sf', 'nand', 'spi-nand' ?).
> >> >>>
> >> >>> The series has been tested on an Ocelot board PCB123 (VSC7514),
> >> >>> featuring a Macronix SPI NAND chip.
> >> >>>
> >> >>> TL;DR: the series contains:
> >> >>> - A few patches from Linux to resynchronize some areas of the MTD layer.
> >> >>> - Various fixes and re-organization of the MTD subsystem.
> >> >>> - The introduction of the SPI-mem interface.
> >> >>> - The addition of the generic SPI-NAND driver (and its bindings).
> >> >>> - Several SPI NAND chip drivers (Macronix, Micron, Winbond).
> >> >>> - A new 'mtd' command.
> >> >>> - Support for spi-nand devices in mtdparts.
> >> >>>
> >> >>> To test your SPI-NAND device with U-Boot simply follow these lines:
> >> >>>  
> >> >>> > setenv mtdparts mtdparts=spi-nand0:1m(foo),-(bar)
> >> >>> > setenv mtdids spi-nand0=spi-nand0
> >> >>> > mtdparts             # show the spi-nand device partitions
> >> >>> > ubi part bar         # create a static UBI volume in the bar partition  
> >> >>>
> >> >>> Thanks,
> >> >>> Miquèl
> >> >>>
> >> >>> Changes since v5:
> >> >>> -----------------
> >> >>> * Included Boris fixup about the build issues.
> >> >>> * Added Rb/Ab tags from Jagan on patchs 20/21.  
> >> >>
> >> >> I can't see a pull request flow on U-Boot ML, I suppose you use a
> >> >> different mean for that purpose.
> >> >>
> >> >> Jagan, is this version OK? Is it part of your PR?  
> >> >
> >> > Travis is going on [1], will send PR once all fine.
> >> >
> >> > [1] https://travis-ci.org/openedev/u-boot-amarula/builds/411596788  
> >>
> >> There are some build issues, not quite sure whether it relates. please
> >> look into it.  
> >
> > Thanks for the reports.
> >  
> >>
> >> [2] https://travis-ci.org/openedev/u-boot-amarula/jobs/411596814
> >> [3] https://travis-ci.org/openedev/u-boot-amarula/jobs/411596815  
> >
> > Boris supposedly fixed all the build issues related to my changes (I
> > don't think the "missing interrupt parent" in a DTS file is related),
> > please pull his branch [1].  
> 
> the DTS warnings are unrelated and can be ignored. Only the onenand_*
> stuff seems
> to be a regression.

OneNAND warnings should be gone with Boris fixups.

Thanks,
Miquèl

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

* [U-Boot] [PATCH v6 00/27] SPI-NAND support
  2018-08-06 17:50             ` Jagan Teki
@ 2018-08-08 10:08               ` Miquel Raynal
  0 siblings, 0 replies; 41+ messages in thread
From: Miquel Raynal @ 2018-08-08 10:08 UTC (permalink / raw)
  To: u-boot

Hi Jagan,

Jagan Teki <jagan@amarulasolutions.com> wrote on Mon, 6 Aug 2018
23:20:19 +0530:

> Are you planning to send the next version?

I was not as we gave you a branch to pull patches from and test with
Travis if the warnings were gone [1].

Of course I can send the patches if you want them here also.

If Stefan sends a new iteration of his series I could fold the changes.

[1] https://github.com/bbrezillon/u-boot/commits/wip-spi


Thanks,
Miquèl

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

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

Thread overview: 41+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-08-01  8:18 [U-Boot] [PATCH v6 00/27] SPI-NAND support Miquel Raynal
2018-08-01  8:18 ` [U-Boot] [PATCH v6 01/27] mtd: Fallback to ->_read/write_oob() when ->_read/write() is missing Miquel Raynal
2018-08-01  8:18 ` [U-Boot] [PATCH v6 02/27] mtd: Uninline mtd_write_oob and move it to mtdcore.c Miquel Raynal
2018-08-01  8:18 ` [U-Boot] [PATCH v6 03/27] mtd: Add sanity checks in mtd_write/read_oob() Miquel Raynal
2018-08-01  8:18 ` [U-Boot] [PATCH v6 04/27] mtd: Fallback to ->_read/write() when ->_read/write_oob() is missing Miquel Raynal
2018-08-01  8:18 ` [U-Boot] [PATCH v6 05/27] mtd: add get/set of_node/flash_node helpers Miquel Raynal
2018-08-01  8:18 ` [U-Boot] [PATCH v6 06/27] mtd: fix build issue with includes Miquel Raynal
2018-08-01  8:18 ` [U-Boot] [PATCH v6 07/27] mtd: move definitions to enlarge their range Miquel Raynal
2018-08-01  8:18 ` [U-Boot] [PATCH v6 08/27] mtd: move all flash categories inside MTD submenu Miquel Raynal
2018-08-01  8:18 ` [U-Boot] [PATCH v6 09/27] mtd: move NAND files into a raw/ subdirectory Miquel Raynal
2018-08-01  8:18 ` [U-Boot] [PATCH v6 10/27] mtd: rename nand into rawnand in Kconfig prompt Miquel Raynal
2018-08-01  8:18 ` [U-Boot] [PATCH v6 11/27] mtd: nand: Add core infrastructure to deal with NAND devices Miquel Raynal
2018-08-01  8:18 ` [U-Boot] [PATCH v6 12/27] mtd: nand: Pass mode information to nand_page_io_req Miquel Raynal
2018-08-01  8:18 ` [U-Boot] [PATCH v6 13/27] spi: Extend the core to ease integration of SPI memory controllers Miquel Raynal
2018-08-01  8:18 ` [U-Boot] [PATCH v6 14/27] mtd: nand: Add core infrastructure to support SPI NANDs Miquel Raynal
2018-08-01  8:18 ` [U-Boot] [PATCH v6 15/27] mtd: spinand: Add initial support for Micron MT29F2G01ABAGD Miquel Raynal
2018-08-01  8:18 ` [U-Boot] [PATCH v6 16/27] mtd: spinand: Add initial support for Winbond W25M02GV Miquel Raynal
2018-08-01  8:18 ` [U-Boot] [PATCH v6 17/27] mtd: spinand: Add initial support for the MX35LF1GE4AB chip Miquel Raynal
2018-08-01  8:18 ` [U-Boot] [PATCH v6 18/27] mtd: spinand: Add initial support for the MX35LF2GE4AB chip Miquel Raynal
2018-08-01  8:18 ` [U-Boot] [PATCH v6 19/27] dt-bindings: Add bindings for SPI NAND devices Miquel Raynal
2018-08-01  8:18 ` [U-Boot] [PATCH v6 20/27] mtd: declare MTD_PARTITIONS symbol in Kconfig Miquel Raynal
2018-08-01  8:18 ` [U-Boot] [PATCH v6 21/27] cmd: ubi: delete useless and misleading definitions Miquel Raynal
2018-08-01  8:18 ` [U-Boot] [PATCH v6 22/27] cmd: mtdparts: accept spi-nand devices Miquel Raynal
2018-08-01  8:18 ` [U-Boot] [PATCH v6 23/27] cmd: mtdparts: add a generic 'mtdparts' parser Miquel Raynal
2018-08-01  8:18 ` [U-Boot] [PATCH v6 24/27] cmd: mtdparts: remove useless 'mtdparts=' prefix Miquel Raynal
2018-08-01  8:18 ` [U-Boot] [PATCH v6 25/27] mtd: uclass: add probe function Miquel Raynal
2018-08-01  8:18 ` [U-Boot] [PATCH v6 26/27] cmd: mtd: add 'mtd' command Miquel Raynal
2018-08-01  8:18 ` [U-Boot] [PATCH v6 27/27] cmd: mtdparts: try to probe the MTD devices as a fallback Miquel Raynal
2018-08-03  8:27 ` [U-Boot] [PATCH v6 00/27] SPI-NAND support Miquel Raynal
2018-08-03  9:50   ` Jagan Teki
2018-08-03 12:08     ` Jagan Teki
2018-08-04  7:23       ` Miquel Raynal
2018-08-04  8:34         ` Boris Brezillon
2018-08-04  9:59           ` Miquel Raynal
2018-08-06 17:50             ` Jagan Teki
2018-08-08 10:08               ` Miquel Raynal
2018-08-07 14:39         ` Daniel Schwierzeck
2018-08-08  9:17           ` Miquel Raynal
2018-08-06 17:45 ` Stefan Roese
2018-08-06 20:43   ` Boris Brezillon
2018-08-07  4:59     ` Stefan Roese

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.