From 5b00fc8b7fbf422bdc18de2bfa414db38026094f Mon Sep 17 00:00:00 2001 From: Jagannadha Sutradharudu Teki Date: Sat, 5 Jan 2013 19:12:12 +0530 Subject: [PATCH] sf: Add bank address access support This patch provides support to access bank 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. bank address register contains an information to access the 4th byte address so-that the flashes which has > 16MB can be accessible. Signed-off-by: Jagannadha Sutradharudu Teki --- drivers/mtd/spi/spi_flash.c | 82 ++++++++++++++++++++++++++++ drivers/mtd/spi/spi_flash_internal.h | 9 +++ 2 files changed, 91 insertions(+) diff --git a/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c index 90c51c7110d..7bc4322d83a 100644 --- a/drivers/mtd/spi/spi_flash.c +++ b/drivers/mtd/spi/spi_flash.c @@ -12,6 +12,7 @@ #include #include #include +#include #include "spi_flash_internal.h" @@ -31,6 +32,30 @@ static void spi_flash_addr(struct spi_flash *flash, } } +static int spi_flash_check_bankaddr_access(struct spi_flash *flash, u32 *offset) +{ + int ret; + + if (*offset >= SZ_16M) { + ret = spi_flash_bankaddr_access(flash, STATUS_BANKADDR_ENABLE); + if (ret) { + debug("SF: fail to %s bank addr bit\n", + STATUS_BANKADDR_ENABLE ? "set" : "reset"); + return ret; + } + *offset -= SZ_16M; + } else { + ret = spi_flash_bankaddr_access(flash, STATUS_BANKADDR_DISABLE); + if (ret) { + debug("SF: fail to %s bank addr bit\n", + STATUS_BANKADDR_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, @@ -81,6 +106,14 @@ int spi_flash_cmd_write_multi(struct spi_flash *flash, u32 offset, int ret; u8 cmd[flash->addr_width+1]; + if ((flash->size > SZ_16M) && (flash->addr_width == 3)) { + ret = spi_flash_check_bankaddr_access(flash, &offset); + if (ret) { + debug("SF: fail to acess bank_addr\n"); + return ret; + } + } + page_size = flash->page_size; page_addr = offset / page_size; byte_addr = offset % page_size; @@ -149,6 +182,15 @@ int spi_flash_cmd_read_fast(struct spi_flash *flash, u32 offset, unsigned long page_size; unsigned long byte_addr; u8 cmd[flash->addr_width+2]; + int ret; + + if ((flash->size > SZ_16M) && (flash->addr_width == 3)) { + ret = spi_flash_check_bankaddr_access(flash, &offset); + if (ret) { + debug("SF: fail to acess bank_addr\n"); + return ret; + } + } page_size = flash->page_size; page_addr = offset / page_size; @@ -211,6 +253,14 @@ int spi_flash_cmd_erase(struct spi_flash *flash, u32 offset, size_t len) unsigned long page_addr; u8 cmd[flash->addr_width+1]; + if ((flash->size > SZ_16M) && (flash->addr_width == 3)) { + ret = spi_flash_check_bankaddr_access(flash, &offset); + if (ret) { + debug("SF: fail to acess bank_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"); @@ -320,6 +370,38 @@ int spi_flash_cmd_bankaddr_read(struct spi_flash *flash, void *data) return spi_flash_read_common(flash, &cmd, 1, data, 1); } +int spi_flash_bankaddr_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_bankaddr_read(flash, (void *)&data); + if (ret < 0) { + debug("SF: fail to read bank addr register\n"); + return ret; + } + + if ((data != status) & !write_done) { + debug("SF: need to %s bank addr bit\n", + status ? "set" : "reset"); + + write_done = 1; + ret = spi_flash_cmd_bankaddr_write(flash, status); + if (ret < 0) { + debug("SF: fail to write bank addr bit\n"); + return ret; + } + } else { + debug("SF: bank 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 bb22f5cd8d6..dc411e55197 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_BANKADDR_ENABLE 0x01 +#define STATUS_BANKADDR_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); @@ -87,6 +89,13 @@ int spi_flash_cmd_bankaddr_write(struct spi_flash *flash, u8 ear); /* Read the bank address register */ int spi_flash_cmd_bankaddr_read(struct spi_flash *flash, void *data); +/* + * Bank address access + * access 4th byte address in 3-byte addessing mode for flashes + * which has an actual size of > 16MB. + */ +int spi_flash_bankaddr_access(struct spi_flash *flash, u8 status); + /* * Same as spi_flash_cmd_read() except it also claims/releases the SPI * bus. Used as common part of the ->read() operation. -- 2.47.3