All of lore.kernel.org
 help / color / mirror / Atom feed
* [U-Boot] [PATCH v9 00/21] dm: Generic MTD Subsystem/SPI-NOR
@ 2016-10-30 18:23 Jagan Teki
  2016-10-30 18:23 ` [U-Boot] [PATCH v9 01/21] dm: mtd: Add dm mtd core ops Jagan Teki
                   ` (21 more replies)
  0 siblings, 22 replies; 39+ messages in thread
From: Jagan Teki @ 2016-10-30 18:23 UTC (permalink / raw)
  To: u-boot

The previous series [1] [2] are added SPI-NOR on top of
mtd/spi where it bypassing DM_SPI_FLASH and use the existing
mtd core (which is non-dm), I feel this is moving in a reverse
direction where adding new feature with the help of non-dm mtd
core support and also few of the spi drivers are not fully dm-driven.

Previous design series[3]: keep the mtd/spi as it is and start adding
spi-nor features separately. The idea here is to add the dm features
to MTD first and then add UCLASS_MTD spi-nor drivers so-that the commands
are interfacing to spi-nor through dm-driven MTD core to spi-nor.

This series adding a new command 'mtd.c' which is common for all MTD devices
SPI-NOR, SPI-NOR(master) and Parallel NOR with dm-driven. 

SPI-NOR and Parallel NOR:
------------------------

------------------------------------
              mtd.c
------------------------------------
            mtd-uclass
------------------------------------
       SPI-NOR Core        CFI FLASH
------------------------------------
m25p80.c        zynq_qspi
-----------------------------------
spi-uclass      SPI NOR chip
-----------------------------------
spi drivers
-----------------------------------
SPI NOR chip
-----------------------------------

drivers/mtd/spi-nor/

- Add dm mtd operations
- spi-nor.c:   Add basic SPI-NOR core like erase/read/write ops and lock's will add later
- m25p80.c:    spi-nor to spi divers interface layer drivers/spi-nor
- zynq_qspi.c: zynq qspi spi-nor controller driver.

Current Status:
--------------
- SPI-NOR Controller design flow working, see Log

TODO:
----
- SPI-NOR with SPI bus
- Parallel NOR.

Log:
----
Zynq> mtd
mtd - MTD Sub-system

Usage:
mtd list                        - show list of MTD devices
mtd info                        - show current MTD device info
mtd probe devnum                - probe the 'devnum' MTD device
mtd erase offset len            - erase 'len' bytes from 'offset'
mtd write addr to len           - write 'len' bytes to 'to' from 'addr'
mtd read addr from len          - read 'len' bytes from 'from' to 'addr'
Zynq> mtd list
MTD 1:  spi-nor at e000d000
Zynq>
MTD 1:  spi-nor at e000d000
Zynq> mtd list
MTD 1:  spi-nor at e000d000
Zynq> mtd probe 0
failing to set MTD device 0
Zynq> mtd probe 1
SPI-NOR: detected s25fl128s_64k with page size 256 Bytes, erase size 64 KiB, total 16 MiB
Zynq> mtd info  
MTD Device 1: s25fl128s_64k
 Page size:     256 B
 Erase size:    64 KiB
 Size:          16 MiB
Zynq> mtd list
MTD 1:  spi-nor at e000d000  (active 1)
Zynq> mtd erase 0xE00000 0x100000
MTD: 1048576 bytes @ 0xe00000 Erased: OK
Zynq> mw.b 0x100 0xaa 0x100000
Zynq> mtd write 0x100 0xE00000 0x100000
device 0 offset 0xe00000, size 0x100000
MTD: 1048576 bytes @ 0xe00000 Written: OK
Zynq> mtd read 0x3000000 0xE00000 0x100000
device 0 offset 0xe00000, size 0x100000
MTD: 1048576 bytes @ 0xe00000 Read: OK
Zynq> cmp.b 0x3000000 0x100 0x100000
Total of 1048576 byte(s) were the same

Testing:
-------
$ git clone git://git.denx.de/u-boot-spi.git
$ cd u-boot-spi
$ git checkout -b mtd origin/mtd-working

[1] http://lists.denx.de/pipermail/u-boot/2016-March/249286.html
[2] http://lists.denx.de/pipermail/u-boot/2016-February/245418.html
[3] [PATCH RFC v8 00/16]  SPI-NOR/MTD addition

Jagan Teki (21):
  dm: mtd: Add dm mtd core ops
  mtd: Add SPI-NOR core support
  mtd: spi-nor: Kconfig: Add MTD_SPI_NOR entry
  mtd: spi-nor: Kconfig: Add MTD_SPI_NOR_USE_4K_SECTORS
  mtd: spi-nor: Kconfig: Add SPI_NOR_MISC entry
  mtd: spi-nor: Kconfig: Add SPI_NOR_MACRONIX entry
  mtd: spi-nor: Kconfig: Add SPI_NOR_SPANSION entry
  mtd: spi-nor: Kconfig: Add SPI_NOR_STMICRO entry
  mtd: spi-nor: Kconfig: Add SPI_NOR_SST entry
  mtd: spi-nor: Kconfig: Add SPI_NOR_WINBOND entry
  spi: Add spi_write_then_read
  mtd: spi-nor: Add m25p80 driver
  mtd: spi-nor: Kconfig: Add MTD_M25P80 entry
  mtd: spi-nor: Add zynq qspinor driver
  mtd: spi-nor: zynq_qspi: Kconfig: Add MTD_ZYNQ
  mtd: spi-nor: Add 4-byte addresswidth support
  dm: mtd: Add uclass_driver.flags
  dm: mtd: Add post_bind
  cmd: Add mtd command support
  arm: dts: zynq: Add zynq-qspinor node
  dm: zynq: microzed: Enable MTD/SPI-NOR

 Makefile                           |   1 +
 arch/arm/dts/zynq-7000.dtsi        |  12 +
 arch/arm/dts/zynq-microzed.dts     |   6 +
 cmd/Kconfig                        |   6 +
 cmd/Makefile                       |   1 +
 cmd/mtd.c                          | 285 ++++++++++++++++
 configs/zynq_microzed_defconfig    |  14 +-
 drivers/mtd/Kconfig                |   2 +
 drivers/mtd/Makefile               |   2 +-
 drivers/mtd/mtd-uclass.c           |  93 +++++
 drivers/mtd/spi-nor/Kconfig        |  89 +++++
 drivers/mtd/spi-nor/Makefile       |  15 +
 drivers/mtd/spi-nor/m25p80.c       | 218 ++++++++++++
 drivers/mtd/spi-nor/spi-nor-ids.c  | 176 ++++++++++
 drivers/mtd/spi-nor/spi-nor.c      | 684 +++++++++++++++++++++++++++++++++++++
 drivers/mtd/spi-nor/zynq_qspinor.c | 641 ++++++++++++++++++++++++++++++++++
 drivers/spi/spi-uclass.c           |  24 ++
 include/linux/err.h                |   5 +
 include/linux/mtd/spi-nor.h        | 211 ++++++++++++
 include/mtd.h                      |  63 ++++
 include/spi.h                      |  20 ++
 21 files changed, 2562 insertions(+), 6 deletions(-)
 create mode 100644 cmd/mtd.c
 create mode 100644 drivers/mtd/spi-nor/Kconfig
 create mode 100644 drivers/mtd/spi-nor/Makefile
 create mode 100644 drivers/mtd/spi-nor/m25p80.c
 create mode 100644 drivers/mtd/spi-nor/spi-nor-ids.c
 create mode 100644 drivers/mtd/spi-nor/spi-nor.c
 create mode 100644 drivers/mtd/spi-nor/zynq_qspinor.c
 create mode 100644 include/linux/mtd/spi-nor.h

-- 
2.7.4

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

* [U-Boot] [PATCH v9 01/21] dm: mtd: Add dm mtd core ops
  2016-10-30 18:23 [U-Boot] [PATCH v9 00/21] dm: Generic MTD Subsystem/SPI-NOR Jagan Teki
@ 2016-10-30 18:23 ` Jagan Teki
  2016-11-05 16:07   ` Simon Glass
  2016-10-30 18:23 ` [U-Boot] [PATCH v9 02/21] mtd: Add SPI-NOR core support Jagan Teki
                   ` (20 subsequent siblings)
  21 siblings, 1 reply; 39+ messages in thread
From: Jagan Teki @ 2016-10-30 18:23 UTC (permalink / raw)
  To: u-boot

- Add generic dm_mtd operations
- Add mtd_read|erase|write_dm
- Add add_mtd_device_dm

The respetive MTD_UCLASS drivers must install the hooks to these
dm_mtd_ops and other core ops are act as a interface b/w drivers
vs command code.

Signed-off-by: Jagan Teki <jagan@openedev.com>
---
 drivers/mtd/mtd-uclass.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++
 include/mtd.h            | 54 ++++++++++++++++++++++++++++++++++++
 2 files changed, 126 insertions(+)

diff --git a/drivers/mtd/mtd-uclass.c b/drivers/mtd/mtd-uclass.c
index 7b7c48e..acbd713 100644
--- a/drivers/mtd/mtd-uclass.c
+++ b/drivers/mtd/mtd-uclass.c
@@ -1,4 +1,5 @@
 /*
+ * Copyright (C) 2016 Jagan Teki <jagan@openedev.com>
  * Copyright (C) 2015 Thomas Chou <thomas@wytron.com.tw>
  *
  * SPDX-License-Identifier:	GPL-2.0+
@@ -8,6 +9,77 @@
 #include <dm.h>
 #include <errno.h>
 #include <mtd.h>
+#include <linux/log2.h>
+
+int dm_mtd_read(struct udevice *dev, loff_t from, size_t len, size_t *retlen,
+		u_char *buf)
+{
+	struct mtd_info *mtd = mtd_get_info(dev);
+
+	*retlen = 0;
+	if (from < 0 || from > mtd->size || len > mtd->size - from)
+		return -EINVAL;
+	if (!len)
+		return 0;
+
+	return mtd_get_ops(dev)->_read(dev, from, len, retlen, buf);
+}
+
+int dm_mtd_erase(struct udevice *dev, struct erase_info *instr)
+{
+	struct mtd_info *mtd = mtd_get_info(dev);
+
+	if (instr->addr > mtd->size || instr->len > mtd->size - instr->addr)
+		return -EINVAL;
+	if (!(mtd->flags & MTD_WRITEABLE))
+		return -EROFS;
+	instr->fail_addr = MTD_FAIL_ADDR_UNKNOWN;
+	if (!instr->len) {
+		instr->state = MTD_ERASE_DONE;
+		return 0;
+	}
+
+	return mtd_get_ops(dev)->_erase(dev, instr);
+}
+
+int dm_mtd_write(struct udevice *dev, loff_t to, size_t len, size_t *retlen,
+		 const u_char *buf)
+{
+	struct mtd_info *mtd = mtd_get_info(dev);
+
+	*retlen = 0;
+	if (to < 0 || to > mtd->size || len > mtd->size - to)
+		return -EINVAL;
+	if (!mtd_get_ops(dev)->_write || !(mtd->flags & MTD_WRITEABLE))
+		return -EROFS;
+	if (!len)
+		return 0;
+
+	return mtd_get_ops(dev)->_write(dev, to, len, retlen, buf);
+}
+
+int dm_add_mtd_device(struct udevice *dev)
+{
+	struct mtd_info *mtd = mtd_get_info(dev);
+
+	BUG_ON(mtd->writesize == 0);
+	mtd->usecount = 0;
+
+	if (is_power_of_2(mtd->erasesize))
+		mtd->erasesize_shift = ffs(mtd->erasesize) - 1;
+	else
+		mtd->erasesize_shift = 0;
+
+	if (is_power_of_2(mtd->writesize))
+		mtd->writesize_shift = ffs(mtd->writesize) - 1;
+	else
+		mtd->writesize_shift = 0;
+
+	mtd->erasesize_mask = (1 << mtd->erasesize_shift) - 1;
+	mtd->writesize_mask = (1 << mtd->writesize_shift) - 1;
+
+	return 0;
+}
 
 /*
  * Implement a MTD uclass which should include most flash drivers.
diff --git a/include/mtd.h b/include/mtd.h
index 3f8c293..93b5eaf 100644
--- a/include/mtd.h
+++ b/include/mtd.h
@@ -20,4 +20,58 @@ static inline struct mtd_info *mtd_get_info(struct udevice *dev)
 	return dev_get_uclass_priv(dev);
 }
 
+struct dm_mtd_ops {
+	int (*_erase)(struct udevice *dev, struct erase_info *instr);
+	int (*_read)(struct udevice *dev, loff_t from, size_t len,
+		     size_t *retlen, u_char *buf);
+	int (*_write)(struct udevice *dev, loff_t to, size_t len,
+		      size_t *retlen, const u_char *buf);
+};
+
+/* Access the serial operations for a device */
+#define mtd_get_ops(dev) ((struct dm_mtd_ops *)(dev)->driver->ops)
+
+/**
+ * dm_mtd_read() - Read data from MTD device
+ *
+ * @dev:	MTD device
+ * @from:	Offset into device in bytes to read from
+ * @len:	Length of bytes to read
+ * @retlen:	Length of return bytes read to
+ * @buf:	Buffer to put the data that is read
+ * @return 0 if OK, -ve on error
+ */
+int dm_mtd_read(struct udevice *dev, loff_t from, size_t len, size_t *retlen,
+		u_char *buf);
+
+/**
+ * dm_mtd_write() - Write data to MTD device
+ *
+ * @dev:	MTD device
+ * @to:		Offset into device in bytes to write to
+ * @len:	Length of bytes to write
+ * @retlen:	Length of return bytes to write to
+ * @buf:	Buffer containing bytes to write
+ * @return 0 if OK, -ve on error
+ */
+int dm_mtd_write(struct udevice *dev, loff_t to, size_t len, size_t *retlen,
+		 const u_char *buf);
+
+/**
+ * dm_mtd_erase() - Erase blocks of the MTD device
+ *
+ * @dev:	MTD device
+ * @instr:	Erase info details of MTD device
+ * @return 0 if OK, -ve on error
+ */
+int dm_mtd_erase(struct udevice *dev, struct erase_info *instr);
+
+/**
+ * dm_add_mtd_device() - Add MTD device
+ *
+ * @dev:	MTD device
+ * @return 0 if OK, -ve on error
+ */
+int dm_add_mtd_device(struct udevice *dev);
+
 #endif	/* _MTD_H_ */
-- 
2.7.4

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

* [U-Boot] [PATCH v9 02/21] mtd: Add SPI-NOR core support
  2016-10-30 18:23 [U-Boot] [PATCH v9 00/21] dm: Generic MTD Subsystem/SPI-NOR Jagan Teki
  2016-10-30 18:23 ` [U-Boot] [PATCH v9 01/21] dm: mtd: Add dm mtd core ops Jagan Teki
@ 2016-10-30 18:23 ` Jagan Teki
  2016-11-05 16:10   ` Simon Glass
  2016-10-30 18:23 ` [U-Boot] [PATCH v9 03/21] mtd: spi-nor: Kconfig: Add MTD_SPI_NOR entry Jagan Teki
                   ` (19 subsequent siblings)
  21 siblings, 1 reply; 39+ messages in thread
From: Jagan Teki @ 2016-10-30 18:23 UTC (permalink / raw)
  To: u-boot

Some of the SPI device drivers at drivers/spi not a real
spi controllers, Unlike normal/generic SPI controllers they
operates only with SPI-NOR flash devices. these were technically
termed as SPI-NOR controllers, Ex: drivers/spi/fsl_qspi.c

The problem with these were resides at drivers/spi is entire
SPI layer becomes SPI-NOR flash oriented which is absolutely
a wrong indication where SPI layer getting effected more with
flash operations - So this SPI-NOR core will resolve this issue
by separating all SPI-NOR flash operations from spi layer and
creats a generic layer called SPI-NOR core which can be used to
interact SPI-NOR to SPI driver interface layer and the SPI-NOR
controller driver. The idea is taken from Linux spi-nor framework.

------------------------------
	cmd_sf.c
------------------------------
	mtd-uclass
-------------------------------
	SPI-NOR	Core
-------------------------------
m25p80.c 	zynq_qspi
-------------------------------
spi-uclass	SPI NOR chip
-------------------------------
spi drivers
-------------------------------
SPI NOR chip
-------------------------------

Signed-off-by: Jagan Teki <jagan@openedev.com>
---
 Makefile                          |   1 +
 drivers/mtd/spi-nor/Makefile      |   9 +
 drivers/mtd/spi-nor/spi-nor-ids.c | 176 +++++++++++
 drivers/mtd/spi-nor/spi-nor.c     | 648 ++++++++++++++++++++++++++++++++++++++
 include/linux/err.h               |   5 +
 include/linux/mtd/spi-nor.h       | 207 ++++++++++++
 6 files changed, 1046 insertions(+)
 create mode 100644 drivers/mtd/spi-nor/Makefile
 create mode 100644 drivers/mtd/spi-nor/spi-nor-ids.c
 create mode 100644 drivers/mtd/spi-nor/spi-nor.c
 create mode 100644 include/linux/mtd/spi-nor.h

diff --git a/Makefile b/Makefile
index c67cc99..6404b12 100644
--- a/Makefile
+++ b/Makefile
@@ -642,6 +642,7 @@ libs-$(CONFIG_CMD_NAND) += drivers/mtd/nand/
 libs-y += drivers/mtd/onenand/
 libs-$(CONFIG_CMD_UBI) += drivers/mtd/ubi/
 libs-y += drivers/mtd/spi/
+libs-y += drivers/mtd/spi-nor/
 libs-y += drivers/net/
 libs-y += drivers/net/phy/
 libs-y += drivers/pci/
diff --git a/drivers/mtd/spi-nor/Makefile b/drivers/mtd/spi-nor/Makefile
new file mode 100644
index 0000000..15e43ea
--- /dev/null
+++ b/drivers/mtd/spi-nor/Makefile
@@ -0,0 +1,9 @@
+#
+# Copyright (C) 2016 Jagan Teki <jagan@openedev.com>
+#
+# SPDX-License-Identifier:	GPL-2.0+
+
+## spi-nor core
+ifdef CONFIG_MTD_SPI_NOR
+obj-y	+= spi-nor.o spi-nor-ids.o
+endif
diff --git a/drivers/mtd/spi-nor/spi-nor-ids.c b/drivers/mtd/spi-nor/spi-nor-ids.c
new file mode 100644
index 0000000..bde8513
--- /dev/null
+++ b/drivers/mtd/spi-nor/spi-nor-ids.c
@@ -0,0 +1,176 @@
+/*
+ * SPI NOR IDs.
+ *
+ * Copyright (C) 2016 Jagan Teki <jagan@openedev.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <linux/mtd/spi-nor.h>
+
+/* Used when the "_ext_id" is two bytes at most */
+#define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags)	\
+		.id = {							\
+			((_jedec_id) >> 16) & 0xff,			\
+			((_jedec_id) >> 8) & 0xff,			\
+			(_jedec_id) & 0xff,				\
+			((_ext_id) >> 8) & 0xff,			\
+			(_ext_id) & 0xff,				\
+			},						\
+		.id_len = (!(_jedec_id) ? 0 : (3 + ((_ext_id) ? 2 : 0))),	\
+		.sector_size = (_sector_size),				\
+		.n_sectors = (_n_sectors),				\
+		.page_size = 256,					\
+		.flags = (_flags),
+
+#define INFO6(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags)	\
+		.id = {							\
+			((_jedec_id) >> 16) & 0xff,			\
+			((_jedec_id) >> 8) & 0xff,			\
+			(_jedec_id) & 0xff,				\
+			((_ext_id) >> 16) & 0xff,			\
+			((_ext_id) >> 8) & 0xff,			\
+			(_ext_id) & 0xff,				\
+			},						\
+		.id_len = 6,						\
+		.sector_size = (_sector_size),				\
+		.n_sectors = (_n_sectors),				\
+		.page_size = 256,					\
+		.flags = (_flags),
+
+const struct spi_nor_info spi_nor_ids[] = {
+#ifdef CONFIG_SPI_NOR_MACRONIX	/* MACRONIX */
+	{"mx25l2006e",	   INFO(0xc22012, 0x0, 64 * 1024,     4, 0) },
+	{"mx25l4005",	   INFO(0xc22013, 0x0, 64 * 1024,     8, 0) },
+	{"mx25l8005",	   INFO(0xc22014, 0x0, 64 * 1024,    16, 0) },
+	{"mx25l1605d",	   INFO(0xc22015, 0x0, 64 * 1024,    32, 0) },
+	{"mx25l3205d",	   INFO(0xc22016, 0x0, 64 * 1024,    64, 0) },
+	{"mx25l6405d",	   INFO(0xc22017, 0x0, 64 * 1024,   128, 0) },
+	{"mx25l12805",	   INFO(0xc22018, 0x0, 64 * 1024,   256, RD_FULL | WR_QPP) },
+	{"mx25l25635f",	   INFO(0xc22019, 0x0, 64 * 1024,   512, RD_FULL | WR_QPP) },
+	{"mx25l51235f",	   INFO(0xc2201a, 0x0, 64 * 1024,  1024, RD_FULL | WR_QPP) },
+	{"mx25l12855e",	   INFO(0xc22618, 0x0, 64 * 1024,   256, RD_FULL | WR_QPP) },
+#endif
+#ifdef CONFIG_SPI_NOR_SPANSION	/* SPANSION */
+	{"s25fl008a",	   INFO(0x010213, 0x0, 64 * 1024,    16, 0) },
+	{"s25fl016a",	   INFO(0x010214, 0x0, 64 * 1024,    32, 0) },
+	{"s25fl032a",	   INFO(0x010215, 0x0, 64 * 1024,    64, 0) },
+	{"s25fl064a",	   INFO(0x010216, 0x0, 64 * 1024,   128, 0) },
+	{"s25fl116k",	   INFO(0x014015, 0x0, 64 * 1024,   128, 0) },
+	{"s25fl164k",	   INFO(0x014017, 0x0140,  64 * 1024,   128, 0) },
+	{"s25fl128p_256k", INFO(0x012018, 0x0300, 256 * 1024,    64, RD_FULL | WR_QPP) },
+	{"s25fl128p_64k",  INFO(0x012018, 0x0301,  64 * 1024,   256, RD_FULL | WR_QPP) },
+	{"s25fl032p",	   INFO(0x010215, 0x4d00,  64 * 1024,    64, RD_FULL | WR_QPP) },
+	{"s25fl064p",	   INFO(0x010216, 0x4d00,  64 * 1024,   128, RD_FULL | WR_QPP) },
+	{"s25fl128s_256k", INFO(0x012018, 0x4d00, 256 * 1024,    64, RD_FULL | WR_QPP) },
+	{"s25fl128s_64k",  INFO(0x012018, 0x4d01,  64 * 1024,   256, RD_FULL | WR_QPP) },
+	{"s25fl256s_256k", INFO(0x010219, 0x4d00, 256 * 1024,   128, RD_FULL | WR_QPP) },
+	{"s25fl256s_64k",  INFO(0x010219, 0x4d01,  64 * 1024,   512, RD_FULL | WR_QPP) },
+	{"s25s256s_64k",   INFO6(0x010219, 0x4d0181, 64 * 1024, 512, RD_FULL | WR_QPP | SECT_4K) },
+	{"s25s512s",       INFO(0x010220, 0x4d00, 128 * 1024,   512, RD_FULL | WR_QPP) },
+	{"s25fl512s_256k", INFO(0x010220, 0x4d00, 256 * 1024,   256, RD_FULL | WR_QPP) },
+	{"s25fl512s_64k",  INFO(0x010220, 0x4d01,  64 * 1024,  1024, RD_FULL | WR_QPP) },
+	{"s25fl512s_512k", INFO(0x010220, 0x4f00, 256 * 1024,   256, RD_FULL | WR_QPP) },
+#endif
+#ifdef CONFIG_SPI_NOR_STMICRO	/* STMICRO */
+	{"m25p10",	   INFO(0x202011, 0x0, 32 * 1024,     4, 0) },
+	{"m25p20",	   INFO(0x202012, 0x0, 64 * 1024,     4, 0) },
+	{"m25p40",	   INFO(0x202013, 0x0, 64 * 1024,     8, 0) },
+	{"m25p80",	   INFO(0x202014, 0x0, 64 * 1024,    16, 0) },
+	{"m25p16",	   INFO(0x202015, 0x0, 64 * 1024,    32, 0) },
+	{"m25pE16",	   INFO(0x208015, 0x1000, 64 * 1024, 32, 0) },
+	{"m25pX16",	   INFO(0x207115, 0x1000, 64 * 1024, 32, RD_QUAD | RD_DUAL) },
+	{"m25p32",	   INFO(0x202016, 0x0,  64 * 1024,    64, 0) },
+	{"m25p64",	   INFO(0x202017, 0x0,  64 * 1024,   128, 0) },
+	{"m25p128",	   INFO(0x202018, 0x0, 256 * 1024,    64, 0) },
+	{"m25pX64",	   INFO(0x207117, 0x0,  64 * 1024,   128, SECT_4K) },
+	{"n25q016a",       INFO(0x20bb15, 0x0,	64 * 1024,    32, SECT_4K) },
+	{"n25q32",	   INFO(0x20ba16, 0x0,  64 * 1024,    64, RD_FULL | WR_QPP | SECT_4K) },
+	{"n25q32a",	   INFO(0x20bb16, 0x0,  64 * 1024,    64, RD_FULL | WR_QPP | SECT_4K) },
+	{"n25q64",	   INFO(0x20ba17, 0x0,  64 * 1024,   128, RD_FULL | WR_QPP | SECT_4K) },
+	{"n25q64a",	   INFO(0x20bb17, 0x0,  64 * 1024,   128, RD_FULL | WR_QPP | SECT_4K) },
+	{"n25q128",	   INFO(0x20ba18, 0x0,  64 * 1024,   256, RD_FULL | WR_QPP) },
+	{"n25q128a",	   INFO(0x20bb18, 0x0,  64 * 1024,   256, RD_FULL | WR_QPP) },
+	{"n25q256",	   INFO(0x20ba19, 0x0,  64 * 1024,   512, RD_FULL | WR_QPP | SECT_4K) },
+	{"n25q256a",	   INFO(0x20bb19, 0x0,  64 * 1024,   512, RD_FULL | WR_QPP | SECT_4K) },
+	{"n25q512",	   INFO(0x20ba20, 0x0,  64 * 1024,  1024, RD_FULL | WR_QPP | E_FSR | SECT_4K) },
+	{"n25q512a",	   INFO(0x20bb20, 0x0,  64 * 1024,  1024, RD_FULL | WR_QPP | E_FSR | SECT_4K) },
+	{"n25q1024",	   INFO(0x20ba21, 0x0,  64 * 1024,  2048, RD_FULL | WR_QPP | E_FSR | SECT_4K) },
+	{"n25q1024a",	   INFO(0x20bb21, 0x0,  64 * 1024,  2048, RD_FULL | WR_QPP | E_FSR | SECT_4K) },
+#endif
+#ifdef CONFIG_SPI_NOR_SST	/* SST */
+	{"sst25vf040b",	   INFO(0xbf258d, 0x0,	64 * 1024,     8, SECT_4K | SST_WR) },
+	{"sst25vf080b",	   INFO(0xbf258e, 0x0,	64 * 1024,    16, SECT_4K | SST_WR) },
+	{"sst25vf016b",	   INFO(0xbf2541, 0x0,	64 * 1024,    32, SECT_4K | SST_WR) },
+	{"sst25vf032b",	   INFO(0xbf254a, 0x0,	64 * 1024,    64, SECT_4K | SST_WR) },
+	{"sst25vf064c",	   INFO(0xbf254b, 0x0,	64 * 1024,   128, SECT_4K) },
+	{"sst25wf512",	   INFO(0xbf2501, 0x0,	64 * 1024,     1, SECT_4K | SST_WR) },
+	{"sst25wf010",	   INFO(0xbf2502, 0x0,	64 * 1024,     2, SECT_4K | SST_WR) },
+	{"sst25wf020",	   INFO(0xbf2503, 0x0,	64 * 1024,     4, SECT_4K | SST_WR) },
+	{"sst25wf040",	   INFO(0xbf2504, 0x0,	64 * 1024,     8, SECT_4K | SST_WR) },
+	{"sst25wf040b",	   INFO(0x621613, 0x0,	64 * 1024,     8, SECT_4K) },
+	{"sst25wf080",	   INFO(0xbf2505, 0x0,	64 * 1024,    16, SECT_4K | SST_WR) },
+#endif
+#ifdef CONFIG_SPI_NOR_WINBOND	/* WINBOND */
+	{"w25p80",	   INFO(0xef2014, 0x0,	64 * 1024,    16, 0) },
+	{"w25p16",	   INFO(0xef2015, 0x0,	64 * 1024,    32, 0) },
+	{"w25p32",	   INFO(0xef2016, 0x0,	64 * 1024,    64, 0) },
+	{"w25x40",	   INFO(0xef3013, 0x0,	64 * 1024,     8, SECT_4K) },
+	{"w25x16",	   INFO(0xef3015, 0x0,	64 * 1024,    32, SECT_4K) },
+	{"w25x32",	   INFO(0xef3016, 0x0,	64 * 1024,    64, SECT_4K) },
+	{"w25x64",	   INFO(0xef3017, 0x0,	64 * 1024,   128, SECT_4K) },
+	{"w25q80bl",	   INFO(0xef4014, 0x0,	64 * 1024,    16, RD_FULL | WR_QPP | SECT_4K) },
+	{"w25q16cl",	   INFO(0xef4015, 0x0,	64 * 1024,    32, RD_FULL | WR_QPP | SECT_4K) },
+	{"w25q32bv",	   INFO(0xef4016, 0x0,	64 * 1024,    64, RD_FULL | WR_QPP | SECT_4K) },
+	{"w25q64cv",	   INFO(0xef4017, 0x0,	64 * 1024,   128, RD_FULL | WR_QPP | SECT_4K) },
+	{"w25q128bv",	   INFO(0xef4018, 0x0,	64 * 1024,   256, RD_FULL | WR_QPP | SECT_4K) },
+	{"w25q256",	   INFO(0xef4019, 0x0,	64 * 1024,   512, RD_FULL | WR_QPP | SECT_4K) },
+	{"w25q80bw",	   INFO(0xef5014, 0x0,	64 * 1024,    16, RD_FULL | WR_QPP | SECT_4K) },
+	{"w25q16dw",	   INFO(0xef6015, 0x0,	64 * 1024,    32, RD_FULL | WR_QPP | SECT_4K) },
+	{"w25q32dw",	   INFO(0xef6016, 0x0,	64 * 1024,    64, RD_FULL | WR_QPP | SECT_4K) },
+	{"w25q64dw",	   INFO(0xef6017, 0x0,	64 * 1024,   128, RD_FULL | WR_QPP | SECT_4K) },
+	{"w25q128fw",	   INFO(0xef6018, 0x0,	64 * 1024,   256, RD_FULL | WR_QPP | SECT_4K) },
+#endif
+#ifdef CONFIG_SPI_NOR_MISC
+	/* ATMEL */
+	{"at45db011d",	   INFO(0x1f2200, 0x0, 64 * 1024,     4, SECT_4K) },
+	{"at45db021d",	   INFO(0x1f2300, 0x0, 64 * 1024,     8, SECT_4K) },
+	{"at45db041d",	   INFO(0x1f2400, 0x0, 64 * 1024,     8, SECT_4K) },
+	{"at45db081d",	   INFO(0x1f2500, 0x0, 64 * 1024,    16, SECT_4K) },
+	{"at45db161d",	   INFO(0x1f2600, 0x0, 64 * 1024,    32, SECT_4K) },
+	{"at45db321d",	   INFO(0x1f2700, 0x0, 64 * 1024,    64, SECT_4K) },
+	{"at45db641d",	   INFO(0x1f2800, 0x0, 64 * 1024,   128, SECT_4K) },
+	{"at25df321a",     INFO(0x1f4701, 0x0, 64 * 1024,    64, SECT_4K) },
+	{"at25df321",      INFO(0x1f4700, 0x0, 64 * 1024,    64, SECT_4K) },
+	{"at26df081a",     INFO(0x1f4501, 0x0, 64 * 1024,    16, SECT_4K) },
+
+	/* EON */
+	{"en25q32b",	   INFO(0x1c3016, 0x0, 64 * 1024,    64, 0) },
+	{"en25q64",	   INFO(0x1c3017, 0x0, 64 * 1024,   128, SECT_4K) },
+	{"en25q128b",	   INFO(0x1c3018, 0x0, 64 * 1024,   256, 0) },
+	{"en25s64",	   INFO(0x1c3817, 0x0, 64 * 1024,   128, 0) },
+
+	/* GIGADEVICE */
+	{"gd25q64b",	   INFO(0xc84017, 0x0, 64 * 1024,   128, SECT_4K) },
+	{"gd25lq32",	   INFO(0xc86016, 0x0, 64 * 1024,    64, SECT_4K) },
+
+	/* ISSI */
+	{"is25lp032",	   INFO(0x9d6016, 0x0, 64 * 1024,    64, 0) },
+	{"is25lp064",	   INFO(0x9d6017, 0x0, 64 * 1024,   128, 0) },
+	{"is25lp128",	   INFO(0x9d6018, 0x0, 64 * 1024,   256, 0) },
+#endif
+	{},	/* Empty entry to terminate the list */
+	/*
+	 * Note:
+	 * Below paired flash devices has similar spi_nor params.
+	 * (s25fl129p_64k, s25fl128s_64k)
+	 * (w25q80bl, w25q80bv)
+	 * (w25q16cl, w25q16dv)
+	 * (w25q32bv, w25q32fv_spi)
+	 * (w25q64cv, w25q64fv_spi)
+	 * (w25q128bv, w25q128fv_spi)
+	 * (w25q32dw, w25q32fv_qpi)
+	 * (w25q64dw, w25q64fv_qpi)
+	 * (w25q128fw, w25q128fv_qpi)
+	 */
+};
diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
new file mode 100644
index 0000000..12e7cfe
--- /dev/null
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -0,0 +1,648 @@
+/*
+ * SPI NOR Core framework.
+ *
+ * Copyright (C) 2016 Jagan Teki <jagan@openedev.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <mapmem.h>
+#include <mtd.h>
+
+#include <linux/math64.h>
+#include <linux/types.h>
+#include <linux/mtd/spi-nor.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* Set write enable latch with Write Enable command */
+static inline int write_enable(struct spi_nor *nor)
+{
+	return nor->write_reg(nor, SNOR_OP_WREN, NULL, 0);
+}
+
+/* Re-set write enable latch with Write Disable command */
+static inline int write_disable(struct spi_nor *nor)
+{
+	return nor->write_reg(nor, SNOR_OP_WRDI, NULL, 0);
+}
+
+static int read_sr(struct spi_nor *nor)
+{
+	u8 sr;
+	int ret;
+
+	ret = nor->read_reg(nor, SNOR_OP_RDSR, &sr, 1);
+	if (ret < 0) {
+		debug("spi-nor: fail to read status register\n");
+		return ret;
+	}
+
+	return sr;
+}
+
+static int read_fsr(struct spi_nor *nor)
+{
+	u8 fsr;
+	int ret;
+
+	ret = nor->read_reg(nor, SNOR_OP_RDFSR, &fsr, 1);
+	if (ret < 0) {
+		debug("spi-nor: fail to read flag status register\n");
+		return ret;
+	}
+
+	return fsr;
+}
+
+static int write_sr(struct spi_nor *nor, u8 ws)
+{
+	nor->cmd_buf[0] = ws;
+	return nor->write_reg(nor, SNOR_OP_WRSR, nor->cmd_buf, 1);
+}
+
+#if defined(CONFIG_SPI_NOR_SPANSION) || defined(CONFIG_SPI_NOR_WINBOND)
+static int read_cr(struct spi_nor *nor)
+{
+	u8 cr;
+	int ret;
+
+	ret = nor->read_reg(nor, SNOR_OP_RDCR, &cr, 1);
+	if (ret < 0) {
+		debug("spi-nor: fail to read config register\n");
+		return ret;
+	}
+
+	return cr;
+}
+
+/*
+ * Write status Register and configuration register with 2 bytes
+ * - First byte will be written to the status register.
+ * - Second byte will be written to the configuration register.
+ * Return negative if error occured.
+ */
+static int write_sr_cr(struct spi_nor *nor, u16 val)
+{
+	nor->cmd_buf[0] = val & 0xff;
+	nor->cmd_buf[1] = (val >> 8);
+
+	return nor->write_reg(nor, SNOR_OP_WRSR, nor->cmd_buf, 2);
+}
+#endif
+
+static int spi_nor_sr_ready(struct spi_nor *nor)
+{
+	int sr = read_sr(nor);
+	if (sr < 0)
+		return sr;
+	else
+		return !(sr & SR_WIP);
+}
+
+static int spi_nor_fsr_ready(struct spi_nor *nor)
+{
+	int fsr = read_fsr(nor);
+	if (fsr < 0)
+		return fsr;
+	else
+		return fsr & FSR_READY;
+}
+
+static int spi_nor_ready(struct spi_nor *nor)
+{
+	int sr, fsr;
+
+	sr = spi_nor_sr_ready(nor);
+	if (sr < 0)
+		return sr;
+
+	fsr = 1;
+	if (nor->flags & SNOR_F_USE_FSR) {
+		fsr = spi_nor_fsr_ready(nor);
+		if (fsr < 0)
+			return fsr;
+	}
+
+	return sr && fsr;
+}
+
+static int spi_nor_wait_till_ready(struct spi_nor *nor, unsigned long timeout)
+{
+	int timebase, ret;
+
+	timebase = get_timer(0);
+
+	while (get_timer(timebase) < timeout) {
+		ret = spi_nor_ready(nor);
+		if (ret < 0)
+			return ret;
+		if (ret)
+			return 0;
+	}
+
+	printf("spi-nor: Timeout!\n");
+
+	return -ETIMEDOUT;
+}
+
+static const struct spi_nor_info *spi_nor_id(struct spi_nor *nor)
+{
+	int				tmp;
+	u8				id[SPI_NOR_MAX_ID_LEN];
+	const struct spi_nor_info	*info;
+
+	tmp = nor->read_reg(nor, SNOR_OP_RDID, id, SPI_NOR_MAX_ID_LEN);
+	if (tmp < 0) {
+		printf("spi-nor: error %d reading JEDEC ID\n", tmp);
+		return ERR_PTR(tmp);
+	}
+
+	info = spi_nor_ids;
+	for (; info->name != NULL; info++) {
+		if (info->id_len) {
+			if (!memcmp(info->id, id, info->id_len))
+				return info;
+		}
+	}
+
+	printf("spi-nor: unrecognized JEDEC id bytes: %02x, %2x, %2x\n",
+	       id[0], id[1], id[2]);
+	return ERR_PTR(-ENODEV);
+}
+
+static int spi_nor_erase(struct udevice *dev, struct erase_info *instr)
+{
+	struct mtd_info *mtd = mtd_get_info(dev);
+	struct spi_nor *nor = mtd->priv;
+	u32 addr, len, erase_addr;
+	uint32_t rem;
+	int ret = -1;
+
+	div_u64_rem(instr->len, mtd->erasesize, &rem);
+	if (rem)
+		return -EINVAL;
+
+	addr = instr->addr;
+	len = instr->len;
+
+	while (len) {
+		erase_addr = addr;
+
+		write_enable(nor);
+
+		ret = nor->write(nor, erase_addr, 0, NULL);
+		if (ret < 0)
+			goto erase_err;
+
+		ret = spi_nor_wait_till_ready(nor, SNOR_READY_WAIT_ERASE);
+		if (ret < 0)
+			goto erase_err;
+
+		addr += mtd->erasesize;
+		len -= mtd->erasesize;
+	}
+
+	write_disable(nor);
+
+	instr->state = MTD_ERASE_DONE;
+	mtd_erase_callback(instr);
+
+	return ret;
+
+erase_err:
+	instr->state = MTD_ERASE_FAILED;
+	return ret;
+}
+
+static int spi_nor_write(struct udevice *dev, loff_t to, size_t len,
+			 size_t *retlen, const u_char *buf)
+{
+	struct mtd_info *mtd = mtd_get_info(dev);
+	struct spi_nor *nor = mtd->priv;
+	size_t addr, byte_addr;
+	size_t chunk_len, actual;
+	uint32_t page_size;
+	int ret = -1;
+
+	page_size = mtd->writebufsize;
+
+	for (actual = 0; actual < len; actual += chunk_len) {
+		addr = to;
+
+		byte_addr = addr % page_size;
+		chunk_len = min(len - actual, (size_t)(page_size - byte_addr));
+
+		if (nor->max_write_size)
+			chunk_len = min(chunk_len,
+					(size_t)nor->max_write_size);
+
+		write_enable(nor);
+
+		ret = nor->write(nor, addr, chunk_len, buf + actual);
+		if (ret < 0)
+			break;
+
+		ret = spi_nor_wait_till_ready(nor, SNOR_READY_WAIT_PROG);
+		if (ret < 0)
+			return ret;
+
+		to += chunk_len;
+		*retlen += chunk_len;
+	}
+
+	return ret;
+}
+
+static int spi_nor_read(struct udevice *dev, loff_t from, size_t len,
+			size_t *retlen, u_char *buf)
+{
+	struct mtd_info *mtd = mtd_get_info(dev);
+	struct spi_nor *nor = mtd->priv;
+	int ret;
+
+	/* Handle memory-mapped SPI */
+	if (nor->memory_map) {
+		ret = nor->read(nor, from, len, buf);
+		if (ret) {
+			debug("spi-nor: mmap read failed\n");
+			return ret;
+		}
+
+		return ret;
+	}
+
+	ret = nor->read(nor, from, len, buf);
+	if (ret < 0)
+		return ret;
+
+	*retlen += len;
+
+	return ret;
+}
+
+#ifdef CONFIG_SPI_NOR_SST
+static int sst_byte_write(struct spi_nor *nor, u32 addr, const void *buf,
+			  size_t *retlen)
+{
+	int ret;
+
+	ret = write_enable(nor);
+	if (ret)
+		return ret;
+
+	nor->program_opcode = SNOR_OP_BP;
+
+	ret = nor->write(nor, addr, 1, buf);
+	if (ret)
+		return ret;
+
+	*retlen += 1;
+
+	return spi_nor_wait_till_ready(nor, SNOR_READY_WAIT_PROG);
+}
+
+static int sst_write_wp(struct udevice *dev, loff_t to, size_t len,
+			size_t *retlen, const u_char *buf)
+{
+	struct mtd_info *mtd = mtd_get_info(dev);
+	struct spi_nor *nor = mtd->priv;
+	size_t actual;
+	int ret;
+
+	/* If the data is not word aligned, write out leading single byte */
+	actual = to % 2;
+	if (actual) {
+		ret = sst_byte_write(nor, to, buf, retlen);
+		if (ret)
+			goto done;
+	}
+	to += actual;
+
+	ret = write_enable(nor);
+	if (ret)
+		goto done;
+
+	for (; actual < len - 1; actual += 2) {
+		nor->program_opcode = SNOR_OP_AAI_WP;
+
+		ret = nor->write(nor, to, 2, buf + actual);
+		if (ret) {
+			debug("spi-nor: sst word program failed\n");
+			break;
+		}
+
+		ret = spi_nor_wait_till_ready(nor, SNOR_READY_WAIT_PROG);
+		if (ret)
+			break;
+
+		to += 2;
+		*retlen += 2;
+	}
+
+	if (!ret)
+		ret = write_disable(nor);
+
+	/* If there is a single trailing byte, write it out */
+	if (!ret && actual != len)
+		ret = sst_byte_write(nor, to, buf + actual, retlen);
+
+ done:
+	return ret;
+}
+
+static int sst_write_bp(struct udevice *dev, loff_t to, size_t len,
+			size_t *retlen, const u_char *buf)
+{
+	struct mtd_info *mtd = mtd_get_info(dev);
+	struct spi_nor *nor = mtd->priv;
+	size_t actual;
+	int ret;
+
+	for (actual = 0; actual < len; actual++) {
+		ret = sst_byte_write(nor, to, buf + actual, retlen);
+		if (ret) {
+			debug("spi-nor: sst byte program failed\n");
+			break;
+		}
+		to++;
+	}
+
+	if (!ret)
+		ret = write_disable(nor);
+
+	return ret;
+}
+#endif
+
+#ifdef CONFIG_SPI_NOR_MACRONIX
+static int macronix_quad_enable(struct spi_nor *nor)
+{
+	int ret, val;
+
+	val = read_sr(nor);
+	if (val < 0)
+		return val;
+
+	if (val & SR_QUAD_EN_MX)
+		return 0;
+
+	write_enable(nor);
+
+	ret = write_sr(nor, val | SR_QUAD_EN_MX);
+	if (ret < 0)
+		return ret;
+
+	if (spi_nor_wait_till_ready(nor, SNOR_READY_WAIT_PROG))
+		return 1;
+
+	ret = read_sr(nor);
+	if (!(ret > 0 && (ret & SR_QUAD_EN_MX))) {
+		printf("spi-nor: Macronix Quad bit not set\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+#endif
+
+#if defined(CONFIG_SPI_NOR_SPANSION) || defined(CONFIG_SPI_NOR_WINBOND)
+static int spansion_quad_enable(struct spi_nor *nor)
+{
+	int ret, val;
+
+	val = read_cr(nor);
+	if (val < 0)
+		return val;
+
+	if (val & CR_QUAD_EN_SPAN)
+		return 0;
+
+	write_enable(nor);
+
+	ret = write_sr_cr(nor, val | CR_QUAD_EN_SPAN);
+	if (ret < 0)
+		return ret;
+
+	if (spi_nor_wait_till_ready(nor, SNOR_READY_WAIT_PROG))
+		return 1;
+
+	/* read back and check it */
+	ret = read_cr(nor);
+	if (!(ret > 0 && (ret & CR_QUAD_EN_SPAN))) {
+		printf("spi-nor: Spansion Quad bit not set\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+#endif
+
+static int set_quad_mode(struct spi_nor *nor, const struct spi_nor_info *info)
+{
+	switch (JEDEC_MFR(info)) {
+#ifdef CONFIG_SPI_NOR_MACRONIX
+	case SNOR_MFR_MACRONIX:
+		return macronix_quad_enable(nor);
+#endif
+#if defined(CONFIG_SPI_NOR_SPANSION) || defined(CONFIG_SPI_NOR_WINBOND)
+	case SNOR_MFR_SPANSION:
+	case SNOR_MFR_WINBOND:
+		return spansion_quad_enable(nor);
+#endif
+#ifdef CONFIG_SPI_NOR_STMICRO
+	case SNOR_MFR_MICRON:
+		return 0;
+#endif
+	default:
+		printf("spi-nor: Need set QEB func for %02x flash\n",
+		       JEDEC_MFR(info));
+		return -1;
+	}
+}
+
+#if CONFIG_IS_ENABLED(OF_CONTROL)
+int spi_nor_decode_fdt(const void *blob, struct spi_nor *nor)
+{
+	struct udevice *dev = nor->dev;
+	struct mtd_info *mtd = mtd_get_info(dev);
+	fdt_addr_t addr;
+	fdt_size_t size;
+	int node;
+
+	/* If there is no node, do nothing */
+	node = fdtdec_next_compatible(blob, 0, COMPAT_GENERIC_SPI_FLASH);
+	if (node < 0)
+		return 0;
+
+	addr = fdtdec_get_addr_size(blob, node, "memory-map", &size);
+	if (addr == FDT_ADDR_T_NONE) {
+		debug("%s: Cannot decode address\n", __func__);
+		return 0;
+	}
+
+	if (mtd->size != size) {
+		debug("%s: Memory map must cover entire device\n", __func__);
+		return -1;
+	}
+	nor->memory_map = map_sysmem(addr, size);
+
+	return 0;
+}
+#endif /* CONFIG_IS_ENABLED(OF_CONTROL) */
+
+static int spi_nor_check(struct spi_nor *nor)
+{
+	if (!nor->read || !nor->write ||
+	    !nor->read_reg || !nor->write_reg) {
+		pr_err("spi-nor: please fill all the necessary fields!\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+int spi_nor_scan(struct udevice *dev)
+{
+	struct mtd_info *mtd = mtd_get_info(dev);
+	struct spi_nor *nor = mtd->priv;
+	struct dm_mtd_ops *ops = mtd_get_ops(dev);
+	const struct spi_nor_info *info = NULL;
+	int ret;
+
+	ret = spi_nor_check(nor);
+	if (ret)
+		return ret;
+
+	info = spi_nor_id(nor);
+	if (IS_ERR_OR_NULL(info))
+		return -ENOENT;
+
+	/*
+	 * Atmel, SST, Macronix, and others serial NOR tend to power up
+	 * with the software protection bits set
+	 */
+	if (JEDEC_MFR(info) == SNOR_MFR_ATMEL ||
+	    JEDEC_MFR(info) == SNOR_MFR_MACRONIX ||
+	    JEDEC_MFR(info) == SNOR_MFR_SST) {
+		write_enable(nor);
+		write_sr(nor, 0);
+	}
+
+	mtd->name = info->name;
+	mtd->priv = nor;
+	mtd->type = MTD_NORFLASH;
+	mtd->writesize = 1;
+	mtd->flags = MTD_CAP_NORFLASH;
+	ops->_erase = spi_nor_erase;
+	ops->_read = spi_nor_read;
+
+	if (info->flags & E_FSR)
+		nor->flags |= SNOR_F_USE_FSR;
+
+	if (info->flags & SST_WR)
+		nor->flags |= SNOR_F_SST_WRITE;
+
+	ops->_write = spi_nor_write;
+#if defined(CONFIG_SPI_NOR_SST)
+	if (nor->flags & SNOR_F_SST_WRITE) {
+		if (nor->mode & SNOR_WRITE_1_1_BYTE)
+			ops->_write = sst_write_bp;
+		else
+			ops->_write = sst_write_wp;
+	}
+#endif
+
+	/* Compute the flash size */
+	nor->page_size = info->page_size;
+	/*
+	 * The Spansion S25FL032P and S25FL064P have 256b pages, yet use the
+	 * 0x4d00 Extended JEDEC code. The rest of the Spansion flashes with
+	 * the 0x4d00 Extended JEDEC code have 512b pages. All of the others
+	 * have 256b pages.
+	 */
+	if (JEDEC_EXT(info) == 0x4d00) {
+		if ((JEDEC_ID(info) != 0x0215) &&
+		    (JEDEC_ID(info) != 0x0216))
+			nor->page_size = 512;
+	}
+	mtd->writebufsize = nor->page_size;
+	mtd->size = info->sector_size * info->n_sectors;
+
+#ifdef CONFIG_MTD_SPI_NOR_USE_4K_SECTORS
+	/* prefer "small sector" erase if possible */
+	if (info->flags & SECT_4K) {
+		nor->erase_opcode = SNOR_OP_BE_4K;
+		mtd->erasesize = 4096;
+	} else
+#endif
+	{
+		nor->erase_opcode = SNOR_OP_SE;
+		mtd->erasesize = info->sector_size;
+	}
+
+	/* Look for read opcode */
+	nor->read_opcode = SNOR_OP_READ_FAST;
+	if (nor->mode & SNOR_READ)
+		nor->read_opcode = SNOR_OP_READ;
+	else if (nor->mode & SNOR_READ_1_1_4 && info->flags & RD_QUAD)
+		nor->read_opcode = SNOR_OP_READ_1_1_4;
+	else if (nor->mode & SNOR_READ_1_1_2 && info->flags & RD_DUAL)
+		nor->read_opcode = SNOR_OP_READ_1_1_2;
+
+	/* Look for program opcode */
+	if (info->flags & WR_QPP && nor->mode & SNOR_WRITE_1_1_4)
+		nor->program_opcode = SNOR_OP_QPP;
+	else
+		/* Go for default supported write cmd */
+		nor->program_opcode = SNOR_OP_PP;
+
+	/* Set the quad enable bit - only for quad commands */
+	if ((nor->read_opcode == SNOR_OP_READ_1_1_4) ||
+	    (nor->read_opcode == SNOR_OP_READ_1_1_4_IO) ||
+	    (nor->program_opcode == SNOR_OP_QPP)) {
+		ret = set_quad_mode(nor, info);
+		if (ret) {
+			debug("spi-nor: quad mode not supported for %02x\n",
+			      JEDEC_MFR(info));
+			return ret;
+		}
+	}
+
+	nor->addr_width = 3;
+
+	/* Dummy cycles for read */
+	switch (nor->read_opcode) {
+	case SNOR_OP_READ_1_1_4_IO:
+		nor->read_dummy = 16;
+		break;
+	case SNOR_OP_READ:
+		nor->read_dummy = 0;
+		break;
+	default:
+		nor->read_dummy = 8;
+	}
+
+#if CONFIG_IS_ENABLED(OF_CONTROL)
+	ret = spi_nor_decode_fdt(gd->fdt_blob, nor);
+	if (ret) {
+		debug("spi-nor: FDT decode error\n");
+		return -EINVAL;
+	}
+#endif
+
+#ifndef CONFIG_SPL_BUILD
+	printf("SPI-NOR: detected %s with page size ", mtd->name);
+	print_size(mtd->writebufsize, ", erase size ");
+	print_size(mtd->erasesize, ", total ");
+	print_size(mtd->size, "");
+	if (nor->memory_map)
+		printf(", mapped at %p", nor->memory_map);
+	puts("\n");
+#endif
+
+	return ret;
+}
diff --git a/include/linux/err.h b/include/linux/err.h
index e4d22d5..22e5756 100644
--- a/include/linux/err.h
+++ b/include/linux/err.h
@@ -36,6 +36,11 @@ static inline long IS_ERR(const void *ptr)
 	return IS_ERR_VALUE((unsigned long)ptr);
 }
 
+static inline bool IS_ERR_OR_NULL(const void *ptr)
+{
+	return !ptr || IS_ERR_VALUE((unsigned long)ptr);
+}
+
 /**
  * ERR_CAST - Explicitly cast an error-valued pointer to another pointer type
  * @ptr: The pointer to cast.
diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
new file mode 100644
index 0000000..4e5b3ba
--- /dev/null
+++ b/include/linux/mtd/spi-nor.h
@@ -0,0 +1,207 @@
+/*
+ * SPI NOR Core header file.
+ *
+ * Copyright (C) 2016 Jagan Teki <jagan@openedev.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef __MTD_SPI_NOR_H
+#define __MTD_SPI_NOR_H
+
+#include <common.h>
+
+/*
+ * Manufacturer IDs
+ *
+ * The first byte returned from the flash after sending opcode SPINOR_OP_RDID.
+ * Sometimes these are the same as CFI IDs, but sometimes they aren't.
+ */
+#define SNOR_MFR_ATMEL		0x1f
+#define SNOR_MFR_MACRONIX	0xc2
+#define SNOR_MFR_MICRON		0x20	/* ST Micro <--> Micron */
+#define SNOR_MFR_SPANSION	0x01
+#define SNOR_MFR_SST		0xbf
+#define SNOR_MFR_WINBOND	0xef
+
+/**
+ * SPI NOR opcodes.
+ *
+ * Note on opcode nomenclature: some opcodes have a format like
+ * SNOR_OP_FUNCTION{4,}_x_y_z. The numbers x, y, and z stand for the number
+ * of I/O lines used for the opcode, address, and data (respectively). The
+ * FUNCTION has an optional suffix of '4', to represent an opcode which
+ * requires a 4-byte (32-bit) address.
+ */
+#define SNOR_OP_WRDI		0x04	/* Write disable */
+#define SNOR_OP_WREN		0x06	/* Write enable */
+#define SNOR_OP_RDSR		0x05	/* Read status register */
+#define SNOR_OP_WRSR		0x01	/* Write status register 1 byte */
+#define SNOR_OP_READ		0x03	/* Read data bytes (low frequency) */
+#define SNOR_OP_READ_FAST	0x0b	/* Read data bytes (high frequency) */
+#define SNOR_OP_READ_1_1_2	0x3b	/* Read data bytes (Dual SPI) */
+#define SNOR_OP_READ_1_1_2_IO	0xbb	/* Read data bytes (Dual IO SPI) */
+#define SNOR_OP_READ_1_1_4	0x6b	/* Read data bytes (Quad SPI) */
+#define SNOR_OP_READ_1_1_4_IO	0xeb	/* Read data bytes (Quad IO SPI) */
+#define SNOR_OP_BRWR		0x17	/* Bank register write */
+#define SNOR_OP_BRRD		0x16	/* Bank register read */
+#define SNOR_OP_WREAR		0xC5	/* Write extended address register */
+#define SNOR_OP_RDEAR		0xC8	/* Read extended address register */
+#define SNOR_OP_PP		0x02	/* Page program (up to 256 bytes) */
+#define SNOR_OP_QPP		0x32	/* Quad Page program */
+#define SNOR_OP_BE_4K		0x20	/* Erase 4KiB block */
+#define SNOR_OP_BE_4K_PMC	0xd7    /* Erase 4KiB block on PMC chips */
+#define SNOR_OP_BE_32K		0x52    /* Erase 32KiB block */
+#define SPINOR_OP_CHIP_ERASE	0xc7    /* Erase whole flash chip */
+#define SNOR_OP_SE		0xd8	/* Sector erase (usually 64KiB) */
+#define SNOR_OP_RDID		0x9f	/* Read JEDEC ID */
+#define SNOR_OP_RDCR		0x35	/* Read configuration register */
+#define SNOR_OP_RDFSR		0x70	/* Read flag status register */
+
+/* Used for SST flashes only. */
+#define SNOR_OP_BP		0x02	/* Byte program */
+#define SNOR_OP_AAI_WP		0xad	/* Auto addr increment word program */
+
+/* Status Register bits. */
+#define SR_WIP			BIT(0)	/* Write in progress */
+#define SR_WEL			BIT(1)	/* Write enable latch */
+
+/* meaning of other SR_* bits may differ between vendors */
+#define SR_BP0			BIT(2)	/* Block protect 0 */
+#define SR_BP1			BIT(3)	/* Block protect 1 */
+#define SR_BP2			BIT(4)	/* Block protect 2 */
+#define SR_SRWD			BIT(7)	/* SR write protect */
+
+#define SR_QUAD_EN_MX		BIT(6)	/* Macronix Quad I/O */
+
+/* Flag Status Register bits */
+#define FSR_READY		BIT(7)
+
+/* Configuration Register bits. */
+#define CR_QUAD_EN_SPAN		BIT(1) /* Spansion/Winbond Quad I/O */
+
+/* Flash timeout values */
+#define SNOR_READY_WAIT_PROG	(2 * CONFIG_SYS_HZ)
+#define SNOR_READY_WAIT_ERASE	(5 * CONFIG_SYS_HZ)
+#define SNOR_MAX_CMD_SIZE	4
+#define SNOR_16MB_BOUN		0x1000000
+
+enum snor_option_flags {
+	SNOR_F_SST_WRITE	= BIT(0),
+	SNOR_F_USE_FSR		= BIT(1),
+	SNOR_F_U_PAGE		= BIT(1),
+};
+
+enum mode {
+	SNOR_READ		= BIT(0),
+	SNOR_READ_1_1_2		= BIT(1),
+	SNOR_READ_1_1_4		= BIT(2),
+	SNOR_READ_1_1_2_IO	= BIT(3),
+	SNOR_READ_1_1_4_IO	= BIT(4),
+	SNOR_WRITE_1_1_BYTE	= BIT(5),
+	SNOR_WRITE_1_1_4	= BIT(6),
+};
+
+#define JEDEC_MFR(info)		((info)->id[0])
+#define JEDEC_ID(info)		(((info)->id[1]) << 8 | ((info)->id[2]))
+#define JEDEC_EXT(info)		(((info)->id[3]) << 8 | ((info)->id[4]))
+#define SPI_NOR_MAX_ID_LEN	6
+
+struct spi_nor_info {
+	char		*name;
+
+	/*
+	 * This array stores the ID bytes.
+	 * The first three bytes are the JEDIC ID.
+	 * JEDEC ID zero means "no ID" (mostly older chips).
+	 */
+	u8		id[SPI_NOR_MAX_ID_LEN];
+	u8		id_len;
+
+	/* The size listed here is what works with SNOR_OP_SE, which isn't
+	 * necessarily called a "sector" by the vendor.
+	 */
+	unsigned	sector_size;
+	u16		n_sectors;
+
+	u16		page_size;
+
+	u16		flags;
+#define SECT_4K			BIT(0)
+#define E_FSR			BIT(1)
+#define SST_WR			BIT(2)
+#define WR_QPP			BIT(3)
+#define RD_QUAD			BIT(4)
+#define RD_DUAL			BIT(5)
+#define RD_QUADIO		BIT(6)
+#define RD_DUALIO		BIT(7)
+#define RD_FULL			(RD_QUAD | RD_DUAL | RD_QUADIO | RD_DUALIO)
+};
+
+extern const struct spi_nor_info spi_nor_ids[];
+
+/**
+ * struct spi_nor - Structure for defining a the SPI NOR layer
+ *
+ * @dev:		SPI NOR device
+ * @name:		name of the SPI NOR device
+ * @page_size:		the page size of the SPI NOR
+ * @addr_width:		number of address bytes
+ * @erase_opcode:	the opcode for erasing a sector
+ * @read_opcode:	the read opcode
+ * @read_dummy:		the dummy bytes needed by the read operation
+ * @program_opcode:	the program opcode
+ * @max_write_size:	If non-zero, the maximum number of bytes which can
+ *			be written at once, excluding command bytes.
+ * @flags:		flag options for the current SPI-NOR (SNOR_F_*)
+ * @mode:		read, write mode or any other mode bits.
+ * @read_mode:		read mode.
+ * @cmd_buf:		used by the write_reg
+ * @read_reg:		[DRIVER-SPECIFIC] read out the register
+ * @write_reg:		[DRIVER-SPECIFIC] write data to the register
+ * @read:		[DRIVER-SPECIFIC] read data from the SPI NOR
+ * @write:		[DRIVER-SPECIFIC] write data to the SPI NOR
+ * @memory_map:	address of read-only SPI NOR access
+ * @priv:		the private data
+ */
+struct spi_nor {
+	struct udevice		*dev;
+	const char		*name;
+	u32			page_size;
+	u8			addr_width;
+	u8			erase_opcode;
+	u8			read_opcode;
+	u8			read_dummy;
+	u8			program_opcode;
+	u32			max_write_size;
+	u32			flags;
+	u8			mode;
+	u8			read_mode;
+	u8			cmd_buf[SNOR_MAX_CMD_SIZE];
+
+	int (*read_reg)(struct spi_nor *nor, u8 cmd, u8 *val, int len);
+	int (*write_reg)(struct spi_nor *nor, u8 cmd, u8 *data, int len);
+
+	int (*read)(struct spi_nor *nor, loff_t from, size_t len,
+		    u_char *read_buf);
+	int (*write)(struct spi_nor *nor, loff_t to, size_t len,
+		     const u_char *write_buf);
+
+	void *memory_map;
+	void *priv;
+};
+
+/**
+ * spi_nor_scan() - scan the SPI NOR
+ *
+ * @dev:		SPI NOR device
+ *
+ * The drivers can use this fuction to scan the SPI NOR.
+ * In the scanning, it will try to get all the necessary information to
+ * fill the mtd_info{} and the spi_nor{}.
+ *
+ * @return 0 if OK, -ve on error
+ */
+int spi_nor_scan(struct udevice *dev);
+
+#endif /* __MTD_SPI_NOR_H */
-- 
2.7.4

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

* [U-Boot] [PATCH v9 03/21] mtd: spi-nor: Kconfig: Add MTD_SPI_NOR entry
  2016-10-30 18:23 [U-Boot] [PATCH v9 00/21] dm: Generic MTD Subsystem/SPI-NOR Jagan Teki
  2016-10-30 18:23 ` [U-Boot] [PATCH v9 01/21] dm: mtd: Add dm mtd core ops Jagan Teki
  2016-10-30 18:23 ` [U-Boot] [PATCH v9 02/21] mtd: Add SPI-NOR core support Jagan Teki
@ 2016-10-30 18:23 ` Jagan Teki
  2016-11-05 16:09   ` Simon Glass
  2016-10-30 18:23 ` [U-Boot] [PATCH v9 04/21] mtd: spi-nor: Kconfig: Add MTD_SPI_NOR_USE_4K_SECTORS Jagan Teki
                   ` (18 subsequent siblings)
  21 siblings, 1 reply; 39+ messages in thread
From: Jagan Teki @ 2016-10-30 18:23 UTC (permalink / raw)
  To: u-boot

Added CONFIG_MTD_SPI_NOR kconfig entry

Signed-off-by: Jagan Teki <jagan@openedev.com>
---
 drivers/mtd/Kconfig         |  2 ++
 drivers/mtd/spi-nor/Kconfig | 14 ++++++++++++++
 2 files changed, 16 insertions(+)
 create mode 100644 drivers/mtd/spi-nor/Kconfig

diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig
index 3a9705c..3dc4221 100644
--- a/drivers/mtd/Kconfig
+++ b/drivers/mtd/Kconfig
@@ -41,4 +41,6 @@ source "drivers/mtd/nand/Kconfig"
 
 source "drivers/mtd/spi/Kconfig"
 
+source "drivers/mtd/spi-nor/Kconfig"
+
 source "drivers/mtd/ubi/Kconfig"
diff --git a/drivers/mtd/spi-nor/Kconfig b/drivers/mtd/spi-nor/Kconfig
new file mode 100644
index 0000000..130b0a4
--- /dev/null
+++ b/drivers/mtd/spi-nor/Kconfig
@@ -0,0 +1,14 @@
+menuconfig MTD_SPI_NOR
+	tristate "SPI-NOR device support"
+	depends on MTD
+	help
+	  This is the core SPI NOR framework which can be used to interact SPI-NOR
+	  to SPI driver interface layer and the SPI-NOR controller driver.
+
+	  Unlike normal/generic spi controllers, they are few controllers which are
+	  exclusively used to connect SPI-NOR devices, called SPI-NOR controllers.
+	  So technically these controllers shouldn't reside at drivers/spi as these
+	  may effect the generic SPI bus functionalities, so this SPI-NOR core acts
+	  as a common core framework between the generic SPI controller drivers vs
+	  SPI-NOR controller drivers for SPI-NOR device access. Note that from SPI-NOR
+	  core to SPI drivers there should be an interface layer.
-- 
2.7.4

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

* [U-Boot] [PATCH v9 04/21] mtd: spi-nor: Kconfig: Add MTD_SPI_NOR_USE_4K_SECTORS
  2016-10-30 18:23 [U-Boot] [PATCH v9 00/21] dm: Generic MTD Subsystem/SPI-NOR Jagan Teki
                   ` (2 preceding siblings ...)
  2016-10-30 18:23 ` [U-Boot] [PATCH v9 03/21] mtd: spi-nor: Kconfig: Add MTD_SPI_NOR entry Jagan Teki
@ 2016-10-30 18:23 ` Jagan Teki
  2016-11-05 16:09   ` Simon Glass
  2016-10-30 18:23 ` [U-Boot] [PATCH v9 05/21] mtd: spi-nor: Kconfig: Add SPI_NOR_MISC entry Jagan Teki
                   ` (17 subsequent siblings)
  21 siblings, 1 reply; 39+ messages in thread
From: Jagan Teki @ 2016-10-30 18:23 UTC (permalink / raw)
  To: u-boot

Added CONFIG_MTD_SPI_NOR_USE_4K_SECTORS kconfig entry

Signed-off-by: Jagan Teki <jagan@openedev.com>
---
 drivers/mtd/spi-nor/Kconfig | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/drivers/mtd/spi-nor/Kconfig b/drivers/mtd/spi-nor/Kconfig
index 130b0a4..40cd5ba 100644
--- a/drivers/mtd/spi-nor/Kconfig
+++ b/drivers/mtd/spi-nor/Kconfig
@@ -12,3 +12,21 @@ menuconfig MTD_SPI_NOR
 	  as a common core framework between the generic SPI controller drivers vs
 	  SPI-NOR controller drivers for SPI-NOR device access. Note that from SPI-NOR
 	  core to SPI drivers there should be an interface layer.
+
+if MTD_SPI_NOR
+
+config MTD_SPI_NOR_USE_4K_SECTORS
+	bool "Use small 4096 B erase sectors"
+	default y
+	help
+	  Many flash memories support erasing small (4096 B) sectors. Depending
+	  on the usage this feature may provide performance gain in comparison
+	  to erasing whole blocks (32/64 KiB).
+	  Changing a small part of the flash's contents is usually faster with
+	  small sectors. On the other hand erasing should be faster when using
+	  64 KiB block instead of 16 ? 4 KiB sectors.
+
+	  Please note that some tools/drivers/filesystems may not work with
+	  4096 B erase size (e.g. UBIFS requires 15 KiB as a minimum).
+
+endif # MTD_SPI_NOR
-- 
2.7.4

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

* [U-Boot] [PATCH v9 05/21] mtd: spi-nor: Kconfig: Add SPI_NOR_MISC entry
  2016-10-30 18:23 [U-Boot] [PATCH v9 00/21] dm: Generic MTD Subsystem/SPI-NOR Jagan Teki
                   ` (3 preceding siblings ...)
  2016-10-30 18:23 ` [U-Boot] [PATCH v9 04/21] mtd: spi-nor: Kconfig: Add MTD_SPI_NOR_USE_4K_SECTORS Jagan Teki
@ 2016-10-30 18:23 ` Jagan Teki
  2016-11-05 16:09   ` Simon Glass
  2016-10-30 18:23 ` [U-Boot] [PATCH v9 06/21] mtd: spi-nor: Kconfig: Add SPI_NOR_MACRONIX entry Jagan Teki
                   ` (16 subsequent siblings)
  21 siblings, 1 reply; 39+ messages in thread
From: Jagan Teki @ 2016-10-30 18:23 UTC (permalink / raw)
  To: u-boot

Added CONFIG_SPI_NOR_MISC kconfig entry

Signed-off-by: Jagan Teki <jagan@openedev.com>
---
 drivers/mtd/spi-nor/Kconfig | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/drivers/mtd/spi-nor/Kconfig b/drivers/mtd/spi-nor/Kconfig
index 40cd5ba..348709b 100644
--- a/drivers/mtd/spi-nor/Kconfig
+++ b/drivers/mtd/spi-nor/Kconfig
@@ -29,4 +29,10 @@ config MTD_SPI_NOR_USE_4K_SECTORS
 	  Please note that some tools/drivers/filesystems may not work with
 	  4096 B erase size (e.g. UBIFS requires 15 KiB as a minimum).
 
+config SPI_NOR_MISC
+	bool "Miscellaneous SPI NOR flash's support"
+	help
+	  Add SPI-NOR support for various flash chips like Atmel, EON,
+	  GigaDevice, and ISSI.
+
 endif # MTD_SPI_NOR
-- 
2.7.4

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

* [U-Boot] [PATCH v9 06/21] mtd: spi-nor: Kconfig: Add SPI_NOR_MACRONIX entry
  2016-10-30 18:23 [U-Boot] [PATCH v9 00/21] dm: Generic MTD Subsystem/SPI-NOR Jagan Teki
                   ` (4 preceding siblings ...)
  2016-10-30 18:23 ` [U-Boot] [PATCH v9 05/21] mtd: spi-nor: Kconfig: Add SPI_NOR_MISC entry Jagan Teki
@ 2016-10-30 18:23 ` Jagan Teki
  2016-11-05 16:09   ` Simon Glass
  2016-10-30 18:23 ` [U-Boot] [PATCH v9 07/21] mtd: spi-nor: Kconfig: Add SPI_NOR_SPANSION entry Jagan Teki
                   ` (15 subsequent siblings)
  21 siblings, 1 reply; 39+ messages in thread
From: Jagan Teki @ 2016-10-30 18:23 UTC (permalink / raw)
  To: u-boot

Added CONFIG_SPI_NOR_MACRONIX kconfig entry

Signed-off-by: Jagan Teki <jagan@openedev.com>
---
 drivers/mtd/spi-nor/Kconfig | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/drivers/mtd/spi-nor/Kconfig b/drivers/mtd/spi-nor/Kconfig
index 348709b..c0ca14b 100644
--- a/drivers/mtd/spi-nor/Kconfig
+++ b/drivers/mtd/spi-nor/Kconfig
@@ -35,4 +35,9 @@ config SPI_NOR_MISC
 	  Add SPI-NOR support for various flash chips like Atmel, EON,
 	  GigaDevice, and ISSI.
 
+config SPI_NOR_MACRONIX
+	bool "Macronix SPI NOR flash support"
+	help
+	  Add support for various Macronix SPI flash chips (MX25Lxxx)
+
 endif # MTD_SPI_NOR
-- 
2.7.4

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

* [U-Boot] [PATCH v9 07/21] mtd: spi-nor: Kconfig: Add SPI_NOR_SPANSION entry
  2016-10-30 18:23 [U-Boot] [PATCH v9 00/21] dm: Generic MTD Subsystem/SPI-NOR Jagan Teki
                   ` (5 preceding siblings ...)
  2016-10-30 18:23 ` [U-Boot] [PATCH v9 06/21] mtd: spi-nor: Kconfig: Add SPI_NOR_MACRONIX entry Jagan Teki
@ 2016-10-30 18:23 ` Jagan Teki
  2016-11-05 16:09   ` Simon Glass
  2016-10-30 18:23 ` [U-Boot] [PATCH v9 08/21] mtd: spi-nor: Kconfig: Add SPI_NOR_STMICRO entry Jagan Teki
                   ` (14 subsequent siblings)
  21 siblings, 1 reply; 39+ messages in thread
From: Jagan Teki @ 2016-10-30 18:23 UTC (permalink / raw)
  To: u-boot

Added CONFIG_SPI_NOR_SPANSION kconfig entry

Signed-off-by: Jagan Teki <jagan@openedev.com>
---
 drivers/mtd/spi-nor/Kconfig | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/drivers/mtd/spi-nor/Kconfig b/drivers/mtd/spi-nor/Kconfig
index c0ca14b..d4303db 100644
--- a/drivers/mtd/spi-nor/Kconfig
+++ b/drivers/mtd/spi-nor/Kconfig
@@ -40,4 +40,9 @@ config SPI_NOR_MACRONIX
 	help
 	  Add support for various Macronix SPI flash chips (MX25Lxxx)
 
+config SPI_NOR_SPANSION
+	bool "Spansion SPI NOR flash support"
+	help
+	  Add support for various Spansion SPI flash chips (S25FLxxx)
+
 endif # MTD_SPI_NOR
-- 
2.7.4

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

* [U-Boot] [PATCH v9 08/21] mtd: spi-nor: Kconfig: Add SPI_NOR_STMICRO entry
  2016-10-30 18:23 [U-Boot] [PATCH v9 00/21] dm: Generic MTD Subsystem/SPI-NOR Jagan Teki
                   ` (6 preceding siblings ...)
  2016-10-30 18:23 ` [U-Boot] [PATCH v9 07/21] mtd: spi-nor: Kconfig: Add SPI_NOR_SPANSION entry Jagan Teki
@ 2016-10-30 18:23 ` Jagan Teki
  2016-11-05 16:09   ` Simon Glass
  2016-10-30 18:23 ` [U-Boot] [PATCH v9 09/21] mtd: spi-nor: Kconfig: Add SPI_NOR_SST entry Jagan Teki
                   ` (13 subsequent siblings)
  21 siblings, 1 reply; 39+ messages in thread
From: Jagan Teki @ 2016-10-30 18:23 UTC (permalink / raw)
  To: u-boot

Added CONFIG_SPI_NOR_STMICRO kconfig entry

Signed-off-by: Jagan Teki <jagan@openedev.com>
---
 drivers/mtd/spi-nor/Kconfig | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/drivers/mtd/spi-nor/Kconfig b/drivers/mtd/spi-nor/Kconfig
index d4303db..8ed4891 100644
--- a/drivers/mtd/spi-nor/Kconfig
+++ b/drivers/mtd/spi-nor/Kconfig
@@ -45,4 +45,9 @@ config SPI_NOR_SPANSION
 	help
 	  Add support for various Spansion SPI flash chips (S25FLxxx)
 
+config SPI_NOR_STMICRO
+	bool "STMicro SPI NOR flash support"
+	help
+	  Add support for various STMicro SPI flash chips (M25Pxxx and N25Qxxx)
+
 endif # MTD_SPI_NOR
-- 
2.7.4

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

* [U-Boot] [PATCH v9 09/21] mtd: spi-nor: Kconfig: Add SPI_NOR_SST entry
  2016-10-30 18:23 [U-Boot] [PATCH v9 00/21] dm: Generic MTD Subsystem/SPI-NOR Jagan Teki
                   ` (7 preceding siblings ...)
  2016-10-30 18:23 ` [U-Boot] [PATCH v9 08/21] mtd: spi-nor: Kconfig: Add SPI_NOR_STMICRO entry Jagan Teki
@ 2016-10-30 18:23 ` Jagan Teki
  2016-11-05 16:09   ` Simon Glass
  2016-10-30 18:23 ` [U-Boot] [PATCH v9 10/21] mtd: spi-nor: Kconfig: Add SPI_NOR_WINBOND entry Jagan Teki
                   ` (12 subsequent siblings)
  21 siblings, 1 reply; 39+ messages in thread
From: Jagan Teki @ 2016-10-30 18:23 UTC (permalink / raw)
  To: u-boot

Added CONFIG_SPI_NOR_SST kconfig entry

Signed-off-by: Jagan Teki <jagan@openedev.com>
---
 drivers/mtd/spi-nor/Kconfig | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/drivers/mtd/spi-nor/Kconfig b/drivers/mtd/spi-nor/Kconfig
index 8ed4891..edcc47e 100644
--- a/drivers/mtd/spi-nor/Kconfig
+++ b/drivers/mtd/spi-nor/Kconfig
@@ -50,4 +50,9 @@ config SPI_NOR_STMICRO
 	help
 	  Add support for various STMicro SPI flash chips (M25Pxxx and N25Qxxx)
 
+config SPI_NOR_SST
+	bool "SST SPI NOR flash support"
+	help
+	  Add support for various SST SPI flash chips (SST25xxx)
+
 endif # MTD_SPI_NOR
-- 
2.7.4

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

* [U-Boot] [PATCH v9 10/21] mtd: spi-nor: Kconfig: Add SPI_NOR_WINBOND entry
  2016-10-30 18:23 [U-Boot] [PATCH v9 00/21] dm: Generic MTD Subsystem/SPI-NOR Jagan Teki
                   ` (8 preceding siblings ...)
  2016-10-30 18:23 ` [U-Boot] [PATCH v9 09/21] mtd: spi-nor: Kconfig: Add SPI_NOR_SST entry Jagan Teki
@ 2016-10-30 18:23 ` Jagan Teki
  2016-11-05 16:09   ` Simon Glass
  2016-10-30 18:23 ` [U-Boot] [PATCH v9 11/21] spi: Add spi_write_then_read Jagan Teki
                   ` (11 subsequent siblings)
  21 siblings, 1 reply; 39+ messages in thread
From: Jagan Teki @ 2016-10-30 18:23 UTC (permalink / raw)
  To: u-boot

Added CONFIG_SPI_NOR_WINBOND kconfig entry

Signed-off-by: Jagan Teki <jagan@openedev.com>
---
 drivers/mtd/spi-nor/Kconfig | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/drivers/mtd/spi-nor/Kconfig b/drivers/mtd/spi-nor/Kconfig
index edcc47e..3ad2b16 100644
--- a/drivers/mtd/spi-nor/Kconfig
+++ b/drivers/mtd/spi-nor/Kconfig
@@ -55,4 +55,9 @@ config SPI_NOR_SST
 	help
 	  Add support for various SST SPI flash chips (SST25xxx)
 
+config SPI_NOR_WINBOND
+	bool "Winbond SPI NOR flash support"
+	help
+	  Add support for various Winbond SPI flash chips (W25xxx)
+
 endif # MTD_SPI_NOR
-- 
2.7.4

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

* [U-Boot] [PATCH v9 11/21] spi: Add spi_write_then_read
  2016-10-30 18:23 [U-Boot] [PATCH v9 00/21] dm: Generic MTD Subsystem/SPI-NOR Jagan Teki
                   ` (9 preceding siblings ...)
  2016-10-30 18:23 ` [U-Boot] [PATCH v9 10/21] mtd: spi-nor: Kconfig: Add SPI_NOR_WINBOND entry Jagan Teki
@ 2016-10-30 18:23 ` Jagan Teki
  2016-11-05 16:09   ` Simon Glass
  2016-10-30 18:23 ` [U-Boot] [PATCH v9 12/21] mtd: spi-nor: Add m25p80 driver Jagan Teki
                   ` (10 subsequent siblings)
  21 siblings, 1 reply; 39+ messages in thread
From: Jagan Teki @ 2016-10-30 18:23 UTC (permalink / raw)
  To: u-boot

Add support for SPI synchronous write followed by read,
this is common interface call from spi-nor to spi drivers.

Signed-off-by: Jagan Teki <jagan@openedev.com>
---
 drivers/spi/spi-uclass.c | 24 ++++++++++++++++++++++++
 include/spi.h            | 20 ++++++++++++++++++++
 2 files changed, 44 insertions(+)

diff --git a/drivers/spi/spi-uclass.c b/drivers/spi/spi-uclass.c
index d9c49e4..bb33fd8 100644
--- a/drivers/spi/spi-uclass.c
+++ b/drivers/spi/spi-uclass.c
@@ -108,6 +108,30 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
 	return dm_spi_xfer(slave->dev, bitlen, dout, din, flags);
 }
 
+int spi_write_then_read(struct spi_slave *slave, const u8 *opcode,
+			size_t n_opcode, const u8 *txbuf, u8 *rxbuf,
+			size_t n_buf)
+{
+	unsigned long flags = SPI_XFER_BEGIN;
+	int ret;
+
+	if (n_buf == 0)
+		flags |= SPI_XFER_END;
+
+	ret = spi_xfer(slave, n_opcode * 8, opcode, NULL, flags);
+	if (ret) {
+		debug("spi: failed to send command (%zu bytes): %d\n",
+		      n_opcode, ret);
+	} else if (n_buf != 0) {
+		ret = spi_xfer(slave, n_buf * 8, txbuf, rxbuf, SPI_XFER_END);
+		if (ret)
+			debug("spi: failed to transfer %zu bytes of data: %d\n",
+			      n_buf, ret);
+	}
+
+	return ret;
+}
+
 static int spi_child_post_bind(struct udevice *dev)
 {
 	struct dm_spi_slave_platdata *plat = dev_get_parent_platdata(dev);
diff --git a/include/spi.h b/include/spi.h
index 4c17983..336ac99 100644
--- a/include/spi.h
+++ b/include/spi.h
@@ -258,6 +258,26 @@ int spi_set_wordlen(struct spi_slave *slave, unsigned int wordlen);
 int  spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
 		void *din, unsigned long flags);
 
+/**
+ * spi_write_then_read - SPI synchronous write followed by read
+ *
+ * This performs a half duplex transaction in which the first transaction
+ * is to send the opcode and if the length of buf is non-zero then it start
+ * the second transaction as tx or rx based on the need from respective slave.
+ *
+ * @slave:	slave device with which opcode/data will be exchanged
+ * @opcode:	opcode used for specific transfer
+ * @n_opcode:	size of opcode, in bytes
+ * @txbuf:	buffer into which data to be written
+ * @rxbuf:	buffer into which data will be read
+ * @n_buf:	size of buf (whether it's [tx|rx]buf), in bytes
+ *
+ * Returns: 0 on success, not 0 on failure
+ */
+int spi_write_then_read(struct spi_slave *slave, const u8 *opcode,
+			size_t n_opcode, const u8 *txbuf, u8 *rxbuf,
+			size_t n_buf);
+
 /* Copy memory mapped data */
 void spi_flash_copy_mmap(void *data, void *offset, size_t len);
 
-- 
2.7.4

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

* [U-Boot] [PATCH v9 12/21] mtd: spi-nor: Add m25p80 driver
  2016-10-30 18:23 [U-Boot] [PATCH v9 00/21] dm: Generic MTD Subsystem/SPI-NOR Jagan Teki
                   ` (10 preceding siblings ...)
  2016-10-30 18:23 ` [U-Boot] [PATCH v9 11/21] spi: Add spi_write_then_read Jagan Teki
@ 2016-10-30 18:23 ` Jagan Teki
  2016-11-05 16:10   ` Simon Glass
  2016-10-30 18:23 ` [U-Boot] [PATCH v9 13/21] mtd: spi-nor: Kconfig: Add MTD_M25P80 entry Jagan Teki
                   ` (9 subsequent siblings)
  21 siblings, 1 reply; 39+ messages in thread
From: Jagan Teki @ 2016-10-30 18:23 UTC (permalink / raw)
  To: u-boot

This is MTD SPI-NOR driver for ST M25Pxx (and similar)
serial flash chips which is written as MTD_UCLASS.

Signed-off-by: Jagan Teki <jagan@openedev.com>
---
 drivers/mtd/spi-nor/Makefile |   3 +
 drivers/mtd/spi-nor/m25p80.c | 217 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 220 insertions(+)
 create mode 100644 drivers/mtd/spi-nor/m25p80.c

diff --git a/drivers/mtd/spi-nor/Makefile b/drivers/mtd/spi-nor/Makefile
index 15e43ea..d11ccf4 100644
--- a/drivers/mtd/spi-nor/Makefile
+++ b/drivers/mtd/spi-nor/Makefile
@@ -7,3 +7,6 @@
 ifdef CONFIG_MTD_SPI_NOR
 obj-y	+= spi-nor.o spi-nor-ids.o
 endif
+
+## spi-nor to spi interface driver
+obj-$(CONFIG_MTD_M25P80)	+= m25p80.o
diff --git a/drivers/mtd/spi-nor/m25p80.c b/drivers/mtd/spi-nor/m25p80.c
new file mode 100644
index 0000000..740d3f6
--- /dev/null
+++ b/drivers/mtd/spi-nor/m25p80.c
@@ -0,0 +1,217 @@
+/*
+ * MTD SPI-NOR driver for ST M25Pxx (and similar) serial flash chips
+ *
+ * Copyright (C) 2016 Jagan Teki <jagan@openedev.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <dma.h>
+#include <errno.h>
+#include <mtd.h>
+#include <spi.h>
+
+#include <dm/device-internal.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/spi-nor.h>
+
+#define MAX_CMD_SIZE		6
+struct m25p {
+	struct spi_slave	*spi;
+	struct spi_nor		spi_nor;
+	u8			command[MAX_CMD_SIZE];
+};
+
+static void m25p_addr2cmd(struct spi_nor *nor, unsigned int addr, u8 *cmd)
+{
+	/* opcode is in cmd[0] */
+	cmd[1] = addr >> (nor->addr_width * 8 -  8);
+	cmd[2] = addr >> (nor->addr_width * 8 - 16);
+	cmd[3] = addr >> (nor->addr_width * 8 - 24);
+}
+
+static int m25p_cmdsz(struct spi_nor *nor)
+{
+	return 1 + nor->addr_width;
+}
+
+static int m25p80_read_reg(struct spi_nor *nor, u8 opcode, u8 *val, int len)
+{
+	struct m25p *flash = nor->priv;
+	struct spi_slave *spi = flash->spi;
+	int ret;
+
+	ret = spi_write_then_read(spi, &opcode, 1, NULL, val, len);
+	if (ret < 0) {
+		debug("m25p80: error %d reading register %x\n", ret, opcode);
+		return ret;
+	}
+
+	return ret;
+}
+
+static int m25p80_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
+{
+	struct m25p *flash = nor->priv;
+	struct spi_slave *spi = flash->spi;
+	int ret;
+
+	ret = spi_write_then_read(spi, &opcode, 1, buf, NULL, len);
+	if (ret < 0) {
+		debug("m25p80: error %d writing register %x\n", ret, opcode);
+		return ret;
+	}
+
+	return ret;
+}
+
+/*
+ * TODO: remove the weak after all the other spi_flash_copy_mmap
+ * implementations removed from drivers
+ */
+void __weak flash_copy_mmap(void *data, void *offset, size_t len)
+{
+#ifdef CONFIG_DMA
+	if (!dma_memcpy(data, offset, len))
+		return;
+#endif
+	memcpy(data, offset, len);
+}
+
+static int m25p80_read(struct spi_nor *nor, loff_t from, size_t len,
+		       u_char *buf)
+{
+	struct m25p *flash = nor->priv;
+	struct spi_slave *spi = flash->spi;
+	unsigned int dummy = nor->read_dummy;
+	int ret;
+
+	if (nor->memory_map) {
+		spi_xfer(spi, 0, NULL, NULL, SPI_XFER_MMAP);
+		flash_copy_mmap(buf, nor->memory_map + from, len);
+		spi_xfer(spi, 0, NULL, NULL, SPI_XFER_MMAP_END);
+		spi_release_bus(spi);
+		return 0;
+	}
+
+	/* convert the dummy cycles to the number of bytes */
+	dummy /= 8;
+
+	flash->command[0] = nor->read_opcode;
+	m25p_addr2cmd(nor, from, flash->command);
+
+	ret = spi_write_then_read(spi, flash->command, m25p_cmdsz(nor) + dummy,
+				  NULL, buf, len);
+	if (ret < 0) {
+		debug("m25p80: error %d reading %x\n", ret, flash->command[0]);
+		return ret;
+	}
+
+	return ret;
+}
+
+static int m25p80_write(struct spi_nor *nor, loff_t to, size_t len,
+			const u_char *buf)
+{
+	struct m25p *flash = nor->priv;
+	struct spi_slave *spi = flash->spi;
+	int cmd_sz = m25p_cmdsz(nor);
+	int ret;
+
+	if ((nor->program_opcode == SNOR_OP_AAI_WP) && (buf != NULL))
+		cmd_sz = 1;
+
+	flash->command[0] = nor->program_opcode;
+	if (buf == NULL)
+		flash->command[0] = nor->erase_opcode;
+	m25p_addr2cmd(nor, to, flash->command);
+
+	ret = spi_write_then_read(spi, flash->command, cmd_sz, buf, NULL, len);
+	if (ret < 0) {
+		debug("m25p80: error %d writing %x\n", ret, flash->command[0]);
+		return ret;
+	}
+
+	return ret;
+}
+
+static int m25p_probe(struct udevice *dev)
+{
+	struct mtd_info *mtd = mtd_get_info(dev);
+	struct spi_slave *spi = dev_get_parent_priv(dev);
+	struct m25p *flash = dev_get_priv(dev);
+	struct spi_nor *nor;
+	int ret;
+
+	nor = &flash->spi_nor;
+
+	flash->spi = spi;
+	nor->priv = flash;
+	mtd->priv = nor;
+	nor->dev = dev;
+
+	/* install hooks */
+	nor->read = m25p80_read;
+	nor->write = m25p80_write;
+	nor->read_reg = m25p80_read_reg;
+	nor->write_reg = m25p80_write_reg;
+
+	/* claim spi bus */
+	ret = spi_claim_bus(spi);
+	if (ret) {
+		debug("m25p80: failed to claim SPI bus: %d\n", ret);
+		return ret;
+	}
+
+	if (spi->mode & SPI_RX_SLOW)
+		nor->mode = SNOR_READ;
+	else if (spi->mode & SPI_RX_DUAL)
+		nor->mode = SNOR_READ_1_1_2;
+	else if (spi->mode & SPI_RX_QUAD)
+		nor->mode = SNOR_READ_1_1_4;
+
+	if (spi->mode & SPI_TX_BYTE)
+		nor->mode |= SNOR_WRITE_1_1_BYTE;
+	else if (spi->mode & SPI_TX_QUAD)
+		nor->mode |= SNOR_WRITE_1_1_4;
+
+	nor->memory_map = spi->memory_map;
+	nor->max_write_size = spi->max_write_size;
+
+	ret = spi_nor_scan(dev);
+	if (ret)
+		goto err_scan;
+
+	ret = dm_add_mtd_device(dev);
+	if (ret)
+		goto err_mtd;
+
+	return 0;
+
+err_mtd:
+	device_remove(dev);
+	spi_free_slave(spi);
+err_scan:
+	spi_release_bus(spi);
+	return ret;
+}
+
+static const struct udevice_id m25p_ids[] = {
+	/*
+	 * Generic compatibility for SPI NOR that can be identified by the
+	 * JEDEC READ ID opcode (0x9F). Use this, if possible.
+	 */
+	{ .compatible = "jedec,spi-nor" },
+	{ }
+};
+
+U_BOOT_DRIVER(m25p80) = {
+	.name		= "m25p80",
+	.id		= UCLASS_MTD,
+	.of_match	= m25p_ids,
+	.probe		= m25p_probe,
+	.priv_auto_alloc_size = sizeof(struct m25p),
+};
-- 
2.7.4

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

* [U-Boot] [PATCH v9 13/21] mtd: spi-nor: Kconfig: Add MTD_M25P80 entry
  2016-10-30 18:23 [U-Boot] [PATCH v9 00/21] dm: Generic MTD Subsystem/SPI-NOR Jagan Teki
                   ` (11 preceding siblings ...)
  2016-10-30 18:23 ` [U-Boot] [PATCH v9 12/21] mtd: spi-nor: Add m25p80 driver Jagan Teki
@ 2016-10-30 18:23 ` Jagan Teki
  2016-11-05 16:09   ` Simon Glass
  2016-10-30 18:23 ` [U-Boot] [PATCH v9 14/21] mtd: spi-nor: Add zynq qspinor driver Jagan Teki
                   ` (8 subsequent siblings)
  21 siblings, 1 reply; 39+ messages in thread
From: Jagan Teki @ 2016-10-30 18:23 UTC (permalink / raw)
  To: u-boot

Add CONFIG_MTD_M25P80 kconfig entry

Signed-off-by: Jagan Teki <jagan@openedev.com>
---
 drivers/mtd/spi-nor/Kconfig | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/drivers/mtd/spi-nor/Kconfig b/drivers/mtd/spi-nor/Kconfig
index 3ad2b16..64d5553 100644
--- a/drivers/mtd/spi-nor/Kconfig
+++ b/drivers/mtd/spi-nor/Kconfig
@@ -15,6 +15,23 @@ menuconfig MTD_SPI_NOR
 
 if MTD_SPI_NOR
 
+config MTD_M25P80
+	tristate "Support most SPI Flash chips (AT26DF, M25P, W25X, ...)"
+	depends on DM_SPI
+	help
+	  This enables access to most modern SPI flash chips, used for
+	  program and data storage.   Series supported include Atmel AT26DF,
+	  Spansion S25SL, SST 25VF, ST M25P, and Winbond W25X.  Other chips
+	  are supported as well.  See the driver source for the current list,
+	  or to add other chips.
+
+	  Note that the original DataFlash chips (AT45 series, not AT26DF),
+	  need an entirely different driver.
+
+	  Set up your spi devices with the right board-specific platform data,
+	  if you want to specify device partitioning or to use a device which
+	  doesn't support the JEDEC ID instruction.
+
 config MTD_SPI_NOR_USE_4K_SECTORS
 	bool "Use small 4096 B erase sectors"
 	default y
-- 
2.7.4

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

* [U-Boot] [PATCH v9 14/21] mtd: spi-nor: Add zynq qspinor driver
  2016-10-30 18:23 [U-Boot] [PATCH v9 00/21] dm: Generic MTD Subsystem/SPI-NOR Jagan Teki
                   ` (12 preceding siblings ...)
  2016-10-30 18:23 ` [U-Boot] [PATCH v9 13/21] mtd: spi-nor: Kconfig: Add MTD_M25P80 entry Jagan Teki
@ 2016-10-30 18:23 ` Jagan Teki
  2016-10-30 18:23 ` [U-Boot] [PATCH v9 15/21] mtd: spi-nor: zynq_qspi: Kconfig: Add MTD_ZYNQ Jagan Teki
                   ` (7 subsequent siblings)
  21 siblings, 0 replies; 39+ messages in thread
From: Jagan Teki @ 2016-10-30 18:23 UTC (permalink / raw)
  To: u-boot

Zynq qspinor controller is works similar way as generic
spi controller with additional features that make this
controller work more specific to flash chips as salve
devices.

Why, zynq qspi written as spi-nor controller driver.

(1) dual flash:
    This describes two/dual memories are connected with
    a single chip select line from a controller like dual stack
    and dual parallel connections see doc/SPI/README.dual-flash
    for more details.

    Adding this support to spi-nor core looks quite managable and
    other generic code might effect and more over this is controller
    specific.

Signed-off-by: Jagan Teki <jagan@openedev.com>
---
 drivers/mtd/spi-nor/Makefile       |   3 +
 drivers/mtd/spi-nor/zynq_qspinor.c | 641 +++++++++++++++++++++++++++++++++++++
 2 files changed, 644 insertions(+)
 create mode 100644 drivers/mtd/spi-nor/zynq_qspinor.c

diff --git a/drivers/mtd/spi-nor/Makefile b/drivers/mtd/spi-nor/Makefile
index d11ccf4..bbaeee0 100644
--- a/drivers/mtd/spi-nor/Makefile
+++ b/drivers/mtd/spi-nor/Makefile
@@ -10,3 +10,6 @@ endif
 
 ## spi-nor to spi interface driver
 obj-$(CONFIG_MTD_M25P80)	+= m25p80.o
+
+## spi-nor drivers
+obj-$(CONFIG_MTD_ZYNQ_QSPI)	+= zynq_qspinor.o
diff --git a/drivers/mtd/spi-nor/zynq_qspinor.c b/drivers/mtd/spi-nor/zynq_qspinor.c
new file mode 100644
index 0000000..c04e87a
--- /dev/null
+++ b/drivers/mtd/spi-nor/zynq_qspinor.c
@@ -0,0 +1,641 @@
+/*
+ * (C) Copyright 2016 Jagan Teki <jagan@openedev.com>
+ *
+ * Xilinx Zynq Quad-SPI(QSPI) NOR controller driver
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <malloc.h>
+#include <mtd.h>
+#include <asm/io.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/spi-nor.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* zynq qspi register bit masks ZYNQ_QSPI_<REG>_<BIT>_MASK */
+#define ZYNQ_QSPI_CR_IFMODE_MASK	BIT(31)	/* Flash intrface mode*/
+#define ZYNQ_QSPI_CR_MSA_MASK		BIT(15)	/* Manual start enb */
+#define ZYNQ_QSPI_CR_MCS_MASK		BIT(14)	/* Manual chip select */
+#define ZYNQ_QSPI_CR_PCS_MASK		BIT(10)	/* Peri chip select */
+#define ZYNQ_QSPI_CR_FW_MASK		GENMASK(7, 6)	/* FIFO width */
+#define ZYNQ_QSPI_CR_SS_MASK		GENMASK(13, 10)	/* Slave Select */
+#define ZYNQ_QSPI_CR_BAUD_MASK		GENMASK(5, 3)	/* Baud rate div */
+#define ZYNQ_QSPI_CR_CPHA_MASK		BIT(2)	/* Clock phase */
+#define ZYNQ_QSPI_CR_CPOL_MASK		BIT(1)	/* Clock polarity */
+#define ZYNQ_QSPI_CR_MSTREN_MASK	BIT(0)	/* Mode select */
+#define ZYNQ_QSPI_IXR_RXNEMPTY_MASK	BIT(4)	/* RX_FIFO_not_empty */
+#define ZYNQ_QSPI_IXR_TXOW_MASK		BIT(2)	/* TX_FIFO_not_full */
+#define ZYNQ_QSPI_IXR_ALL_MASK		GENMASK(6, 0)	/* All IXR bits */
+#define ZYNQ_QSPI_ENR_SPI_EN_MASK	BIT(0)	/* SPI Enable */
+#define ZYNQ_QSPI_LQSPICFG_LQMODE_MASK	BIT(31) /* Linear QSPI Mode */
+
+/* zynq qspi Transmit Data Register */
+#define ZYNQ_QSPI_TXD_00_00_OFFSET	0x1C	/* Transmit 4-byte inst */
+#define ZYNQ_QSPI_TXD_00_01_OFFSET	0x80	/* Transmit 1-byte inst */
+#define ZYNQ_QSPI_TXD_00_10_OFFSET	0x84	/* Transmit 2-byte inst */
+#define ZYNQ_QSPI_TXD_00_11_OFFSET	0x88	/* Transmit 3-byte inst */
+
+#define ZYNQ_QSPI_XFER_BEGIN		BIT(0)
+#define ZYNQ_QSPI_XFER_END		BIT(1)
+#define ZYNQ_QSPI_TXFIFO_THRESHOLD	1	/* Tx FIFO threshold level*/
+#define ZYNQ_QSPI_RXFIFO_THRESHOLD	32	/* Rx FIFO threshold level */
+
+#define ZYNQ_QSPI_CR_BAUD_MAX		8	/* Baud rate divisor max val */
+#define ZYNQ_QSPI_CR_BAUD_SHIFT		3	/* Baud rate divisor shift */
+#define ZYNQ_QSPI_CR_SS_SHIFT		10	/* Slave select shift */
+#define ZYNQ_QSPI_MAX_CMDSZ		4	/* 1 byte opcode,3 byte addr */
+
+#define ZYNQ_QSPI_FIFO_DEPTH		63
+#ifndef CONFIG_SYS_ZYNQ_QSPI_WAIT
+#define CONFIG_SYS_ZYNQ_QSPI_WAIT	CONFIG_SYS_HZ/100	/* 10 ms */
+#endif
+
+/* zynq qspi register set */
+struct zynq_qspinor_regs {
+	u32 cr;		/* 0x00 */
+	u32 isr;	/* 0x04 */
+	u32 ier;	/* 0x08 */
+	u32 idr;	/* 0x0C */
+	u32 imr;	/* 0x10 */
+	u32 enr;	/* 0x14 */
+	u32 dr;		/* 0x18 */
+	u32 txd0r;	/* 0x1C */
+	u32 drxr;	/* 0x20 */
+	u32 sicr;	/* 0x24 */
+	u32 txftr;	/* 0x28 */
+	u32 rxftr;	/* 0x2C */
+	u32 gpior;	/* 0x30 */
+	u32 reserved0[19];
+	u32 txd1r;	/* 0x80 */
+	u32 txd2r;	/* 0x84 */
+	u32 txd3r;	/* 0x88 */
+	u32 reserved1[5];
+	u32 lqspicfg;	/* 0xA0 */
+	u32 lqspists;	/* 0xA4 */
+};
+
+/* zynq qspi platform data */
+struct zynq_qspinor_platdata {
+	struct zynq_qspinor_regs *regs;
+	u32 frequency;          /* input frequency */
+	u32 speed_hz;
+};
+
+/* zynq qspi priv */
+struct zynq_qspinor_priv {
+	struct zynq_qspinor_regs *regs;
+	struct spi_nor spi_nor;
+	u8 cs;
+	u8 mode;
+	u8 fifo_depth;
+	u32 freq;		/* required frequency */
+	u8 cmd[4];		/* 1 byte opcode + 3-byte address */
+	const void *tx_buf;
+	void *rx_buf;
+	unsigned len;
+	int bytes_to_transfer;
+	int bytes_to_receive;
+	unsigned int is_inst;
+	unsigned cs_change:1;
+};
+
+static void zynq_qspinor_addr(u32 addr, u8 *cmd)
+{
+	/* opcode is in cmd[0] */
+	cmd[1] = addr >> 16;
+	cmd[2] = addr >> 8;
+	cmd[3] = addr >> 0;
+}
+
+/*
+ * zynq_qspinor_read_data - Copy data to RX buffer
+ * @zqspi:	Pointer to the zynq_qspinor structure
+ * @data:	The 32 bit variable where data is stored
+ * @size:	Number of bytes to be copied from data to RX buffer
+ */
+static void zynq_qspinor_read_data(struct zynq_qspinor_priv *priv,
+				   u32 data, u8 size)
+{
+	u8 byte3;
+
+	debug("%s: data 0x%04x rx_buf addr: 0x%08x size %d\n", __func__ ,
+	      data, (unsigned)(priv->rx_buf), size);
+
+	if (priv->rx_buf) {
+		switch (size) {
+		case 1:
+			*((u8 *)priv->rx_buf) = data;
+			priv->rx_buf += 1;
+			break;
+		case 2:
+			*((u16 *)priv->rx_buf) = data;
+			priv->rx_buf += 2;
+			break;
+		case 3:
+			*((u16 *)priv->rx_buf) = data;
+			priv->rx_buf += 2;
+			byte3 = (u8)(data >> 16);
+			*((u8 *)priv->rx_buf) = byte3;
+			priv->rx_buf += 1;
+			break;
+		case 4:
+			/* Can not assume word aligned buffer */
+			memcpy(priv->rx_buf, &data, size);
+			priv->rx_buf += 4;
+			break;
+		default:
+			/* This will never execute */
+			break;
+		}
+	}
+	priv->bytes_to_receive -= size;
+	if (priv->bytes_to_receive < 0)
+		priv->bytes_to_receive = 0;
+}
+
+/*
+ * zynq_qspinor_write_data - Copy data from TX buffer
+ * @zqspi:	Pointer to the zynq_qspinor structure
+ * @data:	Pointer to the 32 bit variable where data is to be copied
+ * @size:	Number of bytes to be copied from TX buffer to data
+ */
+static void zynq_qspinor_write_data(struct  zynq_qspinor_priv *priv,
+		u32 *data, u8 size)
+{
+	if (priv->tx_buf) {
+		switch (size) {
+		case 1:
+			*data = *((u8 *)priv->tx_buf);
+			priv->tx_buf += 1;
+			*data |= 0xFFFFFF00;
+			break;
+		case 2:
+			*data = *((u16 *)priv->tx_buf);
+			priv->tx_buf += 2;
+			*data |= 0xFFFF0000;
+			break;
+		case 3:
+			*data = *((u16 *)priv->tx_buf);
+			priv->tx_buf += 2;
+			*data |= (*((u8 *)priv->tx_buf) << 16);
+			priv->tx_buf += 1;
+			*data |= 0xFF000000;
+			break;
+		case 4:
+			/* Can not assume word aligned buffer */
+			memcpy(data, priv->tx_buf, size);
+			priv->tx_buf += 4;
+			break;
+		default:
+			/* This will never execute */
+			break;
+		}
+	} else {
+		*data = 0;
+	}
+
+	debug("%s: data 0x%08x tx_buf addr: 0x%08x size %d\n", __func__,
+	      *data, (u32)priv->tx_buf, size);
+
+	priv->bytes_to_transfer -= size;
+	if (priv->bytes_to_transfer < 0)
+		priv->bytes_to_transfer = 0;
+}
+
+static void zynq_qspinor_chipselect(struct  zynq_qspinor_priv *priv, int is_on)
+{
+	u32 confr;
+	struct zynq_qspinor_regs *regs = priv->regs;
+
+	confr = readl(&regs->cr);
+
+	if (is_on) {
+		/* Select the slave */
+		confr &= ~ZYNQ_QSPI_CR_SS_MASK;
+		confr |= (~(1 << priv->cs) << ZYNQ_QSPI_CR_SS_SHIFT) &
+					ZYNQ_QSPI_CR_SS_MASK;
+	} else
+		/* Deselect the slave */
+		confr |= ZYNQ_QSPI_CR_SS_MASK;
+
+	writel(confr, &regs->cr);
+}
+
+/*
+ * zynq_qspinor_fill_tx_fifo - Fills the TX FIFO with as many bytes as possible
+ * @zqspi:	Pointer to the zynq_qspinor structure
+ */
+static void zynq_qspinor_fill_tx_fifo(struct zynq_qspinor_priv *priv, u32 size)
+{
+	u32 data = 0;
+	u32 fifocount = 0;
+	unsigned len, offset;
+	struct zynq_qspinor_regs *regs = priv->regs;
+	static const unsigned offsets[4] = {
+		ZYNQ_QSPI_TXD_00_00_OFFSET, ZYNQ_QSPI_TXD_00_01_OFFSET,
+		ZYNQ_QSPI_TXD_00_10_OFFSET, ZYNQ_QSPI_TXD_00_11_OFFSET };
+
+	while ((fifocount < size) &&
+			(priv->bytes_to_transfer > 0)) {
+		if (priv->bytes_to_transfer >= 4) {
+			if (priv->tx_buf) {
+				memcpy(&data, priv->tx_buf, 4);
+				priv->tx_buf += 4;
+			} else {
+				data = 0;
+			}
+			writel(data, &regs->txd0r);
+			priv->bytes_to_transfer -= 4;
+			fifocount++;
+		} else {
+			/* Write TXD1, TXD2, TXD3 only if TxFIFO is empty. */
+			if (!(readl(&regs->isr)
+					& ZYNQ_QSPI_IXR_TXOW_MASK) &&
+					!priv->rx_buf)
+				return;
+			len = priv->bytes_to_transfer;
+			zynq_qspinor_write_data(priv, &data, len);
+			offset = (priv->rx_buf) ? offsets[0] : offsets[len];
+			writel(data, &regs->cr + (offset / 4));
+		}
+	}
+}
+
+/*
+ * zynq_qspinor_irq_poll - Interrupt service routine of the QSPI controller
+ * @zqspi:	Pointer to the zynq_qspinor structure
+ *
+ * This function handles TX empty and Mode Fault interrupts only.
+ * On TX empty interrupt this function reads the received data from RX FIFO and
+ * fills the TX FIFO if there is any data remaining to be transferred.
+ * On Mode Fault interrupt this function indicates that transfer is completed,
+ * the SPI subsystem will identify the error as the remaining bytes to be
+ * transferred is non-zero.
+ *
+ * returns:	0 for poll timeout
+ *		1 transfer operation complete
+ */
+static int zynq_qspinor_irq_poll(struct zynq_qspinor_priv *priv)
+{
+	struct zynq_qspinor_regs *regs = priv->regs;
+	u32 rxindex = 0;
+	u32 rxcount;
+	u32 status, timeout;
+
+	/* Poll until any of the interrupt status bits are set */
+	timeout = get_timer(0);
+	do {
+		status = readl(&regs->isr);
+	} while ((status == 0) &&
+		(get_timer(timeout) < CONFIG_SYS_ZYNQ_QSPI_WAIT));
+
+	if (status == 0) {
+		printf("zynq_qspinor_irq_poll: Timeout!\n");
+		return -ETIMEDOUT;
+	}
+
+	writel(status, &regs->isr);
+
+	/* Disable all interrupts */
+	writel(ZYNQ_QSPI_IXR_ALL_MASK, &regs->idr);
+	if ((status & ZYNQ_QSPI_IXR_TXOW_MASK) ||
+	    (status & ZYNQ_QSPI_IXR_RXNEMPTY_MASK)) {
+		/*
+		 * This bit is set when Tx FIFO has < THRESHOLD entries. We have
+		 * the THRESHOLD value set to 1, so this bit indicates Tx FIFO
+		 * is empty
+		 */
+		rxcount = priv->bytes_to_receive - priv->bytes_to_transfer;
+		rxcount = (rxcount % 4) ? ((rxcount/4)+1) : (rxcount/4);
+		while ((rxindex < rxcount) &&
+				(rxindex < ZYNQ_QSPI_RXFIFO_THRESHOLD)) {
+			/* Read out the data from the RX FIFO */
+			u32 data;
+			data = readl(&regs->drxr);
+
+			if (priv->bytes_to_receive >= 4) {
+				if (priv->rx_buf) {
+					memcpy(priv->rx_buf, &data, 4);
+					priv->rx_buf += 4;
+				}
+				priv->bytes_to_receive -= 4;
+			} else {
+				zynq_qspinor_read_data(priv, data,
+						       priv->bytes_to_receive);
+			}
+			rxindex++;
+		}
+
+		if (priv->bytes_to_transfer) {
+			/* There is more data to send */
+			zynq_qspinor_fill_tx_fifo(priv,
+						  ZYNQ_QSPI_RXFIFO_THRESHOLD);
+
+			writel(ZYNQ_QSPI_IXR_ALL_MASK, &regs->ier);
+		} else {
+			/*
+			 * If transfer and receive is completed then only send
+			 * complete signal
+			 */
+			if (!priv->bytes_to_receive) {
+				/* return operation complete */
+				writel(ZYNQ_QSPI_IXR_ALL_MASK,
+				       &regs->idr);
+				return 1;
+			}
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * zynq_qspinor_start_transfer - Initiates the QSPI transfer
+ * @qspi:	Pointer to the spi_device structure
+ * @transfer:	Pointer to the spi_transfer structure which provide information
+ *		about next transfer parameters
+ *
+ * This function fills the TX FIFO, starts the QSPI transfer, and waits for the
+ * transfer to be completed.
+ *
+ * returns:	Number of bytes transferred in the last transfer
+ */
+static int zynq_qspinor_start_transfer(struct zynq_qspinor_priv *priv)
+{
+	u32 data = 0;
+	struct zynq_qspinor_regs *regs = priv->regs;
+
+	debug("%s: qspi: 0x%08x transfer: 0x%08x len: %d\n", __func__,
+	      (u32)priv, (u32)priv, priv->len);
+
+	priv->bytes_to_transfer = priv->len;
+	priv->bytes_to_receive = priv->len;
+
+	if (priv->len < 4)
+		zynq_qspinor_fill_tx_fifo(priv, priv->len);
+	else
+		zynq_qspinor_fill_tx_fifo(priv, priv->fifo_depth);
+
+	writel(ZYNQ_QSPI_IXR_ALL_MASK, &regs->ier);
+
+	/* wait for completion */
+	do {
+		data = zynq_qspinor_irq_poll(priv);
+	} while (data == 0);
+
+	return (priv->len) - (priv->bytes_to_transfer);
+}
+
+static int zynq_qspinor_transfer(struct zynq_qspinor_priv *priv)
+{
+	unsigned cs_change = 1;
+	int status = 0;
+
+	while (1) {
+		/* Select the chip if required */
+		if (cs_change)
+			zynq_qspinor_chipselect(priv, 1);
+
+		cs_change = priv->cs_change;
+
+		if (!priv->tx_buf && !priv->rx_buf && priv->len) {
+			status = -1;
+			break;
+		}
+
+		/* Request the transfer */
+		if (priv->len) {
+			status = zynq_qspinor_start_transfer(priv);
+			priv->is_inst = 0;
+		}
+
+		if (status != priv->len) {
+			if (status > 0)
+				status = -EMSGSIZE;
+			debug("zynq_qspinor_transfer:%d len:%d\n",
+			      status, priv->len);
+			break;
+		}
+		status = 0;
+
+		if (cs_change)
+			/* Deselect the chip */
+			zynq_qspinor_chipselect(priv, 0);
+
+		break;
+	}
+
+	return 0;
+}
+
+static int zynq_qspinor_xfer(struct spi_nor *nor, unsigned int bitlen,
+		const void *dout, void *din, unsigned long flags)
+{
+	struct zynq_qspinor_priv *priv = nor->priv;
+
+	priv->tx_buf = dout;
+	priv->rx_buf = din;
+	priv->len = bitlen / 8;
+
+	/*
+	 * Festering sore.
+	 * Assume that the beginning of a transfer with bits to
+	 * transmit must contain a device command.
+	 */
+	if (dout && flags & ZYNQ_QSPI_XFER_BEGIN)
+		priv->is_inst = 1;
+	else
+		priv->is_inst = 0;
+
+	if (flags & ZYNQ_QSPI_XFER_END)
+		priv->cs_change = 1;
+	else
+		priv->cs_change = 0;
+
+	zynq_qspinor_transfer(priv);
+
+	return 0;
+}
+
+static int zynq_qspinor_tx_then_rx(struct spi_nor *nor, const u8 *opcode,
+				size_t n_opcode, const u8 *txbuf,
+				u8 *rxbuf, size_t n_buf)
+{
+	struct zynq_qspinor_priv *priv = nor->priv;
+	struct zynq_qspinor_regs *regs = priv->regs;
+	unsigned long flags = ZYNQ_QSPI_XFER_BEGIN;
+	int ret;
+
+	/* enable spi */
+	writel(ZYNQ_QSPI_ENR_SPI_EN_MASK, &regs->enr);
+
+	if (n_buf == 0)
+		flags |= ZYNQ_QSPI_XFER_END;
+
+	ret = zynq_qspinor_xfer(nor, n_opcode * 8, opcode, NULL, flags);
+	if (ret) {
+		debug("%s: failed to send command (%zu bytes): %d\n",
+		      __func__, n_opcode, ret);
+	} else if (n_buf != 0) {
+		ret = zynq_qspinor_xfer(nor, n_buf * 8, txbuf, rxbuf,
+				     ZYNQ_QSPI_XFER_END);
+		if (ret)
+			debug("%s: failed to transfer %zu bytes of data: %d\n",
+			      __func__, n_buf, ret);
+	}
+
+	/* disable spi */
+	writel(~ZYNQ_QSPI_ENR_SPI_EN_MASK, &regs->enr);
+
+	return ret;
+}
+
+static int zynq_qspinor_read_reg(struct spi_nor *nor, u8 opcode,
+				 u8 *val, int len)
+{
+	return zynq_qspinor_tx_then_rx(nor, &opcode, 1, NULL, val, len);
+}
+
+static int zynq_qspinor_write_reg(struct spi_nor *nor, u8 opcode,
+				  u8 *buf, int len)
+{
+	return zynq_qspinor_tx_then_rx(nor, &opcode, 1, buf, NULL, len);
+}
+
+static int zynq_qspinor_read(struct spi_nor *nor, loff_t from,
+			     size_t len, u_char *buf)
+{
+	struct zynq_qspinor_priv *priv = nor->priv;
+	unsigned int cmd_sz = sizeof(priv->cmd) + (nor->read_dummy / 8);
+
+	priv->cmd[0] = nor->read_opcode;
+	zynq_qspinor_addr(from, priv->cmd);
+
+	return zynq_qspinor_tx_then_rx(nor, priv->cmd, cmd_sz, NULL, buf, len);
+}
+
+static int zynq_qspinor_write(struct spi_nor *nor, loff_t to,
+			      size_t len, const u_char *buf)
+{
+	struct zynq_qspinor_priv *priv = nor->priv;
+
+	priv->cmd[0] = nor->program_opcode;
+	if (buf == NULL)
+		priv->cmd[0] = nor->erase_opcode;
+
+	zynq_qspinor_addr(to, priv->cmd);
+
+	return zynq_qspinor_tx_then_rx(nor, priv->cmd, sizeof(priv->cmd),
+				    buf, NULL, len);
+}
+
+static void zynq_qspinor_init_hw(struct zynq_qspinor_priv *priv)
+{
+	struct zynq_qspinor_regs *regs = priv->regs;
+	u32 confr;
+
+	/* disable QSPI */
+	writel(~ZYNQ_QSPI_ENR_SPI_EN_MASK, &regs->enr);
+
+	/* disable Interrupts */
+	writel(ZYNQ_QSPI_IXR_ALL_MASK, &regs->idr);
+
+	/* dlear the TX and RX threshold reg */
+	writel(ZYNQ_QSPI_TXFIFO_THRESHOLD, &regs->txftr);
+	writel(ZYNQ_QSPI_RXFIFO_THRESHOLD, &regs->rxftr);
+
+	/* clear the RX FIFO */
+	while (readl(&regs->isr) & ZYNQ_QSPI_IXR_RXNEMPTY_MASK)
+		readl(&regs->drxr);
+
+	/* clear Interrupts */
+	writel(ZYNQ_QSPI_IXR_ALL_MASK, &regs->isr);
+
+	/* manual slave select and Auto start */
+	confr = readl(&regs->cr);
+	confr &= ~ZYNQ_QSPI_CR_MSA_MASK;
+	confr |= ZYNQ_QSPI_CR_IFMODE_MASK | ZYNQ_QSPI_CR_MCS_MASK |
+		ZYNQ_QSPI_CR_PCS_MASK | ZYNQ_QSPI_CR_FW_MASK |
+		ZYNQ_QSPI_CR_MSTREN_MASK;
+	writel(confr, &regs->cr);
+
+	/* enable SPI */
+	writel(ZYNQ_QSPI_ENR_SPI_EN_MASK, &regs->enr);
+}
+
+static int zynq_qspinor_ofdata_to_platdata(struct udevice *bus)
+{
+	struct zynq_qspinor_platdata *plat = bus->platdata;
+	const void *blob = gd->fdt_blob;
+	int node = bus->of_offset;
+
+	plat->regs = (struct zynq_qspinor_regs *)fdtdec_get_addr(blob,
+							      node, "reg");
+
+	/* FIXME: Use 166MHz as a suitable default */
+	plat->frequency = fdtdec_get_int(blob, node, "spi-max-frequency",
+					166666666);
+	plat->speed_hz = plat->frequency / 2;
+
+	debug("%s: regs=%p max-frequency=%d\n", __func__,
+	      plat->regs, plat->frequency);
+
+	return 0;
+}
+
+static int zynq_qspinor_probe(struct udevice *dev)
+{
+	struct mtd_info *mtd = mtd_get_info(dev);
+	struct zynq_qspinor_platdata *plat = dev_get_platdata(dev);
+	struct zynq_qspinor_priv *priv = dev_get_priv(dev);
+	struct spi_nor *nor;
+	int ret;
+
+	nor = &priv->spi_nor;
+
+	nor->priv = priv;
+	mtd->priv = nor;
+	nor->dev = dev;
+
+	priv->regs = plat->regs;
+	priv->fifo_depth = ZYNQ_QSPI_FIFO_DEPTH;
+
+	/* install the hooks */
+	nor->read = zynq_qspinor_read;
+	nor->write = zynq_qspinor_write;
+	nor->read_reg = zynq_qspinor_read_reg;
+	nor->write_reg = zynq_qspinor_write_reg;
+
+	/* init the zynq spi hw */
+	zynq_qspinor_init_hw(priv);
+
+	ret = spi_nor_scan(dev);
+	if (ret)
+		return -EINVAL;
+
+	ret = dm_add_mtd_device(dev);
+	if (ret)
+		return ret;
+
+	return ret;
+}
+
+static const struct udevice_id zynq_qspinor_ids[] = {
+	{ .compatible = "xlnx,zynq-qspinor-1.0" },
+	{ }
+};
+
+U_BOOT_DRIVER(zynq_qspinor) = {
+	.name   = "zynq_qspinor",
+	.id     = UCLASS_MTD,
+	.of_match = zynq_qspinor_ids,
+	.ofdata_to_platdata = zynq_qspinor_ofdata_to_platdata,
+	.platdata_auto_alloc_size = sizeof(struct zynq_qspinor_platdata),
+	.priv_auto_alloc_size = sizeof(struct zynq_qspinor_priv),
+	.probe  = zynq_qspinor_probe,
+};
-- 
2.7.4

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

* [U-Boot] [PATCH v9 15/21] mtd: spi-nor: zynq_qspi: Kconfig: Add MTD_ZYNQ
  2016-10-30 18:23 [U-Boot] [PATCH v9 00/21] dm: Generic MTD Subsystem/SPI-NOR Jagan Teki
                   ` (13 preceding siblings ...)
  2016-10-30 18:23 ` [U-Boot] [PATCH v9 14/21] mtd: spi-nor: Add zynq qspinor driver Jagan Teki
@ 2016-10-30 18:23 ` Jagan Teki
  2016-10-30 18:23 ` [U-Boot] [PATCH v9 16/21] mtd: spi-nor: Add 4-byte addresswidth support Jagan Teki
                   ` (6 subsequent siblings)
  21 siblings, 0 replies; 39+ messages in thread
From: Jagan Teki @ 2016-10-30 18:23 UTC (permalink / raw)
  To: u-boot

Add CONFIG_MTD_ZYNQ_QSPI kconfig entry

Signed-off-by: Jagan Teki <jagan@openedev.com>
---
 drivers/mtd/spi-nor/Kconfig | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/drivers/mtd/spi-nor/Kconfig b/drivers/mtd/spi-nor/Kconfig
index 64d5553..4b2a5e8 100644
--- a/drivers/mtd/spi-nor/Kconfig
+++ b/drivers/mtd/spi-nor/Kconfig
@@ -46,6 +46,15 @@ config MTD_SPI_NOR_USE_4K_SECTORS
 	  Please note that some tools/drivers/filesystems may not work with
 	  4096 B erase size (e.g. UBIFS requires 15 KiB as a minimum).
 
+config MTD_ZYNQ_QSPI
+	bool "Zynq QSPI NOR controller driver"
+	depends on ARCH_ZYNQ
+	help
+	  Enable the Zynq Quad-SPI (QSPI) driver. This driver can be
+	  used to access the SPI NOR flash on platforms embedding this
+	  Zynq QSPI IP core. This IP is used to connect the flash in
+	  4-bit qspi, 8-bit dual stacked and shared 4-bit dual parallel.
+
 config SPI_NOR_MISC
 	bool "Miscellaneous SPI NOR flash's support"
 	help
-- 
2.7.4

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

* [U-Boot] [PATCH v9 16/21] mtd: spi-nor: Add 4-byte addresswidth support
  2016-10-30 18:23 [U-Boot] [PATCH v9 00/21] dm: Generic MTD Subsystem/SPI-NOR Jagan Teki
                   ` (14 preceding siblings ...)
  2016-10-30 18:23 ` [U-Boot] [PATCH v9 15/21] mtd: spi-nor: zynq_qspi: Kconfig: Add MTD_ZYNQ Jagan Teki
@ 2016-10-30 18:23 ` Jagan Teki
  2016-10-30 18:23 ` [U-Boot] [PATCH v9 17/21] dm: mtd: Add uclass_driver.flags Jagan Teki
                   ` (5 subsequent siblings)
  21 siblings, 0 replies; 39+ messages in thread
From: Jagan Teki @ 2016-10-30 18:23 UTC (permalink / raw)
  To: u-boot

Add 4-byte address supports, so-that SPI-NOR chips
has > 16MiB should accessible.

Signed-off-by: Jagan Teki <jagan@openedev.com>
---
 drivers/mtd/spi-nor/m25p80.c  |  1 +
 drivers/mtd/spi-nor/spi-nor.c | 36 ++++++++++++++++++++++++++++++++++++
 include/linux/mtd/spi-nor.h   |  6 +++++-
 3 files changed, 42 insertions(+), 1 deletion(-)

diff --git a/drivers/mtd/spi-nor/m25p80.c b/drivers/mtd/spi-nor/m25p80.c
index 740d3f6..285fae5 100644
--- a/drivers/mtd/spi-nor/m25p80.c
+++ b/drivers/mtd/spi-nor/m25p80.c
@@ -31,6 +31,7 @@ static void m25p_addr2cmd(struct spi_nor *nor, unsigned int addr, u8 *cmd)
 	cmd[1] = addr >> (nor->addr_width * 8 -  8);
 	cmd[2] = addr >> (nor->addr_width * 8 - 16);
 	cmd[3] = addr >> (nor->addr_width * 8 - 24);
+	cmd[4] = addr >> (nor->addr_width * 8 - 32);
 }
 
 static int m25p_cmdsz(struct spi_nor *nor)
diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index 12e7cfe..103b68b 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -378,6 +378,36 @@ static int sst_write_bp(struct udevice *dev, loff_t to, size_t len,
 }
 #endif
 
+/* Enable/disable 4-byte addressing mode. */
+static int set_4byte(struct spi_nor *nor, const struct spi_nor_info *info,
+		     int enable)
+{
+	int status;
+	bool need_wren = false;
+	u8 cmd;
+
+	switch (JEDEC_MFR(info)) {
+	case SNOR_MFR_MICRON:
+		/* Some Micron need WREN command; all will accept it */
+		need_wren = true;
+	case SNOR_MFR_MACRONIX:
+	case SNOR_MFR_WINBOND:
+		if (need_wren)
+			write_enable(nor);
+
+		cmd = enable ? SNOR_OP_EN4B : SNOR_OP_EX4B;
+		status = nor->write_reg(nor, cmd, NULL, 0);
+		if (need_wren)
+			write_disable(nor);
+
+		return status;
+	default:
+		/* Spansion style */
+		nor->cmd_buf[0] = enable << 7;
+		return nor->write_reg(nor, SNOR_OP_BRWR, nor->cmd_buf, 1);
+	}
+}
+
 #ifdef CONFIG_SPI_NOR_MACRONIX
 static int macronix_quad_enable(struct spi_nor *nor)
 {
@@ -613,6 +643,12 @@ int spi_nor_scan(struct udevice *dev)
 	}
 
 	nor->addr_width = 3;
+	if (mtd->size > SNOR_16MB_BOUN) {
+		nor->addr_width = 4;
+		ret = set_4byte(nor, info, true);
+		if (ret)
+			return ret;
+	}
 
 	/* Dummy cycles for read */
 	switch (nor->read_opcode) {
diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
index 4e5b3ba..ad573db 100644
--- a/include/linux/mtd/spi-nor.h
+++ b/include/linux/mtd/spi-nor.h
@@ -62,6 +62,10 @@
 #define SNOR_OP_BP		0x02	/* Byte program */
 #define SNOR_OP_AAI_WP		0xad	/* Auto addr increment word program */
 
+/* Used for Macronix and Winbond flashes. */
+#define SNOR_OP_EN4B		0xb7	/* Enter 4-byte mode */
+#define SNOR_OP_EX4B		0xe9	/* Exit 4-byte mode */
+
 /* Status Register bits. */
 #define SR_WIP			BIT(0)	/* Write in progress */
 #define SR_WEL			BIT(1)	/* Write enable latch */
@@ -83,7 +87,7 @@
 /* Flash timeout values */
 #define SNOR_READY_WAIT_PROG	(2 * CONFIG_SYS_HZ)
 #define SNOR_READY_WAIT_ERASE	(5 * CONFIG_SYS_HZ)
-#define SNOR_MAX_CMD_SIZE	4
+#define SNOR_MAX_CMD_SIZE	6
 #define SNOR_16MB_BOUN		0x1000000
 
 enum snor_option_flags {
-- 
2.7.4

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

* [U-Boot] [PATCH v9 17/21] dm: mtd: Add uclass_driver.flags
  2016-10-30 18:23 [U-Boot] [PATCH v9 00/21] dm: Generic MTD Subsystem/SPI-NOR Jagan Teki
                   ` (15 preceding siblings ...)
  2016-10-30 18:23 ` [U-Boot] [PATCH v9 16/21] mtd: spi-nor: Add 4-byte addresswidth support Jagan Teki
@ 2016-10-30 18:23 ` Jagan Teki
  2016-11-05 16:10   ` Simon Glass
  2016-10-30 18:23 ` [U-Boot] [PATCH v9 18/21] dm: mtd: Add post_bind Jagan Teki
                   ` (4 subsequent siblings)
  21 siblings, 1 reply; 39+ messages in thread
From: Jagan Teki @ 2016-10-30 18:23 UTC (permalink / raw)
  To: u-boot

Add flags for mtd-uclass driver.

Signed-off-by: Jagan Teki <jagan@openedev.com>
---
 drivers/mtd/mtd-uclass.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/mtd/mtd-uclass.c b/drivers/mtd/mtd-uclass.c
index acbd713..5922b70 100644
--- a/drivers/mtd/mtd-uclass.c
+++ b/drivers/mtd/mtd-uclass.c
@@ -89,5 +89,6 @@ int dm_add_mtd_device(struct udevice *dev)
 UCLASS_DRIVER(mtd) = {
 	.id		= UCLASS_MTD,
 	.name		= "mtd",
+	.flags		= DM_UC_FLAG_SEQ_ALIAS,
 	.per_device_auto_alloc_size = sizeof(struct mtd_info),
 };
-- 
2.7.4

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

* [U-Boot] [PATCH v9 18/21] dm: mtd: Add post_bind
  2016-10-30 18:23 [U-Boot] [PATCH v9 00/21] dm: Generic MTD Subsystem/SPI-NOR Jagan Teki
                   ` (16 preceding siblings ...)
  2016-10-30 18:23 ` [U-Boot] [PATCH v9 17/21] dm: mtd: Add uclass_driver.flags Jagan Teki
@ 2016-10-30 18:23 ` Jagan Teki
  2016-11-05 16:10   ` Simon Glass
  2016-10-30 18:23 ` [U-Boot] [PATCH v9 19/21] cmd: Add mtd command support Jagan Teki
                   ` (3 subsequent siblings)
  21 siblings, 1 reply; 39+ messages in thread
From: Jagan Teki @ 2016-10-30 18:23 UTC (permalink / raw)
  To: u-boot

Add .post_bind on mtd-uclass driver

Signed-off-by: Jagan Teki <jagan@openedev.com>
---
 drivers/mtd/mtd-uclass.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/mtd/mtd-uclass.c b/drivers/mtd/mtd-uclass.c
index 5922b70..8eb6e8f 100644
--- a/drivers/mtd/mtd-uclass.c
+++ b/drivers/mtd/mtd-uclass.c
@@ -11,6 +11,8 @@
 #include <mtd.h>
 #include <linux/log2.h>
 
+#include <dm/device-internal.h>
+
 int dm_mtd_read(struct udevice *dev, loff_t from, size_t len, size_t *retlen,
 		u_char *buf)
 {
@@ -90,5 +92,6 @@ UCLASS_DRIVER(mtd) = {
 	.id		= UCLASS_MTD,
 	.name		= "mtd",
 	.flags		= DM_UC_FLAG_SEQ_ALIAS,
+	.post_bind	= dm_scan_fdt_dev,
 	.per_device_auto_alloc_size = sizeof(struct mtd_info),
 };
-- 
2.7.4

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

* [U-Boot] [PATCH v9 19/21] cmd: Add mtd command support
  2016-10-30 18:23 [U-Boot] [PATCH v9 00/21] dm: Generic MTD Subsystem/SPI-NOR Jagan Teki
                   ` (17 preceding siblings ...)
  2016-10-30 18:23 ` [U-Boot] [PATCH v9 18/21] dm: mtd: Add post_bind Jagan Teki
@ 2016-10-30 18:23 ` Jagan Teki
  2016-11-05 16:10   ` Simon Glass
  2016-10-30 18:23 ` [U-Boot] [PATCH v9 20/21] arm: dts: zynq: Add zynq-qspinor node Jagan Teki
                   ` (2 subsequent siblings)
  21 siblings, 1 reply; 39+ messages in thread
From: Jagan Teki @ 2016-10-30 18:23 UTC (permalink / raw)
  To: u-boot

cmd/mtd.c is a generic command to access all low level
MTD devices, like SPI-NOR, Parallel NOR and NAND.

This is implemented based on u-boot driver model, so any
new driver added for using this command must follow dm principles.

Signed-off-by: Jagan Teki <jagan@openedev.com>
---
 cmd/Kconfig              |   6 +
 cmd/Makefile             |   1 +
 cmd/mtd.c                | 285 +++++++++++++++++++++++++++++++++++++++++++++++
 drivers/mtd/Makefile     |   2 +-
 drivers/mtd/mtd-uclass.c |  17 +++
 include/mtd.h            |   9 ++
 6 files changed, 319 insertions(+), 1 deletion(-)
 create mode 100644 cmd/mtd.c

diff --git a/cmd/Kconfig b/cmd/Kconfig
index 86554ea..9386692 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -706,6 +706,12 @@ config CMD_FS_GENERIC
 	  fs types.
 endmenu
 
+config CMD_MTD
+	bool "Generic command for accessing MTD devices"
+	help
+	  Command to support MTD devices accessing.
+	  MTD devices like SPI-NOR, Parallel NOR and NAND.
+
 config CMD_UBI
 	tristate "Enable UBI - Unsorted block images commands"
 	select CRC32
diff --git a/cmd/Makefile b/cmd/Makefile
index 81b98ee..d50a405 100644
--- a/cmd/Makefile
+++ b/cmd/Makefile
@@ -95,6 +95,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 0000000..0dc529d
--- /dev/null
+++ b/cmd/mtd.c
@@ -0,0 +1,285 @@
+/*
+ * Command for accessing MTD device.
+ *
+ * Copyright (C) 2016 Jagan Teki <jagan@openedev.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <mtd.h>
+
+#include <asm/io.h>
+#include <jffs2/jffs2.h>
+
+static struct udevice *mtd_cur_dev;
+
+static int cmd_mtd_set_devnum(unsigned int devnum)
+{
+	struct udevice *dev;
+	int ret;
+
+	ret = uclass_get_device_by_seq(UCLASS_MTD, devnum, &dev);
+	if (ret) {
+		debug("%s: No MTD device %d\n", __func__, devnum);
+		return ret;
+	}
+	mtd_cur_dev = dev;
+
+	return 0;
+}
+
+static int mtd_get_cur_dev(struct udevice **devp)
+{
+	if (!mtd_cur_dev) {
+		puts("No MTD device selected\n");
+		return -ENODEV;
+	}
+	*devp = mtd_cur_dev;
+
+	return 0;
+}
+
+static int do_mtd_write_read(int argc, char * const argv[])
+{
+	struct udevice *dev;
+	struct mtd_info *mtd;
+	loff_t offset, addr, len, maxsize;
+	u_char *buf;
+	char *endp;
+	int idx = 0;
+	int ret;
+
+	if (argc < 3)
+		return -1;
+
+	ret = mtd_get_cur_dev(&dev);
+	if (ret)
+		return CMD_RET_FAILURE;
+
+	addr = simple_strtoul(argv[1], &endp, 16);
+	if (*argv[1] == 0 || *endp != 0)
+		return -1;
+
+	mtd = mtd_get_info(dev);
+	if (mtd_arg_off_size(argc - 2, &argv[2], &idx, &offset, &len,
+			     &maxsize, MTD_DEV_TYPE_NOR, mtd->size))
+		return -1;
+
+	buf = map_physmem(addr, len, MAP_WRBACK);
+	if (!buf) {
+		puts("failed to map physical memory\n");
+		return 1;
+	}
+
+	if (strcmp(argv[0], "write") == 0)
+		ret = dm_mtd_write(dev, offset, len, (size_t *)&len, buf);
+	else if (strcmp(argv[0], "read") == 0)
+		ret = dm_mtd_read(dev, offset, len, (size_t *)&len, buf);
+
+	printf("MTD: %zu bytes @ %#llx %s: ", (size_t)len, offset,
+	       (strcmp(argv[0], "read") == 0) ? "Read" : "Written");
+	if (ret)
+		printf("ERROR %d\n", ret);
+	else
+		printf("OK\n");
+
+	unmap_physmem(buf, len);
+
+	return ret == 0 ? 0 : 1;
+}
+
+static int mtd_parse_len_arg(struct mtd_info *mtd, char *arg, loff_t *len)
+{
+	char *ep;
+	char round_up_len; /* indicates if the "+length" form used */
+	ulong len_arg;
+
+	round_up_len = 0;
+	if (*arg == '+') {
+		round_up_len = 1;
+		++arg;
+	}
+
+	len_arg = simple_strtoul(arg, &ep, 16);
+	if (ep == arg || *ep != '\0')
+		return -1;
+
+	if (round_up_len && mtd->erasesize > 0)
+		*len = ROUND(len_arg, mtd->erasesize);
+	else
+		*len = len_arg;
+
+	return 1;
+}
+
+static int do_mtd_erase(int argc, char * const argv[])
+{
+	struct udevice *dev;
+	struct mtd_info *mtd;
+	struct erase_info instr;
+	loff_t addr, len, maxsize;
+	int idx = 0;
+	int ret;
+
+	if (argc < 3)
+		return -1;
+
+	ret = mtd_get_cur_dev(&dev);
+	if (ret)
+		return CMD_RET_FAILURE;
+
+	mtd = mtd_get_info(dev);
+	if (mtd_arg_off(argv[1], &idx, &addr, &len, &maxsize,
+			MTD_DEV_TYPE_NOR, mtd->size))
+		return -1;
+
+	ret = mtd_parse_len_arg(mtd, argv[2], &len);
+	if (ret != 1)
+		return -1;
+
+	instr.mtd = mtd;
+	instr.addr = addr;
+	instr.len = len;
+	instr.callback = 0;
+	ret = dm_mtd_erase(dev, &instr);
+	printf("MTD: %zu bytes @ %#llx Erased: %s\n", (size_t)len, addr,
+	       ret ? "ERROR" : "OK");
+
+	return ret == 0 ? 0 : 1;
+}
+
+static int do_mtd_probe(int argc, char * const argv[])
+{
+	struct udevice *dev, *devp;
+	int devnum;
+	int ret;
+
+	devnum = simple_strtoul(argv[1], NULL, 10);
+
+	debug("Setting MTD device to %d\n", devnum);
+	ret = cmd_mtd_set_devnum(devnum);
+	if (ret) {
+		printf("failing to set MTD device %d\n", devnum);
+		return CMD_RET_FAILURE;
+	}
+
+	ret = mtd_get_cur_dev(&dev);
+	if (ret)
+		return CMD_RET_FAILURE;
+
+	ret = dm_mtd_probe(dev, &devp);
+	if (ret) {
+		printf("failed to probe MTD device %d\n", devnum);
+		return CMD_RET_FAILURE;
+	}
+
+	return 0;
+}
+
+static int do_mtd_info(void)
+{
+	struct udevice *dev;
+	struct mtd_info *mtd;
+	int ret;
+
+	ret = mtd_get_cur_dev(&dev);
+	if (ret)
+		return CMD_RET_FAILURE;
+
+	mtd = mtd_get_info(dev);
+	printf("MTD Device %d: %s\n", dev->req_seq, mtd->name);
+	printf(" Page size:\t%d B\n Erase size:\t", mtd->writebufsize);
+	print_size(mtd->erasesize, "\n Size:\t\t");
+	print_size(mtd->size, "");
+	printf("\n");
+
+	return 0;
+}
+
+static int do_mtd_list(void)
+{
+	struct udevice *dev;
+	struct uclass *uc;
+	int ret;
+
+	ret = uclass_get(UCLASS_MTD, &uc);
+	if (ret)
+		return CMD_RET_FAILURE;
+
+	uclass_foreach_dev(dev, uc) {
+		printf("MTD %d:\t%s", dev->req_seq, dev->name);
+			if (device_active(dev))
+				printf("  (active %d)", dev->seq);
+		printf("\n");
+	}
+
+	return 0;
+}
+
+static int do_mtd(cmd_tbl_t *cmdtp, int flag, int argc,
+			char * const argv[])
+{
+	const char *cmd;
+	int ret = 0;
+
+	cmd = argv[1];
+	if (strcmp(cmd, "list") == 0) {
+		if (argc > 2)
+			goto usage;
+
+		ret = do_mtd_list();
+		goto done;
+	}
+
+	if (strcmp(cmd, "info") == 0) {
+		if (argc > 2)
+			goto usage;
+
+		ret = do_mtd_info();
+		goto done;
+	}
+
+	if (argc < 3)
+		goto usage;
+
+	--argc;
+	++argv;
+
+	if (strcmp(cmd, "probe") == 0) {
+		ret = do_mtd_probe(argc, argv);
+		goto done;
+	}
+
+	if (strcmp(cmd, "erase") == 0) {
+		ret = do_mtd_erase(argc, argv);
+		goto done;
+	}
+
+	if (strcmp(cmd, "write") == 0 || strcmp(cmd, "read") == 0) {
+		ret = do_mtd_write_read(argc, argv);
+		goto done;
+	}
+
+done:
+	if (ret != -1)
+		return ret;
+
+usage:
+	return CMD_RET_USAGE;
+}
+
+static char mtd_help_text[] =
+	"list			- show list of MTD devices\n"
+	"mtd info			- show current MTD device info\n"
+	"mtd probe devnum		- probe the 'devnum' MTD device\n"
+	"mtd erase offset len		- erase 'len' bytes from 'offset'\n"
+	"mtd write addr to len		- write 'len' bytes to 'to' from 'addr'\n"
+	"mtd read addr from len		- read 'len' bytes from 'from' to 'addr'";
+
+U_BOOT_CMD(
+	mtd, 5, 1, do_mtd,
+	"MTD Sub-system",
+	mtd_help_text
+);
diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile
index bd680a7..6b54b79 100644
--- a/drivers/mtd/Makefile
+++ b/drivers/mtd/Makefile
@@ -8,7 +8,7 @@
 ifneq (,$(findstring y,$(CONFIG_MTD_DEVICE)$(CONFIG_CMD_NAND)$(CONFIG_CMD_ONENAND)$(CONFIG_CMD_SF)))
 obj-y += mtdcore.o mtd_uboot.o
 endif
-obj-$(CONFIG_MTD) += mtd-uclass.o
+obj-$(CONFIG_MTD) += mtd-uclass.o mtd_uboot.o
 obj-$(CONFIG_MTD_PARTITIONS) += mtdpart.o
 obj-$(CONFIG_MTD_CONCAT) += mtdconcat.o
 obj-$(CONFIG_ALTERA_QSPI) += altera_qspi.o
diff --git a/drivers/mtd/mtd-uclass.c b/drivers/mtd/mtd-uclass.c
index 8eb6e8f..3e63de4 100644
--- a/drivers/mtd/mtd-uclass.c
+++ b/drivers/mtd/mtd-uclass.c
@@ -83,6 +83,23 @@ int dm_add_mtd_device(struct udevice *dev)
 	return 0;
 }
 
+int dm_mtd_probe(struct udevice *dev, struct udevice **devp)
+{
+	*devp = NULL;
+	int ret;
+
+	ret = device_probe(dev);
+	debug("%s:  device_probe: ret=%d\n", __func__, ret);
+	if (ret)
+		goto err;
+
+	*devp = dev;
+	return 0;
+err:
+	device_unbind(dev);
+	return ret;
+}
+
 /*
  * Implement a MTD uclass which should include most flash drivers.
  * The uclass private is pointed to mtd_info.
diff --git a/include/mtd.h b/include/mtd.h
index 93b5eaf..49b8272 100644
--- a/include/mtd.h
+++ b/include/mtd.h
@@ -74,4 +74,13 @@ int dm_mtd_erase(struct udevice *dev, struct erase_info *instr);
  */
 int dm_add_mtd_device(struct udevice *dev);
 
+/**
+ * dm_mtd_probe() - Probe MTD device
+ *
+ * @dev:	MTD device
+ * @devp:	MTD device pointer
+ * @return 0 if OK, -ve on error
+ */
+int dm_mtd_probe(struct udevice *dev, struct udevice **devp);
+
 #endif	/* _MTD_H_ */
-- 
2.7.4

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

* [U-Boot] [PATCH v9 20/21] arm: dts: zynq: Add zynq-qspinor node
  2016-10-30 18:23 [U-Boot] [PATCH v9 00/21] dm: Generic MTD Subsystem/SPI-NOR Jagan Teki
                   ` (18 preceding siblings ...)
  2016-10-30 18:23 ` [U-Boot] [PATCH v9 19/21] cmd: Add mtd command support Jagan Teki
@ 2016-10-30 18:23 ` Jagan Teki
  2016-10-30 18:23 ` [U-Boot] [PATCH v9 21/21] dm: zynq: microzed: Enable MTD/SPI-NOR Jagan Teki
  2016-11-05 16:07 ` [U-Boot] [PATCH v9 00/21] dm: Generic MTD Subsystem/SPI-NOR Simon Glass
  21 siblings, 0 replies; 39+ messages in thread
From: Jagan Teki @ 2016-10-30 18:23 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Jagan Teki <jagan@openedev.com>
---
 arch/arm/dts/zynq-7000.dtsi | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/arch/arm/dts/zynq-7000.dtsi b/arch/arm/dts/zynq-7000.dtsi
index b618a3f..b1aa480 100644
--- a/arch/arm/dts/zynq-7000.dtsi
+++ b/arch/arm/dts/zynq-7000.dtsi
@@ -206,6 +206,18 @@
 			#size-cells = <0>;
 		};
 
+		qspinor: spi-nor at e000d000 {
+			clock-names = "ref_clk", "pclk";
+			clocks = <&clkc 10>, <&clkc 43>;
+			compatible = "xlnx,zynq-qspinor-1.0";
+			status = "disabled";
+			interrupt-parent = <&intc>;
+			interrupts = <0 19 4>;
+			reg = <0xe000d000 0x1000>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+
 		gem0: ethernet at e000b000 {
 			compatible = "cdns,zynq-gem", "cdns,gem";
 			reg = <0xe000b000 0x1000>;
-- 
2.7.4

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

* [U-Boot] [PATCH v9 21/21] dm: zynq: microzed: Enable MTD/SPI-NOR
  2016-10-30 18:23 [U-Boot] [PATCH v9 00/21] dm: Generic MTD Subsystem/SPI-NOR Jagan Teki
                   ` (19 preceding siblings ...)
  2016-10-30 18:23 ` [U-Boot] [PATCH v9 20/21] arm: dts: zynq: Add zynq-qspinor node Jagan Teki
@ 2016-10-30 18:23 ` Jagan Teki
  2016-11-05 16:07 ` [U-Boot] [PATCH v9 00/21] dm: Generic MTD Subsystem/SPI-NOR Simon Glass
  21 siblings, 0 replies; 39+ messages in thread
From: Jagan Teki @ 2016-10-30 18:23 UTC (permalink / raw)
  To: u-boot

- Enable MTD driver model
- Enable cmd/mtd.c
- Enable SPI-NOR
- Enable MTD_ZYNQ_QSPI
- Add mtd1 alias for qspinor node
- Disable SPI_FLASH

Log:
----
Zynq> mtd
mtd - MTD Sub-system

Usage:
mtd list                        - show list of MTD devices
mtd info                        - show current MTD device info
mtd probe devnum                - probe the 'devnum' MTD device
mtd erase offset len            - erase 'len' bytes from 'offset'
mtd write addr to len           - write 'len' bytes to 'to' from 'addr'
mtd read addr from len          - read 'len' bytes from 'from' to 'addr'
Zynq> mtd list
MTD 1:  spi-nor at e000d000
Zynq>
MTD 1:  spi-nor at e000d000
Zynq> mtd list
MTD 1:  spi-nor at e000d000
Zynq> mtd probe 0
failing to set MTD device 0
Zynq> mtd probe 1
SPI-NOR: detected s25fl128s_64k with page size 256 Bytes, erase size 64 KiB, total 16 MiB
Zynq> mtd info
MTD Device 1: s25fl128s_64k
 Page size:     256 B
 Erase size:    64 KiB
 Size:          16 MiB
Zynq> mtd list
MTD 1:  spi-nor at e000d000  (active 1)
Zynq> mtd erase 0xE00000 0x100000
MTD: 1048576 bytes @ 0xe00000 Erased: OK
Zynq> mw.b 0x100 0xaa 0x100000
Zynq> mtd write 0x100 0xE00000 0x100000
device 0 offset 0xe00000, size 0x100000
MTD: 1048576 bytes @ 0xe00000 Written: OK
Zynq> mtd read 0x3000000 0xE00000 0x100000
device 0 offset 0xe00000, size 0x100000
MTD: 1048576 bytes @ 0xe00000 Read: OK
Zynq> cmp.b 0x3000000 0x100 0x100000
Total of 1048576 byte(s) were the same

Signed-off-by: Jagan Teki <jagan@openedev.com>
---
 arch/arm/dts/zynq-microzed.dts  |  6 ++++++
 configs/zynq_microzed_defconfig | 14 +++++++++-----
 2 files changed, 15 insertions(+), 5 deletions(-)

diff --git a/arch/arm/dts/zynq-microzed.dts b/arch/arm/dts/zynq-microzed.dts
index cb238cd..8f56f44 100644
--- a/arch/arm/dts/zynq-microzed.dts
+++ b/arch/arm/dts/zynq-microzed.dts
@@ -15,6 +15,7 @@
 	aliases {
 		serial0 = &uart1;
 		spi0 = &qspi;
+		mtd1 = &qspinor;
 		mmc0 = &sdhci0;
 	};
 
@@ -43,6 +44,11 @@
 	status = "okay";
 };
 
+&qspinor {
+	u-boot,dm-pre-reloc;
+	status = "okay";
+};
+
 &uart1 {
 	u-boot,dm-pre-reloc;
 	status = "okay";
diff --git a/configs/zynq_microzed_defconfig b/configs/zynq_microzed_defconfig
index ad0da0b..87bcbbb 100644
--- a/configs/zynq_microzed_defconfig
+++ b/configs/zynq_microzed_defconfig
@@ -11,6 +11,7 @@ CONFIG_SYS_PROMPT="Zynq> "
 # CONFIG_CMD_IMLS is not set
 # CONFIG_CMD_FLASH is not set
 CONFIG_CMD_MMC=y
+CONFIG_CMD_MTD=y
 CONFIG_CMD_SF=y
 CONFIG_CMD_USB=y
 CONFIG_CMD_DFU=y
@@ -31,13 +32,16 @@ CONFIG_SPL_DM_SEQ_ALIAS=y
 CONFIG_DFU_MMC=y
 CONFIG_DFU_RAM=y
 CONFIG_ZYNQ_SDHCI=y
-CONFIG_SPI_FLASH=y
-CONFIG_SPI_FLASH_BAR=y
-CONFIG_SPI_FLASH_SPANSION=y
-CONFIG_SPI_FLASH_STMICRO=y
-CONFIG_SPI_FLASH_WINBOND=y
 CONFIG_ZYNQ_GEM=y
 CONFIG_ZYNQ_QSPI=y
+CONFIG_MTD=y
+CONFIG_MTD_SPI_NOR=y
+CONFIG_MTD_ZYNQ_QSPI=y
+CONFIG_SPI_NOR_STMICRO=y
+CONFIG_SPI_NOR_SPANSION=y
+CONFIG_SPI_NOR_SST=y
+CONFIG_SPI_NOR_WINBOND=y
+CONFIG_SPI_NOR_MACRONIX=y
 CONFIG_USB=y
 CONFIG_USB_EHCI_HCD=y
 CONFIG_USB_ULPI_VIEWPORT=y
-- 
2.7.4

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

* [U-Boot] [PATCH v9 00/21] dm: Generic MTD Subsystem/SPI-NOR
  2016-10-30 18:23 [U-Boot] [PATCH v9 00/21] dm: Generic MTD Subsystem/SPI-NOR Jagan Teki
                   ` (20 preceding siblings ...)
  2016-10-30 18:23 ` [U-Boot] [PATCH v9 21/21] dm: zynq: microzed: Enable MTD/SPI-NOR Jagan Teki
@ 2016-11-05 16:07 ` Simon Glass
  21 siblings, 0 replies; 39+ messages in thread
From: Simon Glass @ 2016-11-05 16:07 UTC (permalink / raw)
  To: u-boot

Hi Jagan,

On 30 October 2016 at 12:23, Jagan Teki <jagan@openedev.com> wrote:
> The previous series [1] [2] are added SPI-NOR on top of
> mtd/spi where it bypassing DM_SPI_FLASH and use the existing
> mtd core (which is non-dm), I feel this is moving in a reverse
> direction where adding new feature with the help of non-dm mtd
> core support and also few of the spi drivers are not fully dm-driven.
>
> Previous design series[3]: keep the mtd/spi as it is and start adding
> spi-nor features separately. The idea here is to add the dm features
> to MTD first and then add UCLASS_MTD spi-nor drivers so-that the commands
> are interfacing to spi-nor through dm-driven MTD core to spi-nor.
>
> This series adding a new command 'mtd.c' which is common for all MTD devices
> SPI-NOR, SPI-NOR(master) and Parallel NOR with dm-driven.
>
> SPI-NOR and Parallel NOR:
> ------------------------
>
> ------------------------------------
>               mtd.c
> ------------------------------------
>             mtd-uclass
> ------------------------------------
>        SPI-NOR Core        CFI FLASH
> ------------------------------------
> m25p80.c        zynq_qspi
> -----------------------------------
> spi-uclass      SPI NOR chip
> -----------------------------------
> spi drivers
> -----------------------------------
> SPI NOR chip
> -----------------------------------
>
> drivers/mtd/spi-nor/
>
> - Add dm mtd operations
> - spi-nor.c:   Add basic SPI-NOR core like erase/read/write ops and lock's will add later
> - m25p80.c:    spi-nor to spi divers interface layer drivers/spi-nor
> - zynq_qspi.c: zynq qspi spi-nor controller driver.
>
> Current Status:
> --------------
> - SPI-NOR Controller design flow working, see Log
>
> TODO:
> ----
> - SPI-NOR with SPI bus
> - Parallel NOR.
>
> Log:
> ----
> Zynq> mtd
> mtd - MTD Sub-system
>
> Usage:
> mtd list                        - show list of MTD devices
> mtd info                        - show current MTD device info
> mtd probe devnum                - probe the 'devnum' MTD device
> mtd erase offset len            - erase 'len' bytes from 'offset'
> mtd write addr to len           - write 'len' bytes to 'to' from 'addr'
> mtd read addr from len          - read 'len' bytes from 'from' to 'addr'
> Zynq> mtd list
> MTD 1:  spi-nor at e000d000
> Zynq>
> MTD 1:  spi-nor at e000d000
> Zynq> mtd list
> MTD 1:  spi-nor at e000d000
> Zynq> mtd probe 0
> failing to set MTD device 0
> Zynq> mtd probe 1
> SPI-NOR: detected s25fl128s_64k with page size 256 Bytes, erase size 64 KiB, total 16 MiB
> Zynq> mtd info
> MTD Device 1: s25fl128s_64k
>  Page size:     256 B
>  Erase size:    64 KiB
>  Size:          16 MiB
> Zynq> mtd list
> MTD 1:  spi-nor at e000d000  (active 1)
> Zynq> mtd erase 0xE00000 0x100000
> MTD: 1048576 bytes @ 0xe00000 Erased: OK
> Zynq> mw.b 0x100 0xaa 0x100000
> Zynq> mtd write 0x100 0xE00000 0x100000
> device 0 offset 0xe00000, size 0x100000
> MTD: 1048576 bytes @ 0xe00000 Written: OK
> Zynq> mtd read 0x3000000 0xE00000 0x100000
> device 0 offset 0xe00000, size 0x100000
> MTD: 1048576 bytes @ 0xe00000 Read: OK
> Zynq> cmp.b 0x3000000 0x100 0x100000
> Total of 1048576 byte(s) were the same
>
> Testing:
> -------
> $ git clone git://git.denx.de/u-boot-spi.git
> $ cd u-boot-spi
> $ git checkout -b mtd origin/mtd-working
>
> [1] http://lists.denx.de/pipermail/u-boot/2016-March/249286.html
> [2] http://lists.denx.de/pipermail/u-boot/2016-February/245418.html
> [3] [PATCH RFC v8 00/16]  SPI-NOR/MTD addition
>
> Jagan Teki (21):
>   dm: mtd: Add dm mtd core ops
>   mtd: Add SPI-NOR core support
>   mtd: spi-nor: Kconfig: Add MTD_SPI_NOR entry
>   mtd: spi-nor: Kconfig: Add MTD_SPI_NOR_USE_4K_SECTORS
>   mtd: spi-nor: Kconfig: Add SPI_NOR_MISC entry
>   mtd: spi-nor: Kconfig: Add SPI_NOR_MACRONIX entry
>   mtd: spi-nor: Kconfig: Add SPI_NOR_SPANSION entry
>   mtd: spi-nor: Kconfig: Add SPI_NOR_STMICRO entry
>   mtd: spi-nor: Kconfig: Add SPI_NOR_SST entry
>   mtd: spi-nor: Kconfig: Add SPI_NOR_WINBOND entry
>   spi: Add spi_write_then_read
>   mtd: spi-nor: Add m25p80 driver
>   mtd: spi-nor: Kconfig: Add MTD_M25P80 entry
>   mtd: spi-nor: Add zynq qspinor driver
>   mtd: spi-nor: zynq_qspi: Kconfig: Add MTD_ZYNQ
>   mtd: spi-nor: Add 4-byte addresswidth support
>   dm: mtd: Add uclass_driver.flags
>   dm: mtd: Add post_bind
>   cmd: Add mtd command support
>   arm: dts: zynq: Add zynq-qspinor node
>   dm: zynq: microzed: Enable MTD/SPI-NOR
>
>  Makefile                           |   1 +
>  arch/arm/dts/zynq-7000.dtsi        |  12 +
>  arch/arm/dts/zynq-microzed.dts     |   6 +
>  cmd/Kconfig                        |   6 +
>  cmd/Makefile                       |   1 +
>  cmd/mtd.c                          | 285 ++++++++++++++++
>  configs/zynq_microzed_defconfig    |  14 +-
>  drivers/mtd/Kconfig                |   2 +
>  drivers/mtd/Makefile               |   2 +-
>  drivers/mtd/mtd-uclass.c           |  93 +++++
>  drivers/mtd/spi-nor/Kconfig        |  89 +++++
>  drivers/mtd/spi-nor/Makefile       |  15 +
>  drivers/mtd/spi-nor/m25p80.c       | 218 ++++++++++++
>  drivers/mtd/spi-nor/spi-nor-ids.c  | 176 ++++++++++
>  drivers/mtd/spi-nor/spi-nor.c      | 684 +++++++++++++++++++++++++++++++++++++
>  drivers/mtd/spi-nor/zynq_qspinor.c | 641 ++++++++++++++++++++++++++++++++++
>  drivers/spi/spi-uclass.c           |  24 ++
>  include/linux/err.h                |   5 +
>  include/linux/mtd/spi-nor.h        | 211 ++++++++++++
>  include/mtd.h                      |  63 ++++
>  include/spi.h                      |  20 ++
>  21 files changed, 2562 insertions(+), 6 deletions(-)
>  create mode 100644 cmd/mtd.c
>  create mode 100644 drivers/mtd/spi-nor/Kconfig
>  create mode 100644 drivers/mtd/spi-nor/Makefile
>  create mode 100644 drivers/mtd/spi-nor/m25p80.c
>  create mode 100644 drivers/mtd/spi-nor/spi-nor-ids.c
>  create mode 100644 drivers/mtd/spi-nor/spi-nor.c
>  create mode 100644 drivers/mtd/spi-nor/zynq_qspinor.c
>  create mode 100644 include/linux/mtd/spi-nor.h
>
> --
> 2.7.4
>

To me this series is much easier to understand than previously.

Is there a sandbox MTD driver for use in tests?

Regards,
Simon

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

* [U-Boot] [PATCH v9 01/21] dm: mtd: Add dm mtd core ops
  2016-10-30 18:23 ` [U-Boot] [PATCH v9 01/21] dm: mtd: Add dm mtd core ops Jagan Teki
@ 2016-11-05 16:07   ` Simon Glass
  0 siblings, 0 replies; 39+ messages in thread
From: Simon Glass @ 2016-11-05 16:07 UTC (permalink / raw)
  To: u-boot

Hi Jagan,

On 30 October 2016 at 12:23, Jagan Teki <jagan@openedev.com> wrote:
> - Add generic dm_mtd operations
> - Add mtd_read|erase|write_dm
> - Add add_mtd_device_dm
>
> The respetive MTD_UCLASS drivers must install the hooks to these
> dm_mtd_ops and other core ops are act as a interface b/w drivers
> vs command code.
>
> Signed-off-by: Jagan Teki <jagan@openedev.com>
> ---
>  drivers/mtd/mtd-uclass.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++
>  include/mtd.h            | 54 ++++++++++++++++++++++++++++++++++++
>  2 files changed, 126 insertions(+)

Reviewed-by: Simon Glass <sjg@chromium.org>

But please see changes below.

>
> diff --git a/drivers/mtd/mtd-uclass.c b/drivers/mtd/mtd-uclass.c
> index 7b7c48e..acbd713 100644
> --- a/drivers/mtd/mtd-uclass.c
> +++ b/drivers/mtd/mtd-uclass.c
> @@ -1,4 +1,5 @@
>  /*
> + * Copyright (C) 2016 Jagan Teki <jagan@openedev.com>
>   * Copyright (C) 2015 Thomas Chou <thomas@wytron.com.tw>
>   *
>   * SPDX-License-Identifier:    GPL-2.0+
> @@ -8,6 +9,77 @@
>  #include <dm.h>
>  #include <errno.h>
>  #include <mtd.h>
> +#include <linux/log2.h>
> +
> +int dm_mtd_read(struct udevice *dev, loff_t from, size_t len, size_t *retlen,
> +               u_char *buf)
> +{
> +       struct mtd_info *mtd = mtd_get_info(dev);
> +
> +       *retlen = 0;
> +       if (from < 0 || from > mtd->size || len > mtd->size - from)
> +               return -EINVAL;
> +       if (!len)
> +               return 0;
> +
> +       return mtd_get_ops(dev)->_read(dev, from, len, retlen, buf);
> +}
> +
> +int dm_mtd_erase(struct udevice *dev, struct erase_info *instr)
> +{
> +       struct mtd_info *mtd = mtd_get_info(dev);
> +
> +       if (instr->addr > mtd->size || instr->len > mtd->size - instr->addr)
> +               return -EINVAL;
> +       if (!(mtd->flags & MTD_WRITEABLE))
> +               return -EROFS;
> +       instr->fail_addr = MTD_FAIL_ADDR_UNKNOWN;
> +       if (!instr->len) {
> +               instr->state = MTD_ERASE_DONE;
> +               return 0;
> +       }
> +
> +       return mtd_get_ops(dev)->_erase(dev, instr);
> +}
> +
> +int dm_mtd_write(struct udevice *dev, loff_t to, size_t len, size_t *retlen,
> +                const u_char *buf)
> +{
> +       struct mtd_info *mtd = mtd_get_info(dev);
> +
> +       *retlen = 0;
> +       if (to < 0 || to > mtd->size || len > mtd->size - to)
> +               return -EINVAL;
> +       if (!mtd_get_ops(dev)->_write || !(mtd->flags & MTD_WRITEABLE))
> +               return -EROFS;
> +       if (!len)
> +               return 0;
> +
> +       return mtd_get_ops(dev)->_write(dev, to, len, retlen, buf);
> +}
> +
> +int dm_add_mtd_device(struct udevice *dev)
> +{
> +       struct mtd_info *mtd = mtd_get_info(dev);
> +
> +       BUG_ON(mtd->writesize == 0);
> +       mtd->usecount = 0;
> +
> +       if (is_power_of_2(mtd->erasesize))
> +               mtd->erasesize_shift = ffs(mtd->erasesize) - 1;
> +       else
> +               mtd->erasesize_shift = 0;
> +
> +       if (is_power_of_2(mtd->writesize))
> +               mtd->writesize_shift = ffs(mtd->writesize) - 1;
> +       else
> +               mtd->writesize_shift = 0;
> +
> +       mtd->erasesize_mask = (1 << mtd->erasesize_shift) - 1;
> +       mtd->writesize_mask = (1 << mtd->writesize_shift) - 1;
> +
> +       return 0;
> +}
>
>  /*
>   * Implement a MTD uclass which should include most flash drivers.
> diff --git a/include/mtd.h b/include/mtd.h
> index 3f8c293..93b5eaf 100644
> --- a/include/mtd.h
> +++ b/include/mtd.h
> @@ -20,4 +20,58 @@ static inline struct mtd_info *mtd_get_info(struct udevice *dev)
>         return dev_get_uclass_priv(dev);
>  }
>
> +struct dm_mtd_ops {
> +       int (*_erase)(struct udevice *dev, struct erase_info *instr);
> +       int (*_read)(struct udevice *dev, loff_t from, size_t len,
> +                    size_t *retlen, u_char *buf);
> +       int (*_write)(struct udevice *dev, loff_t to, size_t len,
> +                     size_t *retlen, const u_char *buf);

Please add detailed comments to the struct and each method. Also can
you drop the underscore?

> +};
> +
> +/* Access the serial operations for a device */
> +#define mtd_get_ops(dev) ((struct dm_mtd_ops *)(dev)->driver->ops)
> +
> +/**
> + * dm_mtd_read() - Read data from MTD device
> + *
> + * @dev:       MTD device
> + * @from:      Offset into device in bytes to read from
> + * @len:       Length of bytes to read
> + * @retlen:    Length of return bytes read to
> + * @buf:       Buffer to put the data that is read
> + * @return 0 if OK, -ve on error
> + */
> +int dm_mtd_read(struct udevice *dev, loff_t from, size_t len, size_t *retlen,
> +               u_char *buf);
> +
> +/**
> + * dm_mtd_write() - Write data to MTD device
> + *
> + * @dev:       MTD device
> + * @to:                Offset into device in bytes to write to
> + * @len:       Length of bytes to write
> + * @retlen:    Length of return bytes to write to
> + * @buf:       Buffer containing bytes to write
> + * @return 0 if OK, -ve on error
> + */
> +int dm_mtd_write(struct udevice *dev, loff_t to, size_t len, size_t *retlen,
> +                const u_char *buf);
> +
> +/**
> + * dm_mtd_erase() - Erase blocks of the MTD device
> + *
> + * @dev:       MTD device
> + * @instr:     Erase info details of MTD device
> + * @return 0 if OK, -ve on error
> + */
> +int dm_mtd_erase(struct udevice *dev, struct erase_info *instr);
> +
> +/**
> + * dm_add_mtd_device() - Add MTD device
> + *
> + * @dev:       MTD device
> + * @return 0 if OK, -ve on error
> + */
> +int dm_add_mtd_device(struct udevice *dev);
> +
>  #endif /* _MTD_H_ */
> --
> 2.7.4
>

Regards,
Simon

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

* [U-Boot] [PATCH v9 03/21] mtd: spi-nor: Kconfig: Add MTD_SPI_NOR entry
  2016-10-30 18:23 ` [U-Boot] [PATCH v9 03/21] mtd: spi-nor: Kconfig: Add MTD_SPI_NOR entry Jagan Teki
@ 2016-11-05 16:09   ` Simon Glass
  0 siblings, 0 replies; 39+ messages in thread
From: Simon Glass @ 2016-11-05 16:09 UTC (permalink / raw)
  To: u-boot

On 30 October 2016 at 12:23, Jagan Teki <jagan@openedev.com> wrote:
> Added CONFIG_MTD_SPI_NOR kconfig entry
>
> Signed-off-by: Jagan Teki <jagan@openedev.com>
> ---
>  drivers/mtd/Kconfig         |  2 ++
>  drivers/mtd/spi-nor/Kconfig | 14 ++++++++++++++
>  2 files changed, 16 insertions(+)
>  create mode 100644 drivers/mtd/spi-nor/Kconfig

Reviewed-by: Simon Glass <sjg@chromium.org>

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

* [U-Boot] [PATCH v9 04/21] mtd: spi-nor: Kconfig: Add MTD_SPI_NOR_USE_4K_SECTORS
  2016-10-30 18:23 ` [U-Boot] [PATCH v9 04/21] mtd: spi-nor: Kconfig: Add MTD_SPI_NOR_USE_4K_SECTORS Jagan Teki
@ 2016-11-05 16:09   ` Simon Glass
  0 siblings, 0 replies; 39+ messages in thread
From: Simon Glass @ 2016-11-05 16:09 UTC (permalink / raw)
  To: u-boot

On 30 October 2016 at 12:23, Jagan Teki <jagan@openedev.com> wrote:
> Added CONFIG_MTD_SPI_NOR_USE_4K_SECTORS kconfig entry
>
> Signed-off-by: Jagan Teki <jagan@openedev.com>
> ---
>  drivers/mtd/spi-nor/Kconfig | 18 ++++++++++++++++++
>  1 file changed, 18 insertions(+)

Reviewed-by: Simon Glass <sjg@chromium.org>

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

* [U-Boot] [PATCH v9 05/21] mtd: spi-nor: Kconfig: Add SPI_NOR_MISC entry
  2016-10-30 18:23 ` [U-Boot] [PATCH v9 05/21] mtd: spi-nor: Kconfig: Add SPI_NOR_MISC entry Jagan Teki
@ 2016-11-05 16:09   ` Simon Glass
  0 siblings, 0 replies; 39+ messages in thread
From: Simon Glass @ 2016-11-05 16:09 UTC (permalink / raw)
  To: u-boot

On 30 October 2016 at 12:23, Jagan Teki <jagan@openedev.com> wrote:
> Added CONFIG_SPI_NOR_MISC kconfig entry
>
> Signed-off-by: Jagan Teki <jagan@openedev.com>
> ---
>  drivers/mtd/spi-nor/Kconfig | 6 ++++++
>  1 file changed, 6 insertions(+)

Reviewed-by: Simon Glass <sjg@chromium.org>

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

* [U-Boot] [PATCH v9 06/21] mtd: spi-nor: Kconfig: Add SPI_NOR_MACRONIX entry
  2016-10-30 18:23 ` [U-Boot] [PATCH v9 06/21] mtd: spi-nor: Kconfig: Add SPI_NOR_MACRONIX entry Jagan Teki
@ 2016-11-05 16:09   ` Simon Glass
  0 siblings, 0 replies; 39+ messages in thread
From: Simon Glass @ 2016-11-05 16:09 UTC (permalink / raw)
  To: u-boot

On 30 October 2016 at 12:23, Jagan Teki <jagan@openedev.com> wrote:
> Added CONFIG_SPI_NOR_MACRONIX kconfig entry
>
> Signed-off-by: Jagan Teki <jagan@openedev.com>
> ---
>  drivers/mtd/spi-nor/Kconfig | 5 +++++
>  1 file changed, 5 insertions(+)

Reviewed-by: Simon Glass <sjg@chromium.org>

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

* [U-Boot] [PATCH v9 07/21] mtd: spi-nor: Kconfig: Add SPI_NOR_SPANSION entry
  2016-10-30 18:23 ` [U-Boot] [PATCH v9 07/21] mtd: spi-nor: Kconfig: Add SPI_NOR_SPANSION entry Jagan Teki
@ 2016-11-05 16:09   ` Simon Glass
  0 siblings, 0 replies; 39+ messages in thread
From: Simon Glass @ 2016-11-05 16:09 UTC (permalink / raw)
  To: u-boot

On 30 October 2016 at 12:23, Jagan Teki <jagan@openedev.com> wrote:
> Added CONFIG_SPI_NOR_SPANSION kconfig entry
>
> Signed-off-by: Jagan Teki <jagan@openedev.com>
> ---
>  drivers/mtd/spi-nor/Kconfig | 5 +++++
>  1 file changed, 5 insertions(+)

Reviewed-by: Simon Glass <sjg@chromium.org>

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

* [U-Boot] [PATCH v9 08/21] mtd: spi-nor: Kconfig: Add SPI_NOR_STMICRO entry
  2016-10-30 18:23 ` [U-Boot] [PATCH v9 08/21] mtd: spi-nor: Kconfig: Add SPI_NOR_STMICRO entry Jagan Teki
@ 2016-11-05 16:09   ` Simon Glass
  0 siblings, 0 replies; 39+ messages in thread
From: Simon Glass @ 2016-11-05 16:09 UTC (permalink / raw)
  To: u-boot

On 30 October 2016 at 12:23, Jagan Teki <jagan@openedev.com> wrote:
> Added CONFIG_SPI_NOR_STMICRO kconfig entry
>
> Signed-off-by: Jagan Teki <jagan@openedev.com>
> ---
>  drivers/mtd/spi-nor/Kconfig | 5 +++++
>  1 file changed, 5 insertions(+)

Reviewed-by: Simon Glass <sjg@chromium.org>

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

* [U-Boot] [PATCH v9 09/21] mtd: spi-nor: Kconfig: Add SPI_NOR_SST entry
  2016-10-30 18:23 ` [U-Boot] [PATCH v9 09/21] mtd: spi-nor: Kconfig: Add SPI_NOR_SST entry Jagan Teki
@ 2016-11-05 16:09   ` Simon Glass
  0 siblings, 0 replies; 39+ messages in thread
From: Simon Glass @ 2016-11-05 16:09 UTC (permalink / raw)
  To: u-boot

On 30 October 2016 at 12:23, Jagan Teki <jagan@openedev.com> wrote:
> Added CONFIG_SPI_NOR_SST kconfig entry
>
> Signed-off-by: Jagan Teki <jagan@openedev.com>
> ---
>  drivers/mtd/spi-nor/Kconfig | 5 +++++
>  1 file changed, 5 insertions(+)

Reviewed-by: Simon Glass <sjg@chromium.org>

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

* [U-Boot] [PATCH v9 10/21] mtd: spi-nor: Kconfig: Add SPI_NOR_WINBOND entry
  2016-10-30 18:23 ` [U-Boot] [PATCH v9 10/21] mtd: spi-nor: Kconfig: Add SPI_NOR_WINBOND entry Jagan Teki
@ 2016-11-05 16:09   ` Simon Glass
  0 siblings, 0 replies; 39+ messages in thread
From: Simon Glass @ 2016-11-05 16:09 UTC (permalink / raw)
  To: u-boot

On 30 October 2016 at 12:23, Jagan Teki <jagan@openedev.com> wrote:
> Added CONFIG_SPI_NOR_WINBOND kconfig entry
>
> Signed-off-by: Jagan Teki <jagan@openedev.com>
> ---
>  drivers/mtd/spi-nor/Kconfig | 5 +++++
>  1 file changed, 5 insertions(+)

Reviewed-by: Simon Glass <sjg@chromium.org>

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

* [U-Boot] [PATCH v9 11/21] spi: Add spi_write_then_read
  2016-10-30 18:23 ` [U-Boot] [PATCH v9 11/21] spi: Add spi_write_then_read Jagan Teki
@ 2016-11-05 16:09   ` Simon Glass
  0 siblings, 0 replies; 39+ messages in thread
From: Simon Glass @ 2016-11-05 16:09 UTC (permalink / raw)
  To: u-boot

On 30 October 2016 at 12:23, Jagan Teki <jagan@openedev.com> wrote:
> Add support for SPI synchronous write followed by read,
> this is common interface call from spi-nor to spi drivers.
>
> Signed-off-by: Jagan Teki <jagan@openedev.com>
> ---
>  drivers/spi/spi-uclass.c | 24 ++++++++++++++++++++++++
>  include/spi.h            | 20 ++++++++++++++++++++
>  2 files changed, 44 insertions(+)

Reviewed-by: Simon Glass <sjg@chromium.org>

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

* [U-Boot] [PATCH v9 13/21] mtd: spi-nor: Kconfig: Add MTD_M25P80 entry
  2016-10-30 18:23 ` [U-Boot] [PATCH v9 13/21] mtd: spi-nor: Kconfig: Add MTD_M25P80 entry Jagan Teki
@ 2016-11-05 16:09   ` Simon Glass
  0 siblings, 0 replies; 39+ messages in thread
From: Simon Glass @ 2016-11-05 16:09 UTC (permalink / raw)
  To: u-boot

On 30 October 2016 at 12:23, Jagan Teki <jagan@openedev.com> wrote:
> Add CONFIG_MTD_M25P80 kconfig entry
>
> Signed-off-by: Jagan Teki <jagan@openedev.com>
> ---
>  drivers/mtd/spi-nor/Kconfig | 17 +++++++++++++++++
>  1 file changed, 17 insertions(+)

Reviewed-by: Simon Glass <sjg@chromium.org>

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

* [U-Boot] [PATCH v9 12/21] mtd: spi-nor: Add m25p80 driver
  2016-10-30 18:23 ` [U-Boot] [PATCH v9 12/21] mtd: spi-nor: Add m25p80 driver Jagan Teki
@ 2016-11-05 16:10   ` Simon Glass
  0 siblings, 0 replies; 39+ messages in thread
From: Simon Glass @ 2016-11-05 16:10 UTC (permalink / raw)
  To: u-boot

Hi Jagan,

On 30 October 2016 at 12:23, Jagan Teki <jagan@openedev.com> wrote:
> This is MTD SPI-NOR driver for ST M25Pxx (and similar)
> serial flash chips which is written as MTD_UCLASS.
>
> Signed-off-by: Jagan Teki <jagan@openedev.com>
> ---
>  drivers/mtd/spi-nor/Makefile |   3 +
>  drivers/mtd/spi-nor/m25p80.c | 217 +++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 220 insertions(+)
>  create mode 100644 drivers/mtd/spi-nor/m25p80.c
>
> diff --git a/drivers/mtd/spi-nor/Makefile b/drivers/mtd/spi-nor/Makefile
> index 15e43ea..d11ccf4 100644
> --- a/drivers/mtd/spi-nor/Makefile
> +++ b/drivers/mtd/spi-nor/Makefile
> @@ -7,3 +7,6 @@
>  ifdef CONFIG_MTD_SPI_NOR
>  obj-y  += spi-nor.o spi-nor-ids.o
>  endif
> +
> +## spi-nor to spi interface driver
> +obj-$(CONFIG_MTD_M25P80)       += m25p80.o
> diff --git a/drivers/mtd/spi-nor/m25p80.c b/drivers/mtd/spi-nor/m25p80.c
> new file mode 100644
> index 0000000..740d3f6
> --- /dev/null
> +++ b/drivers/mtd/spi-nor/m25p80.c

[...]

> +static const struct udevice_id m25p_ids[] = {
> +       /*
> +        * Generic compatibility for SPI NOR that can be identified by the
> +        * JEDEC READ ID opcode (0x9F). Use this, if possible.
> +        */
> +       { .compatible = "jedec,spi-nor" },
> +       { }
> +};
> +
> +U_BOOT_DRIVER(m25p80) = {
> +       .name           = "m25p80",
> +       .id             = UCLASS_MTD,
> +       .of_match       = m25p_ids,
> +       .probe          = m25p_probe,
> +       .priv_auto_alloc_size = sizeof(struct m25p),

Should this not have some MTD operations from the UCLASS_MTD? i.e.
struct dm_mtd_ops?

> +};
> --
> 2.7.4
>

Regards,
Simon

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

* [U-Boot] [PATCH v9 02/21] mtd: Add SPI-NOR core support
  2016-10-30 18:23 ` [U-Boot] [PATCH v9 02/21] mtd: Add SPI-NOR core support Jagan Teki
@ 2016-11-05 16:10   ` Simon Glass
  0 siblings, 0 replies; 39+ messages in thread
From: Simon Glass @ 2016-11-05 16:10 UTC (permalink / raw)
  To: u-boot

Hi Jagan,

On 30 October 2016 at 12:23, Jagan Teki <jagan@openedev.com> wrote:
> Some of the SPI device drivers at drivers/spi not a real
> spi controllers, Unlike normal/generic SPI controllers they
> operates only with SPI-NOR flash devices. these were technically
> termed as SPI-NOR controllers, Ex: drivers/spi/fsl_qspi.c
>
> The problem with these were resides at drivers/spi is entire
> SPI layer becomes SPI-NOR flash oriented which is absolutely
> a wrong indication where SPI layer getting effected more with
> flash operations - So this SPI-NOR core will resolve this issue
> by separating all SPI-NOR flash operations from spi layer and
> creats a generic layer called SPI-NOR core which can be used to
> interact SPI-NOR to SPI driver interface layer and the SPI-NOR
> controller driver. The idea is taken from Linux spi-nor framework.
>
> ------------------------------
>         cmd_sf.c
> ------------------------------
>         mtd-uclass
> -------------------------------
>         SPI-NOR Core
> -------------------------------
> m25p80.c        zynq_qspi
> -------------------------------
> spi-uclass      SPI NOR chip
> -------------------------------
> spi drivers
> -------------------------------
> SPI NOR chip
> -------------------------------
>
> Signed-off-by: Jagan Teki <jagan@openedev.com>
> ---
>  Makefile                          |   1 +
>  drivers/mtd/spi-nor/Makefile      |   9 +
>  drivers/mtd/spi-nor/spi-nor-ids.c | 176 +++++++++++
>  drivers/mtd/spi-nor/spi-nor.c     | 648 ++++++++++++++++++++++++++++++++++++++
>  include/linux/err.h               |   5 +
>  include/linux/mtd/spi-nor.h       | 207 ++++++++++++
>  6 files changed, 1046 insertions(+)
>  create mode 100644 drivers/mtd/spi-nor/Makefile
>  create mode 100644 drivers/mtd/spi-nor/spi-nor-ids.c
>  create mode 100644 drivers/mtd/spi-nor/spi-nor.c
>  create mode 100644 include/linux/mtd/spi-nor.h
>
[...]

> diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
> new file mode 100644
> index 0000000..4e5b3ba
> --- /dev/null
> +++ b/include/linux/mtd/spi-nor.h
> @@ -0,0 +1,207 @@
> +/*
> + * SPI NOR Core header file.
> + *
> + * Copyright (C) 2016 Jagan Teki <jagan@openedev.com>
> + *
> + * SPDX-License-Identifier:    GPL-2.0+
> + */
> +
> +#ifndef __MTD_SPI_NOR_H
> +#define __MTD_SPI_NOR_H
> +
> +#include <common.h>
> +
> +/*
> + * Manufacturer IDs
> + *
> + * The first byte returned from the flash after sending opcode SPINOR_OP_RDID.
> + * Sometimes these are the same as CFI IDs, but sometimes they aren't.
> + */
> +#define SNOR_MFR_ATMEL         0x1f
> +#define SNOR_MFR_MACRONIX      0xc2
> +#define SNOR_MFR_MICRON                0x20    /* ST Micro <--> Micron */
> +#define SNOR_MFR_SPANSION      0x01
> +#define SNOR_MFR_SST           0xbf
> +#define SNOR_MFR_WINBOND       0xef
> +
> +/**
> + * SPI NOR opcodes.
> + *
> + * Note on opcode nomenclature: some opcodes have a format like
> + * SNOR_OP_FUNCTION{4,}_x_y_z. The numbers x, y, and z stand for the number
> + * of I/O lines used for the opcode, address, and data (respectively). The
> + * FUNCTION has an optional suffix of '4', to represent an opcode which
> + * requires a 4-byte (32-bit) address.
> + */
> +#define SNOR_OP_WRDI           0x04    /* Write disable */
> +#define SNOR_OP_WREN           0x06    /* Write enable */
> +#define SNOR_OP_RDSR           0x05    /* Read status register */
> +#define SNOR_OP_WRSR           0x01    /* Write status register 1 byte */
> +#define SNOR_OP_READ           0x03    /* Read data bytes (low frequency) */
> +#define SNOR_OP_READ_FAST      0x0b    /* Read data bytes (high frequency) */
> +#define SNOR_OP_READ_1_1_2     0x3b    /* Read data bytes (Dual SPI) */
> +#define SNOR_OP_READ_1_1_2_IO  0xbb    /* Read data bytes (Dual IO SPI) */
> +#define SNOR_OP_READ_1_1_4     0x6b    /* Read data bytes (Quad SPI) */
> +#define SNOR_OP_READ_1_1_4_IO  0xeb    /* Read data bytes (Quad IO SPI) */
> +#define SNOR_OP_BRWR           0x17    /* Bank register write */
> +#define SNOR_OP_BRRD           0x16    /* Bank register read */
> +#define SNOR_OP_WREAR          0xC5    /* Write extended address register */
> +#define SNOR_OP_RDEAR          0xC8    /* Read extended address register */
> +#define SNOR_OP_PP             0x02    /* Page program (up to 256 bytes) */
> +#define SNOR_OP_QPP            0x32    /* Quad Page program */
> +#define SNOR_OP_BE_4K          0x20    /* Erase 4KiB block */
> +#define SNOR_OP_BE_4K_PMC      0xd7    /* Erase 4KiB block on PMC chips */
> +#define SNOR_OP_BE_32K         0x52    /* Erase 32KiB block */
> +#define SPINOR_OP_CHIP_ERASE   0xc7    /* Erase whole flash chip */
> +#define SNOR_OP_SE             0xd8    /* Sector erase (usually 64KiB) */
> +#define SNOR_OP_RDID           0x9f    /* Read JEDEC ID */
> +#define SNOR_OP_RDCR           0x35    /* Read configuration register */
> +#define SNOR_OP_RDFSR          0x70    /* Read flag status register */
> +
> +/* Used for SST flashes only. */
> +#define SNOR_OP_BP             0x02    /* Byte program */
> +#define SNOR_OP_AAI_WP         0xad    /* Auto addr increment word program */
> +
> +/* Status Register bits. */
> +#define SR_WIP                 BIT(0)  /* Write in progress */
> +#define SR_WEL                 BIT(1)  /* Write enable latch */
> +
> +/* meaning of other SR_* bits may differ between vendors */
> +#define SR_BP0                 BIT(2)  /* Block protect 0 */
> +#define SR_BP1                 BIT(3)  /* Block protect 1 */
> +#define SR_BP2                 BIT(4)  /* Block protect 2 */
> +#define SR_SRWD                        BIT(7)  /* SR write protect */
> +
> +#define SR_QUAD_EN_MX          BIT(6)  /* Macronix Quad I/O */
> +
> +/* Flag Status Register bits */
> +#define FSR_READY              BIT(7)
> +
> +/* Configuration Register bits. */
> +#define CR_QUAD_EN_SPAN                BIT(1) /* Spansion/Winbond Quad I/O */
> +
> +/* Flash timeout values */
> +#define SNOR_READY_WAIT_PROG   (2 * CONFIG_SYS_HZ)
> +#define SNOR_READY_WAIT_ERASE  (5 * CONFIG_SYS_HZ)
> +#define SNOR_MAX_CMD_SIZE      4
> +#define SNOR_16MB_BOUN         0x1000000
> +
> +enum snor_option_flags {
> +       SNOR_F_SST_WRITE        = BIT(0),
> +       SNOR_F_USE_FSR          = BIT(1),
> +       SNOR_F_U_PAGE           = BIT(1),
> +};
> +
> +enum mode {
> +       SNOR_READ               = BIT(0),
> +       SNOR_READ_1_1_2         = BIT(1),
> +       SNOR_READ_1_1_4         = BIT(2),
> +       SNOR_READ_1_1_2_IO      = BIT(3),
> +       SNOR_READ_1_1_4_IO      = BIT(4),
> +       SNOR_WRITE_1_1_BYTE     = BIT(5),
> +       SNOR_WRITE_1_1_4        = BIT(6),
> +};
> +
> +#define JEDEC_MFR(info)                ((info)->id[0])
> +#define JEDEC_ID(info)         (((info)->id[1]) << 8 | ((info)->id[2]))
> +#define JEDEC_EXT(info)                (((info)->id[3]) << 8 | ((info)->id[4]))
> +#define SPI_NOR_MAX_ID_LEN     6
> +
> +struct spi_nor_info {
> +       char            *name;
> +
> +       /*
> +        * This array stores the ID bytes.
> +        * The first three bytes are the JEDIC ID.
> +        * JEDEC ID zero means "no ID" (mostly older chips).
> +        */
> +       u8              id[SPI_NOR_MAX_ID_LEN];
> +       u8              id_len;
> +
> +       /* The size listed here is what works with SNOR_OP_SE, which isn't
> +        * necessarily called a "sector" by the vendor.
> +        */
> +       unsigned        sector_size;
> +       u16             n_sectors;
> +
> +       u16             page_size;
> +
> +       u16             flags;
> +#define SECT_4K                        BIT(0)
> +#define E_FSR                  BIT(1)
> +#define SST_WR                 BIT(2)
> +#define WR_QPP                 BIT(3)
> +#define RD_QUAD                        BIT(4)
> +#define RD_DUAL                        BIT(5)
> +#define RD_QUADIO              BIT(6)
> +#define RD_DUALIO              BIT(7)
> +#define RD_FULL                        (RD_QUAD | RD_DUAL | RD_QUADIO | RD_DUALIO)
> +};
> +
> +extern const struct spi_nor_info spi_nor_ids[];
> +
> +/**
> + * struct spi_nor - Structure for defining a the SPI NOR layer
> + *
> + * @dev:               SPI NOR device
> + * @name:              name of the SPI NOR device
> + * @page_size:         the page size of the SPI NOR
> + * @addr_width:                number of address bytes
> + * @erase_opcode:      the opcode for erasing a sector
> + * @read_opcode:       the read opcode
> + * @read_dummy:                the dummy bytes needed by the read operation
> + * @program_opcode:    the program opcode
> + * @max_write_size:    If non-zero, the maximum number of bytes which can
> + *                     be written at once, excluding command bytes.
> + * @flags:             flag options for the current SPI-NOR (SNOR_F_*)
> + * @mode:              read, write mode or any other mode bits.
> + * @read_mode:         read mode.
> + * @cmd_buf:           used by the write_reg
> + * @read_reg:          [DRIVER-SPECIFIC] read out the register
> + * @write_reg:         [DRIVER-SPECIFIC] write data to the register
> + * @read:              [DRIVER-SPECIFIC] read data from the SPI NOR
> + * @write:             [DRIVER-SPECIFIC] write data to the SPI NOR
> + * @memory_map:        address of read-only SPI NOR access
> + * @priv:              the private data
> + */
> +struct spi_nor {
> +       struct udevice          *dev;
> +       const char              *name;
> +       u32                     page_size;
> +       u8                      addr_width;
> +       u8                      erase_opcode;
> +       u8                      read_opcode;
> +       u8                      read_dummy;
> +       u8                      program_opcode;
> +       u32                     max_write_size;
> +       u32                     flags;
> +       u8                      mode;
> +       u8                      read_mode;
> +       u8                      cmd_buf[SNOR_MAX_CMD_SIZE];
> +
> +       int (*read_reg)(struct spi_nor *nor, u8 cmd, u8 *val, int len);
> +       int (*write_reg)(struct spi_nor *nor, u8 cmd, u8 *data, int len);
> +
> +       int (*read)(struct spi_nor *nor, loff_t from, size_t len,
> +                   u_char *read_buf);
> +       int (*write)(struct spi_nor *nor, loff_t to, size_t len,
> +                    const u_char *write_buf);

Sos is SPI_NOR a uclass? It seems like you have different drivers for
it, and so it should be. Perhaps the SPI_NOR uclass should be a child
of the MTD uclass?

> +
> +       void *memory_map;
> +       void *priv;
> +};
> +
> +/**
> + * spi_nor_scan() - scan the SPI NOR
> + *
> + * @dev:               SPI NOR device
> + *
> + * The drivers can use this fuction to scan the SPI NOR.
> + * In the scanning, it will try to get all the necessary information to
> + * fill the mtd_info{} and the spi_nor{}.
> + *
> + * @return 0 if OK, -ve on error
> + */
> +int spi_nor_scan(struct udevice *dev);
> +
> +#endif /* __MTD_SPI_NOR_H */
> --
> 2.7.4
>

Regards,
Simon

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

* [U-Boot] [PATCH v9 17/21] dm: mtd: Add uclass_driver.flags
  2016-10-30 18:23 ` [U-Boot] [PATCH v9 17/21] dm: mtd: Add uclass_driver.flags Jagan Teki
@ 2016-11-05 16:10   ` Simon Glass
  0 siblings, 0 replies; 39+ messages in thread
From: Simon Glass @ 2016-11-05 16:10 UTC (permalink / raw)
  To: u-boot

On 30 October 2016 at 12:23, Jagan Teki <jagan@openedev.com> wrote:
> Add flags for mtd-uclass driver.
>
> Signed-off-by: Jagan Teki <jagan@openedev.com>
> ---
>  drivers/mtd/mtd-uclass.c | 1 +
>  1 file changed, 1 insertion(+)

Reviewed-by: Simon Glass <sjg@chromium.org>

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

* [U-Boot] [PATCH v9 18/21] dm: mtd: Add post_bind
  2016-10-30 18:23 ` [U-Boot] [PATCH v9 18/21] dm: mtd: Add post_bind Jagan Teki
@ 2016-11-05 16:10   ` Simon Glass
  0 siblings, 0 replies; 39+ messages in thread
From: Simon Glass @ 2016-11-05 16:10 UTC (permalink / raw)
  To: u-boot

On 30 October 2016 at 12:23, Jagan Teki <jagan@openedev.com> wrote:
> Add .post_bind on mtd-uclass driver
>
> Signed-off-by: Jagan Teki <jagan@openedev.com>
> ---
>  drivers/mtd/mtd-uclass.c | 3 +++
>  1 file changed, 3 insertions(+)

Reviewed-by: Simon Glass <sjg@chromium.org>

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

* [U-Boot] [PATCH v9 19/21] cmd: Add mtd command support
  2016-10-30 18:23 ` [U-Boot] [PATCH v9 19/21] cmd: Add mtd command support Jagan Teki
@ 2016-11-05 16:10   ` Simon Glass
  0 siblings, 0 replies; 39+ messages in thread
From: Simon Glass @ 2016-11-05 16:10 UTC (permalink / raw)
  To: u-boot

On 30 October 2016 at 12:23, Jagan Teki <jagan@openedev.com> wrote:
> cmd/mtd.c is a generic command to access all low level
> MTD devices, like SPI-NOR, Parallel NOR and NAND.
>
> This is implemented based on u-boot driver model, so any
> new driver added for using this command must follow dm principles.
>
> Signed-off-by: Jagan Teki <jagan@openedev.com>
> ---
>  cmd/Kconfig              |   6 +
>  cmd/Makefile             |   1 +
>  cmd/mtd.c                | 285 +++++++++++++++++++++++++++++++++++++++++++++++
>  drivers/mtd/Makefile     |   2 +-
>  drivers/mtd/mtd-uclass.c |  17 +++
>  include/mtd.h            |   9 ++
>  6 files changed, 319 insertions(+), 1 deletion(-)
>  create mode 100644 cmd/mtd.c

Reviewed-by: Simon Glass <sjg@chromium.org>

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

end of thread, other threads:[~2016-11-05 16:10 UTC | newest]

Thread overview: 39+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-10-30 18:23 [U-Boot] [PATCH v9 00/21] dm: Generic MTD Subsystem/SPI-NOR Jagan Teki
2016-10-30 18:23 ` [U-Boot] [PATCH v9 01/21] dm: mtd: Add dm mtd core ops Jagan Teki
2016-11-05 16:07   ` Simon Glass
2016-10-30 18:23 ` [U-Boot] [PATCH v9 02/21] mtd: Add SPI-NOR core support Jagan Teki
2016-11-05 16:10   ` Simon Glass
2016-10-30 18:23 ` [U-Boot] [PATCH v9 03/21] mtd: spi-nor: Kconfig: Add MTD_SPI_NOR entry Jagan Teki
2016-11-05 16:09   ` Simon Glass
2016-10-30 18:23 ` [U-Boot] [PATCH v9 04/21] mtd: spi-nor: Kconfig: Add MTD_SPI_NOR_USE_4K_SECTORS Jagan Teki
2016-11-05 16:09   ` Simon Glass
2016-10-30 18:23 ` [U-Boot] [PATCH v9 05/21] mtd: spi-nor: Kconfig: Add SPI_NOR_MISC entry Jagan Teki
2016-11-05 16:09   ` Simon Glass
2016-10-30 18:23 ` [U-Boot] [PATCH v9 06/21] mtd: spi-nor: Kconfig: Add SPI_NOR_MACRONIX entry Jagan Teki
2016-11-05 16:09   ` Simon Glass
2016-10-30 18:23 ` [U-Boot] [PATCH v9 07/21] mtd: spi-nor: Kconfig: Add SPI_NOR_SPANSION entry Jagan Teki
2016-11-05 16:09   ` Simon Glass
2016-10-30 18:23 ` [U-Boot] [PATCH v9 08/21] mtd: spi-nor: Kconfig: Add SPI_NOR_STMICRO entry Jagan Teki
2016-11-05 16:09   ` Simon Glass
2016-10-30 18:23 ` [U-Boot] [PATCH v9 09/21] mtd: spi-nor: Kconfig: Add SPI_NOR_SST entry Jagan Teki
2016-11-05 16:09   ` Simon Glass
2016-10-30 18:23 ` [U-Boot] [PATCH v9 10/21] mtd: spi-nor: Kconfig: Add SPI_NOR_WINBOND entry Jagan Teki
2016-11-05 16:09   ` Simon Glass
2016-10-30 18:23 ` [U-Boot] [PATCH v9 11/21] spi: Add spi_write_then_read Jagan Teki
2016-11-05 16:09   ` Simon Glass
2016-10-30 18:23 ` [U-Boot] [PATCH v9 12/21] mtd: spi-nor: Add m25p80 driver Jagan Teki
2016-11-05 16:10   ` Simon Glass
2016-10-30 18:23 ` [U-Boot] [PATCH v9 13/21] mtd: spi-nor: Kconfig: Add MTD_M25P80 entry Jagan Teki
2016-11-05 16:09   ` Simon Glass
2016-10-30 18:23 ` [U-Boot] [PATCH v9 14/21] mtd: spi-nor: Add zynq qspinor driver Jagan Teki
2016-10-30 18:23 ` [U-Boot] [PATCH v9 15/21] mtd: spi-nor: zynq_qspi: Kconfig: Add MTD_ZYNQ Jagan Teki
2016-10-30 18:23 ` [U-Boot] [PATCH v9 16/21] mtd: spi-nor: Add 4-byte addresswidth support Jagan Teki
2016-10-30 18:23 ` [U-Boot] [PATCH v9 17/21] dm: mtd: Add uclass_driver.flags Jagan Teki
2016-11-05 16:10   ` Simon Glass
2016-10-30 18:23 ` [U-Boot] [PATCH v9 18/21] dm: mtd: Add post_bind Jagan Teki
2016-11-05 16:10   ` Simon Glass
2016-10-30 18:23 ` [U-Boot] [PATCH v9 19/21] cmd: Add mtd command support Jagan Teki
2016-11-05 16:10   ` Simon Glass
2016-10-30 18:23 ` [U-Boot] [PATCH v9 20/21] arm: dts: zynq: Add zynq-qspinor node Jagan Teki
2016-10-30 18:23 ` [U-Boot] [PATCH v9 21/21] dm: zynq: microzed: Enable MTD/SPI-NOR Jagan Teki
2016-11-05 16:07 ` [U-Boot] [PATCH v9 00/21] dm: Generic MTD Subsystem/SPI-NOR Simon Glass

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.