|
|
|
@ -68,6 +68,51 @@ 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) |
|
|
|
|
{ |
|
|
|
|
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; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
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) |
|
|
|
|
{ |
|
|
|
@ -109,6 +154,53 @@ int spi_flash_write_common(struct spi_flash *flash, const u8 *cmd, |
|
|
|
|
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) |
|
|
|
|
{ |
|
|
|
@ -218,98 +310,6 @@ int spi_flash_cmd_read_fast(struct spi_flash *flash, u32 offset, |
|
|
|
|
return ret; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int spi_flash_cmd_wait_ready(struct spi_flash *flash, unsigned long timeout) |
|
|
|
|
{ |
|
|
|
|
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; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
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_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_status(struct spi_flash *flash, u8 sr) |
|
|
|
|
{ |
|
|
|
|
u8 cmd; |
|
|
|
|