X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=drivers%2Fmtd%2Fspi%2Fspi_flash.c;h=6a6fe37e0eea92e27817f47ca6c79c618325612c;hb=a07d229497f9672d1212700d85ce719ecf63e2af;hp=562f6adb58f9070b5d4986e5574964fd31f17129;hpb=fc207ee4db20ef6e769b0d08dab8b102748acb35;p=u-boot diff --git a/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c index 562f6adb58..6a6fe37e0e 100644 --- a/drivers/mtd/spi/spi_flash.c +++ b/drivers/mtd/spi/spi_flash.c @@ -68,15 +68,60 @@ 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_write_multi(struct spi_flash *flash, u32 offset, - size_t len, const void *buf) +int spi_flash_cmd_wait_ready(struct spi_flash *flash, unsigned long timeout) { - unsigned long page_addr, byte_addr, page_size; - size_t chunk_len, actual; + struct spi_slave *spi = flash->spi; + unsigned long timebase; int ret; - u8 cmd[4], bank_sel; + u8 status; + u8 check_status = 0x0; + u8 poll_bit = STATUS_WIP; + u8 cmd = flash->poll_cmd; - page_size = flash->page_size; + if (cmd == CMD_FLAG_STATUS) { + poll_bit = STATUS_PEC; + check_status = poll_bit; + } + + 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"); + return ret; + } + + timebase = get_timer(0); + do { + WATCHDOG_RESET(); + + ret = spi_xfer(spi, 8, NULL, &status, 0); + if (ret) + return -1; + + if ((status & poll_bit) == check_status) + break; + + } 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; +} + +int spi_flash_write_common(struct spi_flash *flash, const u8 *cmd, + size_t cmd_len, const void *buf, size_t buf_len) +{ + struct spi_slave *spi = flash->spi; + unsigned long timeout = SPI_FLASH_PROG_TIMEOUT; + int ret; + + if (buf == NULL) + timeout = SPI_FLASH_PAGE_ERASE_TIMEOUT; ret = spi_claim_bus(flash->spi); if (ret) { @@ -84,8 +129,93 @@ int spi_flash_cmd_write_multi(struct spi_flash *flash, u32 offset, return ret; } + ret = spi_flash_cmd_write_enable(flash); + if (ret < 0) { + debug("SF: enabling write failed\n"); + return ret; + } + + ret = spi_flash_cmd_write(spi, cmd, cmd_len, buf, buf_len); + if (ret < 0) { + debug("SF: write cmd failed\n"); + return ret; + } + + ret = spi_flash_cmd_wait_ready(flash, timeout); + if (ret < 0) { + debug("SF: write %s timed out\n", + timeout == SPI_FLASH_PROG_TIMEOUT ? + "program" : "page erase"); + return ret; + } + + spi_release_bus(spi); + + return ret; +} + +int spi_flash_cmd_erase(struct spi_flash *flash, u32 offset, size_t len) +{ + u32 erase_size; + u8 cmd[4]; + int ret = -1; + + erase_size = flash->sector_size; + if (offset % erase_size || len % erase_size) { + debug("SF: Erase offset/length not multiple of erase size\n"); + return -1; + } + + if (erase_size == 4096) + cmd[0] = CMD_ERASE_4K; + else + cmd[0] = CMD_ERASE_64K; + + while (len) { +#ifdef CONFIG_SPI_FLASH_BAR + u8 bank_sel; + + bank_sel = offset / SPI_FLASH_16MB_BOUN; + + ret = spi_flash_cmd_bankaddr_write(flash, bank_sel); + if (ret) { + debug("SF: fail to set bank%d\n", bank_sel); + return ret; + } +#endif + spi_flash_addr(offset, cmd); + + debug("SF: erase %2x %2x %2x %2x (%x)\n", cmd[0], cmd[1], + cmd[2], cmd[3], offset); + + ret = spi_flash_write_common(flash, cmd, sizeof(cmd), NULL, 0); + if (ret < 0) { + debug("SF: erase failed\n"); + break; + } + + offset += erase_size; + len -= erase_size; + } + + return ret; +} + +int spi_flash_cmd_write_multi(struct spi_flash *flash, u32 offset, + size_t len, const void *buf) +{ + unsigned long byte_addr, page_size; + size_t chunk_len, actual; + u8 cmd[4]; + int ret = -1; + + page_size = flash->page_size; + cmd[0] = CMD_PAGE_PROGRAM; for (actual = 0; actual < len; actual += chunk_len) { +#ifdef CONFIG_SPI_FLASH_BAR + u8 bank_sel; + bank_sel = offset / SPI_FLASH_16MB_BOUN; ret = spi_flash_cmd_bankaddr_write(flash, bank_sel); @@ -93,42 +223,28 @@ int spi_flash_cmd_write_multi(struct spi_flash *flash, u32 offset, debug("SF: fail to set bank%d\n", bank_sel); return ret; } - - page_addr = offset / page_size; +#endif byte_addr = offset % page_size; chunk_len = min(len - actual, page_size - byte_addr); if (flash->spi->max_write_size) chunk_len = min(chunk_len, flash->spi->max_write_size); - cmd[1] = page_addr >> 8; - cmd[2] = page_addr; - cmd[3] = byte_addr; + spi_flash_addr(offset, cmd); debug("PP: 0x%p => cmd = { 0x%02x 0x%02x%02x%02x } chunk_len = %zu\n", buf + actual, cmd[0], cmd[1], cmd[2], cmd[3], chunk_len); - ret = spi_flash_cmd_write_enable(flash); - if (ret < 0) { - debug("SF: enabling write failed\n"); - break; - } - - ret = spi_flash_cmd_write(flash->spi, cmd, 4, - buf + actual, chunk_len); + ret = spi_flash_write_common(flash, cmd, sizeof(cmd), + buf + actual, chunk_len); if (ret < 0) { debug("SF: write failed\n"); break; } - ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); - if (ret) - break; - offset += chunk_len; } - spi_release_bus(flash->spi); return ret; } @@ -138,8 +254,18 @@ int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd, struct spi_slave *spi = flash->spi; int ret; - spi_claim_bus(spi); + ret = spi_claim_bus(flash->spi); + if (ret) { + debug("SF: unable to claim SPI bus\n"); + return ret; + } + ret = spi_flash_cmd_read(spi, cmd, cmd_len, data, data_len); + if (ret < 0) { + debug("SF: read cmd failed\n"); + return ret; + } + spi_release_bus(spi); return ret; @@ -148,7 +274,7 @@ int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd, int spi_flash_cmd_read_fast(struct spi_flash *flash, u32 offset, size_t len, void *data) { - u8 cmd[5], bank_sel; + u8 cmd[5], bank_sel = 0; u32 remain_len, read_len; int ret = -1; @@ -162,6 +288,7 @@ int spi_flash_cmd_read_fast(struct spi_flash *flash, u32 offset, cmd[4] = 0x00; while (len) { +#ifdef CONFIG_SPI_FLASH_BAR bank_sel = offset / SPI_FLASH_16MB_BOUN; ret = spi_flash_cmd_bankaddr_write(flash, bank_sel); @@ -169,7 +296,7 @@ int spi_flash_cmd_read_fast(struct spi_flash *flash, u32 offset, debug("SF: fail to set bank%d\n", bank_sel); return ret; } - +#endif remain_len = (SPI_FLASH_16MB_BOUN * (bank_sel + 1) - offset); if (len < remain_len) read_len = len; @@ -193,134 +320,22 @@ int spi_flash_cmd_read_fast(struct spi_flash *flash, u32 offset, 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 { - WATCHDOG_RESET(); - - 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); -} - -int spi_flash_cmd_erase(struct spi_flash *flash, u32 offset, size_t len) -{ - u32 erase_size; - int ret; - u8 cmd[4], bank_sel; - - erase_size = flash->sector_size; - 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; - } - - if (erase_size == 4096) - cmd[0] = CMD_ERASE_4K; - else - cmd[0] = CMD_ERASE_64K; - - while (len) { - bank_sel = offset / SPI_FLASH_16MB_BOUN; - - ret = spi_flash_cmd_bankaddr_write(flash, bank_sel); - if (ret) { - debug("SF: fail to set bank%d\n", bank_sel); - return ret; - } - - spi_flash_addr(offset, cmd); - - debug("SF: erase %2x %2x %2x %2x (%x)\n", cmd[0], cmd[1], - cmd[2], cmd[3], offset); - - ret = spi_flash_cmd_write_enable(flash); - 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; - - offset += erase_size; - len -= erase_size; - } - - out: - spi_release_bus(flash->spi); - return ret; -} - int spi_flash_cmd_write_status(struct spi_flash *flash, u8 sr) { u8 cmd; int ret; - ret = spi_flash_cmd_write_enable(flash); - if (ret < 0) { - debug("SF: enabling write failed\n"); - return ret; - } - cmd = CMD_WRITE_STATUS; - ret = spi_flash_cmd_write(flash->spi, &cmd, 1, &sr, 1); - if (ret) { - debug("SF: fail to write status register\n"); - return ret; - } - - ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); + ret = spi_flash_write_common(flash, &cmd, 1, &sr, 1); if (ret < 0) { - debug("SF: write status register timed out\n"); + debug("SF: fail to write status register\n"); return ret; } return 0; } +#ifdef CONFIG_SPI_FLASH_BAR int spi_flash_cmd_bankaddr_write(struct spi_flash *flash, u8 bank_sel) { u8 cmd; @@ -332,25 +347,13 @@ int spi_flash_cmd_bankaddr_write(struct spi_flash *flash, u8 bank_sel) } cmd = flash->bank_write_cmd; - ret = spi_flash_cmd_write_enable(flash); + ret = spi_flash_write_common(flash, &cmd, 1, &bank_sel, 1); if (ret < 0) { - debug("SF: enabling write failed\n"); - return ret; - } - - ret = spi_flash_cmd_write(flash->spi, &cmd, 1, &bank_sel, 1); - if (ret) { - debug("SF: fail to write bank addr register\n"); + debug("SF: fail to write bank register\n"); return ret; } flash->bank_curr = bank_sel; - ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); - if (ret < 0) { - debug("SF: write bank addr register timed out\n"); - return ret; - } - return 0; } @@ -389,6 +392,7 @@ int spi_flash_bank_config(struct spi_flash *flash, u8 idcode0) return 0; } +#endif #ifdef CONFIG_OF_CONTROL int spi_flash_decode_fdt(const void *blob, struct spi_flash *flash) @@ -454,6 +458,9 @@ static const struct { #ifdef CONFIG_SPI_FLASH_EON { 0, 0x1c, spi_flash_probe_eon, }, #endif +#ifdef CONFIG_SPI_FLASH_GIGADEVICE + { 0, 0xc8, spi_flash_probe_gigadevice, }, +#endif #ifdef CONFIG_SPI_FLASH_MACRONIX { 0, 0xc2, spi_flash_probe_macronix, }, #endif @@ -534,10 +541,12 @@ struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs, goto err_manufacturer_probe; } +#ifdef CONFIG_SPI_FLASH_BAR /* Configure the BAR - disover bank cmds and read current bank */ ret = spi_flash_bank_config(flash, *idp); if (ret < 0) goto err_manufacturer_probe; +#endif #ifdef CONFIG_OF_CONTROL if (spi_flash_decode_fdt(gd->fdt_blob, flash)) { @@ -551,6 +560,12 @@ struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs, if (flash->memory_map) printf(", mapped at %p", flash->memory_map); puts("\n"); +#ifndef CONFIG_SPI_FLASH_BAR + if (flash->size > SPI_FLASH_16MB_BOUN) { + puts("SF: Warning - Only lower 16MiB accessible,"); + puts(" Full access #define CONFIG_SPI_FLASH_BAR\n"); + } +#endif spi_release_bus(spi); @@ -581,6 +596,7 @@ 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;