All of lore.kernel.org
 help / color / mirror / Atom feed
* [U-Boot] [PATCH v10 00/27] dm: Generic MTD Subsystem, with SPI-NOR interface
@ 2017-12-28  6:12 Jagan Teki
  2017-12-28  6:12 ` [U-Boot] [PATCH v10 01/27] mtd: Add mtd core ops Jagan Teki
                   ` (28 more replies)
  0 siblings, 29 replies; 55+ messages in thread
From: Jagan Teki @ 2017-12-28  6:12 UTC (permalink / raw)
  To: u-boot

Compared to previous series’s [1], [2], [3] and [4] this patch set
redefined most of the implementation suitable to fit into existing driver-model.

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

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

SPI-NOR:
=======
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.

=======================================
             cmd/spinor.c
=======================================
             mtd-uclass.c
=======================================
           spi-nor-uclass.c
=======================================
              spi-nor.c
=======================================
m25p80.c                zynq_qspinor.c
=======================================
spi-uclass.c
=======================================
zynq_qspi.c
=======================================
        #####SPI NOR chip######
=======================================

Changes for v10:
- Update Simon's R-B tag
- Add mtd dm test case
- implemented entire code wrt MTD, with interface type

code size:
==========
before:
$ arm-linux-gnueabi-size u-boot
   text	   data	    bss	    dec	    hex	filename
 473712	  15152	 222568	 711432	  adb08	u-boot
$ du -hs u-boot-dtb.img 
488K	u-boot-dtb.img

after:
$ arm-linux-gnueabi-size u-boot
   text	   data	    bss	    dec	    hex	filename
 470124	  14352	 222584	 707060	  ac9f4	u-boot
$ du -hs u-boot-dtb.img 
484K	u-boot-dtb.img

approximately 4KiB but DM_SPI_FLASH still there which
can be removed once support added in SPL

test log:
========
Zynq> spinor
spinor - SPI-NOR Sub-system

Usage:
spinor list                     - show list of spinor devices
spinor info                     - show current spinor device info
spinor dev [devnum]             - show or set current spinor device
spinor erase offset len         - erase 'len' bytes from 'offset'
spinor write addr to len        - write 'len' bytes to 'to' from 'addr'
spinor read addr from len       - read 'len' bytes from 'from' to 'addr'
spinor protect lock/unlock sector len - protect/unprotect 'len' bytes starting
                                  at address 'sector'
Zynq> spinor list
flash at 0: 0
spi-nor at e000d000: 1
Zynq> spinor dev 0
switch to dev #0, OK
spinor0 is current device
Zynq> spinor info
bus: flash at 0: 0
device: s25fl128s_64k
page size: 256 B
erase size: 64 KiB
size: 16 MiB
Zynq> spinor erase 0xE00000 0x100000
SPI-NOR: 1048576 bytes @ 0xe00000 Erased: OK
Zynq> mw.b 0x100 0xcc 0x100000
Zynq> spinor write 0x100 0xE00000 0x100000
device 0 offset 0xe00000, size 0x100000
SPI-NOR: 1048576 bytes @ 0xe00000 Written: OK
Zynq> spinor read 0x3000000 0xE00000 0x100000
device 0 offset 0xe00000, size 0x100000
SPI-NOR: 1048576 bytes @ 0xe00000 Read: OK
Zynq> cmp.b 0x3000000 0x100 0x100000
Total of 1048576 byte(s) were the same
Zynq> spinor dev 1
switch to dev #1, OK
spinor1 is current device
Zynq> spinor info
bus: spi-nor at e000d000: 1
device: s25fl128s_64k
page size: 256 B
erase size: 64 KiB
size: 16 MiB
Zynq> spinor erase 0xE00000 0x100000
SPI-NOR: 1048576 bytes @ 0xe00000 Erased: OK
Zynq> mw.b 0x100 0xbb 0x100000
Zynq> spinor write 0x100 0xE00000 0x100000
device 0 offset 0xe00000, size 0x100000
SPI-NOR: 1048576 bytes @ 0xe00000 Written: OK
Zynq> spinor read 0x3000000 0xE00000 0x100000
device 0 offset 0xe00000, size 0x100000
SPI-NOR: 1048576 bytes @ 0xe00000 Read: OK
Zynq> cmp.b 0x3000000 0x100 0x100000
Total of 1048576 byte(s) were the same

WIP:
===
- to support non-dm code
- to support spinor SPL

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

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

Jagan Teki (27):
  mtd: Add mtd core ops
  mtd: add mtd device create operations
  mtd: add SPI-NOR core support
  mtd: spi-nor: sync/modify sst write operations
  mtd: spi-nor: sync/modify lock operations
  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
  mtd-uclass: use platdata_auto_alloc
  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
  cmd: add spinor cmd support
  cmd: spinor: sync/update protect command
  board_r: initialize spi_nor
  env: add spi-nor environment
  arm: dts: zynq: Add zynq-qspinor node
  dm: zynq: microzed: enable MTD/SPI-NOR framework
  test: dm: add tests for mtd devices

 Makefile                             |   1 +
 arch/arm/dts/zynq-7000.dtsi          |  12 +
 arch/arm/dts/zynq-microzed.dts       |  12 +-
 cmd/Kconfig                          |   5 +
 cmd/Makefile                         |   1 +
 cmd/nvedit.c                         |   1 +
 cmd/spinor.c                         | 326 ++++++++++++
 common/board_r.c                     |  13 +
 configs/sandbox_defconfig            |   8 +-
 configs/zynq_microzed_defconfig      |  17 +-
 drivers/mtd/Kconfig                  |   2 +
 drivers/mtd/Makefile                 |   7 +-
 drivers/mtd/mtd-uclass.c             | 203 +++++++-
 drivers/mtd/spi-nor/Kconfig          |  89 ++++
 drivers/mtd/spi-nor/Makefile         |  15 +
 drivers/mtd/spi-nor/m25p80.c         | 251 ++++++++++
 drivers/mtd/spi-nor/spi-nor-ids.c    | 184 +++++++
 drivers/mtd/spi-nor/spi-nor-uclass.c | 160 ++++++
 drivers/mtd/spi-nor/spi-nor.c        | 940 +++++++++++++++++++++++++++++++++++
 drivers/mtd/spi-nor/zynq_qspinor.c   | 622 +++++++++++++++++++++++
 drivers/spi/spi-uclass.c             |  24 +
 env/Kconfig                          |  27 +
 env/Makefile                         |   1 +
 env/env.c                            |   2 +
 env/spinor.c                         | 113 +++++
 include/dm/uclass-id.h               |   1 +
 include/environment.h                |   1 +
 include/linux/mtd/mtd.h              |  14 +
 include/linux/mtd/spi-nor.h          | 223 +++++++++
 include/mtd.h                        | 176 +++++++
 include/spi.h                        |  20 +
 test/dm/Makefile                     |   1 +
 test/dm/mtd.c                        |  33 ++
 33 files changed, 3493 insertions(+), 12 deletions(-)
 create mode 100644 cmd/spinor.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-uclass.c
 create mode 100644 drivers/mtd/spi-nor/spi-nor.c
 create mode 100644 drivers/mtd/spi-nor/zynq_qspinor.c
 create mode 100644 env/spinor.c
 create mode 100644 include/linux/mtd/spi-nor.h
 create mode 100644 test/dm/mtd.c

-- 
2.7.4

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

* [U-Boot] [PATCH v10 01/27] mtd: Add mtd core ops
  2017-12-28  6:12 [U-Boot] [PATCH v10 00/27] dm: Generic MTD Subsystem, with SPI-NOR interface Jagan Teki
@ 2017-12-28  6:12 ` Jagan Teki
  2017-12-28  6:12 ` [U-Boot] [PATCH v10 02/27] mtd: add mtd device create operations Jagan Teki
                   ` (27 subsequent siblings)
  28 siblings, 0 replies; 55+ messages in thread
From: Jagan Teki @ 2017-12-28  6:12 UTC (permalink / raw)
  To: u-boot

- Add generic mtd operations
- Add mtd_dread|derase|dwrite

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

Reviewed-by: Simon Glass <sjg@chromium.org>
Signed-off-by: Jagan Teki <jagan@amarulasolutions.com>
---
 drivers/mtd/mtd-uclass.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++
 include/mtd.h            | 46 ++++++++++++++++++++++++++++++++++++
 2 files changed, 107 insertions(+)

diff --git a/drivers/mtd/mtd-uclass.c b/drivers/mtd/mtd-uclass.c
index 7b7c48e..d2c587f 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,66 @@
 #include <dm.h>
 #include <errno.h>
 #include <mtd.h>
+#include <linux/log2.h>
+
+int mtd_dread(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen,
+	      u_char *buf)
+{
+	struct udevice *dev = mtd->dev;
+	const struct mtd_ops *ops = mtd_get_ops(dev);
+
+	if (!ops->read)
+		return -ENOSYS;
+
+	*retlen = 0;
+	if (from < 0 || from > mtd->size || len > mtd->size - from)
+		return -EINVAL;
+	if (!len)
+		return 0;
+
+	return ops->read(dev, from, len, retlen, buf);
+}
+
+int mtd_derase(struct mtd_info *mtd, struct erase_info *instr)
+{
+	struct udevice *dev = mtd->dev;
+	const struct mtd_ops *ops = mtd_get_ops(dev);
+
+	if (!ops->erase)
+		return -ENOSYS;
+
+	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 ops->erase(dev, instr);
+}
+
+int mtd_dwrite(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen,
+		 const u_char *buf)
+{
+	struct udevice *dev = mtd->dev;
+	const struct mtd_ops *ops = mtd_get_ops(dev);
+
+	if (!ops->write)
+		return -ENOSYS;
+
+	*retlen = 0;
+	if (to < 0 || to > mtd->size || len > mtd->size - to)
+		return -EINVAL;
+	if (!ops->write || !(mtd->flags & MTD_WRITEABLE))
+		return -EROFS;
+	if (!len)
+		return 0;
+
+	return ops->write(dev, to, len, retlen, buf);
+}
 
 /*
  * Implement a MTD uclass which should include most flash drivers.
diff --git a/include/mtd.h b/include/mtd.h
index 3f8c293..32b11c3 100644
--- a/include/mtd.h
+++ b/include/mtd.h
@@ -20,4 +20,50 @@ static inline struct mtd_info *mtd_get_info(struct udevice *dev)
 	return dev_get_uclass_priv(dev);
 }
 
+struct 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 mtd_ops *)(dev)->driver->ops)
+
+/**
+ * mtd_dread() - read data from MTD device
+ *
+ * @mtd:	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 mtd_dread(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen,
+	      u_char *buf);
+
+/**
+ * mtd_dwrite() - write data to MTD device
+ *
+ * @mtd:	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 mtd_dwrite(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen,
+	       const u_char *buf);
+
+/**
+ * mtd_derase() - erase blocks of the MTD device
+ *
+ * @mtd:	MTD device
+ * @instr:	erase info details of MTD device
+ * @return 0 if OK, -ve on error
+ */
+int mtd_derase(struct mtd_info *mtd, struct erase_info *instr);
+
 #endif	/* _MTD_H_ */
-- 
2.7.4

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

* [U-Boot] [PATCH v10 02/27] mtd: add mtd device create operations
  2017-12-28  6:12 [U-Boot] [PATCH v10 00/27] dm: Generic MTD Subsystem, with SPI-NOR interface Jagan Teki
  2017-12-28  6:12 ` [U-Boot] [PATCH v10 01/27] mtd: Add mtd core ops Jagan Teki
@ 2017-12-28  6:12 ` Jagan Teki
  2017-12-28  6:12 ` [U-Boot] [PATCH v10 03/27] mtd: add SPI-NOR core support Jagan Teki
                   ` (26 subsequent siblings)
  28 siblings, 0 replies; 55+ messages in thread
From: Jagan Teki @ 2017-12-28  6:12 UTC (permalink / raw)
  To: u-boot

mtd is common device interaction for most of
memory technology flashes like nand, parallel nor,
spi-nor, dataflash etc, these are terminated as
interface types in u-boot driver model.

This patch add common way of creating mtd device for
respective underlying interface type. once the interface
driver bind happen, the receptive uclass will pass an
interface type to mtd layer to create a device for it.

MTD_IF_TYPE_SPI_NOR in an interface type for all spi nor devices.

Signed-off-by: Suneel Garapati <suneelglinux@gmail.com>
Signed-off-by: Jagan Teki <jagan@amarulasolutions.com>
---
 drivers/mtd/mtd-uclass.c | 121 +++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/mtd/mtd.h  |  14 ++++++
 include/mtd.h            | 116 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 251 insertions(+)

diff --git a/drivers/mtd/mtd-uclass.c b/drivers/mtd/mtd-uclass.c
index d2c587f..c94afe9 100644
--- a/drivers/mtd/mtd-uclass.c
+++ b/drivers/mtd/mtd-uclass.c
@@ -11,6 +11,9 @@
 #include <mtd.h>
 #include <linux/log2.h>
 
+#include <dm/device-internal.h>
+#include <dm/lists.h>
+
 int mtd_dread(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen,
 	      u_char *buf)
 {
@@ -70,6 +73,124 @@ int mtd_dwrite(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen,
 	return ops->write(dev, to, len, retlen, buf);
 }
 
+int mtd_find_device(int mtd_if_type, int devnum, struct udevice **devp)
+{
+	struct uclass *uc;
+	struct udevice *dev;
+	int ret;
+
+	ret = uclass_get(UCLASS_MTD, &uc);
+	if (ret)
+		return ret;
+	uclass_foreach_dev(dev, uc) {
+		struct mtd_info *mtd = dev_get_uclass_platdata(dev);
+
+		debug("%s: mtd_if_type=%d, devnum=%d: %s, %d, %d\n", __func__,
+		      mtd_if_type, devnum, dev->name, mtd->mtd_if_type, mtd->devnum);
+		if (mtd->mtd_if_type == mtd_if_type && mtd->devnum == devnum) {
+			*devp = dev;
+			return 0;
+		}
+	}
+
+	return -ENODEV;
+}
+
+int mtd_get_device(int mtd_if_type, int devnum, struct udevice **devp)
+{
+	int ret;
+
+	ret = mtd_find_device(mtd_if_type, devnum, devp);
+	if (ret)
+		return ret;
+
+	return device_probe(*devp);
+}
+
+int mtd_select_devnum(enum mtd_if_type mtd_if_type, int devnum)
+{
+	struct udevice *dev;
+
+	return mtd_get_device(mtd_if_type, devnum, &dev);
+}
+
+int mtd_find_max_devnum(enum mtd_if_type mtd_if_type)
+{
+	struct udevice *dev;
+	int max_devnum = -ENODEV;
+	struct uclass *uc;
+	int ret;
+
+	ret = uclass_get(UCLASS_MTD, &uc);
+	if (ret)
+		return ret;
+	uclass_foreach_dev(dev, uc) {
+		struct mtd_info *mtd = dev_get_uclass_platdata(dev);
+
+		if (mtd->mtd_if_type == mtd_if_type && mtd->devnum > max_devnum)
+			max_devnum = mtd->devnum;
+	}
+
+	return max_devnum;
+}
+
+static int mtd_next_free_devnum(enum mtd_if_type mtd_if_type)
+{
+	int ret;
+
+	ret = mtd_find_max_devnum(mtd_if_type);
+	if (ret == -ENODEV)
+		return 0;
+	if (ret < 0)
+		return ret;
+
+	return ret + 1;
+}
+
+int mtd_create_device(struct udevice *parent, const char *drv_name,
+		      const char *name, int mtd_if_type, struct udevice **devp)
+{
+	struct mtd_info *mtd;
+	struct udevice *dev;
+	int devnum, ret;
+
+	devnum = mtd_next_free_devnum(mtd_if_type);
+	if (devnum < 0)
+		return devnum;
+	ret = device_bind_driver(parent, drv_name, name, &dev);
+	if (ret)
+		return ret;
+	mtd = dev_get_uclass_platdata(dev);
+	mtd->mtd_if_type = mtd_if_type;
+	mtd->dev = dev;
+	mtd->devnum = devnum;
+	*devp = dev;
+
+	return 0;
+}
+
+int mtd_create_devicef(struct udevice *parent, const char *drv_name,
+		       const char *name, int mtd_if_type,
+		       struct udevice **devp)
+{
+	char dev_name[30], *str;
+	int ret;
+
+	snprintf(dev_name, sizeof(dev_name), "%s.%s", parent->name, name);
+	str = strdup(dev_name);
+	if (!str)
+		return -ENOMEM;
+
+	ret = mtd_create_device(parent, drv_name, str, mtd_if_type, devp);
+	if (ret) {
+		free(str);
+		return ret;
+	}
+	device_set_name_alloced(*devp);
+
+	return ret;
+}
+
 /*
  * Implement a MTD uclass which should include most flash drivers.
  * The uclass private is pointed to mtd_info.
diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
index ba4cbba..6ec9763 100644
--- a/include/linux/mtd/mtd.h
+++ b/include/linux/mtd/mtd.h
@@ -149,6 +149,16 @@ struct nand_ecclayout {
 
 struct module;	/* only needed for owner field in mtd_info */
 
+#ifdef CONFIG_MTD
+/* Interface types: */
+enum mtd_if_type {
+	MTD_IF_TYPE_UNKNOWN = 0,
+	MTD_IF_TYPE_SPI_NOR,
+
+	MTD_IF_TYPE_COUNT,
+};
+#endif
+
 struct mtd_info {
 	u_char type;
 	uint32_t flags;
@@ -309,6 +319,10 @@ struct mtd_info {
 	struct udevice *dev;
 #endif
 	int usecount;
+#ifdef CONFIG_MTD
+	enum mtd_if_type	mtd_if_type;	/* type of mtd interface */
+	int			devnum;		/* device number */
+#endif
 };
 
 int mtd_ooblayout_ecc(struct mtd_info *mtd, int section,
diff --git a/include/mtd.h b/include/mtd.h
index 32b11c3..273b3a6 100644
--- a/include/mtd.h
+++ b/include/mtd.h
@@ -66,4 +66,120 @@ int mtd_dwrite(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen,
  */
 int mtd_derase(struct mtd_info *mtd, struct erase_info *instr);
 
+/**
+ * mtd_find_device() - find a mtd device
+ *
+ * This function does not activate the device. The device will be returned
+ * whether or not it is activated.
+ *
+ * @mtd_if_type:	interface type (enum mtd_if_type_t)
+ * @devnum:		device number (specific to each interface type)
+ * @devp:		the device, if found
+ * @return 0 if found, -ENODEV if no device found, or other -ve error value
+ */
+int mtd_find_device(int mtd_if_type, int devnum, struct udevice **devp);
+
+/**
+ * mtd_get_device() - find and probe a mtd device ready for use
+ *
+ * @mtd_if_type:	interface type (enum mtd_if_type_t)
+ * @devnum:		device number (specific to each interface type)
+ * @devp:		the device, if found
+ * @return 0 if found, -ENODEV if no device found, or other -ve error value
+ */
+int mtd_get_device(int mtd_if_type, int devnum, struct udevice **devp);
+
+/**
+ * mtd_first_device() - find the first device for a given interface
+ *
+ * The device is probed ready for use
+ *
+ * @devnum:	device number (specific to each interface type)
+ * @devp:	the device, if found
+ * @return 0 if found, -ENODEV if no device, or other -ve error value
+ */
+int mtd_first_device(int mtd_if_type, struct udevice **devp);
+
+/**
+ * mtd_next_device() - find the next device for a given interface
+ *
+ * This can be called repeatedly after mtd_first_device() to iterate through
+ * all devices of the given interface type.
+ *
+ * The device is probed ready for use
+ *
+ * @devp:	on entry, the previous device returned. On exit, the next
+ *		device, if found
+ * @return 0 if found, -ENODEV if no device, or other -ve error value
+ */
+int mtd_next_device(struct udevice **devp);
+
+/**
+ * mtd_create_device() - create a new mtd device
+ *
+ * @parent:		parent of the new device
+ * @drv_name:		driver name to use for the mtd device
+ * @name:		name for the device
+ * @mtd_if_type:	Interface type (enum mtd_if_type_t)
+ * @devp:		the new device (which has not been probed)
+ */
+int mtd_create_device(struct udevice *parent, const char *drv_name,
+		      const char *name, int mtd_if_type,
+		      struct udevice **devp);
+
+/**
+ * mtd_create_devicef() - Cceate a new named mtd device
+ *
+ * @parent:		parent of the new device
+ * @drv_name:		driver name to use for the mtd device
+ * @name:		name for the device (parent name is prepended)
+ * @mtd_if_type:	interface type (enum mtd_if_type_t)
+ * @devp:		the new device (which has not been probed)
+ */
+int mtd_create_devicef(struct udevice *parent, const char *drv_name,
+		       const char *name, int mtd_if_type,
+		       struct udevice **devp);
+
+/**
+ * mtd_prepare_device() - prepare a mtd device for use
+ *
+ * This reads partition information from the device if supported.
+ *
+ * @dev:	device to prepare
+ * @return 0 if ok, -ve on error
+ */
+int mtd_prepare_device(struct udevice *dev);
+
+/**
+ * mtd_unbind_all() - unbind all device of the given interface type
+ *
+ * The devices are removed and then unbound.
+ *
+ * @mtd_if_type:	interface type to unbind
+ * @return 0 if OK, -ve on error
+ */
+int mtd_unbind_all(int mtd_if_type);
+
+/**
+ * mtd_find_max_devnum() - find the maximum device number for an interface type
+ *
+ * Finds the last allocated device number for an interface type @mtd_if_type. The
+ * next number is safe to use for a newly allocated device.
+ *
+ * @mtd_if_type:	interface type to scan
+ * @return maximum device number found, or -ENODEV if none, or other -ve on
+ * error
+ */
+int mtd_find_max_devnum(enum mtd_if_type mtd_if_type);
+
+/**
+ * mtd_select_devnum() - select the mtd device from device number
+ *
+ * @mtd_if_type:	interface type to scan
+ * @devnum:		device number, specific to the interface type, or -1 to
+ * @return maximum device number found, or -ENODEV if none, or other -ve on
+ * error
+ */
+int mtd_select_devnum(enum mtd_if_type mtd_if_type, int devnum);
+
 #endif	/* _MTD_H_ */
-- 
2.7.4

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

* [U-Boot] [PATCH v10 03/27] mtd: add SPI-NOR core support
  2017-12-28  6:12 [U-Boot] [PATCH v10 00/27] dm: Generic MTD Subsystem, with SPI-NOR interface Jagan Teki
  2017-12-28  6:12 ` [U-Boot] [PATCH v10 01/27] mtd: Add mtd core ops Jagan Teki
  2017-12-28  6:12 ` [U-Boot] [PATCH v10 02/27] mtd: add mtd device create operations Jagan Teki
@ 2017-12-28  6:12 ` Jagan Teki
  2017-12-29  9:25   ` Andy Yan
                     ` (4 more replies)
  2017-12-28  6:12 ` [U-Boot] [PATCH v10 04/27] mtd: spi-nor: sync/modify sst write operations Jagan Teki
                   ` (25 subsequent siblings)
  28 siblings, 5 replies; 55+ messages in thread
From: Jagan Teki @ 2017-12-28  6:12 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/spinor.c
=======================================
             mtd-uclass.c
=======================================
           spi-nor-uclass.c
=======================================
              spi-nor.c
=======================================
m25p80.c                zynq_qspinor.c
=======================================
spi-uclass.c
=======================================
zynq_qspi.c
=======================================
        #####SPI NOR chip######
=======================================

Signed-off-by: Suneel Garapati <suneelglinux@gmail.com>
Signed-off-by: Jagan Teki <jagan@amarulasolutions.com>
---
 Makefile                             |   1 +
 drivers/mtd/spi-nor/Makefile         |   7 +
 drivers/mtd/spi-nor/spi-nor-ids.c    | 184 +++++++++++
 drivers/mtd/spi-nor/spi-nor-uclass.c | 143 +++++++++
 drivers/mtd/spi-nor/spi-nor.c        | 569 +++++++++++++++++++++++++++++++++++
 include/dm/uclass-id.h               |   1 +
 include/linux/mtd/spi-nor.h          | 217 +++++++++++++
 7 files changed, 1122 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-uclass.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 e6d309a..70b5202 100644
--- a/Makefile
+++ b/Makefile
@@ -662,6 +662,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..c1212a8
--- /dev/null
+++ b/drivers/mtd/spi-nor/Makefile
@@ -0,0 +1,7 @@
+#
+# Copyright (C) 2016 Jagan Teki <jagan@openedev.com>
+#
+# SPDX-License-Identifier:	GPL-2.0+
+
+## spi-nor core
+obj-y	+= spi-nor.o spi-nor-uclass.o spi-nor-ids.o
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..db95655
--- /dev/null
+++ b/drivers/mtd/spi-nor/spi-nor-ids.c
@@ -0,0 +1,184 @@
+/*
+ * 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) },
+	{"mx25u6435f",	   INFO(0xc22537, 0x0, 64 * 1024,   128, RD_FULL | WR_QPP) },
+	{"mx25l12855e",	   INFO(0xc22618, 0x0, 64 * 1024,   256, RD_FULL | WR_QPP) },
+	{"mx25u1635e",     INFO(0xc22535, 0x0, 64 * 1024,  32, SECT_4K) },
+	{"mx66u51235f",    INFO(0xc2253a, 0x0, 64 * 1024,  1024, RD_FULL | WR_QPP) },
+	{"mx66l1g45g",     INFO(0xc2201b, 0x0, 64 * 1024,  2048, 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,    32, 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) },
+	{"s25fs256s_64k",  INFO6(0x010219, 0x4d0181, 64 * 1024, 512, RD_FULL | WR_QPP | SECT_4K) },
+	{"s25fl256s_64k",  INFO(0x010219, 0x4d01,  64 * 1024,   512, RD_FULL | WR_QPP) },
+	{"s25fs512s",      INFO6(0x010220, 0x4d0081, 128 * 1024, 512, RD_FULL | WR_QPP | SECT_4K) },
+	{"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) },
+	{"mt25qu02g",	   INFO(0x20bb22, 0x0,  64 * 1024,  4096, RD_FULL | WR_QPP | E_FSR | SECT_4K) },
+	{"mt25ql02g",	   INFO(0x20ba22, 0x0,  64 * 1024,  4096, RD_FULL | WR_QPP | E_FSR | SECT_4K) },
+	{"mt35xu512g",	   INFO6(0x2c5b1a, 0x104100,  128 * 1024,  512, 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 */
+	{"is25lq040b",	   INFO(0x9d4013, 0x0, 64 * 1024,     8, 0) },
+	{"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-uclass.c b/drivers/mtd/spi-nor/spi-nor-uclass.c
new file mode 100644
index 0000000..919682d
--- /dev/null
+++ b/drivers/mtd/spi-nor/spi-nor-uclass.c
@@ -0,0 +1,143 @@
+/*
+ * 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 <mtd.h>
+
+#include <dm/device-internal.h>
+#include <linux/mtd/spi-nor.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct spi_nor *spi_nor_get_spi_nor_dev(struct udevice *dev)
+{
+	struct spi_nor_uclass_priv *upriv;
+
+	if (!device_active(dev))
+		return NULL;
+	upriv = dev_get_uclass_priv(dev);
+	return upriv->spi_nor;
+}
+
+struct spi_nor *find_spi_nor_device(int dev_num)
+{
+	struct udevice *dev, *spi_nor_dev;
+	int ret;
+
+	ret = mtd_find_device(MTD_IF_TYPE_SPI_NOR, dev_num, &dev);
+	if (ret) {
+		printf("SPI-NOR Device %d not found\n", dev_num);
+		return NULL;
+	}
+
+	spi_nor_dev = dev_get_parent(dev);
+
+	struct spi_nor *nor = spi_nor_get_spi_nor_dev(spi_nor_dev);
+
+	return nor;
+}
+
+int get_spi_nor_num(void)
+{
+	return max((mtd_find_max_devnum(MTD_IF_TYPE_SPI_NOR) + 1), 0);
+}
+
+struct mtd_info *spi_nor_get_mtd_info(struct spi_nor *nor)
+{
+	struct mtd_info *mtd;
+	struct udevice *dev;
+
+	device_find_first_child(nor->dev, &dev);
+	if (!dev)
+		return NULL;
+	mtd = dev_get_uclass_platdata(dev);
+
+	return mtd;
+}
+
+void print_spi_nor_devices(char separator)
+{
+	struct udevice *dev;
+	bool first = true;
+
+	for (uclass_first_device(UCLASS_SPI_NOR, &dev);
+	     dev;
+	     uclass_next_device(&dev), first = false) {
+		struct spi_nor *nor = spi_nor_get_spi_nor_dev(dev);
+
+		if (!first) {
+			printf("%c", separator);
+			if (separator != '\n')
+				puts(" ");
+		}
+
+		printf("%s: %d", dev->name, spi_nor_get_mtd_info(nor)->devnum);
+	}
+
+	printf("\n");
+}
+
+int spi_nor_bind(struct udevice *dev, struct spi_nor *nor)
+{
+	struct udevice *mdev;
+	int ret;
+
+	if (!spi_nor_get_ops(dev))
+		return -ENOSYS;
+
+	ret = mtd_create_devicef(dev, "spinor_mtd", "mtd", MTD_IF_TYPE_SPI_NOR,
+				 &mdev);
+	if (ret) {
+		debug("Cannot create mtd device\n");
+		return ret;
+	}
+	nor->dev = dev;
+
+	return 0;
+}
+
+static int spi_nor_mtd_probe(struct udevice *dev)
+{
+	struct udevice *spi_nor_dev = dev_get_parent(dev);
+	struct spi_nor_uclass_priv *upriv = dev_get_uclass_priv(spi_nor_dev);
+	struct spi_nor *nor = upriv->spi_nor;
+	int ret;
+
+	ret = spi_nor_scan(nor);
+	if (ret) {
+		debug("%s: spi_nor_scan() failed (err=%d)\n", __func__, ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static const struct mtd_ops spi_nor_mtd_ops = {
+	.read	= spi_nor_mread,
+	.erase	= spi_nor_merase,
+};
+
+U_BOOT_DRIVER(spinor_mtd) = {
+	.name		= "spinor_mtd",
+	.id		= UCLASS_MTD,
+	.ops		= &spi_nor_mtd_ops,
+	.probe		= spi_nor_mtd_probe,
+};
+
+U_BOOT_DRIVER(spinor) = {
+	.name	= "spinor",
+	.id	= UCLASS_SPI_NOR,
+};
+
+UCLASS_DRIVER(spinor) = {
+	.id		= UCLASS_SPI_NOR,
+	.name		= "spinor",
+	.flags		= DM_UC_FLAG_SEQ_ALIAS,
+	.per_device_auto_alloc_size = sizeof(struct spi_nor_uclass_priv),
+};
diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
new file mode 100644
index 0000000..09fb8ca
--- /dev/null
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -0,0 +1,569 @@
+/*
+ * 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 <dm/device-internal.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 udevice *dev)
+{
+	return spi_nor_get_ops(dev)->write_reg(dev, SNOR_OP_WREN, NULL, 0);
+}
+
+/* Re-set write enable latch with Write Disable command */
+static inline int write_disable(struct udevice *dev)
+{
+	return spi_nor_get_ops(dev)->write_reg(dev, SNOR_OP_WRDI, NULL, 0);
+}
+
+static int read_sr(struct udevice *dev)
+{
+	u8 sr;
+	int ret;
+
+	ret = spi_nor_get_ops(dev)->read_reg(dev, 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 udevice *dev)
+{
+	u8 fsr;
+	int ret;
+
+	ret = spi_nor_get_ops(dev)->read_reg(dev, 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 udevice *dev, u8 ws)
+{
+	struct spi_nor *nor = spi_nor_get_spi_nor_dev(dev);
+	const struct spi_nor_ops *ops = spi_nor_get_ops(dev);
+
+	nor->cmd_buf[0] = ws;
+	return ops->write_reg(dev, SNOR_OP_WRSR, nor->cmd_buf, 1);
+}
+
+#if defined(CONFIG_SPI_NOR_SPANSION) || defined(CONFIG_SPI_NOR_WINBOND)
+static int read_cr(struct udevice *dev)
+{
+	u8 cr;
+	int ret;
+
+	ret = spi_nor_get_ops(dev)->read_reg(dev, 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 udevice *dev, u16 val)
+{
+	struct spi_nor *nor = spi_nor_get_spi_nor_dev(dev);
+	const struct spi_nor_ops *ops = spi_nor_get_ops(dev);
+
+	nor->cmd_buf[0] = val & 0xff;
+	nor->cmd_buf[1] = (val >> 8);
+
+	return ops->write_reg(dev, SNOR_OP_WRSR, nor->cmd_buf, 2);
+}
+#endif
+
+static int spi_nor_sr_ready(struct udevice *dev)
+{
+	int sr = read_sr(dev);
+	if (sr < 0)
+		return sr;
+	else
+		return !(sr & SR_WIP);
+}
+
+static int spi_nor_fsr_ready(struct udevice *dev)
+{
+	int fsr = read_fsr(dev);
+	if (fsr < 0)
+		return fsr;
+	else
+		return fsr & FSR_READY;
+}
+
+static int spi_nor_ready(struct udevice *dev)
+{
+	struct spi_nor *nor = spi_nor_get_spi_nor_dev(dev);
+	int sr, fsr;
+
+	sr = spi_nor_sr_ready(dev);
+	if (sr < 0)
+		return sr;
+
+	fsr = 1;
+	if (nor->flags & SNOR_F_USE_FSR) {
+		fsr = spi_nor_fsr_ready(dev);
+		if (fsr < 0)
+			return fsr;
+	}
+
+	return sr && fsr;
+}
+
+static int spi_nor_wait_till_ready(struct udevice *dev, unsigned long timeout)
+{
+	int timebase, ret;
+
+	timebase = get_timer(0);
+
+	while (get_timer(timebase) < timeout) {
+		ret = spi_nor_ready(dev);
+		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 udevice *dev)
+{
+	int				tmp;
+	u8				id[SPI_NOR_MAX_ID_LEN];
+	const struct spi_nor_info	*info;
+	const struct spi_nor_ops	*ops = spi_nor_get_ops(dev);
+
+	tmp = ops->read_reg(dev, 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);
+}
+
+int spi_nor_merase(struct udevice *dev, struct erase_info *instr)
+{
+	struct mtd_info *mtd = dev_get_uclass_platdata(dev);
+	int devnum = mtd->devnum;
+	struct spi_nor *nor;
+	const struct spi_nor_ops *ops;
+	u32 addr, len, erase_addr;
+	uint32_t rem;
+	int ret = -1;
+
+	nor = find_spi_nor_device(devnum);
+	if (!nor)
+		return -ENODEV;
+	ops = spi_nor_get_ops(nor->dev);
+
+	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->dev);
+
+		ret = ops->write(nor->dev, erase_addr, 0, NULL);
+		if (ret < 0)
+			goto erase_err;
+
+		ret = spi_nor_wait_till_ready(nor->dev, SNOR_READY_WAIT_ERASE);
+		if (ret < 0)
+			goto erase_err;
+
+		addr += mtd->erasesize;
+		len -= mtd->erasesize;
+	}
+
+	write_disable(nor->dev);
+
+	instr->state = MTD_ERASE_DONE;
+	mtd_erase_callback(instr);
+
+	return ret;
+
+erase_err:
+	instr->state = MTD_ERASE_FAILED;
+	return ret;
+}
+
+static int spi_nor_mwrite(struct udevice *dev, loff_t to, size_t len,
+			  size_t *retlen, const u_char *buf)
+{
+	struct mtd_info *mtd = dev_get_uclass_platdata(dev);
+	int devnum = mtd->devnum;
+	struct spi_nor *nor;
+	const struct spi_nor_ops *ops;
+	size_t addr, byte_addr;
+	size_t chunk_len, actual;
+	uint32_t page_size;
+	int ret = -1;
+
+	nor = find_spi_nor_device(devnum);
+	if (!nor)
+		return -ENODEV;
+	ops = spi_nor_get_ops(nor->dev);
+
+	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->dev);
+
+		ret = ops->write(nor->dev, addr, chunk_len, buf + actual);
+		if (ret < 0)
+			break;
+
+		ret = spi_nor_wait_till_ready(nor->dev, SNOR_READY_WAIT_PROG);
+		if (ret < 0)
+			return ret;
+
+		to += chunk_len;
+		*retlen += chunk_len;
+	}
+
+	return ret;
+}
+
+int spi_nor_mread(struct udevice *dev, loff_t from, size_t len,
+		  size_t *retlen, u_char *buf)
+{
+	struct mtd_info *mtd = dev_get_uclass_platdata(dev);
+	int devnum = mtd->devnum;
+	struct spi_nor *nor;
+	const struct spi_nor_ops *ops;
+	int ret;
+
+	nor = find_spi_nor_device(devnum);
+	if (!nor)
+		return -ENODEV;
+	ops = spi_nor_get_ops(nor->dev);
+
+	/* Handle memory-mapped SPI */
+	if (nor->memory_map) {
+		ret = ops->read(nor->dev, from, len, buf);
+		if (ret) {
+			debug("spi-nor: mmap read failed\n");
+			return ret;
+		}
+
+		return ret;
+	}
+
+	ret = ops->read(nor->dev, from, len, buf);
+	if (ret < 0) {
+		printf("%s ret = %d\n", __func__, ret);
+		return ret;
+	}
+
+	*retlen += len;
+
+	return ret;
+}
+
+#ifdef CONFIG_SPI_NOR_MACRONIX
+static int macronix_quad_enable(struct udevice *dev)
+{
+	int ret, val;
+
+	val = read_sr(dev);
+	if (val < 0)
+		return val;
+
+	if (val & SR_QUAD_EN_MX)
+		return 0;
+
+	write_enable(dev);
+
+	ret = write_sr(dev, val | SR_QUAD_EN_MX);
+	if (ret < 0)
+		return ret;
+
+	if (spi_nor_wait_till_ready(dev, SNOR_READY_WAIT_PROG))
+		return 1;
+
+	ret = read_sr(dev);
+	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 udevice *dev)
+{
+	int ret, val;
+
+	val = read_cr(dev);
+	if (val < 0)
+		return val;
+
+	if (val & CR_QUAD_EN_SPAN)
+		return 0;
+
+	write_enable(dev);
+
+	ret = write_sr_cr(dev, val | CR_QUAD_EN_SPAN);
+	if (ret < 0)
+		return ret;
+
+	if (spi_nor_wait_till_ready(dev, SNOR_READY_WAIT_PROG))
+		return 1;
+
+	/* read back and check it */
+	ret = read_cr(dev);
+	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 udevice *dev, const struct spi_nor_info *info)
+{
+	switch (JEDEC_MFR(info)) {
+#ifdef CONFIG_SPI_NOR_MACRONIX
+	case SNOR_MFR_MACRONIX:
+		return macronix_quad_enable(dev);
+#endif
+#if defined(CONFIG_SPI_NOR_SPANSION) || defined(CONFIG_SPI_NOR_WINBOND)
+	case SNOR_MFR_SPANSION:
+	case SNOR_MFR_WINBOND:
+		return spansion_quad_enable(dev);
+#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) */
+
+int spi_nor_scan(struct spi_nor *nor)
+{
+	struct mtd_info *mtd = spi_nor_get_mtd_info(nor);
+	struct mtd_ops *ops = mtd_get_ops(mtd->dev);
+	const struct spi_nor_info *info = NULL;
+	int ret;
+
+	struct spi_nor_uclass_priv *upriv = dev_get_uclass_priv(nor->dev);
+	upriv->spi_nor = nor;
+
+	if (nor->init_done)
+		return 0;
+	
+	info = spi_nor_id(nor->dev);
+	if (IS_ERR_OR_NULL(info)) {
+		ret = -ENOENT;
+		goto err;
+	}
+
+	/*
+	 * Flash powers up read-only, so clear BP# bits.
+	 *
+	 * Note on some flash (like Macronix), QE (quad enable) bit is in the
+	 * same status register as BP# bits, and we need preserve its original
+	 * value during a reboot cycle as this is required by some platforms
+	 * (like Intel ICH SPI controller working under descriptor mode).
+	 */
+	if (JEDEC_MFR(info) == SNOR_MFR_ATMEL ||
+	   (JEDEC_MFR(info) == SNOR_MFR_SST) ||
+	   (JEDEC_MFR(info) == SNOR_MFR_MACRONIX)) {
+		u8 sr = 0;
+
+		if (JEDEC_MFR(info) == SNOR_MFR_MACRONIX)
+			sr = read_sr(nor->dev) & SR_QUAD_EN_MX;
+		write_sr(nor->dev, sr);
+	}
+
+	mtd->name = info->name;
+	mtd->priv = nor;
+	mtd->type = MTD_NORFLASH;
+	mtd->writesize = 1;
+	mtd->flags = MTD_CAP_NORFLASH;
+
+	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_mwrite;
+
+	/* 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->dev, info);
+		if (ret) {
+			debug("spi-nor: quad mode not supported for %02x\n",
+			      JEDEC_MFR(info));
+			goto err;
+		}
+	}
+
+	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");
+		goto err;
+	}
+#endif
+
+	nor->init_done = 1;
+	return 0;
+err:	
+	nor->init_done = 0;
+	return ret;
+}
diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h
index 3fc2083..06541a4 100644
--- a/include/dm/uclass-id.h
+++ b/include/dm/uclass-id.h
@@ -75,6 +75,7 @@ enum uclass_id {
 	UCLASS_SERIAL,		/* Serial UART */
 	UCLASS_SPI,		/* SPI bus */
 	UCLASS_SPMI,		/* System Power Management Interface bus */
+	UCLASS_SPI_NOR,		/* SPI NOR flash */
 	UCLASS_SPI_FLASH,	/* SPI flash */
 	UCLASS_SPI_GENERIC,	/* Generic SPI flash target */
 	UCLASS_SYSCON,		/* System configuration device */
diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
new file mode 100644
index 0000000..e1688e2
--- /dev/null
+++ b/include/linux/mtd/spi-nor.h
@@ -0,0 +1,217 @@
+/*
+ * 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>
+#include <linux/mtd/mtd.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
+
+/**
+ * struct spi_nor_uclass_priv - Holds information about a device used by the uclass
+ */
+struct spi_nor_uclass_priv {
+	struct spi_nor *spi_nor;
+};
+
+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
+ */
+struct spi_nor {
+	struct udevice		*dev;
+	const char		*name;
+	u8			init_done;
+	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];
+
+	void *memory_map;
+};
+
+struct spi_nor_ops {
+	int (*read_reg)(struct udevice *dev, u8 cmd, u8 *val, int len);
+	int (*write_reg)(struct udevice *dev, u8 cmd, u8 *data, int len);
+
+	int (*read)(struct udevice *dev, loff_t from, size_t len,
+		    u_char *buf);
+	int (*write)(struct udevice *dev, loff_t to, size_t len,
+		     const u_char *buf);
+};
+
+#define spi_nor_get_ops(dev)	((struct spi_nor_ops *)(dev)->driver->ops)
+
+int spi_nor_merase(struct udevice *dev, struct erase_info *instr);
+int spi_nor_mread(struct udevice *dev, loff_t from, size_t len,
+		  size_t *retlen, u_char *buf);
+
+int spi_nor_scan(struct spi_nor *nor);
+int spi_nor_bind(struct udevice *dev, struct spi_nor *nor);
+
+struct spi_nor *find_spi_nor_device(int dev_num);
+int get_spi_nor_num(void);
+struct spi_nor *spi_nor_get_spi_nor_dev(struct udevice *dev);
+struct mtd_info *spi_nor_get_mtd_info(struct spi_nor *nor);
+
+#endif /* __MTD_SPI_NOR_H */
-- 
2.7.4

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

* [U-Boot] [PATCH v10 04/27] mtd: spi-nor: sync/modify sst write operations
  2017-12-28  6:12 [U-Boot] [PATCH v10 00/27] dm: Generic MTD Subsystem, with SPI-NOR interface Jagan Teki
                   ` (2 preceding siblings ...)
  2017-12-28  6:12 ` [U-Boot] [PATCH v10 03/27] mtd: add SPI-NOR core support Jagan Teki
@ 2017-12-28  6:12 ` Jagan Teki
  2017-12-28  6:12 ` [U-Boot] [PATCH v10 05/27] mtd: spi-nor: sync/modify lock operations Jagan Teki
                   ` (24 subsequent siblings)
  28 siblings, 0 replies; 55+ messages in thread
From: Jagan Teki @ 2017-12-28  6:12 UTC (permalink / raw)
  To: u-boot

sst write operations can be changed based on the mode
set from the controller with byte program or word program,
so sync the similar code from legacy spi_flash.c and
update accordingly with mtd operations.

Signed-off-by: Suneel Garapati <suneelglinux@gmail.com>
Signed-off-by: Jagan Teki <jagan@amarulasolutions.com>
---
 drivers/mtd/spi-nor/spi-nor.c | 115 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 115 insertions(+)

diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index 09fb8ca..cfd21fb 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -316,6 +316,113 @@ int spi_nor_mread(struct udevice *dev, loff_t from, size_t 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)
+{
+	const struct spi_nor_ops *ops = spi_nor_get_ops(nor->dev);
+	int ret;
+
+	ret = write_enable(nor->dev);
+	if (ret)
+		return ret;
+
+	nor->program_opcode = SNOR_OP_BP;
+
+	ret = ops->write(nor->dev, addr, 1, buf);
+	if (ret)
+		return ret;
+
+	*retlen += 1;
+
+	return spi_nor_wait_till_ready(nor->dev, SNOR_READY_WAIT_PROG);
+}
+
+static int sst_mwrite_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);
+	int devnum = mtd->devnum;
+	const struct spi_nor_ops *ops;
+	struct spi_nor *nor;
+	size_t actual;
+	int ret;
+
+	nor = find_spi_nor_device(devnum);
+	if (!nor)
+		return -ENODEV;
+	ops = spi_nor_get_ops(nor->dev);
+
+	/* 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->dev);
+	if (ret)
+		goto done;
+
+	for (; actual < len - 1; actual += 2) {
+		nor->program_opcode = SNOR_OP_AAI_WP;
+
+		ret = ops->write(nor->dev, to, 2, buf + actual);
+		if (ret) {
+			debug("spi-nor: sst word program failed\n");
+			break;
+		}
+
+		ret = spi_nor_wait_till_ready(nor->dev, SNOR_READY_WAIT_PROG);
+		if (ret)
+			break;
+
+		to += 2;
+		*retlen += 2;
+	}
+
+	if (!ret)
+		ret = write_disable(nor->dev);
+
+	/* 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_mwrite_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);
+	int devnum = mtd->devnum;
+	struct spi_nor *nor;
+	size_t actual;
+	int ret;
+
+	nor = find_spi_nor_device(devnum);
+	if (!nor)
+		return -ENODEV;
+
+	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->dev);
+
+	return ret;
+}
+#endif
+
 #ifdef CONFIG_SPI_NOR_MACRONIX
 static int macronix_quad_enable(struct udevice *dev)
 {
@@ -482,6 +589,14 @@ int spi_nor_scan(struct spi_nor *nor)
 		nor->flags |= SNOR_F_SST_WRITE;
 
 	ops->write = spi_nor_mwrite;
+#if defined(CONFIG_SPI_NOR_SST)
+	if (nor->flags & SNOR_F_SST_WRITE) {
+		if (nor->mode & SNOR_WRITE_1_1_BYTE)
+			ops->write = sst_mwrite_bp;
+		else
+			ops->write = sst_mwrite_wp;
+	}
+#endif
 
 	/* compute the flash size */
 	nor->page_size = info->page_size;
-- 
2.7.4

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

* [U-Boot] [PATCH v10 05/27] mtd: spi-nor: sync/modify lock operations
  2017-12-28  6:12 [U-Boot] [PATCH v10 00/27] dm: Generic MTD Subsystem, with SPI-NOR interface Jagan Teki
                   ` (3 preceding siblings ...)
  2017-12-28  6:12 ` [U-Boot] [PATCH v10 04/27] mtd: spi-nor: sync/modify sst write operations Jagan Teki
@ 2017-12-28  6:12 ` Jagan Teki
  2017-12-28  6:12 ` [U-Boot] [PATCH v10 06/27] mtd: spi-nor: Kconfig: Add MTD_SPI_NOR entry Jagan Teki
                   ` (23 subsequent siblings)
  28 siblings, 0 replies; 55+ messages in thread
From: Jagan Teki @ 2017-12-28  6:12 UTC (permalink / raw)
  To: u-boot

sync the lock operations from legacy spi_flash.c and
update them according to current spi-nor framework.

Signed-off-by: Suneel Garapati <suneelglinux@gmail.com>
Signed-off-by: Jagan Teki <jagan@amarulasolutions.com>
---
 drivers/mtd/spi-nor/spi-nor.c | 218 ++++++++++++++++++++++++++++++++++++++++++
 include/mtd.h                 |   3 +
 2 files changed, 221 insertions(+)

diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index cfd21fb..8bf9e67 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -186,6 +186,7 @@ static const struct spi_nor_info *spi_nor_id(struct udevice *dev)
 int spi_nor_merase(struct udevice *dev, struct erase_info *instr)
 {
 	struct mtd_info *mtd = dev_get_uclass_platdata(dev);
+	const struct mtd_ops *mops = mtd_get_ops(mtd->dev);
 	int devnum = mtd->devnum;
 	struct spi_nor *nor;
 	const struct spi_nor_ops *ops;
@@ -205,6 +206,14 @@ int spi_nor_merase(struct udevice *dev, struct erase_info *instr)
 	addr = instr->addr;
 	len = instr->len;
 
+	if (mops->is_locked) {
+		ret = mops->is_locked(mtd->dev, addr, len);
+		if (ret > 0) {
+			printf("spi-nor: offset 0x%x is locked, cannot be erased\n", addr);
+			return -EINVAL;
+		}
+	}
+
 	while (len) {
 		erase_addr = addr;
 
@@ -238,6 +247,7 @@ static int spi_nor_mwrite(struct udevice *dev, loff_t to, size_t len,
 			  size_t *retlen, const u_char *buf)
 {
 	struct mtd_info *mtd = dev_get_uclass_platdata(dev);
+	const struct mtd_ops *mops = mtd_get_ops(mtd->dev);
 	int devnum = mtd->devnum;
 	struct spi_nor *nor;
 	const struct spi_nor_ops *ops;
@@ -253,6 +263,14 @@ static int spi_nor_mwrite(struct udevice *dev, loff_t to, size_t len,
 
 	page_size = mtd->writebufsize;
 
+	if (mops->is_locked) {
+		ret = mops->is_locked(mtd->dev, to, len);
+		if (ret > 0) {
+			printf("spi-nor: offset 0x%llx is locked, cannot be written\n", to);
+			return -EINVAL;
+		}
+	}
+
 	for (actual = 0; actual < len; actual += chunk_len) {
 		addr = to;
 
@@ -423,6 +441,197 @@ static int sst_mwrite_bp(struct udevice *dev, loff_t to, size_t len,
 }
 #endif
 
+#if defined(CONFIG_SPI_NOR_STMICRO) || defined(CONFIG_SPI_NOR_SST)
+static void stm_get_locked_range(struct mtd_info *mtd, u8 sr, loff_t *ofs,
+				 u64 *len)
+{
+	u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
+	int shift = ffs(mask) - 1;
+	int pow;
+
+	if (!(sr & mask)) {
+		/* No protection */
+		*ofs = 0;
+		*len = 0;
+	} else {
+		pow = ((sr & mask) ^ mask) >> shift;
+		*len = mtd->size >> pow;
+		*ofs = mtd->size - *len;
+	}
+}
+
+/* Return 1 if the entire region is locked, 0 otherwise */
+static int stm_is_locked_sr(struct mtd_info *mtd, loff_t ofs, u64 len,
+			    u8 sr)
+{
+	loff_t lock_offs;
+	u64 lock_len;
+
+	stm_get_locked_range(mtd, sr, &lock_offs, &lock_len);
+
+	return (ofs + len <= lock_offs + lock_len) && (ofs >= lock_offs);
+}
+
+/*
+ * Check if a region of the flash is (completely) locked. See stm_lock() for
+ * more info.
+ *
+ * Returns 1 if entire region is locked, 0 if any portion is unlocked, and
+ * negative on errors.
+ */
+static int stm_is_locked(struct udevice *dev, loff_t ofs, uint64_t len)
+{
+	struct mtd_info *mtd = dev_get_uclass_platdata(dev);
+	int devnum = mtd->devnum;
+	struct spi_nor *nor;
+	int status;
+
+	nor = find_spi_nor_device(devnum);
+	if (!nor)
+		return -ENODEV;
+
+	status = read_sr(nor->dev);
+	if (status < 0)
+		return status;
+
+	return stm_is_locked_sr(mtd, ofs, len, status);
+}
+
+/*
+ * Lock a region of the flash. Compatible with ST Micro and similar flash.
+ * Supports only the block protection bits BP{0,1,2} in the status register
+ * (SR). Does not support these features found in newer SR bitfields:
+ *   - TB: top/bottom protect - only handle TB=0 (top protect)
+ *   - SEC: sector/block protect - only handle SEC=0 (block protect)
+ *   - CMP: complement protect - only support CMP=0 (range is not complemented)
+ *
+ * Sample table portion for 8MB flash (Winbond w25q64fw):
+ *
+ *   SEC  |  TB   |  BP2  |  BP1  |  BP0  |  Prot Length  | Protected Portion
+ *  --------------------------------------------------------------------------
+ *    X   |   X   |   0   |   0   |   0   |  NONE         | NONE
+ *    0   |   0   |   0   |   0   |   1   |  128 KB       | Upper 1/64
+ *    0   |   0   |   0   |   1   |   0   |  256 KB       | Upper 1/32
+ *    0   |   0   |   0   |   1   |   1   |  512 KB       | Upper 1/16
+ *    0   |   0   |   1   |   0   |   0   |  1 MB         | Upper 1/8
+ *    0   |   0   |   1   |   0   |   1   |  2 MB         | Upper 1/4
+ *    0   |   0   |   1   |   1   |   0   |  4 MB         | Upper 1/2
+ *    X   |   X   |   1   |   1   |   1   |  8 MB         | ALL
+ *
+ * Returns negative on errors, 0 on success.
+ */
+static int stm_lock(struct udevice *dev, loff_t ofs, uint64_t len)
+{
+	struct mtd_info *mtd = dev_get_uclass_platdata(dev);
+	int devnum = mtd->devnum;
+	struct spi_nor *nor;
+	u8 status_old, status_new;
+	u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
+	u8 shift = ffs(mask) - 1, pow, val;
+
+	nor = find_spi_nor_device(devnum);
+	if (!nor)
+		return -ENODEV;
+
+	status_old = read_sr(nor->dev);
+	if (status_old < 0)
+		return status_old;
+
+	/* SPI NOR always locks to the end */
+	if (ofs + len != mtd->size) {
+		/* Does combined region extend to end? */
+		if (!stm_is_locked_sr(mtd, ofs + len, mtd->size - ofs - len,
+				      status_old))
+			return -EINVAL;
+		len = mtd->size - ofs;
+	}
+
+	/*
+	 * Need smallest pow such that:
+	 *
+	 *   1 / (2^pow) <= (len / size)
+	 *
+	 * so (assuming power-of-2 size) we do:
+	 *
+	 *   pow = ceil(log2(size / len)) = log2(size) - floor(log2(len))
+	 */
+	pow = ilog2(mtd->size) - ilog2(len);
+	val = mask - (pow << shift);
+	if (val & ~mask)
+		return -EINVAL;
+
+	/* Don't "lock" with no region! */
+	if (!(val & mask))
+		return -EINVAL;
+
+	status_new = (status_old & ~mask) | val;
+
+	/* Only modify protection if it will not unlock other areas */
+	if ((status_new & mask) <= (status_old & mask))
+		return -EINVAL;
+
+	write_sr(nor->dev, status_new);
+
+	return 0;
+}
+
+/*
+ * Unlock a region of the flash. See stm_lock() for more info
+ *
+ * Returns negative on errors, 0 on success.
+ */
+static int stm_unlock(struct udevice *dev, loff_t ofs, uint64_t len)
+{
+	struct mtd_info *mtd = dev_get_uclass_platdata(dev);
+	int devnum = mtd->devnum;
+	struct spi_nor *nor;
+	uint8_t status_old, status_new;
+	u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
+	u8 shift = ffs(mask) - 1, pow, val;
+
+	nor = find_spi_nor_device(devnum);
+	if (!nor)
+		return -ENODEV;
+
+	status_old = read_sr(nor->dev);
+	if (status_old < 0)
+		return status_old;
+
+	/* Cannot unlock; would unlock larger region than requested */
+	if (stm_is_locked_sr(mtd, ofs - mtd->erasesize, mtd->erasesize,
+			     status_old))
+		return -EINVAL;
+	/*
+	 * Need largest pow such that:
+	 *
+	 *   1 / (2^pow) >= (len / size)
+	 *
+	 * so (assuming power-of-2 size) we do:
+	 *
+	 *   pow = floor(log2(size / len)) = log2(size) - ceil(log2(len))
+	 */
+	pow = ilog2(mtd->size) - order_base_2(mtd->size - (ofs + len));
+	if (ofs + len == mtd->size) {
+		val = 0; /* fully unlocked */
+	} else {
+		val = mask - (pow << shift);
+		/* Some power-of-two sizes are not supported */
+		if (val & ~mask)
+			return -EINVAL;
+	}
+
+	status_new = (status_old & ~mask) | val;
+
+	/* Only modify protection if it will not lock other areas */
+	if ((status_new & mask) >= (status_old & mask))
+		return -EINVAL;
+
+	write_sr(nor->dev, status_new);
+
+	return 0;
+}
+#endif
+
 #ifdef CONFIG_SPI_NOR_MACRONIX
 static int macronix_quad_enable(struct udevice *dev)
 {
@@ -598,6 +807,15 @@ int spi_nor_scan(struct spi_nor *nor)
 	}
 #endif
 
+#if defined(CONFIG_SPI_NOR_STMICRO) || defined(CONFIG_SPI_NOR_SST)
+	/* NOR protection support for STmicro/Micron chips and similar */
+	if (JEDEC_MFR(info) == SNOR_MFR_MICRON ||
+	    JEDEC_MFR(info) == SNOR_MFR_SST) {
+		ops->lock = stm_lock;
+		ops->unlock = stm_unlock;
+		ops->is_locked = stm_is_locked;
+	}
+#endif
 	/* compute the flash size */
 	nor->page_size = info->page_size;
 	/*
diff --git a/include/mtd.h b/include/mtd.h
index 273b3a6..acb2256 100644
--- a/include/mtd.h
+++ b/include/mtd.h
@@ -26,6 +26,9 @@ struct mtd_ops {
 		     size_t *retlen, u_char *buf);
 	int (*write)(struct udevice *dev, loff_t to, size_t len,
 		      size_t *retlen, const u_char *buf);
+	int (*lock) (struct udevice *dev, loff_t ofs, uint64_t len);
+	int (*unlock) (struct udevice *dev, loff_t ofs, uint64_t len);
+	int (*is_locked) (struct udevice *dev, loff_t ofs, uint64_t len);
 };
 
 /* Access the serial operations for a device */
-- 
2.7.4

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

* [U-Boot] [PATCH v10 06/27] mtd: spi-nor: Kconfig: Add MTD_SPI_NOR entry
  2017-12-28  6:12 [U-Boot] [PATCH v10 00/27] dm: Generic MTD Subsystem, with SPI-NOR interface Jagan Teki
                   ` (4 preceding siblings ...)
  2017-12-28  6:12 ` [U-Boot] [PATCH v10 05/27] mtd: spi-nor: sync/modify lock operations Jagan Teki
@ 2017-12-28  6:12 ` Jagan Teki
  2017-12-28  6:12 ` [U-Boot] [PATCH v10 07/27] mtd: spi-nor: Kconfig: Add MTD_SPI_NOR_USE_4K_SECTORS Jagan Teki
                   ` (22 subsequent siblings)
  28 siblings, 0 replies; 55+ messages in thread
From: Jagan Teki @ 2017-12-28  6:12 UTC (permalink / raw)
  To: u-boot

Added CONFIG_MTD_SPI_NOR kconfig entry

Reviewed-by: Simon Glass <sjg@chromium.org>
Signed-off-by: Jagan Teki <jagan@amarulasolutions.com>
---
 drivers/mtd/Kconfig          |  2 ++
 drivers/mtd/spi-nor/Kconfig  | 14 ++++++++++++++
 drivers/mtd/spi-nor/Makefile |  2 ++
 3 files changed, 18 insertions(+)
 create mode 100644 drivers/mtd/spi-nor/Kconfig

diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig
index 1957980..1d5a248 100644
--- a/drivers/mtd/Kconfig
+++ b/drivers/mtd/Kconfig
@@ -46,4 +46,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.
diff --git a/drivers/mtd/spi-nor/Makefile b/drivers/mtd/spi-nor/Makefile
index c1212a8..661f2f6 100644
--- a/drivers/mtd/spi-nor/Makefile
+++ b/drivers/mtd/spi-nor/Makefile
@@ -4,4 +4,6 @@
 # SPDX-License-Identifier:	GPL-2.0+
 
 ## spi-nor core
+ifdef CONFIG_MTD_SPI_NOR
 obj-y	+= spi-nor.o spi-nor-uclass.o spi-nor-ids.o
+endif
-- 
2.7.4

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

* [U-Boot] [PATCH v10 07/27] mtd: spi-nor: Kconfig: Add MTD_SPI_NOR_USE_4K_SECTORS
  2017-12-28  6:12 [U-Boot] [PATCH v10 00/27] dm: Generic MTD Subsystem, with SPI-NOR interface Jagan Teki
                   ` (5 preceding siblings ...)
  2017-12-28  6:12 ` [U-Boot] [PATCH v10 06/27] mtd: spi-nor: Kconfig: Add MTD_SPI_NOR entry Jagan Teki
@ 2017-12-28  6:12 ` Jagan Teki
  2017-12-28  6:12 ` [U-Boot] [PATCH v10 08/27] mtd: spi-nor: Kconfig: Add SPI_NOR_MISC entry Jagan Teki
                   ` (21 subsequent siblings)
  28 siblings, 0 replies; 55+ messages in thread
From: Jagan Teki @ 2017-12-28  6:12 UTC (permalink / raw)
  To: u-boot

Added CONFIG_MTD_SPI_NOR_USE_4K_SECTORS kconfig entry

Reviewed-by: Simon Glass <sjg@chromium.org>
Signed-off-by: Jagan Teki <jagan@amarulasolutions.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] 55+ messages in thread

* [U-Boot] [PATCH v10 08/27] mtd: spi-nor: Kconfig: Add SPI_NOR_MISC entry
  2017-12-28  6:12 [U-Boot] [PATCH v10 00/27] dm: Generic MTD Subsystem, with SPI-NOR interface Jagan Teki
                   ` (6 preceding siblings ...)
  2017-12-28  6:12 ` [U-Boot] [PATCH v10 07/27] mtd: spi-nor: Kconfig: Add MTD_SPI_NOR_USE_4K_SECTORS Jagan Teki
@ 2017-12-28  6:12 ` Jagan Teki
  2017-12-28  6:12 ` [U-Boot] [PATCH v10 09/27] mtd: spi-nor: Kconfig: Add SPI_NOR_MACRONIX entry Jagan Teki
                   ` (20 subsequent siblings)
  28 siblings, 0 replies; 55+ messages in thread
From: Jagan Teki @ 2017-12-28  6:12 UTC (permalink / raw)
  To: u-boot

Added CONFIG_SPI_NOR_MISC kconfig entry

Reviewed-by: Simon Glass <sjg@chromium.org>
Signed-off-by: Jagan Teki <jagan@amarulasolutions.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] 55+ messages in thread

* [U-Boot] [PATCH v10 09/27] mtd: spi-nor: Kconfig: Add SPI_NOR_MACRONIX entry
  2017-12-28  6:12 [U-Boot] [PATCH v10 00/27] dm: Generic MTD Subsystem, with SPI-NOR interface Jagan Teki
                   ` (7 preceding siblings ...)
  2017-12-28  6:12 ` [U-Boot] [PATCH v10 08/27] mtd: spi-nor: Kconfig: Add SPI_NOR_MISC entry Jagan Teki
@ 2017-12-28  6:12 ` Jagan Teki
  2017-12-28  6:12 ` [U-Boot] [PATCH v10 10/27] mtd: spi-nor: Kconfig: Add SPI_NOR_SPANSION entry Jagan Teki
                   ` (19 subsequent siblings)
  28 siblings, 0 replies; 55+ messages in thread
From: Jagan Teki @ 2017-12-28  6:12 UTC (permalink / raw)
  To: u-boot

Added CONFIG_SPI_NOR_MACRONIX kconfig entry

Reviewed-by: Simon Glass <sjg@chromium.org>
Signed-off-by: Jagan Teki <jagan@amarulasolutions.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] 55+ messages in thread

* [U-Boot] [PATCH v10 10/27] mtd: spi-nor: Kconfig: Add SPI_NOR_SPANSION entry
  2017-12-28  6:12 [U-Boot] [PATCH v10 00/27] dm: Generic MTD Subsystem, with SPI-NOR interface Jagan Teki
                   ` (8 preceding siblings ...)
  2017-12-28  6:12 ` [U-Boot] [PATCH v10 09/27] mtd: spi-nor: Kconfig: Add SPI_NOR_MACRONIX entry Jagan Teki
@ 2017-12-28  6:12 ` Jagan Teki
  2017-12-28  6:12 ` [U-Boot] [PATCH v10 11/27] mtd: spi-nor: Kconfig: Add SPI_NOR_STMICRO entry Jagan Teki
                   ` (18 subsequent siblings)
  28 siblings, 0 replies; 55+ messages in thread
From: Jagan Teki @ 2017-12-28  6:12 UTC (permalink / raw)
  To: u-boot

Added CONFIG_SPI_NOR_SPANSION kconfig entry

Reviewed-by: Simon Glass <sjg@chromium.org>
Signed-off-by: Jagan Teki <jagan@amarulasolutions.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] 55+ messages in thread

* [U-Boot] [PATCH v10 11/27] mtd: spi-nor: Kconfig: Add SPI_NOR_STMICRO entry
  2017-12-28  6:12 [U-Boot] [PATCH v10 00/27] dm: Generic MTD Subsystem, with SPI-NOR interface Jagan Teki
                   ` (9 preceding siblings ...)
  2017-12-28  6:12 ` [U-Boot] [PATCH v10 10/27] mtd: spi-nor: Kconfig: Add SPI_NOR_SPANSION entry Jagan Teki
@ 2017-12-28  6:12 ` Jagan Teki
  2017-12-28  6:12 ` [U-Boot] [PATCH v10 12/27] mtd: spi-nor: Kconfig: Add SPI_NOR_SST entry Jagan Teki
                   ` (17 subsequent siblings)
  28 siblings, 0 replies; 55+ messages in thread
From: Jagan Teki @ 2017-12-28  6:12 UTC (permalink / raw)
  To: u-boot

Added CONFIG_SPI_NOR_STMICRO kconfig entry

Reviewed-by: Simon Glass <sjg@chromium.org>
Signed-off-by: Jagan Teki <jagan@amarulasolutions.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] 55+ messages in thread

* [U-Boot] [PATCH v10 12/27] mtd: spi-nor: Kconfig: Add SPI_NOR_SST entry
  2017-12-28  6:12 [U-Boot] [PATCH v10 00/27] dm: Generic MTD Subsystem, with SPI-NOR interface Jagan Teki
                   ` (10 preceding siblings ...)
  2017-12-28  6:12 ` [U-Boot] [PATCH v10 11/27] mtd: spi-nor: Kconfig: Add SPI_NOR_STMICRO entry Jagan Teki
@ 2017-12-28  6:12 ` Jagan Teki
  2017-12-28  6:12 ` [U-Boot] [PATCH v10 13/27] mtd: spi-nor: Kconfig: Add SPI_NOR_WINBOND entry Jagan Teki
                   ` (16 subsequent siblings)
  28 siblings, 0 replies; 55+ messages in thread
From: Jagan Teki @ 2017-12-28  6:12 UTC (permalink / raw)
  To: u-boot

Added CONFIG_SPI_NOR_SST kconfig entry

Reviewed-by: Simon Glass <sjg@chromium.org>
Signed-off-by: Jagan Teki <jagan@amarulasolutions.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] 55+ messages in thread

* [U-Boot] [PATCH v10 13/27] mtd: spi-nor: Kconfig: Add SPI_NOR_WINBOND entry
  2017-12-28  6:12 [U-Boot] [PATCH v10 00/27] dm: Generic MTD Subsystem, with SPI-NOR interface Jagan Teki
                   ` (11 preceding siblings ...)
  2017-12-28  6:12 ` [U-Boot] [PATCH v10 12/27] mtd: spi-nor: Kconfig: Add SPI_NOR_SST entry Jagan Teki
@ 2017-12-28  6:12 ` Jagan Teki
  2017-12-28  6:12 ` [U-Boot] [PATCH v10 14/27] mtd-uclass: use platdata_auto_alloc Jagan Teki
                   ` (15 subsequent siblings)
  28 siblings, 0 replies; 55+ messages in thread
From: Jagan Teki @ 2017-12-28  6:12 UTC (permalink / raw)
  To: u-boot

Added CONFIG_SPI_NOR_WINBOND kconfig entry

Reviewed-by: Simon Glass <sjg@chromium.org>
Signed-off-by: Jagan Teki <jagan@amarulasolutions.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] 55+ messages in thread

* [U-Boot] [PATCH v10 14/27] mtd-uclass: use platdata_auto_alloc
  2017-12-28  6:12 [U-Boot] [PATCH v10 00/27] dm: Generic MTD Subsystem, with SPI-NOR interface Jagan Teki
                   ` (12 preceding siblings ...)
  2017-12-28  6:12 ` [U-Boot] [PATCH v10 13/27] mtd: spi-nor: Kconfig: Add SPI_NOR_WINBOND entry Jagan Teki
@ 2017-12-28  6:12 ` Jagan Teki
  2017-12-28  6:12 ` [U-Boot] [PATCH v10 15/27] spi: Add spi_write_then_read Jagan Teki
                   ` (14 subsequent siblings)
  28 siblings, 0 replies; 55+ messages in thread
From: Jagan Teki @ 2017-12-28  6:12 UTC (permalink / raw)
  To: u-boot

Now, mtd uclass can hold platdata for underlying
interface uclass drivers so use platdata_auto_alloc
and access via dev->uclass_platdata.

Signed-off-by: Suneel Garapati <suneelglinux@gmail.com>
Signed-off-by: Jagan Teki <jagan@amarulasolutions.com>
---
 drivers/mtd/mtd-uclass.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/mtd/mtd-uclass.c b/drivers/mtd/mtd-uclass.c
index c94afe9..d9ecfea 100644
--- a/drivers/mtd/mtd-uclass.c
+++ b/drivers/mtd/mtd-uclass.c
@@ -199,5 +199,5 @@ int mtd_create_devicef(struct udevice *parent, const char *drv_name,
 UCLASS_DRIVER(mtd) = {
 	.id		= UCLASS_MTD,
 	.name		= "mtd",
-	.per_device_auto_alloc_size = sizeof(struct mtd_info),
+	.per_device_platdata_auto_alloc_size = sizeof(struct mtd_info),
 };
-- 
2.7.4

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

* [U-Boot] [PATCH v10 15/27] spi: Add spi_write_then_read
  2017-12-28  6:12 [U-Boot] [PATCH v10 00/27] dm: Generic MTD Subsystem, with SPI-NOR interface Jagan Teki
                   ` (13 preceding siblings ...)
  2017-12-28  6:12 ` [U-Boot] [PATCH v10 14/27] mtd-uclass: use platdata_auto_alloc Jagan Teki
@ 2017-12-28  6:12 ` Jagan Teki
  2017-12-28  6:12 ` [U-Boot] [PATCH v10 16/27] mtd: spi-nor: Add m25p80 driver Jagan Teki
                   ` (13 subsequent siblings)
  28 siblings, 0 replies; 55+ messages in thread
From: Jagan Teki @ 2017-12-28  6:12 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.

Reviewed-by: Simon Glass <sjg@chromium.org>
Signed-off-by: Jagan Teki <jagan@amarulasolutions.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 e06a603..b86c15b 100644
--- a/drivers/spi/spi-uclass.c
+++ b/drivers/spi/spi-uclass.c
@@ -107,6 +107,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;
+}
+
 #if !CONFIG_IS_ENABLED(OF_PLATDATA)
 static int spi_child_post_bind(struct udevice *dev)
 {
diff --git a/include/spi.h b/include/spi.h
index 8c4b882..c67ca23 100644
--- a/include/spi.h
+++ b/include/spi.h
@@ -252,6 +252,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] 55+ messages in thread

* [U-Boot] [PATCH v10 16/27] mtd: spi-nor: Add m25p80 driver
  2017-12-28  6:12 [U-Boot] [PATCH v10 00/27] dm: Generic MTD Subsystem, with SPI-NOR interface Jagan Teki
                   ` (14 preceding siblings ...)
  2017-12-28  6:12 ` [U-Boot] [PATCH v10 15/27] spi: Add spi_write_then_read Jagan Teki
@ 2017-12-28  6:12 ` Jagan Teki
  2017-12-28  6:12 ` [U-Boot] [PATCH v10 17/27] mtd: spi-nor: Kconfig: Add MTD_M25P80 entry Jagan Teki
                   ` (12 subsequent siblings)
  28 siblings, 0 replies; 55+ messages in thread
From: Jagan Teki @ 2017-12-28  6:12 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: Suneel Garapati <suneelglinux@gmail.com>
Signed-off-by: Jagan Teki <jagan@amarulasolutions.com>
---
 drivers/mtd/spi-nor/Makefile |   3 +
 drivers/mtd/spi-nor/m25p80.c | 250 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 253 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 661f2f6..d578be0 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-uclass.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..5465921
--- /dev/null
+++ b/drivers/mtd/spi-nor/m25p80.c
@@ -0,0 +1,250 @@
+/*
+ * 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_platdata {
+	struct spi_nor		spi_nor;
+};
+
+struct m25p_priv {
+	struct spi_slave	*spi;
+	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 m25p_read_reg(struct udevice *dev, u8 opcode, u8 *val, int len)
+{
+	struct m25p_priv *priv = dev_get_priv(dev);
+	struct spi_slave *spi = priv->spi;
+	int ret;
+
+	ret = spi_claim_bus(spi);
+	if (ret) {
+		debug("m25p: failed to claim SPI bus: %d\n", ret);
+		return ret;
+	}
+
+	ret = spi_write_then_read(spi, &opcode, 1, NULL, val, len);
+	if (ret < 0) {
+		debug("m25p: error %d reading register %x\n", ret, opcode);
+		return ret;
+	}
+
+	spi_release_bus(spi);
+	return ret;
+}
+
+static int m25p_write_reg(struct udevice *dev, u8 opcode, u8 *buf, int len)
+{
+	struct m25p_priv *priv = dev_get_priv(dev);
+	struct spi_slave *spi = priv->spi;
+	int ret;
+
+	ret = spi_claim_bus(spi);
+	if (ret) {
+		debug("m25p: failed to claim SPI bus: %d\n", ret);
+		return ret;
+	}
+
+	ret = spi_write_then_read(spi, &opcode, 1, buf, NULL, len);
+	if (ret < 0) {
+		debug("m25p: error %d writing register %x\n", ret, opcode);
+		return ret;
+	}
+
+	spi_release_bus(spi);
+	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 m25p_read(struct udevice *dev, loff_t from, size_t len,
+		       u_char *buf)
+{
+	struct m25p_priv *priv = dev_get_priv(dev);
+	struct spi_slave *spi = priv->spi;
+	struct spi_nor *nor = spi_nor_get_spi_nor_dev(dev);
+	unsigned int dummy;
+	int ret;
+
+	ret = spi_claim_bus(spi);
+	if (ret) {
+		debug("m25p: failed to claim SPI bus: %d\n", ret);
+		return 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 = nor->read_dummy;
+	dummy /= 8;
+
+	priv->command[0] = nor->read_opcode;
+	m25p_addr2cmd(nor, from, priv->command);
+
+	debug("m25p: (read) %2x %2x %2x %2x %2x (%llx)\n",
+	      priv->command[0], priv->command[1], priv->command[2],
+	      priv->command[3], priv->command[4], from);
+	ret = spi_write_then_read(spi, priv->command, m25p_cmdsz(nor) + dummy,
+				  NULL, buf, len);
+	if (ret < 0) {
+		debug("m25p: error %d reading %x\n", ret, priv->command[0]);
+		return ret;
+	}
+
+	spi_release_bus(spi);
+	return ret;
+}
+
+static int m25p_write(struct udevice *dev, loff_t to, size_t len,
+			const u_char *buf)
+{
+	struct m25p_priv *priv = dev_get_priv(dev);
+	struct spi_slave *spi = priv->spi;
+	struct spi_nor *nor = spi_nor_get_spi_nor_dev(dev);
+	int cmd_sz, ret;
+
+	ret = spi_claim_bus(spi);
+	if (ret) {
+		debug("m25p: failed to claim SPI bus: %d\n", ret);
+		return ret;
+	}
+
+	cmd_sz = m25p_cmdsz(nor);
+	if ((nor->program_opcode == SNOR_OP_AAI_WP) && (buf != NULL))
+		cmd_sz = 1;
+
+	priv->command[0] = nor->program_opcode;
+	if (buf == NULL)
+		priv->command[0] = nor->erase_opcode;
+	m25p_addr2cmd(nor, to, priv->command);
+
+	debug("m25p: (%s) %2x %2x %2x %2x %2x (%llx)\n",
+	      (buf == NULL) ? "erase" : "write", priv->command[0],
+	      priv->command[1], priv->command[2], priv->command[3],
+	      priv->command[4], to);
+	ret = spi_write_then_read(spi, priv->command, cmd_sz, buf, NULL, len);
+	if (ret < 0) {
+		debug("m25p: error %d writing %x\n", ret, priv->command[0]);
+		return ret;
+	}
+
+	spi_release_bus(spi);
+	return ret;
+}
+
+const struct spi_nor_ops m25p_ops = {
+	.read		= m25p_read,
+	.write		= m25p_write,
+	.read_reg	= m25p_read_reg,
+	.write_reg	= m25p_write_reg,
+};
+
+static int m25p_probe(struct udevice *dev)
+{
+	struct m25p_platdata *plat = dev_get_platdata(dev);
+	struct m25p_priv *priv = dev_get_priv(dev);
+	struct spi_nor_uclass_priv *upriv = dev_get_uclass_priv(dev);
+	struct spi_slave *spi = dev_get_parent_priv(dev);
+	int ret;
+
+	ret = spi_claim_bus(spi);
+	if (ret) {
+		debug("m25p: failed to claim SPI bus: %d\n", ret);
+		return ret;
+	}
+
+	if (spi->mode & SPI_RX_SLOW)
+		plat->spi_nor.mode = SNOR_READ;
+	else if (spi->mode & SPI_RX_DUAL)
+		plat->spi_nor.mode = SNOR_READ_1_1_2;
+	else if (spi->mode & SPI_RX_QUAD)
+		plat->spi_nor.mode = SNOR_READ_1_1_4;
+
+	if (spi->mode & SPI_TX_BYTE)
+		plat->spi_nor.mode |= SNOR_WRITE_1_1_BYTE;
+	else if (spi->mode & SPI_TX_QUAD)
+		plat->spi_nor.mode |= SNOR_WRITE_1_1_4;
+
+	plat->spi_nor.memory_map = spi->memory_map;
+	plat->spi_nor.max_write_size = spi->max_write_size;
+
+	priv->spi = spi;
+	upriv->spi_nor = &plat->spi_nor;
+
+	return 0;
+}
+
+static int m25p_bind(struct udevice *dev)
+{
+	struct m25p_platdata *plat = dev_get_platdata(dev);
+
+	return spi_nor_bind(dev, &plat->spi_nor);
+}
+
+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(m25p) = {
+	.name		= "m25p",
+	.id		= UCLASS_SPI_NOR,
+	.of_match	= m25p_ids,
+	.ops		= &m25p_ops,
+	.bind		= m25p_bind,
+	.probe		= m25p_probe,
+	.priv_auto_alloc_size = sizeof(struct m25p_priv),
+	.platdata_auto_alloc_size = sizeof(struct m25p_platdata),
+};
-- 
2.7.4

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

* [U-Boot] [PATCH v10 17/27] mtd: spi-nor: Kconfig: Add MTD_M25P80 entry
  2017-12-28  6:12 [U-Boot] [PATCH v10 00/27] dm: Generic MTD Subsystem, with SPI-NOR interface Jagan Teki
                   ` (15 preceding siblings ...)
  2017-12-28  6:12 ` [U-Boot] [PATCH v10 16/27] mtd: spi-nor: Add m25p80 driver Jagan Teki
@ 2017-12-28  6:12 ` Jagan Teki
  2017-12-28  6:12 ` [U-Boot] [PATCH v10 18/27] mtd: spi-nor: Add zynq qspinor driver Jagan Teki
                   ` (11 subsequent siblings)
  28 siblings, 0 replies; 55+ messages in thread
From: Jagan Teki @ 2017-12-28  6:12 UTC (permalink / raw)
  To: u-boot

Add CONFIG_MTD_M25P80 kconfig entry

Reviewed-by: Simon Glass <sjg@chromium.org>
Signed-off-by: Jagan Teki <jagan@amarulasolutions.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] 55+ messages in thread

* [U-Boot] [PATCH v10 18/27] mtd: spi-nor: Add zynq qspinor driver
  2017-12-28  6:12 [U-Boot] [PATCH v10 00/27] dm: Generic MTD Subsystem, with SPI-NOR interface Jagan Teki
                   ` (16 preceding siblings ...)
  2017-12-28  6:12 ` [U-Boot] [PATCH v10 17/27] mtd: spi-nor: Kconfig: Add MTD_M25P80 entry Jagan Teki
@ 2017-12-28  6:12 ` Jagan Teki
  2017-12-28  6:12 ` [U-Boot] [PATCH v10 19/27] mtd: spi-nor: zynq_qspi: Kconfig: Add MTD_ZYNQ Jagan Teki
                   ` (10 subsequent siblings)
  28 siblings, 0 replies; 55+ messages in thread
From: Jagan Teki @ 2017-12-28  6:12 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@amarulasolutions.com>
---
 drivers/mtd/spi-nor/Makefile       |   3 +
 drivers/mtd/spi-nor/zynq_qspinor.c | 622 +++++++++++++++++++++++++++++++++++++
 2 files changed, 625 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 d578be0..ded3bfa 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..278168b
--- /dev/null
+++ b/drivers/mtd/spi-nor/zynq_qspinor.c
@@ -0,0 +1,622 @@
+/*
+ * (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 spi_nor spi_nor;
+};
+
+/* zynq qspi priv */
+struct zynq_qspinor_priv {
+	struct zynq_qspinor_regs *regs;
+	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 zynq_qspinor_priv *priv, unsigned int bitlen,
+		const void *dout, void *din, unsigned long flags)
+{
+	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 zynq_qspinor_priv *priv,
+				   const u8 *opcode, size_t n_opcode,
+				   const u8 *txbuf, u8 *rxbuf, size_t n_buf)
+{
+	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(priv, 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(priv, 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 udevice *dev, u8 opcode,
+				 u8 *val, int len)
+{
+	struct zynq_qspinor_priv *priv = dev_get_priv(dev);
+
+	return zynq_qspinor_tx_then_rx(priv, &opcode, 1, NULL, val, len);
+}
+
+static int zynq_qspinor_write_reg(struct udevice *dev, u8 opcode,
+				  u8 *buf, int len)
+{
+	struct zynq_qspinor_priv *priv = dev_get_priv(dev);
+
+	return zynq_qspinor_tx_then_rx(priv, &opcode, 1, buf, NULL, len);
+}
+
+static int zynq_qspinor_read(struct udevice *dev, loff_t from,
+			     size_t len, u_char *buf)
+{
+	struct zynq_qspinor_priv *priv = dev_get_priv(dev);
+	unsigned int cmd_sz;
+	struct spi_nor *nor = spi_nor_get_spi_nor_dev(dev);
+
+	priv->cmd[0] = nor->read_opcode;
+	zynq_qspinor_addr(from, priv->cmd);
+	cmd_sz = sizeof(priv->cmd) + (nor->read_dummy / 8);
+
+	debug("zynq_qspinor: (read) %2x %2x %2x %2x (%llx)\n", priv->cmd[0],
+	      priv->cmd[1], priv->cmd[2], priv->cmd[3], from);
+	return zynq_qspinor_tx_then_rx(priv, priv->cmd, cmd_sz, NULL, buf, len);
+}
+
+static int zynq_qspinor_write(struct udevice *dev, loff_t to,
+			      size_t len, const u_char *buf)
+{
+	struct zynq_qspinor_priv *priv = dev_get_priv(dev);
+	struct spi_nor *nor = spi_nor_get_spi_nor_dev(dev);
+
+	priv->cmd[0] = nor->program_opcode;
+	if (buf == NULL)
+		priv->cmd[0] = nor->erase_opcode;
+
+	zynq_qspinor_addr(to, priv->cmd);
+
+	debug("zynq_qspinor: (%s) %2x %2x %2x %2x (%llx)\n",
+	      (buf == NULL) ? "erase" : "write", priv->cmd[0], priv->cmd[1],
+	      priv->cmd[2], priv->cmd[3], to);
+	return zynq_qspinor_tx_then_rx(priv, priv->cmd, sizeof(priv->cmd),
+				       buf, NULL, len);
+}
+
+const struct spi_nor_ops zynq_qspinor_ops = {
+	.read		= zynq_qspinor_read,
+	.write		= zynq_qspinor_write,
+	.read_reg	= zynq_qspinor_read_reg,
+	.write_reg	= zynq_qspinor_write_reg,
+};
+
+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);
+
+	/* clear 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_probe(struct udevice *dev)
+{
+	struct zynq_qspinor_platdata *plat = dev_get_platdata(dev);
+	struct zynq_qspinor_priv *priv = dev_get_priv(dev);
+	struct spi_nor_uclass_priv *upriv = dev_get_uclass_priv(dev);
+
+	priv->regs = (void *)dev_read_addr(dev);
+	priv->fifo_depth = ZYNQ_QSPI_FIFO_DEPTH;
+
+	/* init the zynq spi hw */
+	zynq_qspinor_init_hw(priv);
+
+	upriv->spi_nor = &plat->spi_nor;
+
+	return 0;
+}
+
+static int zynq_qspinor_bind(struct udevice *dev)
+{
+	struct zynq_qspinor_platdata *plat = dev_get_platdata(dev);
+
+	return spi_nor_bind(dev, &plat->spi_nor);
+}
+
+static const struct udevice_id zynq_qspinor_ids[] = {
+	{ .compatible = "xlnx,zynq-qspinor-1.0" },
+	{ }
+};
+
+U_BOOT_DRIVER(zynq_qspinor) = {
+	.name   = "zynq_qspinor",
+	.id     = UCLASS_SPI_NOR,
+	.of_match = zynq_qspinor_ids,
+	.ops	= &zynq_qspinor_ops,
+	.bind	= zynq_qspinor_bind,
+	.probe  = zynq_qspinor_probe,
+	.priv_auto_alloc_size = sizeof(struct zynq_qspinor_priv),
+	.platdata_auto_alloc_size = sizeof(struct zynq_qspinor_platdata),
+};
-- 
2.7.4

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

* [U-Boot] [PATCH v10 19/27] mtd: spi-nor: zynq_qspi: Kconfig: Add MTD_ZYNQ
  2017-12-28  6:12 [U-Boot] [PATCH v10 00/27] dm: Generic MTD Subsystem, with SPI-NOR interface Jagan Teki
                   ` (17 preceding siblings ...)
  2017-12-28  6:12 ` [U-Boot] [PATCH v10 18/27] mtd: spi-nor: Add zynq qspinor driver Jagan Teki
@ 2017-12-28  6:12 ` Jagan Teki
  2017-12-28  6:12 ` [U-Boot] [PATCH v10 20/27] mtd: spi-nor: Add 4-byte addresswidth support Jagan Teki
                   ` (9 subsequent siblings)
  28 siblings, 0 replies; 55+ messages in thread
From: Jagan Teki @ 2017-12-28  6:12 UTC (permalink / raw)
  To: u-boot

Add CONFIG_MTD_ZYNQ_QSPI kconfig entry

Signed-off-by: Jagan Teki <jagan@amarulasolutions.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] 55+ messages in thread

* [U-Boot] [PATCH v10 20/27] mtd: spi-nor: Add 4-byte addresswidth support
  2017-12-28  6:12 [U-Boot] [PATCH v10 00/27] dm: Generic MTD Subsystem, with SPI-NOR interface Jagan Teki
                   ` (18 preceding siblings ...)
  2017-12-28  6:12 ` [U-Boot] [PATCH v10 19/27] mtd: spi-nor: zynq_qspi: Kconfig: Add MTD_ZYNQ Jagan Teki
@ 2017-12-28  6:12 ` Jagan Teki
  2017-12-28  8:06   ` Cyrille Pitchen
  2017-12-28  6:12 ` [U-Boot] [PATCH v10 21/27] cmd: add spinor cmd support Jagan Teki
                   ` (8 subsequent siblings)
  28 siblings, 1 reply; 55+ messages in thread
From: Jagan Teki @ 2017-12-28  6:12 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@amarulasolutions.com>
---
 drivers/mtd/spi-nor/m25p80.c  |  1 +
 drivers/mtd/spi-nor/spi-nor.c | 38 ++++++++++++++++++++++++++++++++++++++
 include/linux/mtd/spi-nor.h   |  6 +++++-
 3 files changed, 44 insertions(+), 1 deletion(-)

diff --git a/drivers/mtd/spi-nor/m25p80.c b/drivers/mtd/spi-nor/m25p80.c
index 5465921..7af6f59 100644
--- a/drivers/mtd/spi-nor/m25p80.c
+++ b/drivers/mtd/spi-nor/m25p80.c
@@ -35,6 +35,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 8bf9e67..e0085cf 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -632,6 +632,38 @@ static int stm_unlock(struct udevice *dev, loff_t ofs, uint64_t len)
 }
 #endif
 
+/* Enable/disable 4-byte addressing mode. */
+static int set_4byte(struct udevice *dev, const struct spi_nor_info *info,
+		     int enable)
+{
+	struct spi_nor *nor = spi_nor_get_spi_nor_dev(dev);
+	const struct spi_nor_ops *ops = spi_nor_get_ops(dev);
+	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(dev);
+
+		cmd = enable ? SNOR_OP_EN4B : SNOR_OP_EX4B;
+		status = ops->write_reg(dev, cmd, NULL, 0);
+		if (need_wren)
+			write_disable(dev);
+
+		return status;
+	default:
+		/* Spansion style */
+		nor->cmd_buf[0] = enable << 7;
+		return ops->write_reg(dev, SNOR_OP_BRWR, nor->cmd_buf, 1);
+	}
+}
+
 #ifdef CONFIG_SPI_NOR_MACRONIX
 static int macronix_quad_enable(struct udevice *dev)
 {
@@ -873,6 +905,12 @@ int spi_nor_scan(struct spi_nor *nor)
 	}
 
 	nor->addr_width = 3;
+	if (mtd->size > SNOR_16MB_BOUN) {
+		nor->addr_width = 4;
+		ret = set_4byte(nor->dev, info, true);
+		if (ret)
+			goto err;
+	}
 
 	/* 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 e1688e2..fc4a649 100644
--- a/include/linux/mtd/spi-nor.h
+++ b/include/linux/mtd/spi-nor.h
@@ -63,6 +63,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 */
@@ -84,7 +88,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
 
 /**
-- 
2.7.4

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

* [U-Boot] [PATCH v10 21/27] cmd: add spinor cmd support
  2017-12-28  6:12 [U-Boot] [PATCH v10 00/27] dm: Generic MTD Subsystem, with SPI-NOR interface Jagan Teki
                   ` (19 preceding siblings ...)
  2017-12-28  6:12 ` [U-Boot] [PATCH v10 20/27] mtd: spi-nor: Add 4-byte addresswidth support Jagan Teki
@ 2017-12-28  6:12 ` Jagan Teki
  2017-12-28  6:12 ` [U-Boot] [PATCH v10 22/27] cmd: spinor: sync/update protect command Jagan Teki
                   ` (7 subsequent siblings)
  28 siblings, 0 replies; 55+ messages in thread
From: Jagan Teki @ 2017-12-28  6:12 UTC (permalink / raw)
  To: u-boot

Now, spi-nor framework is up so access spi-nor device
from command prompt via 'spinor'

Signed-off-by: Suneel Garapati <suneelglinux@gmail.com>
Signed-off-by: Jagan Teki <jagan@amarulasolutions.com>
---
 cmd/Kconfig                 |   5 +
 cmd/Makefile                |   1 +
 cmd/spinor.c                | 281 ++++++++++++++++++++++++++++++++++++++++++++
 drivers/mtd/Makefile        |   7 +-
 include/linux/mtd/spi-nor.h |   1 +
 5 files changed, 293 insertions(+), 2 deletions(-)
 create mode 100644 cmd/spinor.c

diff --git a/cmd/Kconfig b/cmd/Kconfig
index c033223..130c226 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -870,6 +870,11 @@ config CMD_SDRAM
 	  SDRAM has an EEPROM with information that can be read using the
 	  I2C bus. This is only available on some boards.
 
+config CMD_SPINOR
+	bool "spinor"
+	help
+	  SPI NOR Flash support
+
 config CMD_SF
 	bool "sf"
 	help
diff --git a/cmd/Makefile b/cmd/Makefile
index 00e3869..81ab932 100644
--- a/cmd/Makefile
+++ b/cmd/Makefile
@@ -108,6 +108,7 @@ obj-$(CONFIG_CMD_REMOTEPROC) += remoteproc.o
 obj-$(CONFIG_SANDBOX) += host.o
 obj-$(CONFIG_CMD_SATA) += sata.o
 obj-$(CONFIG_CMD_NVME) += nvme.o
+obj-$(CONFIG_CMD_SPINOR) += spinor.o
 obj-$(CONFIG_CMD_SF) += sf.o
 obj-$(CONFIG_CMD_SCSI) += scsi.o disk.o
 obj-$(CONFIG_CMD_SHA1SUM) += sha1sum.o
diff --git a/cmd/spinor.c b/cmd/spinor.c
new file mode 100644
index 0000000..b781151
--- /dev/null
+++ b/cmd/spinor.c
@@ -0,0 +1,281 @@
+/*
+ * Command for accessing SPI-NOR 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 <linux/mtd/mtd.h>
+#include <linux/mtd/spi-nor.h>
+
+#include <asm/io.h>
+#include <jffs2/jffs2.h>
+
+static int curr_device = 0;
+
+static int do_spinor_list(void)
+{
+	print_spi_nor_devices('\n');
+	return CMD_RET_SUCCESS;
+}
+
+static struct spi_nor *init_spinor_device(int dev, bool force_init)
+{
+	struct spi_nor *nor;
+
+	nor = find_spi_nor_device(dev);
+	if (!nor) {
+		printf("No SPI-NOR device found! %x\n", dev);
+		return NULL;
+	}
+
+	if (force_init)
+		nor->init_done = 0;
+	if (spi_nor_scan(nor))
+		return NULL;
+
+	return nor;
+}
+
+static void print_spinor_info(struct spi_nor *nor)
+{
+	struct mtd_info *mtd = spi_nor_get_mtd_info(nor);
+
+	printf("bus: %s: %d\n", nor->dev->name, mtd->devnum);
+	printf("device: %s\n", mtd->name);
+	printf("page size: %d B\nerase size: ", mtd->writebufsize);
+	print_size(mtd->erasesize, "\nsize: ");
+	print_size(mtd->size, "");
+	if (nor->memory_map)
+		printf(", mapped at %p", nor->memory_map);
+	printf("\n");
+}
+
+static int do_spinor_info(void)
+{
+	struct spi_nor *nor;
+
+	if (curr_device < 0) {
+		if (get_spi_nor_num() > 0)
+			curr_device = 0;
+		else {
+			puts("No SPI-NOR device available\n");
+			return 1;
+		}
+	}
+
+	nor = init_spinor_device(curr_device, false);
+	if (!nor)
+		return CMD_RET_FAILURE;
+
+	print_spinor_info(nor);
+	return CMD_RET_SUCCESS;
+}
+
+static int do_spinor_dev(int argc, char * const argv[])
+{
+	struct spi_nor *nor;
+	int devnum = 0;
+	int ret;
+
+	if (argc == 2)
+		devnum = curr_device;
+	else if (argc == 3)
+		devnum = simple_strtoul(argv[2], NULL, 10);
+
+	nor = init_spinor_device(devnum, true);
+	if (!nor)
+		return CMD_RET_FAILURE;
+
+	ret = mtd_select_devnum(MTD_IF_TYPE_SPI_NOR, devnum);
+	printf("switch to dev #%d, %s\n", devnum, (!ret) ? "OK" : "ERROR");
+	if (ret)
+		return CMD_RET_FAILURE;
+
+	curr_device = devnum;
+	printf("spinor%d is current device\n", curr_device);
+
+	return CMD_RET_SUCCESS;
+}
+
+static int do_spinor_write_read(int argc, char * const argv[])
+{
+	struct mtd_info *mtd;
+	struct spi_nor *nor;
+	loff_t offset, addr, len, maxsize;
+	u_char *buf;
+	char *endp;
+	int idx = 0;
+	int ret = CMD_RET_FAILURE;
+
+	if (argc != 4)
+		return CMD_RET_USAGE;
+
+	nor = init_spinor_device(curr_device, false);
+	if (!nor)
+		return CMD_RET_FAILURE;
+
+	addr = simple_strtoul(argv[1], &endp, 16);
+	if (*argv[1] == 0 || *endp != 0)
+		return CMD_RET_FAILURE;
+
+	mtd = spi_nor_get_mtd_info(nor);
+	if (mtd_arg_off_size(argc - 2, &argv[2], &idx, &offset, &len,
+			     &maxsize, MTD_DEV_TYPE_NOR, mtd->size))
+		return CMD_RET_FAILURE;
+
+	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 = mtd_dwrite(mtd, offset, len, (size_t *)&len, buf);
+	else if (strcmp(argv[0], "read") == 0)
+		ret = mtd_dread(mtd, offset, len, (size_t *)&len, buf);
+
+	printf("SPI-NOR: %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 ? CMD_RET_SUCCESS : CMD_RET_FAILURE;
+}
+
+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_spinor_erase(int argc, char * const argv[])
+{
+	struct mtd_info *mtd;
+	struct spi_nor *nor;
+	struct erase_info instr;
+	loff_t addr, len, maxsize;
+	int idx = 0;
+	int ret;
+
+	if (argc != 3)
+		return CMD_RET_USAGE;
+
+	nor = init_spinor_device(curr_device, false);
+	if (!nor)
+		return CMD_RET_FAILURE;
+
+	mtd = spi_nor_get_mtd_info(nor);
+	if (mtd_arg_off(argv[1], &idx, &addr, &len, &maxsize,
+			MTD_DEV_TYPE_NOR, mtd->size))
+		return CMD_RET_FAILURE;
+
+	ret = mtd_parse_len_arg(mtd, argv[2], &len);
+	if (ret != 1)
+		return CMD_RET_FAILURE;
+
+	instr.mtd = mtd;
+	instr.addr = addr;
+	instr.len = len;
+	instr.callback = 0;
+	ret = mtd_derase(mtd, &instr);
+	printf("SPI-NOR: %zu bytes @ %#llx Erased: %s\n", (size_t)len, addr,
+	       ret ? "ERROR" : "OK");
+
+	return ret == 0 ? CMD_RET_SUCCESS : CMD_RET_FAILURE;
+}
+
+static int do_spinor(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_spinor_list();
+		goto done;
+	}
+
+	if (strcmp(cmd, "dev") == 0) {
+		if (argc > 3)
+			goto usage;
+
+		ret = do_spinor_dev(argc, argv);
+		goto done;
+	}
+
+	if (strcmp(cmd, "info") == 0) {
+		if (argc > 2)
+			goto usage;
+
+		ret = do_spinor_info();
+		goto done;
+	}
+
+	if (argc < 3)
+		goto usage;
+
+	--argc;
+	++argv;
+
+	if (strcmp(cmd, "erase") == 0) {
+		ret = do_spinor_erase(argc, argv);
+		goto done;
+	}
+
+	if (strcmp(cmd, "write") == 0 || strcmp(cmd, "read") == 0) {
+		ret = do_spinor_write_read(argc, argv);
+		goto done;
+	}
+
+done:
+	if (ret != -1)
+		return ret;
+
+usage:
+	return CMD_RET_USAGE;
+}
+
+static char spinor_help_text[] =
+	"list			- show list of spinor devices\n"
+	"spinor info			- show current spinor device info\n"
+	"spinor dev [devnum]		- show or set current spinor device\n"
+	"spinor erase offset len         - erase 'len' bytes from 'offset'\n"
+	"spinor write addr to len	- write 'len' bytes to 'to' from 'addr'\n"
+	"spinor read addr from len	- read 'len' bytes from 'from' to 'addr'";
+
+U_BOOT_CMD(
+	spinor, 5, 1, do_spinor,
+	"SPI-NOR Sub-system",
+	spinor_help_text
+);
diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile
index 20c0d0a..c5209ad 100644
--- a/drivers/mtd/Makefile
+++ b/drivers/mtd/Makefile
@@ -5,8 +5,11 @@
 # SPDX-License-Identifier:	GPL-2.0+
 #
 
-ifneq (,$(findstring y,$(CONFIG_MTD_DEVICE)$(CONFIG_CMD_NAND)$(CONFIG_CMD_ONENAND)$(CONFIG_CMD_SF)))
-obj-y += mtdcore.o mtd_uboot.o
+ifneq (,$(findstring y,$(CONFIG_MTD_DEVICE)$(CONFIG_CMD_NAND)$(CONFIG_CMD_ONENAND)$(CONFIG_CMD_SF),$(CONFIG_CMD_SPINOR)))
+obj-y += mtd_uboot.o
+ifndef CONFIG_MTD
+obj-y += mtdcore.o
+endif
 endif
 obj-$(CONFIG_MTD) += mtd-uclass.o
 obj-$(CONFIG_MTD_PARTITIONS) += mtdpart.o
diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
index fc4a649..9c3da70 100644
--- a/include/linux/mtd/spi-nor.h
+++ b/include/linux/mtd/spi-nor.h
@@ -217,5 +217,6 @@ struct spi_nor *find_spi_nor_device(int dev_num);
 int get_spi_nor_num(void);
 struct spi_nor *spi_nor_get_spi_nor_dev(struct udevice *dev);
 struct mtd_info *spi_nor_get_mtd_info(struct spi_nor *nor);
+void print_spi_nor_devices(char separator);
 
 #endif /* __MTD_SPI_NOR_H */
-- 
2.7.4

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

* [U-Boot] [PATCH v10 22/27] cmd: spinor: sync/update protect command
  2017-12-28  6:12 [U-Boot] [PATCH v10 00/27] dm: Generic MTD Subsystem, with SPI-NOR interface Jagan Teki
                   ` (20 preceding siblings ...)
  2017-12-28  6:12 ` [U-Boot] [PATCH v10 21/27] cmd: add spinor cmd support Jagan Teki
@ 2017-12-28  6:12 ` Jagan Teki
  2017-12-28  6:12 ` [U-Boot] [PATCH v10 23/27] board_r: initialize spi_nor Jagan Teki
                   ` (6 subsequent siblings)
  28 siblings, 0 replies; 55+ messages in thread
From: Jagan Teki @ 2017-12-28  6:12 UTC (permalink / raw)
  To: u-boot

sync the protect command from legacy cmd/sf.c and
update them according to current spi-nor framework.

Signed-off-by: Suneel Garapati <suneelglinux@gmail.com>
Signed-off-by: Jagan Teki <jagan@amarulasolutions.com>
---
 cmd/spinor.c             | 47 ++++++++++++++++++++++++++++++++++++++++++++++-
 drivers/mtd/mtd-uclass.c | 19 +++++++++++++++++++
 include/mtd.h            | 11 +++++++++++
 3 files changed, 76 insertions(+), 1 deletion(-)

diff --git a/cmd/spinor.c b/cmd/spinor.c
index b781151..ef8decf 100644
--- a/cmd/spinor.c
+++ b/cmd/spinor.c
@@ -151,6 +151,44 @@ static int do_spinor_write_read(int argc, char * const argv[])
 	return ret == 0 ? CMD_RET_SUCCESS : CMD_RET_FAILURE;
 }
 
+static int do_spinor_protect(int argc, char * const argv[])
+{
+	struct mtd_info *mtd;
+	struct spi_nor *nor;
+	loff_t sector, len, maxsize;
+	char *endp;
+	int idx = 0;
+	bool prot = false;
+	int ret = CMD_RET_FAILURE;
+
+	if (argc != 4)
+		return CMD_RET_USAGE;
+
+	nor = init_spinor_device(curr_device, false);
+	if (!nor)
+		return CMD_RET_FAILURE;
+
+	sector = simple_strtoul(argv[2], &endp, 16);
+	if (*argv[2] == 0 || *endp != 0)
+		return CMD_RET_FAILURE;
+
+	mtd = spi_nor_get_mtd_info(nor);
+	if (mtd_arg_off_size(argc - 3, &argv[3], &idx, &sector, &len,
+			     &maxsize, MTD_DEV_TYPE_NOR, mtd->size))
+		return CMD_RET_FAILURE;
+
+	if (strcmp(argv[1], "lock") == 0)
+		prot = true;
+	else if (strcmp(argv[1], "unlock") == 0)
+		prot = false;
+	else
+		return -1;  /* Unknown parameter */
+
+	ret = mtd_dprotect(mtd, sector, len, prot);
+
+	return ret == 0 ? CMD_RET_SUCCESS : CMD_RET_FAILURE;
+}
+
 static int mtd_parse_len_arg(struct mtd_info *mtd, char *arg, loff_t *len)
 {
 	char *ep;
@@ -258,6 +296,11 @@ static int do_spinor(cmd_tbl_t *cmdtp, int flag, int argc,
 		goto done;
 	}
 
+	if (strcmp(cmd, "protect") == 0) {
+		ret = do_spinor_protect(argc, argv);
+		goto done;
+	}
+
 done:
 	if (ret != -1)
 		return ret;
@@ -272,7 +315,9 @@ static char spinor_help_text[] =
 	"spinor dev [devnum]		- show or set current spinor device\n"
 	"spinor erase offset len         - erase 'len' bytes from 'offset'\n"
 	"spinor write addr to len	- write 'len' bytes to 'to' from 'addr'\n"
-	"spinor read addr from len	- read 'len' bytes from 'from' to 'addr'";
+	"spinor read addr from len	- read 'len' bytes from 'from' to 'addr'\n"
+	"spinor protect lock/unlock sector len - protect/unprotect 'len' bytes starting\n"
+	"				  at address 'sector'";
 
 U_BOOT_CMD(
 	spinor, 5, 1, do_spinor,
diff --git a/drivers/mtd/mtd-uclass.c b/drivers/mtd/mtd-uclass.c
index d9ecfea..535f68e 100644
--- a/drivers/mtd/mtd-uclass.c
+++ b/drivers/mtd/mtd-uclass.c
@@ -73,6 +73,25 @@ int mtd_dwrite(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen,
 	return ops->write(dev, to, len, retlen, buf);
 }
 
+int mtd_dprotect(struct mtd_info *mtd, loff_t ofs, uint64_t len, bool prot)
+{
+	struct udevice *dev = mtd->dev;
+	const struct mtd_ops *ops = mtd_get_ops(dev);
+
+	if (!ops->lock || !ops->unlock)
+		return -ENOSYS;
+
+	if (ofs < 0 || ofs > mtd->size || len > mtd->size - ofs)
+		return -EINVAL;
+	if (!len)
+		return 0;
+
+	if (prot)
+		return ops->lock(dev, ofs, len);
+	else
+		return ops->unlock(dev, ofs, len);
+}
+
 int mtd_find_device(int mtd_if_type, int devnum, struct udevice **devp)
 {
 	struct uclass *uc;
diff --git a/include/mtd.h b/include/mtd.h
index acb2256..6390133 100644
--- a/include/mtd.h
+++ b/include/mtd.h
@@ -61,6 +61,17 @@ int mtd_dwrite(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen,
 	       const u_char *buf);
 
 /**
+ * mtd_dprotect - protect area of MTD device
+ *
+ * @mtd:	MTD device
+ * @ofs:	sector start offset into device in bytes to protect to
+ * @len:	len of bytes to protect
+ * @prot:	protect boolean, true for lock, false for unlock
+ * @return 0 if OK, -ve on error
+ */
+int mtd_dprotect(struct mtd_info *mtd, loff_t ofs, uint64_t len, bool prot);
+
+/**
  * mtd_derase() - erase blocks of the MTD device
  *
  * @mtd:	MTD device
-- 
2.7.4

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

* [U-Boot] [PATCH v10 23/27] board_r: initialize spi_nor
  2017-12-28  6:12 [U-Boot] [PATCH v10 00/27] dm: Generic MTD Subsystem, with SPI-NOR interface Jagan Teki
                   ` (21 preceding siblings ...)
  2017-12-28  6:12 ` [U-Boot] [PATCH v10 22/27] cmd: spinor: sync/update protect command Jagan Teki
@ 2017-12-28  6:12 ` Jagan Teki
  2018-01-08  3:52   ` Simon Glass
  2017-12-28  6:12 ` [U-Boot] [PATCH v10 24/27] env: add spi-nor environment Jagan Teki
                   ` (5 subsequent siblings)
  28 siblings, 1 reply; 55+ messages in thread
From: Jagan Teki @ 2017-12-28  6:12 UTC (permalink / raw)
  To: u-boot

initialize spi-nor framework during boot, so-that detected
buses can appears at boot log.

Signed-off-by: Suneel Garapati <suneelglinux@gmail.com>
Signed-off-by: Jagan Teki <jagan@amarulasolutions.com>
---
 common/board_r.c                     | 13 +++++++++++++
 drivers/mtd/spi-nor/spi-nor-uclass.c | 17 +++++++++++++++++
 include/linux/mtd/spi-nor.h          |  1 +
 3 files changed, 31 insertions(+)

diff --git a/common/board_r.c b/common/board_r.c
index 09167c1..8030548 100644
--- a/common/board_r.c
+++ b/common/board_r.c
@@ -42,6 +42,7 @@
 #include <scsi.h>
 #include <serial.h>
 #include <spi.h>
+#include <linux/mtd/spi-nor.h>
 #include <stdio_dev.h>
 #include <timer.h>
 #include <trace.h>
@@ -400,6 +401,15 @@ static int initr_spi(void)
 }
 #endif
 
+#ifdef CONFIG_MTD_SPI_NOR
+static int initr_spi_nor(void)
+{
+	puts("SPI-NOR: ");
+	spi_nor_init();
+	return 0;
+}
+#endif
+
 #ifdef CONFIG_CMD_NAND
 /* go init the NAND */
 static int initr_nand(void)
@@ -762,6 +772,9 @@ static init_fnc_t init_sequence_r[] = {
 #ifdef CONFIG_PPC
 	initr_spi,
 #endif
+#ifdef CONFIG_MTD_SPI_NOR
+	initr_spi_nor,
+#endif
 #ifdef CONFIG_CMD_NAND
 	initr_nand,
 #endif
diff --git a/drivers/mtd/spi-nor/spi-nor-uclass.c b/drivers/mtd/spi-nor/spi-nor-uclass.c
index 919682d..8a37be0 100644
--- a/drivers/mtd/spi-nor/spi-nor-uclass.c
+++ b/drivers/mtd/spi-nor/spi-nor-uclass.c
@@ -15,6 +15,23 @@
 
 DECLARE_GLOBAL_DATA_PTR;
 
+int spi_nor_init(void)
+{
+	struct udevice *bus;
+
+	for (uclass_first_device(UCLASS_SPI_NOR, &bus);
+	     bus;
+	     uclass_next_device(&bus)) {
+		;
+	}
+
+#ifndef CONFIG_SPL_BUILD
+	print_spi_nor_devices(',');
+#endif
+
+	return 0;
+}
+
 struct spi_nor *spi_nor_get_spi_nor_dev(struct udevice *dev)
 {
 	struct spi_nor_uclass_priv *upriv;
diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
index 9c3da70..2e8e52d 100644
--- a/include/linux/mtd/spi-nor.h
+++ b/include/linux/mtd/spi-nor.h
@@ -218,5 +218,6 @@ int get_spi_nor_num(void);
 struct spi_nor *spi_nor_get_spi_nor_dev(struct udevice *dev);
 struct mtd_info *spi_nor_get_mtd_info(struct spi_nor *nor);
 void print_spi_nor_devices(char separator);
+int spi_nor_init(void);
 
 #endif /* __MTD_SPI_NOR_H */
-- 
2.7.4

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

* [U-Boot] [PATCH v10 24/27] env: add spi-nor environment
  2017-12-28  6:12 [U-Boot] [PATCH v10 00/27] dm: Generic MTD Subsystem, with SPI-NOR interface Jagan Teki
                   ` (22 preceding siblings ...)
  2017-12-28  6:12 ` [U-Boot] [PATCH v10 23/27] board_r: initialize spi_nor Jagan Teki
@ 2017-12-28  6:12 ` Jagan Teki
  2018-01-04  7:06   ` Prabhakar Kushwaha
  2017-12-28  6:12 ` [U-Boot] [PATCH v10 25/27] arm: dts: zynq: Add zynq-qspinor node Jagan Teki
                   ` (4 subsequent siblings)
  28 siblings, 1 reply; 55+ messages in thread
From: Jagan Teki @ 2017-12-28  6:12 UTC (permalink / raw)
  To: u-boot

Now spi-nor framework is up so access the environment
through en/spinor.c

Signed-off-by: Suneel Garapati <suneelglinux@gmail.com>
Signed-off-by: Jagan Teki <jagan@amarulasolutions.com>
---
 cmd/nvedit.c          |   1 +
 env/Kconfig           |  27 ++++++++++++
 env/Makefile          |   1 +
 env/env.c             |   2 +
 env/spinor.c          | 113 ++++++++++++++++++++++++++++++++++++++++++++++++++
 include/environment.h |   1 +
 6 files changed, 145 insertions(+)
 create mode 100644 env/spinor.c

diff --git a/cmd/nvedit.c b/cmd/nvedit.c
index 4e79d03..2e5e88d 100644
--- a/cmd/nvedit.c
+++ b/cmd/nvedit.c
@@ -50,6 +50,7 @@ DECLARE_GLOBAL_DATA_PTR;
 	!defined(CONFIG_ENV_IS_IN_ONENAND)	&& \
 	!defined(CONFIG_ENV_IS_IN_SATA)		&& \
 	!defined(CONFIG_ENV_IS_IN_SPI_FLASH)	&& \
+	!defined(CONFIG_ENV_IS_IN_SPI_NOR)	&& \
 	!defined(CONFIG_ENV_IS_IN_REMOTE)	&& \
 	!defined(CONFIG_ENV_IS_IN_UBI)		&& \
 	!defined(CONFIG_ENV_IS_NOWHERE)
diff --git a/env/Kconfig b/env/Kconfig
index 2477bf8..1b694d5 100644
--- a/env/Kconfig
+++ b/env/Kconfig
@@ -329,6 +329,22 @@ config ENV_IS_IN_SPI_FLASH
 
 	  Define the SPI work mode. If not defined then use SPI_MODE_3.
 
+config ENV_IS_IN_SPI_NOR
+	bool "Environment is in SPI-NOR flash"
+	depends on !CHAIN_OF_TRUST
+	help
+	  Define this if you have a SPI NOR Flash memory device which you
+	  want to use for the environment.
+
+	  - CONFIG_ENV_OFFSET:
+	  - CONFIG_ENV_SIZE:
+
+	  These two #defines specify the offset and size of the
+	  environment area within the SPI NOR Flash. CONFIG_ENV_OFFSET must be
+	  aligned to an erase sector boundary.
+
+	  - CONFIG_ENV_SECT_SIZE:
+
 config ENV_IS_IN_UBI
 	bool "Environment in a UBI volume"
 	depends on !CHAIN_OF_TRUST
@@ -396,6 +412,17 @@ config ENV_FAT_FILE
 	  It's a string of the FAT file name. This file use to store the
 	  environment.
 
+config ENV_SPI_NOR_DEVNUM
+	int "SPI-NOR device number for the environment"
+	depends on ENV_IS_IN_SPI_NOR
+	default 0
+	help
+	  Define this an integer of spi nor device number for the environment.
+	  Since spi nor framework assign device numbers automatically by devicetree
+	  node definition which start from 0, so assign 0 as default.
+
+	  If board need different devnum then, this can be change.
+
 if ARCH_SUNXI
 
 config ENV_OFFSET
diff --git a/env/Makefile b/env/Makefile
index 7ce8231..21fe9a4 100644
--- a/env/Makefile
+++ b/env/Makefile
@@ -25,6 +25,7 @@ obj-$(CONFIG_ENV_IS_IN_NVRAM) += nvram.o
 obj-$(CONFIG_ENV_IS_IN_ONENAND) += onenand.o
 obj-$(CONFIG_ENV_IS_IN_SATA) += sata.o
 obj-$(CONFIG_ENV_IS_IN_SPI_FLASH) += sf.o
+obj-$(CONFIG_ENV_IS_IN_SPI_NOR) += spinor.o
 obj-$(CONFIG_ENV_IS_IN_REMOTE) += remote.o
 obj-$(CONFIG_ENV_IS_IN_UBI) += ubi.o
 obj-$(CONFIG_ENV_IS_NOWHERE) += nowhere.o
diff --git a/env/env.c b/env/env.c
index 76a5608..be1672c 100644
--- a/env/env.c
+++ b/env/env.c
@@ -44,6 +44,8 @@ static enum env_location env_get_default_location(void)
 		return ENVL_REMOTE;
 	else if IS_ENABLED(CONFIG_ENV_IS_IN_SPI_FLASH)
 		return ENVL_SPI_FLASH;
+	else if IS_ENABLED(CONFIG_ENV_IS_IN_SPI_NOR)
+		return ENVL_SPI_NOR;
 	else if IS_ENABLED(CONFIG_ENV_IS_IN_UBI)
 		return ENVL_UBI;
 	else if IS_ENABLED(CONFIG_ENV_IS_NOWHERE)
diff --git a/env/spinor.c b/env/spinor.c
new file mode 100644
index 0000000..bc6fdfa
--- /dev/null
+++ b/env/spinor.c
@@ -0,0 +1,113 @@
+/*
+ * SPI-NOR Environment.
+ *
+ * Copyright (C) 2017 Jagan Teki <jagan@openedev.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <environment.h>
+#include <memalign.h>
+#include <mtd.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/spi-nor.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static struct spi_nor *env_init_spinor(void)
+{
+	struct spi_nor *nor;
+	int devnum = CONFIG_ENV_SPI_NOR_DEVNUM;
+
+	nor = find_spi_nor_device(devnum);
+	if (!nor)
+		return NULL;
+
+	if (spi_nor_scan(nor))
+		return NULL;
+
+	return nor;
+}
+
+static int env_spinor_save(void)
+{
+	ALLOC_CACHE_ALIGN_BUFFER(env_t, env_new, 1);
+	struct spi_nor *nor;
+	struct mtd_info *mtd;
+	struct erase_info instr;
+	loff_t len, sector;
+	int ret;
+
+	nor = env_init_spinor();
+	if (!nor)
+		return -EIO;
+
+	ret = env_export(env_new);
+	if (ret)
+		return -EINVAL;
+
+	mtd = spi_nor_get_mtd_info(nor);
+	if (!mtd)
+		return -EIO;
+
+	sector = DIV_ROUND_UP(CONFIG_ENV_SIZE, CONFIG_ENV_SECT_SIZE);
+	len = sector * CONFIG_ENV_SECT_SIZE;
+	instr.mtd = mtd;
+        instr.addr = CONFIG_ENV_OFFSET;
+        instr.len = len;
+        instr.callback = 0;
+
+	puts("erasing spinor flash...\n");
+        ret = mtd_derase(mtd, &instr);
+	if (ret)
+		return -EIO;
+
+	len = CONFIG_ENV_SIZE;
+	puts("writing spinor flash...\n");
+	ret = mtd_dwrite(mtd, CONFIG_ENV_OFFSET, len,
+			 (size_t *)&len, (u_char *)env_new);
+	if (ret)
+		return -EIO;
+
+	puts("done\n");
+	return ret;
+}
+
+static int env_spinor_load(void)
+{
+	ALLOC_CACHE_ALIGN_BUFFER(char, buf, CONFIG_ENV_SIZE);
+	struct spi_nor *nor;
+	struct mtd_info *mtd;
+	loff_t offset, len;
+	int ret;
+
+	nor = env_init_spinor();
+	if (!nor)
+		return -EIO;
+
+	offset = CONFIG_ENV_OFFSET;
+	len = CONFIG_ENV_SIZE;
+
+	mtd = spi_nor_get_mtd_info(nor);
+	if (!mtd)
+		return -EIO;
+
+	ret = mtd_dread(mtd, offset, len, (size_t *)&len, (uchar *)buf);
+	if (ret)
+		return -EIO;
+
+	ret = env_import(buf, 1);
+	if (ret)
+		gd->env_valid = ENV_VALID;
+
+	return ret;
+}
+
+U_BOOT_ENV_LOCATION(spinor) = {
+	.location	= ENVL_SPI_NOR,
+	ENV_NAME("SPI-NOR Flash")
+	.load		= env_spinor_load,
+	.save		= env_save_ptr(env_spinor_save),
+};
diff --git a/include/environment.h b/include/environment.h
index d29f82c..8e8be26 100644
--- a/include/environment.h
+++ b/include/environment.h
@@ -198,6 +198,7 @@ enum env_location {
 	ENVL_ONENAND,
 	ENVL_REMOTE,
 	ENVL_SPI_FLASH,
+	ENVL_SPI_NOR,
 	ENVL_UBI,
 	ENVL_NOWHERE,
 
-- 
2.7.4

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

* [U-Boot] [PATCH v10 25/27] arm: dts: zynq: Add zynq-qspinor node
  2017-12-28  6:12 [U-Boot] [PATCH v10 00/27] dm: Generic MTD Subsystem, with SPI-NOR interface Jagan Teki
                   ` (23 preceding siblings ...)
  2017-12-28  6:12 ` [U-Boot] [PATCH v10 24/27] env: add spi-nor environment Jagan Teki
@ 2017-12-28  6:12 ` Jagan Teki
  2017-12-28  6:12 ` [U-Boot] [PATCH v10 26/27] dm: zynq: microzed: enable MTD/SPI-NOR framework Jagan Teki
                   ` (3 subsequent siblings)
  28 siblings, 0 replies; 55+ messages in thread
From: Jagan Teki @ 2017-12-28  6:12 UTC (permalink / raw)
  To: u-boot

zynq qspi controller can be considered as spi-nor
controller since controller meant for accessing
spi-nor chips along with flash related functionalities.

Signed-off-by: Jagan Teki <jagan@amarulasolutions.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 d9774d8..fa7965d 100644
--- a/arch/arm/dts/zynq-7000.dtsi
+++ b/arch/arm/dts/zynq-7000.dtsi
@@ -213,6 +213,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] 55+ messages in thread

* [U-Boot] [PATCH v10 26/27] dm: zynq: microzed: enable MTD/SPI-NOR framework
  2017-12-28  6:12 [U-Boot] [PATCH v10 00/27] dm: Generic MTD Subsystem, with SPI-NOR interface Jagan Teki
                   ` (24 preceding siblings ...)
  2017-12-28  6:12 ` [U-Boot] [PATCH v10 25/27] arm: dts: zynq: Add zynq-qspinor node Jagan Teki
@ 2017-12-28  6:12 ` Jagan Teki
  2017-12-28  6:12 ` [U-Boot] [PATCH v10 27/27] test: dm: add tests for mtd devices Jagan Teki
                   ` (2 subsequent siblings)
  28 siblings, 0 replies; 55+ messages in thread
From: Jagan Teki @ 2017-12-28  6:12 UTC (permalink / raw)
  To: u-boot

Enable spi-nor framework for zynq microzed board,
the zynq_qspi controller at spi still there for
testing once the framework is mature will drop.

test log:
========
Zynq> spinor
spinor - SPI-NOR Sub-system

Usage:
spinor list                     - show list of spinor devices
spinor info                     - show current spinor device info
spinor dev [devnum]             - show or set current spinor device
spinor erase offset len         - erase 'len' bytes from 'offset'
spinor write addr to len        - write 'len' bytes to 'to' from 'addr'
spinor read addr from len       - read 'len' bytes from 'from' to 'addr'
spinor protect lock/unlock sector len - protect/unprotect 'len' bytes starting
                                  at address 'sector'
Zynq> spinor list
flash at 0: 0
spi-nor at e000d000: 1
Zynq> spinor dev 0
switch to dev #0, OK
spinor0 is current device
Zynq> spinor info
bus: flash at 0: 0
device: s25fl128s_64k
page size: 256 B
erase size: 64 KiB
size: 16 MiB
Zynq> spinor erase 0xE00000 0x100000
SPI-NOR: 1048576 bytes @ 0xe00000 Erased: OK
Zynq> mw.b 0x100 0xcc 0x100000
Zynq> spinor write 0x100 0xE00000 0x100000
device 0 offset 0xe00000, size 0x100000
SPI-NOR: 1048576 bytes @ 0xe00000 Written: OK
Zynq> spinor read 0x3000000 0xE00000 0x100000
device 0 offset 0xe00000, size 0x100000
SPI-NOR: 1048576 bytes @ 0xe00000 Read: OK
Zynq> cmp.b 0x3000000 0x100 0x100000
Total of 1048576 byte(s) were the same
Zynq> spinor dev 1
switch to dev #1, OK
spinor1 is current device
Zynq> spinor info
bus: spi-nor at e000d000: 1
device: s25fl128s_64k
page size: 256 B
erase size: 64 KiB
size: 16 MiB
Zynq> spinor erase 0xE00000 0x100000
SPI-NOR: 1048576 bytes @ 0xe00000 Erased: OK
Zynq> mw.b 0x100 0xbb 0x100000
Zynq> spinor write 0x100 0xE00000 0x100000
device 0 offset 0xe00000, size 0x100000
SPI-NOR: 1048576 bytes @ 0xe00000 Written: OK
Zynq> spinor read 0x3000000 0xE00000 0x100000
device 0 offset 0xe00000, size 0x100000
SPI-NOR: 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@amarulasolutions.com>
---
 arch/arm/dts/zynq-microzed.dts  | 12 +++++++++++-
 configs/zynq_microzed_defconfig | 17 ++++++++++-------
 2 files changed, 21 insertions(+), 8 deletions(-)

diff --git a/arch/arm/dts/zynq-microzed.dts b/arch/arm/dts/zynq-microzed.dts
index 2d07b92..ff973dd 100644
--- a/arch/arm/dts/zynq-microzed.dts
+++ b/arch/arm/dts/zynq-microzed.dts
@@ -14,7 +14,6 @@
 
 	aliases {
 		serial0 = &uart1;
-		spi0 = &qspi;
 		mmc0 = &sdhci0;
 	};
 
@@ -41,6 +40,17 @@
 &qspi {
 	u-boot,dm-pre-reloc;
 	status = "okay";
+
+	s25fl128s_64k: flash at 0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		reg = <0>;
+		compatible = "jedec,spi-nor";
+	};
+};
+
+&qspinor {
+	status = "okay";
 };
 
 &uart1 {
diff --git a/configs/zynq_microzed_defconfig b/configs/zynq_microzed_defconfig
index a713314..56908fe 100644
--- a/configs/zynq_microzed_defconfig
+++ b/configs/zynq_microzed_defconfig
@@ -19,7 +19,7 @@ CONFIG_CMD_FPGA_LOADMK=y
 CONFIG_CMD_FPGA_LOADP=y
 CONFIG_CMD_GPIO=y
 CONFIG_CMD_MMC=y
-CONFIG_CMD_SF=y
+CONFIG_CMD_SPINOR=y
 CONFIG_CMD_USB=y
 # CONFIG_CMD_SETEXPR is not set
 CONFIG_CMD_TFTPPUT=y
@@ -32,7 +32,7 @@ CONFIG_CMD_EXT4=y
 CONFIG_CMD_EXT4_WRITE=y
 CONFIG_CMD_FAT=y
 CONFIG_CMD_FS_GENERIC=y
-CONFIG_ENV_IS_IN_SPI_FLASH=y
+CONFIG_ENV_IS_IN_SPI_NOR=y
 CONFIG_NET_RANDOM_ETHADDR=y
 CONFIG_SPL_DM_SEQ_ALIAS=y
 CONFIG_DFU_MMC=y
@@ -40,14 +40,17 @@ CONFIG_DFU_RAM=y
 CONFIG_FPGA_XILINX=y
 CONFIG_MMC_SDHCI=y
 CONFIG_MMC_SDHCI_ZYNQ=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_SERIAL=y
 CONFIG_ZYNQ_QSPI=y
+CONFIG_MTD=y
+CONFIG_MTD_SPI_NOR=y
+CONFIG_MTD_M25P80=y
+CONFIG_MTD_ZYNQ_QSPI=y
+CONFIG_SPI_NOR_STMICRO=y
+CONFIG_SPI_NOR_SPANSION=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] 55+ messages in thread

* [U-Boot] [PATCH v10 27/27] test: dm: add tests for mtd devices
  2017-12-28  6:12 [U-Boot] [PATCH v10 00/27] dm: Generic MTD Subsystem, with SPI-NOR interface Jagan Teki
                   ` (25 preceding siblings ...)
  2017-12-28  6:12 ` [U-Boot] [PATCH v10 26/27] dm: zynq: microzed: enable MTD/SPI-NOR framework Jagan Teki
@ 2017-12-28  6:12 ` Jagan Teki
  2017-12-28 14:44 ` [U-Boot] [PATCH v10 00/27] dm: Generic MTD Subsystem, with SPI-NOR interface Lukasz Majewski
  2018-01-23  9:00 ` Siva Durga Prasad Paladugu
  28 siblings, 0 replies; 55+ messages in thread
From: Jagan Teki @ 2017-12-28  6:12 UTC (permalink / raw)
  To: u-boot

Add some tests to check that mtd devices work as expected,
more tests will add it in future.

Also removed CMD_MTDPARTS which breaking driver-model MTD.

Signed-off-by: Jagan Teki <jagan@amarulasolutions.com>
---
 configs/sandbox_defconfig |  8 +++++++-
 test/dm/Makefile          |  1 +
 test/dm/mtd.c             | 33 +++++++++++++++++++++++++++++++++
 3 files changed, 41 insertions(+), 1 deletion(-)
 create mode 100644 test/dm/mtd.c

diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig
index 7efb4eb..658d9f2 100644
--- a/configs/sandbox_defconfig
+++ b/configs/sandbox_defconfig
@@ -65,7 +65,6 @@ CONFIG_CMD_BTRFS=y
 CONFIG_CMD_CBFS=y
 CONFIG_CMD_CRAMFS=y
 CONFIG_CMD_EXT4_WRITE=y
-CONFIG_CMD_MTDPARTS=y
 CONFIG_CMD_LOG=y
 CONFIG_MAC_PARTITION=y
 CONFIG_AMIGA_PARTITION=y
@@ -197,3 +196,10 @@ CONFIG_UT_TIME=y
 CONFIG_UT_DM=y
 CONFIG_UT_ENV=y
 CONFIG_UT_OVERLAY=y
+CONFIG_MTD=y
+CONFIG_MTD_SPI_NOR=y
+CONFIG_MTD_M25P80=y
+CONFIG_SPI_NOR_STMICRO=y
+CONFIG_SPI_NOR_SPANSION=y
+CONFIG_SPI_NOR_WINBOND=y
+CONFIG_SPI_NOR_MACRONIX=y
diff --git a/test/dm/Makefile b/test/dm/Makefile
index 513c456..55f7450 100644
--- a/test/dm/Makefile
+++ b/test/dm/Makefile
@@ -22,6 +22,7 @@ obj-$(CONFIG_DM_GPIO) += gpio.o
 obj-$(CONFIG_DM_I2C) += i2c.o
 obj-$(CONFIG_LED) += led.o
 obj-$(CONFIG_DM_MAILBOX) += mailbox.o
+obj-$(CONFIG_MTD) += mtd.o
 obj-$(CONFIG_DM_MMC) += mmc.o
 obj-$(CONFIG_DM_PCI) += pci.o
 obj-$(CONFIG_PHY) += phy.o
diff --git a/test/dm/mtd.c b/test/dm/mtd.c
new file mode 100644
index 0000000..fe98593
--- /dev/null
+++ b/test/dm/mtd.c
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2017 Jagan Teki <jagan@openedev.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <asm/state.h>
+#include <dm/test.h>
+#include <test/ut.h>
+
+#include <mtd.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/spi-nor.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* Test that we can find mtd devices without probing them */
+static int dm_test_mtd_find(struct unit_test_state *uts)
+{
+	struct udevice *mtd, *spinor, *dev;
+
+	ut_assertok(mtd_create_device(mtd, "spinor_mtd", "test",
+				      MTD_IF_TYPE_SPI_NOR, &spinor));
+
+	ut_asserteq(-ENODEV, mtd_find_device(MTD_IF_TYPE_SPI_NOR, 1, &dev));
+	ut_assertok(mtd_find_device(MTD_IF_TYPE_SPI_NOR, 0, &dev));
+	ut_asserteq_ptr(spinor, dev);
+
+	return 0;
+}
+DM_TEST(dm_test_mtd_find, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
-- 
2.7.4

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

* [U-Boot] [PATCH v10 20/27] mtd: spi-nor: Add 4-byte addresswidth support
  2017-12-28  6:12 ` [U-Boot] [PATCH v10 20/27] mtd: spi-nor: Add 4-byte addresswidth support Jagan Teki
@ 2017-12-28  8:06   ` Cyrille Pitchen
  2017-12-28  8:08     ` Cyrille Pitchen
  0 siblings, 1 reply; 55+ messages in thread
From: Cyrille Pitchen @ 2017-12-28  8:06 UTC (permalink / raw)
  To: u-boot

Hi Jagan,

Le 28/12/2017 à 07:12, Jagan Teki a écrit :
> Add 4-byte address supports, so-that SPI-NOR chips
> has > 16MiB should accessible.
> 
> Signed-off-by: Jagan Teki <jagan@amarulasolutions.com>
> ---
>  drivers/mtd/spi-nor/m25p80.c  |  1 +
>  drivers/mtd/spi-nor/spi-nor.c | 38 ++++++++++++++++++++++++++++++++++++++
>  include/linux/mtd/spi-nor.h   |  6 +++++-
>  3 files changed, 44 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/mtd/spi-nor/m25p80.c b/drivers/mtd/spi-nor/m25p80.c
> index 5465921..7af6f59 100644
> --- a/drivers/mtd/spi-nor/m25p80.c
> +++ b/drivers/mtd/spi-nor/m25p80.c
> @@ -35,6 +35,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 8bf9e67..e0085cf 100644
> --- a/drivers/mtd/spi-nor/spi-nor.c
> +++ b/drivers/mtd/spi-nor/spi-nor.c
> @@ -632,6 +632,38 @@ static int stm_unlock(struct udevice *dev, loff_t ofs, uint64_t len)
>  }
>  #endif
>  
> +/* Enable/disable 4-byte addressing mode. */
> +static int set_4byte(struct udevice *dev, const struct spi_nor_info *info,
> +		     int enable)
> +{
> +	struct spi_nor *nor = spi_nor_get_spi_nor_dev(dev);
> +	const struct spi_nor_ops *ops = spi_nor_get_ops(dev);
> +	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(dev);
> +
> +		cmd = enable ? SNOR_OP_EN4B : SNOR_OP_EX4B;
> +		status = ops->write_reg(dev, cmd, NULL, 0);
> +		if (need_wren)
> +			write_disable(dev);
> +
> +		return status;
> +	default:
> +		/* Spansion style */
> +		nor->cmd_buf[0] = enable << 7;
> +		return ops->write_reg(dev, SNOR_OP_BRWR, nor->cmd_buf, 1);
> +	}
> +}
> +
>  #ifdef CONFIG_SPI_NOR_MACRONIX
>  static int macronix_quad_enable(struct udevice *dev)
>  {
> @@ -873,6 +905,12 @@ int spi_nor_scan(struct spi_nor *nor)
>  	}
>  
>  	nor->addr_width = 3;
> +	if (mtd->size > SNOR_16MB_BOUN) {
> +		nor->addr_width = 4;
> +		ret = set_4byte(nor->dev, info, true);
> +		if (ret)
> +			goto err;
> +	}
>

This is a bad idea: you make the SPI NOR memory enter its 4-byte address
mode, which is statefull. Then, once in Linux for instance, the memory
would still be in its 4-byte address mode but expected to be in its reset
state, hence in 3-byte address mode.

At this point, this might not be an issue yet because spi-nor under linux
is likely to use the 4-byte address instruction set if available, which is
stateless by the way, so whatever the memory is in its 3-byte or in 4-byte
address mode, the op codes of the 4-byte address instruction set are always
expected to be followed by a 4-byte address. So Linux won't notice that the
SPI NOR memory is in its 4-byte mode but not in its 3-byte mode as expected.

However, if a spurious reboot occurs at the CPU side after the SPI NOR
memory has entered its 4-byte address mode, either still in u-boot or
already in linux or whatever running code, the SPI NOR memory, likely not
reset on its side, would still be in its 4-byte address mode, whereas many
earlier boot-loaders would expect the memory to be in it's reset state, ie
in its 3-byte address mode. Hence those boot-loaders, running before u-boot,
would not be able to read data (load u-boot) from the SPI NOR memory:
the boot would fail!

Examples of those early boot-loaders are the ROM Codes of many Atmel
SAMA5Dx SoCs but I'm pretty sure this issue also applies to other
manufacturers based on patches I've seen on the linux-mtd mailing list to
add the SPI_NOR_4B_OPCODES flag to some memory parts:
https://patchwork.ozlabs.org/patch/750305/

Think about a watchdog resetting the CPU for instance.


TL;DR
You should avoid making the SPI NOR memory enter its statefull 4-byte
address mode but consider using the stateless 4-byte address instruction
set instead, when possible.

Almost all recent SPI NOR memories with sizes > 16MiB support the 4-byte
address mode.

Best regards,

Cyrille
  
>  	/* 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 e1688e2..fc4a649 100644
> --- a/include/linux/mtd/spi-nor.h
> +++ b/include/linux/mtd/spi-nor.h
> @@ -63,6 +63,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 */
> @@ -84,7 +88,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
>  
>  /**
> 

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

* [U-Boot] [PATCH v10 20/27] mtd: spi-nor: Add 4-byte addresswidth support
  2017-12-28  8:06   ` Cyrille Pitchen
@ 2017-12-28  8:08     ` Cyrille Pitchen
  0 siblings, 0 replies; 55+ messages in thread
From: Cyrille Pitchen @ 2017-12-28  8:08 UTC (permalink / raw)
  To: u-boot

Le 28/12/2017 à 09:06, Cyrille Pitchen a écrit :
> Hi Jagan,
> 
> Le 28/12/2017 à 07:12, Jagan Teki a écrit :
>> Add 4-byte address supports, so-that SPI-NOR chips
>> has > 16MiB should accessible.
>>
>> Signed-off-by: Jagan Teki <jagan@amarulasolutions.com>
>> ---
>>  drivers/mtd/spi-nor/m25p80.c  |  1 +
>>  drivers/mtd/spi-nor/spi-nor.c | 38 ++++++++++++++++++++++++++++++++++++++
>>  include/linux/mtd/spi-nor.h   |  6 +++++-
>>  3 files changed, 44 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/mtd/spi-nor/m25p80.c b/drivers/mtd/spi-nor/m25p80.c
>> index 5465921..7af6f59 100644
>> --- a/drivers/mtd/spi-nor/m25p80.c
>> +++ b/drivers/mtd/spi-nor/m25p80.c
>> @@ -35,6 +35,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 8bf9e67..e0085cf 100644
>> --- a/drivers/mtd/spi-nor/spi-nor.c
>> +++ b/drivers/mtd/spi-nor/spi-nor.c
>> @@ -632,6 +632,38 @@ static int stm_unlock(struct udevice *dev, loff_t ofs, uint64_t len)
>>  }
>>  #endif
>>  
>> +/* Enable/disable 4-byte addressing mode. */
>> +static int set_4byte(struct udevice *dev, const struct spi_nor_info *info,
>> +		     int enable)
>> +{
>> +	struct spi_nor *nor = spi_nor_get_spi_nor_dev(dev);
>> +	const struct spi_nor_ops *ops = spi_nor_get_ops(dev);
>> +	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(dev);
>> +
>> +		cmd = enable ? SNOR_OP_EN4B : SNOR_OP_EX4B;
>> +		status = ops->write_reg(dev, cmd, NULL, 0);
>> +		if (need_wren)
>> +			write_disable(dev);
>> +
>> +		return status;
>> +	default:
>> +		/* Spansion style */
>> +		nor->cmd_buf[0] = enable << 7;
>> +		return ops->write_reg(dev, SNOR_OP_BRWR, nor->cmd_buf, 1);
>> +	}
>> +}
>> +
>>  #ifdef CONFIG_SPI_NOR_MACRONIX
>>  static int macronix_quad_enable(struct udevice *dev)
>>  {
>> @@ -873,6 +905,12 @@ int spi_nor_scan(struct spi_nor *nor)
>>  	}
>>  
>>  	nor->addr_width = 3;
>> +	if (mtd->size > SNOR_16MB_BOUN) {
>> +		nor->addr_width = 4;
>> +		ret = set_4byte(nor->dev, info, true);
>> +		if (ret)
>> +			goto err;
>> +	}
>>
> 
> This is a bad idea: you make the SPI NOR memory enter its 4-byte address
> mode, which is statefull. Then, once in Linux for instance, the memory
> would still be in its 4-byte address mode but expected to be in its reset
> state, hence in 3-byte address mode.
> 
> At this point, this might not be an issue yet because spi-nor under linux
> is likely to use the 4-byte address instruction set if available, which is
> stateless by the way, so whatever the memory is in its 3-byte or in 4-byte
> address mode, the op codes of the 4-byte address instruction set are always
> expected to be followed by a 4-byte address. So Linux won't notice that the
> SPI NOR memory is in its 4-byte mode but not in its 3-byte mode as expected.
> 
> However, if a spurious reboot occurs at the CPU side after the SPI NOR
> memory has entered its 4-byte address mode, either still in u-boot or
> already in linux or whatever running code, the SPI NOR memory, likely not
> reset on its side, would still be in its 4-byte address mode, whereas many
> earlier boot-loaders would expect the memory to be in it's reset state, ie
> in its 3-byte address mode. Hence those boot-loaders, running before u-boot,
> would not be able to read data (load u-boot) from the SPI NOR memory:
> the boot would fail!
> 
> Examples of those early boot-loaders are the ROM Codes of many Atmel
> SAMA5Dx SoCs but I'm pretty sure this issue also applies to other
> manufacturers based on patches I've seen on the linux-mtd mailing list to
> add the SPI_NOR_4B_OPCODES flag to some memory parts:
> https://patchwork.ozlabs.org/patch/750305/
> 
> Think about a watchdog resetting the CPU for instance.
> 
> 
> TL;DR
> You should avoid making the SPI NOR memory enter its statefull 4-byte
> address mode but consider using the stateless 4-byte address instruction
> set instead, when possible.
> 
> Almost all recent SPI NOR memories with sizes > 16MiB support the 4-byte
> address mode.

I meant the 4-byte address instruction set ;)
> 
> Best regards,
> 
> Cyrille
>   
>>  	/* 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 e1688e2..fc4a649 100644
>> --- a/include/linux/mtd/spi-nor.h
>> +++ b/include/linux/mtd/spi-nor.h
>> @@ -63,6 +63,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 */
>> @@ -84,7 +88,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
>>  
>>  /**
>>
> 

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

* [U-Boot] [PATCH v10 00/27] dm: Generic MTD Subsystem, with SPI-NOR interface
  2017-12-28  6:12 [U-Boot] [PATCH v10 00/27] dm: Generic MTD Subsystem, with SPI-NOR interface Jagan Teki
                   ` (26 preceding siblings ...)
  2017-12-28  6:12 ` [U-Boot] [PATCH v10 27/27] test: dm: add tests for mtd devices Jagan Teki
@ 2017-12-28 14:44 ` Lukasz Majewski
  2018-01-02 10:09   ` Jagan Teki
  2018-01-23  9:00 ` Siva Durga Prasad Paladugu
  28 siblings, 1 reply; 55+ messages in thread
From: Lukasz Majewski @ 2017-12-28 14:44 UTC (permalink / raw)
  To: u-boot

Hi Jagan,

> Compared to previous series’s [1], [2], [3] and [4] this patch set
> redefined most of the implementation suitable to fit into existing
> driver-model.
> 
> MTD is generic subsystem for underlying flash devices like nand,
> parallel nor, spinor, dataflash etc. So to drive this theory with
> driver model(with an example of block layer) mtd is common device
> interaction for most of  memory technology flashes like nand,
> parallel nor, spinor, dataflash etc, these are treated as interface
> types wrt u-boot driver model.
> 
> Once the respective interface driver bind happen, the uclass driver
> will pass an 'interface type' to mtd layer to create device for it,
> for example once spinor ULASS_SPI_NOR driver bind happen,
> the uclass driver of spinor will pass MTD_IF_TYPE_SPI_NOR 
> interface type to create mtd device for spinor devices.
> 
> SPI-NOR:
> =======
> 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.

I must admit that I'm a bit confused....

If you don't mind I would like to ask for clarification of a few things:



> 
> =======================================
>              cmd/spinor.c

		^^^^^ - this would be a new set of commands to comply
		with DM? 

		What about "sf" command which we use now to get access
		to SPI-NOR memory? A lot of boards already use "sf"
		command... which may be tricky to replace.

> =======================================
>              mtd-uclass.c
		^^^^^ - here we will have a generic MTD layer (as it is
		in Linux)

> =======================================
>            spi-nor-uclass.c
> =======================================
>               spi-nor.c
		^^^^^^ - why do we need to have spi-nor.c ? Cannot we
		have its functionality in the spi-nor-uclass.c ?
		(I'm just curious)

> =======================================
> m25p80.c                zynq_qspinor.c
  ^^^^^ - this is the     ^^^^^^^^ - [*]
"generic" spi-nor
driver used in Linux. 
I suppose that it will
be reused here?

> =======================================
> spi-uclass.c
  ^^^^^^^ - why do we
need this uclass?

> =======================================
> zynq_qspi.c
 ^^^^^ - This is probably
the low-level driver for
zynq QSPI IP block - why
do we have zynq_qspinor.c file above [*]?
What is the difference/need of such division?

> =======================================
>         #####SPI NOR chip######
> =======================================
> 
> Changes for v10:
> - Update Simon's R-B tag
> - Add mtd dm test case
> - implemented entire code wrt MTD, with interface type
> 
> code size:
> ==========
> before:
> $ arm-linux-gnueabi-size u-boot
>    text	   data	    bss	    dec
> hex	filename 473712	  15152	 222568
> 711432	  adb08	u-boot $ du -hs u-boot-dtb.img 
> 488K	u-boot-dtb.img
> 
> after:
> $ arm-linux-gnueabi-size u-boot
>    text	   data	    bss	    dec
> hex	filename 470124	  14352	 222584
> 707060	  ac9f4	u-boot $ du -hs u-boot-dtb.img 
> 484K	u-boot-dtb.img
> 
> approximately 4KiB but DM_SPI_FLASH still there which
> can be removed once support added in SPL
> 
> test log:
> ========
> Zynq> spinor  
> spinor - SPI-NOR Sub-system
> 
> Usage:
> spinor list                     - show list of spinor devices
> spinor info                     - show current spinor device info
> spinor dev [devnum]             - show or set current spinor device
> spinor erase offset len         - erase 'len' bytes from 'offset'
> spinor write addr to len        - write 'len' bytes to 'to' from
	 ^^^^^^^^^^^^^^^^ I would love to see support for "mtdparts="
	It would facilitate handling SPI-NOR "partitions" like
	u-boot/SPI/envs/ etc.

I also suppose that "sf probe" (or any its replacement with spinor)
would be not necessary to call before using other SPI-NOR related
commands?


Maybe the biggest request - would it be possible to
add ./doc/README.spi-nor entry with good explanation of this?




> 'addr' spinor read addr from len       - read 'len' bytes from 'from'
> to 'addr' spinor protect lock/unlock sector len - protect/unprotect
> 'len' bytes starting at address 'sector'
> Zynq> spinor list  
> flash at 0: 0
> spi-nor at e000d000: 1
> Zynq> spinor dev 0  
> switch to dev #0, OK
> spinor0 is current device
> Zynq> spinor info  
> bus: flash at 0: 0
> device: s25fl128s_64k
> page size: 256 B
> erase size: 64 KiB
> size: 16 MiB
> Zynq> spinor erase 0xE00000 0x100000  
> SPI-NOR: 1048576 bytes @ 0xe00000 Erased: OK
> Zynq> mw.b 0x100 0xcc 0x100000
> Zynq> spinor write 0x100 0xE00000 0x100000  
> device 0 offset 0xe00000, size 0x100000
> SPI-NOR: 1048576 bytes @ 0xe00000 Written: OK
> Zynq> spinor read 0x3000000 0xE00000 0x100000  
> device 0 offset 0xe00000, size 0x100000
> SPI-NOR: 1048576 bytes @ 0xe00000 Read: OK
> Zynq> cmp.b 0x3000000 0x100 0x100000  
> Total of 1048576 byte(s) were the same
> Zynq> spinor dev 1  
> switch to dev #1, OK
> spinor1 is current device
> Zynq> spinor info  
> bus: spi-nor at e000d000: 1
> device: s25fl128s_64k
> page size: 256 B
> erase size: 64 KiB
> size: 16 MiB
> Zynq> spinor erase 0xE00000 0x100000  
> SPI-NOR: 1048576 bytes @ 0xe00000 Erased: OK
> Zynq> mw.b 0x100 0xbb 0x100000
> Zynq> spinor write 0x100 0xE00000 0x100000  
> device 0 offset 0xe00000, size 0x100000
> SPI-NOR: 1048576 bytes @ 0xe00000 Written: OK
> Zynq> spinor read 0x3000000 0xE00000 0x100000  
> device 0 offset 0xe00000, size 0x100000
> SPI-NOR: 1048576 bytes @ 0xe00000 Read: OK
> Zynq> cmp.b 0x3000000 0x100 0x100000  
> Total of 1048576 byte(s) were the same
> 
> WIP:
> ===
> - to support non-dm code
> - to support spinor SPL
> 
> Repo:
> ====
> $ git clone git://git.denx.de/u-boot-spi.git
> $ cd u-boot-spi
> $ git checkout -b mtd-spinor-working origin/mtd-spinor-working
> 
> [1] https://lists.denx.de/pipermail/u-boot/2016-October/271459.html
> [2] http://lists.denx.de/pipermail/u-boot/2016-March/249286.html
> [3] http://lists.denx.de/pipermail/u-boot/2016-February/245418.html
> [4] [PATCH RFC v8 00/16]  SPI-NOR/MTD addition
> 
> Jagan Teki (27):
>   mtd: Add mtd core ops
>   mtd: add mtd device create operations
>   mtd: add SPI-NOR core support
>   mtd: spi-nor: sync/modify sst write operations
>   mtd: spi-nor: sync/modify lock operations
>   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
>   mtd-uclass: use platdata_auto_alloc
>   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
>   cmd: add spinor cmd support
>   cmd: spinor: sync/update protect command
>   board_r: initialize spi_nor
>   env: add spi-nor environment
>   arm: dts: zynq: Add zynq-qspinor node
>   dm: zynq: microzed: enable MTD/SPI-NOR framework
>   test: dm: add tests for mtd devices
> 
>  Makefile                             |   1 +
>  arch/arm/dts/zynq-7000.dtsi          |  12 +
>  arch/arm/dts/zynq-microzed.dts       |  12 +-
>  cmd/Kconfig                          |   5 +
>  cmd/Makefile                         |   1 +
>  cmd/nvedit.c                         |   1 +
>  cmd/spinor.c                         | 326 ++++++++++++
>  common/board_r.c                     |  13 +
>  configs/sandbox_defconfig            |   8 +-
>  configs/zynq_microzed_defconfig      |  17 +-
>  drivers/mtd/Kconfig                  |   2 +
>  drivers/mtd/Makefile                 |   7 +-
>  drivers/mtd/mtd-uclass.c             | 203 +++++++-
>  drivers/mtd/spi-nor/Kconfig          |  89 ++++
>  drivers/mtd/spi-nor/Makefile         |  15 +
>  drivers/mtd/spi-nor/m25p80.c         | 251 ++++++++++
>  drivers/mtd/spi-nor/spi-nor-ids.c    | 184 +++++++
>  drivers/mtd/spi-nor/spi-nor-uclass.c | 160 ++++++
>  drivers/mtd/spi-nor/spi-nor.c        | 940
> +++++++++++++++++++++++++++++++++++
> drivers/mtd/spi-nor/zynq_qspinor.c   | 622 +++++++++++++++++++++++
> drivers/spi/spi-uclass.c             |  24 +
> env/Kconfig                          |  27 +
> env/Makefile                         |   1 +
> env/env.c                            |   2 +
> env/spinor.c                         | 113 +++++
> include/dm/uclass-id.h               |   1 +
> include/environment.h                |   1 +
> include/linux/mtd/mtd.h              |  14 +
> include/linux/mtd/spi-nor.h          | 223 +++++++++
> include/mtd.h                        | 176 +++++++
> include/spi.h                        |  20 +
> test/dm/Makefile                     |   1 +
> test/dm/mtd.c                        |  33 ++ 33 files changed, 3493
> insertions(+), 12 deletions(-) create mode 100644 cmd/spinor.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-uclass.c
>  create mode 100644 drivers/mtd/spi-nor/spi-nor.c
>  create mode 100644 drivers/mtd/spi-nor/zynq_qspinor.c
>  create mode 100644 env/spinor.c
>  create mode 100644 include/linux/mtd/spi-nor.h
>  create mode 100644 test/dm/mtd.c
> 



Best regards,

Lukasz Majewski

--

DENX Software Engineering GmbH,      Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 488 bytes
Desc: OpenPGP digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20171228/79f7f7f9/attachment.sig>

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

* [U-Boot] [PATCH v10 03/27] mtd: add SPI-NOR core support
  2017-12-28  6:12 ` [U-Boot] [PATCH v10 03/27] mtd: add SPI-NOR core support Jagan Teki
@ 2017-12-29  9:25   ` Andy Yan
  2018-01-02 10:18   ` Prabhakar Kushwaha
                     ` (3 subsequent siblings)
  4 siblings, 0 replies; 55+ messages in thread
From: Andy Yan @ 2017-12-29  9:25 UTC (permalink / raw)
  To: u-boot

Hi Jagan:

2017-12-28 14:12 GMT+08:00 Jagan Teki <jagan@amarulasolutions.com>:

> 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/spinor.c
> =======================================
>              mtd-uclass.c
> =======================================
>            spi-nor-uclass.c
> =======================================
>               spi-nor.c
> =======================================
> m25p80.c                zynq_qspinor.c
> =======================================
> spi-uclass.c
> =======================================
> zynq_qspi.c
> =======================================
>         #####SPI NOR chip######
> =======================================
>
> Signed-off-by: Suneel Garapati <suneelglinux@gmail.com>
> Signed-off-by: Jagan Teki <jagan@amarulasolutions.com>
> ---
>  Makefile                             |   1 +
>  drivers/mtd/spi-nor/Makefile         |   7 +
>  drivers/mtd/spi-nor/spi-nor-ids.c    | 184 +++++++++++
>  drivers/mtd/spi-nor/spi-nor-uclass.c | 143 +++++++++
>  drivers/mtd/spi-nor/spi-nor.c        | 569 ++++++++++++++++++++++++++++++
> +++++
>  include/dm/uclass-id.h               |   1 +
>  include/linux/mtd/spi-nor.h          | 217 +++++++++++++
>  7 files changed, 1122 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-uclass.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 e6d309a..70b5202 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -662,6 +662,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..c1212a8
> --- /dev/null
> +++ b/drivers/mtd/spi-nor/Makefile
> @@ -0,0 +1,7 @@
> +#
> +# Copyright (C) 2016 Jagan Teki <jagan@openedev.com>
> +#
> +# SPDX-License-Identifier:     GPL-2.0+
> +
> +## spi-nor core
> +obj-y  += spi-nor.o spi-nor-uclass.o spi-nor-ids.o
> 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..db95655
> --- /dev/null
> +++ b/drivers/mtd/spi-nor/spi-nor-ids.c
> @@ -0,0 +1,184 @@
> +/*
> + * 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) },
> +       {"mx25u6435f",     INFO(0xc22537, 0x0, 64 * 1024,   128, RD_FULL |
> WR_QPP) },
> +       {"mx25l12855e",    INFO(0xc22618, 0x0, 64 * 1024,   256, RD_FULL |
> WR_QPP) },
> +       {"mx25u1635e",     INFO(0xc22535, 0x0, 64 * 1024,  32, SECT_4K) },
> +       {"mx66u51235f",    INFO(0xc2253a, 0x0, 64 * 1024,  1024, RD_FULL |
> WR_QPP) },
> +       {"mx66l1g45g",     INFO(0xc2201b, 0x0, 64 * 1024,  2048, 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,    32, 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) },
> +       {"s25fs256s_64k",  INFO6(0x010219, 0x4d0181, 64 * 1024, 512,
> RD_FULL | WR_QPP | SECT_4K) },
> +       {"s25fl256s_64k",  INFO(0x010219, 0x4d01,  64 * 1024,   512,
> RD_FULL | WR_QPP) },
> +       {"s25fs512s",      INFO6(0x010220, 0x4d0081, 128 * 1024, 512,
> RD_FULL | WR_QPP | SECT_4K) },
> +       {"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) },
> +       {"mt25qu02g",      INFO(0x20bb22, 0x0,  64 * 1024,  4096, RD_FULL
> | WR_QPP | E_FSR | SECT_4K) },
> +       {"mt25ql02g",      INFO(0x20ba22, 0x0,  64 * 1024,  4096, RD_FULL
> | WR_QPP | E_FSR | SECT_4K) },
> +       {"mt35xu512g",     INFO6(0x2c5b1a, 0x104100,  128 * 1024,  512,
> 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 */
> +       {"is25lq040b",     INFO(0x9d4013, 0x0, 64 * 1024,     8, 0) },
> +       {"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-uclass.c
> b/drivers/mtd/spi-nor/spi-nor-uclass.c
> new file mode 100644
> index 0000000..919682d
> --- /dev/null
> +++ b/drivers/mtd/spi-nor/spi-nor-uclass.c
> @@ -0,0 +1,143 @@
> +/*
> + * 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 <mtd.h>
> +
> +#include <dm/device-internal.h>
> +#include <linux/mtd/spi-nor.h>
> +
> +DECLARE_GLOBAL_DATA_PTR;
> +
> +struct spi_nor *spi_nor_get_spi_nor_dev(struct udevice *dev)
> +{
> +       struct spi_nor_uclass_priv *upriv;
> +
> +       if (!device_active(dev))
> +               return NULL;
> +       upriv = dev_get_uclass_priv(dev);
> +       return upriv->spi_nor;
> +}
> +
> +struct spi_nor *find_spi_nor_device(int dev_num)
> +{
> +       struct udevice *dev, *spi_nor_dev;
> +       int ret;
> +
> +       ret = mtd_find_device(MTD_IF_TYPE_SPI_NOR, dev_num, &dev);
> +       if (ret) {
> +               printf("SPI-NOR Device %d not found\n", dev_num);
> +               return NULL;
> +       }
> +
> +       spi_nor_dev = dev_get_parent(dev);
> +
> +       struct spi_nor *nor = spi_nor_get_spi_nor_dev(spi_nor_dev);
> +
> +       return nor;
> +}
> +
> +int get_spi_nor_num(void)
> +{
> +       return max((mtd_find_max_devnum(MTD_IF_TYPE_SPI_NOR) + 1), 0);
> +}
> +
> +struct mtd_info *spi_nor_get_mtd_info(struct spi_nor *nor)
> +{
> +       struct mtd_info *mtd;
> +       struct udevice *dev;
> +
> +       device_find_first_child(nor->dev, &dev);
> +       if (!dev)
> +               return NULL;
> +       mtd = dev_get_uclass_platdata(dev);
> +
> +       return mtd;
> +}
> +
> +void print_spi_nor_devices(char separator)
> +{
> +       struct udevice *dev;
> +       bool first = true;
> +
> +       for (uclass_first_device(UCLASS_SPI_NOR, &dev);
> +            dev;
> +            uclass_next_device(&dev), first = false) {
> +               struct spi_nor *nor = spi_nor_get_spi_nor_dev(dev);
> +
> +               if (!first) {
> +                       printf("%c", separator);
> +                       if (separator != '\n')
> +                               puts(" ");
> +               }
> +
> +               printf("%s: %d", dev->name, spi_nor_get_mtd_info(nor)->
> devnum);
> +       }
> +
> +       printf("\n");
> +}
> +
> +int spi_nor_bind(struct udevice *dev, struct spi_nor *nor)
> +{
> +       struct udevice *mdev;
> +       int ret;
> +
> +       if (!spi_nor_get_ops(dev))
> +               return -ENOSYS;
> +
> +       ret = mtd_create_devicef(dev, "spinor_mtd", "mtd",
> MTD_IF_TYPE_SPI_NOR,
> +                                &mdev);
> +       if (ret) {
> +               debug("Cannot create mtd device\n");
> +               return ret;
> +       }
> +       nor->dev = dev;
> +
> +       return 0;
> +}
> +
> +static int spi_nor_mtd_probe(struct udevice *dev)
> +{
> +       struct udevice *spi_nor_dev = dev_get_parent(dev);
> +       struct spi_nor_uclass_priv *upriv = dev_get_uclass_priv(spi_nor_
> dev);
> +       struct spi_nor *nor = upriv->spi_nor;
> +       int ret;
> +
> +       ret = spi_nor_scan(nor);
> +       if (ret) {
> +               debug("%s: spi_nor_scan() failed (err=%d)\n", __func__,
> ret);
> +               return ret;
> +       }
> +
> +       return 0;
> +}
> +
> +static const struct mtd_ops spi_nor_mtd_ops = {
> +       .read   = spi_nor_mread,
> +       .erase  = spi_nor_merase,
> +};
> +
> +U_BOOT_DRIVER(spinor_mtd) = {
> +       .name           = "spinor_mtd",
> +       .id             = UCLASS_MTD,
> +       .ops            = &spi_nor_mtd_ops,
> +       .probe          = spi_nor_mtd_probe,
> +};
> +
> +U_BOOT_DRIVER(spinor) = {
> +       .name   = "spinor",
> +       .id     = UCLASS_SPI_NOR,
> +};
> +
> +UCLASS_DRIVER(spinor) = {
> +       .id             = UCLASS_SPI_NOR,
> +       .name           = "spinor",
> +       .flags          = DM_UC_FLAG_SEQ_ALIAS,
> +       .per_device_auto_alloc_size = sizeof(struct spi_nor_uclass_priv),
> +};
> diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
> new file mode 100644
> index 0000000..09fb8ca
> --- /dev/null
> +++ b/drivers/mtd/spi-nor/spi-nor.c
> @@ -0,0 +1,569 @@
> +/*
> + * 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 <dm/device-internal.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 udevice *dev)
> +{
> +       return spi_nor_get_ops(dev)->write_reg(dev, SNOR_OP_WREN, NULL,
> 0);
> +}
> +
> +/* Re-set write enable latch with Write Disable command */
> +static inline int write_disable(struct udevice *dev)
> +{
> +       return spi_nor_get_ops(dev)->write_reg(dev, SNOR_OP_WRDI, NULL,
> 0);
> +}
> +
> +static int read_sr(struct udevice *dev)
> +{
> +       u8 sr;
> +       int ret;
> +
> +       ret = spi_nor_get_ops(dev)->read_reg(dev, 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 udevice *dev)
> +{
> +       u8 fsr;
> +       int ret;
> +
> +       ret = spi_nor_get_ops(dev)->read_reg(dev, 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 udevice *dev, u8 ws)
> +{
> +       struct spi_nor *nor = spi_nor_get_spi_nor_dev(dev);
> +       const struct spi_nor_ops *ops = spi_nor_get_ops(dev);
> +
> +       nor->cmd_buf[0] = ws;
> +       return ops->write_reg(dev, SNOR_OP_WRSR, nor->cmd_buf, 1);
> +}
> +
> +#if defined(CONFIG_SPI_NOR_SPANSION) || defined(CONFIG_SPI_NOR_WINBOND)
> +static int read_cr(struct udevice *dev)
> +{
> +       u8 cr;
> +       int ret;
> +
> +       ret = spi_nor_get_ops(dev)->read_reg(dev, 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.
>

     s/occured/occurred



> + */
> +static int write_sr_cr(struct udevice *dev, u16 val)
> +{
> +       struct spi_nor *nor = spi_nor_get_spi_nor_dev(dev);
> +       const struct spi_nor_ops *ops = spi_nor_get_ops(dev);
> +
> +       nor->cmd_buf[0] = val & 0xff;
> +       nor->cmd_buf[1] = (val >> 8);
> +
> +       return ops->write_reg(dev, SNOR_OP_WRSR, nor->cmd_buf, 2);
> +}
> +#endif
> +
> +static int spi_nor_sr_ready(struct udevice *dev)
> +{
> +       int sr = read_sr(dev);
> +       if (sr < 0)
> +               return sr;
> +       else
> +               return !(sr & SR_WIP);
> +}
> +
> +static int spi_nor_fsr_ready(struct udevice *dev)
> +{
> +       int fsr = read_fsr(dev);
> +       if (fsr < 0)
> +               return fsr;
> +       else
> +               return fsr & FSR_READY;
> +}
> +
> +static int spi_nor_ready(struct udevice *dev)
> +{
> +       struct spi_nor *nor = spi_nor_get_spi_nor_dev(dev);
> +       int sr, fsr;
> +
> +       sr = spi_nor_sr_ready(dev);
> +       if (sr < 0)
> +               return sr;
> +
> +       fsr = 1;
> +       if (nor->flags & SNOR_F_USE_FSR) {
> +               fsr = spi_nor_fsr_ready(dev);
> +               if (fsr < 0)
> +                       return fsr;
> +       }
> +
> +       return sr && fsr;
> +}
> +
> +static int spi_nor_wait_till_ready(struct udevice *dev, unsigned long
> timeout)
> +{
> +       int timebase, ret;
> +
> +       timebase = get_timer(0);
> +
> +       while (get_timer(timebase) < timeout) {
> +               ret = spi_nor_ready(dev);
> +               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 udevice *dev)
> +{
> +       int                             tmp;
> +       u8                              id[SPI_NOR_MAX_ID_LEN];
> +       const struct spi_nor_info       *info;
> +       const struct spi_nor_ops        *ops = spi_nor_get_ops(dev);
> +
> +       tmp = ops->read_reg(dev, 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);
> +}
> +
> +int spi_nor_merase(struct udevice *dev, struct erase_info *instr)
> +{
> +       struct mtd_info *mtd = dev_get_uclass_platdata(dev);
> +       int devnum = mtd->devnum;
> +       struct spi_nor *nor;
> +       const struct spi_nor_ops *ops;
> +       u32 addr, len, erase_addr;
> +       uint32_t rem;
> +       int ret = -1;
> +
> +       nor = find_spi_nor_device(devnum);
> +       if (!nor)
> +               return -ENODEV;
> +       ops = spi_nor_get_ops(nor->dev);
> +
> +       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->dev);
> +
> +               ret = ops->write(nor->dev, erase_addr, 0, NULL);
> +               if (ret < 0)
> +                       goto erase_err;
> +
> +               ret = spi_nor_wait_till_ready(nor->dev,
> SNOR_READY_WAIT_ERASE);
> +               if (ret < 0)
> +                       goto erase_err;
> +
> +               addr += mtd->erasesize;
> +               len -= mtd->erasesize;
> +       }
> +
> +       write_disable(nor->dev);
> +
> +       instr->state = MTD_ERASE_DONE;
> +       mtd_erase_callback(instr);
> +
> +       return ret;
> +
> +erase_err:
> +       instr->state = MTD_ERASE_FAILED;
> +       return ret;
> +}
> +
> +static int spi_nor_mwrite(struct udevice *dev, loff_t to, size_t len,
> +                         size_t *retlen, const u_char *buf)
> +{
> +       struct mtd_info *mtd = dev_get_uclass_platdata(dev);
> +       int devnum = mtd->devnum;
> +       struct spi_nor *nor;
> +       const struct spi_nor_ops *ops;
> +       size_t addr, byte_addr;
> +       size_t chunk_len, actual;
> +       uint32_t page_size;
> +       int ret = -1;
> +
> +       nor = find_spi_nor_device(devnum);
> +       if (!nor)
> +               return -ENODEV;
> +       ops = spi_nor_get_ops(nor->dev);
> +
> +       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->dev);
> +
> +               ret = ops->write(nor->dev, addr, chunk_len, buf + actual);
> +               if (ret < 0)
> +                       break;
> +
> +               ret = spi_nor_wait_till_ready(nor->dev,
> SNOR_READY_WAIT_PROG);
> +               if (ret < 0)
> +                       return ret;
> +
> +               to += chunk_len;
> +               *retlen += chunk_len;
> +       }
> +
> +       return ret;
> +}
> +
> +int spi_nor_mread(struct udevice *dev, loff_t from, size_t len,
> +                 size_t *retlen, u_char *buf)
> +{
> +       struct mtd_info *mtd = dev_get_uclass_platdata(dev);
> +       int devnum = mtd->devnum;
> +       struct spi_nor *nor;
> +       const struct spi_nor_ops *ops;
> +       int ret;
> +
> +       nor = find_spi_nor_device(devnum);
> +       if (!nor)
> +               return -ENODEV;
> +       ops = spi_nor_get_ops(nor->dev);
> +
> +       /* Handle memory-mapped SPI */
> +       if (nor->memory_map) {
> +               ret = ops->read(nor->dev, from, len, buf);
> +               if (ret) {
> +                       debug("spi-nor: mmap read failed\n");
> +                       return ret;
> +               }
> +
> +               return ret;
> +       }
> +
> +       ret = ops->read(nor->dev, from, len, buf);
> +       if (ret < 0) {
> +               printf("%s ret = %d\n", __func__, ret);
> +               return ret;
> +       }
> +
> +       *retlen += len;
> +
> +       return ret;
> +}
> +
> +#ifdef CONFIG_SPI_NOR_MACRONIX
> +static int macronix_quad_enable(struct udevice *dev)
> +{
> +       int ret, val;
> +
> +       val = read_sr(dev);
> +       if (val < 0)
> +               return val;
> +
> +       if (val & SR_QUAD_EN_MX)
> +               return 0;
> +
> +       write_enable(dev);
> +
> +       ret = write_sr(dev, val | SR_QUAD_EN_MX);
> +       if (ret < 0)
> +               return ret;
> +
> +       if (spi_nor_wait_till_ready(dev, SNOR_READY_WAIT_PROG))
> +               return 1;
> +
> +       ret = read_sr(dev);
> +       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 udevice *dev)
> +{
> +       int ret, val;
> +
> +       val = read_cr(dev);
> +       if (val < 0)
> +               return val;
> +
> +       if (val & CR_QUAD_EN_SPAN)
> +               return 0;
> +
> +       write_enable(dev);
> +
> +       ret = write_sr_cr(dev, val | CR_QUAD_EN_SPAN);
> +       if (ret < 0)
> +               return ret;
> +
> +       if (spi_nor_wait_till_ready(dev, SNOR_READY_WAIT_PROG))
> +               return 1;
> +
> +       /* read back and check it */
> +       ret = read_cr(dev);
> +       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 udevice *dev, const struct spi_nor_info
> *info)
> +{
> +       switch (JEDEC_MFR(info)) {
> +#ifdef CONFIG_SPI_NOR_MACRONIX
> +       case SNOR_MFR_MACRONIX:
> +               return macronix_quad_enable(dev);
> +#endif
> +#if defined(CONFIG_SPI_NOR_SPANSION) || defined(CONFIG_SPI_NOR_WINBOND)
> +       case SNOR_MFR_SPANSION:
> +       case SNOR_MFR_WINBOND:
> +               return spansion_quad_enable(dev);
> +#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) */
> +
> +int spi_nor_scan(struct spi_nor *nor)
> +{
> +       struct mtd_info *mtd = spi_nor_get_mtd_info(nor);
> +       struct mtd_ops *ops = mtd_get_ops(mtd->dev);
> +       const struct spi_nor_info *info = NULL;
> +       int ret;
> +
> +       struct spi_nor_uclass_priv *upriv = dev_get_uclass_priv(nor->dev);
> +       upriv->spi_nor = nor;
> +
> +       if (nor->init_done)
> +               return 0;
> +
>

     trailing whitespace


+       info = spi_nor_id(nor->dev);
> +       if (IS_ERR_OR_NULL(info)) {
> +               ret = -ENOENT;
> +               goto err;
> +       }
> +
> +       /*
> +        * Flash powers up read-only, so clear BP# bits.
> +        *
> +        * Note on some flash (like Macronix), QE (quad enable) bit is in
> the
> +        * same status register as BP# bits, and we need preserve its
> original
> +        * value during a reboot cycle as this is required by some
> platforms
> +        * (like Intel ICH SPI controller working under descriptor mode).
> +        */
> +       if (JEDEC_MFR(info) == SNOR_MFR_ATMEL ||
> +          (JEDEC_MFR(info) == SNOR_MFR_SST) ||
> +          (JEDEC_MFR(info) == SNOR_MFR_MACRONIX)) {
> +               u8 sr = 0;
> +
> +               if (JEDEC_MFR(info) == SNOR_MFR_MACRONIX)
> +                       sr = read_sr(nor->dev) & SR_QUAD_EN_MX;
> +               write_sr(nor->dev, sr);
> +       }
> +
> +       mtd->name = info->name;
> +       mtd->priv = nor;
> +       mtd->type = MTD_NORFLASH;
> +       mtd->writesize = 1;
> +       mtd->flags = MTD_CAP_NORFLASH;
> +
> +       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_mwrite;
> +
> +       /* 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->dev, info);
> +               if (ret) {
> +                       debug("spi-nor: quad mode not supported for
> %02x\n",
> +                             JEDEC_MFR(info));
> +                       goto err;
> +               }
> +       }
> +
> +       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");
> +               goto err;
> +       }
> +#endif
> +
> +       nor->init_done = 1;
> +       return 0;
> +err:
>

trailing whitespace



> +       nor->init_done = 0;
> +       return ret;
> +}
> diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h
> index 3fc2083..06541a4 100644
> --- a/include/dm/uclass-id.h
> +++ b/include/dm/uclass-id.h
> @@ -75,6 +75,7 @@ enum uclass_id {
>         UCLASS_SERIAL,          /* Serial UART */
>         UCLASS_SPI,             /* SPI bus */
>         UCLASS_SPMI,            /* System Power Management Interface bus */
> +       UCLASS_SPI_NOR,         /* SPI NOR flash */
>         UCLASS_SPI_FLASH,       /* SPI flash */
>         UCLASS_SPI_GENERIC,     /* Generic SPI flash target */
>         UCLASS_SYSCON,          /* System configuration device */
> diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
> new file mode 100644
> index 0000000..e1688e2
> --- /dev/null
> +++ b/include/linux/mtd/spi-nor.h
> @@ -0,0 +1,217 @@
> +/*
> + * 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>
> +#include <linux/mtd/mtd.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
> +
> +/**
> + * struct spi_nor_uclass_priv - Holds information about a device used by
> the uclass
> + */
> +struct spi_nor_uclass_priv {
> +       struct spi_nor *spi_nor;
> +};
> +
> +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
> + */
> +struct spi_nor {
> +       struct udevice          *dev;
> +       const char              *name;
> +       u8                      init_done;
> +       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];
> +
> +       void *memory_map;
> +};
> +
> +struct spi_nor_ops {
> +       int (*read_reg)(struct udevice *dev, u8 cmd, u8 *val, int len);
> +       int (*write_reg)(struct udevice *dev, u8 cmd, u8 *data, int len);
> +
> +       int (*read)(struct udevice *dev, loff_t from, size_t len,
> +                   u_char *buf);
> +       int (*write)(struct udevice *dev, loff_t to, size_t len,
> +                    const u_char *buf);
> +};
> +
> +#define spi_nor_get_ops(dev)   ((struct spi_nor_ops *)(dev)->driver->ops)
> +
> +int spi_nor_merase(struct udevice *dev, struct erase_info *instr);
> +int spi_nor_mread(struct udevice *dev, loff_t from, size_t len,
> +                 size_t *retlen, u_char *buf);
> +
> +int spi_nor_scan(struct spi_nor *nor);
> +int spi_nor_bind(struct udevice *dev, struct spi_nor *nor);
> +
> +struct spi_nor *find_spi_nor_device(int dev_num);
> +int get_spi_nor_num(void);
> +struct spi_nor *spi_nor_get_spi_nor_dev(struct udevice *dev);
> +struct mtd_info *spi_nor_get_mtd_info(struct spi_nor *nor);
> +
> +#endif /* __MTD_SPI_NOR_H */
> --
> 2.7.4
>
> _______________________________________________
> U-Boot mailing list
> U-Boot at lists.denx.de
> https://lists.denx.de/listinfo/u-boot
>

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

* [U-Boot] [PATCH v10 00/27] dm: Generic MTD Subsystem, with SPI-NOR interface
  2017-12-28 14:44 ` [U-Boot] [PATCH v10 00/27] dm: Generic MTD Subsystem, with SPI-NOR interface Lukasz Majewski
@ 2018-01-02 10:09   ` Jagan Teki
  2018-01-03  8:48     ` Vignesh R
  2018-01-23  9:50     ` Siva Durga Prasad Paladugu
  0 siblings, 2 replies; 55+ messages in thread
From: Jagan Teki @ 2018-01-02 10:09 UTC (permalink / raw)
  To: u-boot

On Thu, Dec 28, 2017 at 8:14 PM, Lukasz Majewski <lukma@denx.de> wrote:
> Hi Jagan,
>
>> Compared to previous series’s [1], [2], [3] and [4] this patch set
>> redefined most of the implementation suitable to fit into existing
>> driver-model.
>>
>> MTD is generic subsystem for underlying flash devices like nand,
>> parallel nor, spinor, dataflash etc. So to drive this theory with
>> driver model(with an example of block layer) mtd is common device
>> interaction for most of  memory technology flashes like nand,
>> parallel nor, spinor, dataflash etc, these are treated as interface
>> types wrt u-boot driver model.
>>
>> Once the respective interface driver bind happen, the uclass driver
>> will pass an 'interface type' to mtd layer to create device for it,
>> for example once spinor ULASS_SPI_NOR driver bind happen,
>> the uclass driver of spinor will pass MTD_IF_TYPE_SPI_NOR
>> interface type to create mtd device for spinor devices.
>>
>> SPI-NOR:
>> =======
>> 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.
>
> I must admit that I'm a bit confused....
>
> If you don't mind I would like to ask for clarification of a few things:
>
>
>
>>
>> =======================================
>>              cmd/spinor.c
>
>                 ^^^^^ - this would be a new set of commands to comply
>                 with DM?

with this series yes, and we're working on supporting the same with non-dm.

>
>                 What about "sf" command which we use now to get access
>                 to SPI-NOR memory? A lot of boards already use "sf"
>                 command... which may be tricky to replace.

end-goal will be replace sf with spinor command and removal of 'sf'
will be done when the new spi-nor framework stable enough to handle
all scenarios which are spi-flash supporting as of now.

>
>> =======================================
>>              mtd-uclass.c
>                 ^^^^^ - here we will have a generic MTD layer (as it is
>                 in Linux)

it is not like in Linux, leaving ops names apart all the code is for
creating mtd device for underlying flash devices in the form of
interface type during bind. the interface types as of now is spi-nor
it can be nand, nor, dataflash etc in future if could be.

>
>> =======================================
>>            spi-nor-uclass.c
>> =======================================
>>               spi-nor.c
>                 ^^^^^^ - why do we need to have spi-nor.c ? Cannot we
>                 have its functionality in the spi-nor-uclass.c ?
>                 (I'm just curious)

spi-nor-uclass.c is an uclass driver for underlying UCLASS_SPI_NOR
drivers like m25p80, zynq_qspinor etc but the spi-nor.c is the actual
spi-nor core code which handle actual flash specific stuff. and also
syncing Linux stuff(if require) becomes easy with spi-nor.c as a
separate file.

>
>> =======================================
>> m25p80.c                zynq_qspinor.c
>   ^^^^^ - this is the     ^^^^^^^^ - [*]
> "generic" spi-nor
> driver used in Linux.
> I suppose that it will
> be reused here?

yes - name reused because, I do think the Linux and U-Boot development
on spi-nor will follow in-line at some point but the most of code is
following U-Boot driver-model.

>
>> =======================================
>> spi-uclass.c
>   ^^^^^^^ - why do we
> need this uclass?

This is an existing uclass spi driver for underlying UCLASS_SPI
drivers like drivers/spi/zynq_qspi.c etc

>
>> =======================================
>> zynq_qspi.c
>  ^^^^^ - This is probably
> the low-level driver for
> zynq QSPI IP block - why
> do we have zynq_qspinor.c file above [*]?
> What is the difference/need of such division?

Both the drivers are same, the reason for zynq_qspinor is for testing
framework work for two directions like
- spi driver interface side through m25p80
cmd/spinor->mtd->spi-nor-uclass->spi-nor->m25p80->zynq_qspi.c
- direct spi-nor controller side
spinor->mtd->spi-nor-uclass->spi-nor->zynq_qspinor

Will remove drivers/spi/zynq_qspi.c once all set.

Jagan.

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

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

* [U-Boot] [PATCH v10 03/27] mtd: add SPI-NOR core support
  2017-12-28  6:12 ` [U-Boot] [PATCH v10 03/27] mtd: add SPI-NOR core support Jagan Teki
  2017-12-29  9:25   ` Andy Yan
@ 2018-01-02 10:18   ` Prabhakar Kushwaha
  2018-01-02 10:31     ` Jagan Teki
  2018-01-03  8:49   ` Vignesh R
                     ` (2 subsequent siblings)
  4 siblings, 1 reply; 55+ messages in thread
From: Prabhakar Kushwaha @ 2018-01-02 10:18 UTC (permalink / raw)
  To: u-boot

Hi Jagan,


> -----Original Message-----
> From: U-Boot [mailto:u-boot-bounces at lists.denx.de] On Behalf Of Jagan Teki
> Sent: Thursday, December 28, 2017 11:42 AM
> To: u-boot at lists.denx.de
> Cc: Tom Rini <trini@konsulko.com>
> Subject: [U-Boot] [PATCH v10 03/27] mtd: add SPI-NOR core support
> 
> 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/spinor.c
> =======================================
>              mtd-uclass.c
> =======================================
>            spi-nor-uclass.c
> =======================================
>               spi-nor.c
> =======================================
> m25p80.c                zynq_qspinor.c
> =======================================
> spi-uclass.c
> =======================================
> zynq_qspi.c
> =======================================
>         #####SPI NOR chip######
> =======================================
> 

<snip>


> + * SPDX-License-Identifier:	GPL-2.0+
> + */
> +
> +#include <common.h>
> +#include <dm.h>
> +#include <errno.h>
> +#include <mapmem.h>
> +#include <mtd.h>
> +
> +#include <dm/device-internal.h>
> +#include <linux/math64.h>
> +#include <linux/types.h>
> +#include <linux/mtd/spi-nor.h>
> +
> +int spi_nor_scan(struct spi_nor *nor)
> +{
> +	struct mtd_info *mtd = spi_nor_get_mtd_info(nor);
> +	struct mtd_ops *ops = mtd_get_ops(mtd->dev);
> +	const struct spi_nor_info *info = NULL;
> +	int ret;
> +
> +	struct spi_nor_uclass_priv *upriv = dev_get_uclass_priv(nor->dev);
> +	upriv->spi_nor = nor;
> +
> +	if (nor->init_done)
> +		return 0;
> +
> +	info = spi_nor_id(nor->dev);
> +	if (IS_ERR_OR_NULL(info)) {
> +		ret = -ENOENT;
> +		goto err;
> +	}
> +
> +	/*
> +	 * Flash powers up read-only, so clear BP# bits.
> +	 *
> +	 * Note on some flash (like Macronix), QE (quad enable) bit is in the
> +	 * same status register as BP# bits, and we need preserve its original
> +	 * value during a reboot cycle as this is required by some platforms
> +	 * (like Intel ICH SPI controller working under descriptor mode).
> +	 */
> +	if (JEDEC_MFR(info) == SNOR_MFR_ATMEL ||
> +	   (JEDEC_MFR(info) == SNOR_MFR_SST) ||
> +	   (JEDEC_MFR(info) == SNOR_MFR_MACRONIX)) {
> +		u8 sr = 0;
> +
> +		if (JEDEC_MFR(info) == SNOR_MFR_MACRONIX)
> +			sr = read_sr(nor->dev) & SR_QUAD_EN_MX;
> +		write_sr(nor->dev, sr);
> +	}
> +
> +	mtd->name = info->name;
> +	mtd->priv = nor;
> +	mtd->type = MTD_NORFLASH;
> +	mtd->writesize = 1;
> +	mtd->flags = MTD_CAP_NORFLASH;
> +
> +	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_mwrite;
> +
> +	/* 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;
> +

Are you planning to store read_protocol i.e. 1-1-1. 1-1-2, 1-4-4, 4-4-4 etc information in nor structure?
It will help low level controller driver to configure number of lines to be used during read in instruction, address and data phase. 

Similar framework is present in Linux. 

struct spi_nor  :
* @read_proto:		the SPI protocol for read operations
 * @write_proto:	the SPI protocol for write operations
 * @reg_proto		the SPI protocol for read_reg/write_reg/erase operations


--pk

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

* [U-Boot] [PATCH v10 03/27] mtd: add SPI-NOR core support
  2018-01-02 10:18   ` Prabhakar Kushwaha
@ 2018-01-02 10:31     ` Jagan Teki
  0 siblings, 0 replies; 55+ messages in thread
From: Jagan Teki @ 2018-01-02 10:31 UTC (permalink / raw)
  To: u-boot

On Tue, Jan 2, 2018 at 3:48 PM, Prabhakar Kushwaha
<prabhakar.kushwaha@nxp.com> wrote:
> Hi Jagan,
>
>
>> -----Original Message-----
>> From: U-Boot [mailto:u-boot-bounces at lists.denx.de] On Behalf Of Jagan Teki
>> Sent: Thursday, December 28, 2017 11:42 AM
>> To: u-boot at lists.denx.de
>> Cc: Tom Rini <trini@konsulko.com>
>> Subject: [U-Boot] [PATCH v10 03/27] mtd: add SPI-NOR core support
>>
>> 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/spinor.c
>> =======================================
>>              mtd-uclass.c
>> =======================================
>>            spi-nor-uclass.c
>> =======================================
>>               spi-nor.c
>> =======================================
>> m25p80.c                zynq_qspinor.c
>> =======================================
>> spi-uclass.c
>> =======================================
>> zynq_qspi.c
>> =======================================
>>         #####SPI NOR chip######
>> =======================================
>>
>
> <snip>
>
>
>> + * SPDX-License-Identifier:  GPL-2.0+
>> + */
>> +
>> +#include <common.h>
>> +#include <dm.h>
>> +#include <errno.h>
>> +#include <mapmem.h>
>> +#include <mtd.h>
>> +
>> +#include <dm/device-internal.h>
>> +#include <linux/math64.h>
>> +#include <linux/types.h>
>> +#include <linux/mtd/spi-nor.h>
>> +
>> +int spi_nor_scan(struct spi_nor *nor)
>> +{
>> +     struct mtd_info *mtd = spi_nor_get_mtd_info(nor);
>> +     struct mtd_ops *ops = mtd_get_ops(mtd->dev);
>> +     const struct spi_nor_info *info = NULL;
>> +     int ret;
>> +
>> +     struct spi_nor_uclass_priv *upriv = dev_get_uclass_priv(nor->dev);
>> +     upriv->spi_nor = nor;
>> +
>> +     if (nor->init_done)
>> +             return 0;
>> +
>> +     info = spi_nor_id(nor->dev);
>> +     if (IS_ERR_OR_NULL(info)) {
>> +             ret = -ENOENT;
>> +             goto err;
>> +     }
>> +
>> +     /*
>> +      * Flash powers up read-only, so clear BP# bits.
>> +      *
>> +      * Note on some flash (like Macronix), QE (quad enable) bit is in the
>> +      * same status register as BP# bits, and we need preserve its original
>> +      * value during a reboot cycle as this is required by some platforms
>> +      * (like Intel ICH SPI controller working under descriptor mode).
>> +      */
>> +     if (JEDEC_MFR(info) == SNOR_MFR_ATMEL ||
>> +        (JEDEC_MFR(info) == SNOR_MFR_SST) ||
>> +        (JEDEC_MFR(info) == SNOR_MFR_MACRONIX)) {
>> +             u8 sr = 0;
>> +
>> +             if (JEDEC_MFR(info) == SNOR_MFR_MACRONIX)
>> +                     sr = read_sr(nor->dev) & SR_QUAD_EN_MX;
>> +             write_sr(nor->dev, sr);
>> +     }
>> +
>> +     mtd->name = info->name;
>> +     mtd->priv = nor;
>> +     mtd->type = MTD_NORFLASH;
>> +     mtd->writesize = 1;
>> +     mtd->flags = MTD_CAP_NORFLASH;
>> +
>> +     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_mwrite;
>> +
>> +     /* 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;
>> +
>
> Are you planning to store read_protocol i.e. 1-1-1. 1-1-2, 1-4-4, 4-4-4 etc information in nor structure?
> It will help low level controller driver to configure number of lines to be used during read in instruction, address and data phase.
>
> Similar framework is present in Linux.
>
> struct spi_nor  :
> * @read_proto:          the SPI protocol for read operations
>  * @write_proto:        the SPI protocol for write operations
>  * @reg_proto           the SPI protocol for read_reg/write_reg/erase operations

ok try these and mention code sizes for the same.

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

* [U-Boot] [PATCH v10 00/27] dm: Generic MTD Subsystem, with SPI-NOR interface
  2018-01-02 10:09   ` Jagan Teki
@ 2018-01-03  8:48     ` Vignesh R
  2018-01-03  9:24       ` Jagan Teki
  2018-01-23  9:50     ` Siva Durga Prasad Paladugu
  1 sibling, 1 reply; 55+ messages in thread
From: Vignesh R @ 2018-01-03  8:48 UTC (permalink / raw)
  To: u-boot



On Tuesday 02 January 2018 03:39 PM, Jagan Teki wrote:
> On Thu, Dec 28, 2017 at 8:14 PM, Lukasz Majewski <lukma@denx.de> wrote:
>> Hi Jagan,
>>
>>> Compared to previous series’s [1], [2], [3] and [4] this patch set
>>> redefined most of the implementation suitable to fit into existing
>>> driver-model.
>>>
>>> MTD is generic subsystem for underlying flash devices like nand,
>>> parallel nor, spinor, dataflash etc. So to drive this theory with
>>> driver model(with an example of block layer) mtd is common device
>>> interaction for most of  memory technology flashes like nand,
>>> parallel nor, spinor, dataflash etc, these are treated as interface
>>> types wrt u-boot driver model.
>>>
>>> Once the respective interface driver bind happen, the uclass driver
>>> will pass an 'interface type' to mtd layer to create device for it,
>>> for example once spinor ULASS_SPI_NOR driver bind happen,
>>> the uclass driver of spinor will pass MTD_IF_TYPE_SPI_NOR
>>> interface type to create mtd device for spinor devices.
>>>
>>> SPI-NOR:
>>> =======
>>> 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.
>>
>> I must admit that I'm a bit confused....
>>
>> If you don't mind I would like to ask for clarification of a few things:
>>
>>
>>
>>>
>>> =======================================
>>>              cmd/spinor.c
>>
>>                 ^^^^^ - this would be a new set of commands to comply
>>                 with DM?
> 
> with this series yes, and we're working on supporting the same with non-dm.
> 
>>
>>                 What about "sf" command which we use now to get access
>>                 to SPI-NOR memory? A lot of boards already use "sf"
>>                 command... which may be tricky to replace.
> 
> end-goal will be replace sf with spinor command and removal of 'sf'
> will be done when the new spi-nor framework stable enough to handle
> all scenarios which are spi-flash supporting as of now.

I don't agree on adding new cmd and removing sf. It would be impractical
to change all boot cmds to replace sf with spinor cmd all over U-Boot.
Not to forget the envs already stored on non volatile media need
updation to work with new cmd.
If SPI NOR framework is to abstract all accesses to nor flash devices in
U-Boot, then why cannot it replace the logic implementing cmd sf? All
that is changing is that mtd/spi/* is replaced by spi-nor.c + m25p80.c.
sf probe  can be modified achieve what spinor dev does
sf read for spinor read and so on. Board configs would just need to
enable MTD related configs.



-- 
Regards
Vignesh

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

* [U-Boot] [PATCH v10 03/27] mtd: add SPI-NOR core support
  2017-12-28  6:12 ` [U-Boot] [PATCH v10 03/27] mtd: add SPI-NOR core support Jagan Teki
  2017-12-29  9:25   ` Andy Yan
  2018-01-02 10:18   ` Prabhakar Kushwaha
@ 2018-01-03  8:49   ` Vignesh R
  2018-01-03  9:32     ` Jagan Teki
  2018-01-04  2:33   ` Andy Yan
  2018-02-28  9:42   ` Prabhakar Kushwaha
  4 siblings, 1 reply; 55+ messages in thread
From: Vignesh R @ 2018-01-03  8:49 UTC (permalink / raw)
  To: u-boot



On Thursday 28 December 2017 11:42 AM, Jagan Teki wrote:
[...]
> +static const struct mtd_ops spi_nor_mtd_ops = {
> +	.read	= spi_nor_mread,
> +	.erase	= spi_nor_merase,
> +};
> +

Wondering why spi_nor_mwrite is not hooked up here?

> +U_BOOT_DRIVER(spinor_mtd) = {
> +	.name		= "spinor_mtd",
> +	.id		= UCLASS_MTD,
> +	.ops		= &spi_nor_mtd_ops,
> +	.probe		= spi_nor_mtd_probe,
> +};
> +
> +U_BOOT_DRIVER(spinor) = {
> +	.name	= "spinor",
> +	.id	= UCLASS_SPI_NOR,
> +};
> +
> +UCLASS_DRIVER(spinor) = {
> +	.id		= UCLASS_SPI_NOR,
> +	.name		= "spinor",
> +	.flags		= DM_UC_FLAG_SEQ_ALIAS,
> +	.per_device_auto_alloc_size = sizeof(struct spi_nor_uclass_priv),
> +};

[...]

> diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
> new file mode 100644
> index 0000000..e1688e2
> --- /dev/null
> +++ b/include/linux/mtd/spi-nor.h
> @@ -0,0 +1,217 @@
[...]
> +struct spi_nor {
> +	struct udevice		*dev;
> +	const char		*name;
> +	u8			init_done;
> +	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;

Where is this field used? Shouldn't this field carry single/dual/quad
mode information?

> +	u8			cmd_buf[SNOR_MAX_CMD_SIZE];
> +
> +	void *memory_map;
> +};
> +
> +struct spi_nor_ops {
> +	int (*read_reg)(struct udevice *dev, u8 cmd, u8 *val, int len);
> +	int (*write_reg)(struct udevice *dev, u8 cmd, u8 *data, int len);
> +
> +	int (*read)(struct udevice *dev, loff_t from, size_t len,
> +		    u_char *buf);
> +	int (*write)(struct udevice *dev, loff_t to, size_t len,
> +		     const u_char *buf);
> +};
> +
> +#define spi_nor_get_ops(dev)	((struct spi_nor_ops *)(dev)->driver->ops)
> +
> +int spi_nor_merase(struct udevice *dev, struct erase_info *instr);
> +int spi_nor_mread(struct udevice *dev, loff_t from, size_t len,
> +		  size_t *retlen, u_char *buf);
> +
> +int spi_nor_scan(struct spi_nor *nor);
> +int spi_nor_bind(struct udevice *dev, struct spi_nor *nor);
> +
> +struct spi_nor *find_spi_nor_device(int dev_num);
> +int get_spi_nor_num(void);
> +struct spi_nor *spi_nor_get_spi_nor_dev(struct udevice *dev);
> +struct mtd_info *spi_nor_get_mtd_info(struct spi_nor *nor);
> +
> +#endif /* __MTD_SPI_NOR_H */
> 

-- 
Regards
Vignesh

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

* [U-Boot] [PATCH v10 00/27] dm: Generic MTD Subsystem, with SPI-NOR interface
  2018-01-03  8:48     ` Vignesh R
@ 2018-01-03  9:24       ` Jagan Teki
  2018-01-03 10:59         ` Lukasz Majewski
  2018-01-04 11:52         ` Vignesh R
  0 siblings, 2 replies; 55+ messages in thread
From: Jagan Teki @ 2018-01-03  9:24 UTC (permalink / raw)
  To: u-boot

On Wed, Jan 3, 2018 at 2:18 PM, Vignesh R <vigneshr@ti.com> wrote:
>
>
> On Tuesday 02 January 2018 03:39 PM, Jagan Teki wrote:
>> On Thu, Dec 28, 2017 at 8:14 PM, Lukasz Majewski <lukma@denx.de> wrote:
>>> Hi Jagan,
>>>
>>>> Compared to previous series’s [1], [2], [3] and [4] this patch set
>>>> redefined most of the implementation suitable to fit into existing
>>>> driver-model.
>>>>
>>>> MTD is generic subsystem for underlying flash devices like nand,
>>>> parallel nor, spinor, dataflash etc. So to drive this theory with
>>>> driver model(with an example of block layer) mtd is common device
>>>> interaction for most of  memory technology flashes like nand,
>>>> parallel nor, spinor, dataflash etc, these are treated as interface
>>>> types wrt u-boot driver model.
>>>>
>>>> Once the respective interface driver bind happen, the uclass driver
>>>> will pass an 'interface type' to mtd layer to create device for it,
>>>> for example once spinor ULASS_SPI_NOR driver bind happen,
>>>> the uclass driver of spinor will pass MTD_IF_TYPE_SPI_NOR
>>>> interface type to create mtd device for spinor devices.
>>>>
>>>> SPI-NOR:
>>>> =======
>>>> 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.
>>>
>>> I must admit that I'm a bit confused....
>>>
>>> If you don't mind I would like to ask for clarification of a few things:
>>>
>>>
>>>
>>>>
>>>> =======================================
>>>>              cmd/spinor.c
>>>
>>>                 ^^^^^ - this would be a new set of commands to comply
>>>                 with DM?
>>
>> with this series yes, and we're working on supporting the same with non-dm.
>>
>>>
>>>                 What about "sf" command which we use now to get access
>>>                 to SPI-NOR memory? A lot of boards already use "sf"
>>>                 command... which may be tricky to replace.
>>
>> end-goal will be replace sf with spinor command and removal of 'sf'
>> will be done when the new spi-nor framework stable enough to handle
>> all scenarios which are spi-flash supporting as of now.
>
> I don't agree on adding new cmd and removing sf. It would be impractical
> to change all boot cmds to replace sf with spinor cmd all over U-Boot.
> Not to forget the envs already stored on non volatile media need
> updation to work with new cmd.
> If SPI NOR framework is to abstract all accesses to nor flash devices in
> U-Boot, then why cannot it replace the logic implementing cmd sf? All
> that is changing is that mtd/spi/* is replaced by spi-nor.c + m25p80.c.
> sf probe  can be modified achieve what spinor dev does
> sf read for spinor read and so on. Board configs would just need to
> enable MTD related configs.

I know how hard it is adding new command in u-boot, you can understood
the reason for adding new command if you follow the previous versions
on this series and I hope you does. we have been adding mtd, spi-nor
changes to existing mtd/spi and sf.c since from first series and
observed many issue with respective to framework design(where we move
spi-nor controller drivers on to mtd side) along with driver model. In
v9 we worked on designing MTD UCLASS where mtd command can be commonly
interfaced to all underlying flash devices. and from continuous
evaluation on driver model this series we designed MTD uclass can be a
generic and make run-time creation of underlying flash devices with
interface type, spi-nor is one of the interface. So to make the
framework suitable to command interface the new command named as
spinor. adding/supporting all these new design on top of mtd/spi or sf
doesn’t smooth easy which is proved on previous version. technically
sf termed as spi-flash comprise of spinor and spinand, spinand can be
another interface type with spinand command and adding new features on
legacy code doesn't make sense to me it will eventually breaking
legacy dependencies.

Will all these new framework design, driver model, feasibility to sync
Linux spi-nor.c we adding relevant command, and env.

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

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

* [U-Boot] [PATCH v10 03/27] mtd: add SPI-NOR core support
  2018-01-03  8:49   ` Vignesh R
@ 2018-01-03  9:32     ` Jagan Teki
  2018-01-03  9:56       ` Vignesh R
  0 siblings, 1 reply; 55+ messages in thread
From: Jagan Teki @ 2018-01-03  9:32 UTC (permalink / raw)
  To: u-boot

On Wed, Jan 3, 2018 at 2:19 PM, Vignesh R <vigneshr@ti.com> wrote:
>
>
> On Thursday 28 December 2017 11:42 AM, Jagan Teki wrote:
> [...]
>> +static const struct mtd_ops spi_nor_mtd_ops = {
>> +     .read   = spi_nor_mread,
>> +     .erase  = spi_nor_merase,
>> +};
>> +
>
> Wondering why spi_nor_mwrite is not hooked up here?

yes, because of sst we need to assign the write hook during scan, see spi-nor.c

>
>> +U_BOOT_DRIVER(spinor_mtd) = {
>> +     .name           = "spinor_mtd",
>> +     .id             = UCLASS_MTD,
>> +     .ops            = &spi_nor_mtd_ops,
>> +     .probe          = spi_nor_mtd_probe,
>> +};
>> +
>> +U_BOOT_DRIVER(spinor) = {
>> +     .name   = "spinor",
>> +     .id     = UCLASS_SPI_NOR,
>> +};
>> +
>> +UCLASS_DRIVER(spinor) = {
>> +     .id             = UCLASS_SPI_NOR,
>> +     .name           = "spinor",
>> +     .flags          = DM_UC_FLAG_SEQ_ALIAS,
>> +     .per_device_auto_alloc_size = sizeof(struct spi_nor_uclass_priv),
>> +};
>
> [...]
>
>> diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
>> new file mode 100644
>> index 0000000..e1688e2
>> --- /dev/null
>> +++ b/include/linux/mtd/spi-nor.h
>> @@ -0,0 +1,217 @@
> [...]
>> +struct spi_nor {
>> +     struct udevice          *dev;
>> +     const char              *name;
>> +     u8                      init_done;
>> +     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;
>
> Where is this field used? Shouldn't this field carry single/dual/quad
> mode information?

I think it came up from previous versions, no real use as of now will
check and update in next version

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

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

* [U-Boot] [PATCH v10 03/27] mtd: add SPI-NOR core support
  2018-01-03  9:32     ` Jagan Teki
@ 2018-01-03  9:56       ` Vignesh R
  2018-01-03 10:07         ` Jagan Teki
  0 siblings, 1 reply; 55+ messages in thread
From: Vignesh R @ 2018-01-03  9:56 UTC (permalink / raw)
  To: u-boot



On Wednesday 03 January 2018 03:02 PM, Jagan Teki wrote:
> On Wed, Jan 3, 2018 at 2:19 PM, Vignesh R <vigneshr@ti.com> wrote:
>>
>>
>> On Thursday 28 December 2017 11:42 AM, Jagan Teki wrote:
>> [...]
>>> +static const struct mtd_ops spi_nor_mtd_ops = {
>>> +     .read   = spi_nor_mread,
>>> +     .erase  = spi_nor_merase,
>>> +};
>>> +
>>
>> Wondering why spi_nor_mwrite is not hooked up here?
> 
> yes, because of sst we need to assign the write hook during scan, see spi-nor.c
> 
>>
>>> +U_BOOT_DRIVER(spinor_mtd) = {
>>> +     .name           = "spinor_mtd",
>>> +     .id             = UCLASS_MTD,
>>> +     .ops            = &spi_nor_mtd_ops,
>>> +     .probe          = spi_nor_mtd_probe,
>>> +};
>>> +
>>> +U_BOOT_DRIVER(spinor) = {
>>> +     .name   = "spinor",
>>> +     .id     = UCLASS_SPI_NOR,
>>> +};
>>> +
>>> +UCLASS_DRIVER(spinor) = {
>>> +     .id             = UCLASS_SPI_NOR,
>>> +     .name           = "spinor",
>>> +     .flags          = DM_UC_FLAG_SEQ_ALIAS,
>>> +     .per_device_auto_alloc_size = sizeof(struct spi_nor_uclass_priv),
>>> +};
>>
>> [...]
>>
>>> diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
>>> new file mode 100644
>>> index 0000000..e1688e2
>>> --- /dev/null
>>> +++ b/include/linux/mtd/spi-nor.h
>>> @@ -0,0 +1,217 @@
>> [...]
>>> +struct spi_nor {
>>> +     struct udevice          *dev;
>>> +     const char              *name;
>>> +     u8                      init_done;
>>> +     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;
>>
>> Where is this field used? Shouldn't this field carry single/dual/quad
>> mode information?
> 
> I think it came up from previous versions, no real use as of now will
> check and update in next version

This field is very much needed to inform SPI NOR controllers where to
use 1-1-2 or 1-1-4 or 1-1-1 mode for reading data from flash. It should
be the SPI NOR framework providing this info and not expecting driver to
assume this or infer from DT.

-- 
Regards
Vignesh

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

* [U-Boot] [PATCH v10 03/27] mtd: add SPI-NOR core support
  2018-01-03  9:56       ` Vignesh R
@ 2018-01-03 10:07         ` Jagan Teki
  0 siblings, 0 replies; 55+ messages in thread
From: Jagan Teki @ 2018-01-03 10:07 UTC (permalink / raw)
  To: u-boot

On Wed, Jan 3, 2018 at 3:26 PM, Vignesh R <vigneshr@ti.com> wrote:
>
>
> On Wednesday 03 January 2018 03:02 PM, Jagan Teki wrote:
>> On Wed, Jan 3, 2018 at 2:19 PM, Vignesh R <vigneshr@ti.com> wrote:
>>>
>>>
>>> On Thursday 28 December 2017 11:42 AM, Jagan Teki wrote:
>>> [...]
>>>> +static const struct mtd_ops spi_nor_mtd_ops = {
>>>> +     .read   = spi_nor_mread,
>>>> +     .erase  = spi_nor_merase,
>>>> +};
>>>> +
>>>
>>> Wondering why spi_nor_mwrite is not hooked up here?
>>
>> yes, because of sst we need to assign the write hook during scan, see spi-nor.c
>>
>>>
>>>> +U_BOOT_DRIVER(spinor_mtd) = {
>>>> +     .name           = "spinor_mtd",
>>>> +     .id             = UCLASS_MTD,
>>>> +     .ops            = &spi_nor_mtd_ops,
>>>> +     .probe          = spi_nor_mtd_probe,
>>>> +};
>>>> +
>>>> +U_BOOT_DRIVER(spinor) = {
>>>> +     .name   = "spinor",
>>>> +     .id     = UCLASS_SPI_NOR,
>>>> +};
>>>> +
>>>> +UCLASS_DRIVER(spinor) = {
>>>> +     .id             = UCLASS_SPI_NOR,
>>>> +     .name           = "spinor",
>>>> +     .flags          = DM_UC_FLAG_SEQ_ALIAS,
>>>> +     .per_device_auto_alloc_size = sizeof(struct spi_nor_uclass_priv),
>>>> +};
>>>
>>> [...]
>>>
>>>> diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
>>>> new file mode 100644
>>>> index 0000000..e1688e2
>>>> --- /dev/null
>>>> +++ b/include/linux/mtd/spi-nor.h
>>>> @@ -0,0 +1,217 @@
>>> [...]
>>>> +struct spi_nor {
>>>> +     struct udevice          *dev;
>>>> +     const char              *name;
>>>> +     u8                      init_done;
>>>> +     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;
>>>
>>> Where is this field used? Shouldn't this field carry single/dual/quad
>>> mode information?
>>
>> I think it came up from previous versions, no real use as of now will
>> check and update in next version
>
> This field is very much needed to inform SPI NOR controllers where to
> use 1-1-2 or 1-1-4 or 1-1-1 mode for reading data from flash. It should
> be the SPI NOR framework providing this info and not expecting driver to
> assume this or infer from DT.

yes remember, we have common mode(for both read and write) ie
initialized and used in spi-nor instead have read_mode.

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

* [U-Boot] [PATCH v10 00/27] dm: Generic MTD Subsystem, with SPI-NOR interface
  2018-01-03  9:24       ` Jagan Teki
@ 2018-01-03 10:59         ` Lukasz Majewski
  2018-01-31  8:07           ` Andy Yan
  2018-01-04 11:52         ` Vignesh R
  1 sibling, 1 reply; 55+ messages in thread
From: Lukasz Majewski @ 2018-01-03 10:59 UTC (permalink / raw)
  To: u-boot

Hi Jagan,

> On Wed, Jan 3, 2018 at 2:18 PM, Vignesh R <vigneshr@ti.com> wrote:
> >
> >
> > On Tuesday 02 January 2018 03:39 PM, Jagan Teki wrote:  
> >> On Thu, Dec 28, 2017 at 8:14 PM, Lukasz Majewski <lukma@denx.de>
> >> wrote:  
> >>> Hi Jagan,
> >>>  
> >>>> Compared to previous series’s [1], [2], [3] and [4] this patch
> >>>> set redefined most of the implementation suitable to fit into
> >>>> existing driver-model.
> >>>>
> >>>> MTD is generic subsystem for underlying flash devices like nand,
> >>>> parallel nor, spinor, dataflash etc. So to drive this theory with
> >>>> driver model(with an example of block layer) mtd is common device
> >>>> interaction for most of  memory technology flashes like nand,
> >>>> parallel nor, spinor, dataflash etc, these are treated as
> >>>> interface types wrt u-boot driver model.
> >>>>
> >>>> Once the respective interface driver bind happen, the uclass
> >>>> driver will pass an 'interface type' to mtd layer to create
> >>>> device for it, for example once spinor ULASS_SPI_NOR driver bind
> >>>> happen, the uclass driver of spinor will pass MTD_IF_TYPE_SPI_NOR
> >>>> interface type to create mtd device for spinor devices.
> >>>>
> >>>> SPI-NOR:
> >>>> =======
> >>>> 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.  
> >>>
> >>> I must admit that I'm a bit confused....
> >>>
> >>> If you don't mind I would like to ask for clarification of a few
> >>> things:
> >>>
> >>>
> >>>  
> >>>>
> >>>> =======================================
> >>>>              cmd/spinor.c  
> >>>
> >>>                 ^^^^^ - this would be a new set of commands to
> >>> comply with DM?  
> >>
> >> with this series yes, and we're working on supporting the same
> >> with non-dm. 
> >>>
> >>>                 What about "sf" command which we use now to get
> >>> access to SPI-NOR memory? A lot of boards already use "sf"
> >>>                 command... which may be tricky to replace.  
> >>
> >> end-goal will be replace sf with spinor command and removal of 'sf'
> >> will be done when the new spi-nor framework stable enough to handle
> >> all scenarios which are spi-flash supporting as of now.  
> >
> > I don't agree on adding new cmd and removing sf. It would be
> > impractical to change all boot cmds to replace sf with spinor cmd
> > all over U-Boot. Not to forget the envs already stored on non
> > volatile media need updation to work with new cmd.
> > If SPI NOR framework is to abstract all accesses to nor flash
> > devices in U-Boot, then why cannot it replace the logic
> > implementing cmd sf? All that is changing is that mtd/spi/* is
> > replaced by spi-nor.c + m25p80.c. sf probe  can be modified achieve
> > what spinor dev does sf read for spinor read and so on. Board
> > configs would just need to enable MTD related configs.  
> 
> I know how hard it is adding new command in u-boot, 

Yes, it is. Especially command which duplicates already present
functionality.

> you can understood
> the reason for adding new command if you follow the previous versions
> on this series and I hope you does. 

I must admit that this is the first version, which I reviewed.

The only feasible way would be to have new Kconfig option for this
framework, force spinor for new boards and ..... wait.

After some long time (how long do we struggle with DM
conversion/Kconfig?) we could think about removing "sf" command.

I do want to emphasis that I do agree with Vignesh - there are many
boards out there, which do use sf command, with even more dangerous
situation when company X only plan to update u-boot, but has envs in a
separate partition. Breaking "sf" equals to brick of on-field
devices....

IMHO - we shall have sf command as an alias to new "spinor" command
(even by calling run_command("spinor....");).

> we have been adding mtd, spi-nor
> changes to existing mtd/spi and sf.c since from first series and
> observed many issue with respective to framework design(where we move
> spi-nor controller drivers on to mtd side) along with driver model. In
> v9 we worked on designing MTD UCLASS where mtd command can be commonly
> interfaced to all underlying flash devices. and from continuous
> evaluation on driver model this series we designed MTD uclass can be a
> generic and make run-time creation of underlying flash devices with
> interface type, spi-nor is one of the interface. So to make the
> framework suitable to command interface the new command named as
> spinor. adding/supporting all these new design on top of mtd/spi or sf
> doesn’t smooth easy which is proved on previous version. technically
> sf termed as spi-flash comprise of spinor and spinand, spinand can be
> another interface type with spinand command and adding new features on
> legacy code doesn't make sense to me it will eventually breaking
> legacy dependencies.
> 
> Will all these new framework design, driver model, feasibility to sync
> Linux spi-nor.c we adding relevant command, and env.
> 



Best regards,

Lukasz Majewski

--

DENX Software Engineering GmbH,      Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 488 bytes
Desc: OpenPGP digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20180103/bd12ca0b/attachment.sig>

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

* [U-Boot] [PATCH v10 03/27] mtd: add SPI-NOR core support
  2017-12-28  6:12 ` [U-Boot] [PATCH v10 03/27] mtd: add SPI-NOR core support Jagan Teki
                     ` (2 preceding siblings ...)
  2018-01-03  8:49   ` Vignesh R
@ 2018-01-04  2:33   ` Andy Yan
  2018-02-28  9:42   ` Prabhakar Kushwaha
  4 siblings, 0 replies; 55+ messages in thread
From: Andy Yan @ 2018-01-04  2:33 UTC (permalink / raw)
  To: u-boot

Hi Jagan:

2017-12-28 14:12 GMT+08:00 Jagan Teki <jagan@amarulasolutions.com>:

> 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/spinor.c
> =======================================
>              mtd-uclass.c
> =======================================
>            spi-nor-uclass.c
> =======================================
>               spi-nor.c
> =======================================
> m25p80.c                zynq_qspinor.c
> =======================================
> spi-uclass.c
> =======================================
> zynq_qspi.c
> =======================================
>         #####SPI NOR chip######
> =======================================
>
> Signed-off-by: Suneel Garapati <suneelglinux@gmail.com>
> Signed-off-by: Jagan Teki <jagan@amarulasolutions.com>
> ---
>  Makefile                             |   1 +
>  drivers/mtd/spi-nor/Makefile         |   7 +
>  drivers/mtd/spi-nor/spi-nor-ids.c    | 184 +++++++++++
>  drivers/mtd/spi-nor/spi-nor-uclass.c | 143 +++++++++
>  drivers/mtd/spi-nor/spi-nor.c        | 569 ++++++++++++++++++++++++++++++
> +++++
>  include/dm/uclass-id.h               |   1 +
>  include/linux/mtd/spi-nor.h          | 217 +++++++++++++
>  7 files changed, 1122 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-uclass.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 e6d309a..70b5202 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -662,6 +662,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..c1212a8
> --- /dev/null
> +++ b/drivers/mtd/spi-nor/Makefile
> @@ -0,0 +1,7 @@
> +#
> +# Copyright (C) 2016 Jagan Teki <jagan@openedev.com>
> +#
> +# SPDX-License-Identifier:     GPL-2.0+
> +
> +## spi-nor core
> +obj-y  += spi-nor.o spi-nor-uclass.o spi-nor-ids.o
> 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..db95655
> --- /dev/null
> +++ b/drivers/mtd/spi-nor/spi-nor-ids.c
> @@ -0,0 +1,184 @@
> +/*
> + * 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) },
> +       {"mx25u6435f",     INFO(0xc22537, 0x0, 64 * 1024,   128, RD_FULL |
> WR_QPP) },
> +       {"mx25l12855e",    INFO(0xc22618, 0x0, 64 * 1024,   256, RD_FULL |
> WR_QPP) },
> +       {"mx25u1635e",     INFO(0xc22535, 0x0, 64 * 1024,  32, SECT_4K) },
> +       {"mx66u51235f",    INFO(0xc2253a, 0x0, 64 * 1024,  1024, RD_FULL |
> WR_QPP) },
> +       {"mx66l1g45g",     INFO(0xc2201b, 0x0, 64 * 1024,  2048, 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,    32, 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) },
> +       {"s25fs256s_64k",  INFO6(0x010219, 0x4d0181, 64 * 1024, 512,
> RD_FULL | WR_QPP | SECT_4K) },
> +       {"s25fl256s_64k",  INFO(0x010219, 0x4d01,  64 * 1024,   512,
> RD_FULL | WR_QPP) },
> +       {"s25fs512s",      INFO6(0x010220, 0x4d0081, 128 * 1024, 512,
> RD_FULL | WR_QPP | SECT_4K) },
> +       {"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) },
> +       {"mt25qu02g",      INFO(0x20bb22, 0x0,  64 * 1024,  4096, RD_FULL
> | WR_QPP | E_FSR | SECT_4K) },
> +       {"mt25ql02g",      INFO(0x20ba22, 0x0,  64 * 1024,  4096, RD_FULL
> | WR_QPP | E_FSR | SECT_4K) },
> +       {"mt35xu512g",     INFO6(0x2c5b1a, 0x104100,  128 * 1024,  512,
> 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 */
> +       {"is25lq040b",     INFO(0x9d4013, 0x0, 64 * 1024,     8, 0) },
> +       {"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-uclass.c
> b/drivers/mtd/spi-nor/spi-nor-uclass.c
> new file mode 100644
> index 0000000..919682d
> --- /dev/null
> +++ b/drivers/mtd/spi-nor/spi-nor-uclass.c
> @@ -0,0 +1,143 @@
> +/*
> + * 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 <mtd.h>
> +
> +#include <dm/device-internal.h>
> +#include <linux/mtd/spi-nor.h>
> +
> +DECLARE_GLOBAL_DATA_PTR;
> +
> +struct spi_nor *spi_nor_get_spi_nor_dev(struct udevice *dev)
> +{
> +       struct spi_nor_uclass_priv *upriv;
> +
> +       if (!device_active(dev))
> +               return NULL;
> +       upriv = dev_get_uclass_priv(dev);
> +       return upriv->spi_nor;
> +}
> +
> +struct spi_nor *find_spi_nor_device(int dev_num)
> +{
> +       struct udevice *dev, *spi_nor_dev;
> +       int ret;
> +
> +       ret = mtd_find_device(MTD_IF_TYPE_SPI_NOR, dev_num, &dev);
> +       if (ret) {
> +               printf("SPI-NOR Device %d not found\n", dev_num);
> +               return NULL;
> +       }
> +
> +       spi_nor_dev = dev_get_parent(dev);
> +
> +       struct spi_nor *nor = spi_nor_get_spi_nor_dev(spi_nor_dev);
> +
> +       return nor;
> +}
> +
> +int get_spi_nor_num(void)
> +{
> +       return max((mtd_find_max_devnum(MTD_IF_TYPE_SPI_NOR) + 1), 0);
> +}
> +
> +struct mtd_info *spi_nor_get_mtd_info(struct spi_nor *nor)
> +{
> +       struct mtd_info *mtd;
> +       struct udevice *dev;
> +
> +       device_find_first_child(nor->dev, &dev);
> +       if (!dev)
> +               return NULL;
> +       mtd = dev_get_uclass_platdata(dev);
> +
> +       return mtd;
> +}
> +
> +void print_spi_nor_devices(char separator)
> +{
> +       struct udevice *dev;
> +       bool first = true;
> +
> +       for (uclass_first_device(UCLASS_SPI_NOR, &dev);
> +            dev;
> +            uclass_next_device(&dev), first = false) {
> +               struct spi_nor *nor = spi_nor_get_spi_nor_dev(dev);
> +
> +               if (!first) {
> +                       printf("%c", separator);
> +                       if (separator != '\n')
> +                               puts(" ");
> +               }
> +
> +               printf("%s: %d", dev->name, spi_nor_get_mtd_info(nor)->
> devnum);
> +       }
> +
> +       printf("\n");
> +}
> +
> +int spi_nor_bind(struct udevice *dev, struct spi_nor *nor)
> +{
> +       struct udevice *mdev;
> +       int ret;
> +
> +       if (!spi_nor_get_ops(dev))
> +               return -ENOSYS;
> +
> +       ret = mtd_create_devicef(dev, "spinor_mtd", "mtd",
> MTD_IF_TYPE_SPI_NOR,
> +                                &mdev);
> +       if (ret) {
> +               debug("Cannot create mtd device\n");
> +               return ret;
> +       }
> +       nor->dev = dev;
> +
> +       return 0;
> +}
> +
> +static int spi_nor_mtd_probe(struct udevice *dev)
> +{
> +       struct udevice *spi_nor_dev = dev_get_parent(dev);
> +       struct spi_nor_uclass_priv *upriv = dev_get_uclass_priv(spi_nor_
> dev);
> +       struct spi_nor *nor = upriv->spi_nor;
> +       int ret;
> +
> +       ret = spi_nor_scan(nor);
> +       if (ret) {
> +               debug("%s: spi_nor_scan() failed (err=%d)\n", __func__,
> ret);
> +               return ret;
> +       }
> +
> +       return 0;
> +}
> +
> +static const struct mtd_ops spi_nor_mtd_ops = {
> +       .read   = spi_nor_mread,
> +       .erase  = spi_nor_merase,
> +};
> +
> +U_BOOT_DRIVER(spinor_mtd) = {
> +       .name           = "spinor_mtd",
> +       .id             = UCLASS_MTD,
> +       .ops            = &spi_nor_mtd_ops,
> +       .probe          = spi_nor_mtd_probe,
> +};
> +
> +U_BOOT_DRIVER(spinor) = {
> +       .name   = "spinor",
> +       .id     = UCLASS_SPI_NOR,
> +};
> +
> +UCLASS_DRIVER(spinor) = {
> +       .id             = UCLASS_SPI_NOR,
> +       .name           = "spinor",
> +       .flags          = DM_UC_FLAG_SEQ_ALIAS,
> +       .per_device_auto_alloc_size = sizeof(struct spi_nor_uclass_priv),
> +};
> diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
> new file mode 100644
> index 0000000..09fb8ca
> --- /dev/null
> +++ b/drivers/mtd/spi-nor/spi-nor.c
> @@ -0,0 +1,569 @@
> +/*
> + * 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 <dm/device-internal.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 udevice *dev)
> +{
> +       return spi_nor_get_ops(dev)->write_reg(dev, SNOR_OP_WREN, NULL,
> 0);
> +}
> +
> +/* Re-set write enable latch with Write Disable command */
> +static inline int write_disable(struct udevice *dev)
> +{
> +       return spi_nor_get_ops(dev)->write_reg(dev, SNOR_OP_WRDI, NULL,
> 0);
> +}
> +
> +static int read_sr(struct udevice *dev)
> +{
> +       u8 sr;
> +       int ret;
> +
> +       ret = spi_nor_get_ops(dev)->read_reg(dev, 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 udevice *dev)
> +{
> +       u8 fsr;
> +       int ret;
> +
> +       ret = spi_nor_get_ops(dev)->read_reg(dev, 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 udevice *dev, u8 ws)
> +{
> +       struct spi_nor *nor = spi_nor_get_spi_nor_dev(dev);
> +       const struct spi_nor_ops *ops = spi_nor_get_ops(dev);
> +
> +       nor->cmd_buf[0] = ws;
> +       return ops->write_reg(dev, SNOR_OP_WRSR, nor->cmd_buf, 1);
> +}
> +
> +#if defined(CONFIG_SPI_NOR_SPANSION) || defined(CONFIG_SPI_NOR_WINBOND)
> +static int read_cr(struct udevice *dev)
> +{
> +       u8 cr;
> +       int ret;
> +
> +       ret = spi_nor_get_ops(dev)->read_reg(dev, 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 udevice *dev, u16 val)
> +{
> +       struct spi_nor *nor = spi_nor_get_spi_nor_dev(dev);
> +       const struct spi_nor_ops *ops = spi_nor_get_ops(dev);
> +
> +       nor->cmd_buf[0] = val & 0xff;
> +       nor->cmd_buf[1] = (val >> 8);
> +
> +       return ops->write_reg(dev, SNOR_OP_WRSR, nor->cmd_buf, 2);
> +}
> +#endif
> +
> +static int spi_nor_sr_ready(struct udevice *dev)
> +{
> +       int sr = read_sr(dev);
> +       if (sr < 0)
> +               return sr;
> +       else
> +               return !(sr & SR_WIP);
> +}
> +
> +static int spi_nor_fsr_ready(struct udevice *dev)
> +{
> +       int fsr = read_fsr(dev);
> +       if (fsr < 0)
> +               return fsr;
> +       else
> +               return fsr & FSR_READY;
> +}
> +
> +static int spi_nor_ready(struct udevice *dev)
> +{
> +       struct spi_nor *nor = spi_nor_get_spi_nor_dev(dev);
> +       int sr, fsr;
> +
> +       sr = spi_nor_sr_ready(dev);
> +       if (sr < 0)
> +               return sr;
> +
> +       fsr = 1;
> +       if (nor->flags & SNOR_F_USE_FSR) {
> +               fsr = spi_nor_fsr_ready(dev);
> +               if (fsr < 0)
> +                       return fsr;
> +       }
> +
> +       return sr && fsr;
> +}
> +
> +static int spi_nor_wait_till_ready(struct udevice *dev, unsigned long
> timeout)
> +{
> +       int timebase, ret;
> +
> +       timebase = get_timer(0);
> +
> +       while (get_timer(timebase) < timeout) {
> +               ret = spi_nor_ready(dev);
> +               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 udevice *dev)
> +{
> +       int                             tmp;
> +       u8                              id[SPI_NOR_MAX_ID_LEN];
> +       const struct spi_nor_info       *info;
> +       const struct spi_nor_ops        *ops = spi_nor_get_ops(dev);
> +
> +       tmp = ops->read_reg(dev, 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);
> +}
> +
> +int spi_nor_merase(struct udevice *dev, struct erase_info *instr)
> +{
> +       struct mtd_info *mtd = dev_get_uclass_platdata(dev);
> +       int devnum = mtd->devnum;
> +       struct spi_nor *nor;
> +       const struct spi_nor_ops *ops;
> +       u32 addr, len, erase_addr;
> +       uint32_t rem;
> +       int ret = -1;
> +
> +       nor = find_spi_nor_device(devnum);
> +       if (!nor)
> +               return -ENODEV;
> +       ops = spi_nor_get_ops(nor->dev);
> +
> +       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->dev);
> +
> +               ret = ops->write(nor->dev, erase_addr, 0, NULL);
>


Can we considering use ops->write_reg(nor->dev, nor->erase_opcode,  &addr,
len) here ,  keep sync with
the linux upstream spi-nor does.[0]

[0]
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git/tree/drivers/mtd/spi-nor/spi-nor.c

+               if (ret < 0)
> +                       goto erase_err;
> +
> +               ret = spi_nor_wait_till_ready(nor->dev,
> SNOR_READY_WAIT_ERASE);
> +               if (ret < 0)
> +                       goto erase_err;
> +
> +               addr += mtd->erasesize;
> +               len -= mtd->erasesize;
> +       }
> +
> +       write_disable(nor->dev);
> +
> +       instr->state = MTD_ERASE_DONE;
> +       mtd_erase_callback(instr);
> +
> +       return ret;
> +
> +erase_err:
> +       instr->state = MTD_ERASE_FAILED;
> +       return ret;
> +}
> +
> +static int spi_nor_mwrite(struct udevice *dev, loff_t to, size_t len,
> +                         size_t *retlen, const u_char *buf)
> +{
> +       struct mtd_info *mtd = dev_get_uclass_platdata(dev);
> +       int devnum = mtd->devnum;
> +       struct spi_nor *nor;
> +       const struct spi_nor_ops *ops;
> +       size_t addr, byte_addr;
> +       size_t chunk_len, actual;
> +       uint32_t page_size;
> +       int ret = -1;
> +
> +       nor = find_spi_nor_device(devnum);
> +       if (!nor)
> +               return -ENODEV;
> +       ops = spi_nor_get_ops(nor->dev);
> +
> +       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->dev);
> +
> +               ret = ops->write(nor->dev, addr, chunk_len, buf + actual);
> +               if (ret < 0)
> +                       break;
> +
> +               ret = spi_nor_wait_till_ready(nor->dev,
> SNOR_READY_WAIT_PROG);
> +               if (ret < 0)
> +                       return ret;
> +
> +               to += chunk_len;
> +               *retlen += chunk_len;
> +       }
> +
> +       return ret;
> +}
> +
> +int spi_nor_mread(struct udevice *dev, loff_t from, size_t len,
> +                 size_t *retlen, u_char *buf)
> +{
> +       struct mtd_info *mtd = dev_get_uclass_platdata(dev);
> +       int devnum = mtd->devnum;
> +       struct spi_nor *nor;
> +       const struct spi_nor_ops *ops;
> +       int ret;
> +
> +       nor = find_spi_nor_device(devnum);
> +       if (!nor)
> +               return -ENODEV;
> +       ops = spi_nor_get_ops(nor->dev);
> +
> +       /* Handle memory-mapped SPI */
> +       if (nor->memory_map) {
> +               ret = ops->read(nor->dev, from, len, buf);
> +               if (ret) {
> +                       debug("spi-nor: mmap read failed\n");
> +                       return ret;
> +               }
> +
> +               return ret;
> +       }
> +
> +       ret = ops->read(nor->dev, from, len, buf);
> +       if (ret < 0) {
> +               printf("%s ret = %d\n", __func__, ret);
> +               return ret;
> +       }
> +
> +       *retlen += len;
> +
> +       return ret;
> +}
> +
> +#ifdef CONFIG_SPI_NOR_MACRONIX
> +static int macronix_quad_enable(struct udevice *dev)
> +{
> +       int ret, val;
> +
> +       val = read_sr(dev);
> +       if (val < 0)
> +               return val;
> +
> +       if (val & SR_QUAD_EN_MX)
> +               return 0;
> +
> +       write_enable(dev);
> +
> +       ret = write_sr(dev, val | SR_QUAD_EN_MX);
> +       if (ret < 0)
> +               return ret;
> +
> +       if (spi_nor_wait_till_ready(dev, SNOR_READY_WAIT_PROG))
> +               return 1;
> +
> +       ret = read_sr(dev);
> +       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 udevice *dev)
> +{
> +       int ret, val;
> +
> +       val = read_cr(dev);
> +       if (val < 0)
> +               return val;
> +
> +       if (val & CR_QUAD_EN_SPAN)
> +               return 0;
> +
> +       write_enable(dev);
> +
> +       ret = write_sr_cr(dev, val | CR_QUAD_EN_SPAN);
> +       if (ret < 0)
> +               return ret;
> +
> +       if (spi_nor_wait_till_ready(dev, SNOR_READY_WAIT_PROG))
> +               return 1;
> +
> +       /* read back and check it */
> +       ret = read_cr(dev);
> +       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 udevice *dev, const struct spi_nor_info
> *info)
> +{
> +       switch (JEDEC_MFR(info)) {
> +#ifdef CONFIG_SPI_NOR_MACRONIX
> +       case SNOR_MFR_MACRONIX:
> +               return macronix_quad_enable(dev);
> +#endif
> +#if defined(CONFIG_SPI_NOR_SPANSION) || defined(CONFIG_SPI_NOR_WINBOND)
> +       case SNOR_MFR_SPANSION:
> +       case SNOR_MFR_WINBOND:
> +               return spansion_quad_enable(dev);
> +#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) */
> +
> +int spi_nor_scan(struct spi_nor *nor)
> +{
> +       struct mtd_info *mtd = spi_nor_get_mtd_info(nor);
> +       struct mtd_ops *ops = mtd_get_ops(mtd->dev);
> +       const struct spi_nor_info *info = NULL;
> +       int ret;
> +
> +       struct spi_nor_uclass_priv *upriv = dev_get_uclass_priv(nor->dev);
> +       upriv->spi_nor = nor;
> +
> +       if (nor->init_done)
> +               return 0;
> +
> +       info = spi_nor_id(nor->dev);
> +       if (IS_ERR_OR_NULL(info)) {
> +               ret = -ENOENT;
> +               goto err;
> +       }
> +
> +       /*
> +        * Flash powers up read-only, so clear BP# bits.
> +        *
> +        * Note on some flash (like Macronix), QE (quad enable) bit is in
> the
> +        * same status register as BP# bits, and we need preserve its
> original
> +        * value during a reboot cycle as this is required by some
> platforms
> +        * (like Intel ICH SPI controller working under descriptor mode).
> +        */
> +       if (JEDEC_MFR(info) == SNOR_MFR_ATMEL ||
> +          (JEDEC_MFR(info) == SNOR_MFR_SST) ||
> +          (JEDEC_MFR(info) == SNOR_MFR_MACRONIX)) {
> +               u8 sr = 0;
> +
> +               if (JEDEC_MFR(info) == SNOR_MFR_MACRONIX)
> +                       sr = read_sr(nor->dev) & SR_QUAD_EN_MX;
> +               write_sr(nor->dev, sr);
> +       }
> +
> +       mtd->name = info->name;
> +       mtd->priv = nor;
> +       mtd->type = MTD_NORFLASH;
> +       mtd->writesize = 1;
> +       mtd->flags = MTD_CAP_NORFLASH;
> +
> +       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_mwrite;
> +
> +       /* 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->dev, info);
> +               if (ret) {
> +                       debug("spi-nor: quad mode not supported for
> %02x\n",
> +                             JEDEC_MFR(info));
> +                       goto err;
> +               }
> +       }
> +
> +       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");
> +               goto err;
> +       }
> +#endif
> +
> +       nor->init_done = 1;
> +       return 0;
> +err:
> +       nor->init_done = 0;
> +       return ret;
> +}
> diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h
> index 3fc2083..06541a4 100644
> --- a/include/dm/uclass-id.h
> +++ b/include/dm/uclass-id.h
> @@ -75,6 +75,7 @@ enum uclass_id {
>         UCLASS_SERIAL,          /* Serial UART */
>         UCLASS_SPI,             /* SPI bus */
>         UCLASS_SPMI,            /* System Power Management Interface bus */
> +       UCLASS_SPI_NOR,         /* SPI NOR flash */
>         UCLASS_SPI_FLASH,       /* SPI flash */
>         UCLASS_SPI_GENERIC,     /* Generic SPI flash target */
>         UCLASS_SYSCON,          /* System configuration device */
> diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
> new file mode 100644
> index 0000000..e1688e2
> --- /dev/null
> +++ b/include/linux/mtd/spi-nor.h
> @@ -0,0 +1,217 @@
> +/*
> + * 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>
> +#include <linux/mtd/mtd.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
> +
> +/**
> + * struct spi_nor_uclass_priv - Holds information about a device used by
> the uclass
> + */
> +struct spi_nor_uclass_priv {
> +       struct spi_nor *spi_nor;
> +};
> +
> +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
> + */
> +struct spi_nor {
> +       struct udevice          *dev;
> +       const char              *name;
> +       u8                      init_done;
> +       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];
> +
> +       void *memory_map;
> +};
> +
> +struct spi_nor_ops {
> +       int (*read_reg)(struct udevice *dev, u8 cmd, u8 *val, int len);
> +       int (*write_reg)(struct udevice *dev, u8 cmd, u8 *data, int len);
> +
> +       int (*read)(struct udevice *dev, loff_t from, size_t len,
> +                   u_char *buf);
> +       int (*write)(struct udevice *dev, loff_t to, size_t len,
> +                    const u_char *buf);
> +};
> +
> +#define spi_nor_get_ops(dev)   ((struct spi_nor_ops *)(dev)->driver->ops)
> +
> +int spi_nor_merase(struct udevice *dev, struct erase_info *instr);
> +int spi_nor_mread(struct udevice *dev, loff_t from, size_t len,
> +                 size_t *retlen, u_char *buf);
> +
> +int spi_nor_scan(struct spi_nor *nor);
> +int spi_nor_bind(struct udevice *dev, struct spi_nor *nor);
> +
> +struct spi_nor *find_spi_nor_device(int dev_num);
> +int get_spi_nor_num(void);
> +struct spi_nor *spi_nor_get_spi_nor_dev(struct udevice *dev);
> +struct mtd_info *spi_nor_get_mtd_info(struct spi_nor *nor);
> +
> +#endif /* __MTD_SPI_NOR_H */
> --
> 2.7.4
>
> _______________________________________________
> U-Boot mailing list
> U-Boot at lists.denx.de
> https://lists.denx.de/listinfo/u-boot
>

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

* [U-Boot] [PATCH v10 24/27] env: add spi-nor environment
  2017-12-28  6:12 ` [U-Boot] [PATCH v10 24/27] env: add spi-nor environment Jagan Teki
@ 2018-01-04  7:06   ` Prabhakar Kushwaha
  0 siblings, 0 replies; 55+ messages in thread
From: Prabhakar Kushwaha @ 2018-01-04  7:06 UTC (permalink / raw)
  To: u-boot

Hi Jagan,

> -----Original Message-----
> From: U-Boot [mailto:u-boot-bounces at lists.denx.de] On Behalf Of Jagan Teki
> Sent: Thursday, December 28, 2017 11:43 AM
> To: u-boot at lists.denx.de
> Cc: Tom Rini <trini@konsulko.com>
> Subject: [U-Boot] [PATCH v10 24/27] env: add spi-nor environment
> 
> Now spi-nor framework is up so access the environment
> through en/spinor.c
> 
> Signed-off-by: Suneel Garapati <suneelglinux@gmail.com>
> Signed-off-by: Jagan Teki <jagan@amarulasolutions.com>


This patch is only considering environment to be used after relocation to DDR.

What about the scenario where environment is required during SPL.  
SPL may not be having MTD sub-system ready for env read. In SPL case raw read is required. 
Similar to below patch.

http://patchwork.ozlabs.org/patch/848511/

I request you to consider this patch also. 

--pk 

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

* [U-Boot] [PATCH v10 00/27] dm: Generic MTD Subsystem, with SPI-NOR interface
  2018-01-03  9:24       ` Jagan Teki
  2018-01-03 10:59         ` Lukasz Majewski
@ 2018-01-04 11:52         ` Vignesh R
  1 sibling, 0 replies; 55+ messages in thread
From: Vignesh R @ 2018-01-04 11:52 UTC (permalink / raw)
  To: u-boot



On Wednesday 03 January 2018 02:54 PM, Jagan Teki wrote:
> On Wed, Jan 3, 2018 at 2:18 PM, Vignesh R <vigneshr@ti.com> wrote:
>>
[...]
>>>>>
>>>>> =======================================
>>>>>              cmd/spinor.c
>>>>
>>>>                 ^^^^^ - this would be a new set of commands to comply
>>>>                 with DM?
>>>
>>> with this series yes, and we're working on supporting the same with non-dm.
>>>
>>>>
>>>>                 What about "sf" command which we use now to get access
>>>>                 to SPI-NOR memory? A lot of boards already use "sf"
>>>>                 command... which may be tricky to replace.
>>>
>>> end-goal will be replace sf with spinor command and removal of 'sf'
>>> will be done when the new spi-nor framework stable enough to handle
>>> all scenarios which are spi-flash supporting as of now.
>>
>> I don't agree on adding new cmd and removing sf. It would be impractical
>> to change all boot cmds to replace sf with spinor cmd all over U-Boot.
>> Not to forget the envs already stored on non volatile media need
>> updation to work with new cmd.
>> If SPI NOR framework is to abstract all accesses to nor flash devices in
>> U-Boot, then why cannot it replace the logic implementing cmd sf? All
>> that is changing is that mtd/spi/* is replaced by spi-nor.c + m25p80.c.
>> sf probe  can be modified achieve what spinor dev does
>> sf read for spinor read and so on. Board configs would just need to
>> enable MTD related configs.
> 
> I know how hard it is adding new command in u-boot, you can understood
> the reason for adding new command if you follow the previous versions
> on this series and I hope you does. we have been adding mtd, spi-nor
> changes to existing mtd/spi and sf.c since from first series and
> observed many issue with respective to framework design(where we move
> spi-nor controller drivers on to mtd side) along with driver model. 

I don't remember. Its been a year since RFC v8 which used cmd_sf.c.
Looking at the mailing list archives, I don't see any comments opposing
cmd_sf.c and move to mtd command, that you used in v9

> In v9 we worked on designing MTD UCLASS where mtd command can be commonly
> interfaced to all underlying flash devices. and from continuous
> evaluation on driver model this series we designed MTD uclass can be a
> generic and make run-time creation of underlying flash devices with
> interface type, spi-nor is one of the interface. So to make the
> framework suitable to command interface the new command named as
> spinor. adding/supporting all these new design on top of mtd/spi or sf
> doesn’t smooth easy which is proved on previous version. 

Could you point to/summarize the exact problems that force us to move to
spinor cmd? I failed to find them on archives.


> technically sf termed as spi-flash comprise of spinor and spinand, spinand can be
> another interface type with spinand command and adding new features on
> legacy code doesn't make sense to me it will eventually breaking
> legacy dependencies.
> 

AFAIK, spinand is not yet supported and can be added under MTD with
different U-Boot cmd to access it.


-- 
Regards
Vignesh

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

* [U-Boot] [PATCH v10 23/27] board_r: initialize spi_nor
  2017-12-28  6:12 ` [U-Boot] [PATCH v10 23/27] board_r: initialize spi_nor Jagan Teki
@ 2018-01-08  3:52   ` Simon Glass
  0 siblings, 0 replies; 55+ messages in thread
From: Simon Glass @ 2018-01-08  3:52 UTC (permalink / raw)
  To: u-boot

Hi Jagan,

On 27 December 2017 at 23:12, Jagan Teki <jagan@amarulasolutions.com> wrote:
> initialize spi-nor framework during boot, so-that detected
> buses can appears at boot log.
>
> Signed-off-by: Suneel Garapati <suneelglinux@gmail.com>
> Signed-off-by: Jagan Teki <jagan@amarulasolutions.com>
> ---
>  common/board_r.c                     | 13 +++++++++++++
>  drivers/mtd/spi-nor/spi-nor-uclass.c | 17 +++++++++++++++++
>  include/linux/mtd/spi-nor.h          |  1 +
>  3 files changed, 31 insertions(+)
>

We should rely on driver model to init this when it is first probed,
so this should not be needed.

Regards,
Simon

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

* [U-Boot] [PATCH v10 00/27] dm: Generic MTD Subsystem, with SPI-NOR interface
  2017-12-28  6:12 [U-Boot] [PATCH v10 00/27] dm: Generic MTD Subsystem, with SPI-NOR interface Jagan Teki
                   ` (27 preceding siblings ...)
  2017-12-28 14:44 ` [U-Boot] [PATCH v10 00/27] dm: Generic MTD Subsystem, with SPI-NOR interface Lukasz Majewski
@ 2018-01-23  9:00 ` Siva Durga Prasad Paladugu
  28 siblings, 0 replies; 55+ messages in thread
From: Siva Durga Prasad Paladugu @ 2018-01-23  9:00 UTC (permalink / raw)
  To: u-boot

Hi Jagan,

> -----Original Message-----
> From: U-Boot [mailto:u-boot-bounces at lists.denx.de] On Behalf Of Jagan
> Teki
> Sent: Thursday, December 28, 2017 11:42 AM
> To: u-boot at lists.denx.de
> Cc: Tom Rini <trini@konsulko.com>
> Subject: [U-Boot] [PATCH v10 00/27] dm: Generic MTD Subsystem, with
> SPI-NOR interface
> 
> Compared to previous series’s [1], [2], [3] and [4] this patch set redefined
> most of the implementation suitable to fit into existing driver-model.
> 
> MTD is generic subsystem for underlying flash devices like nand, parallel
> nor, spinor, dataflash etc. So to drive this theory with driver model(with an
> example of block layer) mtd is common device interaction for most of
> memory technology flashes like nand, parallel nor, spinor, dataflash etc,
> these are treated as interface types wrt u-boot driver model.
> 
> Once the respective interface driver bind happen, the uclass driver will pass
> an 'interface type' to mtd layer to create device for it, for example once
> spinor ULASS_SPI_NOR driver bind happen, the uclass driver of spinor will
> pass MTD_IF_TYPE_SPI_NOR interface type to create mtd device for spinor
> devices.
> 
> SPI-NOR:
> =======
> 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.

Sorry for very late response. What's your approach on a controller that supports both
flash with some flash specific functionalities(Like different flash connection topologies)
and legacy spi devices.

Thanks,
Siva
> 
> =======================================
>              cmd/spinor.c
> =======================================
>              mtd-uclass.c
> =======================================
>            spi-nor-uclass.c
> =======================================
>               spi-nor.c
> =======================================
> m25p80.c                zynq_qspinor.c
> =======================================
> spi-uclass.c
> =======================================
> zynq_qspi.c
> =======================================
>         #####SPI NOR chip######
> =======================================
> 
> Changes for v10:
> - Update Simon's R-B tag
> - Add mtd dm test case
> - implemented entire code wrt MTD, with interface type
> 
> code size:
> ==========
> before:
> $ arm-linux-gnueabi-size u-boot
>    text	   data	    bss	    dec	    hex	filename
>  473712	  15152	 222568	 711432	  adb08	u-
> boot
> $ du -hs u-boot-dtb.img
> 488K	u-boot-dtb.img
> 
> after:
> $ arm-linux-gnueabi-size u-boot
>    text	   data	    bss	    dec	    hex	filename
>  470124	  14352	 222584	 707060	  ac9f4	u-
> boot
> $ du -hs u-boot-dtb.img
> 484K	u-boot-dtb.img
> 
> approximately 4KiB but DM_SPI_FLASH still there which can be removed
> once support added in SPL
> 
> test log:
> ========
> Zynq> spinor
> spinor - SPI-NOR Sub-system
> 
> Usage:
> spinor list                     - show list of spinor devices
> spinor info                     - show current spinor device info
> spinor dev [devnum]             - show or set current spinor device
> spinor erase offset len         - erase 'len' bytes from 'offset'
> spinor write addr to len        - write 'len' bytes to 'to' from 'addr'
> spinor read addr from len       - read 'len' bytes from 'from' to 'addr'
> spinor protect lock/unlock sector len - protect/unprotect 'len' bytes starting
>                                   at address 'sector'
> Zynq> spinor list
> flash at 0: 0
> spi-nor at e000d000: 1
> Zynq> spinor dev 0
> switch to dev #0, OK
> spinor0 is current device
> Zynq> spinor info
> bus: flash at 0: 0
> device: s25fl128s_64k
> page size: 256 B
> erase size: 64 KiB
> size: 16 MiB
> Zynq> spinor erase 0xE00000 0x100000
> SPI-NOR: 1048576 bytes @ 0xe00000 Erased: OK
> Zynq> mw.b 0x100 0xcc 0x100000
> Zynq> spinor write 0x100 0xE00000 0x100000
> device 0 offset 0xe00000, size 0x100000
> SPI-NOR: 1048576 bytes @ 0xe00000 Written: OK
> Zynq> spinor read 0x3000000 0xE00000 0x100000
> device 0 offset 0xe00000, size 0x100000
> SPI-NOR: 1048576 bytes @ 0xe00000 Read: OK
> Zynq> cmp.b 0x3000000 0x100 0x100000
> Total of 1048576 byte(s) were the same
> Zynq> spinor dev 1
> switch to dev #1, OK
> spinor1 is current device
> Zynq> spinor info
> bus: spi-nor at e000d000: 1
> device: s25fl128s_64k
> page size: 256 B
> erase size: 64 KiB
> size: 16 MiB
> Zynq> spinor erase 0xE00000 0x100000
> SPI-NOR: 1048576 bytes @ 0xe00000 Erased: OK
> Zynq> mw.b 0x100 0xbb 0x100000
> Zynq> spinor write 0x100 0xE00000 0x100000
> device 0 offset 0xe00000, size 0x100000
> SPI-NOR: 1048576 bytes @ 0xe00000 Written: OK
> Zynq> spinor read 0x3000000 0xE00000 0x100000
> device 0 offset 0xe00000, size 0x100000
> SPI-NOR: 1048576 bytes @ 0xe00000 Read: OK
> Zynq> cmp.b 0x3000000 0x100 0x100000
> Total of 1048576 byte(s) were the same
> 
> WIP:
> ===
> - to support non-dm code
> - to support spinor SPL
> 
> Repo:
> ====
> $ git clone git://git.denx.de/u-boot-spi.git $ cd u-boot-spi $ git checkout -b
> mtd-spinor-working origin/mtd-spinor-working
> 
> [1] https://lists.denx.de/pipermail/u-boot/2016-October/271459.html
> [2] http://lists.denx.de/pipermail/u-boot/2016-March/249286.html
> [3] http://lists.denx.de/pipermail/u-boot/2016-February/245418.html
> [4] [PATCH RFC v8 00/16]  SPI-NOR/MTD addition
> 
> Jagan Teki (27):
>   mtd: Add mtd core ops
>   mtd: add mtd device create operations
>   mtd: add SPI-NOR core support
>   mtd: spi-nor: sync/modify sst write operations
>   mtd: spi-nor: sync/modify lock operations
>   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
>   mtd-uclass: use platdata_auto_alloc
>   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
>   cmd: add spinor cmd support
>   cmd: spinor: sync/update protect command
>   board_r: initialize spi_nor
>   env: add spi-nor environment
>   arm: dts: zynq: Add zynq-qspinor node
>   dm: zynq: microzed: enable MTD/SPI-NOR framework
>   test: dm: add tests for mtd devices
> 
>  Makefile                             |   1 +
>  arch/arm/dts/zynq-7000.dtsi          |  12 +
>  arch/arm/dts/zynq-microzed.dts       |  12 +-
>  cmd/Kconfig                          |   5 +
>  cmd/Makefile                         |   1 +
>  cmd/nvedit.c                         |   1 +
>  cmd/spinor.c                         | 326 ++++++++++++
>  common/board_r.c                     |  13 +
>  configs/sandbox_defconfig            |   8 +-
>  configs/zynq_microzed_defconfig      |  17 +-
>  drivers/mtd/Kconfig                  |   2 +
>  drivers/mtd/Makefile                 |   7 +-
>  drivers/mtd/mtd-uclass.c             | 203 +++++++-
>  drivers/mtd/spi-nor/Kconfig          |  89 ++++
>  drivers/mtd/spi-nor/Makefile         |  15 +
>  drivers/mtd/spi-nor/m25p80.c         | 251 ++++++++++
>  drivers/mtd/spi-nor/spi-nor-ids.c    | 184 +++++++
>  drivers/mtd/spi-nor/spi-nor-uclass.c | 160 ++++++
>  drivers/mtd/spi-nor/spi-nor.c        | 940
> +++++++++++++++++++++++++++++++++++
>  drivers/mtd/spi-nor/zynq_qspinor.c   | 622 +++++++++++++++++++++++
>  drivers/spi/spi-uclass.c             |  24 +
>  env/Kconfig                          |  27 +
>  env/Makefile                         |   1 +
>  env/env.c                            |   2 +
>  env/spinor.c                         | 113 +++++
>  include/dm/uclass-id.h               |   1 +
>  include/environment.h                |   1 +
>  include/linux/mtd/mtd.h              |  14 +
>  include/linux/mtd/spi-nor.h          | 223 +++++++++
>  include/mtd.h                        | 176 +++++++
>  include/spi.h                        |  20 +
>  test/dm/Makefile                     |   1 +
>  test/dm/mtd.c                        |  33 ++
>  33 files changed, 3493 insertions(+), 12 deletions(-)  create mode 100644
> cmd/spinor.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-uclass.c
>  create mode 100644 drivers/mtd/spi-nor/spi-nor.c  create mode 100644
> drivers/mtd/spi-nor/zynq_qspinor.c
>  create mode 100644 env/spinor.c
>  create mode 100644 include/linux/mtd/spi-nor.h  create mode 100644
> test/dm/mtd.c
> 
> --
> 2.7.4
> 
> _______________________________________________
> U-Boot mailing list
> U-Boot at lists.denx.de
> https://lists.denx.de/listinfo/u-boot

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

* [U-Boot] [PATCH v10 00/27] dm: Generic MTD Subsystem, with SPI-NOR interface
  2018-01-02 10:09   ` Jagan Teki
  2018-01-03  8:48     ` Vignesh R
@ 2018-01-23  9:50     ` Siva Durga Prasad Paladugu
  2018-01-23  9:59       ` Jagan Teki
  1 sibling, 1 reply; 55+ messages in thread
From: Siva Durga Prasad Paladugu @ 2018-01-23  9:50 UTC (permalink / raw)
  To: u-boot


Hi Jagan,

> -----Original Message-----
> From: U-Boot [mailto:u-boot-bounces at lists.denx.de] On Behalf Of Jagan
> Teki
> Sent: Tuesday, January 02, 2018 3:39 PM
> To: Lukasz Majewski <lukma@denx.de>
> Cc: U-Boot Mailing List <u-boot@lists.denx.de>; Tom Rini
> <trini@konsulko.com>
> Subject: Re: [U-Boot] [PATCH v10 00/27] dm: Generic MTD Subsystem, with
> SPI-NOR interface
> 
> On Thu, Dec 28, 2017 at 8:14 PM, Lukasz Majewski <lukma@denx.de>
> wrote:
> > Hi Jagan,
> >
> >> Compared to previous series’s [1], [2], [3] and [4] this patch set
> >> redefined most of the implementation suitable to fit into existing
> >> driver-model.
> >>
> >> MTD is generic subsystem for underlying flash devices like nand,
> >> parallel nor, spinor, dataflash etc. So to drive this theory with
> >> driver model(with an example of block layer) mtd is common device
> >> interaction for most of  memory technology flashes like nand,
> >> parallel nor, spinor, dataflash etc, these are treated as interface
> >> types wrt u-boot driver model.
> >>
> >> Once the respective interface driver bind happen, the uclass driver
> >> will pass an 'interface type' to mtd layer to create device for it,
> >> for example once spinor ULASS_SPI_NOR driver bind happen, the uclass
> >> driver of spinor will pass MTD_IF_TYPE_SPI_NOR interface type to
> >> create mtd device for spinor devices.
> >>
> >> SPI-NOR:
> >> =======
> >> 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.
> >
> > I must admit that I'm a bit confused....
> >
> > If you don't mind I would like to ask for clarification of a few things:
> >
> >
> >
> >>
> >> =======================================
> >>              cmd/spinor.c
> >
> >                 ^^^^^ - this would be a new set of commands to comply
> >                 with DM?
> 
> with this series yes, and we're working on supporting the same with non-
> dm.
> 
> >
> >                 What about "sf" command which we use now to get access
> >                 to SPI-NOR memory? A lot of boards already use "sf"
> >                 command... which may be tricky to replace.
> 
> end-goal will be replace sf with spinor command and removal of 'sf'
> will be done when the new spi-nor framework stable enough to handle all
> scenarios which are spi-flash supporting as of now.
> 
> >
> >> =======================================
> >>              mtd-uclass.c
> >                 ^^^^^ - here we will have a generic MTD layer (as it is
> >                 in Linux)
> 
> it is not like in Linux, leaving ops names apart all the code is for creating
> mtd device for underlying flash devices in the form of interface type during
> bind. the interface types as of now is spi-nor it can be nand, nor, dataflash
> etc in future if could be.
> 
> >
> >> =======================================
> >>            spi-nor-uclass.c
> >> =======================================
> >>               spi-nor.c
> >                 ^^^^^^ - why do we need to have spi-nor.c ? Cannot we
> >                 have its functionality in the spi-nor-uclass.c ?
> >                 (I'm just curious)
> 
> spi-nor-uclass.c is an uclass driver for underlying UCLASS_SPI_NOR drivers
> like m25p80, zynq_qspinor etc but the spi-nor.c is the actual spi-nor core
> code which handle actual flash specific stuff. and also syncing Linux stuff(if
> require) becomes easy with spi-nor.c as a separate file.
> 
> >
> >> =======================================
> >> m25p80.c                zynq_qspinor.c
> >   ^^^^^ - this is the     ^^^^^^^^ - [*]
> > "generic" spi-nor
> > driver used in Linux.
> > I suppose that it will
> > be reused here?
> 
> yes - name reused because, I do think the Linux and U-Boot development on
> spi-nor will follow in-line at some point but the most of code is following U-
> Boot driver-model.
> 
> >
> >> =======================================
> >> spi-uclass.c
> >   ^^^^^^^ - why do we
> > need this uclass?
> 
> This is an existing uclass spi driver for underlying UCLASS_SPI drivers like
> drivers/spi/zynq_qspi.c etc
> 
> >
> >> =======================================
> >> zynq_qspi.c
> >  ^^^^^ - This is probably
> > the low-level driver for
> > zynq QSPI IP block - why
> > do we have zynq_qspinor.c file above [*]?
> > What is the difference/need of such division?
> 
> Both the drivers are same, the reason for zynq_qspinor is for testing
> framework work for two directions like
> - spi driver interface side through m25p80 cmd/spinor->mtd->spi-nor-
> uclass->spi-nor->m25p80->zynq_qspi.c
> - direct spi-nor controller side
> spinor->mtd->spi-nor-uclass->spi-nor->zynq_qspinor
> 
> Will remove drivers/spi/zynq_qspi.c once all set.

As mentioned in Zynq TRM, Zynq qspi controller can work in legacy spi mode as well which is same as regular spi controller. 
As you mentioned if you remove from drivers/spi/zynq_qspi and moving it to spi-nor, none can use it in spi legacy mode. Right?

Thanks,
Siva

> 
> Jagan.
> 
> --
> Jagan Teki
> Free Software Engineer | www.openedev.com U-Boot, Linux | Upstream
> Maintainer Hyderabad, India.
> _______________________________________________
> U-Boot mailing list
> U-Boot at lists.denx.de
> https://lists.denx.de/listinfo/u-boot

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

* [U-Boot] [PATCH v10 00/27] dm: Generic MTD Subsystem, with SPI-NOR interface
  2018-01-23  9:50     ` Siva Durga Prasad Paladugu
@ 2018-01-23  9:59       ` Jagan Teki
  2018-01-23 11:50         ` Siva Durga Prasad Paladugu
  0 siblings, 1 reply; 55+ messages in thread
From: Jagan Teki @ 2018-01-23  9:59 UTC (permalink / raw)
  To: u-boot

On Tue, Jan 23, 2018 at 3:20 PM, Siva Durga Prasad Paladugu
<sivadur@xilinx.com> wrote:
>
> Hi Jagan,
>
>> -----Original Message-----
>> From: U-Boot [mailto:u-boot-bounces at lists.denx.de] On Behalf Of Jagan
>> Teki
>> Sent: Tuesday, January 02, 2018 3:39 PM
>> To: Lukasz Majewski <lukma@denx.de>
>> Cc: U-Boot Mailing List <u-boot@lists.denx.de>; Tom Rini
>> <trini@konsulko.com>
>> Subject: Re: [U-Boot] [PATCH v10 00/27] dm: Generic MTD Subsystem, with
>> SPI-NOR interface
>>
>> On Thu, Dec 28, 2017 at 8:14 PM, Lukasz Majewski <lukma@denx.de>
>> wrote:
>> > Hi Jagan,
>> >
>> >> Compared to previous series’s [1], [2], [3] and [4] this patch set
>> >> redefined most of the implementation suitable to fit into existing
>> >> driver-model.
>> >>
>> >> MTD is generic subsystem for underlying flash devices like nand,
>> >> parallel nor, spinor, dataflash etc. So to drive this theory with
>> >> driver model(with an example of block layer) mtd is common device
>> >> interaction for most of  memory technology flashes like nand,
>> >> parallel nor, spinor, dataflash etc, these are treated as interface
>> >> types wrt u-boot driver model.
>> >>
>> >> Once the respective interface driver bind happen, the uclass driver
>> >> will pass an 'interface type' to mtd layer to create device for it,
>> >> for example once spinor ULASS_SPI_NOR driver bind happen, the uclass
>> >> driver of spinor will pass MTD_IF_TYPE_SPI_NOR interface type to
>> >> create mtd device for spinor devices.
>> >>
>> >> SPI-NOR:
>> >> =======
>> >> 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.
>> >
>> > I must admit that I'm a bit confused....
>> >
>> > If you don't mind I would like to ask for clarification of a few things:
>> >
>> >
>> >
>> >>
>> >> =======================================
>> >>              cmd/spinor.c
>> >
>> >                 ^^^^^ - this would be a new set of commands to comply
>> >                 with DM?
>>
>> with this series yes, and we're working on supporting the same with non-
>> dm.
>>
>> >
>> >                 What about "sf" command which we use now to get access
>> >                 to SPI-NOR memory? A lot of boards already use "sf"
>> >                 command... which may be tricky to replace.
>>
>> end-goal will be replace sf with spinor command and removal of 'sf'
>> will be done when the new spi-nor framework stable enough to handle all
>> scenarios which are spi-flash supporting as of now.
>>
>> >
>> >> =======================================
>> >>              mtd-uclass.c
>> >                 ^^^^^ - here we will have a generic MTD layer (as it is
>> >                 in Linux)
>>
>> it is not like in Linux, leaving ops names apart all the code is for creating
>> mtd device for underlying flash devices in the form of interface type during
>> bind. the interface types as of now is spi-nor it can be nand, nor, dataflash
>> etc in future if could be.
>>
>> >
>> >> =======================================
>> >>            spi-nor-uclass.c
>> >> =======================================
>> >>               spi-nor.c
>> >                 ^^^^^^ - why do we need to have spi-nor.c ? Cannot we
>> >                 have its functionality in the spi-nor-uclass.c ?
>> >                 (I'm just curious)
>>
>> spi-nor-uclass.c is an uclass driver for underlying UCLASS_SPI_NOR drivers
>> like m25p80, zynq_qspinor etc but the spi-nor.c is the actual spi-nor core
>> code which handle actual flash specific stuff. and also syncing Linux stuff(if
>> require) becomes easy with spi-nor.c as a separate file.
>>
>> >
>> >> =======================================
>> >> m25p80.c                zynq_qspinor.c
>> >   ^^^^^ - this is the     ^^^^^^^^ - [*]
>> > "generic" spi-nor
>> > driver used in Linux.
>> > I suppose that it will
>> > be reused here?
>>
>> yes - name reused because, I do think the Linux and U-Boot development on
>> spi-nor will follow in-line at some point but the most of code is following U-
>> Boot driver-model.
>>
>> >
>> >> =======================================
>> >> spi-uclass.c
>> >   ^^^^^^^ - why do we
>> > need this uclass?
>>
>> This is an existing uclass spi driver for underlying UCLASS_SPI drivers like
>> drivers/spi/zynq_qspi.c etc
>>
>> >
>> >> =======================================
>> >> zynq_qspi.c
>> >  ^^^^^ - This is probably
>> > the low-level driver for
>> > zynq QSPI IP block - why
>> > do we have zynq_qspinor.c file above [*]?
>> > What is the difference/need of such division?
>>
>> Both the drivers are same, the reason for zynq_qspinor is for testing
>> framework work for two directions like
>> - spi driver interface side through m25p80 cmd/spinor->mtd->spi-nor-
>> uclass->spi-nor->m25p80->zynq_qspi.c
>> - direct spi-nor controller side
>> spinor->mtd->spi-nor-uclass->spi-nor->zynq_qspinor
>>
>> Will remove drivers/spi/zynq_qspi.c once all set.
>
> As mentioned in Zynq TRM, Zynq qspi controller can work in legacy spi mode as well which is same as regular spi controller.
> As you mentioned if you remove from drivers/spi/zynq_qspi and moving it to spi-nor, none can use it in spi legacy mode. Right?

AFAIK, none used till know for generic slaves except for spi-nor. and
main motive here to have support for controller features like BAR,
dual flash however writing this on drivers/spi make difficult have
these.

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

* [U-Boot] [PATCH v10 00/27] dm: Generic MTD Subsystem, with SPI-NOR interface
  2018-01-23  9:59       ` Jagan Teki
@ 2018-01-23 11:50         ` Siva Durga Prasad Paladugu
  0 siblings, 0 replies; 55+ messages in thread
From: Siva Durga Prasad Paladugu @ 2018-01-23 11:50 UTC (permalink / raw)
  To: u-boot

Hi Jagan,

> -----Original Message-----
> From: Jagan Teki [mailto:jagannadh.teki at gmail.com]
> Sent: Tuesday, January 23, 2018 3:29 PM
> To: Siva Durga Prasad Paladugu <sivadur@xilinx.com>
> Cc: Lukasz Majewski <lukma@denx.de>; U-Boot Mailing List <u-
> boot at lists.denx.de>; Tom Rini <trini@konsulko.com>
> Subject: Re: [U-Boot] [PATCH v10 00/27] dm: Generic MTD Subsystem, with
> SPI-NOR interface
> 
> On Tue, Jan 23, 2018 at 3:20 PM, Siva Durga Prasad Paladugu
> <sivadur@xilinx.com> wrote:
> >
> > Hi Jagan,
> >
> >> -----Original Message-----
> >> From: U-Boot [mailto:u-boot-bounces at lists.denx.de] On Behalf Of Jagan
> >> Teki
> >> Sent: Tuesday, January 02, 2018 3:39 PM
> >> To: Lukasz Majewski <lukma@denx.de>
> >> Cc: U-Boot Mailing List <u-boot@lists.denx.de>; Tom Rini
> >> <trini@konsulko.com>
> >> Subject: Re: [U-Boot] [PATCH v10 00/27] dm: Generic MTD Subsystem,
> >> with SPI-NOR interface
> >>
> >> On Thu, Dec 28, 2017 at 8:14 PM, Lukasz Majewski <lukma@denx.de>
> >> wrote:
> >> > Hi Jagan,
> >> >
> >> >> Compared to previous series’s [1], [2], [3] and [4] this patch set
> >> >> redefined most of the implementation suitable to fit into existing
> >> >> driver-model.
> >> >>
> >> >> MTD is generic subsystem for underlying flash devices like nand,
> >> >> parallel nor, spinor, dataflash etc. So to drive this theory with
> >> >> driver model(with an example of block layer) mtd is common device
> >> >> interaction for most of  memory technology flashes like nand,
> >> >> parallel nor, spinor, dataflash etc, these are treated as
> >> >> interface types wrt u-boot driver model.
> >> >>
> >> >> Once the respective interface driver bind happen, the uclass
> >> >> driver will pass an 'interface type' to mtd layer to create device
> >> >> for it, for example once spinor ULASS_SPI_NOR driver bind happen,
> >> >> the uclass driver of spinor will pass MTD_IF_TYPE_SPI_NOR
> >> >> interface type to create mtd device for spinor devices.
> >> >>
> >> >> SPI-NOR:
> >> >> =======
> >> >> 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.
> >> >
> >> > I must admit that I'm a bit confused....
> >> >
> >> > If you don't mind I would like to ask for clarification of a few things:
> >> >
> >> >
> >> >
> >> >>
> >> >> =======================================
> >> >>              cmd/spinor.c
> >> >
> >> >                 ^^^^^ - this would be a new set of commands to comply
> >> >                 with DM?
> >>
> >> with this series yes, and we're working on supporting the same with
> >> non- dm.
> >>
> >> >
> >> >                 What about "sf" command which we use now to get access
> >> >                 to SPI-NOR memory? A lot of boards already use "sf"
> >> >                 command... which may be tricky to replace.
> >>
> >> end-goal will be replace sf with spinor command and removal of 'sf'
> >> will be done when the new spi-nor framework stable enough to handle
> >> all scenarios which are spi-flash supporting as of now.
> >>
> >> >
> >> >> =======================================
> >> >>              mtd-uclass.c
> >> >                 ^^^^^ - here we will have a generic MTD layer (as it is
> >> >                 in Linux)
> >>
> >> it is not like in Linux, leaving ops names apart all the code is for
> >> creating mtd device for underlying flash devices in the form of
> >> interface type during bind. the interface types as of now is spi-nor
> >> it can be nand, nor, dataflash etc in future if could be.
> >>
> >> >
> >> >> =======================================
> >> >>            spi-nor-uclass.c
> >> >> =======================================
> >> >>               spi-nor.c
> >> >                 ^^^^^^ - why do we need to have spi-nor.c ? Cannot we
> >> >                 have its functionality in the spi-nor-uclass.c ?
> >> >                 (I'm just curious)
> >>
> >> spi-nor-uclass.c is an uclass driver for underlying UCLASS_SPI_NOR
> >> drivers like m25p80, zynq_qspinor etc but the spi-nor.c is the actual
> >> spi-nor core code which handle actual flash specific stuff. and also
> >> syncing Linux stuff(if
> >> require) becomes easy with spi-nor.c as a separate file.
> >>
> >> >
> >> >> =======================================
> >> >> m25p80.c                zynq_qspinor.c
> >> >   ^^^^^ - this is the     ^^^^^^^^ - [*]
> >> > "generic" spi-nor
> >> > driver used in Linux.
> >> > I suppose that it will
> >> > be reused here?
> >>
> >> yes - name reused because, I do think the Linux and U-Boot
> >> development on spi-nor will follow in-line at some point but the most
> >> of code is following U- Boot driver-model.
> >>
> >> >
> >> >> =======================================
> >> >> spi-uclass.c
> >> >   ^^^^^^^ - why do we
> >> > need this uclass?
> >>
> >> This is an existing uclass spi driver for underlying UCLASS_SPI
> >> drivers like drivers/spi/zynq_qspi.c etc
> >>
> >> >
> >> >> =======================================
> >> >> zynq_qspi.c
> >> >  ^^^^^ - This is probably
> >> > the low-level driver for
> >> > zynq QSPI IP block - why
> >> > do we have zynq_qspinor.c file above [*]?
> >> > What is the difference/need of such division?
> >>
> >> Both the drivers are same, the reason for zynq_qspinor is for testing
> >> framework work for two directions like
> >> - spi driver interface side through m25p80 cmd/spinor->mtd->spi-nor-
> >> uclass->spi-nor->m25p80->zynq_qspi.c
> >> - direct spi-nor controller side
> >> spinor->mtd->spi-nor-uclass->spi-nor->zynq_qspinor
> >>
> >> Will remove drivers/spi/zynq_qspi.c once all set.
> >
> > As mentioned in Zynq TRM, Zynq qspi controller can work in legacy spi
> mode as well which is same as regular spi controller.
> > As you mentioned if you remove from drivers/spi/zynq_qspi and moving
> it to spi-nor, none can use it in spi legacy mode. Right?
> 
> AFAIK, none used till know for generic slaves except for spi-nor. and main
> motive here to have support for controller features like BAR, dual flash
> however writing this on drivers/spi make difficult have these.

This means, we have to duplicate driver if someone wants to use for legacy spi which is bothering to me.

Thanks,
Siva

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

* [U-Boot] [PATCH v10 00/27] dm: Generic MTD Subsystem, with SPI-NOR interface
  2018-01-03 10:59         ` Lukasz Majewski
@ 2018-01-31  8:07           ` Andy Yan
  0 siblings, 0 replies; 55+ messages in thread
From: Andy Yan @ 2018-01-31  8:07 UTC (permalink / raw)
  To: u-boot

Hi :

2018-01-03 18:59 GMT+08:00 Lukasz Majewski <lukma@denx.de>:

> Hi Jagan,
>
> > On Wed, Jan 3, 2018 at 2:18 PM, Vignesh R <vigneshr@ti.com> wrote:
> > >
> > >
> > > On Tuesday 02 January 2018 03:39 PM, Jagan Teki wrote:
> > >> On Thu, Dec 28, 2017 at 8:14 PM, Lukasz Majewski <lukma@denx.de>
> > >> wrote:
> > >>> Hi Jagan,
> > >>>
> > >>>> Compared to previous series’s [1], [2], [3] and [4] this patch
> > >>>> set redefined most of the implementation suitable to fit into
> > >>>> existing driver-model.
> > >>>>
> > >>>> MTD is generic subsystem for underlying flash devices like nand,
> > >>>> parallel nor, spinor, dataflash etc. So to drive this theory with
> > >>>> driver model(with an example of block layer) mtd is common device
> > >>>> interaction for most of  memory technology flashes like nand,
> > >>>> parallel nor, spinor, dataflash etc, these are treated as
> > >>>> interface types wrt u-boot driver model.
> > >>>>
> > >>>> Once the respective interface driver bind happen, the uclass
> > >>>> driver will pass an 'interface type' to mtd layer to create
> > >>>> device for it, for example once spinor ULASS_SPI_NOR driver bind
> > >>>> happen, the uclass driver of spinor will pass MTD_IF_TYPE_SPI_NOR
> > >>>> interface type to create mtd device for spinor devices.
> > >>>>
> > >>>> SPI-NOR:
> > >>>> =======
> > >>>> 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.
> > >>>
> > >>> I must admit that I'm a bit confused....
> > >>>
> > >>> If you don't mind I would like to ask for clarification of a few
> > >>> things:
> > >>>
> > >>>
> > >>>
> > >>>>
> > >>>> =======================================
> > >>>>              cmd/spinor.c
> > >>>
> > >>>                 ^^^^^ - this would be a new set of commands to
> > >>> comply with DM?
> > >>
> > >> with this series yes, and we're working on supporting the same
> > >> with non-dm.
> > >>>
> > >>>                 What about "sf" command which we use now to get
> > >>> access to SPI-NOR memory? A lot of boards already use "sf"
> > >>>                 command... which may be tricky to replace.
> > >>
> > >> end-goal will be replace sf with spinor command and removal of 'sf'
> > >> will be done when the new spi-nor framework stable enough to handle
> > >> all scenarios which are spi-flash supporting as of now.
> > >
> > > I don't agree on adding new cmd and removing sf. It would be
> > > impractical to change all boot cmds to replace sf with spinor cmd
> > > all over U-Boot. Not to forget the envs already stored on non
> > > volatile media need updation to work with new cmd.
> > > If SPI NOR framework is to abstract all accesses to nor flash
> > > devices in U-Boot, then why cannot it replace the logic
> > > implementing cmd sf? All that is changing is that mtd/spi/* is
> > > replaced by spi-nor.c + m25p80.c. sf probe  can be modified achieve
> > > what spinor dev does sf read for spinor read and so on. Board
> > > configs would just need to enable MTD related configs.
> >
> > I know how hard it is adding new command in u-boot,
>
> Yes, it is. Especially command which duplicates already present
> functionality.
>
> > you can understood
> > the reason for adding new command if you follow the previous versions
> > on this series and I hope you does.
>
> I must admit that this is the first version, which I reviewed.
>
> The only feasible way would be to have new Kconfig option for this
> framework, force spinor for new boards and ..... wait.
>
> After some long time (how long do we struggle with DM
> conversion/Kconfig?) we could think about removing "sf" command.
>
> I do want to emphasis that I do agree with Vignesh - there are many
> boards out there, which do use sf command, with even more dangerous
> situation when company X only plan to update u-boot, but has envs in a
> separate partition. Breaking "sf" equals to brick of on-field
> devices....
>
> IMHO - we shall have sf command as an alias to new "spinor" command
> (even by calling run_command("spinor....");).
>
> > we have been adding mtd, spi-nor
> > changes to existing mtd/spi and sf.c since from first series and
> > observed many issue with respective to framework design(where we move
> > spi-nor controller drivers on to mtd side) along with driver model. In
> > v9 we worked on designing MTD UCLASS where mtd command can be commonly
> > interfaced to all underlying flash devices. and from continuous
> > evaluation on driver model this series we designed MTD uclass can be a
> > generic and make run-time creation of underlying flash devices with
> > interface type, spi-nor is one of the interface. So to make the
> > framework suitable to command interface the new command named as
> > spinor. adding/supporting all these new design on top of mtd/spi or sf
> > doesn’t smooth easy which is proved on previous version. technically
> > sf termed as spi-flash comprise of spinor and spinand, spinand can be
> > another interface type with spinand command and adding new features on
> > legacy code doesn't make sense to me it will eventually breaking
> > legacy dependencies.
> >
> > Will all these new framework design, driver model, feasibility to sync
> > Linux spi-nor.c we adding relevant command, and env.
> >
>
>
>

Can we make a finall direction now,  more than one year passed since
Jagan's first version, and now it gets V10.
From the Linux kernel upstream, the spi nor framework switch to mtd/spi-nor
for a long time, and it works fine now.
I hope u-boot spi nor can switch to mtd/spi-nor too, so we can share many
logic with the kernel code.
Besides, I have a rockchip SPI-NOR controller(SFC), I wrote two different
version drivers, one is based on
drivers/spi, another is based on Jagan's mtd/spi-nor , but I don't know how
to move forward, as the direction is not
clear.

>
> Best regards,
>
> Lukasz Majewski
>
> --
>
> DENX Software Engineering GmbH,      Managing Director: Wolfgang Denk
> HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
> Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
>
> _______________________________________________
> U-Boot mailing list
> U-Boot at lists.denx.de
> https://lists.denx.de/listinfo/u-boot
>
>

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

* [U-Boot] [PATCH v10 03/27] mtd: add SPI-NOR core support
  2017-12-28  6:12 ` [U-Boot] [PATCH v10 03/27] mtd: add SPI-NOR core support Jagan Teki
                     ` (3 preceding siblings ...)
  2018-01-04  2:33   ` Andy Yan
@ 2018-02-28  9:42   ` Prabhakar Kushwaha
  2018-02-28 12:10     ` Boris Brezillon
  2018-03-06  6:38     ` Jagan Teki
  4 siblings, 2 replies; 55+ messages in thread
From: Prabhakar Kushwaha @ 2018-02-28  9:42 UTC (permalink / raw)
  To: u-boot

[Resending on correct patch of the patch-set]

Dear Jagan,


> -----Original Message-----
> From: U-Boot [mailto:u-boot-bounces at lists.denx.de] On Behalf Of Jagan
> Teki
> Sent: Thursday, December 28, 2017 11:42 AM
> To: u-boot at lists.denx.de
> Cc: Tom Rini <trini@konsulko.com>
> Subject: [U-Boot] [PATCH v10 03/27] mtd: add SPI-NOR core support
> 
> 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/spinor.c
> =======================================
>              mtd-uclass.c
> =======================================
>            spi-nor-uclass.c
> =======================================
>               spi-nor.c
> =======================================
> m25p80.c                zynq_qspinor.c
> =======================================
> spi-uclass.c
> =======================================
> zynq_qspi.c
> =======================================
>         #####SPI NOR chip######
> =======================================
> 

As per this patch-set, fsl_qspi is looks to be getting proposed in driver/mtd/spi-nor/ folder.

fsl_qspi is supporting both flash and fpga.  We are not sure about its location. 

There is an on-going effort for similar type of requirement in Linux by Boris Brezillon . It is dealing with controllers supporting NORs, NANDs, SRAMs etc. 
http://patchwork.ozlabs.org/project/linux-mtd/list/?series=27088

Borris has also ported fsl_qspi in driver/spi to use this new framework. It is still not completely tested.  
https://github.com/bbrezillon/linux/commit/43cc45764b975bfbb191de3f6a37e073da1a2706


Will you also follow similar approach as being done in http://patchwork.ozlabs.org/project/linux-mtd/list/?series=27088 for longer term?

For Now, We are planning to update fsl_qspi driver to support dynamic LUT. Similar patch is in progress in Linux http://patchwork.ozlabs.org/project/linux-mtd/list/?series=26084
Now we are confused, should be port fsl_qspi in driver/mtd/spi-nor and then update driver Or We update driver/spi/fsl_qspi for dynamic LUTs. We may need to modify existing framework to get all required info for dynamic LUT.  

Also we want some change in framework like support of
 -  4 byte address and SFDP :  http://patchwork.ozlabs.org/project/uboot/list/?series=19621&state=*
 -  SMPT : in discussion in Linux http://patchwork.ozlabs.org/patch/869718/
 Which code base should we use?   u-boot-spi.git branch mtd-spinor-working  or u-boot.git master branch

--pk

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

* [U-Boot] [PATCH v10 03/27] mtd: add SPI-NOR core support
  2018-02-28  9:42   ` Prabhakar Kushwaha
@ 2018-02-28 12:10     ` Boris Brezillon
  2018-03-06  5:59       ` Prabhakar Kushwaha
  2018-03-06  6:38     ` Jagan Teki
  1 sibling, 1 reply; 55+ messages in thread
From: Boris Brezillon @ 2018-02-28 12:10 UTC (permalink / raw)
  To: u-boot

Prabhakar, Jagan,

On Wed, 28 Feb 2018 09:42:11 +0000
Prabhakar Kushwaha <prabhakar.kushwaha@nxp.com> wrote:

> [Resending on correct patch of the patch-set]
> 
> Dear Jagan,
> 
> 
> > -----Original Message-----
> > From: U-Boot [mailto:u-boot-bounces at lists.denx.de] On Behalf Of
> > Jagan Teki
> > Sent: Thursday, December 28, 2017 11:42 AM
> > To: u-boot at lists.denx.de
> > Cc: Tom Rini <trini@konsulko.com>
> > Subject: [U-Boot] [PATCH v10 03/27] mtd: add SPI-NOR core support
> > 
> > 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

Okay, I've been working a bit with this controller, and can say it's
not quite true. This controller supports any kind of device that
expects memory-like operations (or whatever you want to call them),
that is, everything that is formed of one opcode, X address cycles, Y
dummy cycles and Z data in/out cycles (X, Y and Z can be zero).

Actually, I even think it could support regular SPI transfers, all we'd
have to do is use READ/WRITE instructions to do the transfers.

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

I've discussed it privately with Cyrille before I sent the spi-mem
extension proposal, and he seemed to agree with the approach. I don't
know what his opinion is now that the RFC has been posted, but if he
hasn't changed his mind, that means Linux implementation is going in
the opposite direction. So it's probably worth reconsidering this move.

Cyrille, could you clarify your opinion? I'm also waiting your feedback
on the RFC to send a v2 addressing the comments I had from other people.

> > 
> > =======================================
> >              cmd/spinor.c
> > =======================================
> >              mtd-uclass.c
> > =======================================
> >            spi-nor-uclass.c
> > =======================================
> >               spi-nor.c
> > =======================================
> > m25p80.c                zynq_qspinor.c
> > =======================================
> > spi-uclass.c
> > =======================================
> > zynq_qspi.c
> > =======================================
> >         #####SPI NOR chip######
> > =======================================
> >   
> 
> As per this patch-set, fsl_qspi is looks to be getting proposed in
> driver/mtd/spi-nor/ folder.
> 
> fsl_qspi is supporting both flash and fpga.  We are not sure about
> its location. 
> 
> There is an on-going effort for similar type of requirement in Linux
> by Boris Brezillon . It is dealing with controllers supporting NORs,
> NANDs, SRAMs etc.
> http://patchwork.ozlabs.org/project/linux-mtd/list/?series=27088
> 
> Borris has also ported fsl_qspi in driver/spi to use this new
> framework. It is still not completely tested.
> https://github.com/bbrezillon/linux/commit/43cc45764b975bfbb191de3f6a37e073da1a2706
> 
> 
> Will you also follow similar approach as being done in
> http://patchwork.ozlabs.org/project/linux-mtd/list/?series=27088 for
> longer term?

That would be great if the code base could converge.

Regards,

Boris

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

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

* [U-Boot] [PATCH v10 03/27] mtd: add SPI-NOR core support
  2018-02-28 12:10     ` Boris Brezillon
@ 2018-03-06  5:59       ` Prabhakar Kushwaha
  0 siblings, 0 replies; 55+ messages in thread
From: Prabhakar Kushwaha @ 2018-03-06  5:59 UTC (permalink / raw)
  To: u-boot

Dear Jagan,


> -----Original Message-----
> From: Boris Brezillon [mailto:boris.brezillon at bootlin.com]
> Sent: Wednesday, February 28, 2018 5:40 PM
> To: Prabhakar Kushwaha <prabhakar.kushwaha@nxp.com>; Jagan Teki
> <jagan@amarulasolutions.com>; Cyrille Pitchen
> <cyrille.pitchen@wedev4u.fr>
> Cc: u-boot at lists.denx.de; Suresh Gupta <suresh.gupta@nxp.com>; Yogesh
> Narayan Gaur <yogeshnarayan.gaur@nxp.com>; Poonam Aggrwal
> <poonam.aggrwal@nxp.com>; Ashish Kumar <ashish.kumar@nxp.com>;
> Han Xu <han.xu@nxp.com>; Frieder Schrempf
> <frieder.schrempf@exceet.de>; Boris Brezillon <boris.brezillon@free-
> electrons.com>
> Subject: Re: [U-Boot] [PATCH v10 03/27] mtd: add SPI-NOR core support
> 
> Prabhakar, Jagan,
> 
> On Wed, 28 Feb 2018 09:42:11 +0000
> Prabhakar Kushwaha <prabhakar.kushwaha@nxp.com> wrote:
> 
> > [Resending on correct patch of the patch-set]
> >
> > Dear Jagan,
> >
> >
> > > -----Original Message-----
> > > From: U-Boot [mailto:u-boot-bounces at lists.denx.de] On Behalf Of
> > > Jagan Teki
> > > Sent: Thursday, December 28, 2017 11:42 AM
> > > To: u-boot at lists.denx.de
> > > Cc: Tom Rini <trini@konsulko.com>
> > > Subject: [U-Boot] [PATCH v10 03/27] mtd: add SPI-NOR core support
> > >
> > > 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
> 
> Okay, I've been working a bit with this controller, and can say it's
> not quite true. This controller supports any kind of device that
> expects memory-like operations (or whatever you want to call them),
> that is, everything that is formed of one opcode, X address cycles, Y
> dummy cycles and Z data in/out cycles (X, Y and Z can be zero).

> Actually, I even think it could support regular SPI transfers, all we'd
> have to do is use READ/WRITE instructions to do the transfers.

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

> I've discussed it privately with Cyrille before I sent the spi-mem
> extension proposal, and he seemed to agree with the approach. I don't
> know what his opinion is now that the RFC has been posted, but if he
> hasn't changed his mind, that means Linux implementation is going in
> the opposite direction. So it's probably worth reconsidering this move.

> Cyrille, could you clarify your opinion? I'm also waiting your feedback
> on the RFC to send a v2 addressing the comments I had from other people.

> > > 
> > > =======================================
> > >             cmd/spinor.c
> > > =======================================
> > >              mtd-uclass.c
> > > =======================================
> > >           spi-nor-uclass.c
> > > =======================================
> > >               spi-nor.c
> > > =======================================
> > > m25p80.c                zynq_qspinor.c
> > > =======================================
> > > spi-uclass.c
> > > =======================================
> > > zynq_qspi.c
> > > =======================================
> > >         #####SPI NOR chip######
> > > =======================================
> > >   
> 
> > As per this patch-set, fsl_qspi is looks to be getting proposed in
> > driver/mtd/spi-nor/ folder.
> > 
> > fsl_qspi is supporting both flash and fpga.  We are not sure about
> > its location. 
> > 
> > There is an on-going effort for similar type of requirement in Linux
> > by Boris Brezillon . It is dealing with controllers supporting NORs,
> > NANDs, SRAMs etc.
> > http://patchwork.ozlabs.org/project/linux-mtd/list/?series=27088
> > 
> > Borris has also ported fsl_qspi in driver/spi to use this new
> > framework. It is still not completely tested.
> > https://github.com/bbrezillon/linux/commit/43cc45764b975bfbb191de3f6a37e073da1a2706
> > 
> > 
> > Will you also follow similar approach as being done in
> > http://patchwork.ozlabs.org/project/linux-mtd/list/?series=27088 for
> > longer term?

> That would be great if the code base could converge.

Please help us with your strategy towards qspi framework.
We are waiting for your direction before creating/sending patches of qspi driver & framework in upstream. 

--pk

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

* [U-Boot] [PATCH v10 03/27] mtd: add SPI-NOR core support
  2018-02-28  9:42   ` Prabhakar Kushwaha
  2018-02-28 12:10     ` Boris Brezillon
@ 2018-03-06  6:38     ` Jagan Teki
  1 sibling, 0 replies; 55+ messages in thread
From: Jagan Teki @ 2018-03-06  6:38 UTC (permalink / raw)
  To: u-boot

On Wed, Feb 28, 2018 at 3:12 PM, Prabhakar Kushwaha
<prabhakar.kushwaha@nxp.com> wrote:
> [Resending on correct patch of the patch-set]
>
> Dear Jagan,
>
>
>> -----Original Message-----
>> From: U-Boot [mailto:u-boot-bounces at lists.denx.de] On Behalf Of Jagan
>> Teki
>> Sent: Thursday, December 28, 2017 11:42 AM
>> To: u-boot at lists.denx.de
>> Cc: Tom Rini <trini@konsulko.com>
>> Subject: [U-Boot] [PATCH v10 03/27] mtd: add SPI-NOR core support
>>
>> 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/spinor.c
>> =======================================
>>              mtd-uclass.c
>> =======================================
>>            spi-nor-uclass.c
>> =======================================
>>               spi-nor.c
>> =======================================
>> m25p80.c                zynq_qspinor.c
>> =======================================
>> spi-uclass.c
>> =======================================
>> zynq_qspi.c
>> =======================================
>>         #####SPI NOR chip######
>> =======================================
>>
>
> As per this patch-set, fsl_qspi is looks to be getting proposed in driver/mtd/spi-nor/ folder.
>
> fsl_qspi is supporting both flash and fpga.  We are not sure about its location.
>
> There is an on-going effort for similar type of requirement in Linux by Boris Brezillon . It is dealing with controllers supporting NORs, NANDs, SRAMs etc.
> http://patchwork.ozlabs.org/project/linux-mtd/list/?series=27088
>
> Borris has also ported fsl_qspi in driver/spi to use this new framework. It is still not completely tested.
> https://github.com/bbrezillon/linux/commit/43cc45764b975bfbb191de3f6a37e073da1a2706

These look going in reverse direction, since
drivers/mtd/spi-nor/fsl_qspi was meant for SPI-NOR flash(from initial
version SPI-NOR framework patches) and now it going in driver/spi..
look like it need more discussion with respective people who involved
on these.

>
>
> Will you also follow similar approach as being done in http://patchwork.ozlabs.org/project/linux-mtd/list/?series=27088 for longer term?
>
> For Now, We are planning to update fsl_qspi driver to support dynamic LUT. Similar patch is in progress in Linux http://patchwork.ozlabs.org/project/linux-mtd/list/?series=26084
> Now we are confused, should be port fsl_qspi in driver/mtd/spi-nor and then update driver Or We update driver/spi/fsl_qspi for dynamic LUTs. We may need to modify existing framework to get all required info for dynamic LUT.

As of now, I would like to write it in driver/mtd/spi-nor assuming all
LUT or fsl related changes donesn't harm core areas so-that moving
back to drivers/spi might be easy if Linux does.

>
> Also we want some change in framework like support of
>  -  4 byte address and SFDP :  http://patchwork.ozlabs.org/project/uboot/list/?series=19621&state=*
>  -  SMPT : in discussion in Linux http://patchwork.ozlabs.org/patch/869718/
>  Which code base should we use?   u-boot-spi.git branch mtd-spinor-working  or u-boot.git master branch

Pls use this https://github.com/openedev/u-boot-spi/commits/master

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

end of thread, other threads:[~2018-03-06  6:38 UTC | newest]

Thread overview: 55+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-12-28  6:12 [U-Boot] [PATCH v10 00/27] dm: Generic MTD Subsystem, with SPI-NOR interface Jagan Teki
2017-12-28  6:12 ` [U-Boot] [PATCH v10 01/27] mtd: Add mtd core ops Jagan Teki
2017-12-28  6:12 ` [U-Boot] [PATCH v10 02/27] mtd: add mtd device create operations Jagan Teki
2017-12-28  6:12 ` [U-Boot] [PATCH v10 03/27] mtd: add SPI-NOR core support Jagan Teki
2017-12-29  9:25   ` Andy Yan
2018-01-02 10:18   ` Prabhakar Kushwaha
2018-01-02 10:31     ` Jagan Teki
2018-01-03  8:49   ` Vignesh R
2018-01-03  9:32     ` Jagan Teki
2018-01-03  9:56       ` Vignesh R
2018-01-03 10:07         ` Jagan Teki
2018-01-04  2:33   ` Andy Yan
2018-02-28  9:42   ` Prabhakar Kushwaha
2018-02-28 12:10     ` Boris Brezillon
2018-03-06  5:59       ` Prabhakar Kushwaha
2018-03-06  6:38     ` Jagan Teki
2017-12-28  6:12 ` [U-Boot] [PATCH v10 04/27] mtd: spi-nor: sync/modify sst write operations Jagan Teki
2017-12-28  6:12 ` [U-Boot] [PATCH v10 05/27] mtd: spi-nor: sync/modify lock operations Jagan Teki
2017-12-28  6:12 ` [U-Boot] [PATCH v10 06/27] mtd: spi-nor: Kconfig: Add MTD_SPI_NOR entry Jagan Teki
2017-12-28  6:12 ` [U-Boot] [PATCH v10 07/27] mtd: spi-nor: Kconfig: Add MTD_SPI_NOR_USE_4K_SECTORS Jagan Teki
2017-12-28  6:12 ` [U-Boot] [PATCH v10 08/27] mtd: spi-nor: Kconfig: Add SPI_NOR_MISC entry Jagan Teki
2017-12-28  6:12 ` [U-Boot] [PATCH v10 09/27] mtd: spi-nor: Kconfig: Add SPI_NOR_MACRONIX entry Jagan Teki
2017-12-28  6:12 ` [U-Boot] [PATCH v10 10/27] mtd: spi-nor: Kconfig: Add SPI_NOR_SPANSION entry Jagan Teki
2017-12-28  6:12 ` [U-Boot] [PATCH v10 11/27] mtd: spi-nor: Kconfig: Add SPI_NOR_STMICRO entry Jagan Teki
2017-12-28  6:12 ` [U-Boot] [PATCH v10 12/27] mtd: spi-nor: Kconfig: Add SPI_NOR_SST entry Jagan Teki
2017-12-28  6:12 ` [U-Boot] [PATCH v10 13/27] mtd: spi-nor: Kconfig: Add SPI_NOR_WINBOND entry Jagan Teki
2017-12-28  6:12 ` [U-Boot] [PATCH v10 14/27] mtd-uclass: use platdata_auto_alloc Jagan Teki
2017-12-28  6:12 ` [U-Boot] [PATCH v10 15/27] spi: Add spi_write_then_read Jagan Teki
2017-12-28  6:12 ` [U-Boot] [PATCH v10 16/27] mtd: spi-nor: Add m25p80 driver Jagan Teki
2017-12-28  6:12 ` [U-Boot] [PATCH v10 17/27] mtd: spi-nor: Kconfig: Add MTD_M25P80 entry Jagan Teki
2017-12-28  6:12 ` [U-Boot] [PATCH v10 18/27] mtd: spi-nor: Add zynq qspinor driver Jagan Teki
2017-12-28  6:12 ` [U-Boot] [PATCH v10 19/27] mtd: spi-nor: zynq_qspi: Kconfig: Add MTD_ZYNQ Jagan Teki
2017-12-28  6:12 ` [U-Boot] [PATCH v10 20/27] mtd: spi-nor: Add 4-byte addresswidth support Jagan Teki
2017-12-28  8:06   ` Cyrille Pitchen
2017-12-28  8:08     ` Cyrille Pitchen
2017-12-28  6:12 ` [U-Boot] [PATCH v10 21/27] cmd: add spinor cmd support Jagan Teki
2017-12-28  6:12 ` [U-Boot] [PATCH v10 22/27] cmd: spinor: sync/update protect command Jagan Teki
2017-12-28  6:12 ` [U-Boot] [PATCH v10 23/27] board_r: initialize spi_nor Jagan Teki
2018-01-08  3:52   ` Simon Glass
2017-12-28  6:12 ` [U-Boot] [PATCH v10 24/27] env: add spi-nor environment Jagan Teki
2018-01-04  7:06   ` Prabhakar Kushwaha
2017-12-28  6:12 ` [U-Boot] [PATCH v10 25/27] arm: dts: zynq: Add zynq-qspinor node Jagan Teki
2017-12-28  6:12 ` [U-Boot] [PATCH v10 26/27] dm: zynq: microzed: enable MTD/SPI-NOR framework Jagan Teki
2017-12-28  6:12 ` [U-Boot] [PATCH v10 27/27] test: dm: add tests for mtd devices Jagan Teki
2017-12-28 14:44 ` [U-Boot] [PATCH v10 00/27] dm: Generic MTD Subsystem, with SPI-NOR interface Lukasz Majewski
2018-01-02 10:09   ` Jagan Teki
2018-01-03  8:48     ` Vignesh R
2018-01-03  9:24       ` Jagan Teki
2018-01-03 10:59         ` Lukasz Majewski
2018-01-31  8:07           ` Andy Yan
2018-01-04 11:52         ` Vignesh R
2018-01-23  9:50     ` Siva Durga Prasad Paladugu
2018-01-23  9:59       ` Jagan Teki
2018-01-23 11:50         ` Siva Durga Prasad Paladugu
2018-01-23  9:00 ` Siva Durga Prasad Paladugu

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.