[U-Boot] [WIP/PATCH 0/4] unify SPI flash drivers

The amount of duplication across SPI flash driver has always annoyed me, and we've seen bugs that affect multiple drivers fixed in only some, and I figure if the Linux kernel driver can unify these things, then there is really no reason we can't too.
So this here are a few incremental patches to get us closer to a unified driver. I think the diffstat speaks for itself, and there are even more pieces here which could possibly be merged. But I got bored for now.
I've only lightly tested them so far with one SPI flash driver, so for now they're not for merging. Once I can get more testing on our side, I'll send out a pull request.
For you adventurous/bored types, you can grab these from my sf branch: git://git.denx.de/u-boot-blackfin.git Any feedback as to success/failure would be great.
Mike Frysinger (4): sf: unify read/write helpers sf: unify status polling for ready bit sf: unify erase functions sf: unify read functions
drivers/mtd/spi/atmel.c | 49 +--------- drivers/mtd/spi/eon.c | 121 ++----------------------- drivers/mtd/spi/macronix.c | 126 ++------------------------ drivers/mtd/spi/spansion.c | 120 +----------------------- drivers/mtd/spi/spi_flash.c | 170 +++++++++++++++++++++++++--------- drivers/mtd/spi/spi_flash_internal.h | 23 +++++ drivers/mtd/spi/sst.c | 116 +---------------------- drivers/mtd/spi/stmicro.c | 125 +------------------------ drivers/mtd/spi/winbond.c | 148 +---------------------------- 9 files changed, 190 insertions(+), 808 deletions(-)

These functions largely do the same exact thing, so unify them all into one basic function.
Signed-off-by: Mike Frysinger vapier@gentoo.org --- drivers/mtd/spi/spi_flash.c | 67 ++++++++++++------------------------------ 1 files changed, 19 insertions(+), 48 deletions(-)
diff --git a/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c index b61d219..2b7f22c 100644 --- a/drivers/mtd/spi/spi_flash.c +++ b/drivers/mtd/spi/spi_flash.c @@ -14,32 +14,10 @@
#include "spi_flash_internal.h"
-int spi_flash_cmd(struct spi_slave *spi, u8 cmd, void *response, size_t len) -{ - unsigned long flags = SPI_XFER_BEGIN; - int ret; - - if (len == 0) - flags |= SPI_XFER_END; - - ret = spi_xfer(spi, 8, &cmd, NULL, flags); - if (ret) { - debug("SF: Failed to send command %02x: %d\n", cmd, ret); - return ret; - } - - if (len) { - ret = spi_xfer(spi, len * 8, NULL, response, SPI_XFER_END); - if (ret) - debug("SF: Failed to read response (%zu bytes): %d\n", - len, ret); - } - - return ret; -} - -int spi_flash_cmd_read(struct spi_slave *spi, const u8 *cmd, - size_t cmd_len, void *data, size_t data_len) +static int spi_flash_read_write(struct spi_slave *spi, + const u8 *cmd, size_t cmd_len, + const u8 *data_out, u8 *data_in, + size_t data_len) { unsigned long flags = SPI_XFER_BEGIN; int ret; @@ -49,41 +27,34 @@ int spi_flash_cmd_read(struct spi_slave *spi, const u8 *cmd,
ret = spi_xfer(spi, cmd_len * 8, cmd, NULL, flags); if (ret) { - debug("SF: Failed to send read command (%zu bytes): %d\n", + debug("SF: Failed to send command (%zu bytes): %d\n", cmd_len, ret); } else if (data_len != 0) { - ret = spi_xfer(spi, data_len * 8, NULL, data, SPI_XFER_END); + ret = spi_xfer(spi, data_len * 8, data_out, data_in, SPI_XFER_END); if (ret) - debug("SF: Failed to read %zu bytes of data: %d\n", + debug("SF: Failed to transfer %zu bytes of data: %d\n", data_len, ret); }
return ret; }
-int spi_flash_cmd_write(struct spi_slave *spi, const u8 *cmd, size_t cmd_len, - const void *data, size_t data_len) +int spi_flash_cmd(struct spi_slave *spi, u8 cmd, void *response, size_t len) { - unsigned long flags = SPI_XFER_BEGIN; - int ret; - - if (data_len == 0) - flags |= SPI_XFER_END; - - ret = spi_xfer(spi, cmd_len * 8, cmd, NULL, flags); - if (ret) { - debug("SF: Failed to send read command (%zu bytes): %d\n", - cmd_len, ret); - } else if (data_len != 0) { - ret = spi_xfer(spi, data_len * 8, data, NULL, SPI_XFER_END); - if (ret) - debug("SF: Failed to read %zu bytes of data: %d\n", - data_len, ret); - } + return spi_flash_cmd_read(spi, &cmd, 1, response, len); +}
- return ret; +int spi_flash_cmd_read(struct spi_slave *spi, const u8 *cmd, + size_t cmd_len, void *data, size_t data_len) +{ + return spi_flash_read_write(spi, cmd, cmd_len, NULL, data, data_len); }
+int spi_flash_cmd_write(struct spi_slave *spi, const u8 *cmd, size_t cmd_len, + const void *data, size_t data_len) +{ + return spi_flash_read_write(spi, cmd, cmd_len, data, NULL, data_len); +}
int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd, size_t cmd_len, void *data, size_t data_len)

Dear Mike Frysinger,
In message 1294644014-7560-2-git-send-email-vapier@gentoo.org you wrote:
These functions largely do the same exact thing, so unify them all into one basic function.
Signed-off-by: Mike Frysinger vapier@gentoo.org
drivers/mtd/spi/spi_flash.c | 67 ++++++++++++------------------------------ 1 files changed, 19 insertions(+), 48 deletions(-)
Applied, thanks.
Best regards,
Wolfgang Denk

All of the spi flash drivers implement the status register polling for detecting the device ready state, so unify them all in a new helper function -- spi_flash_wait_ready.
Signed-off-by: Mike Frysinger vapier@gentoo.org --- drivers/mtd/spi/atmel.c | 31 +------------------- drivers/mtd/spi/eon.c | 48 ++----------------------------- drivers/mtd/spi/macronix.c | 48 ++----------------------------- drivers/mtd/spi/spansion.c | 41 ++------------------------ drivers/mtd/spi/spi_flash.c | 41 +++++++++++++++++++++++++++ drivers/mtd/spi/spi_flash_internal.h | 15 ++++++++++ drivers/mtd/spi/sst.c | 41 ++------------------------- drivers/mtd/spi/stmicro.c | 48 ++----------------------------- drivers/mtd/spi/winbond.c | 51 ++------------------------------- 9 files changed, 81 insertions(+), 283 deletions(-)
diff --git a/drivers/mtd/spi/atmel.c b/drivers/mtd/spi/atmel.c index 8d02169..7827b75 100644 --- a/drivers/mtd/spi/atmel.c +++ b/drivers/mtd/spi/atmel.c @@ -113,35 +113,8 @@ static const struct atmel_spi_flash_params atmel_spi_flash_table[] = {
static int at45_wait_ready(struct spi_flash *flash, unsigned long timeout) { - struct spi_slave *spi = flash->spi; - unsigned long timebase; - int ret; - u8 cmd = CMD_AT45_READ_STATUS; - u8 status; - - timebase = get_timer(0); - - ret = spi_xfer(spi, 8, &cmd, NULL, SPI_XFER_BEGIN); - if (ret) - return -1; - - do { - ret = spi_xfer(spi, 8, NULL, &status, 0); - if (ret) - return -1; - - if (status & AT45_STATUS_READY) - break; - } while (get_timer(timebase) < timeout); - - /* Deactivate CS */ - spi_xfer(spi, 0, NULL, NULL, SPI_XFER_END); - - if (status & AT45_STATUS_READY) - return 0; - - /* Timed out */ - return -1; + return spi_flash_cmd_poll_bit(flash, timeout, + CMD_AT45_READ_STATUS, AT45_STATUS_READY); }
/* diff --git a/drivers/mtd/spi/eon.c b/drivers/mtd/spi/eon.c index 02c3bb9..4af1e06 100644 --- a/drivers/mtd/spi/eon.c +++ b/drivers/mtd/spi/eon.c @@ -25,8 +25,6 @@
#define EON_ID_EN25Q128 0x18
-#define EON_SR_WIP (1 << 0) /* Write-in-Progress */ - struct eon_spi_flash_params { u8 idcode1; u16 page_size; @@ -58,40 +56,6 @@ static const struct eon_spi_flash_params eon_spi_flash_table[] = { }, };
-static int eon_wait_ready(struct spi_flash *flash, unsigned long timeout) -{ - struct spi_slave *spi = flash->spi; - unsigned long timebase; - int ret; - u8 cmd = CMD_EN25Q128_RDSR; - u8 status; - - ret = spi_xfer(spi, 8, &cmd, NULL, SPI_XFER_BEGIN); - if (ret) { - debug("SF: Failed to send command %02x: %d\n", cmd, ret); - return ret; - } - - timebase = get_timer(0); - do { - ret = spi_xfer(spi, 8, NULL, &status, 0); - if (ret) - return -1; - - if ((status & EON_SR_WIP) == 0) - break; - - } while (get_timer(timebase) < timeout); - - spi_xfer(spi, 0, NULL, NULL, SPI_XFER_END); - - if ((status & EON_SR_WIP) == 0) - return 0; - - /* Timed out */ - return -1; -} - static int eon_read_fast(struct spi_flash *flash, u32 offset, size_t len, void *buf) { @@ -160,11 +124,9 @@ static int eon_write(struct spi_flash *flash, break; }
- ret = eon_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); - if (ret < 0) { - debug("SF: EON page programming timed out\n"); + ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); + if (ret) break; - }
page_addr++; byte_addr = 0; @@ -221,11 +183,9 @@ int eon_erase(struct spi_flash *flash, u32 offset, size_t len) break; }
- ret = eon_wait_ready(flash, SPI_FLASH_PAGE_ERASE_TIMEOUT); - if (ret < 0) { - debug("SF: EON page erase timed out\n"); + ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PAGE_ERASE_TIMEOUT); + if (ret) break; - } }
debug("SF: EON: Successfully erased %u bytes @ 0x%x\n", diff --git a/drivers/mtd/spi/macronix.c b/drivers/mtd/spi/macronix.c index 76d5284..291fd17 100644 --- a/drivers/mtd/spi/macronix.c +++ b/drivers/mtd/spi/macronix.c @@ -49,8 +49,6 @@ #define CMD_MX25XX_DP 0xb9 /* Deep Power-down */ #define CMD_MX25XX_RES 0xab /* Release from DP, and Read Signature */
-#define MACRONIX_SR_WIP (1 << 0) /* Write-in-Progress */ - struct macronix_spi_flash_params { u16 idcode; u16 page_size; @@ -114,40 +112,6 @@ static const struct macronix_spi_flash_params macronix_spi_flash_table[] = { }, };
-static int macronix_wait_ready(struct spi_flash *flash, unsigned long timeout) -{ - struct spi_slave *spi = flash->spi; - unsigned long timebase; - int ret; - u8 status; - u8 cmd = CMD_MX25XX_RDSR; - - ret = spi_xfer(spi, 8, &cmd, NULL, SPI_XFER_BEGIN); - if (ret) { - debug("SF: Failed to send command %02x: %d\n", cmd, ret); - return ret; - } - - timebase = get_timer(0); - do { - ret = spi_xfer(spi, 8, NULL, &status, 0); - if (ret) - return -1; - - if ((status & MACRONIX_SR_WIP) == 0) - break; - - } while (get_timer(timebase) < timeout); - - spi_xfer(spi, 0, NULL, NULL, SPI_XFER_END); - - if ((status & MACRONIX_SR_WIP) == 0) - return 0; - - /* Timed out */ - return -1; -} - static int macronix_read_fast(struct spi_flash *flash, u32 offset, size_t len, void *buf) { @@ -216,11 +180,9 @@ static int macronix_write(struct spi_flash *flash, break; }
- ret = macronix_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); - if (ret < 0) { - debug("SF: Macronix page programming timed out\n"); + ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); + if (ret) break; - }
page_addr++; byte_addr = 0; @@ -282,11 +244,9 @@ int macronix_erase(struct spi_flash *flash, u32 offset, size_t len) break; }
- ret = macronix_wait_ready(flash, SPI_FLASH_PAGE_ERASE_TIMEOUT); - if (ret < 0) { - debug("SF: Macronix page erase timed out\n"); + ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PAGE_ERASE_TIMEOUT); + if (ret) break; - } }
debug("SF: Macronix: Successfully erased %u bytes @ 0x%x\n", diff --git a/drivers/mtd/spi/spansion.c b/drivers/mtd/spi/spansion.c index c0900f9..d0f03ff 100644 --- a/drivers/mtd/spi/spansion.c +++ b/drivers/mtd/spi/spansion.c @@ -54,8 +54,6 @@ #define SPSN_EXT_ID_S25FL128P_64KB 0x0301 #define SPSN_EXT_ID_S25FL032P 0x4d00
-#define SPANSION_SR_WIP (1 << 0) /* Write-in-Progress */ - struct spansion_spi_flash_params { u16 idcode1; u16 idcode2; @@ -135,32 +133,6 @@ static const struct spansion_spi_flash_params spansion_spi_flash_table[] = { }, };
-static int spansion_wait_ready(struct spi_flash *flash, unsigned long timeout) -{ - struct spi_slave *spi = flash->spi; - unsigned long timebase; - int ret; - u8 status; - - timebase = get_timer(0); - do { - ret = spi_flash_cmd(spi, CMD_S25FLXX_RDSR, &status, sizeof(status)); - if (ret) - return -1; - - if ((status & SPANSION_SR_WIP) == 0) - break; - - } while (get_timer(timebase) < timeout); - - - if ((status & SPANSION_SR_WIP) == 0) - return 0; - - /* Timed out */ - return -1; -} - static int spansion_read_fast(struct spi_flash *flash, u32 offset, size_t len, void *buf) { @@ -233,11 +205,9 @@ static int spansion_write(struct spi_flash *flash, break; }
- ret = spansion_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); - if (ret < 0) { - debug("SF: SPANSION page programming timed out\n"); + ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); + if (ret) break; - }
page_addr++; byte_addr = 0; @@ -297,12 +267,9 @@ int spansion_erase(struct spi_flash *flash, u32 offset, size_t len) break; }
- /* Up to 2 seconds */ - ret = spansion_wait_ready(flash, SPI_FLASH_PAGE_ERASE_TIMEOUT); - if (ret < 0) { - debug("SF: SPANSION page erase timed out\n"); + ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PAGE_ERASE_TIMEOUT); + if (ret) break; - } }
debug("SF: SPANSION: Successfully erased %u bytes @ 0x%x\n", diff --git a/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c index 2b7f22c..e483ce4 100644 --- a/drivers/mtd/spi/spi_flash.c +++ b/drivers/mtd/spi/spi_flash.c @@ -69,6 +69,47 @@ int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd, return ret; }
+int spi_flash_cmd_poll_bit(struct spi_flash *flash, unsigned long timeout, + u8 cmd, u8 poll_bit) +{ + struct spi_slave *spi = flash->spi; + unsigned long timebase; + int ret; + u8 status; + + ret = spi_xfer(spi, 8, &cmd, NULL, SPI_XFER_BEGIN); + if (ret) { + debug("SF: Failed to send command %02x: %d\n", cmd, ret); + return ret; + } + + timebase = get_timer(0); + do { + ret = spi_xfer(spi, 8, NULL, &status, 0); + if (ret) + return -1; + + if ((status & poll_bit) == 0) + break; + + } while (get_timer(timebase) < timeout); + + spi_xfer(spi, 0, NULL, NULL, SPI_XFER_END); + + if ((status & poll_bit) == 0) + return 0; + + /* Timed out */ + debug("SF: time out!\n"); + return -1; +} + +int spi_flash_cmd_wait_ready(struct spi_flash *flash, unsigned long timeout) +{ + return spi_flash_cmd_poll_bit(flash, timeout, + CMD_READ_STATUS, STATUS_WIP); +} + /* * 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 68dcffb..440c044 100644 --- a/drivers/mtd/spi/spi_flash_internal.h +++ b/drivers/mtd/spi/spi_flash_internal.h @@ -19,6 +19,11 @@ #define CMD_READ_ARRAY_FAST 0x0b #define CMD_READ_ARRAY_LEGACY 0xe8
+#define CMD_READ_STATUS 0x05 + +/* Common status */ +#define STATUS_WIP 0x01 + /* 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);
@@ -43,6 +48,16 @@ int spi_flash_cmd_write(struct spi_slave *spi, const u8 *cmd, size_t cmd_len, int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd, size_t cmd_len, void *data, size_t data_len);
+/* Send a command to the device and wait for some bit to clear itself. */ +int spi_flash_cmd_poll_bit(struct spi_flash *flash, unsigned long timeout, + u8 cmd, u8 poll_bit); + +/* + * Send the read status command to the device and wait for the wip + * (write-in-progress) bit to clear itself. + */ +int spi_flash_cmd_wait_ready(struct spi_flash *flash, unsigned long timeout); + /* Manufacturer-specific probe functions */ struct spi_flash *spi_flash_probe_spansion(struct spi_slave *spi, u8 *idcode); struct spi_flash *spi_flash_probe_atmel(struct spi_slave *spi, u8 *idcode); diff --git a/drivers/mtd/spi/sst.c b/drivers/mtd/spi/sst.c index 2557891..4a82f8a 100644 --- a/drivers/mtd/spi/sst.c +++ b/drivers/mtd/spi/sst.c @@ -90,41 +90,6 @@ static const struct sst_spi_flash_params sst_spi_flash_table[] = { };
static int -sst_wait_ready(struct spi_flash *flash, unsigned long timeout) -{ - struct spi_slave *spi = flash->spi; - unsigned long timebase; - int ret; - u8 byte = CMD_SST_RDSR; - - ret = spi_xfer(spi, sizeof(byte) * 8, &byte, NULL, SPI_XFER_BEGIN); - if (ret) { - debug("SF: Failed to send command %02x: %d\n", byte, ret); - return ret; - } - - timebase = get_timer(0); - do { - ret = spi_xfer(spi, sizeof(byte) * 8, NULL, &byte, 0); - if (ret) - break; - - if ((byte & SST_SR_WIP) == 0) - break; - - } while (get_timer(timebase) < timeout); - - spi_xfer(spi, 0, NULL, NULL, SPI_XFER_END); - - if (!ret && (byte & SST_SR_WIP) != 0) - ret = -1; - - if (ret) - debug("SF: sst wait for ready timed out\n"); - return ret; -} - -static int sst_enable_writing(struct spi_flash *flash) { int ret = spi_flash_cmd(flash->spi, CMD_SST_WREN, NULL, 0); @@ -177,7 +142,7 @@ sst_byte_write(struct spi_flash *flash, u32 offset, const void *buf) if (ret) return ret;
- return sst_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); + return spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); }
static int @@ -224,7 +189,7 @@ sst_write(struct spi_flash *flash, u32 offset, size_t len, const void *buf) break; }
- ret = sst_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); + ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); if (ret) break;
@@ -298,7 +263,7 @@ sst_erase(struct spi_flash *flash, u32 offset, size_t len) break; }
- ret = sst_wait_ready(flash, SPI_FLASH_PAGE_ERASE_TIMEOUT); + ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PAGE_ERASE_TIMEOUT); if (ret) break; } diff --git a/drivers/mtd/spi/stmicro.c b/drivers/mtd/spi/stmicro.c index 3134027..02da8b2 100644 --- a/drivers/mtd/spi/stmicro.c +++ b/drivers/mtd/spi/stmicro.c @@ -55,8 +55,6 @@ #define STM_ID_M25P80 0x14 #define STM_ID_M25P128 0x18
-#define STMICRO_SR_WIP (1 << 0) /* Write-in-Progress */ - struct stmicro_spi_flash_params { u8 idcode1; u16 page_size; @@ -136,40 +134,6 @@ static const struct stmicro_spi_flash_params stmicro_spi_flash_table[] = { }, };
-static int stmicro_wait_ready(struct spi_flash *flash, unsigned long timeout) -{ - struct spi_slave *spi = flash->spi; - unsigned long timebase; - int ret; - u8 cmd = CMD_M25PXX_RDSR; - u8 status; - - ret = spi_xfer(spi, 8, &cmd, NULL, SPI_XFER_BEGIN); - if (ret) { - debug("SF: Failed to send command %02x: %d\n", cmd, ret); - return ret; - } - - timebase = get_timer(0); - do { - ret = spi_xfer(spi, 8, NULL, &status, 0); - if (ret) - return -1; - - if ((status & STMICRO_SR_WIP) == 0) - break; - - } while (get_timer(timebase) < timeout); - - spi_xfer(spi, 0, NULL, NULL, SPI_XFER_END); - - if ((status & STMICRO_SR_WIP) == 0) - return 0; - - /* Timed out */ - return -1; -} - static int stmicro_read_fast(struct spi_flash *flash, u32 offset, size_t len, void *buf) { @@ -238,11 +202,9 @@ static int stmicro_write(struct spi_flash *flash, break; }
- ret = stmicro_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); - if (ret < 0) { - debug("SF: STMicro page programming timed out\n"); + ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); + if (ret) break; - }
page_addr++; byte_addr = 0; @@ -304,11 +266,9 @@ int stmicro_erase(struct spi_flash *flash, u32 offset, size_t len) break; }
- ret = stmicro_wait_ready(flash, SPI_FLASH_PAGE_ERASE_TIMEOUT); - if (ret < 0) { - debug("SF: STMicro page erase timed out\n"); + ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PAGE_ERASE_TIMEOUT); + if (ret) break; - } }
debug("SF: STMicro: Successfully erased %u bytes @ 0x%x\n", diff --git a/drivers/mtd/spi/winbond.c b/drivers/mtd/spi/winbond.c index 4452355..d8c1cb1 100644 --- a/drivers/mtd/spi/winbond.c +++ b/drivers/mtd/spi/winbond.c @@ -24,8 +24,6 @@ #define CMD_W25_DP 0xb9 /* Deep Power-down */ #define CMD_W25_RES 0xab /* Release from DP, and Read Signature */
-#define WINBOND_SR_WIP (1 << 0) /* Write-in-Progress */ - struct winbond_spi_flash_params { uint16_t id; /* Log2 of page size in power-of-two mode */ @@ -107,43 +105,6 @@ static const struct winbond_spi_flash_params winbond_spi_flash_table[] = { }, };
-static int winbond_wait_ready(struct spi_flash *flash, unsigned long timeout) -{ - struct spi_slave *spi = flash->spi; - unsigned long timebase; - int ret; - u8 status; - u8 cmd[4] = { CMD_W25_RDSR, 0xff, 0xff, 0xff }; - - ret = spi_xfer(spi, 32, &cmd[0], NULL, SPI_XFER_BEGIN); - if (ret) { - debug("SF: Failed to send command %02x: %d\n", cmd, ret); - return ret; - } - - timebase = get_timer(0); - do { - ret = spi_xfer(spi, 8, NULL, &status, 0); - if (ret) { - debug("SF: Failed to get status for cmd %02x: %d\n", cmd, ret); - return -1; - } - - if ((status & WINBOND_SR_WIP) == 0) - break; - - } while (get_timer(timebase) < timeout); - - spi_xfer(spi, 0, NULL, NULL, SPI_XFER_END); - - if ((status & WINBOND_SR_WIP) == 0) - return 0; - - debug("SF: Timed out on command %02x: %d\n", cmd, ret); - /* Timed out */ - return -1; -} - /* * Assemble the address part of a command for Winbond devices in * non-power-of-two page size mode. @@ -230,11 +191,9 @@ static int winbond_write(struct spi_flash *flash, goto out; }
- ret = winbond_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); - if (ret < 0) { - debug("SF: Winbond page programming timed out\n"); + ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); + if (ret) goto out; - }
page_addr++; byte_addr = 0; @@ -298,11 +257,9 @@ int winbond_erase(struct spi_flash *flash, u32 offset, size_t len) goto out; }
- ret = winbond_wait_ready(flash, SPI_FLASH_PAGE_ERASE_TIMEOUT); - if (ret < 0) { - debug("SF: Winbond sector erase timed out\n"); + ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PAGE_ERASE_TIMEOUT); + if (ret) goto out; - } }
debug("SF: Winbond: Successfully erased %u bytes @ 0x%x\n",

Dear Mike Frysinger,
In message 1294644014-7560-3-git-send-email-vapier@gentoo.org you wrote:
All of the spi flash drivers implement the status register polling for detecting the device ready state, so unify them all in a new helper function -- spi_flash_wait_ready.
Signed-off-by: Mike Frysinger vapier@gentoo.org
drivers/mtd/spi/atmel.c | 31 +------------------- drivers/mtd/spi/eon.c | 48 ++----------------------------- drivers/mtd/spi/macronix.c | 48 ++----------------------------- drivers/mtd/spi/spansion.c | 41 ++------------------------ drivers/mtd/spi/spi_flash.c | 41 +++++++++++++++++++++++++++ drivers/mtd/spi/spi_flash_internal.h | 15 ++++++++++ drivers/mtd/spi/sst.c | 41 ++------------------------- drivers/mtd/spi/stmicro.c | 48 ++----------------------------- drivers/mtd/spi/winbond.c | 51 ++------------------------------- 9 files changed, 81 insertions(+), 283 deletions(-)
Applied, thanks.
Best regards,
Wolfgang Denk

Signed-off-by: Mike Frysinger vapier@gentoo.org --- drivers/mtd/spi/eon.c | 55 ++--------------------------- drivers/mtd/spi/macronix.c | 60 ++------------------------------ drivers/mtd/spi/spansion.c | 57 ++----------------------------- drivers/mtd/spi/spi_flash.c | 58 +++++++++++++++++++++++++++++++ drivers/mtd/spi/spi_flash_internal.h | 5 +++ drivers/mtd/spi/sst.c | 63 ++-------------------------------- drivers/mtd/spi/stmicro.c | 59 ++------------------------------ drivers/mtd/spi/winbond.c | 61 ++------------------------------- 8 files changed, 83 insertions(+), 335 deletions(-)
diff --git a/drivers/mtd/spi/eon.c b/drivers/mtd/spi/eon.c index 4af1e06..0c0b05f 100644 --- a/drivers/mtd/spi/eon.c +++ b/drivers/mtd/spi/eon.c @@ -141,58 +141,11 @@ static int eon_write(struct spi_flash *flash,
int eon_erase(struct spi_flash *flash, u32 offset, size_t len) { - /* block erase */ struct eon_spi_flash *eon = to_eon_spi_flash(flash); - unsigned long block_size; - size_t actual; - int ret; - u8 cmd[4]; - - - block_size = eon->params->page_size * eon->params->pages_per_sector - * eon->params->sectors_per_block; - - if (offset % block_size || len % block_size) { - debug("SF: Erase offset/length not multiple of block size\n"); - return -1; - } - - len /= block_size; - cmd[0] = CMD_EN25Q128_BE; - cmd[2] = 0x00; - cmd[3] = 0x00; - - ret = spi_claim_bus(flash->spi); - if (ret) { - debug("SF: Unable to claim SPI bus\n"); - return ret; - } - - ret = 0; - for (actual = 0; actual < len; actual++) { - cmd[1] = (offset / block_size) + actual; - ret = spi_flash_cmd(flash->spi, CMD_EN25Q128_WREN, NULL, 0); - if (ret < 0) { - debug("SF: Enabling Write failed\n"); - break; - } - - ret = spi_flash_cmd_write(flash->spi, cmd, 4, NULL, 0); - if (ret < 0) { - debug("SF: EON page erase failed\n"); - break; - } - - ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PAGE_ERASE_TIMEOUT); - if (ret) - break; - } - - debug("SF: EON: Successfully erased %u bytes @ 0x%x\n", - len * block_size, offset); - - spi_release_bus(flash->spi); - return ret; + return spi_flash_cmd_erase(flash, CMD_EN25Q128_BE, + eon->params->page_size * eon->params->pages_per_sector * + eon->params->sectors_per_block; + offset, len); }
struct spi_flash *spi_flash_probe_eon(struct spi_slave *spi, u8 *idcode) diff --git a/drivers/mtd/spi/macronix.c b/drivers/mtd/spi/macronix.c index 291fd17..573e1db 100644 --- a/drivers/mtd/spi/macronix.c +++ b/drivers/mtd/spi/macronix.c @@ -198,62 +198,10 @@ static int macronix_write(struct spi_flash *flash, int macronix_erase(struct spi_flash *flash, u32 offset, size_t len) { struct macronix_spi_flash *mcx = to_macronix_spi_flash(flash); - unsigned long sector_size; - size_t actual; - int ret; - u8 cmd[4]; - - /* - * This function currently uses sector erase only. - * probably speed things up by using bulk erase - * when possible. - */ - - sector_size = mcx->params->page_size * mcx->params->pages_per_sector - * mcx->params->sectors_per_block; - - if (offset % sector_size || len % sector_size) { - debug("SF: Erase offset/length not multiple of sector size\n"); - return -1; - } - - len /= sector_size; - cmd[0] = CMD_MX25XX_BE; - cmd[2] = 0x00; - cmd[3] = 0x00; - - ret = spi_claim_bus(flash->spi); - if (ret) { - debug("SF: Unable to claim SPI bus\n"); - return ret; - } - - ret = 0; - for (actual = 0; actual < len; actual++) { - cmd[1] = (offset / sector_size) + actual; - - ret = spi_flash_cmd(flash->spi, CMD_MX25XX_WREN, NULL, 0); - if (ret < 0) { - debug("SF: Enabling Write failed\n"); - break; - } - - ret = spi_flash_cmd_write(flash->spi, cmd, 4, NULL, 0); - if (ret < 0) { - debug("SF: Macronix page erase failed\n"); - break; - } - - ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PAGE_ERASE_TIMEOUT); - if (ret) - break; - } - - debug("SF: Macronix: Successfully erased %u bytes @ 0x%x\n", - len * sector_size, offset); - - spi_release_bus(flash->spi); - return ret; + return spi_flash_cmd_erase(flash, CMD_MX25XX_BE, + mcx->params->page_size * mcx->params->pages_per_sector * + mcx->params->sectors_per_block, + offset, len); }
struct spi_flash *spi_flash_probe_macronix(struct spi_slave *spi, u8 *idcode) diff --git a/drivers/mtd/spi/spansion.c b/drivers/mtd/spi/spansion.c index d0f03ff..be4fc67 100644 --- a/drivers/mtd/spi/spansion.c +++ b/drivers/mtd/spi/spansion.c @@ -223,60 +223,9 @@ static int spansion_write(struct spi_flash *flash, int spansion_erase(struct spi_flash *flash, u32 offset, size_t len) { struct spansion_spi_flash *spsn = to_spansion_spi_flash(flash); - unsigned long sector_size; - size_t actual; - int ret; - u8 cmd[4]; - - /* - * This function currently uses sector erase only. - * probably speed things up by using bulk erase - * when possible. - */ - - sector_size = spsn->params->page_size * spsn->params->pages_per_sector; - - if (offset % sector_size || len % sector_size) { - debug("SF: Erase offset/length not multiple of sector size\n"); - return -1; - } - - cmd[0] = CMD_S25FLXX_SE; - cmd[2] = 0x00; - cmd[3] = 0x00; - - ret = spi_claim_bus(flash->spi); - if (ret) { - debug("SF: Unable to claim SPI bus\n"); - return ret; - } - - ret = 0; - for (actual = 0; actual < len; actual += sector_size) { - cmd[1] = (offset + actual) >> 16; - - ret = spi_flash_cmd(flash->spi, CMD_S25FLXX_WREN, NULL, 0); - if (ret < 0) { - debug("SF: Enabling Write failed\n"); - break; - } - - ret = spi_flash_cmd_write(flash->spi, cmd, 4, NULL, 0); - if (ret < 0) { - debug("SF: SPANSION page erase failed\n"); - break; - } - - ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PAGE_ERASE_TIMEOUT); - if (ret) - break; - } - - debug("SF: SPANSION: Successfully erased %u bytes @ 0x%x\n", - len, offset); - - spi_release_bus(flash->spi); - return ret; + return spi_flash_cmd_erase(flash, CMD_S25FLXX_SE, + spsn->params->page_size * spsn->params->pages_per_sector, + offset, len); }
struct spi_flash *spi_flash_probe_spansion(struct spi_slave *spi, u8 *idcode) diff --git a/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c index e483ce4..ca4bbb2 100644 --- a/drivers/mtd/spi/spi_flash.c +++ b/drivers/mtd/spi/spi_flash.c @@ -14,6 +14,14 @@
#include "spi_flash_internal.h"
+static void spi_flash_addr(u32 addr, u8 *cmd) +{ + /* cmd[0] is actual command */ + cmd[1] = addr >> 16; + cmd[2] = addr >> 8; + cmd[3] = addr >> 0; +} + static int spi_flash_read_write(struct spi_slave *spi, const u8 *cmd, size_t cmd_len, const u8 *data_out, u8 *data_in, @@ -110,6 +118,56 @@ int spi_flash_cmd_wait_ready(struct spi_flash *flash, unsigned long timeout) CMD_READ_STATUS, STATUS_WIP); }
+int spi_flash_cmd_erase(struct spi_flash *flash, u8 erase_cmd, + u32 erase_size, u32 offset, size_t len) +{ + u32 start, end; + int ret; + u8 cmd[4]; + + if (offset % erase_size || len % erase_size) { + debug("SF: Erase offset/length not multiple of erase size\n"); + return -1; + } + + ret = spi_claim_bus(flash->spi); + if (ret) { + debug("SF: Unable to claim SPI bus\n"); + return ret; + } + + cmd[0] = erase_cmd; + start = offset; + end = start + len; + + while (offset < end) { + spi_flash_addr(offset, cmd); + offset += erase_size; + + debug("SF: erase %2x %2x %2x %2x (%x)\n", cmd[0], cmd[1], + cmd[2], cmd[3], offset); + + ret = spi_flash_cmd(flash->spi, CMD_WRITE_ENABLE, NULL, 0); + if (ret) + goto out; + + ret = spi_flash_cmd_write(flash->spi, cmd, sizeof(cmd), NULL, 0); + if (ret) + goto out; + + ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PAGE_ERASE_TIMEOUT); + if (ret) + goto out; + } + + debug("SF: Successfully erased %lu bytes @ %#x\n", + len * erase_size, start); + + out: + spi_release_bus(flash->spi); + return ret; +} + /* * 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 440c044..114b634 100644 --- a/drivers/mtd/spi/spi_flash_internal.h +++ b/drivers/mtd/spi/spi_flash_internal.h @@ -20,6 +20,7 @@ #define CMD_READ_ARRAY_LEGACY 0xe8
#define CMD_READ_STATUS 0x05 +#define CMD_WRITE_ENABLE 0x06
/* Common status */ #define STATUS_WIP 0x01 @@ -58,6 +59,10 @@ int spi_flash_cmd_poll_bit(struct spi_flash *flash, unsigned long timeout, */ int spi_flash_cmd_wait_ready(struct spi_flash *flash, unsigned long timeout);
+/* Erase sectors. */ +int spi_flash_cmd_erase(struct spi_flash *flash, u8 erase_cmd, + u32 erase_size, u32 offset, size_t len); + /* Manufacturer-specific probe functions */ struct spi_flash *spi_flash_probe_spansion(struct spi_slave *spi, u8 *idcode); struct spi_flash *spi_flash_probe_atmel(struct spi_slave *spi, u8 *idcode); diff --git a/drivers/mtd/spi/sst.c b/drivers/mtd/spi/sst.c index 4a82f8a..d550550 100644 --- a/drivers/mtd/spi/sst.c +++ b/drivers/mtd/spi/sst.c @@ -212,67 +212,10 @@ sst_write(struct spi_flash *flash, u32 offset, size_t len, const void *buf) return ret; }
-int -sst_erase(struct spi_flash *flash, u32 offset, size_t len) +int sst_erase(struct spi_flash *flash, u32 offset, size_t len) { - unsigned long sector_size; - u32 start, end; - int ret; - u8 cmd[4]; - - /* - * This function currently uses sector erase only. - * Probably speed things up by using bulk erase - * when possible. - */ - - sector_size = SST_SECTOR_SIZE; - - if (offset % sector_size) { - debug("SF: Erase offset not multiple of sector size\n"); - return -1; - } - - ret = spi_claim_bus(flash->spi); - if (ret) { - debug("SF: Unable to claim SPI bus\n"); - return ret; - } - - cmd[0] = CMD_SST_SE; - cmd[3] = 0; - start = offset; - end = start + len; - - ret = 0; - while (offset < end) { - cmd[1] = offset >> 16; - cmd[2] = offset >> 8; - offset += sector_size; - - debug("SF: erase %2x %2x %2x %2x (%x)\n", cmd[0], cmd[1], - cmd[2], cmd[3], offset); - - ret = sst_enable_writing(flash); - if (ret) - break; - - ret = spi_flash_cmd_write(flash->spi, cmd, sizeof(cmd), NULL, 0); - if (ret) { - debug("SF: sst page erase failed\n"); - break; - } - - ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PAGE_ERASE_TIMEOUT); - if (ret) - break; - } - - debug("SF: sst: Successfully erased %lu bytes @ 0x%x\n", - len * sector_size, start); - - spi_release_bus(flash->spi); - return ret; + return spi_flash_cmd_erase(flash, CMD_SST_SE, SST_SECTOR_SIZE, + offset, len); }
static int diff --git a/drivers/mtd/spi/stmicro.c b/drivers/mtd/spi/stmicro.c index 02da8b2..494005c 100644 --- a/drivers/mtd/spi/stmicro.c +++ b/drivers/mtd/spi/stmicro.c @@ -220,62 +220,9 @@ static int stmicro_write(struct spi_flash *flash, int stmicro_erase(struct spi_flash *flash, u32 offset, size_t len) { struct stmicro_spi_flash *stm = to_stmicro_spi_flash(flash); - unsigned long sector_size; - size_t actual; - int ret; - u8 cmd[4]; - - /* - * This function currently uses sector erase only. - * probably speed things up by using bulk erase - * when possible. - */ - - sector_size = stm->params->page_size * stm->params->pages_per_sector; - - if (offset % sector_size || len % sector_size) { - debug("SF: Erase offset/length not multiple of sector size\n"); - return -1; - } - - len /= sector_size; - cmd[0] = CMD_M25PXX_SE; - cmd[2] = 0x00; - cmd[3] = 0x00; - - ret = spi_claim_bus(flash->spi); - if (ret) { - debug("SF: Unable to claim SPI bus\n"); - return ret; - } - - ret = 0; - for (actual = 0; actual < len; actual++) { - cmd[1] = offset >> 16; - offset += sector_size; - - ret = spi_flash_cmd(flash->spi, CMD_M25PXX_WREN, NULL, 0); - if (ret < 0) { - debug("SF: Enabling Write failed\n"); - break; - } - - ret = spi_flash_cmd_write(flash->spi, cmd, 4, NULL, 0); - if (ret < 0) { - debug("SF: STMicro page erase failed\n"); - break; - } - - ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PAGE_ERASE_TIMEOUT); - if (ret) - break; - } - - debug("SF: STMicro: Successfully erased %u bytes @ 0x%x\n", - len * sector_size, offset); - - spi_release_bus(flash->spi); - return ret; + return spi_flash_cmd_erase(flash, CMD_M25PXX_SE, + stm->params->page_size * stm->params->pages_per_sector, + offset, len); }
struct spi_flash *spi_flash_probe_stmicro(struct spi_slave *spi, u8 * idcode) diff --git a/drivers/mtd/spi/winbond.c b/drivers/mtd/spi/winbond.c index d8c1cb1..8470a82 100644 --- a/drivers/mtd/spi/winbond.c +++ b/drivers/mtd/spi/winbond.c @@ -211,64 +211,9 @@ out: int winbond_erase(struct spi_flash *flash, u32 offset, size_t len) { struct winbond_spi_flash *stm = to_winbond_spi_flash(flash); - unsigned long sector_size; - unsigned int page_shift; - size_t actual; - int ret; - u8 cmd[4]; - - /* - * This function currently uses sector erase only. - * probably speed things up by using bulk erase - * when possible. - */ - - page_shift = stm->params->l2_page_size; - sector_size = (1 << page_shift) * stm->params->pages_per_sector; - - if (offset % sector_size || len % sector_size) { - debug("SF: Erase offset/length not multiple of sector size\n"); - return -1; - } - - len /= sector_size; - cmd[0] = CMD_W25_SE; - - ret = spi_claim_bus(flash->spi); - if (ret) { - debug("SF: Unable to claim SPI bus\n"); - return ret; - } - - for (actual = 0; actual < len; actual++) { - winbond_build_address(stm, &cmd[1], offset + actual * sector_size); - printf("Erase: %02x %02x %02x %02x\n", - cmd[0], cmd[1], cmd[2], cmd[3]); - - ret = spi_flash_cmd(flash->spi, CMD_W25_WREN, NULL, 0); - if (ret < 0) { - debug("SF: Enabling Write failed\n"); - goto out; - } - - ret = spi_flash_cmd_write(flash->spi, cmd, 4, NULL, 0); - if (ret < 0) { - debug("SF: Winbond sector erase failed\n"); - goto out; - } - - ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PAGE_ERASE_TIMEOUT); - if (ret) - goto out; - } - - debug("SF: Winbond: Successfully erased %u bytes @ 0x%x\n", - len * sector_size, offset); - ret = 0; - -out: - spi_release_bus(flash->spi); - return ret; + return spi_flash_cmd_erase(flash, CMD_W25_SE, + (1 << stm->params->l2_page_size) * stm->params->pages_per_sector, + offset, len); }
struct spi_flash *spi_flash_probe_winbond(struct spi_slave *spi, u8 *idcode)

Dear Mike Frysinger,
In message 1294644014-7560-4-git-send-email-vapier@gentoo.org you wrote:
Signed-off-by: Mike Frysinger vapier@gentoo.org
drivers/mtd/spi/eon.c | 55 ++--------------------------- drivers/mtd/spi/macronix.c | 60 ++------------------------------ drivers/mtd/spi/spansion.c | 57 ++----------------------------- drivers/mtd/spi/spi_flash.c | 58 +++++++++++++++++++++++++++++++ drivers/mtd/spi/spi_flash_internal.h | 5 +++ drivers/mtd/spi/sst.c | 63 ++-------------------------------- drivers/mtd/spi/stmicro.c | 59 ++------------------------------ drivers/mtd/spi/winbond.c | 61 ++------------------------------- 8 files changed, 83 insertions(+), 335 deletions(-)
Applied, thanks.
Best regards,
Wolfgang Denk

Signed-off-by: Mike Frysinger vapier@gentoo.org --- drivers/mtd/spi/atmel.c | 18 +------------- drivers/mtd/spi/eon.c | 22 +----------------- drivers/mtd/spi/macronix.c | 22 +----------------- drivers/mtd/spi/spansion.c | 26 +--------------------- drivers/mtd/spi/spi_flash.c | 12 ++++++++++ drivers/mtd/spi/spi_flash_internal.h | 3 ++ drivers/mtd/spi/sst.c | 14 ------------ drivers/mtd/spi/stmicro.c | 22 +----------------- drivers/mtd/spi/winbond.c | 40 +--------------------------------- 9 files changed, 22 insertions(+), 157 deletions(-)
diff --git a/drivers/mtd/spi/atmel.c b/drivers/mtd/spi/atmel.c index 7827b75..a9910b1 100644 --- a/drivers/mtd/spi/atmel.c +++ b/drivers/mtd/spi/atmel.c @@ -143,20 +143,6 @@ static void at45_build_address(struct atmel_spi_flash *asf, u8 *cmd, u32 offset) cmd[2] = byte_addr; }
-static int dataflash_read_fast_p2(struct spi_flash *flash, - u32 offset, size_t len, void *buf) -{ - u8 cmd[5]; - - cmd[0] = CMD_READ_ARRAY_FAST; - cmd[1] = offset >> 16; - cmd[2] = offset >> 8; - cmd[3] = offset; - cmd[4] = 0x00; - - return spi_flash_read_common(flash, cmd, sizeof(cmd), buf, len); -} - static int dataflash_read_fast_at45(struct spi_flash *flash, u32 offset, size_t len, void *buf) { @@ -492,7 +478,7 @@ struct spi_flash *spi_flash_probe_atmel(struct spi_slave *spi, u8 *idcode) asf->flash.erase = dataflash_erase_at45; page_size += 1 << (params->l2_page_size - 5); } else { - asf->flash.read = dataflash_read_fast_p2; + asf->flash.read = spi_flash_cmd_read_fast; asf->flash.write = dataflash_write_p2; asf->flash.erase = dataflash_erase_p2; } @@ -501,7 +487,7 @@ struct spi_flash *spi_flash_probe_atmel(struct spi_slave *spi, u8 *idcode)
case DF_FAMILY_AT26F: case DF_FAMILY_AT26DF: - asf->flash.read = dataflash_read_fast_p2; + asf->flash.read = spi_flash_cmd_read_fast; break;
default: diff --git a/drivers/mtd/spi/eon.c b/drivers/mtd/spi/eon.c index 0c0b05f..01caed5 100644 --- a/drivers/mtd/spi/eon.c +++ b/drivers/mtd/spi/eon.c @@ -56,26 +56,6 @@ static const struct eon_spi_flash_params eon_spi_flash_table[] = { }, };
-static int eon_read_fast(struct spi_flash *flash, - u32 offset, size_t len, void *buf) -{ - struct eon_spi_flash *eon = to_eon_spi_flash(flash); - unsigned long page_addr; - unsigned long page_size; - u8 cmd[5]; - - page_size = eon->params->page_size; - page_addr = offset / page_size; - - cmd[0] = CMD_READ_ARRAY_FAST; - cmd[1] = page_addr >> 8; - cmd[2] = page_addr; - cmd[3] = offset % page_size; - cmd[4] = 0x00; - - return spi_flash_read_common(flash, cmd, sizeof(cmd), buf, len); -} - static int eon_write(struct spi_flash *flash, u32 offset, size_t len, const void *buf) { @@ -177,7 +157,7 @@ struct spi_flash *spi_flash_probe_eon(struct spi_slave *spi, u8 *idcode)
eon->flash.write = eon_write; eon->flash.erase = eon_erase; - eon->flash.read = eon_read_fast; + eon->flash.read = spi_flash_cmd_read_fast; eon->flash.size = params->page_size * params->pages_per_sector * params->nr_sectors;
diff --git a/drivers/mtd/spi/macronix.c b/drivers/mtd/spi/macronix.c index 573e1db..4155d4d 100644 --- a/drivers/mtd/spi/macronix.c +++ b/drivers/mtd/spi/macronix.c @@ -112,26 +112,6 @@ static const struct macronix_spi_flash_params macronix_spi_flash_table[] = { }, };
-static int macronix_read_fast(struct spi_flash *flash, - u32 offset, size_t len, void *buf) -{ - struct macronix_spi_flash *mcx = to_macronix_spi_flash(flash); - unsigned long page_addr; - unsigned long page_size; - u8 cmd[5]; - - page_size = mcx->params->page_size; - page_addr = offset / page_size; - - cmd[0] = CMD_READ_ARRAY_FAST; - cmd[1] = page_addr >> 8; - cmd[2] = page_addr; - cmd[3] = offset % page_size; - cmd[4] = 0x00; - - return spi_flash_read_common(flash, cmd, sizeof(cmd), buf, len); -} - static int macronix_write(struct spi_flash *flash, u32 offset, size_t len, const void *buf) { @@ -234,7 +214,7 @@ struct spi_flash *spi_flash_probe_macronix(struct spi_slave *spi, u8 *idcode)
mcx->flash.write = macronix_write; mcx->flash.erase = macronix_erase; - mcx->flash.read = macronix_read_fast; + mcx->flash.read = spi_flash_cmd_read_fast; mcx->flash.size = params->page_size * params->pages_per_sector * params->sectors_per_block * params->nr_blocks;
diff --git a/drivers/mtd/spi/spansion.c b/drivers/mtd/spi/spansion.c index be4fc67..d54a5fa 100644 --- a/drivers/mtd/spi/spansion.c +++ b/drivers/mtd/spi/spansion.c @@ -133,30 +133,6 @@ static const struct spansion_spi_flash_params spansion_spi_flash_table[] = { }, };
-static int spansion_read_fast(struct spi_flash *flash, - u32 offset, size_t len, void *buf) -{ - struct spansion_spi_flash *spsn = to_spansion_spi_flash(flash); - unsigned long page_addr; - unsigned long page_size; - u8 cmd[5]; - - page_size = spsn->params->page_size; - page_addr = offset / page_size; - - cmd[0] = CMD_READ_ARRAY_FAST; - cmd[1] = page_addr >> 8; - cmd[2] = page_addr; - cmd[3] = offset % page_size; - cmd[4] = 0x00; - - debug - ("READ: 0x%x => cmd = { 0x%02x 0x%02x%02x%02x%02x } len = 0x%x\n", - offset, cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], len); - - return spi_flash_read_common(flash, cmd, sizeof(cmd), buf, len); -} - static int spansion_write(struct spi_flash *flash, u32 offset, size_t len, const void *buf) { @@ -263,7 +239,7 @@ struct spi_flash *spi_flash_probe_spansion(struct spi_slave *spi, u8 *idcode)
spsn->flash.write = spansion_write; spsn->flash.erase = spansion_erase; - spsn->flash.read = spansion_read_fast; + spsn->flash.read = spi_flash_cmd_read_fast; spsn->flash.size = params->page_size * params->pages_per_sector * params->nr_sectors;
diff --git a/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c index ca4bbb2..5c261f1 100644 --- a/drivers/mtd/spi/spi_flash.c +++ b/drivers/mtd/spi/spi_flash.c @@ -77,6 +77,18 @@ int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd, return ret; }
+int spi_flash_cmd_read_fast(struct spi_flash *flash, u32 offset, + size_t len, void *data) +{ + u8 cmd[5]; + + cmd[0] = CMD_READ_ARRAY_FAST; + spi_flash_addr(offset, cmd); + cmd[4] = 0x00; + + return spi_flash_read_common(flash, cmd, sizeof(cmd), data, len); +} + int spi_flash_cmd_poll_bit(struct spi_flash *flash, unsigned long timeout, u8 cmd, u8 poll_bit) { diff --git a/drivers/mtd/spi/spi_flash_internal.h b/drivers/mtd/spi/spi_flash_internal.h index 114b634..d7bcd6d 100644 --- a/drivers/mtd/spi/spi_flash_internal.h +++ b/drivers/mtd/spi/spi_flash_internal.h @@ -35,6 +35,9 @@ int spi_flash_cmd(struct spi_slave *spi, u8 cmd, void *response, size_t len); int spi_flash_cmd_read(struct spi_slave *spi, const u8 *cmd, size_t cmd_len, void *data, size_t data_len);
+int spi_flash_cmd_read_fast(struct spi_flash *flash, u32 offset, + size_t len, void *data); + /* * Send a multi-byte command to the device followed by (optional) * data. Used for programming the flash array, etc. diff --git a/drivers/mtd/spi/sst.c b/drivers/mtd/spi/sst.c index d550550..792d04d 100644 --- a/drivers/mtd/spi/sst.c +++ b/drivers/mtd/spi/sst.c @@ -108,19 +108,6 @@ sst_disable_writing(struct spi_flash *flash) }
static int -sst_read_fast(struct spi_flash *flash, u32 offset, size_t len, void *buf) -{ - u8 cmd[5] = { - CMD_READ_ARRAY_FAST, - offset >> 16, - offset >> 8, - offset, - 0x00, - }; - return spi_flash_read_common(flash, cmd, sizeof(cmd), buf, len); -} - -static int sst_byte_write(struct spi_flash *flash, u32 offset, const void *buf) { int ret; @@ -269,7 +256,6 @@ spi_flash_probe_sst(struct spi_slave *spi, u8 *idcode)
stm->flash.write = sst_write; stm->flash.erase = sst_erase; - stm->flash.read = sst_read_fast; stm->flash.size = SST_SECTOR_SIZE * params->nr_sectors;
printf("SF: Detected %s with page size %u, total ", diff --git a/drivers/mtd/spi/stmicro.c b/drivers/mtd/spi/stmicro.c index 494005c..7ef690d 100644 --- a/drivers/mtd/spi/stmicro.c +++ b/drivers/mtd/spi/stmicro.c @@ -134,26 +134,6 @@ static const struct stmicro_spi_flash_params stmicro_spi_flash_table[] = { }, };
-static int stmicro_read_fast(struct spi_flash *flash, - u32 offset, size_t len, void *buf) -{ - struct stmicro_spi_flash *stm = to_stmicro_spi_flash(flash); - unsigned long page_addr; - unsigned long page_size; - u8 cmd[5]; - - page_size = stm->params->page_size; - page_addr = offset / page_size; - - cmd[0] = CMD_READ_ARRAY_FAST; - cmd[1] = page_addr >> 8; - cmd[2] = page_addr; - cmd[3] = offset % page_size; - cmd[4] = 0x00; - - return spi_flash_read_common(flash, cmd, sizeof(cmd), buf, len); -} - static int stmicro_write(struct spi_flash *flash, u32 offset, size_t len, const void *buf) { @@ -268,7 +248,7 @@ struct spi_flash *spi_flash_probe_stmicro(struct spi_slave *spi, u8 * idcode)
stm->flash.write = stmicro_write; stm->flash.erase = stmicro_erase; - stm->flash.read = stmicro_read_fast; + stm->flash.read = spi_flash_cmd_read_fast; stm->flash.size = params->page_size * params->pages_per_sector * params->nr_sectors;
diff --git a/drivers/mtd/spi/winbond.c b/drivers/mtd/spi/winbond.c index 8470a82..e88802f 100644 --- a/drivers/mtd/spi/winbond.c +++ b/drivers/mtd/spi/winbond.c @@ -105,44 +105,6 @@ static const struct winbond_spi_flash_params winbond_spi_flash_table[] = { }, };
-/* - * Assemble the address part of a command for Winbond devices in - * non-power-of-two page size mode. - */ -static void winbond_build_address(struct winbond_spi_flash *stm, u8 *cmd, u32 offset) -{ - unsigned long page_addr; - unsigned long byte_addr; - unsigned long page_size; - unsigned int page_shift; - - /* - * The "extra" space per page is the power-of-two page size - * divided by 32. - */ - page_shift = stm->params->l2_page_size; - page_size = (1 << page_shift); - page_addr = offset / page_size; - byte_addr = offset % page_size; - - cmd[0] = page_addr >> (16 - page_shift); - cmd[1] = page_addr << (page_shift - 8) | (byte_addr >> 8); - cmd[2] = byte_addr; -} - -static int winbond_read_fast(struct spi_flash *flash, - u32 offset, size_t len, void *buf) -{ - struct winbond_spi_flash *stm = to_winbond_spi_flash(flash); - u8 cmd[5]; - - cmd[0] = CMD_READ_ARRAY_FAST; - winbond_build_address(stm, cmd + 1, offset); - cmd[4] = 0x00; - - return spi_flash_read_common(flash, cmd, sizeof(cmd), buf, len); -} - static int winbond_write(struct spi_flash *flash, u32 offset, size_t len, const void *buf) { @@ -250,7 +212,7 @@ struct spi_flash *spi_flash_probe_winbond(struct spi_slave *spi, u8 *idcode)
stm->flash.write = winbond_write; stm->flash.erase = winbond_erase; - stm->flash.read = winbond_read_fast; + stm->flash.read = spi_flash_cmd_read_fast; stm->flash.size = page_size * params->pages_per_sector * params->sectors_per_block * params->nr_blocks;

Dear Mike Frysinger,
In message 1294644014-7560-5-git-send-email-vapier@gentoo.org you wrote:
Signed-off-by: Mike Frysinger vapier@gentoo.org
drivers/mtd/spi/atmel.c | 18 +------------- drivers/mtd/spi/eon.c | 22 +----------------- drivers/mtd/spi/macronix.c | 22 +----------------- drivers/mtd/spi/spansion.c | 26 +--------------------- drivers/mtd/spi/spi_flash.c | 12 ++++++++++ drivers/mtd/spi/spi_flash_internal.h | 3 ++ drivers/mtd/spi/sst.c | 14 ------------ drivers/mtd/spi/stmicro.c | 22 +----------------- drivers/mtd/spi/winbond.c | 40 +--------------------------------- 9 files changed, 22 insertions(+), 157 deletions(-)
Applied, thanks.
Best regards,
Wolfgang Denk

Hello Mike,
I'm working on put our espi controller related patches to open source, I noticed your unify patches several days ago, and I rebased my patches on these Unify patches, and tested it on my board, it works as expect, so should I wait until your unify patches been merged to main tree? And will these unify patch be Merged into next release?
Any comment would be appreciated.
Thanks & Best Regards, Shaohui Xie
-----Original Message----- From: u-boot-bounces@lists.denx.de [mailto:u-boot-bounces@lists.denx.de] On Behalf Of Mike Frysinger Sent: Monday, January 10, 2011 3:20 PM To: u-boot@lists.denx.de Subject: [U-Boot] [WIP/PATCH 0/4] unify SPI flash drivers
The amount of duplication across SPI flash driver has always annoyed me, and we've seen bugs that affect multiple drivers fixed in only some, and I figure if the Linux kernel driver can unify these things, then there is really no reason we can't too.
So this here are a few incremental patches to get us closer to a unified driver. I think the diffstat speaks for itself, and there are even more pieces here which could possibly be merged. But I got bored for now.
I've only lightly tested them so far with one SPI flash driver, so for now they're not for merging. Once I can get more testing on our side, I'll send out a pull request.
For you adventurous/bored types, you can grab these from my sf branch: git://git.denx.de/u-boot-blackfin.git Any feedback as to success/failure would be great.
Mike Frysinger (4): sf: unify read/write helpers sf: unify status polling for ready bit sf: unify erase functions sf: unify read functions
drivers/mtd/spi/atmel.c | 49 +--------- drivers/mtd/spi/eon.c | 121 ++----------------------- drivers/mtd/spi/macronix.c | 126 ++------------------------ drivers/mtd/spi/spansion.c | 120 +----------------------- drivers/mtd/spi/spi_flash.c | 170 +++++++++++++++++++++++++----
drivers/mtd/spi/spi_flash_internal.h | 23 +++++ drivers/mtd/spi/sst.c | 116 +---------------------- drivers/mtd/spi/stmicro.c | 125 +------------------------ drivers/mtd/spi/winbond.c | 148 +---------------------------- 9 files changed, 190 insertions(+), 808 deletions(-)
-- 1.7.4.rc1
U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot

On Mar 15, 2011, at 2:06 AM, Xie Shaohui-B21989 wrote:
Hello Mike,
I'm working on put our espi controller related patches to open source, I noticed your unify patches several days ago, and I rebased my patches on these Unify patches, and tested it on my board, it works as expect, so should I wait until your unify patches been merged to main tree? And will these unify patch be Merged into next release?
Any comment would be appreciated.
Thanks & Best Regards, Shaohui Xie
I'd ask we post the espi controller driver on top of Mike's patches. This way we can provide review feedback on the eSPI.
- k
participants (4)
-
Kumar Gala
-
Mike Frysinger
-
Wolfgang Denk
-
Xie Shaohui-B21989