Refreshed all patches. Removed upstreamed hunks: - 703-phy-support-layerscape.patch Compile-tested on: ar71xx Runtime-tested on: ar71xx Signed-off-by: Koen Vandeputte <koen.vandeputte@ncentric.com>
		
			
				
	
	
		
			987 lines
		
	
	
		
			32 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			987 lines
		
	
	
		
			32 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
From 825d57369b196b64387348922b47adc5b651622c Mon Sep 17 00:00:00 2001
 | 
						|
From: Yangbo Lu <yangbo.lu@nxp.com>
 | 
						|
Date: Wed, 17 Jan 2018 14:55:47 +0800
 | 
						|
Subject: [PATCH 05/30] mtd: spi-nor: support layerscape
 | 
						|
 | 
						|
This is an integrated patch for layerscape qspi support.
 | 
						|
 | 
						|
Signed-off-by: Suresh Gupta <suresh.gupta@nxp.com>
 | 
						|
Signed-off-by: Yunhui Cui <B56489@freescale.com>
 | 
						|
Signed-off-by: mar.krzeminski <mar.krzeminski@gmail.com>
 | 
						|
Signed-off-by: Alison Wang <b18965@freescale.com>
 | 
						|
Signed-off-by: Nobuhiro Iwamatsu <nobuhiro.iwamatsu.kw@hitachi.com>
 | 
						|
Signed-off-by: LABBE Corentin <clabbe.montjoie@gmail.com>
 | 
						|
Signed-off-by: Yuan Yao <yao.yuan@nxp.com>
 | 
						|
Signed-off-by: Alexander Kurz <akurz@blala.de>
 | 
						|
Signed-off-by: L. D. Pinney <ldpinney@gmail.com>
 | 
						|
Signed-off-by: Ash Benz <ash.benz@bk.ru>
 | 
						|
Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
 | 
						|
---
 | 
						|
 drivers/mtd/mtdchar.c             |   2 +-
 | 
						|
 drivers/mtd/spi-nor/fsl-quadspi.c | 327 +++++++++++++++++++++++++++++++-------
 | 
						|
 drivers/mtd/spi-nor/spi-nor.c     | 136 ++++++++++++++--
 | 
						|
 include/linux/mtd/spi-nor.h       |  14 +-
 | 
						|
 4 files changed, 409 insertions(+), 70 deletions(-)
 | 
						|
 | 
						|
--- a/drivers/mtd/mtdchar.c
 | 
						|
+++ b/drivers/mtd/mtdchar.c
 | 
						|
@@ -455,7 +455,7 @@ static int mtdchar_readoob(struct file *
 | 
						|
 	 * data. For our userspace tools it is important to dump areas
 | 
						|
 	 * with ECC errors!
 | 
						|
 	 * For kernel internal usage it also might return -EUCLEAN
 | 
						|
-	 * to signal the caller that a bitflip has occured and has
 | 
						|
+	 * to signal the caller that a bitflip has occurred and has
 | 
						|
 	 * been corrected by the ECC algorithm.
 | 
						|
 	 *
 | 
						|
 	 * Note: currently the standard NAND function, nand_read_oob_std,
 | 
						|
--- a/drivers/mtd/spi-nor/fsl-quadspi.c
 | 
						|
+++ b/drivers/mtd/spi-nor/fsl-quadspi.c
 | 
						|
@@ -41,6 +41,8 @@
 | 
						|
 #define QUADSPI_QUIRK_TKT253890		(1 << 2)
 | 
						|
 /* Controller cannot wake up from wait mode, TKT245618 */
 | 
						|
 #define QUADSPI_QUIRK_TKT245618         (1 << 3)
 | 
						|
+/* QSPI_AMBA_BASE is internally added by SOC design */
 | 
						|
+#define QUADSPI_AMBA_BASE_INTERNAL	(0x10000)
 | 
						|
 
 | 
						|
 /* The registers */
 | 
						|
 #define QUADSPI_MCR			0x00
 | 
						|
@@ -193,7 +195,7 @@
 | 
						|
 #define QUADSPI_LUT_NUM		64
 | 
						|
 
 | 
						|
 /* SEQID -- we can have 16 seqids at most. */
 | 
						|
-#define SEQID_QUAD_READ		0
 | 
						|
+#define SEQID_READ		0
 | 
						|
 #define SEQID_WREN		1
 | 
						|
 #define SEQID_WRDI		2
 | 
						|
 #define SEQID_RDSR		3
 | 
						|
@@ -205,15 +207,22 @@
 | 
						|
 #define SEQID_RDCR		9
 | 
						|
 #define SEQID_EN4B		10
 | 
						|
 #define SEQID_BRWR		11
 | 
						|
+#define SEQID_RDAR_OR_RD_EVCR	12
 | 
						|
+#define SEQID_WRAR		13
 | 
						|
+#define SEQID_WD_EVCR           14
 | 
						|
 
 | 
						|
 #define QUADSPI_MIN_IOMAP SZ_4M
 | 
						|
 
 | 
						|
+#define FLASH_VENDOR_SPANSION_FS	"s25fs"
 | 
						|
+#define SPANSION_S25FS_FAMILY	(1 << 1)
 | 
						|
+
 | 
						|
 enum fsl_qspi_devtype {
 | 
						|
 	FSL_QUADSPI_VYBRID,
 | 
						|
 	FSL_QUADSPI_IMX6SX,
 | 
						|
 	FSL_QUADSPI_IMX7D,
 | 
						|
 	FSL_QUADSPI_IMX6UL,
 | 
						|
 	FSL_QUADSPI_LS1021A,
 | 
						|
+	FSL_QUADSPI_LS2080A,
 | 
						|
 };
 | 
						|
 
 | 
						|
 struct fsl_qspi_devtype_data {
 | 
						|
@@ -224,7 +233,7 @@ struct fsl_qspi_devtype_data {
 | 
						|
 	int driver_data;
 | 
						|
 };
 | 
						|
 
 | 
						|
-static struct fsl_qspi_devtype_data vybrid_data = {
 | 
						|
+static const struct fsl_qspi_devtype_data vybrid_data = {
 | 
						|
 	.devtype = FSL_QUADSPI_VYBRID,
 | 
						|
 	.rxfifo = 128,
 | 
						|
 	.txfifo = 64,
 | 
						|
@@ -232,7 +241,7 @@ static struct fsl_qspi_devtype_data vybr
 | 
						|
 	.driver_data = QUADSPI_QUIRK_SWAP_ENDIAN,
 | 
						|
 };
 | 
						|
 
 | 
						|
-static struct fsl_qspi_devtype_data imx6sx_data = {
 | 
						|
+static const struct fsl_qspi_devtype_data imx6sx_data = {
 | 
						|
 	.devtype = FSL_QUADSPI_IMX6SX,
 | 
						|
 	.rxfifo = 128,
 | 
						|
 	.txfifo = 512,
 | 
						|
@@ -241,7 +250,7 @@ static struct fsl_qspi_devtype_data imx6
 | 
						|
 		       | QUADSPI_QUIRK_TKT245618,
 | 
						|
 };
 | 
						|
 
 | 
						|
-static struct fsl_qspi_devtype_data imx7d_data = {
 | 
						|
+static const struct fsl_qspi_devtype_data imx7d_data = {
 | 
						|
 	.devtype = FSL_QUADSPI_IMX7D,
 | 
						|
 	.rxfifo = 512,
 | 
						|
 	.txfifo = 512,
 | 
						|
@@ -250,7 +259,7 @@ static struct fsl_qspi_devtype_data imx7
 | 
						|
 		       | QUADSPI_QUIRK_4X_INT_CLK,
 | 
						|
 };
 | 
						|
 
 | 
						|
-static struct fsl_qspi_devtype_data imx6ul_data = {
 | 
						|
+static const struct fsl_qspi_devtype_data imx6ul_data = {
 | 
						|
 	.devtype = FSL_QUADSPI_IMX6UL,
 | 
						|
 	.rxfifo = 128,
 | 
						|
 	.txfifo = 512,
 | 
						|
@@ -267,6 +276,14 @@ static struct fsl_qspi_devtype_data ls10
 | 
						|
 	.driver_data = 0,
 | 
						|
 };
 | 
						|
 
 | 
						|
+static struct fsl_qspi_devtype_data ls2080a_data = {
 | 
						|
+	.devtype = FSL_QUADSPI_LS2080A,
 | 
						|
+	.rxfifo = 128,
 | 
						|
+	.txfifo = 64,
 | 
						|
+	.ahb_buf_size = 1024,
 | 
						|
+	.driver_data = QUADSPI_AMBA_BASE_INTERNAL | QUADSPI_QUIRK_TKT253890,
 | 
						|
+};
 | 
						|
+
 | 
						|
 #define FSL_QSPI_MAX_CHIP	4
 | 
						|
 struct fsl_qspi {
 | 
						|
 	struct spi_nor nor[FSL_QSPI_MAX_CHIP];
 | 
						|
@@ -282,6 +299,7 @@ struct fsl_qspi {
 | 
						|
 	u32 nor_size;
 | 
						|
 	u32 nor_num;
 | 
						|
 	u32 clk_rate;
 | 
						|
+	u32 ddr_smp;
 | 
						|
 	unsigned int chip_base_addr; /* We may support two chips. */
 | 
						|
 	bool has_second_chip;
 | 
						|
 	bool big_endian;
 | 
						|
@@ -309,6 +327,23 @@ static inline int needs_wakeup_wait_mode
 | 
						|
 	return q->devtype_data->driver_data & QUADSPI_QUIRK_TKT245618;
 | 
						|
 }
 | 
						|
 
 | 
						|
+static inline int has_added_amba_base_internal(struct fsl_qspi *q)
 | 
						|
+{
 | 
						|
+	return q->devtype_data->driver_data & QUADSPI_AMBA_BASE_INTERNAL;
 | 
						|
+}
 | 
						|
+
 | 
						|
+static u32 fsl_get_nor_vendor(struct spi_nor *nor)
 | 
						|
+{
 | 
						|
+	u32 vendor_id;
 | 
						|
+
 | 
						|
+	if (nor->vendor) {
 | 
						|
+		if (memcmp(nor->vendor, FLASH_VENDOR_SPANSION_FS,
 | 
						|
+					sizeof(FLASH_VENDOR_SPANSION_FS) - 1))
 | 
						|
+			vendor_id = SPANSION_S25FS_FAMILY;
 | 
						|
+	}
 | 
						|
+	return vendor_id;
 | 
						|
+}
 | 
						|
+
 | 
						|
 /*
 | 
						|
  * R/W functions for big- or little-endian registers:
 | 
						|
  * The qSPI controller's endian is independent of the CPU core's endian.
 | 
						|
@@ -331,6 +366,31 @@ static u32 qspi_readl(struct fsl_qspi *q
 | 
						|
 		return ioread32(addr);
 | 
						|
 }
 | 
						|
 
 | 
						|
+static inline u32 *u8tou32(u32 *dest, const u8 *src, size_t n)
 | 
						|
+{
 | 
						|
+	size_t i;
 | 
						|
+	*dest = 0;
 | 
						|
+
 | 
						|
+	n = n > 4 ? 4 : n;
 | 
						|
+	for (i = 0; i < n; i++)
 | 
						|
+		*dest |= *src++ << i * 8;
 | 
						|
+
 | 
						|
+	return dest;
 | 
						|
+
 | 
						|
+}
 | 
						|
+
 | 
						|
+static inline u8 *u32tou8(u8 *dest, const u32 *src, size_t n)
 | 
						|
+{
 | 
						|
+	size_t i;
 | 
						|
+	u8 *xdest = dest;
 | 
						|
+
 | 
						|
+	n = n > 4 ? 4 : n;
 | 
						|
+	for (i = 0; i < n; i++)
 | 
						|
+		*xdest++ = *src >> i * 8;
 | 
						|
+
 | 
						|
+	return dest;
 | 
						|
+}
 | 
						|
+
 | 
						|
 /*
 | 
						|
  * An IC bug makes us to re-arrange the 32-bit data.
 | 
						|
  * The following chips, such as IMX6SLX, have fixed this bug.
 | 
						|
@@ -373,8 +433,15 @@ static void fsl_qspi_init_lut(struct fsl
 | 
						|
 	void __iomem *base = q->iobase;
 | 
						|
 	int rxfifo = q->devtype_data->rxfifo;
 | 
						|
 	u32 lut_base;
 | 
						|
-	u8 cmd, addrlen, dummy;
 | 
						|
 	int i;
 | 
						|
+	u32 vendor;
 | 
						|
+
 | 
						|
+	struct spi_nor *nor = &q->nor[0];
 | 
						|
+	u8 addrlen = (nor->addr_width == 3) ? ADDR24BIT : ADDR32BIT;
 | 
						|
+	u8 read_op = nor->read_opcode;
 | 
						|
+	u8 read_dm = nor->read_dummy;
 | 
						|
+
 | 
						|
+	vendor = fsl_get_nor_vendor(nor);
 | 
						|
 
 | 
						|
 	fsl_qspi_unlock_lut(q);
 | 
						|
 
 | 
						|
@@ -382,24 +449,50 @@ static void fsl_qspi_init_lut(struct fsl
 | 
						|
 	for (i = 0; i < QUADSPI_LUT_NUM; i++)
 | 
						|
 		qspi_writel(q, 0, base + QUADSPI_LUT_BASE + i * 4);
 | 
						|
 
 | 
						|
-	/* Quad Read */
 | 
						|
-	lut_base = SEQID_QUAD_READ * 4;
 | 
						|
+	/* Read */
 | 
						|
+	lut_base = SEQID_READ * 4;
 | 
						|
 
 | 
						|
-	if (q->nor_size <= SZ_16M) {
 | 
						|
-		cmd = SPINOR_OP_READ_1_1_4;
 | 
						|
-		addrlen = ADDR24BIT;
 | 
						|
-		dummy = 8;
 | 
						|
-	} else {
 | 
						|
-		/* use the 4-byte address */
 | 
						|
-		cmd = SPINOR_OP_READ_1_1_4;
 | 
						|
-		addrlen = ADDR32BIT;
 | 
						|
-		dummy = 8;
 | 
						|
-	}
 | 
						|
-
 | 
						|
-	qspi_writel(q, LUT0(CMD, PAD1, cmd) | LUT1(ADDR, PAD1, addrlen),
 | 
						|
+	if (nor->flash_read == SPI_NOR_FAST) {
 | 
						|
+		qspi_writel(q, LUT0(CMD, PAD1, read_op) |
 | 
						|
+			    LUT1(ADDR, PAD1, addrlen),
 | 
						|
+				base + QUADSPI_LUT(lut_base));
 | 
						|
+		qspi_writel(q,  LUT0(DUMMY, PAD1, read_dm) |
 | 
						|
+			    LUT1(FSL_READ, PAD1, rxfifo),
 | 
						|
+				base + QUADSPI_LUT(lut_base + 1));
 | 
						|
+	} else if (nor->flash_read == SPI_NOR_QUAD) {
 | 
						|
+		if (q->nor_size == 0x4000000) {
 | 
						|
+			read_op = 0xEC;
 | 
						|
+		qspi_writel(q,
 | 
						|
+			LUT0(CMD, PAD1, read_op) | LUT1(ADDR, PAD4, addrlen),
 | 
						|
 			base + QUADSPI_LUT(lut_base));
 | 
						|
-	qspi_writel(q, LUT0(DUMMY, PAD1, dummy) | LUT1(FSL_READ, PAD4, rxfifo),
 | 
						|
+		qspi_writel(q,
 | 
						|
+			LUT0(MODE, PAD4, 0xff) | LUT1(DUMMY, PAD4, read_dm),
 | 
						|
 			base + QUADSPI_LUT(lut_base + 1));
 | 
						|
+		qspi_writel(q,
 | 
						|
+			LUT0(FSL_READ, PAD4, rxfifo),
 | 
						|
+			base + QUADSPI_LUT(lut_base + 2));
 | 
						|
+		} else {
 | 
						|
+			qspi_writel(q, LUT0(CMD, PAD1, read_op) |
 | 
						|
+				    LUT1(ADDR, PAD1, addrlen),
 | 
						|
+				    base + QUADSPI_LUT(lut_base));
 | 
						|
+			qspi_writel(q, LUT0(DUMMY, PAD1, read_dm) |
 | 
						|
+				    LUT1(FSL_READ, PAD4, rxfifo),
 | 
						|
+				    base + QUADSPI_LUT(lut_base + 1));
 | 
						|
+		}
 | 
						|
+	} else if (nor->flash_read == SPI_NOR_DDR_QUAD) {
 | 
						|
+		/* read mode : 1-4-4, such as Spansion s25fl128s. */
 | 
						|
+		qspi_writel(q, LUT0(CMD, PAD1, read_op)
 | 
						|
+			| LUT1(ADDR_DDR, PAD4, addrlen),
 | 
						|
+			base + QUADSPI_LUT(lut_base));
 | 
						|
+
 | 
						|
+		qspi_writel(q, LUT0(MODE_DDR, PAD4, 0xff)
 | 
						|
+			| LUT1(DUMMY, PAD1, read_dm),
 | 
						|
+			base + QUADSPI_LUT(lut_base + 1));
 | 
						|
+
 | 
						|
+		qspi_writel(q, LUT0(FSL_READ_DDR, PAD4, rxfifo)
 | 
						|
+			| LUT1(JMP_ON_CS, PAD1, 0),
 | 
						|
+			base + QUADSPI_LUT(lut_base + 2));
 | 
						|
+	}
 | 
						|
 
 | 
						|
 	/* Write enable */
 | 
						|
 	lut_base = SEQID_WREN * 4;
 | 
						|
@@ -409,16 +502,8 @@ static void fsl_qspi_init_lut(struct fsl
 | 
						|
 	/* Page Program */
 | 
						|
 	lut_base = SEQID_PP * 4;
 | 
						|
 
 | 
						|
-	if (q->nor_size <= SZ_16M) {
 | 
						|
-		cmd = SPINOR_OP_PP;
 | 
						|
-		addrlen = ADDR24BIT;
 | 
						|
-	} else {
 | 
						|
-		/* use the 4-byte address */
 | 
						|
-		cmd = SPINOR_OP_PP;
 | 
						|
-		addrlen = ADDR32BIT;
 | 
						|
-	}
 | 
						|
-
 | 
						|
-	qspi_writel(q, LUT0(CMD, PAD1, cmd) | LUT1(ADDR, PAD1, addrlen),
 | 
						|
+	qspi_writel(q, LUT0(CMD, PAD1, nor->program_opcode) |
 | 
						|
+		    LUT1(ADDR, PAD1, addrlen),
 | 
						|
 			base + QUADSPI_LUT(lut_base));
 | 
						|
 	qspi_writel(q, LUT0(FSL_WRITE, PAD1, 0),
 | 
						|
 			base + QUADSPI_LUT(lut_base + 1));
 | 
						|
@@ -432,10 +517,8 @@ static void fsl_qspi_init_lut(struct fsl
 | 
						|
 	/* Erase a sector */
 | 
						|
 	lut_base = SEQID_SE * 4;
 | 
						|
 
 | 
						|
-	cmd = q->nor[0].erase_opcode;
 | 
						|
-	addrlen = q->nor_size <= SZ_16M ? ADDR24BIT : ADDR32BIT;
 | 
						|
-
 | 
						|
-	qspi_writel(q, LUT0(CMD, PAD1, cmd) | LUT1(ADDR, PAD1, addrlen),
 | 
						|
+	qspi_writel(q, LUT0(CMD, PAD1, nor->erase_opcode) |
 | 
						|
+		    LUT1(ADDR, PAD1, addrlen),
 | 
						|
 			base + QUADSPI_LUT(lut_base));
 | 
						|
 
 | 
						|
 	/* Erase the whole chip */
 | 
						|
@@ -476,6 +559,44 @@ static void fsl_qspi_init_lut(struct fsl
 | 
						|
 	qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_BRWR),
 | 
						|
 			base + QUADSPI_LUT(lut_base));
 | 
						|
 
 | 
						|
+
 | 
						|
+	/*
 | 
						|
+	 * Flash Micron and Spansion command confilict
 | 
						|
+	 * use the same value 0x65. But it indicates different meaning.
 | 
						|
+	 */
 | 
						|
+	lut_base = SEQID_RDAR_OR_RD_EVCR * 4;
 | 
						|
+
 | 
						|
+	if (vendor == SPANSION_S25FS_FAMILY) {
 | 
						|
+		/*
 | 
						|
+		* Read any device register.
 | 
						|
+		* Used for Spansion S25FS-S family flash only.
 | 
						|
+		*/
 | 
						|
+		qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_SPANSION_RDAR) |
 | 
						|
+			    LUT1(ADDR, PAD1, ADDR24BIT),
 | 
						|
+			    base + QUADSPI_LUT(lut_base));
 | 
						|
+		qspi_writel(q, LUT0(DUMMY, PAD1, 8) | LUT1(FSL_READ, PAD1, 1),
 | 
						|
+			    base + QUADSPI_LUT(lut_base + 1));
 | 
						|
+	} else {
 | 
						|
+		qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_RD_EVCR),
 | 
						|
+			    base + QUADSPI_LUT(lut_base));
 | 
						|
+	}
 | 
						|
+
 | 
						|
+	/*
 | 
						|
+	 * Write any device register.
 | 
						|
+	 * Used for Spansion S25FS-S family flash only.
 | 
						|
+	 */
 | 
						|
+	lut_base = SEQID_WRAR * 4;
 | 
						|
+	qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_SPANSION_WRAR) |
 | 
						|
+			LUT1(ADDR, PAD1, ADDR24BIT),
 | 
						|
+			base + QUADSPI_LUT(lut_base));
 | 
						|
+	qspi_writel(q, LUT0(FSL_WRITE, PAD1, 1),
 | 
						|
+			base + QUADSPI_LUT(lut_base + 1));
 | 
						|
+
 | 
						|
+	/* Write EVCR register */
 | 
						|
+	lut_base = SEQID_WD_EVCR * 4;
 | 
						|
+	qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_WD_EVCR),
 | 
						|
+		    base + QUADSPI_LUT(lut_base));
 | 
						|
+
 | 
						|
 	fsl_qspi_lock_lut(q);
 | 
						|
 }
 | 
						|
 
 | 
						|
@@ -483,8 +604,24 @@ static void fsl_qspi_init_lut(struct fsl
 | 
						|
 static int fsl_qspi_get_seqid(struct fsl_qspi *q, u8 cmd)
 | 
						|
 {
 | 
						|
 	switch (cmd) {
 | 
						|
+	case SPINOR_OP_READ_1_4_4_D:
 | 
						|
+	case SPINOR_OP_READ4_1_4_4_D:
 | 
						|
+	case SPINOR_OP_READ4_1_1_4:
 | 
						|
 	case SPINOR_OP_READ_1_1_4:
 | 
						|
-		return SEQID_QUAD_READ;
 | 
						|
+	case SPINOR_OP_READ_FAST:
 | 
						|
+	case SPINOR_OP_READ4_FAST:
 | 
						|
+		return SEQID_READ;
 | 
						|
+	/*
 | 
						|
+	 * Spansion & Micron use the same command value 0x65
 | 
						|
+	 * Spansion: SPINOR_OP_SPANSION_RDAR, read any register.
 | 
						|
+	 * Micron: SPINOR_OP_RD_EVCR,
 | 
						|
+	 * read enhanced volatile configuration register.
 | 
						|
+	 * case SPINOR_OP_RD_EVCR:
 | 
						|
+	 */
 | 
						|
+	case SPINOR_OP_SPANSION_RDAR:
 | 
						|
+		return SEQID_RDAR_OR_RD_EVCR;
 | 
						|
+	case SPINOR_OP_SPANSION_WRAR:
 | 
						|
+		return SEQID_WRAR;
 | 
						|
 	case SPINOR_OP_WREN:
 | 
						|
 		return SEQID_WREN;
 | 
						|
 	case SPINOR_OP_WRDI:
 | 
						|
@@ -496,6 +633,7 @@ static int fsl_qspi_get_seqid(struct fsl
 | 
						|
 	case SPINOR_OP_CHIP_ERASE:
 | 
						|
 		return SEQID_CHIP_ERASE;
 | 
						|
 	case SPINOR_OP_PP:
 | 
						|
+	case SPINOR_OP_PP_4B:
 | 
						|
 		return SEQID_PP;
 | 
						|
 	case SPINOR_OP_RDID:
 | 
						|
 		return SEQID_RDID;
 | 
						|
@@ -507,6 +645,8 @@ static int fsl_qspi_get_seqid(struct fsl
 | 
						|
 		return SEQID_EN4B;
 | 
						|
 	case SPINOR_OP_BRWR:
 | 
						|
 		return SEQID_BRWR;
 | 
						|
+	case SPINOR_OP_WD_EVCR:
 | 
						|
+		return SEQID_WD_EVCR;
 | 
						|
 	default:
 | 
						|
 		if (cmd == q->nor[0].erase_opcode)
 | 
						|
 			return SEQID_SE;
 | 
						|
@@ -531,8 +671,11 @@ fsl_qspi_runcmd(struct fsl_qspi *q, u8 c
 | 
						|
 	/* save the reg */
 | 
						|
 	reg = qspi_readl(q, base + QUADSPI_MCR);
 | 
						|
 
 | 
						|
-	qspi_writel(q, q->memmap_phy + q->chip_base_addr + addr,
 | 
						|
-			base + QUADSPI_SFAR);
 | 
						|
+	if (has_added_amba_base_internal(q))
 | 
						|
+		qspi_writel(q, q->chip_base_addr + addr, base + QUADSPI_SFAR);
 | 
						|
+	else
 | 
						|
+		qspi_writel(q, q->memmap_phy + q->chip_base_addr + addr,
 | 
						|
+			    base + QUADSPI_SFAR);
 | 
						|
 	qspi_writel(q, QUADSPI_RBCT_WMRK_MASK | QUADSPI_RBCT_RXBRD_USEIPS,
 | 
						|
 			base + QUADSPI_RBCT);
 | 
						|
 	qspi_writel(q, reg | QUADSPI_MCR_CLR_RXF_MASK, base + QUADSPI_MCR);
 | 
						|
@@ -582,10 +725,10 @@ static void fsl_qspi_read_data(struct fs
 | 
						|
 				q->chip_base_addr, tmp);
 | 
						|
 
 | 
						|
 		if (len >= 4) {
 | 
						|
-			*((u32 *)rxbuf) = tmp;
 | 
						|
+			u32tou8(rxbuf, &tmp, 4);
 | 
						|
 			rxbuf += 4;
 | 
						|
 		} else {
 | 
						|
-			memcpy(rxbuf, &tmp, len);
 | 
						|
+			u32tou8(rxbuf, &tmp, len);
 | 
						|
 			break;
 | 
						|
 		}
 | 
						|
 
 | 
						|
@@ -619,11 +762,12 @@ static inline void fsl_qspi_invalid(stru
 | 
						|
 }
 | 
						|
 
 | 
						|
 static ssize_t fsl_qspi_nor_write(struct fsl_qspi *q, struct spi_nor *nor,
 | 
						|
-				u8 opcode, unsigned int to, u32 *txbuf,
 | 
						|
+				u8 opcode, unsigned int to, u8 *txbuf,
 | 
						|
 				unsigned count)
 | 
						|
 {
 | 
						|
 	int ret, i, j;
 | 
						|
 	u32 tmp;
 | 
						|
+	u8 byts;
 | 
						|
 
 | 
						|
 	dev_dbg(q->dev, "to 0x%.8x:0x%.8x, len : %d\n",
 | 
						|
 		q->chip_base_addr, to, count);
 | 
						|
@@ -633,10 +777,13 @@ static ssize_t fsl_qspi_nor_write(struct
 | 
						|
 	qspi_writel(q, tmp | QUADSPI_MCR_CLR_TXF_MASK, q->iobase + QUADSPI_MCR);
 | 
						|
 
 | 
						|
 	/* fill the TX data to the FIFO */
 | 
						|
+	byts = count;
 | 
						|
 	for (j = 0, i = ((count + 3) / 4); j < i; j++) {
 | 
						|
-		tmp = fsl_qspi_endian_xchg(q, *txbuf);
 | 
						|
+		u8tou32(&tmp, txbuf, byts);
 | 
						|
+		tmp = fsl_qspi_endian_xchg(q, tmp);
 | 
						|
 		qspi_writel(q, tmp, q->iobase + QUADSPI_TBDR);
 | 
						|
-		txbuf++;
 | 
						|
+		txbuf += 4;
 | 
						|
+		byts -= 4;
 | 
						|
 	}
 | 
						|
 
 | 
						|
 	/* fill the TXFIFO upto 16 bytes for i.MX7d */
 | 
						|
@@ -657,11 +804,43 @@ static void fsl_qspi_set_map_addr(struct
 | 
						|
 {
 | 
						|
 	int nor_size = q->nor_size;
 | 
						|
 	void __iomem *base = q->iobase;
 | 
						|
+	u32 mem_base;
 | 
						|
+
 | 
						|
+	if (has_added_amba_base_internal(q))
 | 
						|
+		mem_base = 0x0;
 | 
						|
+	else
 | 
						|
+		mem_base = q->memmap_phy;
 | 
						|
+
 | 
						|
+	qspi_writel(q, nor_size + mem_base, base + QUADSPI_SFA1AD);
 | 
						|
+	qspi_writel(q, nor_size * 2 + mem_base, base + QUADSPI_SFA2AD);
 | 
						|
+	qspi_writel(q, nor_size * 3 + mem_base, base + QUADSPI_SFB1AD);
 | 
						|
+	qspi_writel(q, nor_size * 4 + mem_base, base + QUADSPI_SFB2AD);
 | 
						|
+}
 | 
						|
+
 | 
						|
+/*
 | 
						|
+ * enable controller ddr quad mode to support different
 | 
						|
+ * vender flashes ddr quad mode.
 | 
						|
+ */
 | 
						|
+static void set_ddr_quad_mode(struct fsl_qspi *q)
 | 
						|
+{
 | 
						|
+	u32 reg, reg2;
 | 
						|
+
 | 
						|
+	reg = qspi_readl(q, q->iobase + QUADSPI_MCR);
 | 
						|
+
 | 
						|
+	/* Firstly, disable the module */
 | 
						|
+	qspi_writel(q, reg | QUADSPI_MCR_MDIS_MASK, q->iobase + QUADSPI_MCR);
 | 
						|
+
 | 
						|
+	/* Set the Sampling Register for DDR */
 | 
						|
+	reg2 = qspi_readl(q, q->iobase + QUADSPI_SMPR);
 | 
						|
+	reg2 &= ~QUADSPI_SMPR_DDRSMP_MASK;
 | 
						|
+	reg2 |= (((q->ddr_smp) << QUADSPI_SMPR_DDRSMP_SHIFT) &
 | 
						|
+			QUADSPI_SMPR_DDRSMP_MASK);
 | 
						|
+	qspi_writel(q, reg2, q->iobase + QUADSPI_SMPR);
 | 
						|
+
 | 
						|
+	/* Enable the module again (enable the DDR too) */
 | 
						|
+	reg |= QUADSPI_MCR_DDR_EN_MASK;
 | 
						|
+	qspi_writel(q, reg, q->iobase + QUADSPI_MCR);
 | 
						|
 
 | 
						|
-	qspi_writel(q, nor_size + q->memmap_phy, base + QUADSPI_SFA1AD);
 | 
						|
-	qspi_writel(q, nor_size * 2 + q->memmap_phy, base + QUADSPI_SFA2AD);
 | 
						|
-	qspi_writel(q, nor_size * 3 + q->memmap_phy, base + QUADSPI_SFB1AD);
 | 
						|
-	qspi_writel(q, nor_size * 4 + q->memmap_phy, base + QUADSPI_SFB2AD);
 | 
						|
 }
 | 
						|
 
 | 
						|
 /*
 | 
						|
@@ -704,6 +883,11 @@ static void fsl_qspi_init_abh_read(struc
 | 
						|
 	seqid = fsl_qspi_get_seqid(q, q->nor[0].read_opcode);
 | 
						|
 	qspi_writel(q, seqid << QUADSPI_BFGENCR_SEQID_SHIFT,
 | 
						|
 		q->iobase + QUADSPI_BFGENCR);
 | 
						|
+
 | 
						|
+	/* enable the DDR quad read */
 | 
						|
+	if (q->nor->flash_read == SPI_NOR_DDR_QUAD)
 | 
						|
+		set_ddr_quad_mode(q);
 | 
						|
+
 | 
						|
 }
 | 
						|
 
 | 
						|
 /* This function was used to prepare and enable QSPI clock */
 | 
						|
@@ -822,6 +1006,7 @@ static const struct of_device_id fsl_qsp
 | 
						|
 	{ .compatible = "fsl,imx7d-qspi", .data = (void *)&imx7d_data, },
 | 
						|
 	{ .compatible = "fsl,imx6ul-qspi", .data = (void *)&imx6ul_data, },
 | 
						|
 	{ .compatible = "fsl,ls1021a-qspi", .data = (void *)&ls1021a_data, },
 | 
						|
+	{ .compatible = "fsl,ls2080a-qspi", .data = (void *)&ls2080a_data, },
 | 
						|
 	{ /* sentinel */ }
 | 
						|
 };
 | 
						|
 MODULE_DEVICE_TABLE(of, fsl_qspi_dt_ids);
 | 
						|
@@ -835,8 +1020,12 @@ static int fsl_qspi_read_reg(struct spi_
 | 
						|
 {
 | 
						|
 	int ret;
 | 
						|
 	struct fsl_qspi *q = nor->priv;
 | 
						|
+	u32 to = 0;
 | 
						|
 
 | 
						|
-	ret = fsl_qspi_runcmd(q, opcode, 0, len);
 | 
						|
+	if (opcode == SPINOR_OP_SPANSION_RDAR)
 | 
						|
+		u8tou32(&to, nor->cmd_buf, 4);
 | 
						|
+
 | 
						|
+	ret = fsl_qspi_runcmd(q, opcode, to, len);
 | 
						|
 	if (ret)
 | 
						|
 		return ret;
 | 
						|
 
 | 
						|
@@ -848,9 +1037,13 @@ static int fsl_qspi_write_reg(struct spi
 | 
						|
 {
 | 
						|
 	struct fsl_qspi *q = nor->priv;
 | 
						|
 	int ret;
 | 
						|
+	u32 to = 0;
 | 
						|
+
 | 
						|
+	if (opcode == SPINOR_OP_SPANSION_WRAR)
 | 
						|
+		u8tou32(&to, nor->cmd_buf, 4);
 | 
						|
 
 | 
						|
 	if (!buf) {
 | 
						|
-		ret = fsl_qspi_runcmd(q, opcode, 0, 1);
 | 
						|
+		ret = fsl_qspi_runcmd(q, opcode, to, 1);
 | 
						|
 		if (ret)
 | 
						|
 			return ret;
 | 
						|
 
 | 
						|
@@ -859,7 +1052,7 @@ static int fsl_qspi_write_reg(struct spi
 | 
						|
 
 | 
						|
 	} else if (len > 0) {
 | 
						|
 		ret = fsl_qspi_nor_write(q, nor, opcode, 0,
 | 
						|
-					(u32 *)buf, len);
 | 
						|
+					buf, len);
 | 
						|
 		if (ret > 0)
 | 
						|
 			return 0;
 | 
						|
 	} else {
 | 
						|
@@ -875,7 +1068,7 @@ static ssize_t fsl_qspi_write(struct spi
 | 
						|
 {
 | 
						|
 	struct fsl_qspi *q = nor->priv;
 | 
						|
 	ssize_t ret = fsl_qspi_nor_write(q, nor, nor->program_opcode, to,
 | 
						|
-					 (u32 *)buf, len);
 | 
						|
+					 (u8 *)buf, len);
 | 
						|
 
 | 
						|
 	/* invalid the data in the AHB buffer. */
 | 
						|
 	fsl_qspi_invalid(q);
 | 
						|
@@ -922,7 +1115,7 @@ static ssize_t fsl_qspi_read(struct spi_
 | 
						|
 		len);
 | 
						|
 
 | 
						|
 	/* Read out the data directly from the AHB buffer.*/
 | 
						|
-	memcpy(buf, q->ahb_addr + q->chip_base_addr + from - q->memmap_offs,
 | 
						|
+	memcpy_toio(buf, q->ahb_addr + q->chip_base_addr + from - q->memmap_offs,
 | 
						|
 		len);
 | 
						|
 
 | 
						|
 	return len;
 | 
						|
@@ -980,6 +1173,8 @@ static int fsl_qspi_probe(struct platfor
 | 
						|
 	struct spi_nor *nor;
 | 
						|
 	struct mtd_info *mtd;
 | 
						|
 	int ret, i = 0;
 | 
						|
+	int find_node;
 | 
						|
+	enum read_mode mode = SPI_NOR_QUAD;
 | 
						|
 
 | 
						|
 	q = devm_kzalloc(dev, sizeof(*q), GFP_KERNEL);
 | 
						|
 	if (!q)
 | 
						|
@@ -1027,6 +1222,12 @@ static int fsl_qspi_probe(struct platfor
 | 
						|
 		goto clk_failed;
 | 
						|
 	}
 | 
						|
 
 | 
						|
+	/* find ddrsmp value */
 | 
						|
+	ret = of_property_read_u32(dev->of_node, "fsl,ddr-sampling-point",
 | 
						|
+				&q->ddr_smp);
 | 
						|
+	if (ret)
 | 
						|
+		q->ddr_smp = 0;
 | 
						|
+
 | 
						|
 	/* find the irq */
 | 
						|
 	ret = platform_get_irq(pdev, 0);
 | 
						|
 	if (ret < 0) {
 | 
						|
@@ -1050,6 +1251,7 @@ static int fsl_qspi_probe(struct platfor
 | 
						|
 
 | 
						|
 	mutex_init(&q->lock);
 | 
						|
 
 | 
						|
+	find_node = 0;
 | 
						|
 	/* iterate the subnodes. */
 | 
						|
 	for_each_available_child_of_node(dev->of_node, np) {
 | 
						|
 		/* skip the holes */
 | 
						|
@@ -1076,18 +1278,25 @@ static int fsl_qspi_probe(struct platfor
 | 
						|
 		ret = of_property_read_u32(np, "spi-max-frequency",
 | 
						|
 				&q->clk_rate);
 | 
						|
 		if (ret < 0)
 | 
						|
-			goto mutex_failed;
 | 
						|
+			continue;
 | 
						|
 
 | 
						|
 		/* set the chip address for READID */
 | 
						|
 		fsl_qspi_set_base_addr(q, nor);
 | 
						|
 
 | 
						|
-		ret = spi_nor_scan(nor, NULL, SPI_NOR_QUAD);
 | 
						|
+		ret = of_property_read_bool(np, "m25p,fast-read");
 | 
						|
+		mode = (ret) ? SPI_NOR_FAST : SPI_NOR_QUAD;
 | 
						|
+		/* Can we enable the DDR Quad Read? */
 | 
						|
+		ret = of_property_read_bool(np, "ddr-quad-read");
 | 
						|
 		if (ret)
 | 
						|
-			goto mutex_failed;
 | 
						|
+			mode = SPI_NOR_DDR_QUAD;
 | 
						|
+
 | 
						|
+		ret = spi_nor_scan(nor, NULL, mode);
 | 
						|
+		if (ret)
 | 
						|
+			continue;
 | 
						|
 
 | 
						|
 		ret = mtd_device_register(mtd, NULL, 0);
 | 
						|
 		if (ret)
 | 
						|
-			goto mutex_failed;
 | 
						|
+			continue;
 | 
						|
 
 | 
						|
 		/* Set the correct NOR size now. */
 | 
						|
 		if (q->nor_size == 0) {
 | 
						|
@@ -1110,8 +1319,12 @@ static int fsl_qspi_probe(struct platfor
 | 
						|
 			nor->page_size = q->devtype_data->txfifo;
 | 
						|
 
 | 
						|
 		i++;
 | 
						|
+		find_node++;
 | 
						|
 	}
 | 
						|
 
 | 
						|
+	if (find_node == 0)
 | 
						|
+		goto mutex_failed;
 | 
						|
+
 | 
						|
 	/* finish the rest init. */
 | 
						|
 	ret = fsl_qspi_nor_setup_last(q);
 | 
						|
 	if (ret)
 | 
						|
--- a/drivers/mtd/spi-nor/spi-nor.c
 | 
						|
+++ b/drivers/mtd/spi-nor/spi-nor.c
 | 
						|
@@ -40,6 +40,13 @@
 | 
						|
 #define SPI_NOR_MAX_ID_LEN	6
 | 
						|
 #define SPI_NOR_MAX_ADDR_WIDTH	4
 | 
						|
 
 | 
						|
+#define SPI_NOR_MICRON_WRITE_ENABLE    0x7f
 | 
						|
+/* Added for S25FS-S family flash */
 | 
						|
+#define SPINOR_CONFIG_REG3_OFFSET      0x800004
 | 
						|
+#define CR3V_4KB_ERASE_UNABLE  0x8
 | 
						|
+#define SPINOR_S25FS_FAMILY_ID 0x81
 | 
						|
+
 | 
						|
+
 | 
						|
 struct flash_info {
 | 
						|
 	char		*name;
 | 
						|
 
 | 
						|
@@ -68,7 +75,8 @@ struct flash_info {
 | 
						|
 #define SECT_4K_PMC		BIT(4)	/* SPINOR_OP_BE_4K_PMC works uniformly */
 | 
						|
 #define SPI_NOR_DUAL_READ	BIT(5)	/* Flash supports Dual Read */
 | 
						|
 #define SPI_NOR_QUAD_READ	BIT(6)	/* Flash supports Quad Read */
 | 
						|
-#define USE_FSR			BIT(7)	/* use flag status register */
 | 
						|
+#define USE_FSR			BIT(13)	/* use flag status register */
 | 
						|
+#define SPI_NOR_DDR_QUAD_READ	BIT(7)	/* Flash supports DDR Quad Read */
 | 
						|
 #define SPI_NOR_HAS_LOCK	BIT(8)	/* Flash supports lock/unlock via SR */
 | 
						|
 #define SPI_NOR_HAS_TB		BIT(9)	/*
 | 
						|
 					 * Flash SR has Top/Bottom (TB) protect
 | 
						|
@@ -85,9 +93,11 @@ struct flash_info {
 | 
						|
 					 * Use dedicated 4byte address op codes
 | 
						|
 					 * to support memory size above 128Mib.
 | 
						|
 					 */
 | 
						|
+#define NO_CHIP_ERASE		BIT(12) /* Chip does not support chip erase */
 | 
						|
 };
 | 
						|
 
 | 
						|
 #define JEDEC_MFR(info)	((info)->id[0])
 | 
						|
+#define EXT_ID(info)	((info)->id[5])
 | 
						|
 
 | 
						|
 static const struct flash_info *spi_nor_match_id(const char *name);
 | 
						|
 
 | 
						|
@@ -132,7 +142,7 @@ static int read_fsr(struct spi_nor *nor)
 | 
						|
 /*
 | 
						|
  * Read configuration register, returning its value in the
 | 
						|
  * location. Return the configuration register value.
 | 
						|
- * Returns negative if error occured.
 | 
						|
+ * Returns negative if error occurred.
 | 
						|
  */
 | 
						|
 static int read_cr(struct spi_nor *nor)
 | 
						|
 {
 | 
						|
@@ -160,6 +170,8 @@ static inline int spi_nor_read_dummy_cyc
 | 
						|
 	case SPI_NOR_DUAL:
 | 
						|
 	case SPI_NOR_QUAD:
 | 
						|
 		return 8;
 | 
						|
+	case SPI_NOR_DDR_QUAD:
 | 
						|
+		return 6;
 | 
						|
 	case SPI_NOR_NORMAL:
 | 
						|
 		return 0;
 | 
						|
 	}
 | 
						|
@@ -961,6 +973,8 @@ static const struct flash_info spi_nor_i
 | 
						|
 
 | 
						|
 	/* ESMT */
 | 
						|
 	{ "f25l32pa", INFO(0x8c2016, 0, 64 * 1024, 64, SECT_4K | SPI_NOR_HAS_LOCK) },
 | 
						|
+	{ "f25l32qa", INFO(0x8c4116, 0, 64 * 1024, 64, SECT_4K | SPI_NOR_HAS_LOCK) },
 | 
						|
+	{ "f25l64qa", INFO(0x8c4117, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_HAS_LOCK) },
 | 
						|
 
 | 
						|
 	/* Everspin */
 | 
						|
 	{ "mr25h256", CAT25_INFO( 32 * 1024, 1, 256, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) },
 | 
						|
@@ -1020,12 +1034,15 @@ static const struct flash_info spi_nor_i
 | 
						|
 	{ "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, SECT_4K) },
 | 
						|
+	{ "mx25u2033e",  INFO(0xc22532, 0, 64 * 1024,   4, SECT_4K) },
 | 
						|
+	{ "mx25u4035",   INFO(0xc22533, 0, 64 * 1024,   8, SECT_4K) },
 | 
						|
+	{ "mx25u8035",   INFO(0xc22534, 0, 64 * 1024,  16, SECT_4K) },
 | 
						|
 	{ "mx25u3235f",	 INFO(0xc22536, 0, 64 * 1024, 64, 0) },
 | 
						|
 	{ "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) },
 | 
						|
 	{ "mx25l25635e", INFO(0xc22019, 0, 64 * 1024, 512, 0) },
 | 
						|
-	{ "mx25u25635f", INFO(0xc22539, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_4B_OPCODES) },
 | 
						|
+	{ "mx25u25635f", INFO(0xc22539, 0, 64 * 1024, 512, SECT_4K) },
 | 
						|
 	{ "mx25l25655e", INFO(0xc22619, 0, 64 * 1024, 512, 0) },
 | 
						|
 	{ "mx66l51235l", INFO(0xc2201a, 0, 64 * 1024, 1024, SPI_NOR_QUAD_READ) },
 | 
						|
 	{ "mx66l1g55g",  INFO(0xc2261b, 0, 64 * 1024, 2048, SPI_NOR_QUAD_READ) },
 | 
						|
@@ -1039,10 +1056,11 @@ static const struct flash_info spi_nor_i
 | 
						|
 	{ "n25q128a11",  INFO(0x20bb18, 0, 64 * 1024,  256, SECT_4K | SPI_NOR_QUAD_READ) },
 | 
						|
 	{ "n25q128a13",  INFO(0x20ba18, 0, 64 * 1024,  256, SECT_4K | SPI_NOR_QUAD_READ) },
 | 
						|
 	{ "n25q256a",    INFO(0x20ba19, 0, 64 * 1024,  512, SECT_4K | SPI_NOR_QUAD_READ) },
 | 
						|
+	{ "n25q256ax1",  INFO(0x20bb19, 0, 64 * 1024,  512, SECT_4K | SPI_NOR_QUAD_READ) },
 | 
						|
 	{ "n25q512a",    INFO(0x20bb20, 0, 64 * 1024, 1024, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) },
 | 
						|
 	{ "n25q512ax3",  INFO(0x20ba20, 0, 64 * 1024, 1024, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) },
 | 
						|
-	{ "n25q00",      INFO(0x20ba21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) },
 | 
						|
-	{ "n25q00a",     INFO(0x20bb21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) },
 | 
						|
+	{ "n25q00",      INFO(0x20ba21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE) },
 | 
						|
+	{ "n25q00a",     INFO(0x20bb21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE) },
 | 
						|
 
 | 
						|
 	/* PMC */
 | 
						|
 	{ "pm25lv512",   INFO(0,        0, 32 * 1024,    2, SECT_4K_PMC) },
 | 
						|
@@ -1060,8 +1078,11 @@ static const struct flash_info spi_nor_i
 | 
						|
 	{ "s70fl01gs",  INFO(0x010221, 0x4d00, 256 * 1024, 256, 0) },
 | 
						|
 	{ "s25sl12800", INFO(0x012018, 0x0300, 256 * 1024,  64, 0) },
 | 
						|
 	{ "s25sl12801", INFO(0x012018, 0x0301,  64 * 1024, 256, 0) },
 | 
						|
-	{ "s25fl128s",	INFO6(0x012018, 0x4d0180, 64 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
 | 
						|
+	{ "s25fs256s1", INFO6(0x010219, 0x4d0181, 64 * 1024, 512, 0)},
 | 
						|
+	{ "s25fl128s",	INFO6(0x012018, 0x4d0180, 64 * 1024, 256, SPI_NOR_QUAD_READ
 | 
						|
+			| SPI_NOR_DDR_QUAD_READ) },
 | 
						|
 	{ "s25fl129p0", INFO(0x012018, 0x4d00, 256 * 1024,  64, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
 | 
						|
+	{ "s25fs512s",  INFO6(0x010220, 0x4d0081, 256 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)},
 | 
						|
 	{ "s25fl129p1", INFO(0x012018, 0x4d01,  64 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
 | 
						|
 	{ "s25sl004a",  INFO(0x010212,      0,  64 * 1024,   8, 0) },
 | 
						|
 	{ "s25sl008a",  INFO(0x010213,      0,  64 * 1024,  16, 0) },
 | 
						|
@@ -1136,6 +1157,9 @@ static const struct flash_info spi_nor_i
 | 
						|
 	{ "w25x80", INFO(0xef3014, 0, 64 * 1024,  16, SECT_4K) },
 | 
						|
 	{ "w25x16", INFO(0xef3015, 0, 64 * 1024,  32, SECT_4K) },
 | 
						|
 	{ "w25x32", INFO(0xef3016, 0, 64 * 1024,  64, SECT_4K) },
 | 
						|
+	{ "w25q20cl", INFO(0xef4012, 0, 64 * 1024,  4, SECT_4K) },
 | 
						|
+	{ "w25q20bw", INFO(0xef5012, 0, 64 * 1024,  4, SECT_4K) },
 | 
						|
+	{ "w25q20ew", INFO(0xef6012, 0, 64 * 1024,  4, SECT_4K) },
 | 
						|
 	{ "w25q32", INFO(0xef4016, 0, 64 * 1024,  64, SECT_4K) },
 | 
						|
 	{
 | 
						|
 		"w25q32dw", INFO(0xef6016, 0, 64 * 1024,  64,
 | 
						|
@@ -1207,6 +1231,53 @@ static const struct flash_info *spi_nor_
 | 
						|
 		id[0], id[1], id[2]);
 | 
						|
 	return ERR_PTR(-ENODEV);
 | 
						|
 }
 | 
						|
+/*
 | 
						|
+ * The S25FS-S family physical sectors may be configured as a
 | 
						|
+ * hybrid combination of eight 4-kB parameter sectors
 | 
						|
+ * at the top or bottom of the address space with all
 | 
						|
+ * but one of the remaining sectors being uniform size.
 | 
						|
+ * The Parameter Sector Erase commands (20h or 21h) must
 | 
						|
+ * be used to erase the 4-kB parameter sectors individually.
 | 
						|
+ * The Sector (uniform sector) Erase commands (D8h or DCh)
 | 
						|
+ * must be used to erase any of the remaining
 | 
						|
+ * sectors, including the portion of highest or lowest address
 | 
						|
+ * sector that is not overlaid by the parameter sectors.
 | 
						|
+ * The uniform sector erase command has no effect on parameter sectors.
 | 
						|
+ */
 | 
						|
+static int spansion_s25fs_disable_4kb_erase(struct spi_nor *nor)
 | 
						|
+{
 | 
						|
+	struct fsl_qspi *q;
 | 
						|
+	u32 cr3v_addr  = SPINOR_CONFIG_REG3_OFFSET;
 | 
						|
+	u8 cr3v = 0x0;
 | 
						|
+	int ret = 0x0;
 | 
						|
+
 | 
						|
+	q = nor->priv;
 | 
						|
+
 | 
						|
+	nor->cmd_buf[2] = cr3v_addr >> 16;
 | 
						|
+	nor->cmd_buf[1] = cr3v_addr >> 8;
 | 
						|
+	nor->cmd_buf[0] = cr3v_addr >> 0;
 | 
						|
+
 | 
						|
+	ret = nor->read_reg(nor, SPINOR_OP_SPANSION_RDAR, &cr3v, 1);
 | 
						|
+	if (ret)
 | 
						|
+		return ret;
 | 
						|
+	if (cr3v & CR3V_4KB_ERASE_UNABLE)
 | 
						|
+		return 0;
 | 
						|
+	ret = nor->write_reg(nor, SPINOR_OP_WREN, NULL, 0);
 | 
						|
+	if (ret)
 | 
						|
+		return ret;
 | 
						|
+	cr3v = CR3V_4KB_ERASE_UNABLE;
 | 
						|
+	nor->program_opcode = SPINOR_OP_SPANSION_WRAR;
 | 
						|
+	nor->write(nor, cr3v_addr, 1, &cr3v);
 | 
						|
+
 | 
						|
+	ret = nor->read_reg(nor, SPINOR_OP_SPANSION_RDAR, &cr3v, 1);
 | 
						|
+	if (ret)
 | 
						|
+		return ret;
 | 
						|
+	if (!(cr3v & CR3V_4KB_ERASE_UNABLE))
 | 
						|
+		return -EPERM;
 | 
						|
+
 | 
						|
+	return 0;
 | 
						|
+}
 | 
						|
+
 | 
						|
 
 | 
						|
 static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len,
 | 
						|
 			size_t *retlen, u_char *buf)
 | 
						|
@@ -1426,7 +1497,7 @@ static int macronix_quad_enable(struct s
 | 
						|
  * Write status Register and configuration register with 2 bytes
 | 
						|
  * The first byte will be written to the status register, while the
 | 
						|
  * second byte will be written to the configuration register.
 | 
						|
- * Return negative if error occured.
 | 
						|
+ * Return negative if error occurred.
 | 
						|
  */
 | 
						|
 static int write_sr_cr(struct spi_nor *nor, u16 val)
 | 
						|
 {
 | 
						|
@@ -1474,6 +1545,24 @@ static int spansion_quad_enable(struct s
 | 
						|
 	return 0;
 | 
						|
 }
 | 
						|
 
 | 
						|
+static int set_ddr_quad_mode(struct spi_nor *nor, const struct flash_info *info)
 | 
						|
+{
 | 
						|
+	int status;
 | 
						|
+
 | 
						|
+	switch (JEDEC_MFR(info)) {
 | 
						|
+	case SNOR_MFR_SPANSION:
 | 
						|
+		status = spansion_quad_enable(nor);
 | 
						|
+		if (status) {
 | 
						|
+			dev_err(nor->dev, "Spansion DDR quad-read not enabled\n");
 | 
						|
+			return status;
 | 
						|
+		}
 | 
						|
+		return status;
 | 
						|
+	default:
 | 
						|
+		return -EINVAL;
 | 
						|
+	}
 | 
						|
+}
 | 
						|
+
 | 
						|
+
 | 
						|
 static int set_quad_mode(struct spi_nor *nor, const struct flash_info *info)
 | 
						|
 {
 | 
						|
 	int status;
 | 
						|
@@ -1620,9 +1709,25 @@ int spi_nor_scan(struct spi_nor *nor, co
 | 
						|
 		write_sr(nor, 0);
 | 
						|
 		spi_nor_wait_till_ready(nor);
 | 
						|
 	}
 | 
						|
+	if (JEDEC_MFR(info) == SNOR_MFR_MICRON) {
 | 
						|
+		ret = read_sr(nor);
 | 
						|
+		ret &= SPI_NOR_MICRON_WRITE_ENABLE;
 | 
						|
+
 | 
						|
+		write_enable(nor);
 | 
						|
+		write_sr(nor, ret);
 | 
						|
+	}
 | 
						|
+
 | 
						|
+	if (EXT_ID(info) == SPINOR_S25FS_FAMILY_ID) {
 | 
						|
+		ret = spansion_s25fs_disable_4kb_erase(nor);
 | 
						|
+		if (ret)
 | 
						|
+			return ret;
 | 
						|
+	}
 | 
						|
+
 | 
						|
 
 | 
						|
 	if (!mtd->name)
 | 
						|
 		mtd->name = dev_name(dev);
 | 
						|
+	if (info->name)
 | 
						|
+		nor->vendor = info->name;
 | 
						|
 	mtd->priv = nor;
 | 
						|
 	mtd->type = MTD_NORFLASH;
 | 
						|
 	mtd->writesize = 1;
 | 
						|
@@ -1656,6 +1761,8 @@ int spi_nor_scan(struct spi_nor *nor, co
 | 
						|
 		nor->flags |= SNOR_F_USE_FSR;
 | 
						|
 	if (info->flags & SPI_NOR_HAS_TB)
 | 
						|
 		nor->flags |= SNOR_F_HAS_SR_TB;
 | 
						|
+	if (info->flags & NO_CHIP_ERASE)
 | 
						|
+		nor->flags |= SNOR_F_NO_OP_CHIP_ERASE;
 | 
						|
 
 | 
						|
 #ifdef CONFIG_MTD_SPI_NOR_USE_4K_SECTORS
 | 
						|
 	/* prefer "small sector" erase if possible */
 | 
						|
@@ -1695,9 +1802,15 @@ int spi_nor_scan(struct spi_nor *nor, co
 | 
						|
 	/* Some devices cannot do fast-read, no matter what DT tells us */
 | 
						|
 	if (info->flags & SPI_NOR_NO_FR)
 | 
						|
 		nor->flash_read = SPI_NOR_NORMAL;
 | 
						|
-
 | 
						|
-	/* Quad/Dual-read mode takes precedence over fast/normal */
 | 
						|
-	if (mode == SPI_NOR_QUAD && info->flags & SPI_NOR_QUAD_READ) {
 | 
						|
+	/* DDR Quad/Quad/Dual-read mode takes precedence over fast/normal */
 | 
						|
+	if (mode == SPI_NOR_DDR_QUAD && info->flags & SPI_NOR_DDR_QUAD_READ) {
 | 
						|
+		ret = set_ddr_quad_mode(nor, info);
 | 
						|
+		if (ret) {
 | 
						|
+			dev_err(dev, "DDR quad mode not supported\n");
 | 
						|
+			return ret;
 | 
						|
+		}
 | 
						|
+		nor->flash_read = SPI_NOR_DDR_QUAD;
 | 
						|
+	} else if (mode == SPI_NOR_QUAD && info->flags & SPI_NOR_QUAD_READ) {
 | 
						|
 		ret = set_quad_mode(nor, info);
 | 
						|
 		if (ret) {
 | 
						|
 			dev_err(dev, "quad mode not supported\n");
 | 
						|
@@ -1710,6 +1823,9 @@ int spi_nor_scan(struct spi_nor *nor, co
 | 
						|
 
 | 
						|
 	/* Default commands */
 | 
						|
 	switch (nor->flash_read) {
 | 
						|
+	case SPI_NOR_DDR_QUAD:
 | 
						|
+		nor->read_opcode = SPINOR_OP_READ4_1_4_4_D;
 | 
						|
+		break;
 | 
						|
 	case SPI_NOR_QUAD:
 | 
						|
 		nor->read_opcode = SPINOR_OP_READ_1_1_4;
 | 
						|
 		break;
 | 
						|
--- a/include/linux/mtd/spi-nor.h
 | 
						|
+++ b/include/linux/mtd/spi-nor.h
 | 
						|
@@ -31,10 +31,10 @@
 | 
						|
 
 | 
						|
 /*
 | 
						|
  * Note on opcode nomenclature: some opcodes have a format like
 | 
						|
- * SPINOR_OP_FUNCTION{4,}_x_y_z. The numbers x, y, and z stand for the number
 | 
						|
+ * SPINOR_OP_FUNCTION{4,}_x_y_z{_D}. The numbers x, y,and z stand for the number
 | 
						|
  * of I/O lines used for the opcode, address, and data (respectively). The
 | 
						|
  * FUNCTION has an optional suffix of '4', to represent an opcode which
 | 
						|
- * requires a 4-byte (32-bit) address.
 | 
						|
+ * requires a 4-byte (32-bit) address. The suffix of 'D' stands for the
 | 
						|
  */
 | 
						|
 
 | 
						|
 /* Flash opcodes. */
 | 
						|
@@ -46,7 +46,9 @@
 | 
						|
 #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_D	0xed	/* Read data bytes (DDR Quad SPI) */
 | 
						|
 #define SPINOR_OP_READ_1_4_4	0xeb	/* Read data bytes (Quad I/O SPI) */
 | 
						|
+#define SPINOR_OP_READ4_1_4_4_D	0xee	/* Read data bytes (DDR Quad SPI) */
 | 
						|
 #define SPINOR_OP_PP		0x02	/* Page program (up to 256 bytes) */
 | 
						|
 #define SPINOR_OP_PP_1_1_4	0x32	/* Quad page program */
 | 
						|
 #define SPINOR_OP_PP_1_4_4	0x38	/* Quad page program */
 | 
						|
@@ -62,9 +64,11 @@
 | 
						|
 /* 4-byte address opcodes - used on Spansion and some Macronix flashes. */
 | 
						|
 #define SPINOR_OP_READ_4B	0x13	/* Read data bytes (low frequency) */
 | 
						|
 #define SPINOR_OP_READ_FAST_4B	0x0c	/* Read data bytes (high frequency) */
 | 
						|
+#define SPINOR_OP_READ4_FAST    0x0c    /* Read data bytes (high frequency) */
 | 
						|
 #define SPINOR_OP_READ_1_1_2_4B	0x3c	/* Read data bytes (Dual Output SPI) */
 | 
						|
 #define SPINOR_OP_READ_1_2_2_4B	0xbc	/* Read data bytes (Dual I/O SPI) */
 | 
						|
 #define SPINOR_OP_READ_1_1_4_4B	0x6c	/* Read data bytes (Quad Output SPI) */
 | 
						|
+#define SPINOR_OP_READ4_1_1_4  0x6c    /* Read data bytes (Quad SPI) */
 | 
						|
 #define SPINOR_OP_READ_1_4_4_4B	0xec	/* Read data bytes (Quad I/O SPI) */
 | 
						|
 #define SPINOR_OP_PP_4B		0x12	/* Page program (up to 256 bytes) */
 | 
						|
 #define SPINOR_OP_PP_1_1_4_4B	0x34	/* Quad page program */
 | 
						|
@@ -94,6 +98,10 @@
 | 
						|
 /* Used for Spansion flashes only. */
 | 
						|
 #define SPINOR_OP_BRWR		0x17	/* Bank register write */
 | 
						|
 
 | 
						|
+/* Used for Spansion S25FS-S family flash only. */
 | 
						|
+#define SPINOR_OP_SPANSION_RDAR	0x65	/* Read any device register */
 | 
						|
+#define SPINOR_OP_SPANSION_WRAR	0x71	/* Write any device register */
 | 
						|
+
 | 
						|
 /* Used for Micron flashes only. */
 | 
						|
 #define SPINOR_OP_RD_EVCR      0x65    /* Read EVCR register */
 | 
						|
 #define SPINOR_OP_WD_EVCR      0x61    /* Write EVCR register */
 | 
						|
@@ -124,6 +132,7 @@ enum read_mode {
 | 
						|
 	SPI_NOR_FAST,
 | 
						|
 	SPI_NOR_DUAL,
 | 
						|
 	SPI_NOR_QUAD,
 | 
						|
+	SPI_NOR_DDR_QUAD,
 | 
						|
 };
 | 
						|
 
 | 
						|
 #define SPI_NOR_MAX_CMD_SIZE	8
 | 
						|
@@ -189,6 +198,7 @@ struct spi_nor {
 | 
						|
 	bool			sst_write_second;
 | 
						|
 	u32			flags;
 | 
						|
 	u8			cmd_buf[SPI_NOR_MAX_CMD_SIZE];
 | 
						|
+	char			*vendor;
 | 
						|
 
 | 
						|
 	int (*prepare)(struct spi_nor *nor, enum spi_nor_ops ops);
 | 
						|
 	void (*unprepare)(struct spi_nor *nor, enum spi_nor_ops ops);
 |