[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, &reg, read_len);
++	rxbuf += read_len;
++
++	if (n_rx > 4) {
++		reg = readl(reg_base + CQSPI_REG_CMDREADDATAUPPER);
++
++		read_len = n_rx - read_len;
++		memcpy(rxbuf, &reg, 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