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:
parent
93b2bd70ff
commit
1cf85774da
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue