From 6cfe5c5e7f6a4b3d46f65967fe10820ee2e3d2fa Mon Sep 17 00:00:00 2001
From: Yunhui Cui <yunhui.cui@nxp.com>
Date: Fri, 13 May 2016 16:30:33 +0800
Subject: [PATCH 31/93] mtd: sf: add exceed flash 16MB support for qspi

spi/spi_flash.c: The flash S25FS512S cannot legacy commands
such as Bank Address Related Command, So we need add the exceed
16MB suuport. So we extend the cmd[] size to support 32-bit address,
what's more, as to spi/fsl_qspi.c need to a flag to pionts the address
mask, So add the magic num '0xaa' into cmd[].

Signed-off-by: Yunhui Cui <yunhui.cui@nxp.com>
---
 arch/arm/dts/fsl-ls1012a.dtsi    |    2 +-
 drivers/mtd/spi/sf_internal.h    |    7 ++++
 drivers/mtd/spi/spi_flash.c      |   73 ++++++++++++++++++++++++++++++--------
 drivers/spi/fsl_qspi.c           |   30 ++++++++++++++--
 include/configs/ls1012a_common.h |    3 +-
 5 files changed, 95 insertions(+), 20 deletions(-)

diff --git a/arch/arm/dts/fsl-ls1012a.dtsi b/arch/arm/dts/fsl-ls1012a.dtsi
index 87a287a..2549c91 100644
--- a/arch/arm/dts/fsl-ls1012a.dtsi
+++ b/arch/arm/dts/fsl-ls1012a.dtsi
@@ -108,7 +108,7 @@
 			#address-cells = <1>;
 			#size-cells = <0>;
 			reg = <0x0 0x1550000 0x0 0x10000>,
-				<0x0 0x40000000 0x0 0x4000000>;
+				<0x0 0x40000000 0x0 0x8000000>;
 			reg-names = "QuadSPI", "QuadSPI-memory";
 			num-cs = <2>;
 			big-endian;
diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h
index c778b60..3c38425 100644
--- a/drivers/mtd/spi/sf_internal.h
+++ b/drivers/mtd/spi/sf_internal.h
@@ -57,6 +57,13 @@ enum spi_nor_option_flags {
 #define SPI_FLASH_CMD_LEN		(1 + SPI_FLASH_3B_ADDR_LEN)
 #define SPI_FLASH_16MB_BOUN		0x1000000
 
+#define SPI_FLASH_ADDR_MAGIC		0xaa
+#define SPI_FLASH_ADDR_MAGIC_LEN	1
+#define SPI_FLASH_4B_ADDR_LEN		4
+#define SPI_FLASH_CMD_LEN_EXT		(1 + SPI_FLASH_4B_ADDR_LEN + \
+		SPI_FLASH_ADDR_MAGIC_LEN)
+#define SPI_FLASH_64MB_BOUN		0x4000000
+
 /* CFI Manufacture ID's */
 #define SPI_FLASH_CFI_MFR_SPANSION	0x01
 #define SPI_FLASH_CFI_MFR_STMICRO	0x20
diff --git a/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c
index 97e53c7..9d61ac0 100644
--- a/drivers/mtd/spi/spi_flash.c
+++ b/drivers/mtd/spi/spi_flash.c
@@ -21,12 +21,20 @@
 
 DECLARE_GLOBAL_DATA_PTR;
 
-static void spi_flash_addr(u32 addr, u8 *cmd)
+static void spi_flash_addr(u32 addr, u8 *cmd, u32 offset_ext)
 {
-	/* cmd[0] is actual command */
-	cmd[1] = addr >> 16;
-	cmd[2] = addr >> 8;
-	cmd[3] = addr >> 0;
+	if (offset_ext >= SPI_FLASH_16MB_BOUN) {
+		/* cmd[0] is actual command */
+		cmd[1] = addr >> 24;
+		cmd[2] = addr >> 16;
+		cmd[3] = addr >> 8;
+		cmd[4] = addr >> 0;
+		cmd[5] = SPI_FLASH_ADDR_MAGIC;
+	} else {
+		cmd[1] = addr >> 16;
+		cmd[2] = addr >> 8;
+		cmd[3] = addr >> 0;
+	}
 }
 
 /* Read commands array */
@@ -302,9 +310,11 @@ int spi_flash_write_common(struct spi_flash *flash, const u8 *cmd,
 int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len)
 {
 	u32 erase_size, erase_addr;
-	u8 cmd[SPI_FLASH_CMD_LEN];
+	u8 *cmd, cmdsz;
 	int ret = -1;
+	u32 offset_ext;
 
+	offset_ext = offset;
 	erase_size = flash->erase_size;
 	if (offset % erase_size || len % erase_size) {
 		debug("SF: Erase offset/length not multiple of erase size\n");
@@ -319,7 +329,18 @@ int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len)
 		}
 	}
 
+	if (offset > SPI_FLASH_16MB_BOUN)
+		cmdsz = SPI_FLASH_CMD_LEN_EXT + flash->dummy_byte;
+	else
+		cmdsz = SPI_FLASH_CMD_LEN + flash->dummy_byte;
+	cmd = calloc(1, cmdsz);
+	if (!cmd) {
+		debug("SF: Failed to allocate cmd\n");
+		return -ENOMEM;
+	}
+	memset(cmd, 0x0, cmdsz);
 	cmd[0] = flash->erase_cmd;
+
 	while (len) {
 		erase_addr = offset;
 
@@ -332,7 +353,7 @@ int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len)
 		if (ret < 0)
 			return ret;
 #endif
-		spi_flash_addr(erase_addr, cmd);
+		spi_flash_addr(erase_addr, cmd, offset_ext);
 
 		debug("SF: erase %2x %2x %2x %2x (%x)\n", cmd[0], cmd[1],
 		      cmd[2], cmd[3], erase_addr);
@@ -347,6 +368,7 @@ int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len)
 		len -= erase_size;
 	}
 
+	free(cmd);
 	return ret;
 }
 
@@ -356,9 +378,11 @@ int spi_flash_cmd_write_ops(struct spi_flash *flash, u32 offset,
 	unsigned long byte_addr, page_size;
 	u32 write_addr;
 	size_t chunk_len, actual;
-	u8 cmd[SPI_FLASH_CMD_LEN];
+	u8 *cmd, cmdsz;
 	int ret = -1;
+	u32 offset_ext;
 
+	offset_ext = offset;
 	page_size = flash->page_size;
 
 	if (flash->flash_is_locked) {
@@ -369,6 +393,16 @@ int spi_flash_cmd_write_ops(struct spi_flash *flash, u32 offset,
 		}
 	}
 
+	if (offset > SPI_FLASH_16MB_BOUN)
+		cmdsz = SPI_FLASH_CMD_LEN_EXT + flash->dummy_byte;
+	else
+		cmdsz = SPI_FLASH_CMD_LEN + flash->dummy_byte;
+	cmd = calloc(1, cmdsz);
+	if (!cmd) {
+		debug("SF: Failed to allocate cmd\n");
+		return -ENOMEM;
+	}
+	memset(cmd, 0x0, cmdsz);
 	cmd[0] = flash->write_cmd;
 	for (actual = 0; actual < len; actual += chunk_len) {
 		write_addr = offset;
@@ -389,7 +423,7 @@ int spi_flash_cmd_write_ops(struct spi_flash *flash, u32 offset,
 			chunk_len = min(chunk_len,
 					(size_t)flash->spi->max_write_size);
 
-		spi_flash_addr(write_addr, cmd);
+		spi_flash_addr(write_addr, cmd, offset_ext);
 
 		debug("SF: 0x%p => cmd = { 0x%02x 0x%02x%02x%02x } chunk_len = %zu\n",
 		      buf + actual, cmd[0], cmd[1], cmd[2], cmd[3], chunk_len);
@@ -404,6 +438,7 @@ int spi_flash_cmd_write_ops(struct spi_flash *flash, u32 offset,
 		offset += chunk_len;
 	}
 
+	free(cmd);
 	return ret;
 }
 
@@ -442,6 +477,9 @@ int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset,
 	u32 remain_len, read_len, read_addr;
 	int bank_sel = 0;
 	int ret = -1;
+	u32 offset_ext;
+
+	offset_ext = offset;
 
 	/* Handle memory-mapped SPI */
 	if (flash->memory_map) {
@@ -456,15 +494,18 @@ int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset,
 		spi_release_bus(flash->spi);
 		return 0;
 	}
-
-	cmdsz = SPI_FLASH_CMD_LEN + flash->dummy_byte;
+	if (offset > SPI_FLASH_16MB_BOUN)
+		cmdsz = SPI_FLASH_CMD_LEN_EXT + flash->dummy_byte;
+	else
+		cmdsz = SPI_FLASH_CMD_LEN + flash->dummy_byte;
 	cmd = calloc(1, cmdsz);
 	if (!cmd) {
 		debug("SF: Failed to allocate cmd\n");
 		return -ENOMEM;
 	}
-
+	memset(cmd, 0x0, cmdsz);
 	cmd[0] = flash->read_cmd;
+
 	while (len) {
 		read_addr = offset;
 
@@ -478,14 +519,18 @@ int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset,
 			return ret;
 		bank_sel = flash->bank_curr;
 #endif
-		remain_len = ((SPI_FLASH_16MB_BOUN << flash->shift) *
+		if (offset_ext >= SPI_FLASH_16MB_BOUN) {
+			remain_len = flash->size - offset;
+		} else {
+			remain_len = ((SPI_FLASH_16MB_BOUN << flash->shift) *
 				(bank_sel + 1)) - offset;
+		}
 		if (len < remain_len)
 			read_len = len;
 		else
 			read_len = remain_len;
 
-		spi_flash_addr(read_addr, cmd);
+		spi_flash_addr(read_addr, cmd, offset_ext);
 
 		ret = spi_flash_read_common(flash, cmd, cmdsz, data, read_len);
 		if (ret < 0) {
diff --git a/drivers/spi/fsl_qspi.c b/drivers/spi/fsl_qspi.c
index 2b20038..09759fa 100644
--- a/drivers/spi/fsl_qspi.c
+++ b/drivers/spi/fsl_qspi.c
@@ -26,6 +26,9 @@ DECLARE_GLOBAL_DATA_PTR;
 #endif
 
 #define OFFSET_BITS_MASK	GENMASK(23, 0)
+/* the qspi contrller memmap space ,instead of flash space */
+#define OFFSET_BITS_MASK_QSPI_SPACE	GENMASK(27, 0)
+#define SPI_FLASH_ADDR_EXT_MAGIC	0xaa
 
 #define FLASH_STATUS_WEL	0x02
 
@@ -757,6 +760,13 @@ int qspi_xfer(struct fsl_qspi_priv *priv, unsigned int bitlen,
 	u32 bytes = DIV_ROUND_UP(bitlen, 8);
 	static u32 wr_sfaddr;
 	u32 txbuf;
+	u8 offset_ext = 0;
+	u32 flash_offset;
+
+	if (((u8 *)dout)[5] == SPI_FLASH_ADDR_EXT_MAGIC) {
+		offset_ext = 1;
+		memcpy(&flash_offset, dout + 1, 4);
+	}
 
 	if (dout) {
 		if (flags & SPI_XFER_BEGIN) {
@@ -772,14 +782,28 @@ int qspi_xfer(struct fsl_qspi_priv *priv, unsigned int bitlen,
 
 		if (priv->cur_seqid == QSPI_CMD_FAST_READ ||
 		    priv->cur_seqid == QSPI_CMD_RDAR) {
-			priv->sf_addr = swab32(txbuf) & OFFSET_BITS_MASK;
+			if (offset_ext)
+				priv->sf_addr = swab32(flash_offset) &
+					OFFSET_BITS_MASK_QSPI_SPACE;
+			else
+				priv->sf_addr = swab32(txbuf) &
+					OFFSET_BITS_MASK;
 		} else if ((priv->cur_seqid == QSPI_CMD_SE) ||
 			   (priv->cur_seqid == QSPI_CMD_BE_4K)) {
-			priv->sf_addr = swab32(txbuf) & OFFSET_BITS_MASK;
+			if (offset_ext)
+				priv->sf_addr = swab32(flash_offset) &
+					OFFSET_BITS_MASK_QSPI_SPACE;
+			else
+				priv->sf_addr = swab32(txbuf) &
+					OFFSET_BITS_MASK;
 			qspi_op_erase(priv);
 		} else if (priv->cur_seqid == QSPI_CMD_PP ||
 			   priv->cur_seqid == QSPI_CMD_WRAR) {
-			wr_sfaddr = swab32(txbuf) & OFFSET_BITS_MASK;
+			if (offset_ext)
+				wr_sfaddr = swab32(flash_offset) &
+					OFFSET_BITS_MASK_QSPI_SPACE;
+			else
+				wr_sfaddr = swab32(txbuf) & OFFSET_BITS_MASK;
 		} else if ((priv->cur_seqid == QSPI_CMD_BRWR) ||
 			 (priv->cur_seqid == QSPI_CMD_WREAR)) {
 #ifdef CONFIG_SPI_FLASH_BAR
diff --git a/include/configs/ls1012a_common.h b/include/configs/ls1012a_common.h
index 3fd360a..150444d 100644
--- a/include/configs/ls1012a_common.h
+++ b/include/configs/ls1012a_common.h
@@ -63,9 +63,8 @@
 #define QSPI0_AMBA_BASE		0x40000000
 #define CONFIG_SPI_FLASH_SPANSION
 #define CONFIG_DM_SPI_FLASH
-#define CONFIG_SPI_FLASH_BAR
 
-#define FSL_QSPI_FLASH_SIZE		(1 << 24)
+#define FSL_QSPI_FLASH_SIZE		(1 << 26)
 #define FSL_QSPI_FLASH_NUM		2
 
 /*
-- 
1.7.9.5

