SPI: Support STMicro partial page write

Ported from spi/winbond.c.

Fixes this error:
   ICH SPI: Too much to write.
   Does your SPI chip driver use CONTROLLER_PAGE_LIMIT?

Change-Id: I50db8fd1104d3b7d319b278b14f97e3ff9cb6404
Signed-off-by: Kyösti Mälkki <kyosti.malkki@gmail.com>
Reviewed-on: http://review.coreboot.org/3877
Tested-by: build bot (Jenkins)
Reviewed-by: David Hendricks <dhendrix@chromium.org>
This commit is contained in:
Kyösti Mälkki 2013-08-18 12:44:24 +03:00
parent 93b2bd70ff
commit 1cf85774da
1 changed files with 12 additions and 14 deletions

View File

@ -136,7 +136,6 @@ static int stmicro_write(struct spi_flash *flash,
u32 offset, size_t len, const void *buf) u32 offset, size_t len, const void *buf)
{ {
struct stmicro_spi_flash *stm = to_stmicro_spi_flash(flash); struct stmicro_spi_flash *stm = to_stmicro_spi_flash(flash);
unsigned long page_addr;
unsigned long byte_addr; unsigned long byte_addr;
unsigned long page_size; unsigned long page_size;
size_t chunk_len; size_t chunk_len;
@ -144,8 +143,7 @@ static int stmicro_write(struct spi_flash *flash,
int ret; int ret;
u8 cmd[4]; u8 cmd[4];
page_size = stm->params->page_size; page_size = min(stm->params->page_size, CONTROLLER_PAGE_LIMIT);
page_addr = offset / page_size;
byte_addr = offset % page_size; byte_addr = offset % page_size;
flash->spi->rw = SPI_WRITE_FLAG; flash->spi->rw = SPI_WRITE_FLAG;
@ -155,15 +153,13 @@ static int stmicro_write(struct spi_flash *flash,
return ret; return ret;
} }
ret = 0;
for (actual = 0; actual < len; actual += chunk_len) { for (actual = 0; actual < len; actual += chunk_len) {
chunk_len = min(len - actual, page_size - byte_addr); chunk_len = min(len - actual, page_size - byte_addr);
cmd[0] = CMD_M25PXX_PP; cmd[0] = CMD_M25PXX_PP;
cmd[1] = page_addr >> 8; cmd[1] = (offset >> 16) & 0xff;
cmd[2] = page_addr; cmd[2] = (offset >> 8) & 0xff;
cmd[3] = byte_addr; cmd[3] = offset & 0xff;
#if CONFIG_DEBUG_SPI_FLASH #if CONFIG_DEBUG_SPI_FLASH
printk(BIOS_SPEW, "PP: 0x%p => cmd = { 0x%02x 0x%02x%02x%02x }" printk(BIOS_SPEW, "PP: 0x%p => cmd = { 0x%02x 0x%02x%02x%02x }"
" chunk_len = %zu\n", " chunk_len = %zu\n",
@ -173,29 +169,31 @@ static int stmicro_write(struct spi_flash *flash,
ret = spi_flash_cmd(flash->spi, CMD_M25PXX_WREN, NULL, 0); ret = spi_flash_cmd(flash->spi, CMD_M25PXX_WREN, NULL, 0);
if (ret < 0) { if (ret < 0) {
printk(BIOS_WARNING, "SF: Enabling Write failed\n"); printk(BIOS_WARNING, "SF: Enabling Write failed\n");
break; goto out;
} }
ret = spi_flash_cmd_write(flash->spi, cmd, 4, ret = spi_flash_cmd_write(flash->spi, cmd, 4,
buf + actual, chunk_len); buf + actual, chunk_len);
if (ret < 0) { if (ret < 0) {
printk(BIOS_WARNING, "SF: STMicro Page Program failed\n"); printk(BIOS_WARNING, "SF: STMicro Page Program failed\n");
break; goto out;
} }
ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT);
if (ret) if (ret)
break; goto out;
page_addr++; offset += chunk_len;
byte_addr = 0; byte_addr = 0;
} }
#if CONFIG_DEBUG_SPI_FLASH #if CONFIG_DEBUG_SPI_FLASH
printk(BIOS_SPEW, "SF: STMicro: Successfully programmed %zu bytes @ 0x%x\n", printk(BIOS_SPEW, "SF: STMicro: Successfully programmed %zu bytes @"
len, offset); " 0x%lx\n", len, (unsigned long)(offset - len));
#endif #endif
ret = 0;
out:
spi_release_bus(flash->spi); spi_release_bus(flash->spi);
return ret; return ret;
} }