From b5e96fa77e4fa3b7171b2a1809907c0963677a69 Mon Sep 17 00:00:00 2001 From: Jagannadha Sutradharudu Teki Date: Tue, 1 Oct 2013 01:46:46 +0530 Subject: [PATCH] sf: Fix dual parallel erase/program on micron devices Usually by polling flag status register is enough to erase/program die based micron flashes instead of read status register. But dual parallel with die based micron topology doesn't works with this setup instead it requires both the registers need to poll. So, updated the code for polling read and flag status register for die based micron flash devices. Signed-off-by: Jagannadha Sutradharudu Teki Acked-by: Punnaiah Choudary Kalluri Signed-off-by: Michal Simek --- drivers/mtd/spi/spi_flash.c | 60 +++++++++++++++++++++---------------- drivers/mtd/spi/stmicro.c | 4 +++ 2 files changed, 39 insertions(+), 25 deletions(-) diff --git a/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c index 6c266ac1a36..314391ba946 100644 --- a/drivers/mtd/spi/spi_flash.c +++ b/drivers/mtd/spi/spi_flash.c @@ -71,46 +71,57 @@ int spi_flash_cmd_write(struct spi_slave *spi, const u8 *cmd, size_t cmd_len, return spi_flash_read_write(spi, cmd, cmd_len, data, NULL, data_len); } -int spi_flash_cmd_wait_ready(struct spi_flash *flash, unsigned long timeout) +static int spi_flash_get_status(struct spi_flash *flash, u8 cmd, u8 *resp) { - struct spi_slave *spi = flash->spi; - unsigned long timebase; int ret; - u8 status; - u8 check_status = 0x0; - u8 poll_bit = STATUS_WIP; - u8 cmd = flash->poll_cmd; - - if (cmd == CMD_FLAG_STATUS) { - poll_bit = STATUS_PEC; - check_status = poll_bit; - } + struct spi_slave *spi = flash->spi; ret = spi_xfer(spi, 8, &cmd, NULL, SPI_XFER_BEGIN); if (ret) { debug("SF: fail to read %s status register\n", - cmd == CMD_READ_STATUS ? "read" : "flag"); + cmd == CMD_READ_STATUS ? "read" : "flag"); return ret; } + WATCHDOG_RESET(); + + ret = spi_xfer(spi, 8, NULL, resp, 0); + if (ret) + return -1; + + spi_xfer(spi, 0, NULL, NULL, SPI_XFER_END); + + return 0; +} + +int spi_flash_cmd_wait_ready(struct spi_flash *flash, unsigned long timeout) +{ + unsigned long timebase; + u8 status; + int ret; + timebase = get_timer(0); do { - WATCHDOG_RESET(); - - ret = spi_xfer(spi, 8, NULL, &status, 0); + ret = spi_flash_get_status(flash, CMD_READ_STATUS, &status); if (ret) return -1; - if ((status & poll_bit) == check_status) - break; - + if ((status & STATUS_WIP) == 0) { +#ifdef CONFIG_SPI_FLASH_STMICRO + if (flash->poll_cmd == CMD_FLAG_STATUS) { + ret = spi_flash_get_status(flash, + CMD_FLAG_STATUS, &status); + if (ret) + return -1; + + if ((status & STATUS_PEC) == STATUS_PEC) + return 0; + } +#endif + return 0; + } } while (get_timer(timebase) < timeout); - spi_xfer(spi, 0, NULL, NULL, SPI_XFER_END); - - if ((status & poll_bit) == check_status) - return 0; - /* Timed out */ debug("SF: time out!\n"); return -1; @@ -708,7 +719,6 @@ void *spi_flash_do_alloc(int offset, int size, struct spi_slave *spi, /* Set up some basic fields - caller will sort out sizes */ flash->spi = spi; flash->name = name; - flash->poll_cmd = CMD_READ_STATUS; flash->read = spi_flash_cmd_read_fast; flash->write = spi_flash_cmd_write_multi; diff --git a/drivers/mtd/spi/stmicro.c b/drivers/mtd/spi/stmicro.c index f7ebcee20e9..1d75b3477cb 100644 --- a/drivers/mtd/spi/stmicro.c +++ b/drivers/mtd/spi/stmicro.c @@ -252,5 +252,9 @@ struct spi_flash *spi_flash_probe_stmicro(struct spi_slave *spi, u8 * idcode) if (flash->spi->is_dual == MODE_DUAL_STACKED) flash->size *= 2; + /* Poll for flag status, for 256MB devices onwards */ + if (flash->size >= 0x2000000) + flash->poll_cmd = CMD_FLAG_STATUS; + return flash; } -- 2.47.3