
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@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