From: Jagannadha Sutradharudu Teki Date: Mon, 30 Sep 2013 20:16:46 +0000 (+0530) Subject: sf: Fix dual parallel erase/program on micron devices X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=b5e96fa77e4fa3b7171b2a1809907c0963677a69;p=thirdparty%2Fu-boot.git 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 --- 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; }