Skip to contentSkip to conversation

dm: Generic MTD Subsystem, with SPI-NOR interface

PATCH New Jagan Teki 10 participants 55 messages Dec 28, 2017 – Mar 6, 2018

Subsystems (6)
lore
Share & tools
lore

Jagan Teki

author
#0 lore raw

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

=======================================
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
Signature · 1 line
2.7.4
author
#1 lore raw

PATCH v10 1/27 mtd: Add mtd core ops

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

---
 drivers/mtd/mtd-uclass.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++
 include/mtd.h            | 46 ++++++++++++++++++++++++++++++++++++
 2 files changed, 107 insertions(+)
drivers/mtd/mtd-uclass.c +61 -0
index 7b7c48e..d2c587f 100644
@@ -1,4 +1,5 @@
 /*
+ * Copyright (C) 2016 Jagan Teki <[email protected]>
  * Copyright (C) 2015 Thomas Chou <[email protected]>
  *
  * 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.
include/mtd.h +46 -0

50 lines not on this page · raw message

Signature · 1 line
2.7.4
author
#2 lore raw

PATCH v10 2/27 mtd: add mtd device create operations

In reply to Jagan Teki

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.

---
 drivers/mtd/mtd-uclass.c | 121 +++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/mtd/mtd.h  |  14 ++++++
 include/mtd.h            | 116 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 251 insertions(+)
drivers/mtd/mtd-uclass.c +121 -0
index d2c587f..c94afe9 100644
@@ -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.
include/linux/mtd/mtd.h +14 -0
index ba4cbba..6ec9763 100644
@@ -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,
include/mtd.h +116 -0

120 lines not on this page · raw message

Signature · 1 line
2.7.4
author
#3 lore raw

PATCH v10 3/27 mtd: add SPI-NOR core support

In reply to Jagan Teki

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

=======================================

---
 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
Makefile +1 -0
index e6d309a..70b5202 100644
@@ -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/
drivers/mtd/spi-nor/Makefile new file +7 -0
new file mode 100644
index 0000000..c1212a8
@@ -0,0 +1,7 @@
+#
+# Copyright (C) 2016 Jagan Teki <[email protected]>
+#
+# SPDX-License-Identifier:	GPL-2.0+
+
+## spi-nor core
+obj-y	+= spi-nor.o spi-nor-uclass.o spi-nor-ids.o
drivers/mtd/spi-nor/spi-nor-ids.c new file +184 -0

184 lines not on this page · raw message

drivers/mtd/spi-nor/spi-nor-uclass.c new file +143 -0

143 lines not on this page · raw message

drivers/mtd/spi-nor/spi-nor.c new file +569 -0

569 lines not on this page · raw message

include/dm/uclass-id.h +1 -0
index 3fc2083..06541a4 100644
@@ -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 */
include/linux/mtd/spi-nor.h new file +217 -0

217 lines not on this page · raw message

Signature · 1 line
2.7.4
#4 lore raw

PATCH v10 3/27 mtd: add SPI-NOR core support

Hi Jagan:

2017-12-28 14:12 GMT+08:00 Jagan Teki <[email protected]>:

Quoted 587 lines

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

=======================================

---
 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
Makefile +1 -0
index e6d309a..70b5202 100644
@@ -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/
drivers/mtd/spi-nor/Makefile new file +7 -0
new file mode 100644
index 0000000..c1212a8
@@ -0,0 +1,7 @@
+#
+# Copyright (C) 2016 Jagan Teki <[email protected]>
+#
+# SPDX-License-Identifier:     GPL-2.0+
+
+## spi-nor core
+obj-y  += spi-nor.o spi-nor-uclass.o spi-nor-ids.o
drivers/mtd/spi-nor/spi-nor-ids.c new file +49 -0
new file mode 100644
index 0000000..db95655
@@ -0,0 +1,184 @@
+/*
+ * SPI NOR IDs.
+ *
+ * Copyright (C) 2016 Jagan Teki <[email protected]>
+ *
+ * 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) },

drivers/mtd/spi-nor/spi-nor-ids.c new file +2 -0
+       {"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) },

drivers/mtd/spi-nor/spi-nor-ids.c new file +9 -0
+#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) },
drivers/mtd/spi-nor/spi-nor-ids.c new file +9 -0
+#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) },

drivers/mtd/spi-nor/spi-nor-ids.c new file +4 -0
+       {"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) },
drivers/mtd/spi-nor/spi-nor-ids.c new file +3 -0
+#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) },

drivers/mtd/spi-nor/spi-nor-ids.c new file +6 -0
+#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) },
drivers/mtd/spi-nor/spi-nor-ids.c new file +4 -0
+#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)
},

drivers/mtd/spi-nor/spi-nor-ids.c new file +4 -0
+
+       /* EON */
+       {"en25q32b",       INFO(0x1c3016, 0x0, 64 * 1024,    64, 0) },
+       {"en25q64",        INFO(0x1c3017, 0x0, 64 * 1024,   128, SECT_4K)

},

drivers/mtd/spi-nor/spi-nor-ids.c new file +5 -0
+       {"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)
},

drivers/mtd/spi-nor/spi-nor-ids.c new file +22 -0
+
+       /* 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)
+        */
+};
drivers/mtd/spi-nor/spi-nor-uclass.c new file +80 -0
new file mode 100644
index 0000000..919682d
@@ -0,0 +1,143 @@
+/*
+ * SPI NOR Core framework.
+ *
+ * Copyright (C) 2016 Jagan Teki <[email protected]>
+ *
+ * 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);

drivers/mtd/spi-nor/spi-nor-uclass.c new file +14 -0
+       }
+
+       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,

drivers/mtd/spi-nor/spi-nor-uclass.c new file +14 -0
+                                &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);

drivers/mtd/spi-nor/spi-nor-uclass.c new file +6 -0
+       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);

drivers/mtd/spi-nor/spi-nor-uclass.c new file +29 -0
+               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),
+};
drivers/mtd/spi-nor/spi-nor.c new file +25 -0
new file mode 100644
index 0000000..09fb8ca
@@ -0,0 +1,569 @@
+/*
+ * SPI NOR Core framework.
+ *
+ * Copyright (C) 2016 Jagan Teki <[email protected]>
+ *
+ * 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);

drivers/mtd/spi-nor/spi-nor.c new file +6 -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);

drivers/mtd/spi-nor/spi-nor.c new file +49 -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;

drivers/mtd/spi-nor/spi-nor.c line 90

Quoted 10 lines
drivers/mtd/spi-nor/spi-nor.c new file +10 -0
+       }
+
+       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

Quoted 354 lines

+ */

drivers/mtd/spi-nor/spi-nor.c new file +50 -0
+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)

drivers/mtd/spi-nor/spi-nor.c new file +76 -0
+{
+       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);

drivers/mtd/spi-nor/spi-nor.c new file +43 -0
+               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));

drivers/mtd/spi-nor/spi-nor.c new file +12 -0
+
+               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);

drivers/mtd/spi-nor/spi-nor.c new file +110 -0
+               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)

drivers/mtd/spi-nor/spi-nor.c new file +44 -0
+{
+       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__);

drivers/mtd/spi-nor/spi-nor.c new file +11 -0
+               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);

drivers/mtd/spi-nor/spi-nor.c line 447

Quoted 10 lines
drivers/mtd/spi-nor/spi-nor.c new file +10 -0
+       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);

Quoted 116 lines
drivers/mtd/spi-nor/spi-nor.c new file +9 -0
+       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

drivers/mtd/spi-nor/spi-nor.c new file +30 -0
+        * (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

drivers/mtd/spi-nor/spi-nor.c new file +45 -0
+        * 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",

drivers/mtd/spi-nor/spi-nor.c new file +20 -0
+                             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)

drivers/mtd/spi-nor/spi-nor.c line 566

Quoted 10 lines
drivers/mtd/spi-nor/spi-nor.c new file +10 -0
+       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

Quoted 259 lines
drivers/mtd/spi-nor/spi-nor.c new file +3 -0
+       nor->init_done = 0;
+       return ret;
+}
include/dm/uclass-id.h +1 -0
index 3fc2083..06541a4 100644
@@ -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 */
include/linux/mtd/spi-nor.h new file +18 -0
new file mode 100644
index 0000000..e1688e2
@@ -0,0 +1,217 @@
+/*
+ * SPI NOR Core header file.
+ *
+ * Copyright (C) 2016 Jagan Teki <[email protected]>
+ *
+ * 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.
+ */

include/linux/mtd/spi-nor.h new file +12 -0
+#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.
+ */

include/linux/mtd/spi-nor.h new file +5 -0
+#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) */

include/linux/mtd/spi-nor.h new file +7 -0
+#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)
*/

include/linux/mtd/spi-nor.h new file +13 -0
+#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 */

include/linux/mtd/spi-nor.h new file +18 -0
+
+/* 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 */

include/linux/mtd/spi-nor.h new file +9 -0
+
+/* 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
+ */

include/linux/mtd/spi-nor.h new file +23 -0
+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]))

include/linux/mtd/spi-nor.h new file +31 -0
+#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)

include/linux/mtd/spi-nor.h new file +14 -0
+};
+
+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

+ */

include/linux/mtd/spi-nor.h new file +44 -1
+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

#5 lore raw

PATCH v10 3/27 mtd: add SPI-NOR core support

In reply to Jagan Teki

Hi Jagan,

Quoted 39 lines

-----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 <[email protected]>
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>

Quoted 92 lines

+ * SPDX-License-Identifier: GPL-2.0+
+ */

(quoted diff) +90 -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;
+	}

Review

Quoted 10 lines
(quoted diff) +10 -0
+
+	/* 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

#6 lore raw

PATCH v10 3/27 mtd: add SPI-NOR core support

Quoted 152 lines · Prabhakar Kushwaha

Hi Jagan,

Quoted 39 lines

-----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 <[email protected]>
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>

Quoted 92 lines

+ * SPDX-License-Identifier: GPL-2.0+
+ */

(quoted diff) +90 -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;
+     }

Review

Quoted 10 lines
(quoted diff) +10 -0
+
+     /* 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.

Quoted 6 lines

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.

maintainer
#7 lore raw

PATCH v10 3/27 mtd: add SPI-NOR core support

In reply to Jagan Teki

On Thursday 28 December 2017 11:42 AM, Jagan Teki wrote:
[...]

drivers/mtd/spi-nor/spi-nor-uclass.c line 125

Quoted 5 lines
drivers/mtd/spi-nor/spi-nor-uclass.c new file +5 -0
+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?

Quoted 18 lines
drivers/mtd/spi-nor/spi-nor-uclass.c new file +18 -0
+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),
+};

[...]

Quoted 6 lines
include/linux/mtd/spi-nor.h new file +0 -0
new file mode 100644
index 0000000..e1688e2
@@ -0,0 +1,217 @@

[...]

Quoted 5 lines
include/linux/mtd/spi-nor.h new file +5 -0
+struct spi_nor {
+	struct udevice		*dev;
+	const char		*name;
+	u8			init_done;
+	u32			page_size;

include/linux/mtd/spi-nor.h line 187

Quoted 10 lines
include/linux/mtd/spi-nor.h new file +9 -0
+	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?

Quoted 31 lines
include/linux/mtd/spi-nor.h new file +30 -0
+	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 */
Signature · 2 lines
Regards
Vignesh
#8 lore raw

PATCH v10 3/27 mtd: add SPI-NOR core support

Quoted 11 lines · Vignesh R

On Thursday 28 December 2017 11:42 AM, Jagan Teki wrote:
[...]

drivers/mtd/spi-nor/spi-nor-uclass.c line 125

Quoted 5 lines
drivers/mtd/spi-nor/spi-nor-uclass.c new file +5 -0
+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

Quoted 43 lines
Quoted 19 lines
drivers/mtd/spi-nor/spi-nor-uclass.c new file +18 -0
+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),
+};

[...]

Quoted 6 lines
include/linux/mtd/spi-nor.h new file +0 -0
new file mode 100644
index 0000000..e1688e2
@@ -0,0 +1,217 @@

[...]

Quoted 13 lines
include/linux/mtd/spi-nor.h new file +13 -0
+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;
Quoted 4 lines
Quoted 1 line

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

Signature · 4 lines
Jagan Teki
Free Software Engineer | www.openedev.com
U-Boot, Linux | Upstream Maintainer
Hyderabad, India.
maintainer
#9 lore raw

PATCH v10 3/27 mtd: add SPI-NOR core support

Quoted 58 lines · Jagan Teki
Quoted 11 lines · Vignesh R

On Thursday 28 December 2017 11:42 AM, Jagan Teki wrote:
[...]

drivers/mtd/spi-nor/spi-nor-uclass.c line 125

Quoted 5 lines
drivers/mtd/spi-nor/spi-nor-uclass.c new file +5 -0
+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

Quoted 43 lines
Quoted 19 lines
drivers/mtd/spi-nor/spi-nor-uclass.c new file +18 -0
+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),
+};

[...]

Quoted 6 lines
include/linux/mtd/spi-nor.h new file +0 -0
new file mode 100644
index 0000000..e1688e2
@@ -0,0 +1,217 @@

[...]

Quoted 13 lines
include/linux/mtd/spi-nor.h new file +13 -0
+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;
Quoted 7 lines
Quoted 4 lines
Quoted 1 line

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

Signature · 2 lines
Regards
Vignesh
#10 lore raw

PATCH v10 3/27 mtd: add SPI-NOR core support

Quoted 66 lines · Vignesh R
Quoted 63 lines · Jagan Teki
Quoted 11 lines · Vignesh R

On Thursday 28 December 2017 11:42 AM, Jagan Teki wrote:
[...]

drivers/mtd/spi-nor/spi-nor-uclass.c line 125

Quoted 5 lines
drivers/mtd/spi-nor/spi-nor-uclass.c new file +5 -0
+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

Quoted 47 lines
Quoted 19 lines
drivers/mtd/spi-nor/spi-nor-uclass.c new file +18 -0
+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),
+};

[...]

Quoted 6 lines
include/linux/mtd/spi-nor.h new file +0 -0
new file mode 100644
index 0000000..e1688e2
@@ -0,0 +1,217 @@

[...]

Quoted 5 lines
include/linux/mtd/spi-nor.h new file +5 -0
+struct spi_nor {
+     struct udevice          *dev;
+     const char              *name;
+     u8                      init_done;
+     u32                     page_size;

include/linux/mtd/spi-nor.h line 187

Quoted 10 lines
include/linux/mtd/spi-nor.h new file +9 -0
+     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?

Quoted 7 lines
Quoted 2 lines

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.

#11 lore raw

PATCH v10 3/27 mtd: add SPI-NOR core support

In reply to Jagan Teki

Hi Jagan:

2017-12-28 14:12 GMT+08:00 Jagan Teki <[email protected]>:

Quoted 710 lines

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

=======================================

---
 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
Makefile +1 -0
index e6d309a..70b5202 100644
@@ -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/
drivers/mtd/spi-nor/Makefile new file +7 -0
new file mode 100644
index 0000000..c1212a8
@@ -0,0 +1,7 @@
+#
+# Copyright (C) 2016 Jagan Teki <[email protected]>
+#
+# SPDX-License-Identifier:     GPL-2.0+
+
+## spi-nor core
+obj-y  += spi-nor.o spi-nor-uclass.o spi-nor-ids.o
drivers/mtd/spi-nor/spi-nor-ids.c new file +49 -0
new file mode 100644
index 0000000..db95655
@@ -0,0 +1,184 @@
+/*
+ * SPI NOR IDs.
+ *
+ * Copyright (C) 2016 Jagan Teki <[email protected]>
+ *
+ * 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) },

drivers/mtd/spi-nor/spi-nor-ids.c new file +2 -0
+       {"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) },

drivers/mtd/spi-nor/spi-nor-ids.c new file +9 -0
+#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) },
drivers/mtd/spi-nor/spi-nor-ids.c new file +9 -0
+#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) },

drivers/mtd/spi-nor/spi-nor-ids.c new file +4 -0
+       {"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) },
drivers/mtd/spi-nor/spi-nor-ids.c new file +3 -0
+#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) },

drivers/mtd/spi-nor/spi-nor-ids.c new file +6 -0
+#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) },
drivers/mtd/spi-nor/spi-nor-ids.c new file +4 -0
+#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)
},

drivers/mtd/spi-nor/spi-nor-ids.c new file +4 -0
+
+       /* EON */
+       {"en25q32b",       INFO(0x1c3016, 0x0, 64 * 1024,    64, 0) },
+       {"en25q64",        INFO(0x1c3017, 0x0, 64 * 1024,   128, SECT_4K)

},

drivers/mtd/spi-nor/spi-nor-ids.c new file +5 -0
+       {"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)
},

drivers/mtd/spi-nor/spi-nor-ids.c new file +22 -0
+
+       /* 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)
+        */
+};
drivers/mtd/spi-nor/spi-nor-uclass.c new file +80 -0
new file mode 100644
index 0000000..919682d
@@ -0,0 +1,143 @@
+/*
+ * SPI NOR Core framework.
+ *
+ * Copyright (C) 2016 Jagan Teki <[email protected]>
+ *
+ * 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);

drivers/mtd/spi-nor/spi-nor-uclass.c new file +14 -0
+       }
+
+       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,

drivers/mtd/spi-nor/spi-nor-uclass.c new file +14 -0
+                                &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);

drivers/mtd/spi-nor/spi-nor-uclass.c new file +6 -0
+       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);

drivers/mtd/spi-nor/spi-nor-uclass.c new file +29 -0
+               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),
+};
drivers/mtd/spi-nor/spi-nor.c new file +25 -0
new file mode 100644
index 0000000..09fb8ca
@@ -0,0 +1,569 @@
+/*
+ * SPI NOR Core framework.
+ *
+ * Copyright (C) 2016 Jagan Teki <[email protected]>
+ *
+ * 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);

drivers/mtd/spi-nor/spi-nor.c new file +6 -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);

drivers/mtd/spi-nor/spi-nor.c new file +110 -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)

drivers/mtd/spi-nor/spi-nor.c new file +61 -0
+{
+       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)

drivers/mtd/spi-nor/spi-nor.c line 213

Quoted 10 lines
drivers/mtd/spi-nor/spi-nor.c new file +9 -0
+               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)

Quoted 623 lines
drivers/mtd/spi-nor/spi-nor.c new file +3 -0
+                       goto erase_err;
+
+               ret = spi_nor_wait_till_ready(nor->dev,

SNOR_READY_WAIT_ERASE);

drivers/mtd/spi-nor/spi-nor.c new file +43 -0
+               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));

drivers/mtd/spi-nor/spi-nor.c new file +12 -0
+
+               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);

drivers/mtd/spi-nor/spi-nor.c new file +110 -0
+               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)

drivers/mtd/spi-nor/spi-nor.c new file +44 -0
+{
+       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__);

drivers/mtd/spi-nor/spi-nor.c new file +31 -0
+               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

drivers/mtd/spi-nor/spi-nor.c new file +30 -0
+        * (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

drivers/mtd/spi-nor/spi-nor.c new file +45 -0
+        * 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",

drivers/mtd/spi-nor/spi-nor.c new file +33 -0
+                             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;
+}
include/dm/uclass-id.h +1 -0
index 3fc2083..06541a4 100644
@@ -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 */
include/linux/mtd/spi-nor.h new file +18 -0
new file mode 100644
index 0000000..e1688e2
@@ -0,0 +1,217 @@
+/*
+ * SPI NOR Core header file.
+ *
+ * Copyright (C) 2016 Jagan Teki <[email protected]>
+ *
+ * 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.
+ */

include/linux/mtd/spi-nor.h new file +12 -0
+#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.
+ */

include/linux/mtd/spi-nor.h new file +5 -0
+#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) */

include/linux/mtd/spi-nor.h new file +7 -0
+#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)
*/

include/linux/mtd/spi-nor.h new file +13 -0
+#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 */

include/linux/mtd/spi-nor.h new file +18 -0
+
+/* 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 */

include/linux/mtd/spi-nor.h new file +9 -0
+
+/* 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
+ */

include/linux/mtd/spi-nor.h new file +23 -0
+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]))

include/linux/mtd/spi-nor.h new file +31 -0
+#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)

include/linux/mtd/spi-nor.h new file +14 -0
+};
+
+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

+ */

include/linux/mtd/spi-nor.h new file +44 -1
+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

#12 lore raw

PATCH v10 3/27 mtd: add SPI-NOR core support

In reply to Jagan Teki

[Resending on correct patch of the patch-set]

Dear Jagan,

Quoted 36 lines

-----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 <[email protected]>
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
=======================================

Quoted 3 lines
        #####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

#13 lore raw

PATCH v10 3/27 mtd: add SPI-NOR core support

Prabhakar, Jagan,

Quoted 17 lines · On Wed, 28 Feb 2018 09:42:11 +0000 Prabhakar Kushwaha…

[Resending on correct patch of the patch-set]

Dear Jagan,

Quoted 12 lines

-----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 <[email protected]>
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.

Quoted 9 lines
Quoted 9 lines

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.

Quoted 31 lines
Quoted 16 lines

=======================================
cmd/spinor.c
=======================================
mtd-uclass.c
=======================================
spi-nor-uclass.c
=======================================
spi-nor.c
=======================================
m25p80.c zynq_qspinor.c
=======================================
spi-uclass.c
=======================================
zynq_qspi.c
=======================================

Quoted 3 lines
        #####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

Quoted 8 lines

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

Signature · 3 lines
Boris Brezillon, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com
#14 lore raw

PATCH v10 3/27 mtd: add SPI-NOR core support

Dear Jagan,

Quoted 101 lines

-----Original Message-----
From: Boris Brezillon [mailto:boris.brezillon at bootlin.com]
Sent: Wednesday, February 28, 2018 5:40 PM
To: Prabhakar Kushwaha <[email protected]>; Jagan Teki <[email protected]>; Cyrille Pitchen <[email protected]>
Cc: u-boot at lists.denx.de; Suresh Gupta <[email protected]>; Yogesh Narayan Gaur <[email protected]>; Poonam Aggrwal <[email protected]>; Ashish Kumar <[email protected]>; Han Xu <[email protected]>; Frieder Schrempf <[email protected]>; Boris Brezillon <boris.brezillon@free- electrons.com>
Subject: Re: [U-Boot] [PATCH v10 03/27] mtd: add SPI-NOR core support

Prabhakar, Jagan,

Quoted 17 lines · On Wed, 28 Feb 2018 09:42:11 +0000 Prabhakar Kushwaha…

[Resending on correct patch of the patch-set]

Dear Jagan,

Quoted 12 lines

-----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 <[email protected]>
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.

Quoted 9 lines
Quoted 9 lines

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.

Quoted 36 lines
Quoted 16 lines

=======================================
cmd/spinor.c
=======================================
mtd-uclass.c
=======================================
spi-nor-uclass.c
=======================================
spi-nor.c
=======================================
m25p80.c zynq_qspinor.c
=======================================
spi-uclass.c
=======================================
zynq_qspi.c
=======================================

Quoted 3 lines
        #####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

Quoted 5 lines
Quoted 3 lines

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

#15 lore raw

PATCH v10 3/27 mtd: add SPI-NOR core support

In reply to Prabhakar Kushwaha
Quoted 47 lines · Prabhakar Kushwaha

[Resending on correct patch of the patch-set]

Dear Jagan,

Quoted 36 lines

-----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 <[email protected]>
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
=======================================

Quoted 3 lines
        #####SPI NOR chip######

=======================================

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

Quoted 7 lines

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.

Quoted 6 lines

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.

Quoted 5 lines

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

author
#16 lore raw

PATCH v10 4/27 mtd: spi-nor: sync/modify sst write operations

In reply to Jagan Teki

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.

---
 drivers/mtd/spi-nor/spi-nor.c | 115 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 115 insertions(+)
drivers/mtd/spi-nor/spi-nor.c +115 -0
index 09fb8ca..cfd21fb 100644
@@ -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;
Signature · 1 line
2.7.4
author
#17 lore raw

PATCH v10 5/27 mtd: spi-nor: sync/modify lock operations

In reply to Jagan Teki

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

---
 drivers/mtd/spi-nor/spi-nor.c | 218 ++++++++++++++++++++++++++++++++++++++++++
 include/mtd.h                 |   3 +
 2 files changed, 221 insertions(+)
drivers/mtd/spi-nor/spi-nor.c +218 -0
index cfd21fb..8bf9e67 100644
@@ -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;
 	/*
include/mtd.h +3 -0
index 273b3a6..acb2256 100644
@@ -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 */
Signature · 1 line
2.7.4
author
#18 lore raw

PATCH v10 6/27 mtd: spi-nor: Kconfig: Add MTD_SPI_NOR entry

In reply to Jagan Teki

Added CONFIG_MTD_SPI_NOR kconfig entry

---
 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
drivers/mtd/Kconfig +2 -0
index 1957980..1d5a248 100644
@@ -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"
drivers/mtd/spi-nor/Kconfig new file +14 -0
new file mode 100644
index 0000000..130b0a4
@@ -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.
drivers/mtd/spi-nor/Makefile +2 -0
index c1212a8..661f2f6 100644
@@ -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
Signature · 1 line
2.7.4
author
#19 lore raw

PATCH v10 7/27 mtd: spi-nor: Kconfig: Add MTD_SPI_NOR_USE_4K_SECTORS

In reply to Jagan Teki

Added CONFIG_MTD_SPI_NOR_USE_4K_SECTORS kconfig entry

---
 drivers/mtd/spi-nor/Kconfig | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)
drivers/mtd/spi-nor/Kconfig +18 -0
index 130b0a4..40cd5ba 100644
@@ -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
Signature · 1 line
2.7.4
author
#20 lore raw

PATCH v10 8/27 mtd: spi-nor: Kconfig: Add SPI_NOR_MISC entry

In reply to Jagan Teki

Added CONFIG_SPI_NOR_MISC kconfig entry

---
 drivers/mtd/spi-nor/Kconfig | 6 ++++++
 1 file changed, 6 insertions(+)
drivers/mtd/spi-nor/Kconfig +6 -0
index 40cd5ba..348709b 100644
@@ -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
Signature · 1 line
2.7.4
author
#21 lore raw

PATCH v10 9/27 mtd: spi-nor: Kconfig: Add SPI_NOR_MACRONIX entry

In reply to Jagan Teki

Added CONFIG_SPI_NOR_MACRONIX kconfig entry

---
 drivers/mtd/spi-nor/Kconfig | 5 +++++
 1 file changed, 5 insertions(+)
drivers/mtd/spi-nor/Kconfig +5 -0
index 348709b..c0ca14b 100644
@@ -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
Signature · 1 line
2.7.4
author
#22 lore raw

PATCH v10 10/27 mtd: spi-nor: Kconfig: Add SPI_NOR_SPANSION entry

In reply to Jagan Teki

Added CONFIG_SPI_NOR_SPANSION kconfig entry

---
 drivers/mtd/spi-nor/Kconfig | 5 +++++
 1 file changed, 5 insertions(+)
drivers/mtd/spi-nor/Kconfig +5 -0
index c0ca14b..d4303db 100644
@@ -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
Signature · 1 line
2.7.4
author
#23 lore raw

PATCH v10 11/27 mtd: spi-nor: Kconfig: Add SPI_NOR_STMICRO entry

In reply to Jagan Teki

Added CONFIG_SPI_NOR_STMICRO kconfig entry

---
 drivers/mtd/spi-nor/Kconfig | 5 +++++
 1 file changed, 5 insertions(+)
drivers/mtd/spi-nor/Kconfig +5 -0
index d4303db..8ed4891 100644
@@ -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
Signature · 1 line
2.7.4
author
#24 lore raw

PATCH v10 12/27 mtd: spi-nor: Kconfig: Add SPI_NOR_SST entry

In reply to Jagan Teki

Added CONFIG_SPI_NOR_SST kconfig entry

---
 drivers/mtd/spi-nor/Kconfig | 5 +++++
 1 file changed, 5 insertions(+)
drivers/mtd/spi-nor/Kconfig +5 -0
index 8ed4891..edcc47e 100644
@@ -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
Signature · 1 line
2.7.4
author
#25 lore raw

PATCH v10 13/27 mtd: spi-nor: Kconfig: Add SPI_NOR_WINBOND entry

In reply to Jagan Teki

Added CONFIG_SPI_NOR_WINBOND kconfig entry

---
 drivers/mtd/spi-nor/Kconfig | 5 +++++
 1 file changed, 5 insertions(+)
drivers/mtd/spi-nor/Kconfig +5 -0
index edcc47e..3ad2b16 100644
@@ -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
Signature · 1 line
2.7.4
author
#26 lore raw

PATCH v10 14/27 mtd-uclass: use platdata_auto_alloc

In reply to Jagan Teki

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

---
 drivers/mtd/mtd-uclass.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/mtd/mtd-uclass.c +1 -1
index c94afe9..d9ecfea 100644
@@ -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),
 };
Signature · 1 line
2.7.4
author
#27 lore raw

PATCH v10 15/27 spi: Add spi_write_then_read

In reply to Jagan Teki

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

---
 drivers/spi/spi-uclass.c | 24 ++++++++++++++++++++++++
 include/spi.h            | 20 ++++++++++++++++++++
 2 files changed, 44 insertions(+)
drivers/spi/spi-uclass.c +24 -0
index e06a603..b86c15b 100644
@@ -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)
 {
include/spi.h +20 -0
index 8c4b882..c67ca23 100644
@@ -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);
 
Signature · 1 line
2.7.4
author
#28 lore raw

PATCH v10 16/27 mtd: spi-nor: Add m25p80 driver

In reply to Jagan Teki

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

---
 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
drivers/mtd/spi-nor/Makefile +3 -0
index 661f2f6..d578be0 100644
@@ -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
drivers/mtd/spi-nor/m25p80.c new file +250 -0

250 lines not on this page · raw message

Signature · 1 line
2.7.4
author
#29 lore raw

PATCH v10 17/27 mtd: spi-nor: Kconfig: Add MTD_M25P80 entry

In reply to Jagan Teki

Add CONFIG_MTD_M25P80 kconfig entry

---
 drivers/mtd/spi-nor/Kconfig | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)
drivers/mtd/spi-nor/Kconfig +17 -0
index 3ad2b16..64d5553 100644
@@ -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
Signature · 1 line
2.7.4
author
#30 lore raw

PATCH v10 18/27 mtd: spi-nor: Add zynq qspinor driver

In reply to Jagan Teki

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.

---
 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
drivers/mtd/spi-nor/Makefile +3 -0
index d578be0..ded3bfa 100644
@@ -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
drivers/mtd/spi-nor/zynq_qspinor.c new file +622 -0

622 lines not on this page · raw message

Signature · 1 line
2.7.4
author
#31 lore raw

PATCH v10 19/27 mtd: spi-nor: zynq_qspi: Kconfig: Add MTD_ZYNQ

In reply to Jagan Teki

Add CONFIG_MTD_ZYNQ_QSPI kconfig entry

---
 drivers/mtd/spi-nor/Kconfig | 9 +++++++++
 1 file changed, 9 insertions(+)
drivers/mtd/spi-nor/Kconfig +9 -0
index 64d5553..4b2a5e8 100644
@@ -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
Signature · 1 line
2.7.4
author
#32 lore raw

PATCH v10 20/27 mtd: spi-nor: Add 4-byte addresswidth support

In reply to Jagan Teki

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

---
 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(-)
drivers/mtd/spi-nor/m25p80.c +1 -0
index 5465921..7af6f59 100644
@@ -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)
drivers/mtd/spi-nor/spi-nor.c +38 -0
index 8bf9e67..e0085cf 100644
@@ -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) {
include/linux/mtd/spi-nor.h +5 -1
index e1688e2..fc4a649 100644
@@ -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
 
 /**
Signature · 1 line
2.7.4
#33 lore raw

PATCH v10 20/27 mtd: spi-nor: Add 4-byte addresswidth support

Hi Jagan,

Quoted 66 lines · Jagan Teki

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

---
 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(-)
drivers/mtd/spi-nor/m25p80.c +1 -0
index 5465921..7af6f59 100644
@@ -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)
drivers/mtd/spi-nor/spi-nor.c +32 -0
index 8bf9e67..e0085cf 100644
@@ -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)
 {

drivers/mtd/spi-nor/spi-nor.c int spi_nor_scan(struct spi_nor *nor) · line 914

Quoted 10 lines
drivers/mtd/spi-nor/spi-nor.c +6 -0
@@ -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

Quoted 27 lines
drivers/mtd/spi-nor/spi-nor.c +0 -0
 	/* Dummy cycles for read */
 	switch (nor->read_opcode) {
include/linux/mtd/spi-nor.h +5 -1
index e1688e2..fc4a649 100644
@@ -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
 
 /**
#34 lore raw

PATCH v10 20/27 mtd: spi-nor: Add 4-byte addresswidth support

Le 28/12/2017 à 09:06, Cyrille Pitchen a écrit :

Quoted 110 lines

Hi Jagan,

Quoted 66 lines · Jagan Teki

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

---
 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(-)
drivers/mtd/spi-nor/m25p80.c +1 -0
index 5465921..7af6f59 100644
@@ -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)
drivers/mtd/spi-nor/spi-nor.c +32 -0
index 8bf9e67..e0085cf 100644
@@ -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)
 {

drivers/mtd/spi-nor/spi-nor.c int spi_nor_scan(struct spi_nor *nor) · line 914

Quoted 10 lines
drivers/mtd/spi-nor/spi-nor.c +6 -0
@@ -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.

Quoted 7 lines

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

Quoted 33 lines

Best regards,

Cyrille

Quoted 27 lines
drivers/mtd/spi-nor/spi-nor.c +0 -0
 	/* Dummy cycles for read */
 	switch (nor->read_opcode) {
include/linux/mtd/spi-nor.h +5 -1
index e1688e2..fc4a649 100644
@@ -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
 
 /**
author
#35 lore raw

PATCH v10 21/27 cmd: add spinor cmd support

In reply to Jagan Teki

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

---
 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
cmd/Kconfig +5 -0
index c033223..130c226 100644
@@ -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
cmd/Makefile +1 -0
index 00e3869..81ab932 100644
@@ -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
cmd/spinor.c new file +281 -0

281 lines not on this page · raw message

drivers/mtd/Makefile +5 -2
index 20c0d0a..c5209ad 100644
@@ -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
include/linux/mtd/spi-nor.h +1 -0
index fc4a649..9c3da70 100644
@@ -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 */
Signature · 1 line
2.7.4
author
#36 lore raw

PATCH v10 22/27 cmd: spinor: sync/update protect command

In reply to Jagan Teki

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

---
 cmd/spinor.c             | 47 ++++++++++++++++++++++++++++++++++++++++++++++-
 drivers/mtd/mtd-uclass.c | 19 +++++++++++++++++++
 include/mtd.h            | 11 +++++++++++
 3 files changed, 76 insertions(+), 1 deletion(-)
cmd/spinor.c +46 -1
index b781151..ef8decf 100644
@@ -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,
drivers/mtd/mtd-uclass.c +19 -0
index d9ecfea..535f68e 100644
@@ -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;
include/mtd.h +11 -0
index acb2256..6390133 100644
@@ -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
Signature · 1 line
2.7.4
author
#37 lore raw

PATCH v10 23/27 board_r: initialize spi_nor

In reply to Jagan Teki

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

---
 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(+)
common/board_r.c +13 -0
index 09167c1..8030548 100644
@@ -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
drivers/mtd/spi-nor/spi-nor-uclass.c +17 -0
index 919682d..8a37be0 100644
@@ -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;
include/linux/mtd/spi-nor.h +1 -0
index 9c3da70..2e8e52d 100644
@@ -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 */
Signature · 1 line
2.7.4
#38 lore raw

PATCH v10 23/27 board_r: initialize spi_nor

Hi Jagan,

Quoted 11 lines · Jagan Teki

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

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

author
#39 lore raw

PATCH v10 24/27 env: add spi-nor environment

In reply to Jagan Teki

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

---
 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
cmd/nvedit.c +1 -0
index 4e79d03..2e5e88d 100644
@@ -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)
env/Kconfig +27 -0
index 2477bf8..1b694d5 100644
@@ -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
env/Makefile +1 -0
index 7ce8231..21fe9a4 100644
@@ -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
env/env.c +2 -0
index 76a5608..be1672c 100644
@@ -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)
env/spinor.c new file +113 -0

113 lines not on this page · raw message

include/environment.h +1 -0
index d29f82c..8e8be26 100644
@@ -198,6 +198,7 @@ enum env_location {
 	ENVL_ONENAND,
 	ENVL_REMOTE,
 	ENVL_SPI_FLASH,
+	ENVL_SPI_NOR,
 	ENVL_UBI,
 	ENVL_NOWHERE,
 
Signature · 1 line
2.7.4
#40 lore raw

PATCH v10 24/27 env: add spi-nor environment

Hi Jagan,

Quoted 7 lines

-----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 <[email protected]>
Subject: [U-Boot] [PATCH v10 24/27] env: add spi-nor environment

Quoted 5 lines

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

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

author
#41 lore raw

PATCH v10 25/27 arm: dts: zynq: Add zynq-qspinor node

In reply to Jagan Teki

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

---
 arch/arm/dts/zynq-7000.dtsi | 12 ++++++++++++
 1 file changed, 12 insertions(+)
arch/arm/dts/zynq-7000.dtsi +12 -0
index d9774d8..fa7965d 100644
@@ -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>;
Signature · 1 line
2.7.4
author
#42 lore raw

PATCH v10 26/27 dm: zynq: microzed: enable MTD/SPI-NOR framework

In reply to Jagan Teki

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

---
 arch/arm/dts/zynq-microzed.dts  | 12 +++++++++++-
 configs/zynq_microzed_defconfig | 17 ++++++++++-------
 2 files changed, 21 insertions(+), 8 deletions(-)
arch/arm/dts/zynq-microzed.dts +11 -1
index 2d07b92..ff973dd 100644
@@ -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 {
configs/zynq_microzed_defconfig +10 -7
index a713314..56908fe 100644
@@ -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
Signature · 1 line
2.7.4
author
#43 lore raw

PATCH v10 27/27 test: dm: add tests for mtd devices

In reply to Jagan Teki

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.

---
 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
configs/sandbox_defconfig +7 -1
index 7efb4eb..658d9f2 100644
@@ -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
test/dm/Makefile +1 -0
index 513c456..55f7450 100644
@@ -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
test/dm/mtd.c new file +33 -0
new file mode 100644
index 0000000..fe98593
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2017 Jagan Teki <[email protected]>
+ *
+ * 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);
Signature · 1 line
2.7.4
#44 lore raw

v10 cover dm: Generic MTD Subsystem, with SPI-NOR interface

In reply to Jagan Teki

Hi Jagan,

Quoted 24 lines

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

Quoted 8 lines

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:

Quoted 3 lines

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

Quoted 2 lines

=======================================
mtd-uclass.c

^^^^^ - here we will have a generic MTD layer (as it is in Linux)

Quoted 4 lines

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

Quoted 2 lines

=======================================
m25p80.c zynq_qspinor.c

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

Quoted 2 lines

=======================================
spi-uclass.c

^^^^^^^ - why do we
need this uclass?

Quoted 2 lines

=======================================
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?

Quoted 33 lines

=======================================

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

Quoted 6 lines

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?

Quoted 129 lines

'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
Quoted 9 lines
 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>

#45 lore raw

v10 cover dm: Generic MTD Subsystem, with SPI-NOR interface

Quoted 42 lines · Lukasz Majewski

Hi Jagan,

Quoted 24 lines

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

Quoted 8 lines

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:

Quoted 1 line
Quoted 5 lines
Quoted 2 lines

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

Quoted 4 lines

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.

Quoted 5 lines
Quoted 3 lines

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

Quoted 8 lines
Quoted 5 lines

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

Quoted 8 lines
Quoted 3 lines

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

Quoted 5 lines
Quoted 3 lines

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

Quoted 8 lines
Quoted 3 lines

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

Signature · 4 lines
Jagan Teki
Free Software Engineer | www.openedev.com
U-Boot, Linux | Upstream Maintainer
Hyderabad, India.
maintainer
#46 lore raw

v10 cover dm: Generic MTD Subsystem, with SPI-NOR interface

Quoted 52 lines · Jagan Teki
Quoted 42 lines · Lukasz Majewski

Hi Jagan,

Quoted 24 lines

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

Quoted 8 lines

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:

Quoted 1 line
Quoted 5 lines
Quoted 2 lines

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

Quoted 1 line
Quoted 7 lines
Quoted 3 lines

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.

Signature · 2 lines
Regards
Vignesh
#47 lore raw

v10 cover dm: Generic MTD Subsystem, with SPI-NOR interface

Quoted 63 lines · Vignesh R
Quoted 52 lines · Jagan Teki
Quoted 42 lines · Lukasz Majewski

Hi Jagan,

Quoted 24 lines

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

Quoted 8 lines

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:

Quoted 1 line
Quoted 5 lines
Quoted 2 lines

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

Quoted 1 line
Quoted 7 lines
Quoted 3 lines

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.

Quoted 10 lines

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.

Signature · 4 lines
Jagan Teki
Free Software Engineer | www.openedev.com
U-Boot, Linux | Upstream Maintainer
Hyderabad, India.
#48 lore raw

v10 cover dm: Generic MTD Subsystem, with SPI-NOR interface

Hi Jagan,

Quoted 77 lines · Vignesh R
Quoted 65 lines · Jagan Teki
Quoted 54 lines
Quoted 43 lines · Lukasz Majewski

Hi Jagan,

Quoted 24 lines

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

Quoted 8 lines

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:

Quoted 1 line
Quoted 5 lines
Quoted 2 lines

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

Quoted 1 line
Quoted 7 lines
Quoted 3 lines

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.

Quoted 10 lines

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.

Quoted 1 line

I know how hard it is adding new command in u-boot,

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

Quoted 3 lines

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

Quoted 17 lines

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.

Quoted 3 lines

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>

#49 lore raw

v10 cover dm: Generic MTD Subsystem, with SPI-NOR interface

Hi :

2018-01-03 18:59 GMT+08:00 Lukasz Majewski <[email protected]>:

Quoted 96 lines

Hi Jagan,

Quoted 77 lines · Vignesh R
Quoted 65 lines · Jagan Teki
Quoted 54 lines
Quoted 43 lines · Lukasz Majewski

Hi Jagan,

Quoted 24 lines

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

Quoted 8 lines

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:

Quoted 1 line
Quoted 5 lines
Quoted 2 lines

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

Quoted 1 line
Quoted 7 lines
Quoted 3 lines

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.

Quoted 10 lines

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.

Quoted 1 line

I know how hard it is adding new command in u-boot,

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

Quoted 3 lines

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.

Quoted 32 lines

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

Quoted 20 lines

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.

Quoted 17 lines

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

maintainer
#50 lore raw

v10 cover dm: Generic MTD Subsystem, with SPI-NOR interface

In reply to Jagan Teki
Quoted 2 lines · Jagan Teki
Quoted 1 line · Vignesh R

[...]

Quoted 29 lines
Quoted 18 lines
Quoted 10 lines
Quoted 6 lines
Quoted 3 lines

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

Quoted 1 line
Quoted 7 lines
Quoted 3 lines

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.

Quoted 10 lines

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.

Quoted 6 lines

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

Quoted 8 lines

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.

Quoted 5 lines

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.

Signature · 2 lines
Regards
Vignesh
#51 lore raw

v10 cover dm: Generic MTD Subsystem, with SPI-NOR interface

In reply to Jagan Teki

Hi Jagan,

Quoted 128 lines

-----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 <[email protected]>
Cc: U-Boot Mailing List <[email protected]>; Tom Rini <[email protected]>
Subject: Re: [U-Boot] [PATCH v10 00/27] dm: Generic MTD Subsystem, with SPI-NOR interface

Quoted 42 lines · Lukasz Majewski

Hi Jagan,

Quoted 24 lines

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

Quoted 8 lines

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:

Quoted 1 line
Quoted 5 lines
Quoted 2 lines

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

Quoted 4 lines

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.

Quoted 5 lines
Quoted 3 lines

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

Quoted 8 lines
Quoted 5 lines

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

Quoted 8 lines
Quoted 3 lines

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

Quoted 5 lines
Quoted 3 lines

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

Quoted 8 lines
Quoted 3 lines

=======================================
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?

Quoted 8 lines

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

Quoted 11 lines

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

#52 lore raw

v10 cover dm: Generic MTD Subsystem, with SPI-NOR interface

Quoted 138 lines · Siva Durga Prasad Paladugu

Hi Jagan,

Quoted 135 lines

-----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 <[email protected]>
Cc: U-Boot Mailing List <[email protected]>; Tom Rini <[email protected]>
Subject: Re: [U-Boot] [PATCH v10 00/27] dm: Generic MTD Subsystem, with SPI-NOR interface

Quoted 42 lines · Lukasz Majewski

Hi Jagan,

Quoted 24 lines

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

Quoted 8 lines

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:

Quoted 1 line
Quoted 5 lines
Quoted 2 lines

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

Quoted 4 lines

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.

Quoted 5 lines
Quoted 3 lines

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

Quoted 8 lines
Quoted 5 lines

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

Quoted 8 lines
Quoted 3 lines

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

Quoted 5 lines
Quoted 3 lines

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

Quoted 8 lines
Quoted 3 lines

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

Quoted 4 lines
Quoted 1 line

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.

#53 lore raw

v10 cover dm: Generic MTD Subsystem, with SPI-NOR interface

Hi Jagan,

Quoted 152 lines

-----Original Message-----
From: Jagan Teki [mailto:jagannadh.teki at gmail.com]
Sent: Tuesday, January 23, 2018 3:29 PM
To: Siva Durga Prasad Paladugu <[email protected]>
Cc: Lukasz Majewski <[email protected]>; U-Boot Mailing List <u- boot at lists.denx.de>; Tom Rini <[email protected]>
Subject: Re: [U-Boot] [PATCH v10 00/27] dm: Generic MTD Subsystem, with SPI-NOR interface

Quoted 141 lines · Siva Durga Prasad Paladugu

Hi Jagan,

Quoted 137 lines

-----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 <[email protected]>
Cc: U-Boot Mailing List <[email protected]>; Tom Rini <[email protected]>
Subject: Re: [U-Boot] [PATCH v10 00/27] dm: Generic MTD Subsystem, with SPI-NOR interface

Quoted 42 lines · Lukasz Majewski

Hi Jagan,

Quoted 24 lines

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

Quoted 8 lines

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:

Quoted 1 line
Quoted 5 lines
Quoted 2 lines

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

Quoted 4 lines

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.

Quoted 5 lines
Quoted 3 lines

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

Quoted 8 lines
Quoted 5 lines

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

Quoted 8 lines
Quoted 3 lines

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

Quoted 5 lines
Quoted 3 lines

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

Quoted 8 lines
Quoted 3 lines

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

Quoted 8 lines
Quoted 1 line

As mentioned in Zynq TRM, Zynq qspi controller can work in legacy spi

mode as well which is same as regular spi controller.

Quoted 1 line

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

#54 lore raw

v10 cover dm: Generic MTD Subsystem, with SPI-NOR interface

In reply to Jagan Teki

Hi Jagan,

Quoted 31 lines

-----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 <[email protected]>
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

Quoted 7 lines

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

Quoted 199 lines

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