[OpenWrt-Devel] [PATCH] target: socfpga: Add support for QSPI NOR boot
Marek Vasut
marex at denx.de
Tue May 24 10:51:52 EDT 2016
Add necessary kernel backports to support the Cadence QSPI controller
present on the Altera SoCFPGA SoC.
Signed-off-by: Marek Vasut <marex at denx.de>
---
target/linux/socfpga/config-4.4 | 2 +
...-gpio-altera-Fix-altr-interrupt-type-prop.patch | 6 +-
...dwc2-gadget-Repair-DSTS-register-decoding.patch | 6 +-
...-dts-Enable-MMC-support-at-correct-place-.patch | 8 +-
...ocfpga-Add-support-for-HPS-LEDs-on-SoCKit.patch | 6 +-
...ga-Add-support-for-HPS-KEYs-SWs-on-SoCKit.patch | 6 +-
...td-add-get-set-of_node-flash_node-helpers.patch | 87 ++
.../0007-mtd-nand-spi-nor-assign-MTD-of_node.patch | 44 +
...r-convert-to-spi_nor_-get-set-_flash_node.patch | 91 ++
.../0009-mtd-spi-nor-drop-flash_node-field.patch | 64 +
...-remove-unnecessary-leading-space-from-db.patch | 32 +
...-provide-default-erase_sector-implementat.patch | 112 ++
...-nor-mx25l3205d-mx25l6405d-append-SECT_4K.patch | 32 +
...-Fix-error-message-with-unrecognized-JEDE.patch | 35 +
...i-nor-fix-error-handling-in-spi_nor_erase.patch | 44 +
...i-nor-Check-the-return-value-from-read_sr.patch | 60 +
...016-mtd-spi-nor-remove-micron_quad_enable.patch | 110 ++
...-properly-detect-the-memory-when-it-boots.patch | 244 ++++
...-select-op-codes-and-SPI-NOR-protocols-by.patch | 203 +++
...-spi-nor-fix-support-of-Macronix-memories.patch | 139 ++
...d-spi-nor-fix-support-of-Winbond-memories.patch | 179 +++
...td-spi-nor-fix-support-of-Micron-memories.patch | 224 +++
...-spi-nor-fix-support-of-Spansion-memories.patch | 116 ++
...-configure-the-number-of-dummy-clock-cycl.patch | 264 ++++
...-configure-the-number-of-dummy-clock-cycl.patch | 159 +++
...-configure-the-number-of-dummy-clock-cycl.patch | 237 ++++
...-configure-the-number-of-dummy-clock-cycl.patch | 215 +++
...add-support-of-dual-and-quad-spi-protocol.patch | 293 ++++
...grab-device-tree-node-directly-from-maste.patch | 81 ++
...on-atmel-quadspi-add-binding-file-for-Atm.patch | 58 +
...-Bindings-for-Cadence-Quad-SPI-Flash-Cont.patch | 99 ++
...-Add-driver-for-Cadence-Quad-SPI-Flash-Co.patch | 1431 ++++++++++++++++++++
...fpga-Add-Candence-QSPI-controller-DT-node.patch | 42 +
...3-ARM-socfpga-Enable-QSPI-flash-on-SoCKit.patch | 47 +
34 files changed, 4760 insertions(+), 16 deletions(-)
create mode 100644 target/linux/socfpga/patches-4.4/0006-mtd-add-get-set-of_node-flash_node-helpers.patch
create mode 100644 target/linux/socfpga/patches-4.4/0007-mtd-nand-spi-nor-assign-MTD-of_node.patch
create mode 100644 target/linux/socfpga/patches-4.4/0008-mtd-spi-nor-convert-to-spi_nor_-get-set-_flash_node.patch
create mode 100644 target/linux/socfpga/patches-4.4/0009-mtd-spi-nor-drop-flash_node-field.patch
create mode 100644 target/linux/socfpga/patches-4.4/0010-mtd-spi-nor-remove-unnecessary-leading-space-from-db.patch
create mode 100644 target/linux/socfpga/patches-4.4/0011-mtd-spi-nor-provide-default-erase_sector-implementat.patch
create mode 100644 target/linux/socfpga/patches-4.4/0012-mtd-spi-nor-mx25l3205d-mx25l6405d-append-SECT_4K.patch
create mode 100644 target/linux/socfpga/patches-4.4/0013-mtd-spi-nor-Fix-error-message-with-unrecognized-JEDE.patch
create mode 100644 target/linux/socfpga/patches-4.4/0014-mtd-spi-nor-fix-error-handling-in-spi_nor_erase.patch
create mode 100644 target/linux/socfpga/patches-4.4/0015-mtd-spi-nor-Check-the-return-value-from-read_sr.patch
create mode 100644 target/linux/socfpga/patches-4.4/0016-mtd-spi-nor-remove-micron_quad_enable.patch
create mode 100644 target/linux/socfpga/patches-4.4/0017-mtd-spi-nor-properly-detect-the-memory-when-it-boots.patch
create mode 100644 target/linux/socfpga/patches-4.4/0018-mtd-spi-nor-select-op-codes-and-SPI-NOR-protocols-by.patch
create mode 100644 target/linux/socfpga/patches-4.4/0019-mtd-spi-nor-fix-support-of-Macronix-memories.patch
create mode 100644 target/linux/socfpga/patches-4.4/0020-mtd-spi-nor-fix-support-of-Winbond-memories.patch
create mode 100644 target/linux/socfpga/patches-4.4/0021-mtd-spi-nor-fix-support-of-Micron-memories.patch
create mode 100644 target/linux/socfpga/patches-4.4/0022-mtd-spi-nor-fix-support-of-Spansion-memories.patch
create mode 100644 target/linux/socfpga/patches-4.4/0023-mtd-spi-nor-configure-the-number-of-dummy-clock-cycl.patch
create mode 100644 target/linux/socfpga/patches-4.4/0024-mtd-spi-nor-configure-the-number-of-dummy-clock-cycl.patch
create mode 100644 target/linux/socfpga/patches-4.4/0025-mtd-spi-nor-configure-the-number-of-dummy-clock-cycl.patch
create mode 100644 target/linux/socfpga/patches-4.4/0026-mtd-spi-nor-configure-the-number-of-dummy-clock-cycl.patch
create mode 100644 target/linux/socfpga/patches-4.4/0027-mtd-m25p80-add-support-of-dual-and-quad-spi-protocol.patch
create mode 100644 target/linux/socfpga/patches-4.4/0028-mtd-ofpart-grab-device-tree-node-directly-from-maste.patch
create mode 100644 target/linux/socfpga/patches-4.4/0029-Documentation-atmel-quadspi-add-binding-file-for-Atm.patch
create mode 100644 target/linux/socfpga/patches-4.4/0030-mtd-spi-nor-Bindings-for-Cadence-Quad-SPI-Flash-Cont.patch
create mode 100644 target/linux/socfpga/patches-4.4/0031-mtd-spi-nor-Add-driver-for-Cadence-Quad-SPI-Flash-Co.patch
create mode 100644 target/linux/socfpga/patches-4.4/0032-ARM-socfpga-Add-Candence-QSPI-controller-DT-node.patch
create mode 100644 target/linux/socfpga/patches-4.4/0033-ARM-socfpga-Enable-QSPI-flash-on-SoCKit.patch
diff --git a/target/linux/socfpga/config-4.4 b/target/linux/socfpga/config-4.4
index 15cac52..b68bf7a 100644
--- a/target/linux/socfpga/config-4.4
+++ b/target/linux/socfpga/config-4.4
@@ -416,6 +416,7 @@ CONFIG_MMC_DW_PLTFM=y
CONFIG_MODULES_TREE_LOOKUP=y
CONFIG_MODULES_USE_ELF_REL=y
CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_M25P80=y
CONFIG_MTD_SPI_NOR=y
CONFIG_MTD_UBI=y
CONFIG_MTD_UBI_BEB_LIMIT=20
@@ -621,6 +622,7 @@ CONFIG_SPARSE_IRQ=y
CONFIG_SPI=y
CONFIG_SPI_ALTERA=y
CONFIG_SPI_BITBANG=y
+CONFIG_SPI_CADENCE_QUADSPI=y
CONFIG_SPI_DESIGNWARE=y
CONFIG_SPI_DW_MMIO=y
CONFIG_SPI_MASTER=y
diff --git a/target/linux/socfpga/patches-4.4/0001-dt-bindings-gpio-altera-Fix-altr-interrupt-type-prop.patch b/target/linux/socfpga/patches-4.4/0001-dt-bindings-gpio-altera-Fix-altr-interrupt-type-prop.patch
index b89793a..bf658eb 100644
--- a/target/linux/socfpga/patches-4.4/0001-dt-bindings-gpio-altera-Fix-altr-interrupt-type-prop.patch
+++ b/target/linux/socfpga/patches-4.4/0001-dt-bindings-gpio-altera-Fix-altr-interrupt-type-prop.patch
@@ -1,7 +1,7 @@
-From b32732e51a774e8514f40975f2600f02ef9db0b4 Mon Sep 17 00:00:00 2001
+From 39c5b88eedd3e99c57aeaf7d7d61a830a4ef4b80 Mon Sep 17 00:00:00 2001
From: Marek Vasut <marex at denx.de>
Date: Mon, 29 Feb 2016 17:19:59 +0100
-Subject: [PATCH 1/5] dt-bindings: gpio: altera: Fix altr,interrupt-type
+Subject: [PATCH 01/33] dt-bindings: gpio: altera: Fix altr,interrupt-type
property
The altr,interrupt-trigger property is not used by the driver.
@@ -41,5 +41,5 @@ index 12f5014..826a720 100644
gpio-controller;
#interrupt-cells = <1>;
--
-2.7.0
+2.8.1
diff --git a/target/linux/socfpga/patches-4.4/0002-usb-dwc2-gadget-Repair-DSTS-register-decoding.patch b/target/linux/socfpga/patches-4.4/0002-usb-dwc2-gadget-Repair-DSTS-register-decoding.patch
index 9be3834..2a2b2ba 100644
--- a/target/linux/socfpga/patches-4.4/0002-usb-dwc2-gadget-Repair-DSTS-register-decoding.patch
+++ b/target/linux/socfpga/patches-4.4/0002-usb-dwc2-gadget-Repair-DSTS-register-decoding.patch
@@ -1,7 +1,7 @@
-From e5cbd23e4f40181c907a1abc136b17de8cb86809 Mon Sep 17 00:00:00 2001
+From f7697963e1b0fc1496709f84c00da5cb144a58a3 Mon Sep 17 00:00:00 2001
From: Marek Vasut <marex at denx.de>
Date: Thu, 17 Dec 2015 23:42:35 +0100
-Subject: [PATCH 2/5] usb: dwc2: gadget: Repair DSTS register decoding
+Subject: [PATCH 02/33] usb: dwc2: gadget: Repair DSTS register decoding
The "enumspd" field is located in register DSTS[2:1], but the code
which checks the bitfield does not shift the value accordingly. This
@@ -32,5 +32,5 @@ index 0abf73c..48e47c1 100644
case DSTS_ENUMSPD_FS48:
hsotg->gadget.speed = USB_SPEED_FULL;
--
-2.7.0
+2.8.1
diff --git a/target/linux/socfpga/patches-4.4/0003-ARM-socfpga-dts-Enable-MMC-support-at-correct-place-.patch b/target/linux/socfpga/patches-4.4/0003-ARM-socfpga-dts-Enable-MMC-support-at-correct-place-.patch
index b12de6d..5dec3388 100644
--- a/target/linux/socfpga/patches-4.4/0003-ARM-socfpga-dts-Enable-MMC-support-at-correct-place-.patch
+++ b/target/linux/socfpga/patches-4.4/0003-ARM-socfpga-dts-Enable-MMC-support-at-correct-place-.patch
@@ -1,8 +1,8 @@
-From 6b8c64eb90e5d958f32524ff2d0571b3b6ac92df Mon Sep 17 00:00:00 2001
+From 23d14e4479c925904bc7620a55c66eb8babacbb9 Mon Sep 17 00:00:00 2001
From: Marek Vasut <marex at denx.de>
Date: Mon, 21 Dec 2015 00:42:01 -0600
-Subject: [PATCH 3/5] ARM: socfpga: dts: Enable MMC support at correct place in
- the DT
+Subject: [PATCH 03/33] ARM: socfpga: dts: Enable MMC support at correct place
+ in the DT
The socfpga.dtsi explicitly enabled MMC support, but not all boards are
equiped with an MMC card. There are setups which only have QSPI NOR.
@@ -86,5 +86,5 @@ index 48bf651..b61f22f 100644
&usb1 {
--
-2.7.0
+2.8.1
diff --git a/target/linux/socfpga/patches-4.4/0004-ARM-socfpga-Add-support-for-HPS-LEDs-on-SoCKit.patch b/target/linux/socfpga/patches-4.4/0004-ARM-socfpga-Add-support-for-HPS-LEDs-on-SoCKit.patch
index 954f03e..f3155c5 100644
--- a/target/linux/socfpga/patches-4.4/0004-ARM-socfpga-Add-support-for-HPS-LEDs-on-SoCKit.patch
+++ b/target/linux/socfpga/patches-4.4/0004-ARM-socfpga-Add-support-for-HPS-LEDs-on-SoCKit.patch
@@ -1,7 +1,7 @@
-From e56e545745dc42cba743dab549d0afb1a39d14b4 Mon Sep 17 00:00:00 2001
+From 2088bf920b5ff60ab14e9fca940b4ae28e8b88d3 Mon Sep 17 00:00:00 2001
From: Marek Vasut <marex at denx.de>
Date: Mon, 22 Jun 2015 23:37:47 +0200
-Subject: [PATCH 4/5] ARM: socfpga: Add support for HPS LEDs on SoCKit
+Subject: [PATCH 04/33] ARM: socfpga: Add support for HPS LEDs on SoCKit
Add support for the blue LEDs on the SoCFPGA SoCkit board.
@@ -62,5 +62,5 @@ index b61f22f..1461690 100644
status = "okay";
};
--
-2.7.0
+2.8.1
diff --git a/target/linux/socfpga/patches-4.4/0005-ARM-socfpga-Add-support-for-HPS-KEYs-SWs-on-SoCKit.patch b/target/linux/socfpga/patches-4.4/0005-ARM-socfpga-Add-support-for-HPS-KEYs-SWs-on-SoCKit.patch
index a5e53f5..8e24b6c 100644
--- a/target/linux/socfpga/patches-4.4/0005-ARM-socfpga-Add-support-for-HPS-KEYs-SWs-on-SoCKit.patch
+++ b/target/linux/socfpga/patches-4.4/0005-ARM-socfpga-Add-support-for-HPS-KEYs-SWs-on-SoCKit.patch
@@ -1,7 +1,7 @@
-From a953c0800246e99c9b449bd9ec0b26682a82700c Mon Sep 17 00:00:00 2001
+From 7e990b69f2331daf7847ddb82bb5da9623f24f4f Mon Sep 17 00:00:00 2001
From: Marek Vasut <marex at denx.de>
Date: Tue, 23 Jun 2015 00:41:08 +0200
-Subject: [PATCH 5/5] ARM: socfpga: Add support for HPS KEYs/SWs on SoCKit
+Subject: [PATCH 05/33] ARM: socfpga: Add support for HPS KEYs/SWs on SoCKit
Add support for the keys and flip-switches on the SoCFPGA SoCkit board.
@@ -96,5 +96,5 @@ index 1461690..02e22f5 100644
};
--
-2.7.0
+2.8.1
diff --git a/target/linux/socfpga/patches-4.4/0006-mtd-add-get-set-of_node-flash_node-helpers.patch b/target/linux/socfpga/patches-4.4/0006-mtd-add-get-set-of_node-flash_node-helpers.patch
new file mode 100644
index 0000000..c3415d3
--- /dev/null
+++ b/target/linux/socfpga/patches-4.4/0006-mtd-add-get-set-of_node-flash_node-helpers.patch
@@ -0,0 +1,87 @@
+From cb0416f4be60979f3fd3e99a9baff17ac9b8381f Mon Sep 17 00:00:00 2001
+From: Brian Norris <computersforpeace at gmail.com>
+Date: Fri, 30 Oct 2015 20:33:20 -0700
+Subject: [PATCH 06/33] mtd: add get/set of_node/flash_node helpers
+
+We are going to begin using the mtd->dev.of_node field for MTD device
+nodes, so let's add helpers for it. Also, we'll be making some
+conversions on spi_nor (and nand_chip eventually) too, so get that ready
+with their own helpers.
+
+Signed-off-by: Brian Norris <computersforpeace at gmail.com>
+Reviewed-by: Boris Brezillon <boris.brezillon at free-electrons.com>
+---
+ include/linux/mtd/mtd.h | 11 +++++++++++
+ include/linux/mtd/nand.h | 11 +++++++++++
+ include/linux/mtd/spi-nor.h | 11 +++++++++++
+ 3 files changed, 33 insertions(+)
+
+diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
+index f17fa75..cc84923 100644
+--- a/include/linux/mtd/mtd.h
++++ b/include/linux/mtd/mtd.h
+@@ -254,6 +254,17 @@ struct mtd_info {
+ int usecount;
+ };
+
++static inline void mtd_set_of_node(struct mtd_info *mtd,
++ struct device_node *np)
++{
++ mtd->dev.of_node = np;
++}
++
++static inline struct device_node *mtd_get_of_node(struct mtd_info *mtd)
++{
++ return mtd->dev.of_node;
++}
++
+ int mtd_erase(struct mtd_info *mtd, struct erase_info *instr);
+ int mtd_point(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen,
+ void **virt, resource_size_t *phys);
+diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
+index 5a9d1d4..4f7c9b9 100644
+--- a/include/linux/mtd/nand.h
++++ b/include/linux/mtd/nand.h
+@@ -719,6 +719,17 @@ struct nand_chip {
+ void *priv;
+ };
+
++static inline void nand_set_flash_node(struct nand_chip *chip,
++ struct device_node *np)
++{
++ chip->flash_node = np;
++}
++
++static inline struct device_node *nand_get_flash_node(struct nand_chip *chip)
++{
++ return chip->flash_node;
++}
++
+ /*
+ * NAND Flash Manufacturer ID Codes
+ */
+diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
+index 12a4611..823c5381 100644
+--- a/include/linux/mtd/spi-nor.h
++++ b/include/linux/mtd/spi-nor.h
+@@ -184,6 +184,17 @@ struct spi_nor {
+ void *priv;
+ };
+
++static inline void spi_nor_set_flash_node(struct spi_nor *nor,
++ struct device_node *np)
++{
++ nor->flash_node = np;
++}
++
++static inline struct device_node *spi_nor_get_flash_node(struct spi_nor *nor)
++{
++ return nor->flash_node;
++}
++
+ /**
+ * spi_nor_scan() - scan the SPI NOR
+ * @nor: the spi_nor structure
+--
+2.8.1
+
diff --git a/target/linux/socfpga/patches-4.4/0007-mtd-nand-spi-nor-assign-MTD-of_node.patch b/target/linux/socfpga/patches-4.4/0007-mtd-nand-spi-nor-assign-MTD-of_node.patch
new file mode 100644
index 0000000..c556a64
--- /dev/null
+++ b/target/linux/socfpga/patches-4.4/0007-mtd-nand-spi-nor-assign-MTD-of_node.patch
@@ -0,0 +1,44 @@
+From 0b3e7c875f3f6ac9127b55eb99817c2f412e164e Mon Sep 17 00:00:00 2001
+From: Brian Norris <computersforpeace at gmail.com>
+Date: Fri, 30 Oct 2015 20:33:22 -0700
+Subject: [PATCH 07/33] mtd: {nand,spi-nor}: assign MTD of_node
+
+We should pass along our flash DT node to the MTD layer, so it can set
+up ofpart for us.
+
+Signed-off-by: Brian Norris <computersforpeace at gmail.com>
+Reviewed-by: Boris Brezillon <boris.brezillon at free-electrons.com>
+---
+ drivers/mtd/nand/nand_base.c | 3 +++
+ drivers/mtd/spi-nor/spi-nor.c | 1 +
+ 2 files changed, 4 insertions(+)
+
+diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
+index 3ff583f..1f30656 100644
+--- a/drivers/mtd/nand/nand_base.c
++++ b/drivers/mtd/nand/nand_base.c
+@@ -3990,6 +3990,9 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,
+ int ret;
+
+ if (chip->flash_node) {
++ /* MTD can automatically handle DT partitions, etc. */
++ mtd_set_of_node(mtd, chip->flash_node);
++
+ ret = nand_dt_init(mtd, chip, chip->flash_node);
+ if (ret)
+ return ret;
+diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
+index 32477c4..24ad373 100644
+--- a/drivers/mtd/spi-nor/spi-nor.c
++++ b/drivers/mtd/spi-nor/spi-nor.c
+@@ -1256,6 +1256,7 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
+ mtd->flags |= MTD_NO_ERASE;
+
+ mtd->dev.parent = dev;
++ mtd_set_of_node(mtd, np);
+ nor->page_size = info->page_size;
+ mtd->writebufsize = nor->page_size;
+
+--
+2.8.1
+
diff --git a/target/linux/socfpga/patches-4.4/0008-mtd-spi-nor-convert-to-spi_nor_-get-set-_flash_node.patch b/target/linux/socfpga/patches-4.4/0008-mtd-spi-nor-convert-to-spi_nor_-get-set-_flash_node.patch
new file mode 100644
index 0000000..0f4093f
--- /dev/null
+++ b/target/linux/socfpga/patches-4.4/0008-mtd-spi-nor-convert-to-spi_nor_-get-set-_flash_node.patch
@@ -0,0 +1,91 @@
+From bf8554bc3b6b699e9c5b990f63b286b31cf7e80b Mon Sep 17 00:00:00 2001
+From: Brian Norris <computersforpeace at gmail.com>
+Date: Fri, 30 Oct 2015 20:33:24 -0700
+Subject: [PATCH 08/33] mtd: spi-nor: convert to spi_nor_{get,
+ set}_flash_node()
+
+Used semantic patch with 'make coccicheck MODE=patch COCCI=script.cocci':
+
+---8<----
+virtual patch
+
+@@
+struct spi_nor b;
+struct spi_nor *c;
+expression d;
+@@
+(
+-(b).flash_node = (d)
++spi_nor_set_flash_node(&b, d)
+|
+-(c)->flash_node = (d)
++spi_nor_set_flash_node(c, d)
+)
+---8<----
+
+And a manual conversion for the one use of spi_nor_get_flash_node().
+
+Signed-off-by: Brian Norris <computersforpeace at gmail.com>
+Reviewed-by: Boris Brezillon <boris.brezillon at free-electrons.com>
+---
+ drivers/mtd/devices/m25p80.c | 2 +-
+ drivers/mtd/spi-nor/fsl-quadspi.c | 2 +-
+ drivers/mtd/spi-nor/nxp-spifi.c | 2 +-
+ drivers/mtd/spi-nor/spi-nor.c | 2 +-
+ 4 files changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
+index fe9ceb7..bc7a802 100644
+--- a/drivers/mtd/devices/m25p80.c
++++ b/drivers/mtd/devices/m25p80.c
+@@ -199,7 +199,7 @@ static int m25p_probe(struct spi_device *spi)
+ nor->read_reg = m25p80_read_reg;
+
+ nor->dev = &spi->dev;
+- nor->flash_node = spi->dev.of_node;
++ spi_nor_set_flash_node(nor, spi->dev.of_node);
+ nor->priv = flash;
+
+ spi_set_drvdata(spi, flash);
+diff --git a/drivers/mtd/spi-nor/fsl-quadspi.c b/drivers/mtd/spi-nor/fsl-quadspi.c
+index 7b10ed4..8f4d920 100644
+--- a/drivers/mtd/spi-nor/fsl-quadspi.c
++++ b/drivers/mtd/spi-nor/fsl-quadspi.c
+@@ -1013,7 +1013,7 @@ static int fsl_qspi_probe(struct platform_device *pdev)
+ mtd = &nor->mtd;
+
+ nor->dev = dev;
+- nor->flash_node = np;
++ spi_nor_set_flash_node(nor, np);
+ nor->priv = q;
+
+ /* fill the hooks */
+diff --git a/drivers/mtd/spi-nor/nxp-spifi.c b/drivers/mtd/spi-nor/nxp-spifi.c
+index 9e82098..4524b28 100644
+--- a/drivers/mtd/spi-nor/nxp-spifi.c
++++ b/drivers/mtd/spi-nor/nxp-spifi.c
+@@ -330,7 +330,7 @@ static int nxp_spifi_setup_flash(struct nxp_spifi *spifi,
+ writel(ctrl, spifi->io_base + SPIFI_CTRL);
+
+ spifi->nor.dev = spifi->dev;
+- spifi->nor.flash_node = np;
++ spi_nor_set_flash_node(&spifi->nor, np);
+ spifi->nor.priv = spifi;
+ spifi->nor.read = nxp_spifi_read;
+ spifi->nor.write = nxp_spifi_write;
+diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
+index 24ad373..b76090e 100644
+--- a/drivers/mtd/spi-nor/spi-nor.c
++++ b/drivers/mtd/spi-nor/spi-nor.c
+@@ -1151,7 +1151,7 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
+ const struct flash_info *info = NULL;
+ struct device *dev = nor->dev;
+ struct mtd_info *mtd = &nor->mtd;
+- struct device_node *np = nor->flash_node;
++ struct device_node *np = spi_nor_get_flash_node(nor);
+ int ret;
+ int i;
+
+--
+2.8.1
+
diff --git a/target/linux/socfpga/patches-4.4/0009-mtd-spi-nor-drop-flash_node-field.patch b/target/linux/socfpga/patches-4.4/0009-mtd-spi-nor-drop-flash_node-field.patch
new file mode 100644
index 0000000..1da6c94
--- /dev/null
+++ b/target/linux/socfpga/patches-4.4/0009-mtd-spi-nor-drop-flash_node-field.patch
@@ -0,0 +1,64 @@
+From 1348b9e2300f66a4ffcb5b467f4c99cfb958ffca Mon Sep 17 00:00:00 2001
+From: Brian Norris <computersforpeace at gmail.com>
+Date: Fri, 30 Oct 2015 20:33:27 -0700
+Subject: [PATCH 09/33] mtd: spi-nor: drop flash_node field
+
+We can just alias to the MTD of_node.
+
+Signed-off-by: Brian Norris <computersforpeace at gmail.com>
+Reviewed-by: Boris Brezillon <boris.brezillon at free-electrons.com>
+---
+ drivers/mtd/spi-nor/spi-nor.c | 1 -
+ include/linux/mtd/spi-nor.h | 6 ++----
+ 2 files changed, 2 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
+index b76090e..3e06d5b 100644
+--- a/drivers/mtd/spi-nor/spi-nor.c
++++ b/drivers/mtd/spi-nor/spi-nor.c
+@@ -1256,7 +1256,6 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
+ mtd->flags |= MTD_NO_ERASE;
+
+ mtd->dev.parent = dev;
+- mtd_set_of_node(mtd, np);
+ nor->page_size = info->page_size;
+ mtd->writebufsize = nor->page_size;
+
+diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
+index 823c5381..592420b 100644
+--- a/include/linux/mtd/spi-nor.h
++++ b/include/linux/mtd/spi-nor.h
+@@ -123,7 +123,6 @@ enum spi_nor_option_flags {
+ * @mtd: point to a mtd_info structure
+ * @lock: the lock for the read/write/erase/lock/unlock operations
+ * @dev: point to a spi device, or a spi nor controller device.
+- * @flash_node: point to a device node describing this flash instance.
+ * @page_size: the page size of the SPI NOR
+ * @addr_width: number of address bytes
+ * @erase_opcode: the opcode for erasing a sector
+@@ -154,7 +153,6 @@ struct spi_nor {
+ struct mtd_info mtd;
+ struct mutex lock;
+ struct device *dev;
+- struct device_node *flash_node;
+ u32 page_size;
+ u8 addr_width;
+ u8 erase_opcode;
+@@ -187,12 +185,12 @@ struct spi_nor {
+ static inline void spi_nor_set_flash_node(struct spi_nor *nor,
+ struct device_node *np)
+ {
+- nor->flash_node = np;
++ mtd_set_of_node(&nor->mtd, np);
+ }
+
+ static inline struct device_node *spi_nor_get_flash_node(struct spi_nor *nor)
+ {
+- return nor->flash_node;
++ return mtd_get_of_node(&nor->mtd);
+ }
+
+ /**
+--
+2.8.1
+
diff --git a/target/linux/socfpga/patches-4.4/0010-mtd-spi-nor-remove-unnecessary-leading-space-from-db.patch b/target/linux/socfpga/patches-4.4/0010-mtd-spi-nor-remove-unnecessary-leading-space-from-db.patch
new file mode 100644
index 0000000..19b22c5
--- /dev/null
+++ b/target/linux/socfpga/patches-4.4/0010-mtd-spi-nor-remove-unnecessary-leading-space-from-db.patch
@@ -0,0 +1,32 @@
+From f8c5645dd28440380622c2ad3744de0b55bd0bdf Mon Sep 17 00:00:00 2001
+From: Brian Norris <computersforpeace at gmail.com>
+Date: Fri, 30 Oct 2015 12:56:22 -0700
+Subject: [PATCH 10/33] mtd: spi-nor: remove unnecessary leading space from dbg
+ print
+
+As Cyrille noted [1], this line is wrong.
+
+[1] http://lists.infradead.org/pipermail/linux-mtd/2015-September/061725.html
+
+Signed-off-by: Brian Norris <computersforpeace at gmail.com>
+Cc: Cyrille Pitchen <cyrille.pitchen at atmel.com>
+---
+ drivers/mtd/spi-nor/spi-nor.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
+index 3e06d5b..107571e 100644
+--- a/drivers/mtd/spi-nor/spi-nor.c
++++ b/drivers/mtd/spi-nor/spi-nor.c
+@@ -856,7 +856,7 @@ static const struct flash_info *spi_nor_read_id(struct spi_nor *nor)
+
+ tmp = nor->read_reg(nor, SPINOR_OP_RDID, id, SPI_NOR_MAX_ID_LEN);
+ if (tmp < 0) {
+- dev_dbg(nor->dev, " error %d reading JEDEC ID\n", tmp);
++ dev_dbg(nor->dev, "error %d reading JEDEC ID\n", tmp);
+ return ERR_PTR(tmp);
+ }
+
+--
+2.8.1
+
diff --git a/target/linux/socfpga/patches-4.4/0011-mtd-spi-nor-provide-default-erase_sector-implementat.patch b/target/linux/socfpga/patches-4.4/0011-mtd-spi-nor-provide-default-erase_sector-implementat.patch
new file mode 100644
index 0000000..666b069
--- /dev/null
+++ b/target/linux/socfpga/patches-4.4/0011-mtd-spi-nor-provide-default-erase_sector-implementat.patch
@@ -0,0 +1,112 @@
+From 29675718c3880cbe7a8d8c6819c07dcec656c544 Mon Sep 17 00:00:00 2001
+From: Brian Norris <computersforpeace at gmail.com>
+Date: Tue, 10 Nov 2015 12:15:27 -0800
+Subject: [PATCH 11/33] mtd: spi-nor: provide default erase_sector
+ implementation
+
+Some spi-nor drivers perform sector erase by duplicating their
+write_reg() command. Let's not require that the driver fill this out,
+and provide a default instead.
+
+Tested on m25p80.c and Medatek's MT8173 SPI NOR flash driver.
+
+Signed-off-by: Brian Norris <computersforpeace at gmail.com>
+---
+ drivers/mtd/spi-nor/spi-nor.c | 37 +++++++++++++++++++++++++++++++++----
+ include/linux/mtd/spi-nor.h | 3 ++-
+ 2 files changed, 35 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
+index 107571e..0d2be38 100644
+--- a/drivers/mtd/spi-nor/spi-nor.c
++++ b/drivers/mtd/spi-nor/spi-nor.c
+@@ -38,6 +38,7 @@
+ #define CHIP_ERASE_2MB_READY_WAIT_JIFFIES (40UL * HZ)
+
+ #define SPI_NOR_MAX_ID_LEN 6
++#define SPI_NOR_MAX_ADDR_WIDTH 4
+
+ struct flash_info {
+ char *name;
+@@ -313,6 +314,29 @@ static void spi_nor_unlock_and_unprep(struct spi_nor *nor, enum spi_nor_ops ops)
+ }
+
+ /*
++ * Initiate the erasure of a single sector
++ */
++static int spi_nor_erase_sector(struct spi_nor *nor, u32 addr)
++{
++ u8 buf[SPI_NOR_MAX_ADDR_WIDTH];
++ int i;
++
++ if (nor->erase)
++ return nor->erase(nor, addr);
++
++ /*
++ * Default implementation, if driver doesn't have a specialized HW
++ * control
++ */
++ for (i = nor->addr_width - 1; i >= 0; i--) {
++ buf[i] = addr & 0xff;
++ addr >>= 8;
++ }
++
++ return nor->write_reg(nor, nor->erase_opcode, buf, nor->addr_width);
++}
++
++/*
+ * Erase an address range on the nor chip. The address range may extend
+ * one or more erase sectors. Return an error is there is a problem erasing.
+ */
+@@ -371,10 +395,9 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)
+ while (len) {
+ write_enable(nor);
+
+- if (nor->erase(nor, addr)) {
+- ret = -EIO;
++ ret = spi_nor_erase_sector(nor, addr);
++ if (ret)
+ goto erase_err;
+- }
+
+ addr += mtd->erasesize;
+ len -= mtd->erasesize;
+@@ -1138,7 +1161,7 @@ static int set_quad_mode(struct spi_nor *nor, const struct flash_info *info)
+ static int spi_nor_check(struct spi_nor *nor)
+ {
+ if (!nor->dev || !nor->read || !nor->write ||
+- !nor->read_reg || !nor->write_reg || !nor->erase) {
++ !nor->read_reg || !nor->write_reg) {
+ pr_err("spi-nor: please fill all the necessary fields!\n");
+ return -EINVAL;
+ }
+@@ -1338,6 +1361,12 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
+ nor->addr_width = 3;
+ }
+
++ if (nor->addr_width > SPI_NOR_MAX_ADDR_WIDTH) {
++ dev_err(dev, "address width is too large: %u\n",
++ nor->addr_width);
++ return -EINVAL;
++ }
++
+ nor->read_dummy = spi_nor_read_dummy_cycles(nor);
+
+ dev_info(dev, "%s (%lld Kbytes)\n", info->name,
+diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
+index 592420b..62356d5 100644
+--- a/include/linux/mtd/spi-nor.h
++++ b/include/linux/mtd/spi-nor.h
+@@ -142,7 +142,8 @@ enum spi_nor_option_flags {
+ * @read: [DRIVER-SPECIFIC] read data from the SPI NOR
+ * @write: [DRIVER-SPECIFIC] write data to the SPI NOR
+ * @erase: [DRIVER-SPECIFIC] erase a sector of the SPI NOR
+- * at the offset @offs
++ * at the offset @offs; if not provided by the driver,
++ * spi-nor will send the erase opcode via write_reg()
+ * @flash_lock: [FLASH-SPECIFIC] lock a region of the SPI NOR
+ * @flash_unlock: [FLASH-SPECIFIC] unlock a region of the SPI NOR
+ * @flash_is_locked: [FLASH-SPECIFIC] check if a region of the SPI NOR is
+--
+2.8.1
+
diff --git a/target/linux/socfpga/patches-4.4/0012-mtd-spi-nor-mx25l3205d-mx25l6405d-append-SECT_4K.patch b/target/linux/socfpga/patches-4.4/0012-mtd-spi-nor-mx25l3205d-mx25l6405d-append-SECT_4K.patch
new file mode 100644
index 0000000..720d687
--- /dev/null
+++ b/target/linux/socfpga/patches-4.4/0012-mtd-spi-nor-mx25l3205d-mx25l6405d-append-SECT_4K.patch
@@ -0,0 +1,32 @@
+From 655585649ba3f4675b4386afc1feb22c6a880eb8 Mon Sep 17 00:00:00 2001
+From: Andreas Fenkart <afenkart at gmail.com>
+Date: Thu, 5 Nov 2015 10:04:23 +0100
+Subject: [PATCH 12/33] mtd: spi-nor: mx25l3205d/mx25l6405d: append SECT_4K
+
+according datasheet both chips can erase 4kByte sectors individually
+
+Signed-off-by: Andreas Fenkart <andreas.fenkart at dev.digitalstrom.org>
+Signed-off-by: Brian Norris <computersforpeace at gmail.com>
+---
+ drivers/mtd/spi-nor/spi-nor.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
+index 0d2be38..c5bc927 100644
+--- a/drivers/mtd/spi-nor/spi-nor.c
++++ b/drivers/mtd/spi-nor/spi-nor.c
+@@ -738,9 +738,9 @@ static const struct flash_info spi_nor_ids[] = {
+ { "mx25l4005a", INFO(0xc22013, 0, 64 * 1024, 8, SECT_4K) },
+ { "mx25l8005", INFO(0xc22014, 0, 64 * 1024, 16, 0) },
+ { "mx25l1606e", INFO(0xc22015, 0, 64 * 1024, 32, SECT_4K) },
+- { "mx25l3205d", INFO(0xc22016, 0, 64 * 1024, 64, 0) },
++ { "mx25l3205d", INFO(0xc22016, 0, 64 * 1024, 64, SECT_4K) },
+ { "mx25l3255e", INFO(0xc29e16, 0, 64 * 1024, 64, SECT_4K) },
+- { "mx25l6405d", INFO(0xc22017, 0, 64 * 1024, 128, 0) },
++ { "mx25l6405d", INFO(0xc22017, 0, 64 * 1024, 128, SECT_4K) },
+ { "mx25u6435f", INFO(0xc22537, 0, 64 * 1024, 128, SECT_4K) },
+ { "mx25l12805d", INFO(0xc22018, 0, 64 * 1024, 256, 0) },
+ { "mx25l12855e", INFO(0xc22618, 0, 64 * 1024, 256, 0) },
+--
+2.8.1
+
diff --git a/target/linux/socfpga/patches-4.4/0013-mtd-spi-nor-Fix-error-message-with-unrecognized-JEDE.patch b/target/linux/socfpga/patches-4.4/0013-mtd-spi-nor-Fix-error-message-with-unrecognized-JEDE.patch
new file mode 100644
index 0000000..1fd8955
--- /dev/null
+++ b/target/linux/socfpga/patches-4.4/0013-mtd-spi-nor-Fix-error-message-with-unrecognized-JEDE.patch
@@ -0,0 +1,35 @@
+From 14b9112f7d20455ffef7d796317e7d08c6545b41 Mon Sep 17 00:00:00 2001
+From: Ricardo Ribalda <ricardo.ribalda at gmail.com>
+Date: Mon, 30 Nov 2015 20:41:17 +0100
+Subject: [PATCH 13/33] mtd: spi-nor: Fix error message with unrecognized JEDEC
+
+The error message was:
+
+m25p80 spi32766.0: unrecognized JEDEC id bytes: 00, 0, 0
+
+The new error message:
+
+m25p80 spi32766.0: unrecognized JEDEC id bytes: 00, 00, 00
+
+Signed-off-by: Ricardo Ribalda Delgado <ricardo.ribalda at gmail.com>
+Signed-off-by: Brian Norris <computersforpeace at gmail.com>
+---
+ drivers/mtd/spi-nor/spi-nor.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
+index c5bc927..3a50eea 100644
+--- a/drivers/mtd/spi-nor/spi-nor.c
++++ b/drivers/mtd/spi-nor/spi-nor.c
+@@ -890,7 +890,7 @@ static const struct flash_info *spi_nor_read_id(struct spi_nor *nor)
+ return &spi_nor_ids[tmp];
+ }
+ }
+- dev_err(nor->dev, "unrecognized JEDEC id bytes: %02x, %2x, %2x\n",
++ dev_err(nor->dev, "unrecognized JEDEC id bytes: %02x, %02x, %02x\n",
+ id[0], id[1], id[2]);
+ return ERR_PTR(-ENODEV);
+ }
+--
+2.8.1
+
diff --git a/target/linux/socfpga/patches-4.4/0014-mtd-spi-nor-fix-error-handling-in-spi_nor_erase.patch b/target/linux/socfpga/patches-4.4/0014-mtd-spi-nor-fix-error-handling-in-spi_nor_erase.patch
new file mode 100644
index 0000000..c9f48ea
--- /dev/null
+++ b/target/linux/socfpga/patches-4.4/0014-mtd-spi-nor-fix-error-handling-in-spi_nor_erase.patch
@@ -0,0 +1,44 @@
+From 93aa2e2f5af5b8e766fc22c3ff83a1642462025f Mon Sep 17 00:00:00 2001
+From: Heiner Kallweit <hkallweit1 at gmail.com>
+Date: Tue, 17 Nov 2015 20:18:54 +0100
+Subject: [PATCH 14/33] mtd: spi-nor: fix error handling in spi_nor_erase
+
+The documenting comment of mtd_erase in mtdcore.c states:
+Device drivers are supposed to call instr->callback() whenever
+the operation completes, even if it completes with a failure.
+
+Currently the callback isn't called in case of failure. Fix this.
+
+Signed-off-by: Heiner Kallweit <hkallweit1 at gmail.com>
+Signed-off-by: Brian Norris <computersforpeace at gmail.com>
+---
+ drivers/mtd/spi-nor/spi-nor.c | 8 ++------
+ 1 file changed, 2 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
+index 3a50eea..43e00e2 100644
+--- a/drivers/mtd/spi-nor/spi-nor.c
++++ b/drivers/mtd/spi-nor/spi-nor.c
+@@ -410,17 +410,13 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)
+
+ write_disable(nor);
+
++erase_err:
+ spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_ERASE);
+
+- instr->state = MTD_ERASE_DONE;
++ instr->state = ret ? MTD_ERASE_FAILED : MTD_ERASE_DONE;
+ mtd_erase_callback(instr);
+
+ return ret;
+-
+-erase_err:
+- spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_ERASE);
+- instr->state = MTD_ERASE_FAILED;
+- return ret;
+ }
+
+ static void stm_get_locked_range(struct spi_nor *nor, u8 sr, loff_t *ofs,
+--
+2.8.1
+
diff --git a/target/linux/socfpga/patches-4.4/0015-mtd-spi-nor-Check-the-return-value-from-read_sr.patch b/target/linux/socfpga/patches-4.4/0015-mtd-spi-nor-Check-the-return-value-from-read_sr.patch
new file mode 100644
index 0000000..bfb5a97
--- /dev/null
+++ b/target/linux/socfpga/patches-4.4/0015-mtd-spi-nor-Check-the-return-value-from-read_sr.patch
@@ -0,0 +1,60 @@
+From 8f5f914b1b6d70d6d7455e0f89df84b3377677f9 Mon Sep 17 00:00:00 2001
+From: Fabio Estevam <fabio.estevam at freescale.com>
+Date: Fri, 20 Nov 2015 16:26:11 -0200
+Subject: [PATCH 15/33] mtd: spi-nor: Check the return value from read_sr()
+
+We should better check the return value from read_sr() and
+propagate it in the case of error.
+
+Signed-off-by: Fabio Estevam <fabio.estevam at freescale.com>
+Signed-off-by: Brian Norris <computersforpeace at gmail.com>
+---
+ drivers/mtd/spi-nor/spi-nor.c | 10 ++++++++--
+ 1 file changed, 8 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
+index 43e00e2..f8f36d4 100644
+--- a/drivers/mtd/spi-nor/spi-nor.c
++++ b/drivers/mtd/spi-nor/spi-nor.c
+@@ -478,11 +478,13 @@ static int stm_is_locked_sr(struct spi_nor *nor, loff_t ofs, uint64_t len,
+ static int stm_lock(struct spi_nor *nor, loff_t ofs, uint64_t len)
+ {
+ struct mtd_info *mtd = &nor->mtd;
+- u8 status_old, status_new;
++ int status_old, status_new;
+ u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
+ u8 shift = ffs(mask) - 1, pow, val;
+
+ status_old = read_sr(nor);
++ if (status_old < 0)
++ return status_old;
+
+ /* SPI NOR always locks to the end */
+ if (ofs + len != mtd->size) {
+@@ -528,11 +530,13 @@ static int stm_lock(struct spi_nor *nor, loff_t ofs, uint64_t len)
+ static int stm_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len)
+ {
+ struct mtd_info *mtd = &nor->mtd;
+- uint8_t status_old, status_new;
++ int status_old, status_new;
+ u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
+ u8 shift = ffs(mask) - 1, pow, val;
+
+ status_old = read_sr(nor);
++ if (status_old < 0)
++ return status_old;
+
+ /* Cannot unlock; would unlock larger region than requested */
+ if (stm_is_locked_sr(nor, ofs - mtd->erasesize, mtd->erasesize,
+@@ -1032,6 +1036,8 @@ static int macronix_quad_enable(struct spi_nor *nor)
+ int ret, val;
+
+ val = read_sr(nor);
++ if (val < 0)
++ return val;
+ write_enable(nor);
+
+ write_sr(nor, val | SR_QUAD_EN_MX);
+--
+2.8.1
+
diff --git a/target/linux/socfpga/patches-4.4/0016-mtd-spi-nor-remove-micron_quad_enable.patch b/target/linux/socfpga/patches-4.4/0016-mtd-spi-nor-remove-micron_quad_enable.patch
new file mode 100644
index 0000000..48ceb8e
--- /dev/null
+++ b/target/linux/socfpga/patches-4.4/0016-mtd-spi-nor-remove-micron_quad_enable.patch
@@ -0,0 +1,110 @@
+From 246e2a5cc60e2179bf8849310b7af9eaa5c505f9 Mon Sep 17 00:00:00 2001
+From: Cyrille Pitchen <cyrille.pitchen at atmel.com>
+Date: Fri, 8 Jan 2016 17:02:13 +0100
+Subject: [PATCH 16/33] mtd: spi-nor: remove micron_quad_enable()
+
+This patch remove the micron_quad_enable() function which force the Quad
+SPI mode. However, once this mode is enabled, the Micron memory expect ALL
+commands to use the SPI 4-4-4 protocol. Hence a failure does occur when
+calling spi_nor_wait_till_ready() right after the update of the Enhanced
+Volatile Configuration Register (EVCR) in the micron_quad_enable() as
+the SPI controller driver is not aware about the protocol change.
+
+Since there is almost no performance increase using Fast Read 4-4-4
+commands instead of Fast Read 1-1-4 commands, we rather keep on using the
+Extended SPI mode than enabling the Quad SPI mode.
+
+Let's take the example of the pretty standard use of 8 dummy cycles during
+Fast Read operations on 64KB erase sectors:
+
+Fast Read 1-1-4 requires 8 cycles for the command, then 24 cycles for the
+3byte address followed by 8 dummy clock cycles and finally 65536*2 cycles
+for the read data; so 131112 clock cycles.
+
+On the other hand the Fast Read 4-4-4 would require 2 cycles for the
+command, then 6 cycles for the 3byte address followed by 8 dummy clock
+cycles and finally 65536*2 cycles for the read data. So 131088 clock
+cycles. The theorical bandwidth increase is 0.0%.
+
+Now using Fast Read operations on 512byte pages:
+Fast Read 1-1-4 needs 8+24+8+(512*2) = 1064 clock cycles whereas Fast
+Read 4-4-4 would requires 2+6+8+(512*2) = 1040 clock cycles. Hence the
+theorical bandwidth increase is 2.3%.
+Consecutive reads for non sequential pages is not a relevant use case so
+The Quad SPI mode is not worth it.
+
+mtd_speedtest seems to confirm these figures.
+
+Signed-off-by: Cyrille Pitchen <cyrille.pitchen at atmel.com>
+Fixes: 548cd3ab54da ("mtd: spi-nor: Add quad I/O support for Micron SPI NOR")
+---
+ drivers/mtd/spi-nor/spi-nor.c | 46 +------------------------------------------
+ 1 file changed, 1 insertion(+), 45 deletions(-)
+
+diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
+index f8f36d4..6e72e96 100644
+--- a/drivers/mtd/spi-nor/spi-nor.c
++++ b/drivers/mtd/spi-nor/spi-nor.c
+@@ -1092,45 +1092,6 @@ static int spansion_quad_enable(struct spi_nor *nor)
+ return 0;
+ }
+
+-static int micron_quad_enable(struct spi_nor *nor)
+-{
+- int ret;
+- u8 val;
+-
+- ret = nor->read_reg(nor, SPINOR_OP_RD_EVCR, &val, 1);
+- if (ret < 0) {
+- dev_err(nor->dev, "error %d reading EVCR\n", ret);
+- return ret;
+- }
+-
+- write_enable(nor);
+-
+- /* set EVCR, enable quad I/O */
+- nor->cmd_buf[0] = val & ~EVCR_QUAD_EN_MICRON;
+- ret = nor->write_reg(nor, SPINOR_OP_WD_EVCR, nor->cmd_buf, 1);
+- if (ret < 0) {
+- dev_err(nor->dev, "error while writing EVCR register\n");
+- return ret;
+- }
+-
+- ret = spi_nor_wait_till_ready(nor);
+- if (ret)
+- return ret;
+-
+- /* read EVCR and check it */
+- ret = nor->read_reg(nor, SPINOR_OP_RD_EVCR, &val, 1);
+- if (ret < 0) {
+- dev_err(nor->dev, "error %d reading EVCR\n", ret);
+- return ret;
+- }
+- if (val & EVCR_QUAD_EN_MICRON) {
+- dev_err(nor->dev, "Micron EVCR Quad bit not clear\n");
+- return -EINVAL;
+- }
+-
+- return 0;
+-}
+-
+ static int set_quad_mode(struct spi_nor *nor, const struct flash_info *info)
+ {
+ int status;
+@@ -1144,12 +1105,7 @@ static int set_quad_mode(struct spi_nor *nor, const struct flash_info *info)
+ }
+ return status;
+ case SNOR_MFR_MICRON:
+- status = micron_quad_enable(nor);
+- if (status) {
+- dev_err(nor->dev, "Micron quad-read not enabled\n");
+- return -EINVAL;
+- }
+- return status;
++ return 0;
+ default:
+ status = spansion_quad_enable(nor);
+ if (status) {
+--
+2.8.1
+
diff --git a/target/linux/socfpga/patches-4.4/0017-mtd-spi-nor-properly-detect-the-memory-when-it-boots.patch b/target/linux/socfpga/patches-4.4/0017-mtd-spi-nor-properly-detect-the-memory-when-it-boots.patch
new file mode 100644
index 0000000..63cd47e
--- /dev/null
+++ b/target/linux/socfpga/patches-4.4/0017-mtd-spi-nor-properly-detect-the-memory-when-it-boots.patch
@@ -0,0 +1,244 @@
+From 06883bee58d1beedef783f7f5662367736d90924 Mon Sep 17 00:00:00 2001
+From: Cyrille Pitchen <cyrille.pitchen at atmel.com>
+Date: Fri, 8 Jan 2016 17:02:14 +0100
+Subject: [PATCH 17/33] mtd: spi-nor: properly detect the memory when it boots
+ in Quad or Dual mode
+
+The quad (or dual) mode of a spi-nor memory may be enabled at boot time by
+non-volatile bits in some setting register. Also such a mode may have
+already been enabled at early stage by some boot loader.
+
+Hence, we should not guess the spi-nor memory is always configured for the
+regular SPI 1-1-1 protocol.
+
+Micron and Macronix memories, once their Quad (or dual for Micron) mode
+enabled, no longer process the regular JEDEC Read ID (0x9f) command but
+instead reply to a new command: JEDEC Read ID Multiple I/O (0xaf).
+Besides, in Quad mode both memory manufacturers expect ALL commands to
+use the SPI 4-4-4 protocol. For Micron memories, enabling their Dual mode
+implies to use the SPI 2-2-2 protocol for ALL commands.
+
+Winbond memories, once their Quad mode enabled, expect ALL commands to use
+the SPI 4-4-4 protocol. Unlike Micron and Macronix memories, they still
+reply to the regular JEDEC Read ID (0x9f) command.
+
+Signed-off-by: Cyrille Pitchen <cyrille.pitchen at atmel.com>
+---
+ drivers/mtd/spi-nor/spi-nor.c | 83 ++++++++++++++++++++++++++++++++++++++++---
+ include/linux/mtd/spi-nor.h | 50 ++++++++++++++++++++++++--
+ 2 files changed, 127 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
+index 6e72e96..9ad2d40 100644
+--- a/drivers/mtd/spi-nor/spi-nor.c
++++ b/drivers/mtd/spi-nor/spi-nor.c
+@@ -73,6 +73,12 @@ struct flash_info {
+
+ #define JEDEC_MFR(info) ((info)->id[0])
+
++struct read_id_config {
++ enum read_mode mode;
++ enum spi_nor_protocol proto;
++ u8 opcode;
++};
++
+ static const struct flash_info *spi_nor_match_id(const char *name);
+
+ /*
+@@ -871,11 +877,22 @@ static const struct flash_info spi_nor_ids[] = {
+ { },
+ };
+
+-static const struct flash_info *spi_nor_read_id(struct spi_nor *nor)
++static const struct flash_info *spi_nor_read_id(struct spi_nor *nor,
++ enum read_mode mode)
+ {
+- int tmp;
++ int i, tmp;
+ u8 id[SPI_NOR_MAX_ID_LEN];
+ const struct flash_info *info;
++ static const struct read_id_config configs[] = {
++ /* Winbond QPI mode */
++ {SPI_NOR_QUAD, SNOR_PROTO_4_4_4, SPINOR_OP_RDID},
++
++ /* Micron Quad mode & Macronix QPI mode */
++ {SPI_NOR_QUAD, SNOR_PROTO_4_4_4, SPINOR_OP_MIO_RDID},
++
++ /* Micron Dual mode */
++ {SPI_NOR_DUAL, SNOR_PROTO_2_2_2, SPINOR_OP_MIO_RDID}
++ };
+
+ tmp = nor->read_reg(nor, SPINOR_OP_RDID, id, SPI_NOR_MAX_ID_LEN);
+ if (tmp < 0) {
+@@ -883,6 +900,58 @@ static const struct flash_info *spi_nor_read_id(struct spi_nor *nor)
+ return ERR_PTR(tmp);
+ }
+
++ /*
++ * Check whether the SPI NOR memory has already been configured (at
++ * reset or by some bootloader) to use a protocol other than SPI 1-1-1.
++ */
++ for (i = 0; i < ARRAY_SIZE(configs); ++i) {
++ int len = SPI_NOR_MAX_ID_LEN;
++ bool is_multi = false;
++
++ /*
++ * Check the latest read Manufacturer ID + Device ID (3 bytes):
++ * if they are different from both 0x000000 and 0xffffff, we
++ * assume that we succeeded in reading a valid JEDEC ID so we
++ * don't need to try other SPI protocols.
++ * Indeed when either the protocol or the op code are not valid,
++ * the SPI NOR memory should not reply to the command. Hence the
++ * SPI I/O lines remain in their default state: 1 when connected
++ * to pull-up resistors or 0 with pull-down.
++ */
++ if (!((id[0] == 0xff && id[1] == 0xff && id[2] == 0xff) ||
++ (id[0] == 0x00 && id[1] == 0x00 && id[2] == 0x00)))
++ break;
++
++ /* Only try protocols supported by the user. */
++ if (configs[i].mode != mode)
++ continue;
++
++ /* Set this protocol for all commands. */
++ nor->reg_proto = configs[i].proto;
++ nor->read_proto = configs[i].proto;
++ nor->write_proto = configs[i].proto;
++ nor->erase_proto = configs[i].proto;
++
++ /*
++ * Multiple I/O Read ID only returns the Manufacturer ID
++ * (1 byte) and the Device ID (2 bytes). So we reset the
++ * remaining bytes.
++ */
++ if (configs[i].opcode == SPINOR_OP_MIO_RDID) {
++ is_multi = true;
++ len = 3;
++ memset(id + len, 0, sizeof(id) - len);
++ }
++
++ tmp = nor->read_reg(nor, configs[i].opcode, id, len);
++ if (tmp < 0) {
++ dev_dbg(nor->dev,
++ "error %d reading JEDEC ID%s\n",
++ tmp, (is_multi ? " Multi I/O" : ""));
++ return ERR_PTR(tmp);
++ }
++ }
++
+ for (tmp = 0; tmp < ARRAY_SIZE(spi_nor_ids) - 1; tmp++) {
+ info = &spi_nor_ids[tmp];
+ if (info->id_len) {
+@@ -1140,11 +1209,17 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
+ if (ret)
+ return ret;
+
++ /* Reset SPI protocol for all commands */
++ nor->erase_proto = SNOR_PROTO_1_1_1;
++ nor->read_proto = SNOR_PROTO_1_1_1;
++ nor->write_proto = SNOR_PROTO_1_1_1;
++ nor->reg_proto = SNOR_PROTO_1_1_1;
++
+ if (name)
+ info = spi_nor_match_id(name);
+ /* Try to auto-detect if chip name wasn't specified or not found */
+ if (!info)
+- info = spi_nor_read_id(nor);
++ info = spi_nor_read_id(nor, mode);
+ if (IS_ERR_OR_NULL(info))
+ return -ENOENT;
+
+@@ -1155,7 +1230,7 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
+ if (name && info->id_len) {
+ const struct flash_info *jinfo;
+
+- jinfo = spi_nor_read_id(nor);
++ jinfo = spi_nor_read_id(nor, mode);
+ if (IS_ERR(jinfo)) {
+ return PTR_ERR(jinfo);
+ } else if (jinfo != info) {
+diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
+index 62356d5..53932c8 100644
+--- a/include/linux/mtd/spi-nor.h
++++ b/include/linux/mtd/spi-nor.h
+@@ -75,8 +75,9 @@
+ #define SPINOR_OP_BRWR 0x17 /* Bank register write */
+
+ /* Used for Micron flashes only. */
+-#define SPINOR_OP_RD_EVCR 0x65 /* Read EVCR register */
+-#define SPINOR_OP_WD_EVCR 0x61 /* Write EVCR register */
++#define SPINOR_OP_MIO_RDID 0xaf /* Multiple I/O Read JEDEC ID */
++#define SPINOR_OP_RD_EVCR 0x65 /* Read EVCR register */
++#define SPINOR_OP_WD_EVCR 0x61 /* Write EVCR register */
+
+ /* Status Register bits. */
+ #define SR_WIP BIT(0) /* Write in progress */
+@@ -105,6 +106,43 @@ enum read_mode {
+ SPI_NOR_QUAD,
+ };
+
++
++#define SNOR_PROTO_CMD_OFF 8
++#define SNOR_PROTO_CMD_MASK GENMASK(11, 8)
++#define SNOR_PROTO_CMD_TO_PROTO(cmd) \
++ (((cmd) << SNOR_PROTO_CMD_OFF) & SNOR_PROTO_CMD_MASK)
++#define SNOR_PROTO_CMD_FROM_PROTO(proto) \
++ ((((u32)(proto)) & SNOR_PROTO_CMD_MASK) >> SNOR_PROTO_CMD_OFF)
++
++#define SNOR_PROTO_ADDR_OFF 4
++#define SNOR_PROTO_ADDR_MASK GENMASK(7, 4)
++#define SNOR_PROTO_ADDR_TO_PROTO(addr) \
++ (((addr) << SNOR_PROTO_ADDR_OFF) & SNOR_PROTO_ADDR_MASK)
++#define SNOR_PROTO_ADDR_FROM_PROTO(proto) \
++ ((((u32)(proto)) & SNOR_PROTO_ADDR_MASK) >> SNOR_PROTO_ADDR_OFF)
++
++#define SNOR_PROTO_DATA_OFF 0
++#define SNOR_PROTO_DATA_MASK GENMASK(3, 0)
++#define SNOR_PROTO_DATA_TO_PROTO(data) \
++ (((data) << SNOR_PROTO_DATA_OFF) & SNOR_PROTO_DATA_MASK)
++#define SNOR_PROTO_DATA_FROM_PROTO(proto) \
++ ((((u32)(proto)) & SNOR_PROTO_DATA_MASK) >> SNOR_PROTO_DATA_OFF)
++
++#define SNOR_PROTO(cmd, addr, data) \
++ (SNOR_PROTO_CMD_TO_PROTO(cmd) | \
++ SNOR_PROTO_ADDR_TO_PROTO(addr) | \
++ SNOR_PROTO_DATA_TO_PROTO(data))
++
++enum spi_nor_protocol {
++ SNOR_PROTO_1_1_1 = SNOR_PROTO(1, 1, 1), /* SPI */
++ SNOR_PROTO_1_1_2 = SNOR_PROTO(1, 1, 2), /* Dual Output */
++ SNOR_PROTO_1_1_4 = SNOR_PROTO(1, 1, 4), /* Quad Output */
++ SNOR_PROTO_1_2_2 = SNOR_PROTO(1, 2, 2), /* Dual IO */
++ SNOR_PROTO_1_4_4 = SNOR_PROTO(1, 4, 4), /* Quad IO */
++ SNOR_PROTO_2_2_2 = SNOR_PROTO(2, 2, 2), /* Dual Command */
++ SNOR_PROTO_4_4_4 = SNOR_PROTO(4, 4, 4), /* Quad Command */
++};
++
+ #define SPI_NOR_MAX_CMD_SIZE 8
+ enum spi_nor_ops {
+ SPI_NOR_OPS_READ = 0,
+@@ -132,6 +170,10 @@ enum spi_nor_option_flags {
+ * @flash_read: the mode of the read
+ * @sst_write_second: used by the SST write operation
+ * @flags: flag options for the current SPI-NOR (SNOR_F_*)
++ * @erase_proto: the SPI protocol used by erase operations
++ * @read_proto: the SPI protocol used by read operations
++ * @write_proto: the SPI protocol used by write operations
++ * @reg_proto the SPI protocol used by read_reg/write_reg operations
+ * @cmd_buf: used by the write_reg
+ * @prepare: [OPTIONAL] do some preparations for the
+ * read/write/erase/lock/unlock operations
+@@ -160,6 +202,10 @@ struct spi_nor {
+ u8 read_opcode;
+ u8 read_dummy;
+ u8 program_opcode;
++ enum spi_nor_protocol erase_proto;
++ enum spi_nor_protocol read_proto;
++ enum spi_nor_protocol write_proto;
++ enum spi_nor_protocol reg_proto;
+ enum read_mode flash_read;
+ bool sst_write_second;
+ u32 flags;
+--
+2.8.1
+
diff --git a/target/linux/socfpga/patches-4.4/0018-mtd-spi-nor-select-op-codes-and-SPI-NOR-protocols-by.patch b/target/linux/socfpga/patches-4.4/0018-mtd-spi-nor-select-op-codes-and-SPI-NOR-protocols-by.patch
new file mode 100644
index 0000000..5adef1e
--- /dev/null
+++ b/target/linux/socfpga/patches-4.4/0018-mtd-spi-nor-select-op-codes-and-SPI-NOR-protocols-by.patch
@@ -0,0 +1,203 @@
+From a27dc343ea2de9283ca057fbcafa12a279a19b7b Mon Sep 17 00:00:00 2001
+From: Cyrille Pitchen <cyrille.pitchen at atmel.com>
+Date: Fri, 8 Jan 2016 17:02:15 +0100
+Subject: [PATCH 18/33] mtd: spi-nor: select op codes and SPI NOR protocols by
+ manufacturer
+
+This is a transitional patch to prepare the split by Manufacturer of the
+support of Single/Dual/Quad SPI modes.
+
+Indeed every QSPI NOR manufacturer (Spansion, Micron, Macronix, Winbond)
+supports Dual or Quad SPI modes on its way. Especially the Fast Read op
+code and the SPI NOR protocols to use are not quite the same depending on
+the manufacturer.
+
+For instance Quad commands can use either the SPI 1-1-4, 1-4-4 or 4-4-4
+protocol.
+
+This is why this patch will be completed by fixes for each manufacturer.
+
+Signed-off-by: Cyrille Pitchen <cyrille.pitchen at atmel.com>
+---
+ drivers/mtd/spi-nor/spi-nor.c | 110 ++++++++++++++++++++++++++++++++----------
+ include/linux/mtd/spi-nor.h | 12 +++--
+ 2 files changed, 92 insertions(+), 30 deletions(-)
+
+diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
+index 9ad2d40..889af12 100644
+--- a/drivers/mtd/spi-nor/spi-nor.c
++++ b/drivers/mtd/spi-nor/spi-nor.c
+@@ -1172,17 +1172,61 @@ static int set_quad_mode(struct spi_nor *nor, const struct flash_info *info)
+ dev_err(nor->dev, "Macronix quad-read not enabled\n");
+ return -EINVAL;
+ }
+- return status;
++ /* Check whether Macronix QPI mode is enabled. */
++ if (nor->read_proto != SNOR_PROTO_4_4_4)
++ nor->read_proto = SNOR_PROTO_1_1_4;
++ break;
++
+ case SNOR_MFR_MICRON:
+- return 0;
+- default:
++ /* Check whether Micron Quad mode is enabled. */
++ if (nor->read_proto != SNOR_PROTO_4_4_4)
++ nor->read_proto = SNOR_PROTO_1_1_4;
++ break;
++
++ case SNOR_MFR_SPANSION:
+ status = spansion_quad_enable(nor);
+ if (status) {
+ dev_err(nor->dev, "Spansion quad-read not enabled\n");
+ return -EINVAL;
+ }
+- return status;
++ nor->read_proto = SNOR_PROTO_1_1_4;
++ break;
++
++ default:
++ return -EINVAL;
+ }
++
++ nor->read_opcode = SPINOR_OP_READ_1_1_4;
++ return 0;
++}
++
++static int set_dual_mode(struct spi_nor *nor, const struct flash_info *info)
++{
++ switch (JEDEC_MFR(info)) {
++ case SNOR_MFR_MICRON:
++ /* Check whether Micron Dual mode is enabled. */
++ if (nor->read_proto != SNOR_PROTO_2_2_2)
++ nor->read_proto = SNOR_PROTO_1_1_2;
++ break;
++
++ default:
++ nor->read_proto = SNOR_PROTO_1_1_2;
++ break;
++ }
++
++ nor->read_opcode = SPINOR_OP_READ_1_1_2;
++ return 0;
++}
++
++static int set_single_mode(struct spi_nor *nor, const struct flash_info *info)
++{
++ switch (JEDEC_MFR(info)) {
++ default:
++ nor->read_proto = SNOR_PROTO_1_1_1;
++ break;
++ }
++
++ return 0;
+ }
+
+ static int spi_nor_check(struct spi_nor *nor)
+@@ -1330,7 +1374,30 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
+ if (info->flags & SPI_NOR_NO_FR)
+ nor->flash_read = SPI_NOR_NORMAL;
+
+- /* Quad/Dual-read mode takes precedence over fast/normal */
++ /* Default commands */
++ if (nor->flash_read == SPI_NOR_NORMAL)
++ nor->read_opcode = SPINOR_OP_READ;
++ else
++ nor->read_opcode = SPINOR_OP_READ_FAST;
++
++ nor->program_opcode = SPINOR_OP_PP;
++
++ /*
++ * Quad/Dual-read mode takes precedence over fast/normal.
++ *
++ * Manufacturer specific modes are discovered when reading the JEDEC ID
++ * and are reported by the nor->read_proto value:
++ * - SNOR_PROTO_4_4_4 is either:
++ * + Micron Quad mode enabled
++ * + Macronix/Winbond QPI mode enabled
++ * - SNOR_PROTO_2_2_2 is either:
++ * + Micron Dual mode enabled
++ *
++ * The opcodes and the protocols are updated depending on the
++ * manufacturer.
++ * The read opcode and protocol should be updated by the relevant
++ * function when entering Quad or Dual mode.
++ */
+ if (mode == SPI_NOR_QUAD && info->flags & SPI_NOR_QUAD_READ) {
+ ret = set_quad_mode(nor, info);
+ if (ret) {
+@@ -1339,30 +1406,21 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
+ }
+ nor->flash_read = SPI_NOR_QUAD;
+ } else if (mode == SPI_NOR_DUAL && info->flags & SPI_NOR_DUAL_READ) {
++ ret = set_dual_mode(nor, info);
++ if (ret) {
++ dev_err(dev, "dual mode not supported\n");
++ return ret;
++ }
+ nor->flash_read = SPI_NOR_DUAL;
++ } else if (info->flags & (SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)) {
++ /* We may need to leave a Quad or Dual mode */
++ ret = set_single_mode(nor, info);
++ if (ret) {
++ dev_err(dev, "failed to switch back to single mode\n");
++ return ret;
++ }
+ }
+
+- /* Default commands */
+- switch (nor->flash_read) {
+- case SPI_NOR_QUAD:
+- nor->read_opcode = SPINOR_OP_READ_1_1_4;
+- break;
+- case SPI_NOR_DUAL:
+- nor->read_opcode = SPINOR_OP_READ_1_1_2;
+- break;
+- case SPI_NOR_FAST:
+- nor->read_opcode = SPINOR_OP_READ_FAST;
+- break;
+- case SPI_NOR_NORMAL:
+- nor->read_opcode = SPINOR_OP_READ;
+- break;
+- default:
+- dev_err(dev, "No Read opcode defined\n");
+- return -EINVAL;
+- }
+-
+- nor->program_opcode = SPINOR_OP_PP;
+-
+ if (info->addr_width)
+ nor->addr_width = info->addr_width;
+ else if (mtd->size > 0x1000000) {
+diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
+index 53932c8..89e3228 100644
+--- a/include/linux/mtd/spi-nor.h
++++ b/include/linux/mtd/spi-nor.h
+@@ -42,8 +42,10 @@
+ #define SPINOR_OP_WRSR 0x01 /* Write status register 1 byte */
+ #define SPINOR_OP_READ 0x03 /* Read data bytes (low frequency) */
+ #define SPINOR_OP_READ_FAST 0x0b /* Read data bytes (high frequency) */
+-#define SPINOR_OP_READ_1_1_2 0x3b /* Read data bytes (Dual SPI) */
+-#define SPINOR_OP_READ_1_1_4 0x6b /* Read data bytes (Quad SPI) */
++#define SPINOR_OP_READ_1_1_2 0x3b /* Read data bytes (Dual Output SPI) */
++#define SPINOR_OP_READ_1_2_2 0xbb /* Read data bytes (Dual I/O SPI) */
++#define SPINOR_OP_READ_1_1_4 0x6b /* Read data bytes (Quad Output SPI) */
++#define SPINOR_OP_READ_1_4_4 0xeb /* Read data bytes (Quad I/O SPI) */
+ #define SPINOR_OP_PP 0x02 /* Page program (up to 256 bytes) */
+ #define SPINOR_OP_BE_4K 0x20 /* Erase 4KiB block */
+ #define SPINOR_OP_BE_4K_PMC 0xd7 /* Erase 4KiB block on PMC chips */
+@@ -57,8 +59,10 @@
+ /* 4-byte address opcodes - used on Spansion and some Macronix flashes. */
+ #define SPINOR_OP_READ4 0x13 /* Read data bytes (low frequency) */
+ #define SPINOR_OP_READ4_FAST 0x0c /* Read data bytes (high frequency) */
+-#define SPINOR_OP_READ4_1_1_2 0x3c /* Read data bytes (Dual SPI) */
+-#define SPINOR_OP_READ4_1_1_4 0x6c /* Read data bytes (Quad SPI) */
++#define SPINOR_OP_READ4_1_1_2 0x3c /* Read data bytes (Dual Output SPI) */
++#define SPINOR_OP_READ4_1_2_2 0xbc /* Read data bytes (Dual I/O SPI) */
++#define SPINOR_OP_READ4_1_1_4 0x6c /* Read data bytes (Quad Output SPI) */
++#define SPINOR_OP_READ4_1_4_4 0xec /* Read data bytes (Quad I/O SPI) */
+ #define SPINOR_OP_PP_4B 0x12 /* Page program (up to 256 bytes) */
+ #define SPINOR_OP_SE_4B 0xdc /* Sector erase (usually 64KiB) */
+
+--
+2.8.1
+
diff --git a/target/linux/socfpga/patches-4.4/0019-mtd-spi-nor-fix-support-of-Macronix-memories.patch b/target/linux/socfpga/patches-4.4/0019-mtd-spi-nor-fix-support-of-Macronix-memories.patch
new file mode 100644
index 0000000..087b671
--- /dev/null
+++ b/target/linux/socfpga/patches-4.4/0019-mtd-spi-nor-fix-support-of-Macronix-memories.patch
@@ -0,0 +1,139 @@
+From 4e094634d1995e279f8bc5eb92463295cb894c76 Mon Sep 17 00:00:00 2001
+From: Cyrille Pitchen <cyrille.pitchen at atmel.com>
+Date: Fri, 8 Jan 2016 17:02:16 +0100
+Subject: [PATCH 19/33] mtd: spi-nor: fix support of Macronix memories
+
+This patch fixes the support of Macronix memories. Especially we avoid
+updating the Status Register when not needed as the Quad Enable (QE) bit
+is a non-volatile bit.
+
+Also we add comments to explain why we use some Fast Read op codes rather
+than others.
+
+Signed-off-by: Cyrille Pitchen <cyrille.pitchen at atmel.com>
+---
+ drivers/mtd/spi-nor/spi-nor.c | 81 ++++++++++++++++++++++++++++++++++++++-----
+ 1 file changed, 72 insertions(+), 9 deletions(-)
+
+diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
+index 889af12..1b1f5a6 100644
+--- a/drivers/mtd/spi-nor/spi-nor.c
++++ b/drivers/mtd/spi-nor/spi-nor.c
+@@ -1107,6 +1107,11 @@ static int macronix_quad_enable(struct spi_nor *nor)
+ val = read_sr(nor);
+ if (val < 0)
+ return val;
++
++ if (likely(val & SR_QUAD_EN_MX))
++ return 0;
++ dev_warn(nor->dev, "Macronix Quad mode disabled, enable it\n");
++
+ write_enable(nor);
+
+ write_sr(nor, val | SR_QUAD_EN_MX);
+@@ -1161,21 +1166,73 @@ static int spansion_quad_enable(struct spi_nor *nor)
+ return 0;
+ }
+
++static int macronix_set_quad_mode(struct spi_nor *nor)
++{
++ int status;
++
++ /* Check whether the QPI mode is enabled. */
++ if (nor->read_proto == SNOR_PROTO_4_4_4) {
++ /*
++ * Since the QPI mode is enabled, the Quad Enabled (QE)
++ * non-volatile bit is already set.
++ * However in QPI mode, only the Fast Read 1-4-4 (0xeb)
++ * op code is supported.
++ * WARNING: we should take care about the performance
++ * enhance toggling bits P0-P7 written during the
++ * dummy/mode cycles to avoid entering the continuous
++ * read (performance enhance) mode by mistake!
++ */
++ nor->read_opcode = SPINOR_OP_READ_1_4_4;
++ return 0;
++ }
++
++ /*
++ * The QPI mode is disabled but we still need to set the QE bit:
++ * this disables the reset and write protect features and
++ * frees the associated pins so they can be used as the 3rd
++ * and 4th I/O lines required by Quad SPI commands.
++ * Also we'd rather use the Fast Read 1-1-4 (0x6b) op code than
++ * the Fast Read 1-4-4 (0xeb) op code so we don't care about
++ * entering the continuous read mode by mistake if some
++ * performance enhance toggling bits P0-P7 were written during
++ * dummy/mode cycles.
++ */
++ status = macronix_quad_enable(nor);
++ if (status) {
++ dev_err(nor->dev, "Macronix quad-read not enabled\n");
++ return status;
++ }
++ nor->read_proto = SNOR_PROTO_1_1_4;
++ nor->read_opcode = SPINOR_OP_READ_1_1_4;
++ return 0;
++}
++
++/*
++ * For both Macronix Dual and Single modes, we don't care about the value of
++ * the Quad Enabled (QE) bit since the memory still replies to Dual or Single
++ * SPI commands.
++ */
++
++static int macronix_set_dual_mode(struct spi_nor *nor)
++{
++ nor->read_proto = SNOR_PROTO_1_1_2;
++ nor->read_opcode = SPINOR_OP_READ_1_1_2;
++ return 0;
++}
++
++static int macronix_set_single_mode(struct spi_nor *nor)
++{
++ nor->read_proto = SNOR_PROTO_1_1_1;
++ return 0;
++}
++
+ static int set_quad_mode(struct spi_nor *nor, const struct flash_info *info)
+ {
+ int status;
+
+ switch (JEDEC_MFR(info)) {
+ case SNOR_MFR_MACRONIX:
+- status = macronix_quad_enable(nor);
+- if (status) {
+- dev_err(nor->dev, "Macronix quad-read not enabled\n");
+- return -EINVAL;
+- }
+- /* Check whether Macronix QPI mode is enabled. */
+- if (nor->read_proto != SNOR_PROTO_4_4_4)
+- nor->read_proto = SNOR_PROTO_1_1_4;
+- break;
++ return macronix_set_quad_mode(nor);
+
+ case SNOR_MFR_MICRON:
+ /* Check whether Micron Quad mode is enabled. */
+@@ -1203,6 +1260,9 @@ static int set_quad_mode(struct spi_nor *nor, const struct flash_info *info)
+ static int set_dual_mode(struct spi_nor *nor, const struct flash_info *info)
+ {
+ switch (JEDEC_MFR(info)) {
++ case SNOR_MFR_MACRONIX:
++ return macronix_set_dual_mode(nor);
++
+ case SNOR_MFR_MICRON:
+ /* Check whether Micron Dual mode is enabled. */
+ if (nor->read_proto != SNOR_PROTO_2_2_2)
+@@ -1221,6 +1281,9 @@ static int set_dual_mode(struct spi_nor *nor, const struct flash_info *info)
+ static int set_single_mode(struct spi_nor *nor, const struct flash_info *info)
+ {
+ switch (JEDEC_MFR(info)) {
++ case SNOR_MFR_MACRONIX:
++ return macronix_set_single_mode(nor);
++
+ default:
+ nor->read_proto = SNOR_PROTO_1_1_1;
+ break;
+--
+2.8.1
+
diff --git a/target/linux/socfpga/patches-4.4/0020-mtd-spi-nor-fix-support-of-Winbond-memories.patch b/target/linux/socfpga/patches-4.4/0020-mtd-spi-nor-fix-support-of-Winbond-memories.patch
new file mode 100644
index 0000000..e41fd3f
--- /dev/null
+++ b/target/linux/socfpga/patches-4.4/0020-mtd-spi-nor-fix-support-of-Winbond-memories.patch
@@ -0,0 +1,179 @@
+From 96b232d03a0c4462eacf879ed80b0cfd235e65c4 Mon Sep 17 00:00:00 2001
+From: Cyrille Pitchen <cyrille.pitchen at atmel.com>
+Date: Fri, 8 Jan 2016 17:02:17 +0100
+Subject: [PATCH 20/33] mtd: spi-nor: fix support of Winbond memories
+
+This patch fixes the support of Winbond memories. Indeed, before
+performing any Quad SPI command, the Quad Enable (QE) non-volatile bit
+MUST be set in the Status Register 2.
+
+According to the w25q16fw datasheet from Winbond:
+"When QE=1, the /WP pin becomes IO2 and /HOLD pin becomes IO3."
+
+Quad SPI instructions requires the bidirectional IO2 and IO3 pins.
+
+Signed-off-by: Cyrille Pitchen <cyrille.pitchen at atmel.com>
+---
+ drivers/mtd/spi-nor/spi-nor.c | 100 ++++++++++++++++++++++++++++++++++++++++++
+ include/linux/mtd/spi-nor.h | 6 +++
+ 2 files changed, 106 insertions(+)
+
+diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
+index 1b1f5a6..aa7d26d 100644
+--- a/drivers/mtd/spi-nor/spi-nor.c
++++ b/drivers/mtd/spi-nor/spi-nor.c
+@@ -1166,6 +1166,40 @@ static int spansion_quad_enable(struct spi_nor *nor)
+ return 0;
+ }
+
++static int winbond_quad_enable(struct spi_nor *nor)
++{
++ int ret;
++ u8 sr2;
++
++ ret = nor->read_reg(nor, SPINOR_OP_RDSR2_WINB, &sr2, 1);
++ if (ret < 0)
++ return ret;
++
++ if (likely(sr2 & SR2_QUAD_EN_WINB))
++ return 0;
++ dev_warn(nor->dev, "Winbond Quad mode disabled, enable it\n");
++
++ write_enable(nor);
++
++ sr2 |= SR2_QUAD_EN_WINB;
++ ret = nor->write_reg(nor, SPINOR_OP_WRSR2_WINB, &sr2, 1);
++ if (ret < 0)
++ return ret;
++
++ if (spi_nor_wait_till_ready(nor))
++ return -EIO;
++
++ ret = nor->read_reg(nor, SPINOR_OP_RDSR2_WINB, &sr2, 1);
++ if (ret < 0)
++ return ret;
++ if (!(sr2 & SR2_QUAD_EN_WINB)) {
++ dev_err(nor->dev, "Winbond Quad bit not set\n");
++ return -EINVAL;
++ }
++
++ return 0;
++}
++
+ static int macronix_set_quad_mode(struct spi_nor *nor)
+ {
+ int status;
+@@ -1226,6 +1260,63 @@ static int macronix_set_single_mode(struct spi_nor *nor)
+ return 0;
+ }
+
++static int winbond_set_quad_mode(struct spi_nor *nor)
++{
++ int status;
++
++ /* Check whether the QPI mode is enabled. */
++ if (nor->read_proto == SNOR_PROTO_4_4_4) {
++ /* Since the QPI mode is enabled, the Quad Enabled (QE)
++ * non-volatile bit is already set.
++ * If the Fast Read 1-4-4 (0xeb) were used, we should
++ * take care about the value M7-M0 written during
++ * dummy/mode cycles to avoid entering the continuous
++ * read mode by mistake.
++ * Also the Fast Read 1-1-4 (0x6b) op code is not
++ * supported in QPI mode.
++ * Hence the Fast Read 1-1-1 (0x0b) op code is chosen.
++ */
++ nor->read_opcode = SPINOR_OP_READ_FAST;
++ return 0;
++ }
++
++ /*
++ * The QPI mode is disabled but we still need to set the QE bit:
++ * when QE=1, the /WP pin becomes IO2 and /HOLD pin becomes IO3.
++ * If the Fast Read 1-4-4 (0xeb) were used, we should take care
++ * about the value M7-M0 written during dummy/mode cycles to
++ * avoid entering the continuous read mode by mistake.
++ * Hence the Fast Read 1-1-4 (0x6b) op code is preferred.
++ */
++ status = winbond_quad_enable(nor);
++ if (status) {
++ dev_err(nor->dev, "Winbond quad-read nor enabled\n");
++ return status;
++ }
++ nor->read_proto = SNOR_PROTO_1_1_4;
++ nor->read_opcode = SPINOR_OP_READ_1_1_4;
++ return 0;
++}
++
++/*
++ * For both Winbond Dual and Single modes, we don't care about the value of
++ * the Quad Enabled (QE) bit since the memory still replies to Dual or Single
++ * SPI commands.
++ */
++
++static int winbond_set_dual_mode(struct spi_nor *nor)
++{
++ nor->read_proto = SNOR_PROTO_1_1_2;
++ nor->read_opcode = SPINOR_OP_READ_1_1_2;
++ return 0;
++}
++
++static int winbond_set_single_mode(struct spi_nor *nor)
++{
++ nor->read_proto = SNOR_PROTO_1_1_1;
++ return 0;
++}
++
+ static int set_quad_mode(struct spi_nor *nor, const struct flash_info *info)
+ {
+ int status;
+@@ -1234,6 +1325,9 @@ static int set_quad_mode(struct spi_nor *nor, const struct flash_info *info)
+ case SNOR_MFR_MACRONIX:
+ return macronix_set_quad_mode(nor);
+
++ case SNOR_MFR_WINBOND:
++ return winbond_set_quad_mode(nor);
++
+ case SNOR_MFR_MICRON:
+ /* Check whether Micron Quad mode is enabled. */
+ if (nor->read_proto != SNOR_PROTO_4_4_4)
+@@ -1263,6 +1357,9 @@ static int set_dual_mode(struct spi_nor *nor, const struct flash_info *info)
+ case SNOR_MFR_MACRONIX:
+ return macronix_set_dual_mode(nor);
+
++ case SNOR_MFR_WINBOND:
++ return winbond_set_dual_mode(nor);
++
+ case SNOR_MFR_MICRON:
+ /* Check whether Micron Dual mode is enabled. */
+ if (nor->read_proto != SNOR_PROTO_2_2_2)
+@@ -1284,6 +1381,9 @@ static int set_single_mode(struct spi_nor *nor, const struct flash_info *info)
+ case SNOR_MFR_MACRONIX:
+ return macronix_set_single_mode(nor);
+
++ case SNOR_MFR_WINBOND:
++ return winbond_set_single_mode(nor);
++
+ default:
+ nor->read_proto = SNOR_PROTO_1_1_1;
+ break;
+diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
+index 89e3228..46343f5 100644
+--- a/include/linux/mtd/spi-nor.h
++++ b/include/linux/mtd/spi-nor.h
+@@ -75,6 +75,12 @@
+ #define SPINOR_OP_EN4B 0xb7 /* Enter 4-byte mode */
+ #define SPINOR_OP_EX4B 0xe9 /* Exit 4-byte mode */
+
++/* Used for Winbond flashes only. */
++#define SPINOR_OP_RDSR2_WINB 0x35 /* Read status register 2 */
++#define SPINOR_OP_WRSR2_WINB 0x31 /* Write status register 2 */
++
++#define SR2_QUAD_EN_WINB BIT(1) /* Quad Enable bit */
++
+ /* Used for Spansion flashes only. */
+ #define SPINOR_OP_BRWR 0x17 /* Bank register write */
+
+--
+2.8.1
+
diff --git a/target/linux/socfpga/patches-4.4/0021-mtd-spi-nor-fix-support-of-Micron-memories.patch b/target/linux/socfpga/patches-4.4/0021-mtd-spi-nor-fix-support-of-Micron-memories.patch
new file mode 100644
index 0000000..83d79ab
--- /dev/null
+++ b/target/linux/socfpga/patches-4.4/0021-mtd-spi-nor-fix-support-of-Micron-memories.patch
@@ -0,0 +1,224 @@
+From 0cd0df6b3583920ab9231035e533560b58e71a50 Mon Sep 17 00:00:00 2001
+From: Cyrille Pitchen <cyrille.pitchen at atmel.com>
+Date: Fri, 8 Jan 2016 17:02:18 +0100
+Subject: [PATCH 21/33] mtd: spi-nor: fix support of Micron memories
+
+This patch adds missing mode transitions. Indeed depending on both the
+current memory mode and the new protocol wanted by the user, we may need
+to perform a switch back to the Extended SPI mode.
+
+However when the current mode is the Quad mode and the user has asked for
+a Quad SPI protocol, we'd rather stay in Quad mode and use the Fast Read
+4-4-4 command than switch to the Extended SPI mode and use the Fast Read
+1-1-4 command.
+
+Also we'd rather stay in Dual mode than swith to the Extended SPI mode
+whenever the user has asked for Dual SPI protocol.
+
+Signed-off-by: Cyrille Pitchen <cyrille.pitchen at atmel.com>
+---
+ drivers/mtd/spi-nor/spi-nor.c | 154 +++++++++++++++++++++++++++++++++++++++---
+ include/linux/mtd/spi-nor.h | 1 +
+ 2 files changed, 147 insertions(+), 8 deletions(-)
+
+diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
+index aa7d26d..ae2cbac 100644
+--- a/drivers/mtd/spi-nor/spi-nor.c
++++ b/drivers/mtd/spi-nor/spi-nor.c
+@@ -1317,6 +1317,147 @@ static int winbond_set_single_mode(struct spi_nor *nor)
+ return 0;
+ }
+
++static int micron_set_protocol(struct spi_nor *nor, u8 mask, u8 val,
++ enum spi_nor_protocol proto)
++{
++ u8 evcr;
++ int ret;
++
++ /* Read the Enhanced Volatile Configuration Register (EVCR). */
++ ret = nor->read_reg(nor, SPINOR_OP_RD_EVCR, &evcr, 1);
++ if (ret < 0) {
++ dev_err(nor->dev, "error while reading EVCR register\n");
++ return ret;
++ }
++
++ /* Check whether we need to update the protocol bits. */
++ if ((evcr & mask) == val)
++ return 0;
++
++ /* Set EVCR protocol bits. */
++ write_enable(nor);
++ evcr = (evcr & ~mask) | val;
++ ret = nor->write_reg(nor, SPINOR_OP_WD_EVCR, &evcr, 1);
++ if (ret < 0) {
++ dev_err(nor->dev, "error while writing EVCR register\n");
++ return ret;
++ }
++
++ /* Switch reg protocol now before accessing any other registers. */
++ nor->reg_proto = proto;
++
++ ret = spi_nor_wait_till_ready(nor);
++ if (ret)
++ return ret;
++
++ /* Read EVCR and check it. */
++ ret = nor->read_reg(nor, SPINOR_OP_RD_EVCR, &evcr, 1);
++ if (ret < 0 || (evcr & mask) != val) {
++ dev_err(nor->dev, "Micron EVCR protocol bits not updated\n");
++ return -EINVAL;
++ }
++
++ return 0;
++}
++
++static int micron_set_extended_spi_protocol(struct spi_nor *nor)
++{
++ int ret;
++
++ /* Set Quad/Dual bits to 11 to select the Extended SPI mode */
++ ret = micron_set_protocol(nor,
++ EVCR_QUAD_EN_MICRON | EVCR_DUAL_EN_MICRON,
++ EVCR_QUAD_EN_MICRON | EVCR_DUAL_EN_MICRON,
++ SNOR_PROTO_1_1_1);
++ if (ret) {
++ dev_err(nor->dev, "Failed to set Micron Extended SPI mode\n");
++ return ret;
++ }
++
++ nor->write_proto = SNOR_PROTO_1_1_1;
++ nor->erase_proto = SNOR_PROTO_1_1_1;
++ return 0;
++}
++
++static int micron_set_quad_mode(struct spi_nor *nor)
++{
++ /* Check whether the Dual SPI mode is enabled. */
++ if (unlikely(nor->read_proto == SNOR_PROTO_2_2_2)) {
++ int ret;
++
++ /*
++ * Exit Micron Dual mode and switch to the Extended SPI mode:
++ * we can change the mode safely as we write into a volatile
++ * register.
++ * Also the Quad mode is not worth it for MTD usages: it
++ * should only be relevant for eXecution In Place (XIP) usages,
++ * which are out of the scope of the spi-nor framework.
++ */
++ ret = micron_set_extended_spi_protocol(nor);
++ if (ret)
++ return ret;
++ }
++
++ /*
++ * Whatever the Quad mode is enabled or not, the
++ * Fast Read Quad Output 1-1-4 (0x6b) op code is supported.
++ */
++ if (nor->read_proto != SNOR_PROTO_4_4_4)
++ nor->read_proto = SNOR_PROTO_1_1_4;
++ nor->read_opcode = SPINOR_OP_READ_1_1_4;
++ return 0;
++}
++
++static int micron_set_dual_mode(struct spi_nor *nor)
++{
++ /* Check whether Quad mode is enabled. */
++ if (unlikely(nor->read_proto == SNOR_PROTO_4_4_4)) {
++ int ret;
++
++ /*
++ * Exit Micron Quad mode and switch to the Extended SPI mode:
++ * we can change the mode safely as we write into a volatile
++ * register.
++ * Also the Dual mode is not worth it for MTD usages: it
++ * should only be relevant for eXecution In Place (XIP) usages,
++ * which are out of the scope of the spi-nor framework.
++ */
++ ret = micron_set_extended_spi_protocol(nor);
++ if (ret)
++ return ret;
++ }
++
++ /*
++ * Whatever the Dual mode is enabled or not, the
++ * Fast Read Dual Output 1-1-2 (0x3b) op code is supported.
++ */
++ if (nor->read_proto != SNOR_PROTO_2_2_2)
++ nor->read_proto = SNOR_PROTO_1_1_2;
++ nor->read_opcode = SPINOR_OP_READ_1_1_2;
++ return 0;
++}
++
++static int micron_set_single_mode(struct spi_nor *nor)
++{
++ /* Check whether either the Dual or Quad mode is enabled. */
++ if (unlikely(nor->read_proto != SNOR_PROTO_1_1_1)) {
++ int ret;
++
++ /*
++ * Exit Micron Dual or Quad mode and switch to the Extended SPI
++ * mode: we can change the mode safely as we write into a
++ * volatile register.
++ */
++ ret = micron_set_extended_spi_protocol(nor);
++ if (ret)
++ return ret;
++
++ nor->read_proto = SNOR_PROTO_1_1_1;
++ }
++
++ return 0;
++}
++
+ static int set_quad_mode(struct spi_nor *nor, const struct flash_info *info)
+ {
+ int status;
+@@ -1329,10 +1470,7 @@ static int set_quad_mode(struct spi_nor *nor, const struct flash_info *info)
+ return winbond_set_quad_mode(nor);
+
+ case SNOR_MFR_MICRON:
+- /* Check whether Micron Quad mode is enabled. */
+- if (nor->read_proto != SNOR_PROTO_4_4_4)
+- nor->read_proto = SNOR_PROTO_1_1_4;
+- break;
++ return micron_set_quad_mode(nor);
+
+ case SNOR_MFR_SPANSION:
+ status = spansion_quad_enable(nor);
+@@ -1361,10 +1499,7 @@ static int set_dual_mode(struct spi_nor *nor, const struct flash_info *info)
+ return winbond_set_dual_mode(nor);
+
+ case SNOR_MFR_MICRON:
+- /* Check whether Micron Dual mode is enabled. */
+- if (nor->read_proto != SNOR_PROTO_2_2_2)
+- nor->read_proto = SNOR_PROTO_1_1_2;
+- break;
++ return micron_set_dual_mode(nor);
+
+ default:
+ nor->read_proto = SNOR_PROTO_1_1_2;
+@@ -1384,6 +1519,9 @@ static int set_single_mode(struct spi_nor *nor, const struct flash_info *info)
+ case SNOR_MFR_WINBOND:
+ return winbond_set_single_mode(nor);
+
++ case SNOR_MFR_MICRON:
++ return micron_set_single_mode(nor);
++
+ default:
+ nor->read_proto = SNOR_PROTO_1_1_1;
+ break;
+diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
+index 46343f5..d0a6f34 100644
+--- a/include/linux/mtd/spi-nor.h
++++ b/include/linux/mtd/spi-nor.h
+@@ -102,6 +102,7 @@
+
+ /* Enhanced Volatile Configuration Register bits */
+ #define EVCR_QUAD_EN_MICRON BIT(7) /* Micron Quad I/O */
++#define EVCR_DUAL_EN_MICRON BIT(6) /* Micron Dual I/O */
+
+ /* Flag Status Register bits */
+ #define FSR_READY BIT(7)
+--
+2.8.1
+
diff --git a/target/linux/socfpga/patches-4.4/0022-mtd-spi-nor-fix-support-of-Spansion-memories.patch b/target/linux/socfpga/patches-4.4/0022-mtd-spi-nor-fix-support-of-Spansion-memories.patch
new file mode 100644
index 0000000..a7a8f4b
--- /dev/null
+++ b/target/linux/socfpga/patches-4.4/0022-mtd-spi-nor-fix-support-of-Spansion-memories.patch
@@ -0,0 +1,116 @@
+From 4774693a681539f1e890164acc2d99fede2aa35e Mon Sep 17 00:00:00 2001
+From: Cyrille Pitchen <cyrille.pitchen at atmel.com>
+Date: Fri, 8 Jan 2016 17:02:19 +0100
+Subject: [PATCH 22/33] mtd: spi-nor: fix support of Spansion memories
+
+This patch is only a transitional one. It concludes the series of patches
+to select op codes and protocols by manufacturer.
+
+Signed-off-by: Cyrille Pitchen <cyrille.pitchen at atmel.com>
+---
+ drivers/mtd/spi-nor/spi-nor.c | 53 ++++++++++++++++++++++++++++++-------------
+ 1 file changed, 37 insertions(+), 16 deletions(-)
+
+diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
+index ae2cbac..8a042ab 100644
+--- a/drivers/mtd/spi-nor/spi-nor.c
++++ b/drivers/mtd/spi-nor/spi-nor.c
+@@ -1458,10 +1458,35 @@ static int micron_set_single_mode(struct spi_nor *nor)
+ return 0;
+ }
+
+-static int set_quad_mode(struct spi_nor *nor, const struct flash_info *info)
++static int spansion_set_quad_mode(struct spi_nor *nor)
+ {
+ int status;
+
++ status = spansion_quad_enable(nor);
++ if (status) {
++ dev_err(nor->dev, "Spansion quad-read not enabled\n");
++ return -EINVAL;
++ }
++ nor->read_proto = SNOR_PROTO_1_1_4;
++ nor->read_opcode = SPINOR_OP_READ_1_1_4;
++ return 0;
++}
++
++static int spansion_set_dual_mode(struct spi_nor *nor)
++{
++ nor->read_proto = SNOR_PROTO_1_1_2;
++ nor->read_opcode = SPINOR_OP_READ_1_1_2;
++ return 0;
++}
++
++static int spansion_set_single_mode(struct spi_nor *nor)
++{
++ nor->read_proto = SNOR_PROTO_1_1_1;
++ return 0;
++}
++
++static int set_quad_mode(struct spi_nor *nor, const struct flash_info *info)
++{
+ switch (JEDEC_MFR(info)) {
+ case SNOR_MFR_MACRONIX:
+ return macronix_set_quad_mode(nor);
+@@ -1473,20 +1498,13 @@ static int set_quad_mode(struct spi_nor *nor, const struct flash_info *info)
+ return micron_set_quad_mode(nor);
+
+ case SNOR_MFR_SPANSION:
+- status = spansion_quad_enable(nor);
+- if (status) {
+- dev_err(nor->dev, "Spansion quad-read not enabled\n");
+- return -EINVAL;
+- }
+- nor->read_proto = SNOR_PROTO_1_1_4;
+- break;
++ return spansion_set_quad_mode(nor);
+
+ default:
+- return -EINVAL;
++ break;
+ }
+
+- nor->read_opcode = SPINOR_OP_READ_1_1_4;
+- return 0;
++ return -EINVAL;
+ }
+
+ static int set_dual_mode(struct spi_nor *nor, const struct flash_info *info)
+@@ -1501,13 +1519,14 @@ static int set_dual_mode(struct spi_nor *nor, const struct flash_info *info)
+ case SNOR_MFR_MICRON:
+ return micron_set_dual_mode(nor);
+
++ case SNOR_MFR_SPANSION:
++ return spansion_set_dual_mode(nor);
++
+ default:
+- nor->read_proto = SNOR_PROTO_1_1_2;
+ break;
+ }
+
+- nor->read_opcode = SPINOR_OP_READ_1_1_2;
+- return 0;
++ return -EINVAL;
+ }
+
+ static int set_single_mode(struct spi_nor *nor, const struct flash_info *info)
+@@ -1522,12 +1541,14 @@ static int set_single_mode(struct spi_nor *nor, const struct flash_info *info)
+ case SNOR_MFR_MICRON:
+ return micron_set_single_mode(nor);
+
++ case SNOR_MFR_SPANSION:
++ return spansion_set_single_mode(nor);
++
+ default:
+- nor->read_proto = SNOR_PROTO_1_1_1;
+ break;
+ }
+
+- return 0;
++ return -EINVAL;
+ }
+
+ static int spi_nor_check(struct spi_nor *nor)
+--
+2.8.1
+
diff --git a/target/linux/socfpga/patches-4.4/0023-mtd-spi-nor-configure-the-number-of-dummy-clock-cycl.patch b/target/linux/socfpga/patches-4.4/0023-mtd-spi-nor-configure-the-number-of-dummy-clock-cycl.patch
new file mode 100644
index 0000000..7153a9f
--- /dev/null
+++ b/target/linux/socfpga/patches-4.4/0023-mtd-spi-nor-configure-the-number-of-dummy-clock-cycl.patch
@@ -0,0 +1,264 @@
+From 16410a33d6655d6c85c8c522bc6f2cfebf7c06a4 Mon Sep 17 00:00:00 2001
+From: Cyrille Pitchen <cyrille.pitchen at atmel.com>
+Date: Fri, 8 Jan 2016 17:02:20 +0100
+Subject: [PATCH 23/33] mtd: spi-nor: configure the number of dummy clock
+ cycles by manufacturer
+
+This is a transitional patch which let us set the number of dummy clock
+cycles by manufacturer.
+
+More patches will follow by manufacturer to actually configure the
+relevant number of dummy clock cycles following the dedicated procedure.
+
+For instance, some manufacturers like Spansion configure the number of
+dummy clock cycles to be used by Fast Read command through some
+non-volatile register. In such a case, we should avoid updating its value
+but instead read it then set the nor->read_dummy accordingly.
+
+On the other hand, some manufacturers like Micron use some volatile
+register. In this case, we'd rather update this register to use a number
+of dummy clock cycles, which is a multiple of 8.
+Indeed some drivers, like m25p80, only support writing bytes, hence
+multiples of 8 bits.
+
+Signed-off-by: Cyrille Pitchen <cyrille.pitchen at atmel.com>
+---
+ drivers/mtd/spi-nor/spi-nor.c | 99 ++++++++++++++++++++++++++++++++-----------
+ 1 file changed, 74 insertions(+), 25 deletions(-)
+
+diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
+index 8a042ab..ae3e9d8 100644
+--- a/drivers/mtd/spi-nor/spi-nor.c
++++ b/drivers/mtd/spi-nor/spi-nor.c
+@@ -139,24 +139,6 @@ static int read_cr(struct spi_nor *nor)
+ }
+
+ /*
+- * Dummy Cycle calculation for different type of read.
+- * It can be used to support more commands with
+- * different dummy cycle requirements.
+- */
+-static inline int spi_nor_read_dummy_cycles(struct spi_nor *nor)
+-{
+- switch (nor->flash_read) {
+- case SPI_NOR_FAST:
+- case SPI_NOR_DUAL:
+- case SPI_NOR_QUAD:
+- return 8;
+- case SPI_NOR_NORMAL:
+- return 0;
+- }
+- return 0;
+-}
+-
+-/*
+ * Write status register 1 byte
+ * Returns negative if error occurred.
+ */
+@@ -1217,6 +1199,7 @@ static int macronix_set_quad_mode(struct spi_nor *nor)
+ * read (performance enhance) mode by mistake!
+ */
+ nor->read_opcode = SPINOR_OP_READ_1_4_4;
++ nor->read_dummy = 8;
+ return 0;
+ }
+
+@@ -1238,6 +1221,7 @@ static int macronix_set_quad_mode(struct spi_nor *nor)
+ }
+ nor->read_proto = SNOR_PROTO_1_1_4;
+ nor->read_opcode = SPINOR_OP_READ_1_1_4;
++ nor->read_dummy = 8;
+ return 0;
+ }
+
+@@ -1251,12 +1235,27 @@ static int macronix_set_dual_mode(struct spi_nor *nor)
+ {
+ nor->read_proto = SNOR_PROTO_1_1_2;
+ nor->read_opcode = SPINOR_OP_READ_1_1_2;
++ nor->read_dummy = 8;
+ return 0;
+ }
+
+ static int macronix_set_single_mode(struct spi_nor *nor)
+ {
++ u8 read_dummy;
++
++ switch (nor->read_opcode) {
++ case SPINOR_OP_READ:
++ case SPINOR_OP_READ4:
++ read_dummy = 0;
++ break;
++
++ default:
++ read_dummy = 8;
++ break;
++ }
++
+ nor->read_proto = SNOR_PROTO_1_1_1;
++ nor->read_dummy = read_dummy;
+ return 0;
+ }
+
+@@ -1277,6 +1276,7 @@ static int winbond_set_quad_mode(struct spi_nor *nor)
+ * Hence the Fast Read 1-1-1 (0x0b) op code is chosen.
+ */
+ nor->read_opcode = SPINOR_OP_READ_FAST;
++ nor->read_dummy = 8;
+ return 0;
+ }
+
+@@ -1295,6 +1295,7 @@ static int winbond_set_quad_mode(struct spi_nor *nor)
+ }
+ nor->read_proto = SNOR_PROTO_1_1_4;
+ nor->read_opcode = SPINOR_OP_READ_1_1_4;
++ nor->read_dummy = 8;
+ return 0;
+ }
+
+@@ -1308,12 +1309,27 @@ static int winbond_set_dual_mode(struct spi_nor *nor)
+ {
+ nor->read_proto = SNOR_PROTO_1_1_2;
+ nor->read_opcode = SPINOR_OP_READ_1_1_2;
++ nor->read_dummy = 8;
+ return 0;
+ }
+
+ static int winbond_set_single_mode(struct spi_nor *nor)
+ {
++ u8 read_dummy;
++
++ switch (nor->read_opcode) {
++ case SPINOR_OP_READ:
++ case SPINOR_OP_READ4:
++ read_dummy = 0;
++ break;
++
++ default:
++ read_dummy = 8;
++ break;
++ }
++
+ nor->read_proto = SNOR_PROTO_1_1_1;
++ nor->read_dummy = read_dummy;
+ return 0;
+ }
+
+@@ -1405,6 +1421,7 @@ static int micron_set_quad_mode(struct spi_nor *nor)
+ if (nor->read_proto != SNOR_PROTO_4_4_4)
+ nor->read_proto = SNOR_PROTO_1_1_4;
+ nor->read_opcode = SPINOR_OP_READ_1_1_4;
++ nor->read_dummy = 8;
+ return 0;
+ }
+
+@@ -1434,11 +1451,14 @@ static int micron_set_dual_mode(struct spi_nor *nor)
+ if (nor->read_proto != SNOR_PROTO_2_2_2)
+ nor->read_proto = SNOR_PROTO_1_1_2;
+ nor->read_opcode = SPINOR_OP_READ_1_1_2;
++ nor->read_dummy = 8;
+ return 0;
+ }
+
+ static int micron_set_single_mode(struct spi_nor *nor)
+ {
++ u8 read_dummy;
++
+ /* Check whether either the Dual or Quad mode is enabled. */
+ if (unlikely(nor->read_proto != SNOR_PROTO_1_1_1)) {
+ int ret;
+@@ -1455,6 +1475,18 @@ static int micron_set_single_mode(struct spi_nor *nor)
+ nor->read_proto = SNOR_PROTO_1_1_1;
+ }
+
++ /* Force the number of dummy cycles to 8 for Fast Read, 0 for Read. */
++ switch (nor->read_opcode) {
++ case SPINOR_OP_READ:
++ case SPINOR_OP_READ4:
++ read_dummy = 0;
++ break;
++
++ default:
++ read_dummy = 8;
++ break;
++ }
++ nor->read_dummy = read_dummy;
+ return 0;
+ }
+
+@@ -1469,6 +1501,7 @@ static int spansion_set_quad_mode(struct spi_nor *nor)
+ }
+ nor->read_proto = SNOR_PROTO_1_1_4;
+ nor->read_opcode = SPINOR_OP_READ_1_1_4;
++ nor->read_dummy = 8;
+ return 0;
+ }
+
+@@ -1476,12 +1509,27 @@ static int spansion_set_dual_mode(struct spi_nor *nor)
+ {
+ nor->read_proto = SNOR_PROTO_1_1_2;
+ nor->read_opcode = SPINOR_OP_READ_1_1_2;
++ nor->read_dummy = 8;
+ return 0;
+ }
+
+ static int spansion_set_single_mode(struct spi_nor *nor)
+ {
++ u8 read_dummy;
++
++ switch (nor->read_opcode) {
++ case SPINOR_OP_READ:
++ case SPINOR_OP_READ4:
++ read_dummy = 0;
++ break;
++
++ default:
++ read_dummy = 8;
++ break;
++ }
++
+ nor->read_proto = SNOR_PROTO_1_1_1;
++ nor->read_dummy = read_dummy;
+ return 0;
+ }
+
+@@ -1696,11 +1744,14 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
+ if (info->flags & SPI_NOR_NO_FR)
+ nor->flash_read = SPI_NOR_NORMAL;
+
+- /* Default commands */
+- if (nor->flash_read == SPI_NOR_NORMAL)
++ /* Default commands and number of dummy cycles */
++ if (nor->flash_read == SPI_NOR_NORMAL) {
+ nor->read_opcode = SPINOR_OP_READ;
+- else
++ nor->read_dummy = 0;
++ } else {
+ nor->read_opcode = SPINOR_OP_READ_FAST;
++ nor->read_dummy = 8;
++ }
+
+ nor->program_opcode = SPINOR_OP_PP;
+
+@@ -1715,8 +1766,8 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
+ * - SNOR_PROTO_2_2_2 is either:
+ * + Micron Dual mode enabled
+ *
+- * The opcodes and the protocols are updated depending on the
+- * manufacturer.
++ * The opcodes, the protocols and the number of dummy cycles are updated
++ * depending on the manufacturer.
+ * The read opcode and protocol should be updated by the relevant
+ * function when entering Quad or Dual mode.
+ */
+@@ -1780,8 +1831,6 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
+ return -EINVAL;
+ }
+
+- nor->read_dummy = spi_nor_read_dummy_cycles(nor);
+-
+ dev_info(dev, "%s (%lld Kbytes)\n", info->name,
+ (long long)mtd->size >> 10);
+
+--
+2.8.1
+
diff --git a/target/linux/socfpga/patches-4.4/0024-mtd-spi-nor-configure-the-number-of-dummy-clock-cycl.patch b/target/linux/socfpga/patches-4.4/0024-mtd-spi-nor-configure-the-number-of-dummy-clock-cycl.patch
new file mode 100644
index 0000000..c6bf870
--- /dev/null
+++ b/target/linux/socfpga/patches-4.4/0024-mtd-spi-nor-configure-the-number-of-dummy-clock-cycl.patch
@@ -0,0 +1,159 @@
+From 77fee227b15835d03517dc34675f72e8963ae882 Mon Sep 17 00:00:00 2001
+From: Cyrille Pitchen <cyrille.pitchen at atmel.com>
+Date: Fri, 8 Jan 2016 17:02:21 +0100
+Subject: [PATCH 24/33] mtd: spi-nor: configure the number of dummy clock
+ cycles on Micron memories
+
+The spi-nor framework currently expects all Fast Read operations to use 8
+dummy clock cycles. Especially some drivers like m25p80 can only support
+multiple of 8 dummy clock cycles.
+
+On Micron memories, the number of dummy clock cycles to be used by Fast
+Read commands can be safely set to 8 by updating the Volatile
+Configuration Register (VCR).
+
+Also the XIP bit is set at the same time when updating the VCR so the
+Continuous Read mode is disabled: this prevents us from entering it by
+mistake.
+
+Signed-off-by: Cyrille Pitchen <cyrille.pitchen at atmel.com>
+---
+ drivers/mtd/spi-nor/spi-nor.c | 72 ++++++++++++++++++++++++++++++++++++++-----
+ include/linux/mtd/spi-nor.h | 2 ++
+ 2 files changed, 67 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
+index ae3e9d8..5232984 100644
+--- a/drivers/mtd/spi-nor/spi-nor.c
++++ b/drivers/mtd/spi-nor/spi-nor.c
+@@ -1333,6 +1333,53 @@ static int winbond_set_single_mode(struct spi_nor *nor)
+ return 0;
+ }
+
++static int micron_set_dummy_cycles(struct spi_nor *nor, u8 read_dummy)
++{
++ u8 vcr, val, mask;
++ int ret;
++
++ /* Set bit3 (XIP) to disable the Continuous Read mode */
++ mask = GENMASK(7, 4) | BIT(3);
++ val = ((read_dummy << 4) | BIT(3)) & mask;
++
++ /* Read the Volatile Configuration Register (VCR). */
++ ret = nor->read_reg(nor, SPINOR_OP_RD_VCR, &vcr, 1);
++ if (ret < 0) {
++ dev_err(nor->dev, "error while reading VCR register\n");
++ return ret;
++ }
++
++ /* Check whether we need to update the number of dummy cycles. */
++ if ((vcr & mask) == val) {
++ nor->read_dummy = read_dummy;
++ return 0;
++ }
++
++ /* Update the number of dummy into the VCR. */
++ write_enable(nor);
++ vcr = (vcr & ~mask) | val;
++ ret = nor->write_reg(nor, SPINOR_OP_WR_VCR, &vcr, 1);
++ if (ret < 0) {
++ dev_err(nor->dev, "error while writing VCR register\n");
++ return ret;
++ }
++
++ ret = spi_nor_wait_till_ready(nor);
++ if (ret)
++ return ret;
++
++ /* Read VCR and check it. */
++ ret = nor->read_reg(nor, SPINOR_OP_RD_VCR, &vcr, 1);
++ if (ret < 0 || (vcr & mask) != val) {
++ dev_err(nor->dev, "Micron VCR dummy cycles not updated\n");
++ return -EINVAL;
++ }
++
++ /* Save the number of dummy cycles to use with Fast Read commands */
++ nor->read_dummy = read_dummy;
++ return 0;
++}
++
+ static int micron_set_protocol(struct spi_nor *nor, u8 mask, u8 val,
+ enum spi_nor_protocol proto)
+ {
+@@ -1417,12 +1464,15 @@ static int micron_set_quad_mode(struct spi_nor *nor)
+ /*
+ * Whatever the Quad mode is enabled or not, the
+ * Fast Read Quad Output 1-1-4 (0x6b) op code is supported.
++ * Force the number of dummy cycles to 8 and disable the Continuous Read
++ * mode to prevent some drivers from using it by mistake (m25p80).
++ * We can change these settings safely as we write into a volatile
++ * register.
+ */
+ if (nor->read_proto != SNOR_PROTO_4_4_4)
+ nor->read_proto = SNOR_PROTO_1_1_4;
+ nor->read_opcode = SPINOR_OP_READ_1_1_4;
+- nor->read_dummy = 8;
+- return 0;
++ return micron_set_dummy_cycles(nor, 8);
+ }
+
+ static int micron_set_dual_mode(struct spi_nor *nor)
+@@ -1447,12 +1497,15 @@ static int micron_set_dual_mode(struct spi_nor *nor)
+ /*
+ * Whatever the Dual mode is enabled or not, the
+ * Fast Read Dual Output 1-1-2 (0x3b) op code is supported.
++ * Force the number of dummy cycles to 8 and disable the Continuous Read
++ * mode to prevent some drivers from using it by mistake (m25p80).
++ * We can change these settings safely as we write into a volatile
++ * register.
+ */
+ if (nor->read_proto != SNOR_PROTO_2_2_2)
+ nor->read_proto = SNOR_PROTO_1_1_2;
+ nor->read_opcode = SPINOR_OP_READ_1_1_2;
+- nor->read_dummy = 8;
+- return 0;
++ return micron_set_dummy_cycles(nor, 8);
+ }
+
+ static int micron_set_single_mode(struct spi_nor *nor)
+@@ -1475,7 +1528,13 @@ static int micron_set_single_mode(struct spi_nor *nor)
+ nor->read_proto = SNOR_PROTO_1_1_1;
+ }
+
+- /* Force the number of dummy cycles to 8 for Fast Read, 0 for Read. */
++ /*
++ * Force the number of dummy cycles to 8 for Fast Read, 0 for Read
++ * and disable the Continuous Read mode to prevent some drivers from
++ * using it by mistake (m25p80).
++ * We can change these settings safely as we write into a volatile
++ * register.
++ */
+ switch (nor->read_opcode) {
+ case SPINOR_OP_READ:
+ case SPINOR_OP_READ4:
+@@ -1486,8 +1545,7 @@ static int micron_set_single_mode(struct spi_nor *nor)
+ read_dummy = 8;
+ break;
+ }
+- nor->read_dummy = read_dummy;
+- return 0;
++ return micron_set_dummy_cycles(nor, read_dummy);
+ }
+
+ static int spansion_set_quad_mode(struct spi_nor *nor)
+diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
+index d0a6f34..2dc0f8b 100644
+--- a/include/linux/mtd/spi-nor.h
++++ b/include/linux/mtd/spi-nor.h
+@@ -86,6 +86,8 @@
+
+ /* Used for Micron flashes only. */
+ #define SPINOR_OP_MIO_RDID 0xaf /* Multiple I/O Read JEDEC ID */
++#define SPINOR_OP_RD_VCR 0x85 /* Read VCR register */
++#define SPINOR_OP_WR_VCR 0x81 /* Write VCR register */
+ #define SPINOR_OP_RD_EVCR 0x65 /* Read EVCR register */
+ #define SPINOR_OP_WD_EVCR 0x61 /* Write EVCR register */
+
+--
+2.8.1
+
diff --git a/target/linux/socfpga/patches-4.4/0025-mtd-spi-nor-configure-the-number-of-dummy-clock-cycl.patch b/target/linux/socfpga/patches-4.4/0025-mtd-spi-nor-configure-the-number-of-dummy-clock-cycl.patch
new file mode 100644
index 0000000..a9c3afd
--- /dev/null
+++ b/target/linux/socfpga/patches-4.4/0025-mtd-spi-nor-configure-the-number-of-dummy-clock-cycl.patch
@@ -0,0 +1,237 @@
+From a714a2af12d0de527be168b821373f29f4343cb7 Mon Sep 17 00:00:00 2001
+From: Cyrille Pitchen <cyrille.pitchen at atmel.com>
+Date: Fri, 8 Jan 2016 17:02:22 +0100
+Subject: [PATCH 25/33] mtd: spi-nor: configure the number of dummy clock
+ cycles on Macronix memories
+
+The spi-nor framework currently expects all Fast Read operations to use 8
+dummy clock cycles. Especially some drivers like m25p80 can only support
+multiple of 8 dummy clock cycles.
+
+On Macronix memories, the number of dummy clock cycles to be used by Fast
+Read commands can be safely set to 8 by updating the DC0 and DC1 volatile
+bits inside the Configuration Register.
+
+According to the mx66l1g45g datasheet from Macronix, using 8 dummy clock
+cycles should be enough to set the SPI bus clock frequency up to:
+- 133 MHz for Fast Read 1-1-1, 1-1-2, 1-1-4 and 1-2-2 commands in Single
+ Transfer Rate (STR)
+- 104 MHz for Fast Read 1-4-4 (or 4-4-4 in QPI mode) commands (STR)
+
+Signed-off-by: Cyrille Pitchen <cyrille.pitchen at atmel.com>
+---
+ drivers/mtd/spi-nor/spi-nor.c | 155 +++++++++++++++++++++++++++++++++++++++---
+ 1 file changed, 147 insertions(+), 8 deletions(-)
+
+diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
+index 5232984..55a1d74 100644
+--- a/drivers/mtd/spi-nor/spi-nor.c
++++ b/drivers/mtd/spi-nor/spi-nor.c
+@@ -1182,6 +1182,136 @@ static int winbond_quad_enable(struct spi_nor *nor)
+ return 0;
+ }
+
++static int macronix_dummy2code(u8 read_opcode, u8 read_dummy, u8 *dc)
++{
++ switch (read_opcode) {
++ case SPINOR_OP_READ:
++ case SPINOR_OP_READ4:
++ *dc = 0;
++ break;
++
++ case SPINOR_OP_READ_FAST:
++ case SPINOR_OP_READ_1_1_2:
++ case SPINOR_OP_READ_1_1_4:
++ case SPINOR_OP_READ4_FAST:
++ case SPINOR_OP_READ4_1_1_2:
++ case SPINOR_OP_READ4_1_1_4:
++ switch (read_dummy) {
++ case 6:
++ *dc = 1;
++ break;
++ case 8:
++ *dc = 0;
++ break;
++ case 10:
++ *dc = 3;
++ break;
++ default:
++ return -EINVAL;
++ }
++ break;
++
++ case SPINOR_OP_READ_1_2_2:
++ case SPINOR_OP_READ4_1_2_2:
++ switch (read_dummy) {
++ case 4:
++ *dc = 0;
++ break;
++ case 6:
++ *dc = 1;
++ break;
++ case 8:
++ *dc = 2;
++ break;
++ case 10:
++ *dc = 3;
++ default:
++ return -EINVAL;
++ }
++ break;
++
++ case SPINOR_OP_READ_1_4_4:
++ case SPINOR_OP_READ4_1_4_4:
++ switch (read_dummy) {
++ case 4:
++ *dc = 1;
++ break;
++ case 6:
++ *dc = 0;
++ break;
++ case 8:
++ *dc = 2;
++ break;
++ case 10:
++ *dc = 3;
++ default:
++ return -EINVAL;
++ }
++ break;
++
++ default:
++ return -EINVAL;
++ }
++
++ return 0;
++}
++
++static int macronix_set_dummy_cycles(struct spi_nor *nor, u8 read_dummy)
++{
++ int ret, sr, cr, mask, val;
++ u16 sr_cr;
++ u8 dc;
++
++ /* Convert the number of dummy cycles into Macronix DC volatile bits */
++ ret = macronix_dummy2code(nor->read_opcode, read_dummy, &dc);
++ if (ret)
++ return ret;
++
++ mask = GENMASK(7, 6);
++ val = (dc << 6) & mask;
++
++ cr = read_cr(nor);
++ if (cr < 0) {
++ dev_err(nor->dev, "error while reading the config register\n");
++ return cr;
++ }
++
++ if ((cr & mask) == val) {
++ nor->read_dummy = read_dummy;
++ return 0;
++ }
++
++ sr = read_sr(nor);
++ if (sr < 0) {
++ dev_err(nor->dev, "error while reading the status register\n");
++ return sr;
++ }
++
++ cr = (cr & ~mask) | val;
++ sr_cr = (sr & 0xff) | ((cr & 0xff) << 8);
++ write_enable(nor);
++ ret = write_sr_cr(nor, sr_cr);
++ if (ret) {
++ dev_err(nor->dev,
++ "error while writing the SR and CR registers\n");
++ return ret;
++ }
++
++ ret = spi_nor_wait_till_ready(nor);
++ if (ret)
++ return ret;
++
++ cr = read_cr(nor);
++ if (cr < 0 || (cr & mask) != val) {
++ dev_err(nor->dev, "Macronix Dummy Cycle bits not updated\n");
++ return -EINVAL;
++ }
++
++ /* Save the number of dummy cycles to use with Fast Read commands */
++ nor->read_dummy = read_dummy;
++ return 0;
++}
++
+ static int macronix_set_quad_mode(struct spi_nor *nor)
+ {
+ int status;
+@@ -1199,8 +1329,7 @@ static int macronix_set_quad_mode(struct spi_nor *nor)
+ * read (performance enhance) mode by mistake!
+ */
+ nor->read_opcode = SPINOR_OP_READ_1_4_4;
+- nor->read_dummy = 8;
+- return 0;
++ return macronix_set_dummy_cycles(nor, 8);
+ }
+
+ /*
+@@ -1213,6 +1342,9 @@ static int macronix_set_quad_mode(struct spi_nor *nor)
+ * entering the continuous read mode by mistake if some
+ * performance enhance toggling bits P0-P7 were written during
+ * dummy/mode cycles.
++ *
++ * Use the Fast Read Quad Output 1-1-4 (0x6b) command with 8 dummy
++ * cycles (up to 133MHz for STR and 66MHz for DTR).
+ */
+ status = macronix_quad_enable(nor);
+ if (status) {
+@@ -1221,8 +1353,7 @@ static int macronix_set_quad_mode(struct spi_nor *nor)
+ }
+ nor->read_proto = SNOR_PROTO_1_1_4;
+ nor->read_opcode = SPINOR_OP_READ_1_1_4;
+- nor->read_dummy = 8;
+- return 0;
++ return macronix_set_dummy_cycles(nor, 8);
+ }
+
+ /*
+@@ -1233,16 +1364,25 @@ static int macronix_set_quad_mode(struct spi_nor *nor)
+
+ static int macronix_set_dual_mode(struct spi_nor *nor)
+ {
++ /*
++ * Use the Fast Read Dual Output 1-1-2 (0x3b) command with 8 dummy
++ * cycles (up to 133MHz for STR and 66MHz for DTR).
++ */
+ nor->read_proto = SNOR_PROTO_1_1_2;
+ nor->read_opcode = SPINOR_OP_READ_1_1_2;
+- nor->read_dummy = 8;
+- return 0;
++ return macronix_set_dummy_cycles(nor, 8);
+ }
+
+ static int macronix_set_single_mode(struct spi_nor *nor)
+ {
+ u8 read_dummy;
+
++ /*
++ * Configure 8 dummy cycles for Fast Read 1-1-1 (0x0b) command (up to
++ * 133MHz for STR and 66MHz for DTR). The Read 1-1-1 (0x03) command
++ * expects no dummy cycle.
++ * read_opcode should not be overridden here!
++ */
+ switch (nor->read_opcode) {
+ case SPINOR_OP_READ:
+ case SPINOR_OP_READ4:
+@@ -1255,8 +1395,7 @@ static int macronix_set_single_mode(struct spi_nor *nor)
+ }
+
+ nor->read_proto = SNOR_PROTO_1_1_1;
+- nor->read_dummy = read_dummy;
+- return 0;
++ return macronix_set_dummy_cycles(nor, read_dummy);
+ }
+
+ static int winbond_set_quad_mode(struct spi_nor *nor)
+--
+2.8.1
+
diff --git a/target/linux/socfpga/patches-4.4/0026-mtd-spi-nor-configure-the-number-of-dummy-clock-cycl.patch b/target/linux/socfpga/patches-4.4/0026-mtd-spi-nor-configure-the-number-of-dummy-clock-cycl.patch
new file mode 100644
index 0000000..df79cdc
--- /dev/null
+++ b/target/linux/socfpga/patches-4.4/0026-mtd-spi-nor-configure-the-number-of-dummy-clock-cycl.patch
@@ -0,0 +1,215 @@
+From 7b411f38f7882fdf9f5607bc75deb940a7aaa480 Mon Sep 17 00:00:00 2001
+From: Cyrille Pitchen <cyrille.pitchen at atmel.com>
+Date: Fri, 8 Jan 2016 17:10:53 +0100
+Subject: [PATCH 26/33] mtd: spi-nor: configure the number of dummy clock
+ cycles on Spansion memories
+
+On Spansion memories, the number of dummy clock cycles to be used during
+Fast Read commands is configured through the 2bit latency code (LC). These
+bits are non-volatile inside the Configuration Register.
+
+To avoid breaking the configuration expected at reset by some bootloaders,
+we'd rather read the latency code and set the nor->read_dummy value
+accordingly than update those non-volatile bits.
+
+Since the Quad Enable non-volatile bit can be read at the same time from
+the Control Register, we now check its value to avoid some calls of the
+spansion_quad_enable() function when they are not needed.
+
+Signed-off-by: Cyrille Pitchen <cyrille.pitchen at atmel.com>
+---
+ drivers/mtd/spi-nor/spi-nor.c | 159 ++++++++++++++++++++++++++++++++++++------
+ 1 file changed, 137 insertions(+), 22 deletions(-)
+
+diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
+index 55a1d74..654209a 100644
+--- a/drivers/mtd/spi-nor/spi-nor.c
++++ b/drivers/mtd/spi-nor/spi-nor.c
+@@ -1687,47 +1687,162 @@ static int micron_set_single_mode(struct spi_nor *nor)
+ return micron_set_dummy_cycles(nor, read_dummy);
+ }
+
+-static int spansion_set_quad_mode(struct spi_nor *nor)
++static inline int spansion_get_config(struct spi_nor *nor,
++ bool *quad_enabled,
++ u8 *latency_code)
+ {
+- int status;
++ int cr;
+
+- status = spansion_quad_enable(nor);
+- if (status) {
+- dev_err(nor->dev, "Spansion quad-read not enabled\n");
++ cr = read_cr(nor);
++ if (cr < 0) {
++ dev_err(nor->dev,
++ "error while reading the configuration register\n");
++ return cr;
++ }
++
++ if (quad_enabled)
++ *quad_enabled = !!(cr & CR_QUAD_EN_SPAN);
++
++ if (latency_code)
++ *latency_code = (u8)((cr & GENMASK(7, 6)) >> 6);
++
++ return 0;
++}
++
++static int spansion_set_dummy_cycles(struct spi_nor *nor, u8 latency_code)
++{
++ /* SDR dummy cycles */
++ switch (nor->read_opcode) {
++ case SPINOR_OP_READ:
++ case SPINOR_OP_READ4:
++ nor->read_dummy = 0;
++ break;
++
++ case SPINOR_OP_READ_FAST:
++ case SPINOR_OP_READ_1_1_2:
++ case SPINOR_OP_READ_1_1_4:
++ case SPINOR_OP_READ4_FAST:
++ case SPINOR_OP_READ4_1_1_2:
++ case SPINOR_OP_READ4_1_1_4:
++ nor->read_dummy = (latency_code == 3) ? 0 : 8;
++ break;
++
++ case SPINOR_OP_READ_1_2_2:
++ case SPINOR_OP_READ4_1_2_2:
++ switch (latency_code) {
++ default:
++ case 0:
++ case 3:
++ nor->read_dummy = 4;
++ break;
++ case 1:
++ nor->read_dummy = 5;
++ break;
++ case 2:
++ nor->read_dummy = 6;
++ break;
++ }
++ break;
++
++
++ case SPINOR_OP_READ_1_4_4:
++ case SPINOR_OP_READ4_1_4_4:
++ switch (latency_code) {
++ default:
++ case 0:
++ case 1:
++ nor->read_dummy = 4;
++ break;
++ case 2:
++ nor->read_dummy = 5;
++ break;
++ case 3:
++ nor->read_dummy = 1;
++ break;
++ }
++
++ default:
+ return -EINVAL;
+ }
++
++ return 0;
++}
++
++static int spansion_set_quad_mode(struct spi_nor *nor)
++{
++ bool quad_enabled;
++ u8 latency_code;
++ int ret;
++
++ /*
++ * The QUAD bit of Configuration Register must be set (CR Bit1=1) for
++ * using any Quad SPI command.
++ */
++ ret = spansion_get_config(nor, &quad_enabled, &latency_code);
++ if (ret)
++ return ret;
++
++ /* The Quad mode should be enabled ... */
++ if (!quad_enabled) {
++ /* ... if not try to enable it. */
++ dev_warn(nor->dev, "Spansion Quad mode disabled, enable it\n");
++ ret = spansion_quad_enable(nor);
++ if (ret)
++ return ret;
++ }
++
++ /*
++ * Don't use the Fast Read Quad I/O (0xeb / 0xec) commands as their
++ * number of dummy cycles can not be set to a multiple of 8: some SPI
++ * controllers, especially those relying on the m25p80 driver, expect
++ * the number of dummy cycles to be a multiple of 8.
++ * Also when using a Fast Read Quad I/O command, the memory checks the
++ * value of the first mode/dummy cycles to decice whether it enters or
++ * leaves the Countinuous Read mode. We should never enter the
++ * Countinuous Read mode as the spi-nor framework doesn't support it.
++ * For all these reason, we'd rather use the Fast Read Quad Output
++ * 1-1-4 (0x6b / 0x6c) commands instead.
++ */
+ nor->read_proto = SNOR_PROTO_1_1_4;
+ nor->read_opcode = SPINOR_OP_READ_1_1_4;
+- nor->read_dummy = 8;
+- return 0;
++ return spansion_set_dummy_cycles(nor, latency_code);
+ }
+
+ static int spansion_set_dual_mode(struct spi_nor *nor)
+ {
++ u8 latency_code;
++ int ret;
++
++ /* We don't care about the quad mode status */
++ ret = spansion_get_config(nor, NULL, &latency_code);
++ if (ret)
++ return ret;
++
++ /*
++ * Don't use the Fast Read Dual I/O (0xbb / 0xbc) commands as their
++ * number of dummy cycles can not bet set to a multiple of 8: some SPI
++ * controllers, especially those relying on the m25p80 driver, expect
++ * the number of dummy cycles to be a multiple of 8.
++ * For this reason, w'd rather use the Fast Read Dual Output 1-1-2
++ * (0x3b / 0x3c) commands instead.
++ */
+ nor->read_proto = SNOR_PROTO_1_1_2;
+ nor->read_opcode = SPINOR_OP_READ_1_1_2;
+- nor->read_dummy = 8;
+- return 0;
++ return spansion_set_dummy_cycles(nor, latency_code);
+ }
+
+ static int spansion_set_single_mode(struct spi_nor *nor)
+ {
+- u8 read_dummy;
+-
+- switch (nor->read_opcode) {
+- case SPINOR_OP_READ:
+- case SPINOR_OP_READ4:
+- read_dummy = 0;
+- break;
++ u8 latency_code;
++ int ret;
+
+- default:
+- read_dummy = 8;
+- break;
+- }
++ /* We don't care about the quad mode status */
++ ret = spansion_get_config(nor, NULL, &latency_code);
++ if (ret)
++ return ret;
+
+ nor->read_proto = SNOR_PROTO_1_1_1;
+- nor->read_dummy = read_dummy;
+- return 0;
++ return spansion_set_dummy_cycles(nor, latency_code);
+ }
+
+ static int set_quad_mode(struct spi_nor *nor, const struct flash_info *info)
+--
+2.8.1
+
diff --git a/target/linux/socfpga/patches-4.4/0027-mtd-m25p80-add-support-of-dual-and-quad-spi-protocol.patch b/target/linux/socfpga/patches-4.4/0027-mtd-m25p80-add-support-of-dual-and-quad-spi-protocol.patch
new file mode 100644
index 0000000..d2f5ab6
--- /dev/null
+++ b/target/linux/socfpga/patches-4.4/0027-mtd-m25p80-add-support-of-dual-and-quad-spi-protocol.patch
@@ -0,0 +1,293 @@
+From 8b4f14b2f8ed819a6b9e371128259271e8d88841 Mon Sep 17 00:00:00 2001
+From: Cyrille Pitchen <cyrille.pitchen at atmel.com>
+Date: Fri, 8 Jan 2016 17:10:54 +0100
+Subject: [PATCH 27/33] mtd: m25p80: add support of dual and quad spi protocols
+ to all commands
+
+Before this patch, m25p80_read() supported few SPI protocols:
+- regular SPI 1-1-1
+- SPI Dual Output 1-1-2
+- SPI Quad Output 1-1-4
+On the other hand, all other m25p80_*() hooks only supported SPI 1-1-1.
+
+However once their Quad mode enabled, Micron and Macronix spi-nor memories
+expect all commands to use the SPI 4-4-4 protocol.
+
+Also, once their Dual mode enabled, Micron spi-nor memories expect all
+commands to use the SPI-2-2-2 protocol.
+
+So this patch adds support to all currently existing SPI protocols to
+cover as many protocols as possible.
+
+Signed-off-by: Cyrille Pitchen <cyrille.pitchen at atmel.com>
+---
+ drivers/mtd/devices/m25p80.c | 192 ++++++++++++++++++++++++++++++++++---------
+ 1 file changed, 151 insertions(+), 41 deletions(-)
+
+diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
+index bc7a802..e3e2708 100644
+--- a/drivers/mtd/devices/m25p80.c
++++ b/drivers/mtd/devices/m25p80.c
+@@ -27,22 +27,64 @@
+ #include <linux/spi/flash.h>
+ #include <linux/mtd/spi-nor.h>
+
+-#define MAX_CMD_SIZE 6
++#define MAX_CMD_SIZE 16
+ struct m25p {
+ struct spi_device *spi;
+ struct spi_nor spi_nor;
+ u8 command[MAX_CMD_SIZE];
+ };
+
++static inline int m25p80_proto2nbits(enum spi_nor_protocol proto,
++ unsigned *code_nbits,
++ unsigned *addr_nbits,
++ unsigned *data_nbits)
++{
++ if (code_nbits)
++ *code_nbits = SNOR_PROTO_CMD_FROM_PROTO(proto);
++ if (addr_nbits)
++ *addr_nbits = SNOR_PROTO_ADDR_FROM_PROTO(proto);
++ if (data_nbits)
++ *data_nbits = SNOR_PROTO_DATA_FROM_PROTO(proto);
++
++ return 0;
++}
++
+ static int m25p80_read_reg(struct spi_nor *nor, u8 code, u8 *val, int len)
+ {
+ struct m25p *flash = nor->priv;
+ struct spi_device *spi = flash->spi;
++ unsigned code_nbits, data_nbits;
++ struct spi_transfer xfers[2];
+ int ret;
+
+- ret = spi_write_then_read(spi, &code, 1, val, len);
++ /* Check the total length of command op code and data. */
++ if (len + 1 > MAX_CMD_SIZE)
++ return -EINVAL;
++
++ /* Get transfer protocols (addr_nbits is not relevant here). */
++ ret = m25p80_proto2nbits(nor->reg_proto,
++ &code_nbits, NULL, &data_nbits);
++ if (ret < 0)
++ return ret;
++
++ /* Set up transfers. */
++ memset(xfers, 0, sizeof(xfers));
++
++ flash->command[0] = code;
++ xfers[0].len = 1;
++ xfers[0].tx_buf = flash->command;
++ xfers[0].tx_nbits = code_nbits;
++
++ xfers[1].len = len;
++ xfers[1].rx_buf = &flash->command[1];
++ xfers[1].rx_nbits = data_nbits;
++
++ /* Process command. */
++ ret = spi_sync_transfer(spi, xfers, 2);
+ if (ret < 0)
+ dev_err(&spi->dev, "error %d reading %x\n", ret, code);
++ else
++ memcpy(val, &flash->command[1], len);
+
+ return ret;
+ }
+@@ -65,12 +107,42 @@ static int m25p80_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
+ {
+ struct m25p *flash = nor->priv;
+ struct spi_device *spi = flash->spi;
++ unsigned code_nbits, data_nbits, num_xfers = 1;
++ struct spi_transfer xfers[2];
++ int ret;
++
++ /* Check the total length of command op code and data. */
++ if (buf && (len + 1 > MAX_CMD_SIZE))
++ return -EINVAL;
++
++ /* Get transfer protocols (addr_nbits is not relevant here). */
++ ret = m25p80_proto2nbits(nor->reg_proto,
++ &code_nbits, NULL, &data_nbits);
++ if (ret < 0)
++ return ret;
++
++ /* Set up transfer(s). */
++ memset(xfers, 0, sizeof(xfers));
+
+ flash->command[0] = opcode;
+- if (buf)
++ xfers[0].len = 1;
++ xfers[0].tx_buf = flash->command;
++ xfers[0].tx_nbits = code_nbits;
++
++ if (buf) {
+ memcpy(&flash->command[1], buf, len);
++ if (data_nbits == code_nbits) {
++ xfers[0].len += len;
++ } else {
++ xfers[1].len = len;
++ xfers[1].tx_buf = &flash->command[1];
++ xfers[1].tx_nbits = data_nbits;
++ num_xfers++;
++ }
++ }
+
+- return spi_write(spi, flash->command, len + 1);
++ /* Process command. */
++ return spi_sync_transfer(spi, xfers, num_xfers);
+ }
+
+ static void m25p80_write(struct spi_nor *nor, loff_t to, size_t len,
+@@ -78,43 +150,54 @@ static void m25p80_write(struct spi_nor *nor, loff_t to, size_t len,
+ {
+ struct m25p *flash = nor->priv;
+ struct spi_device *spi = flash->spi;
+- struct spi_transfer t[2] = {};
++ unsigned code_nbits, addr_nbits, data_nbits, num_xfers = 1;
++ struct spi_transfer xfers[3];
+ struct spi_message m;
+- int cmd_sz = m25p_cmdsz(nor);
+-
+- spi_message_init(&m);
++ int ret, cmd_sz = m25p_cmdsz(nor);
+
+ if (nor->program_opcode == SPINOR_OP_AAI_WP && nor->sst_write_second)
+ cmd_sz = 1;
+
+- flash->command[0] = nor->program_opcode;
+- m25p_addr2cmd(nor, to, flash->command);
++ /* Get transfer protocols. */
++ ret = m25p80_proto2nbits(nor->write_proto,
++ &code_nbits, &addr_nbits, &data_nbits);
++ if (ret < 0) {
++ *retlen = 0;
++ return;
++ }
+
+- t[0].tx_buf = flash->command;
+- t[0].len = cmd_sz;
+- spi_message_add_tail(&t[0], &m);
++ /* Set up transfers. */
++ memset(xfers, 0, sizeof(xfers));
++
++ flash->command[0] = nor->program_opcode;
++ xfers[0].len = 1;
++ xfers[0].tx_buf = flash->command;
++ xfers[0].tx_nbits = code_nbits;
++
++ if (cmd_sz > 1) {
++ m25p_addr2cmd(nor, to, flash->command);
++ if (addr_nbits == code_nbits) {
++ xfers[0].len += nor->addr_width;
++ } else {
++ xfers[1].len = nor->addr_width;
++ xfers[1].tx_buf = &flash->command[1];
++ xfers[1].tx_nbits = addr_nbits;
++ num_xfers++;
++ }
++ }
+
+- t[1].tx_buf = buf;
+- t[1].len = len;
+- spi_message_add_tail(&t[1], &m);
++ xfers[num_xfers].len = len;
++ xfers[num_xfers].tx_buf = buf;
++ xfers[num_xfers].tx_nbits = data_nbits;
++ num_xfers++;
+
++ /* Process command. */
++ spi_message_init_with_transfers(&m, xfers, num_xfers);
+ spi_sync(spi, &m);
+
+ *retlen += m.actual_length - cmd_sz;
+ }
+
+-static inline unsigned int m25p80_rx_nbits(struct spi_nor *nor)
+-{
+- switch (nor->flash_read) {
+- case SPI_NOR_DUAL:
+- return 2;
+- case SPI_NOR_QUAD:
+- return 4;
+- default:
+- return 0;
+- }
+-}
+-
+ /*
+ * Read an address range from the nor chip. The address range
+ * may be any size provided it is within the physical boundaries.
+@@ -124,28 +207,55 @@ static int m25p80_read(struct spi_nor *nor, loff_t from, size_t len,
+ {
+ struct m25p *flash = nor->priv;
+ struct spi_device *spi = flash->spi;
+- struct spi_transfer t[2];
+- struct spi_message m;
++ unsigned code_nbits, addr_nbits, data_nbits, num_xfers = 1;
+ unsigned int dummy = nor->read_dummy;
++ struct spi_transfer xfers[3];
++ struct spi_message m;
++ int ret;
++
++ /* Get transfer protocols. */
++ ret = m25p80_proto2nbits(nor->read_proto,
++ &code_nbits, &addr_nbits, &data_nbits);
++ if (ret < 0) {
++ *retlen = 0;
++ return ret;
++ }
+
+ /* convert the dummy cycles to the number of bytes */
+- dummy /= 8;
++ dummy = (dummy * addr_nbits) / 8;
+
+- spi_message_init(&m);
+- memset(t, 0, (sizeof t));
++ /* Set up transfers. */
++ memset(xfers, 0, sizeof(xfers));
+
+ flash->command[0] = nor->read_opcode;
+- m25p_addr2cmd(nor, from, flash->command);
++ xfers[0].len = 1;
++ xfers[0].tx_buf = flash->command;
++ xfers[0].tx_nbits = code_nbits;
+
+- t[0].tx_buf = flash->command;
+- t[0].len = m25p_cmdsz(nor) + dummy;
+- spi_message_add_tail(&t[0], &m);
++ m25p_addr2cmd(nor, from, flash->command);
++ /*
++ * Clear all dummy/mode cycle bits to avoid sending some manufacturer
++ * specific pattern, which might make the memory enter its Continuous
++ * Read mode by mistake.
++ */
++ memset(flash->command + 1 + nor->addr_width, 0, dummy);
++
++ if (addr_nbits == code_nbits) {
++ xfers[0].len += nor->addr_width + dummy;
++ } else {
++ xfers[1].len = nor->addr_width + dummy;
++ xfers[1].tx_buf = &flash->command[1];
++ xfers[1].tx_nbits = addr_nbits;
++ num_xfers++;
++ }
+
+- t[1].rx_buf = buf;
+- t[1].rx_nbits = m25p80_rx_nbits(nor);
+- t[1].len = len;
+- spi_message_add_tail(&t[1], &m);
++ xfers[num_xfers].len = len;
++ xfers[num_xfers].rx_buf = buf;
++ xfers[num_xfers].rx_nbits = data_nbits;
++ num_xfers++;
+
++ /* Process command. */
++ spi_message_init_with_transfers(&m, xfers, num_xfers);
+ spi_sync(spi, &m);
+
+ *retlen = m.actual_length - m25p_cmdsz(nor) - dummy;
+--
+2.8.1
+
diff --git a/target/linux/socfpga/patches-4.4/0028-mtd-ofpart-grab-device-tree-node-directly-from-maste.patch b/target/linux/socfpga/patches-4.4/0028-mtd-ofpart-grab-device-tree-node-directly-from-maste.patch
new file mode 100644
index 0000000..3787607
--- /dev/null
+++ b/target/linux/socfpga/patches-4.4/0028-mtd-ofpart-grab-device-tree-node-directly-from-maste.patch
@@ -0,0 +1,81 @@
+From 62b613003aa4cef3f8bf9a2ec4c7709daf4dde8a Mon Sep 17 00:00:00 2001
+From: Brian Norris <computersforpeace at gmail.com>
+Date: Fri, 30 Oct 2015 20:33:21 -0700
+Subject: [PATCH 28/33] mtd: ofpart: grab device tree node directly from master
+ device node
+
+It seems more logical to use a device node directly associated with the
+MTD master device (i.e., mtd->dev.of_node field) rather than requiring
+auxiliary partition parser information to be passed in by the driver in
+a separate struct.
+
+This patch supports the mtd->dev.of_node field and deprecates the parser
+data 'of_node' field
+
+Driver conversions may now follow.
+
+Additional side benefit to assigning mtd->dev.of_node rather than using
+parser data: the driver core will automatically create a device -> node
+symlink for us.
+
+Signed-off-by: Brian Norris <computersforpeace at gmail.com>
+Reviewed-by: Boris Brezillon <boris.brezillon at free-electrons.com>
+---
+ drivers/mtd/ofpart.c | 18 ++++++++++--------
+ include/linux/mtd/partitions.h | 4 +++-
+ 2 files changed, 13 insertions(+), 9 deletions(-)
+
+diff --git a/drivers/mtd/ofpart.c b/drivers/mtd/ofpart.c
+index 9ed6038..cf4780c 100644
+--- a/drivers/mtd/ofpart.c
++++ b/drivers/mtd/ofpart.c
+@@ -37,10 +37,11 @@ static int parse_ofpart_partitions(struct mtd_info *master,
+ bool dedicated = true;
+
+
+- if (!data)
+- return 0;
+-
+- mtd_node = data->of_node;
++ /*
++ * of_node can be provided through auxiliary parser data or (preferred)
++ * by assigning the master device node
++ */
++ mtd_node = data && data->of_node ? data->of_node : mtd_get_of_node(master);
+ if (!mtd_node)
+ return 0;
+
+@@ -157,10 +158,11 @@ static int parse_ofoldpart_partitions(struct mtd_info *master,
+ } *part;
+ const char *names;
+
+- if (!data)
+- return 0;
+-
+- dp = data->of_node;
++ /*
++ * of_node can be provided through auxiliary parser data or (preferred)
++ * by assigning the master device node
++ */
++ dp = data && data->of_node ? data->of_node : mtd_get_of_node(master);
+ if (!dp)
+ return 0;
+
+diff --git a/include/linux/mtd/partitions.h b/include/linux/mtd/partitions.h
+index 6a35e6d..e742f34 100644
+--- a/include/linux/mtd/partitions.h
++++ b/include/linux/mtd/partitions.h
+@@ -56,7 +56,9 @@ struct device_node;
+ /**
+ * struct mtd_part_parser_data - used to pass data to MTD partition parsers.
+ * @origin: for RedBoot, start address of MTD device
+- * @of_node: for OF parsers, device node containing partitioning information
++ * @of_node: for OF parsers, device node containing partitioning information.
++ * This field is deprecated, as the device node should simply be
++ * assigned to the master struct device.
+ */
+ struct mtd_part_parser_data {
+ unsigned long origin;
+--
+2.8.1
+
diff --git a/target/linux/socfpga/patches-4.4/0029-Documentation-atmel-quadspi-add-binding-file-for-Atm.patch b/target/linux/socfpga/patches-4.4/0029-Documentation-atmel-quadspi-add-binding-file-for-Atm.patch
new file mode 100644
index 0000000..ca8831d
--- /dev/null
+++ b/target/linux/socfpga/patches-4.4/0029-Documentation-atmel-quadspi-add-binding-file-for-Atm.patch
@@ -0,0 +1,58 @@
+From 771ee7cd27c39617ece8727c70f904c31f7415fb Mon Sep 17 00:00:00 2001
+From: Cyrille Pitchen <cyrille.pitchen at atmel.com>
+Date: Fri, 8 Jan 2016 17:10:55 +0100
+Subject: [PATCH 29/33] Documentation: atmel-quadspi: add binding file for
+ Atmel QSPI driver
+
+This patch documents the DT bindings for the driver of the Atmel QSPI
+controller embedded inside sama5d2x SoCs.
+
+Signed-off-by: Cyrille Pitchen <cyrille.pitchen at atmel.com>
+Acked-by: Rob Herring <robh at kernel.org>
+Acked-by: Nicolas Ferre <nicolas.ferre at atmel.com>
+---
+ .../devicetree/bindings/mtd/atmel-quadspi.txt | 32 ++++++++++++++++++++++
+ 1 file changed, 32 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/mtd/atmel-quadspi.txt
+
+diff --git a/Documentation/devicetree/bindings/mtd/atmel-quadspi.txt b/Documentation/devicetree/bindings/mtd/atmel-quadspi.txt
+new file mode 100644
+index 0000000..4898070
+--- /dev/null
++++ b/Documentation/devicetree/bindings/mtd/atmel-quadspi.txt
+@@ -0,0 +1,32 @@
++* Atmel Quad Serial Peripheral Interface (QSPI)
++
++Required properties:
++- compatible: Should be "atmel,sama5d2-qspi".
++- reg: Should contain the locations and lengths of the base registers
++ and the mapped memory.
++- reg-names: Should contain the resource reg names:
++ - qspi_base: configuration register address space
++ - qspi_mmap: memory mapped address space
++- interrupts: Should contain the interrupt for the device.
++- clocks: The phandle of the clock needed by the QSPI controller.
++- #address-cells: Should be <1>.
++- #size-cells: Should be <0>.
++
++Example:
++
++spi at f0020000 {
++ compatible = "atmel,sama5d2-qspi";
++ reg = <0xf0020000 0x100>, <0xd0000000 0x8000000>;
++ reg-names = "qspi_base", "qspi_mmap";
++ interrupts = <52 IRQ_TYPE_LEVEL_HIGH 7>;
++ clocks = <&spi0_clk>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_spi0_default>;
++ status = "okay";
++
++ m25p80 at 0 {
++ ...
++ };
++};
+--
+2.8.1
+
diff --git a/target/linux/socfpga/patches-4.4/0030-mtd-spi-nor-Bindings-for-Cadence-Quad-SPI-Flash-Cont.patch b/target/linux/socfpga/patches-4.4/0030-mtd-spi-nor-Bindings-for-Cadence-Quad-SPI-Flash-Cont.patch
new file mode 100644
index 0000000..7b454a8
--- /dev/null
+++ b/target/linux/socfpga/patches-4.4/0030-mtd-spi-nor-Bindings-for-Cadence-Quad-SPI-Flash-Cont.patch
@@ -0,0 +1,99 @@
+From 8e8a7168e89cc978ca14ab74ab20193ca09e3f3a Mon Sep 17 00:00:00 2001
+From: Graham Moore <grmoore at opensource.altera.com>
+Date: Tue, 28 Jul 2015 12:38:02 -0500
+Subject: [PATCH 30/33] mtd: spi-nor: Bindings for Cadence Quad SPI Flash
+ Controller driver.
+
+Add binding document for the Cadence QSPI controller.
+
+Signed-off-by: Graham Moore <grmoore at opensource.altera.com>
+Signed-off-by: Marek Vasut <marex at denx.de>
+Cc: Alan Tull <atull at opensource.altera.com>
+Cc: Brian Norris <computersforpeace at gmail.com>
+Cc: David Woodhouse <dwmw2 at infradead.org>
+Cc: Dinh Nguyen <dinguyen at opensource.altera.com>
+Cc: Graham Moore <grmoore at opensource.altera.com>
+Cc: Vignesh R <vigneshr at ti.com>
+Cc: Yves Vandervennet <yvanderv at opensource.altera.com>
+Cc: devicetree at vger.kernel.org
+
+V2: Add cdns prefix to driver-specific bindings.
+V3: Use existing property "is-decoded-cs" instead of creating a
+ duplicate, "ext-decoder". Timing parameters are in nanoseconds,
+ not master reference clocks. Remove bus-num completely.
+V4: Add new properties fifo-width and trigger-address
+V7: - Prefix all of the Cadence-specific properties with cdns prefix,
+ those are in particular "cdns,is-decoded-cs", "cdns,fifo-depth",
+ "cdns,fifo-width", "cdns,trigger-address".
+ - Drop bogus properties which were not used and were incorrect.
+V8: Align lines to 80 chars.
+---
+ .../devicetree/bindings/mtd/cadence-quadspi.txt | 56 ++++++++++++++++++++++
+ 1 file changed, 56 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/mtd/cadence-quadspi.txt
+
+diff --git a/Documentation/devicetree/bindings/mtd/cadence-quadspi.txt b/Documentation/devicetree/bindings/mtd/cadence-quadspi.txt
+new file mode 100644
+index 0000000..f248056
+--- /dev/null
++++ b/Documentation/devicetree/bindings/mtd/cadence-quadspi.txt
+@@ -0,0 +1,56 @@
++* Cadence Quad SPI controller
++
++Required properties:
++- compatible : Should be "cdns,qspi-nor".
++- reg : Contains two entries, each of which is a tuple consisting of a
++ physical address and length. The first entry is the address and
++ length of the controller register set. The second entry is the
++ address and length of the QSPI Controller data area.
++- interrupts : Unit interrupt specifier for the controller interrupt.
++- clocks : phandle to the Quad SPI clock.
++- cdns,fifo-depth : Size of the data FIFO in words.
++- cdns,fifo-width : Bus width of the data FIFO in bytes.
++- cdns,trigger-address : 32-bit indirect AHB trigger address.
++
++Optional properties:
++- cdns,is-decoded-cs : Flag to indicate whether decoder is used or not.
++
++Optional subnodes:
++Subnodes of the Cadence Quad SPI controller are spi slave nodes with additional
++custom properties:
++- cdns,read-delay : Delay for read capture logic, in clock cycles
++- cdns,tshsl-ns : Delay in nanoseconds for the length that the master
++ mode chip select outputs are de-asserted between
++ transactions.
++- cdns,tsd2d-ns : Delay in nanoseconds between one chip select being
++ de-activated and the activation of another.
++- cdns,tchsh-ns : Delay in nanoseconds between last bit of current
++ transaction and deasserting the device chip select
++ (qspi_n_ss_out).
++- cdns,tslch-ns : Delay in nanoseconds between setting qspi_n_ss_out low
++ and first bit transfer.
++
++Example:
++
++ qspi: spi at ff705000 {
++ compatible = "cdns,qspi-nor";
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <0xff705000 0x1000>,
++ <0xffa00000 0x1000>;
++ interrupts = <0 151 4>;
++ clocks = <&qspi_clk>;
++ cdns,is-decoded-cs;
++ cdns,fifo-depth = <128>;
++ cdns,fifo-width = <4>;
++ cdns,trigger-address = <0x00000000>;
++
++ flash0: n25q00 at 0 {
++ ...
++ cdns,read-delay = <4>;
++ cdns,tshsl-ns = <50>;
++ cdns,tsd2d-ns = <50>;
++ cdns,tchsh-ns = <4>;
++ cdns,tslch-ns = <4>;
++ };
++ };
+--
+2.8.1
+
diff --git a/target/linux/socfpga/patches-4.4/0031-mtd-spi-nor-Add-driver-for-Cadence-Quad-SPI-Flash-Co.patch b/target/linux/socfpga/patches-4.4/0031-mtd-spi-nor-Add-driver-for-Cadence-Quad-SPI-Flash-Co.patch
new file mode 100644
index 0000000..1a55ee2
--- /dev/null
+++ b/target/linux/socfpga/patches-4.4/0031-mtd-spi-nor-Add-driver-for-Cadence-Quad-SPI-Flash-Co.patch
@@ -0,0 +1,1431 @@
+From 30e33517815b3c518fc2483a23bfe1445c0ae92d Mon Sep 17 00:00:00 2001
+From: Graham Moore <grmoore at opensource.altera.com>
+Date: Tue, 28 Jul 2015 12:38:03 -0500
+Subject: [PATCH 31/33] mtd: spi-nor: Add driver for Cadence Quad SPI Flash
+ Controller.
+
+Add support for the Cadence QSPI controller. This controller is
+present in the Altera SoCFPGA SoCs and this driver has been tested
+on the Cyclone V SoC.
+
+Signed-off-by: Graham Moore <grmoore at opensource.altera.com>
+Signed-off-by: Marek Vasut <marex at denx.de>
+Cc: Alan Tull <atull at opensource.altera.com>
+Cc: Brian Norris <computersforpeace at gmail.com>
+Cc: David Woodhouse <dwmw2 at infradead.org>
+Cc: Dinh Nguyen <dinguyen at opensource.altera.com>
+Cc: Graham Moore <grmoore at opensource.altera.com>
+Cc: Vignesh R <vigneshr at ti.com>
+Cc: Yves Vandervennet <yvanderv at opensource.altera.com>
+Cc: devicetree at vger.kernel.org
+
+V2: use NULL instead of modalias in spi_nor_scan call
+V3: Use existing property is-decoded-cs instead of creating duplicate.
+V4: Support Micron quad mode by snooping command stream for EVCR command
+ and subsequently configuring Cadence controller for quad mode.
+V5: Clean up sparse and smatch complaints. Remove snooping of Micron
+ quad mode. Add comment on XIP mode bit and dummy clock cycles. Set
+ up SRAM partition at 1:1 during init.
+V6: Remove dts patch that was included by mistake. Incorporate Vikas's
+ comments regarding fifo width, SRAM partition setting, and trigger
+ address. Trigger address was added as an unsigned int, as it is not
+ an IO resource per se, and does not need to be mapped. Also add
+ Marek Vasut's workaround for picking up OF properties on subnodes.
+V7: - Perform coding-style cleanup and type fixes. Remove ugly QSPI_*()
+ macros and replace them with functions. Get rid of unused variables.
+ - Implement support for nor->set_protocol() to handle Quad-command,
+ this patch now depends on the following patch:
+ mtd: spi-nor: notify (Q)SPI controller about protocol change
+ - Replace that cqspi_fifo_read() disaster with plain old readsl()
+ and cqspi_fifo_write() tentacle horror with pretty writesl().
+ - Remove CQSPI_SUPPORT_XIP_CHIPS, which is broken.
+ - Get rid of cqspi_find_chipselect() mess, instead just place the
+ struct cqspi_st and chipselect number into struct cqspi_flash_pdata
+ and set nor->priv to the struct cqspi_flash_pdata of that particular
+ chip.
+ - Replace the odd math in calculate_ticks_for_ns() with DIV_ROUND_UP().
+ - Make variables const where applicable.
+V8: - Implement a function to wait for bit being set/unset for a given
+ period of time and use it to replace the ad-hoc bits of code.
+ - Configure the write underflow watermark to be 1/8 if FIFO size.
+ - Extract out the SPI NOR flash probing code into separate function
+ to clearly mark what will soon be considered a boilerplate code.
+ - Repair the handling of mode bits, which caused instability in V7.
+ - Clean up the interrupt handling
+ - Fix Kconfig help text and make the patch depend on OF and COMPILE_TEST.
+V9: - Rename CQSPI_REG_IRQ_IND_RD_OVERFLOW to CQSPI_REG_IRQ_IND_SRAM_FULL
+ - Merge cqspi_controller_disable() into cqspi_controller_enable() and
+ make the mode selectable via parameter.
+V10: - Update against Cyrille's new patchset and changes to linux-mtd.
+ - Repair problem with multiple QSPI NOR devices having the same mtd->name,
+ they are now named devname.cs , where cs is the chipselect ID.
+V11: - Replace dependency on ARCH_SOCFPGA with dependency on ARM
+---
+ drivers/mtd/spi-nor/Kconfig | 11 +
+ drivers/mtd/spi-nor/Makefile | 1 +
+ drivers/mtd/spi-nor/cadence-quadspi.c | 1324 +++++++++++++++++++++++++++++++++
+ 3 files changed, 1336 insertions(+)
+ create mode 100644 drivers/mtd/spi-nor/cadence-quadspi.c
+
+diff --git a/drivers/mtd/spi-nor/Kconfig b/drivers/mtd/spi-nor/Kconfig
+index 2fe2a7e..02082ae 100644
+--- a/drivers/mtd/spi-nor/Kconfig
++++ b/drivers/mtd/spi-nor/Kconfig
+@@ -41,4 +41,15 @@ config SPI_NXP_SPIFI
+ Flash. Enable this option if you have a device with a SPIFI
+ controller and want to access the Flash as a mtd device.
+
++config SPI_CADENCE_QUADSPI
++ tristate "Cadence Quad SPI controller"
++ depends on OF && (ARM || COMPILE_TEST)
++ help
++ Enable support for the Cadence Quad SPI Flash controller.
++
++ Cadence QSPI is a specialized controller for connecting an SPI
++ Flash over 1/2/4-bit wide bus. Enable this option if you have a
++ device with a Cadence QSPI controller and want to access the
++ Flash as an MTD device.
++
+ endif # MTD_SPI_NOR
+diff --git a/drivers/mtd/spi-nor/Makefile b/drivers/mtd/spi-nor/Makefile
+index e53333e..446c6b9 100644
+--- a/drivers/mtd/spi-nor/Makefile
++++ b/drivers/mtd/spi-nor/Makefile
+@@ -1,3 +1,4 @@
+ obj-$(CONFIG_MTD_SPI_NOR) += spi-nor.o
++obj-$(CONFIG_SPI_CADENCE_QUADSPI) += cadence-quadspi.o
+ obj-$(CONFIG_SPI_FSL_QUADSPI) += fsl-quadspi.o
+ obj-$(CONFIG_SPI_NXP_SPIFI) += nxp-spifi.o
+diff --git a/drivers/mtd/spi-nor/cadence-quadspi.c b/drivers/mtd/spi-nor/cadence-quadspi.c
+new file mode 100644
+index 0000000..7e61fba
+--- /dev/null
++++ b/drivers/mtd/spi-nor/cadence-quadspi.c
+@@ -0,0 +1,1324 @@
++/*
++ * Driver for Cadence QSPI Controller
++ *
++ * Copyright Altera Corporation (C) 2012-2014. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms and conditions of the GNU General Public License,
++ * version 2, as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
++ * more details.
++ *
++ * You should have received a copy of the GNU General Public License along with
++ * this program. If not, see <http://www.gnu.org/licenses/>.
++ */
++#include <linux/clk.h>
++#include <linux/completion.h>
++#include <linux/delay.h>
++#include <linux/err.h>
++#include <linux/errno.h>
++#include <linux/interrupt.h>
++#include <linux/io.h>
++#include <linux/jiffies.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
++#include <linux/mtd/spi-nor.h>
++#include <linux/of_device.h>
++#include <linux/of.h>
++#include <linux/platform_device.h>
++#include <linux/sched.h>
++#include <linux/spi/spi.h>
++#include <linux/timer.h>
++
++#define CQSPI_NAME "cadence-qspi"
++#define CQSPI_MAX_CHIPSELECT 16
++
++struct cqspi_st;
++
++struct cqspi_flash_pdata {
++ struct spi_nor nor;
++ struct cqspi_st *cqspi;
++ u32 clk_rate;
++ u32 read_delay;
++ u32 tshsl_ns;
++ u32 tsd2d_ns;
++ u32 tchsh_ns;
++ u32 tslch_ns;
++ u8 inst_width;
++ u8 addr_width;
++ u8 cs;
++};
++
++struct cqspi_st {
++ struct platform_device *pdev;
++
++ struct clk *clk;
++ unsigned int sclk;
++
++ void __iomem *iobase;
++ void __iomem *ahb_base;
++ struct completion transfer_complete;
++ struct mutex bus_mutex;
++
++ int current_cs;
++ unsigned long master_ref_clk_hz;
++ bool is_decoded_cs;
++ u32 fifo_depth;
++ u32 fifo_width;
++ u32 trigger_address;
++ struct cqspi_flash_pdata f_pdata[CQSPI_MAX_CHIPSELECT];
++};
++
++/* Operation timeout value */
++#define CQSPI_TIMEOUT_MS 500
++#define CQSPI_READ_TIMEOUT_MS 10
++
++/* Instruction type */
++#define CQSPI_INST_TYPE_SINGLE 0
++#define CQSPI_INST_TYPE_DUAL 1
++#define CQSPI_INST_TYPE_QUAD 2
++
++#define CQSPI_DUMMY_CLKS_PER_BYTE 8
++#define CQSPI_DUMMY_BYTES_MAX 4
++#define CQSPI_DUMMY_CLKS_MAX 31
++
++#define CQSPI_STIG_DATA_LEN_MAX 8
++
++/* Register map */
++#define CQSPI_REG_CONFIG 0x00
++#define CQSPI_REG_CONFIG_ENABLE_MASK BIT(0)
++#define CQSPI_REG_CONFIG_DECODE_MASK BIT(9)
++#define CQSPI_REG_CONFIG_CHIPSELECT_LSB 10
++#define CQSPI_REG_CONFIG_DMA_MASK BIT(15)
++#define CQSPI_REG_CONFIG_BAUD_LSB 19
++#define CQSPI_REG_CONFIG_IDLE_LSB 31
++#define CQSPI_REG_CONFIG_CHIPSELECT_MASK 0xF
++#define CQSPI_REG_CONFIG_BAUD_MASK 0xF
++
++#define CQSPI_REG_RD_INSTR 0x04
++#define CQSPI_REG_RD_INSTR_OPCODE_LSB 0
++#define CQSPI_REG_RD_INSTR_TYPE_INSTR_LSB 8
++#define CQSPI_REG_RD_INSTR_TYPE_ADDR_LSB 12
++#define CQSPI_REG_RD_INSTR_TYPE_DATA_LSB 16
++#define CQSPI_REG_RD_INSTR_MODE_EN_LSB 20
++#define CQSPI_REG_RD_INSTR_DUMMY_LSB 24
++#define CQSPI_REG_RD_INSTR_TYPE_INSTR_MASK 0x3
++#define CQSPI_REG_RD_INSTR_TYPE_ADDR_MASK 0x3
++#define CQSPI_REG_RD_INSTR_TYPE_DATA_MASK 0x3
++#define CQSPI_REG_RD_INSTR_DUMMY_MASK 0x1F
++
++#define CQSPI_REG_WR_INSTR 0x08
++#define CQSPI_REG_WR_INSTR_OPCODE_LSB 0
++#define CQSPI_REG_WR_INSTR_TYPE_ADDR_LSB 12
++#define CQSPI_REG_WR_INSTR_TYPE_DATA_LSB 16
++
++#define CQSPI_REG_DELAY 0x0C
++#define CQSPI_REG_DELAY_TSLCH_LSB 0
++#define CQSPI_REG_DELAY_TCHSH_LSB 8
++#define CQSPI_REG_DELAY_TSD2D_LSB 16
++#define CQSPI_REG_DELAY_TSHSL_LSB 24
++#define CQSPI_REG_DELAY_TSLCH_MASK 0xFF
++#define CQSPI_REG_DELAY_TCHSH_MASK 0xFF
++#define CQSPI_REG_DELAY_TSD2D_MASK 0xFF
++#define CQSPI_REG_DELAY_TSHSL_MASK 0xFF
++
++#define CQSPI_REG_READCAPTURE 0x10
++#define CQSPI_REG_READCAPTURE_BYPASS_LSB 0
++#define CQSPI_REG_READCAPTURE_DELAY_LSB 1
++#define CQSPI_REG_READCAPTURE_DELAY_MASK 0xF
++
++#define CQSPI_REG_SIZE 0x14
++#define CQSPI_REG_SIZE_ADDRESS_LSB 0
++#define CQSPI_REG_SIZE_PAGE_LSB 4
++#define CQSPI_REG_SIZE_BLOCK_LSB 16
++#define CQSPI_REG_SIZE_ADDRESS_MASK 0xF
++#define CQSPI_REG_SIZE_PAGE_MASK 0xFFF
++#define CQSPI_REG_SIZE_BLOCK_MASK 0x3F
++
++#define CQSPI_REG_SRAMPARTITION 0x18
++#define CQSPI_REG_INDIRECTTRIGGER 0x1C
++
++#define CQSPI_REG_DMA 0x20
++#define CQSPI_REG_DMA_SINGLE_LSB 0
++#define CQSPI_REG_DMA_BURST_LSB 8
++#define CQSPI_REG_DMA_SINGLE_MASK 0xFF
++#define CQSPI_REG_DMA_BURST_MASK 0xFF
++
++#define CQSPI_REG_REMAP 0x24
++#define CQSPI_REG_MODE_BIT 0x28
++
++#define CQSPI_REG_SDRAMLEVEL 0x2C
++#define CQSPI_REG_SDRAMLEVEL_RD_LSB 0
++#define CQSPI_REG_SDRAMLEVEL_WR_LSB 16
++#define CQSPI_REG_SDRAMLEVEL_RD_MASK 0xFFFF
++#define CQSPI_REG_SDRAMLEVEL_WR_MASK 0xFFFF
++
++#define CQSPI_REG_IRQSTATUS 0x40
++#define CQSPI_REG_IRQMASK 0x44
++
++#define CQSPI_REG_INDIRECTRD 0x60
++#define CQSPI_REG_INDIRECTRD_START_MASK BIT(0)
++#define CQSPI_REG_INDIRECTRD_CANCEL_MASK BIT(1)
++#define CQSPI_REG_INDIRECTRD_DONE_MASK BIT(5)
++
++#define CQSPI_REG_INDIRECTRDWATERMARK 0x64
++#define CQSPI_REG_INDIRECTRDSTARTADDR 0x68
++#define CQSPI_REG_INDIRECTRDBYTES 0x6C
++
++#define CQSPI_REG_CMDCTRL 0x90
++#define CQSPI_REG_CMDCTRL_EXECUTE_MASK BIT(0)
++#define CQSPI_REG_CMDCTRL_INPROGRESS_MASK BIT(1)
++#define CQSPI_REG_CMDCTRL_WR_BYTES_LSB 12
++#define CQSPI_REG_CMDCTRL_WR_EN_LSB 15
++#define CQSPI_REG_CMDCTRL_ADD_BYTES_LSB 16
++#define CQSPI_REG_CMDCTRL_ADDR_EN_LSB 19
++#define CQSPI_REG_CMDCTRL_RD_BYTES_LSB 20
++#define CQSPI_REG_CMDCTRL_RD_EN_LSB 23
++#define CQSPI_REG_CMDCTRL_OPCODE_LSB 24
++#define CQSPI_REG_CMDCTRL_WR_BYTES_MASK 0x7
++#define CQSPI_REG_CMDCTRL_ADD_BYTES_MASK 0x3
++#define CQSPI_REG_CMDCTRL_RD_BYTES_MASK 0x7
++
++#define CQSPI_REG_INDIRECTWR 0x70
++#define CQSPI_REG_INDIRECTWR_START_MASK BIT(0)
++#define CQSPI_REG_INDIRECTWR_CANCEL_MASK BIT(1)
++#define CQSPI_REG_INDIRECTWR_DONE_MASK BIT(5)
++
++#define CQSPI_REG_INDIRECTWRWATERMARK 0x74
++#define CQSPI_REG_INDIRECTWRSTARTADDR 0x78
++#define CQSPI_REG_INDIRECTWRBYTES 0x7C
++
++#define CQSPI_REG_CMDADDRESS 0x94
++#define CQSPI_REG_CMDREADDATALOWER 0xA0
++#define CQSPI_REG_CMDREADDATAUPPER 0xA4
++#define CQSPI_REG_CMDWRITEDATALOWER 0xA8
++#define CQSPI_REG_CMDWRITEDATAUPPER 0xAC
++
++/* Interrupt status bits */
++#define CQSPI_REG_IRQ_MODE_ERR BIT(0)
++#define CQSPI_REG_IRQ_UNDERFLOW BIT(1)
++#define CQSPI_REG_IRQ_IND_COMP BIT(2)
++#define CQSPI_REG_IRQ_IND_RD_REJECT BIT(3)
++#define CQSPI_REG_IRQ_WR_PROTECTED_ERR BIT(4)
++#define CQSPI_REG_IRQ_ILLEGAL_AHB_ERR BIT(5)
++#define CQSPI_REG_IRQ_WATERMARK BIT(6)
++#define CQSPI_REG_IRQ_IND_SRAM_FULL BIT(12)
++
++#define CQSPI_IRQ_MASK_RD (CQSPI_REG_IRQ_WATERMARK | \
++ CQSPI_REG_IRQ_IND_SRAM_FULL | \
++ CQSPI_REG_IRQ_IND_COMP)
++
++#define CQSPI_IRQ_MASK_WR (CQSPI_REG_IRQ_IND_COMP | \
++ CQSPI_REG_IRQ_WATERMARK | \
++ CQSPI_REG_IRQ_UNDERFLOW)
++
++#define CQSPI_IRQ_STATUS_MASK 0x1FFFF
++
++static int cqspi_wait_for_bit(void __iomem *reg, const u32 mask, bool clear)
++{
++ unsigned long end = jiffies + msecs_to_jiffies(CQSPI_TIMEOUT_MS);
++ u32 val;
++
++ while (1) {
++ val = readl(reg);
++ if (clear)
++ val = ~val;
++ val &= mask;
++
++ if (val == mask)
++ return 0;
++
++ if (time_after(jiffies, end))
++ return -ETIMEDOUT;
++ }
++}
++
++static bool cqspi_is_idle(struct cqspi_st *cqspi)
++{
++ u32 reg = readl(cqspi->iobase + CQSPI_REG_CONFIG);
++
++ return reg & (1 << CQSPI_REG_CONFIG_IDLE_LSB);
++}
++
++static u32 cqspi_get_rd_sram_level(struct cqspi_st *cqspi)
++{
++ u32 reg = readl(cqspi->iobase + CQSPI_REG_SDRAMLEVEL);
++
++ reg >>= CQSPI_REG_SDRAMLEVEL_RD_LSB;
++ return reg & CQSPI_REG_SDRAMLEVEL_RD_MASK;
++}
++
++static irqreturn_t cqspi_irq_handler(int this_irq, void *dev)
++{
++ struct cqspi_st *cqspi = dev;
++ unsigned int irq_status;
++
++ /* Read interrupt status */
++ irq_status = readl(cqspi->iobase + CQSPI_REG_IRQSTATUS);
++
++ /* Clear interrupt */
++ writel(irq_status, cqspi->iobase + CQSPI_REG_IRQSTATUS);
++
++ irq_status &= CQSPI_IRQ_MASK_RD | CQSPI_IRQ_MASK_WR;
++
++ if (irq_status)
++ complete(&cqspi->transfer_complete);
++
++ return IRQ_HANDLED;
++}
++
++static unsigned int cqspi_calc_rdreg(struct spi_nor *nor, const u8 opcode)
++{
++ unsigned int rdreg = 0;
++ struct cqspi_flash_pdata *f_pdata = nor->priv;
++
++ rdreg |= f_pdata->inst_width << CQSPI_REG_RD_INSTR_TYPE_INSTR_LSB;
++ rdreg |= f_pdata->addr_width << CQSPI_REG_RD_INSTR_TYPE_ADDR_LSB;
++
++ if (nor->flash_read == SPI_NOR_QUAD)
++ rdreg |= CQSPI_INST_TYPE_QUAD
++ << CQSPI_REG_RD_INSTR_TYPE_DATA_LSB;
++ return rdreg;
++}
++
++static int cqspi_wait_idle(struct cqspi_st *cqspi)
++{
++ const unsigned int poll_idle_retry = 3;
++ unsigned int count = 0;
++ unsigned long timeout;
++
++ timeout = jiffies + msecs_to_jiffies(CQSPI_TIMEOUT_MS);
++ while (1) {
++ /*
++ * Read few times in succession to ensure the controller
++ * is indeed idle, that is, the bit does not transition
++ * low again.
++ */
++ if (cqspi_is_idle(cqspi))
++ count++;
++ else
++ count = 0;
++
++ if (count >= poll_idle_retry)
++ return 0;
++
++ if (time_after(jiffies, timeout)) {
++ /* Timeout, in busy mode. */
++ dev_err(&cqspi->pdev->dev,
++ "QSPI is still busy after %dms timeout.\n",
++ CQSPI_TIMEOUT_MS);
++ return -ETIMEDOUT;
++ }
++
++ cpu_relax();
++ }
++}
++
++static int cqspi_exec_flash_cmd(struct cqspi_st *cqspi, unsigned int reg)
++{
++ void __iomem *reg_base = cqspi->iobase;
++ int ret;
++
++ /* Write the CMDCTRL without start execution. */
++ writel(reg, reg_base + CQSPI_REG_CMDCTRL);
++ /* Start execute */
++ reg |= CQSPI_REG_CMDCTRL_EXECUTE_MASK;
++ writel(reg, reg_base + CQSPI_REG_CMDCTRL);
++
++ /* Polling for completion. */
++ ret = cqspi_wait_for_bit(reg_base + CQSPI_REG_CMDCTRL,
++ CQSPI_REG_CMDCTRL_INPROGRESS_MASK, 1);
++ if (ret) {
++ dev_err(&cqspi->pdev->dev,
++ "Flash command execution timed out.\n");
++ return ret;
++ }
++
++ /* Polling QSPI idle status. */
++ return cqspi_wait_idle(cqspi);
++}
++
++static int cqspi_command_read(struct spi_nor *nor,
++ const u8 *txbuf, const unsigned n_tx,
++ u8 *rxbuf, const unsigned n_rx)
++{
++ struct cqspi_flash_pdata *f_pdata = nor->priv;
++ struct cqspi_st *cqspi = f_pdata->cqspi;
++ void __iomem *reg_base = cqspi->iobase;
++ unsigned int rdreg;
++ unsigned int reg;
++ unsigned int read_len;
++ int status;
++
++ if (!n_rx || n_rx > CQSPI_STIG_DATA_LEN_MAX || !rxbuf) {
++ dev_err(nor->dev, "Invalid input argument, len %d rxbuf 0x%p\n",
++ n_rx, rxbuf);
++ return -EINVAL;
++ }
++
++ reg = txbuf[0] << CQSPI_REG_CMDCTRL_OPCODE_LSB;
++
++ rdreg = cqspi_calc_rdreg(nor, txbuf[0]);
++ writel(rdreg, reg_base + CQSPI_REG_RD_INSTR);
++
++ reg |= (0x1 << CQSPI_REG_CMDCTRL_RD_EN_LSB);
++
++ /* 0 means 1 byte. */
++ reg |= (((n_rx - 1) & CQSPI_REG_CMDCTRL_RD_BYTES_MASK)
++ << CQSPI_REG_CMDCTRL_RD_BYTES_LSB);
++ status = cqspi_exec_flash_cmd(cqspi, reg);
++ if (status)
++ return status;
++
++ reg = readl(reg_base + CQSPI_REG_CMDREADDATALOWER);
++
++ /* Put the read value into rx_buf */
++ read_len = (n_rx > 4) ? 4 : n_rx;
++ memcpy(rxbuf, ®, read_len);
++ rxbuf += read_len;
++
++ if (n_rx > 4) {
++ reg = readl(reg_base + CQSPI_REG_CMDREADDATAUPPER);
++
++ read_len = n_rx - read_len;
++ memcpy(rxbuf, ®, read_len);
++ }
++
++ return 0;
++}
++
++static int cqspi_command_write(struct spi_nor *nor, const u8 opcode,
++ const u8 *txbuf, const unsigned n_tx)
++{
++ struct cqspi_flash_pdata *f_pdata = nor->priv;
++ struct cqspi_st *cqspi = f_pdata->cqspi;
++ void __iomem *reg_base = cqspi->iobase;
++ unsigned int reg;
++ unsigned int data;
++ int ret;
++
++ if (n_tx > 4 || (n_tx && !txbuf)) {
++ dev_err(nor->dev,
++ "Invalid input argument, cmdlen %d txbuf 0x%p\n",
++ n_tx, txbuf);
++ return -EINVAL;
++ }
++
++ reg = opcode << CQSPI_REG_CMDCTRL_OPCODE_LSB;
++ if (n_tx) {
++ reg |= (0x1 << CQSPI_REG_CMDCTRL_WR_EN_LSB);
++ reg |= ((n_tx - 1) & CQSPI_REG_CMDCTRL_WR_BYTES_MASK)
++ << CQSPI_REG_CMDCTRL_WR_BYTES_LSB;
++ data = 0;
++ memcpy(&data, txbuf, n_tx);
++ writel(data, reg_base + CQSPI_REG_CMDWRITEDATALOWER);
++ }
++
++ ret = cqspi_exec_flash_cmd(cqspi, reg);
++ return ret;
++}
++
++static int cqspi_command_write_addr(struct spi_nor *nor,
++ const u8 opcode, const unsigned int addr)
++{
++ struct cqspi_flash_pdata *f_pdata = nor->priv;
++ struct cqspi_st *cqspi = f_pdata->cqspi;
++ void __iomem *reg_base = cqspi->iobase;
++ unsigned int reg;
++
++ reg = opcode << CQSPI_REG_CMDCTRL_OPCODE_LSB;
++ reg |= (0x1 << CQSPI_REG_CMDCTRL_ADDR_EN_LSB);
++ reg |= ((nor->addr_width - 1) & CQSPI_REG_CMDCTRL_ADD_BYTES_MASK)
++ << CQSPI_REG_CMDCTRL_ADD_BYTES_LSB;
++
++ writel(addr, reg_base + CQSPI_REG_CMDADDRESS);
++
++ return cqspi_exec_flash_cmd(cqspi, reg);
++}
++
++static int cqspi_indirect_read_setup(struct spi_nor *nor,
++ const unsigned int from_addr)
++{
++ struct cqspi_flash_pdata *f_pdata = nor->priv;
++ struct cqspi_st *cqspi = f_pdata->cqspi;
++ void __iomem *reg_base = cqspi->iobase;
++ unsigned int dummy_clk = 0;
++ unsigned int reg;
++
++ writel(from_addr, reg_base + CQSPI_REG_INDIRECTRDSTARTADDR);
++
++ reg = nor->read_opcode << CQSPI_REG_RD_INSTR_OPCODE_LSB;
++ reg |= cqspi_calc_rdreg(nor, nor->read_opcode);
++
++ /* Setup dummy clock cycles */
++ dummy_clk = nor->read_dummy;
++ if (dummy_clk > CQSPI_DUMMY_CLKS_MAX)
++ dummy_clk = CQSPI_DUMMY_CLKS_MAX;
++
++ if (dummy_clk / 8) {
++ reg |= (1 << CQSPI_REG_RD_INSTR_MODE_EN_LSB);
++ /* Set mode bits high to ensure chip doesn't enter XIP */
++ writel(0xFF, reg_base + CQSPI_REG_MODE_BIT);
++
++ /* Need to subtract the mode byte (8 clocks). */
++ if (f_pdata->inst_width != CQSPI_INST_TYPE_QUAD)
++ dummy_clk -= 8;
++
++ if (dummy_clk)
++ reg |= (dummy_clk & CQSPI_REG_RD_INSTR_DUMMY_MASK)
++ << CQSPI_REG_RD_INSTR_DUMMY_LSB;
++ }
++
++ writel(reg, reg_base + CQSPI_REG_RD_INSTR);
++
++ /* Set address width */
++ reg = readl(reg_base + CQSPI_REG_SIZE);
++ reg &= ~CQSPI_REG_SIZE_ADDRESS_MASK;
++ reg |= (nor->addr_width - 1);
++ writel(reg, reg_base + CQSPI_REG_SIZE);
++ return 0;
++}
++
++static int cqspi_indirect_read_execute(struct spi_nor *nor,
++ u8 *rxbuf, const unsigned n_rx)
++{
++ struct cqspi_flash_pdata *f_pdata = nor->priv;
++ struct cqspi_st *cqspi = f_pdata->cqspi;
++ void __iomem *reg_base = cqspi->iobase;
++ void __iomem *ahb_base = cqspi->ahb_base;
++ unsigned int remaining = n_rx;
++ unsigned int bytes_to_read = 0;
++ int ret = 0;
++
++ writel(remaining, reg_base + CQSPI_REG_INDIRECTRDBYTES);
++
++ /* Clear all interrupts. */
++ writel(CQSPI_IRQ_STATUS_MASK, reg_base + CQSPI_REG_IRQSTATUS);
++
++ writel(CQSPI_IRQ_MASK_RD, reg_base + CQSPI_REG_IRQMASK);
++
++ reinit_completion(&cqspi->transfer_complete);
++ writel(CQSPI_REG_INDIRECTRD_START_MASK,
++ reg_base + CQSPI_REG_INDIRECTRD);
++
++ while (remaining > 0) {
++ ret = wait_for_completion_timeout(&cqspi->transfer_complete,
++ msecs_to_jiffies
++ (CQSPI_READ_TIMEOUT_MS));
++
++ bytes_to_read = cqspi_get_rd_sram_level(cqspi);
++
++ if (!ret && bytes_to_read == 0) {
++ dev_err(nor->dev, "Indirect read timeout, no bytes\n");
++ ret = -ETIMEDOUT;
++ goto failrd;
++ }
++
++ while (bytes_to_read != 0) {
++ bytes_to_read *= cqspi->fifo_width;
++ bytes_to_read = bytes_to_read > remaining ?
++ remaining : bytes_to_read;
++ readsl(ahb_base, rxbuf, DIV_ROUND_UP(bytes_to_read, 4));
++ rxbuf += bytes_to_read;
++ remaining -= bytes_to_read;
++ bytes_to_read = cqspi_get_rd_sram_level(cqspi);
++ }
++
++ if (remaining > 0)
++ reinit_completion(&cqspi->transfer_complete);
++ }
++
++ /* Check indirect done status */
++ ret = cqspi_wait_for_bit(reg_base + CQSPI_REG_INDIRECTRD,
++ CQSPI_REG_INDIRECTRD_DONE_MASK, 0);
++ if (ret) {
++ dev_err(nor->dev,
++ "Indirect read completion error (%i)\n", ret);
++ goto failrd;
++ }
++
++ /* Disable interrupt */
++ writel(0, reg_base + CQSPI_REG_IRQMASK);
++
++ /* Clear indirect completion status */
++ writel(CQSPI_REG_INDIRECTRD_DONE_MASK, reg_base + CQSPI_REG_INDIRECTRD);
++
++ return 0;
++
++failrd:
++ /* Disable interrupt */
++ writel(0, reg_base + CQSPI_REG_IRQMASK);
++
++ /* Cancel the indirect read */
++ writel(CQSPI_REG_INDIRECTWR_CANCEL_MASK,
++ reg_base + CQSPI_REG_INDIRECTRD);
++ return ret;
++}
++
++static int cqspi_indirect_write_setup(struct spi_nor *nor,
++ const unsigned int to_addr)
++{
++ unsigned int reg;
++ struct cqspi_flash_pdata *f_pdata = nor->priv;
++ struct cqspi_st *cqspi = f_pdata->cqspi;
++ void __iomem *reg_base = cqspi->iobase;
++
++ /* Set opcode. */
++ reg = nor->program_opcode << CQSPI_REG_WR_INSTR_OPCODE_LSB;
++ writel(reg, reg_base + CQSPI_REG_WR_INSTR);
++ reg = cqspi_calc_rdreg(nor, nor->program_opcode);
++ writel(reg, reg_base + CQSPI_REG_RD_INSTR);
++
++ writel(to_addr, reg_base + CQSPI_REG_INDIRECTWRSTARTADDR);
++
++ reg = readl(reg_base + CQSPI_REG_SIZE);
++ reg &= ~CQSPI_REG_SIZE_ADDRESS_MASK;
++ reg |= (nor->addr_width - 1);
++ writel(reg, reg_base + CQSPI_REG_SIZE);
++ return 0;
++}
++
++static int cqspi_indirect_write_execute(struct spi_nor *nor,
++ const u8 *txbuf, const unsigned n_tx)
++{
++ const unsigned int page_size = nor->page_size;
++ struct cqspi_flash_pdata *f_pdata = nor->priv;
++ struct cqspi_st *cqspi = f_pdata->cqspi;
++ void __iomem *reg_base = cqspi->iobase;
++ unsigned int remaining = n_tx;
++ unsigned int write_bytes;
++ int ret;
++
++ writel(remaining, reg_base + CQSPI_REG_INDIRECTWRBYTES);
++
++ /* Clear all interrupts. */
++ writel(CQSPI_IRQ_STATUS_MASK, reg_base + CQSPI_REG_IRQSTATUS);
++
++ writel(CQSPI_IRQ_MASK_WR, reg_base + CQSPI_REG_IRQMASK);
++
++ reinit_completion(&cqspi->transfer_complete);
++ writel(CQSPI_REG_INDIRECTWR_START_MASK,
++ reg_base + CQSPI_REG_INDIRECTWR);
++
++ while (remaining > 0) {
++ write_bytes = remaining > page_size ? page_size : remaining;
++ writesl(cqspi->ahb_base, txbuf, DIV_ROUND_UP(write_bytes, 4));
++
++ ret = wait_for_completion_timeout(&cqspi->transfer_complete,
++ msecs_to_jiffies
++ (CQSPI_TIMEOUT_MS));
++ if (!ret) {
++ dev_err(nor->dev, "Indirect write timeout\n");
++ ret = -ETIMEDOUT;
++ goto failwr;
++ }
++
++ txbuf += write_bytes;
++ remaining -= write_bytes;
++
++ if (remaining > 0)
++ reinit_completion(&cqspi->transfer_complete);
++ }
++
++ /* Check indirect done status */
++ ret = cqspi_wait_for_bit(reg_base + CQSPI_REG_INDIRECTWR,
++ CQSPI_REG_INDIRECTWR_DONE_MASK, 0);
++ if (ret) {
++ dev_err(nor->dev,
++ "Indirect write completion error (%i)\n", ret);
++ goto failwr;
++ }
++
++ /* Disable interrupt. */
++ writel(0, reg_base + CQSPI_REG_IRQMASK);
++
++ /* Clear indirect completion status */
++ writel(CQSPI_REG_INDIRECTWR_DONE_MASK, reg_base + CQSPI_REG_INDIRECTWR);
++
++ cqspi_wait_idle(cqspi);
++
++ return 0;
++
++failwr:
++ /* Disable interrupt. */
++ writel(0, reg_base + CQSPI_REG_IRQMASK);
++
++ /* Cancel the indirect write */
++ writel(CQSPI_REG_INDIRECTWR_CANCEL_MASK,
++ reg_base + CQSPI_REG_INDIRECTWR);
++ return ret;
++}
++
++static int cqspi_set_protocol(struct spi_nor *nor, enum spi_nor_protocol proto)
++{
++ struct cqspi_flash_pdata *f_pdata = nor->priv;
++
++ switch (proto) {
++ case SNOR_PROTO_1_1_1:
++ case SNOR_PROTO_1_1_2:
++ case SNOR_PROTO_1_1_4:
++ case SNOR_PROTO_1_2_2:
++ case SNOR_PROTO_1_4_4:
++ f_pdata->inst_width = CQSPI_INST_TYPE_SINGLE;
++ break;
++ case SNOR_PROTO_2_2_2:
++ f_pdata->inst_width = CQSPI_INST_TYPE_DUAL;
++ break;
++ case SNOR_PROTO_4_4_4:
++ f_pdata->inst_width = CQSPI_INST_TYPE_QUAD;
++ break;
++ default:
++ return -EINVAL;
++ }
++
++ switch (proto) {
++ case SNOR_PROTO_1_1_1:
++ case SNOR_PROTO_1_1_2:
++ case SNOR_PROTO_1_1_4:
++ f_pdata->addr_width = CQSPI_INST_TYPE_SINGLE;
++ break;
++ case SNOR_PROTO_1_2_2:
++ case SNOR_PROTO_2_2_2:
++ f_pdata->addr_width = CQSPI_INST_TYPE_DUAL;
++ break;
++ case SNOR_PROTO_1_4_4:
++ case SNOR_PROTO_4_4_4:
++ f_pdata->addr_width = CQSPI_INST_TYPE_QUAD;
++ break;
++ default:
++ return -EINVAL;
++ }
++
++ return 0;
++}
++
++static void cqspi_write(struct spi_nor *nor, loff_t to,
++ size_t len, size_t *retlen, const u_char *buf)
++{
++ int ret;
++
++ ret = cqspi_set_protocol(nor, nor->write_proto);
++ if (ret)
++ return;
++
++ ret = cqspi_indirect_write_setup(nor, to);
++ if (ret)
++ return;
++
++ ret = cqspi_indirect_write_execute(nor, buf, len);
++ if (ret)
++ return;
++
++ *retlen += len;
++}
++
++static int cqspi_read(struct spi_nor *nor, loff_t from,
++ size_t len, size_t *retlen, u_char *buf)
++{
++ int ret;
++
++ ret = cqspi_set_protocol(nor, nor->read_proto);
++ if (ret)
++ return ret;
++
++ ret = cqspi_indirect_read_setup(nor, from);
++ if (ret)
++ return ret;
++
++ ret = cqspi_indirect_read_execute(nor, buf, len);
++ if (ret)
++ return ret;
++
++ *retlen += len;
++ return ret;
++}
++
++static int cqspi_erase(struct spi_nor *nor, loff_t offs)
++{
++ int ret;
++
++ ret = cqspi_set_protocol(nor, nor->erase_proto);
++ if (ret)
++ return ret;
++
++ /* Send write enable, then erase commands. */
++ ret = nor->write_reg(nor, SPINOR_OP_WREN, NULL, 0);
++ if (ret)
++ return ret;
++
++ /* Set up command buffer. */
++ ret = cqspi_command_write_addr(nor, nor->erase_opcode, offs);
++ if (ret)
++ return ret;
++
++ return 0;
++}
++
++static unsigned int calculate_ticks_for_ns(const unsigned int ref_clk_hz,
++ const unsigned int ns_val)
++{
++ unsigned int ticks;
++
++ ticks = ref_clk_hz / 1000; /* kHz */
++ ticks = DIV_ROUND_UP(ticks * ns_val, 1000000);
++
++ return ticks;
++}
++
++static void cqspi_delay(struct spi_nor *nor, const unsigned int sclk_hz)
++{
++ struct cqspi_flash_pdata *f_pdata = nor->priv;
++ struct cqspi_st *cqspi = f_pdata->cqspi;
++ void __iomem *iobase = cqspi->iobase;
++ const unsigned int ref_clk_hz = cqspi->master_ref_clk_hz;
++ unsigned int tshsl, tchsh, tslch, tsd2d;
++ unsigned int reg;
++ unsigned int tsclk;
++
++ /* calculate the number of ref ticks for one sclk tick */
++ tsclk = (ref_clk_hz + sclk_hz - 1) / sclk_hz;
++
++ tshsl = calculate_ticks_for_ns(ref_clk_hz, f_pdata->tshsl_ns);
++ /* this particular value must be at least one sclk */
++ if (tshsl < tsclk)
++ tshsl = tsclk;
++
++ tchsh = calculate_ticks_for_ns(ref_clk_hz, f_pdata->tchsh_ns);
++ tslch = calculate_ticks_for_ns(ref_clk_hz, f_pdata->tslch_ns);
++ tsd2d = calculate_ticks_for_ns(ref_clk_hz, f_pdata->tsd2d_ns);
++
++ reg = (tshsl & CQSPI_REG_DELAY_TSHSL_MASK)
++ << CQSPI_REG_DELAY_TSHSL_LSB;
++ reg |= (tchsh & CQSPI_REG_DELAY_TCHSH_MASK)
++ << CQSPI_REG_DELAY_TCHSH_LSB;
++ reg |= (tslch & CQSPI_REG_DELAY_TSLCH_MASK)
++ << CQSPI_REG_DELAY_TSLCH_LSB;
++ reg |= (tsd2d & CQSPI_REG_DELAY_TSD2D_MASK)
++ << CQSPI_REG_DELAY_TSD2D_LSB;
++ writel(reg, iobase + CQSPI_REG_DELAY);
++}
++
++static void cqspi_config_baudrate_div(struct cqspi_st *cqspi,
++ const unsigned int sclk_hz)
++{
++ const unsigned int ref_clk_hz = cqspi->master_ref_clk_hz;
++ void __iomem *reg_base = cqspi->iobase;
++ unsigned int reg;
++ unsigned int div;
++
++ reg = readl(reg_base + CQSPI_REG_CONFIG);
++ reg &= ~(CQSPI_REG_CONFIG_BAUD_MASK << CQSPI_REG_CONFIG_BAUD_LSB);
++
++ div = ref_clk_hz / sclk_hz;
++
++ /* Recalculate the baudrate divisor based on QSPI specification. */
++ if (div > 32)
++ div = 32;
++
++ /* Check if even number. */
++ if (div & 1)
++ div = (div / 2);
++ else
++ div = (div / 2) - 1;
++
++ div = (div & CQSPI_REG_CONFIG_BAUD_MASK) << CQSPI_REG_CONFIG_BAUD_LSB;
++ reg |= div;
++ writel(reg, reg_base + CQSPI_REG_CONFIG);
++}
++
++static void cqspi_readdata_capture(struct cqspi_st *cqspi,
++ const unsigned int bypass,
++ const unsigned int delay)
++{
++ void __iomem *reg_base = cqspi->iobase;
++ unsigned int reg;
++
++ reg = readl(reg_base + CQSPI_REG_READCAPTURE);
++
++ if (bypass)
++ reg |= (1 << CQSPI_REG_READCAPTURE_BYPASS_LSB);
++ else
++ reg &= ~(1 << CQSPI_REG_READCAPTURE_BYPASS_LSB);
++
++ reg &= ~(CQSPI_REG_READCAPTURE_DELAY_MASK
++ << CQSPI_REG_READCAPTURE_DELAY_LSB);
++
++ reg |= (delay & CQSPI_REG_READCAPTURE_DELAY_MASK)
++ << CQSPI_REG_READCAPTURE_DELAY_LSB;
++
++ writel(reg, reg_base + CQSPI_REG_READCAPTURE);
++}
++
++static void cqspi_chipselect(struct spi_nor *nor)
++{
++ struct cqspi_flash_pdata *f_pdata = nor->priv;
++ struct cqspi_st *cqspi = f_pdata->cqspi;
++ void __iomem *reg_base = cqspi->iobase;
++ unsigned int chip_select = f_pdata->cs;
++ unsigned int reg;
++
++ reg = readl(reg_base + CQSPI_REG_CONFIG);
++ if (cqspi->is_decoded_cs) {
++ reg |= CQSPI_REG_CONFIG_DECODE_MASK;
++ } else {
++ reg &= ~CQSPI_REG_CONFIG_DECODE_MASK;
++
++ /* Convert CS if without decoder.
++ * CS0 to 4b'1110
++ * CS1 to 4b'1101
++ * CS2 to 4b'1011
++ * CS3 to 4b'0111
++ */
++ chip_select = 0xF & ~(1 << chip_select);
++ }
++
++ reg &= ~(CQSPI_REG_CONFIG_CHIPSELECT_MASK
++ << CQSPI_REG_CONFIG_CHIPSELECT_LSB);
++ reg |= (chip_select & CQSPI_REG_CONFIG_CHIPSELECT_MASK)
++ << CQSPI_REG_CONFIG_CHIPSELECT_LSB;
++ writel(reg, reg_base + CQSPI_REG_CONFIG);
++}
++
++static void cqspi_controller_enable(struct cqspi_st *cqspi, bool enable)
++{
++ void __iomem *reg_base = cqspi->iobase;
++ unsigned int reg;
++
++ reg = readl(reg_base + CQSPI_REG_CONFIG);
++
++ if (enable)
++ reg |= CQSPI_REG_CONFIG_ENABLE_MASK;
++ else
++ reg &= ~CQSPI_REG_CONFIG_ENABLE_MASK;
++
++ writel(reg, reg_base + CQSPI_REG_CONFIG);
++}
++
++static void cqspi_switch_cs(struct spi_nor *nor)
++{
++ struct cqspi_flash_pdata *f_pdata = nor->priv;
++ struct cqspi_st *cqspi = f_pdata->cqspi;
++ void __iomem *iobase = cqspi->iobase;
++ unsigned int reg;
++
++ /* configure page size and block size. */
++ reg = readl(iobase + CQSPI_REG_SIZE);
++ reg &= ~(CQSPI_REG_SIZE_PAGE_MASK << CQSPI_REG_SIZE_PAGE_LSB);
++ reg &= ~(CQSPI_REG_SIZE_BLOCK_MASK << CQSPI_REG_SIZE_BLOCK_LSB);
++ reg &= ~CQSPI_REG_SIZE_ADDRESS_MASK;
++ reg |= (nor->page_size << CQSPI_REG_SIZE_PAGE_LSB);
++ reg |= (ilog2(nor->mtd.erasesize) << CQSPI_REG_SIZE_BLOCK_LSB);
++ reg |= (nor->addr_width - 1);
++ writel(reg, iobase + CQSPI_REG_SIZE);
++
++ /* configure the chip select */
++ cqspi_chipselect(nor);
++}
++
++static int cqspi_prep_unlocked(struct spi_nor *nor, enum spi_nor_ops ops)
++{
++ struct cqspi_flash_pdata *f_pdata = nor->priv;
++ struct cqspi_st *cqspi = f_pdata->cqspi;
++ const unsigned int sclk = f_pdata->clk_rate;
++ const int switch_cs = (cqspi->current_cs != f_pdata->cs);
++ const int switch_ck = (cqspi->sclk != sclk);
++
++ if (switch_cs || switch_ck)
++ cqspi_controller_enable(cqspi, 0);
++
++ /* Switch chip select. */
++ if (switch_cs) {
++ cqspi->current_cs = f_pdata->cs;
++ cqspi_switch_cs(nor);
++ }
++
++ /* Setup baudrate divisor and delays */
++ if (switch_ck) {
++ cqspi->sclk = sclk;
++ cqspi_config_baudrate_div(cqspi, sclk);
++ cqspi_delay(nor, sclk);
++ cqspi_readdata_capture(cqspi, 1, f_pdata->read_delay);
++ }
++
++ if (switch_cs || switch_ck)
++ cqspi_controller_enable(cqspi, 1);
++
++ return 0;
++}
++
++static int cqspi_prep(struct spi_nor *nor, enum spi_nor_ops ops)
++{
++ struct cqspi_flash_pdata *f_pdata = nor->priv;
++ struct cqspi_st *cqspi = f_pdata->cqspi;
++
++ mutex_lock(&cqspi->bus_mutex);
++
++ return cqspi_prep_unlocked(nor, ops);
++}
++
++static void cqspi_unprep(struct spi_nor *nor, enum spi_nor_ops ops)
++{
++ struct cqspi_flash_pdata *f_pdata = nor->priv;
++ struct cqspi_st *cqspi = f_pdata->cqspi;
++
++ mutex_unlock(&cqspi->bus_mutex);
++}
++
++static int cqspi_read_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
++{
++ int ret;
++
++ ret = cqspi_set_protocol(nor, nor->reg_proto);
++ if (ret)
++ goto exit;
++
++ cqspi_prep_unlocked(nor, SPI_NOR_OPS_READ);
++
++ ret = cqspi_command_read(nor, &opcode, 1, buf, len);
++exit:
++ return ret;
++}
++
++static int cqspi_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
++{
++ int ret;
++
++ ret = cqspi_set_protocol(nor, nor->reg_proto);
++ if (ret)
++ goto exit;
++
++ cqspi_prep_unlocked(nor, SPI_NOR_OPS_WRITE);
++
++ ret = cqspi_command_write(nor, opcode, buf, len);
++exit:
++ return ret;
++}
++
++static int cqspi_of_get_flash_pdata(struct platform_device *pdev,
++ struct cqspi_flash_pdata *f_pdata,
++ struct device_node *np)
++{
++ if (of_property_read_u32(np, "cdns,read-delay", &f_pdata->read_delay)) {
++ dev_err(&pdev->dev, "couldn't determine read-delay\n");
++ return -ENXIO;
++ }
++
++ if (of_property_read_u32(np, "cdns,tshsl-ns", &f_pdata->tshsl_ns)) {
++ dev_err(&pdev->dev, "couldn't determine tshsl-ns\n");
++ return -ENXIO;
++ }
++
++ if (of_property_read_u32(np, "cdns,tsd2d-ns", &f_pdata->tsd2d_ns)) {
++ dev_err(&pdev->dev, "couldn't determine tsd2d-ns\n");
++ return -ENXIO;
++ }
++
++ if (of_property_read_u32(np, "cdns,tchsh-ns", &f_pdata->tchsh_ns)) {
++ dev_err(&pdev->dev, "couldn't determine tchsh-ns\n");
++ return -ENXIO;
++ }
++
++ if (of_property_read_u32(np, "cdns,tslch-ns", &f_pdata->tslch_ns)) {
++ dev_err(&pdev->dev, "couldn't determine tslch-ns\n");
++ return -ENXIO;
++ }
++
++ if (of_property_read_u32(np, "spi-max-frequency", &f_pdata->clk_rate)) {
++ dev_err(&pdev->dev, "couldn't determine spi-max-frequency\n");
++ return -ENXIO;
++ }
++
++ return 0;
++}
++
++static int cqspi_of_get_pdata(struct platform_device *pdev)
++{
++ struct device_node *np = pdev->dev.of_node;
++ struct cqspi_st *cqspi = platform_get_drvdata(pdev);
++
++ cqspi->is_decoded_cs = of_property_read_bool(np, "cdns,is-decoded-cs");
++
++ if (of_property_read_u32(np, "cdns,fifo-depth", &cqspi->fifo_depth)) {
++ dev_err(&pdev->dev, "couldn't determine fifo-depth\n");
++ return -ENXIO;
++ }
++
++ if (of_property_read_u32(np, "cdns,fifo-width", &cqspi->fifo_width)) {
++ dev_err(&pdev->dev, "couldn't determine fifo-width\n");
++ return -ENXIO;
++ }
++
++ if (of_property_read_u32(np, "cdns,trigger-address",
++ &cqspi->trigger_address)) {
++ dev_err(&pdev->dev, "couldn't determine trigger-address\n");
++ return -ENXIO;
++ }
++
++ return 0;
++}
++
++static void cqspi_controller_init(struct cqspi_st *cqspi)
++{
++ cqspi_controller_enable(cqspi, 0);
++
++ /* Configure the remap address register, no remap */
++ writel(0, cqspi->iobase + CQSPI_REG_REMAP);
++
++ /* Disable all interrupts. */
++ writel(0, cqspi->iobase + CQSPI_REG_IRQMASK);
++
++ /* Configure the SRAM split to 1:1 . */
++ writel(cqspi->fifo_depth / 2, cqspi->iobase + CQSPI_REG_SRAMPARTITION);
++
++ /* Load indirect trigger address. */
++ writel(cqspi->trigger_address,
++ cqspi->iobase + CQSPI_REG_INDIRECTTRIGGER);
++
++ /* Program read watermark -- 1/2 of the FIFO. */
++ writel(cqspi->fifo_depth * cqspi->fifo_width / 2,
++ cqspi->iobase + CQSPI_REG_INDIRECTRDWATERMARK);
++ /* Program write watermark -- 1/8 of the FIFO. */
++ writel(cqspi->fifo_depth * cqspi->fifo_width / 8,
++ cqspi->iobase + CQSPI_REG_INDIRECTWRWATERMARK);
++
++ cqspi_controller_enable(cqspi, 1);
++}
++
++static int cqspi_setup_flash(struct cqspi_st *cqspi, struct device_node *np)
++{
++ struct platform_device *pdev = cqspi->pdev;
++ struct device *dev = &pdev->dev;
++ struct cqspi_flash_pdata *f_pdata;
++ struct spi_nor *nor;
++ struct mtd_info *mtd;
++ unsigned int cs;
++ int i, ret;
++
++ /* Get flash device data */
++ for_each_available_child_of_node(dev->of_node, np) {
++ if (of_property_read_u32(np, "reg", &cs)) {
++ dev_err(dev, "Couldn't determine chip select.\n");
++ goto err;
++ }
++
++ if (cs > CQSPI_MAX_CHIPSELECT) {
++ dev_err(dev, "Chip select %d out of range.\n", cs);
++ goto err;
++ }
++
++ f_pdata = &cqspi->f_pdata[cs];
++ f_pdata->cqspi = cqspi;
++ f_pdata->cs = cs;
++
++ ret = cqspi_of_get_flash_pdata(pdev, f_pdata, np);
++ if (ret)
++ goto err;
++
++ nor = &f_pdata->nor;
++ mtd = &nor->mtd;
++
++ mtd->priv = nor;
++
++ nor->dev = dev;
++ spi_nor_set_flash_node(nor, np);
++ nor->priv = f_pdata;
++
++ nor->read_reg = cqspi_read_reg;
++ nor->write_reg = cqspi_write_reg;
++ nor->read = cqspi_read;
++ nor->write = cqspi_write;
++ nor->erase = cqspi_erase;
++ nor->prepare = cqspi_prep;
++ nor->unprepare = cqspi_unprep;
++
++ mtd->name = kasprintf(GFP_KERNEL, "%s.%d", dev_name(dev), cs);
++ if (!mtd->name) {
++ ret = -ENOMEM;
++ goto err;
++ }
++
++ ret = spi_nor_scan(nor, NULL, SPI_NOR_QUAD);
++ if (ret)
++ goto err;
++
++ ret = mtd_device_register(mtd, NULL, 0);
++ if (ret)
++ goto err;
++ }
++
++ return 0;
++
++err:
++ for (i = 0; i < CQSPI_MAX_CHIPSELECT; i++)
++ if (cqspi->f_pdata[i].nor.mtd.name) {
++ mtd_device_unregister(&cqspi->f_pdata[i].nor.mtd);
++ kfree(cqspi->f_pdata[i].nor.mtd.name);
++ }
++ return ret;
++}
++
++static int cqspi_probe(struct platform_device *pdev)
++{
++ struct device_node *np = pdev->dev.of_node;
++ struct device *dev = &pdev->dev;
++ struct cqspi_st *cqspi;
++ struct resource *res;
++ struct resource *res_ahb;
++ int ret;
++ int irq;
++
++ cqspi = devm_kzalloc(dev, sizeof(*cqspi), GFP_KERNEL);
++ if (!cqspi)
++ return -ENOMEM;
++
++ mutex_init(&cqspi->bus_mutex);
++ cqspi->pdev = pdev;
++ platform_set_drvdata(pdev, cqspi);
++
++ /* Obtain configuration from OF. */
++ ret = cqspi_of_get_pdata(pdev);
++ if (ret) {
++ dev_err(dev, "Cannot get mandatory OF data.\n");
++ return -ENODEV;
++ }
++
++ /* Obtain QSPI clock. */
++ cqspi->clk = devm_clk_get(dev, NULL);
++ if (IS_ERR(cqspi->clk)) {
++ dev_err(dev, "Cannot claim QSPI clock.\n");
++ return PTR_ERR(cqspi->clk);
++ }
++
++ /* Obtain and remap controller address. */
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ cqspi->iobase = devm_ioremap_resource(dev, res);
++ if (IS_ERR(cqspi->iobase)) {
++ dev_err(dev, "Cannot remap controller address.\n");
++ return PTR_ERR(cqspi->iobase);
++ }
++
++ /* Obtain and remap AHB address. */
++ res_ahb = platform_get_resource(pdev, IORESOURCE_MEM, 1);
++ cqspi->ahb_base = devm_ioremap_resource(dev, res_ahb);
++ if (IS_ERR(cqspi->ahb_base)) {
++ dev_err(dev, "Cannot remap AHB address.\n");
++ return PTR_ERR(cqspi->ahb_base);
++ }
++
++ init_completion(&cqspi->transfer_complete);
++
++ /* Obtain IRQ line. */
++ irq = platform_get_irq(pdev, 0);
++ if (irq < 0) {
++ dev_err(dev, "Cannot obtain IRQ.\n");
++ return -ENXIO;
++ }
++
++ ret = clk_prepare_enable(cqspi->clk);
++ if (ret) {
++ dev_err(dev, "Cannot enable QSPI clock.\n");
++ return ret;
++ }
++
++ cqspi->master_ref_clk_hz = clk_get_rate(cqspi->clk);
++
++ ret = devm_request_irq(dev, irq, cqspi_irq_handler, 0,
++ pdev->name, cqspi);
++ if (ret) {
++ dev_err(dev, "Cannot request IRQ.\n");
++ goto probe_irq_failed;
++ }
++
++ cqspi_wait_idle(cqspi);
++ cqspi_controller_init(cqspi);
++ cqspi->current_cs = -1;
++ cqspi->sclk = 0;
++
++ ret = cqspi_setup_flash(cqspi, np);
++ if (ret) {
++ dev_err(dev, "Cadence QSPI NOR probe failed %d\n", ret);
++ goto probe_setup_failed;
++ }
++
++ return ret;
++probe_irq_failed:
++ cqspi_controller_enable(cqspi, 0);
++probe_setup_failed:
++ clk_disable_unprepare(cqspi->clk);
++ return ret;
++}
++
++static int cqspi_remove(struct platform_device *pdev)
++{
++ struct cqspi_st *cqspi = platform_get_drvdata(pdev);
++ int i;
++
++ cqspi_controller_enable(cqspi, 0);
++
++ for (i = 0; i < CQSPI_MAX_CHIPSELECT; i++)
++ if (cqspi->f_pdata[i].nor.mtd.name) {
++ mtd_device_unregister(&cqspi->f_pdata[i].nor.mtd);
++ kfree(cqspi->f_pdata[i].nor.mtd.name);
++ }
++
++ clk_disable_unprepare(cqspi->clk);
++
++ return 0;
++}
++
++#ifdef CONFIG_PM_SLEEP
++static int cqspi_suspend(struct device *dev)
++{
++ struct cqspi_st *cqspi = dev_get_drvdata(dev);
++
++ cqspi_controller_enable(cqspi, 0);
++ return 0;
++}
++
++static int cqspi_resume(struct device *dev)
++{
++ struct cqspi_st *cqspi = dev_get_drvdata(dev);
++
++ cqspi_controller_enable(cqspi, 1);
++ return 0;
++}
++
++static const struct dev_pm_ops cqspi__dev_pm_ops = {
++ .suspend = cqspi_suspend,
++ .resume = cqspi_resume,
++};
++
++#define CQSPI_DEV_PM_OPS (&cqspi__dev_pm_ops)
++#else
++#define CQSPI_DEV_PM_OPS NULL
++#endif
++
++static struct of_device_id const cqspi_dt_ids[] = {
++ {.compatible = "cdns,qspi-nor",},
++ { /* end of table */ }
++};
++
++MODULE_DEVICE_TABLE(of, cqspi_dt_ids);
++
++static struct platform_driver cqspi_platform_driver = {
++ .probe = cqspi_probe,
++ .remove = cqspi_remove,
++ .driver = {
++ .name = CQSPI_NAME,
++ .pm = CQSPI_DEV_PM_OPS,
++ .of_match_table = cqspi_dt_ids,
++ },
++};
++
++module_platform_driver(cqspi_platform_driver);
++
++MODULE_DESCRIPTION("Cadence QSPI Controller Driver");
++MODULE_LICENSE("GPL v2");
++MODULE_ALIAS("platform:" CQSPI_NAME);
++MODULE_AUTHOR("Ley Foon Tan <lftan at altera.com>");
++MODULE_AUTHOR("Graham Moore <grmoore at opensource.altera.com>");
+--
+2.8.1
+
diff --git a/target/linux/socfpga/patches-4.4/0032-ARM-socfpga-Add-Candence-QSPI-controller-DT-node.patch b/target/linux/socfpga/patches-4.4/0032-ARM-socfpga-Add-Candence-QSPI-controller-DT-node.patch
new file mode 100644
index 0000000..e6b4ec7
--- /dev/null
+++ b/target/linux/socfpga/patches-4.4/0032-ARM-socfpga-Add-Candence-QSPI-controller-DT-node.patch
@@ -0,0 +1,42 @@
+From 8abee0bfd7bc652e028e51e2b95cbb3bf42fc152 Mon Sep 17 00:00:00 2001
+From: Stefan Roese <sr at denx.de>
+Date: Wed, 20 May 2015 10:32:03 +0200
+Subject: [PATCH 32/33] ARM: socfpga: Add Candence QSPI controller DT node
+
+Now that the device driver is available, lets add the controller node
+to the socfpga dtsi. So that the SPI NOR flash can be used.
+
+Signed-off-by: Stefan Roese <sr at denx.de>
+Signed-off-by: Marek Vasut <marex at denx.de>
+---
+ arch/arm/boot/dts/socfpga.dtsi | 14 ++++++++++++++
+ 1 file changed, 14 insertions(+)
+
+diff --git a/arch/arm/boot/dts/socfpga.dtsi b/arch/arm/boot/dts/socfpga.dtsi
+index 3ed4abd..ebcd081 100644
+--- a/arch/arm/boot/dts/socfpga.dtsi
++++ b/arch/arm/boot/dts/socfpga.dtsi
+@@ -685,6 +685,20 @@
+ reg = <0xffff0000 0x10000>;
+ };
+
++ qspi: spi at ff705000 {
++ compatible = "cdns,qspi-nor";
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <0xff705000 0x1000>,
++ <0xffa00000 0x1000>;
++ interrupts = <0 151 4>;
++ clocks = <&qspi_clk>;
++ cdns,fifo-depth = <128>;
++ cdns,fifo-width = <4>;
++ cdns,trigger-address = <0x00000000>;
++ status = "disabled";
++ };
++
+ rst: rstmgr at ffd05000 {
+ #reset-cells = <1>;
+ compatible = "altr,rst-mgr";
+--
+2.8.1
+
diff --git a/target/linux/socfpga/patches-4.4/0033-ARM-socfpga-Enable-QSPI-flash-on-SoCKit.patch b/target/linux/socfpga/patches-4.4/0033-ARM-socfpga-Enable-QSPI-flash-on-SoCKit.patch
new file mode 100644
index 0000000..f242d8c
--- /dev/null
+++ b/target/linux/socfpga/patches-4.4/0033-ARM-socfpga-Enable-QSPI-flash-on-SoCKit.patch
@@ -0,0 +1,47 @@
+From 8c1cd66d13406533f9948dbcd25d4b53d389c109 Mon Sep 17 00:00:00 2001
+From: Marek Vasut <marex at denx.de>
+Date: Sun, 21 Jun 2015 23:00:06 +0200
+Subject: [PATCH 33/33] ARM: socfpga: Enable QSPI flash on SoCKit
+
+Add the QSPI NOR node on SoCkit.
+
+Signed-off-by: Marek Vasut <marex at denx.de>
+---
+ arch/arm/boot/dts/socfpga_cyclone5_sockit.dts | 21 +++++++++++++++++++++
+ 1 file changed, 21 insertions(+)
+
+diff --git a/arch/arm/boot/dts/socfpga_cyclone5_sockit.dts b/arch/arm/boot/dts/socfpga_cyclone5_sockit.dts
+index 02e22f5..d706348 100644
+--- a/arch/arm/boot/dts/socfpga_cyclone5_sockit.dts
++++ b/arch/arm/boot/dts/socfpga_cyclone5_sockit.dts
+@@ -175,6 +175,27 @@
+ status = "okay";
+ };
+
++&qspi {
++ status = "okay";
++
++ flash0: n25q00 at 0 {
++ #address-cells = <1>;
++ #size-cells = <1>;
++ compatible = "n25q00";
++ reg = <0>; /* chip select */
++ spi-max-frequency = <100000000>;
++ m25p,fast-read;
++
++ cdns,page-size = <256>;
++ cdns,block-size = <16>;
++ cdns,read-delay = <4>;
++ cdns,tshsl-ns = <50>;
++ cdns,tsd2d-ns = <50>;
++ cdns,tchsh-ns = <4>;
++ cdns,tslch-ns = <4>;
++ };
++};
++
+ &usb1 {
+ status = "okay";
+ };
+--
+2.8.1
+
--
2.7.0
_______________________________________________
openwrt-devel mailing list
openwrt-devel at lists.openwrt.org
https://lists.openwrt.org/cgi-bin/mailman/listinfo/openwrt-devel
More information about the openwrt-devel
mailing list