[U-Boot] [PATCH 3/4] sf: Add extended address access support

Jagannadha Sutradharudu Teki jagannadha.sutradharudu-teki at xilinx.com
Sat Feb 23 12:39:00 CET 2013


This patch provides support to access an extended addressing
in 3-byte address mode.

The current implementation in spi_flash supports 3-byte address mode
due to this up to 16MB amount of flash is able to access for those
flashes which has an actual size of > 16MB.

extended/bank address register contains an information to access the
4th byte addressing hence the flashes which has > 16MB can be accessible.

Signed-off-by: Jagannadha Sutradharudu Teki <jaganna at xilinx.com>
---
 drivers/mtd/spi/spi_flash.c          |   81 ++++++++++++++++++++++++++++++++++
 drivers/mtd/spi/spi_flash_internal.h |    8 +++
 2 files changed, 89 insertions(+), 0 deletions(-)

diff --git a/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c
index c168c1c..16e5f59 100644
--- a/drivers/mtd/spi/spi_flash.c
+++ b/drivers/mtd/spi/spi_flash.c
@@ -23,6 +23,30 @@ static void spi_flash_addr(u32 addr, u8 *cmd)
 	cmd[3] = addr >> 0;
 }
 
+static int spi_flash_check_extaddr_access(struct spi_flash *flash, u32 *offset)
+{
+	int ret;
+
+	if (*offset >= 0x1000000) {
+		ret = spi_flash_extaddr_access(flash, STATUS_EXTADDR_ENABLE);
+		if (ret) {
+			debug("SF: fail to %s ext addr bit\n",
+				STATUS_EXTADDR_ENABLE ? "set" : "reset");
+			return ret;
+		}
+		*offset -= 0x1000000;
+	} else {
+		ret = spi_flash_extaddr_access(flash, STATUS_EXTADDR_DISABLE);
+		if (ret) {
+			debug("SF: fail to %s ext addr bit\n",
+				STATUS_EXTADDR_DISABLE ? "set" : "reset");
+			return ret;
+		}
+	}
+
+	return ret;
+}
+
 static int spi_flash_read_write(struct spi_slave *spi,
 				const u8 *cmd, size_t cmd_len,
 				const u8 *data_out, u8 *data_in,
@@ -73,6 +97,14 @@ int spi_flash_cmd_write_multi(struct spi_flash *flash, u32 offset,
 	int ret;
 	u8 cmd[4];
 
+	if (flash->size > 0x1000000) {
+		ret = spi_flash_check_extaddr_access(flash, &offset);
+		if (ret) {
+			debug("SF: fail to acess ext_addr\n");
+			return ret;
+		}
+	}
+
 	page_size = flash->page_size;
 	page_addr = offset / page_size;
 	byte_addr = offset % page_size;
@@ -139,6 +171,15 @@ int spi_flash_cmd_read_fast(struct spi_flash *flash, u32 offset,
 		size_t len, void *data)
 {
 	u8 cmd[5];
+	int ret;
+
+	if (flash->size > 0x1000000) {
+		ret = spi_flash_check_extaddr_access(flash, &offset);
+		if (ret) {
+			debug("SF: fail to acess ext_addr\n");
+			return ret;
+		}
+	}
 
 	cmd[0] = CMD_READ_ARRAY_FAST;
 	spi_flash_addr(offset, cmd);
@@ -196,6 +237,14 @@ int spi_flash_cmd_erase(struct spi_flash *flash, u32 offset, size_t len)
 	int ret;
 	u8 cmd[4];
 
+	if (flash->size > 0x1000000) {
+		ret = spi_flash_check_extaddr_access(flash, &offset);
+		if (ret) {
+			debug("SF: fail to acess ext_addr\n");
+			return ret;
+		}
+	}
+
 	erase_size = flash->sector_size;
 	if (offset % erase_size || len % erase_size) {
 		debug("SF: Erase offset/length not multiple of erase size\n");
@@ -333,6 +382,38 @@ int spi_flash_cmd_extaddr_read(struct spi_flash *flash, void *data)
 	return spi_flash_read_common(flash, &cmd, 1, data, 1);
 }
 
+int spi_flash_extaddr_access(struct spi_flash *flash, u8 status)
+{
+	int ret, pass;
+	u8 data = 0, write_done = 0;
+
+	for (pass = 0; pass < 2; pass++) {
+		ret = spi_flash_cmd_extaddr_read(flash, (void *)&data);
+		if (ret < 0) {
+			debug("SF: fail to read ext addr register\n");
+			return ret;
+		}
+
+		if ((data != status) & !write_done) {
+			debug("SF: need to %s ext addr bit\n",
+						status ? "set" : "reset");
+
+			write_done = 1;
+			ret = spi_flash_cmd_extaddr_write(flash, status);
+			if (ret < 0) {
+				debug("SF: fail to write ext addr bit\n");
+				return ret;
+			}
+		} else {
+			debug("SF: ext addr bit is %s.\n",
+						status ? "set" : "reset");
+			return ret;
+		}
+	}
+
+	return -1;
+}
+
 /*
  * The following table holds all device probe functions
  *
diff --git a/drivers/mtd/spi/spi_flash_internal.h b/drivers/mtd/spi/spi_flash_internal.h
index 65960ad..a6b04d7 100644
--- a/drivers/mtd/spi/spi_flash_internal.h
+++ b/drivers/mtd/spi/spi_flash_internal.h
@@ -34,6 +34,8 @@
 
 /* Common status */
 #define STATUS_WIP			0x01
+#define STATUS_EXTADDR_ENABLE		0x01
+#define STATUS_EXTADDR_DISABLE		0x00
 
 /* Send a single-byte command to the device and read the response */
 int spi_flash_cmd(struct spi_slave *spi, u8 cmd, void *response, size_t len);
@@ -86,6 +88,12 @@ int spi_flash_cmd_extaddr_write(struct spi_flash *flash, u8 ear);
 
 /* Read the extended address register */
 int spi_flash_cmd_extaddr_read(struct spi_flash *flash, void *data);
+/*
+ * Extended address access
+ * access 4th byte address in 3-byte addessing mode for flashes
+ * which has an actual size of > 16MB.
+ */
+int spi_flash_extaddr_access(struct spi_flash *flash, u8 status);
 
 /*
  * Same as spi_flash_cmd_read() except it also claims/releases the SPI
-- 
1.7.4




More information about the U-Boot mailing list