SPI flash: Fix alignment checks in Page Program commands

There are two separate restrictions to take into account:

  Page Program command must not cross address boundaries defined by the
  flash part's page size.

  Total number of bytes for any command sent to flash part is restricted
  by the SPI controller capabilities.

Consider

  CONTROLLER_PAGE_LIMIT=64, page_size=256, offset=62, len=4.
  This write would be split at offset 64 for no reason.

Consider

  CONTROLLER_PAGE_LIMIT=40, page_size=256, offset=254, len=4.
  This write would not be split at page boundary as required.

We do not really hit the second case. Nevertheless, CONTROLLER_PAGE_LIMIT
is a misnomer for the maximum payload length supported by the SPI controller
and is removed in a followup.

Change-Id: I727f2e7de86a91b6a509460ff1f374acd006a0bc
Signed-off-by: Kyösti Mälkki <kyosti.malkki@gmail.com>
Reviewed-on: http://review.coreboot.org/6162
Tested-by: build bot (Jenkins)
Reviewed-by: Edward O'Callaghan <eocallaghan@alterapraxis.com>
This commit is contained in:
Kyösti Mälkki 2014-06-29 16:15:39 +03:00
parent 562db3bb3f
commit 77d1280d0c
6 changed files with 12 additions and 6 deletions

View File

@ -88,7 +88,7 @@ static int adesto_write(struct spi_flash *flash,
int ret; int ret;
u8 cmd[4]; u8 cmd[4];
page_size = min(1 << stm->params->l2_page_size, CONTROLLER_PAGE_LIMIT); page_size = 1 << stm->params->l2_page_size;
byte_addr = offset % page_size; byte_addr = offset % page_size;
flash->spi->rw = SPI_WRITE_FLAG; flash->spi->rw = SPI_WRITE_FLAG;
@ -100,6 +100,7 @@ static int adesto_write(struct spi_flash *flash,
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);
chunk_len = min(chunk_len, CONTROLLER_PAGE_LIMIT);
cmd[0] = CMD_AT25DF_PP; cmd[0] = CMD_AT25DF_PP;
cmd[1] = (offset >> 16) & 0xff; cmd[1] = (offset >> 16) & 0xff;

View File

@ -70,7 +70,7 @@ static int amic_write(struct spi_flash *flash,
int ret; int ret;
u8 cmd[4]; u8 cmd[4];
page_size = min(1 << amic->params->l2_page_size, CONTROLLER_PAGE_LIMIT); page_size = 1 << amic->params->l2_page_size;
byte_addr = offset % page_size; byte_addr = offset % page_size;
flash->spi->rw = SPI_WRITE_FLAG; flash->spi->rw = SPI_WRITE_FLAG;
@ -82,6 +82,7 @@ static int amic_write(struct spi_flash *flash,
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);
chunk_len = min(chunk_len, CONTROLLER_PAGE_LIMIT);
cmd[0] = CMD_A25_PP; cmd[0] = CMD_A25_PP;
cmd[1] = (offset >> 16) & 0xff; cmd[1] = (offset >> 16) & 0xff;

View File

@ -128,7 +128,7 @@ static int gigadevice_write(struct spi_flash *flash, u32 offset,
int ret; int ret;
u8 cmd[4]; u8 cmd[4];
page_size = min(1 << stm->params->l2_page_size, CONTROLLER_PAGE_LIMIT); page_size = 1 << stm->params->l2_page_size;
byte_addr = offset % page_size; byte_addr = offset % page_size;
flash->spi->rw = SPI_WRITE_FLAG; flash->spi->rw = SPI_WRITE_FLAG;
@ -141,6 +141,7 @@ static int gigadevice_write(struct spi_flash *flash, u32 offset,
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);
chunk_len = min(chunk_len, CONTROLLER_PAGE_LIMIT);
ret = spi_flash_cmd(flash->spi, CMD_GD25_WREN, NULL, 0); ret = spi_flash_cmd(flash->spi, CMD_GD25_WREN, NULL, 0);
if (ret < 0) { if (ret < 0) {

View File

@ -131,7 +131,7 @@ static int macronix_write(struct spi_flash *flash,
int ret; int ret;
u8 cmd[4]; u8 cmd[4];
page_size = min(mcx->params->page_size, CONTROLLER_PAGE_LIMIT); page_size = mcx->params->page_size;
byte_addr = offset % page_size; byte_addr = offset % page_size;
flash->spi->rw = SPI_WRITE_FLAG; flash->spi->rw = SPI_WRITE_FLAG;
@ -144,6 +144,7 @@ static int macronix_write(struct spi_flash *flash,
ret = 0; 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);
chunk_len = min(chunk_len, CONTROLLER_PAGE_LIMIT);
cmd[0] = CMD_MX25XX_PP; cmd[0] = CMD_MX25XX_PP;
cmd[1] = (offset >> 16) & 0xff; cmd[1] = (offset >> 16) & 0xff;

View File

@ -143,7 +143,7 @@ static int stmicro_write(struct spi_flash *flash,
int ret; int ret;
u8 cmd[4]; u8 cmd[4];
page_size = min(stm->params->page_size, CONTROLLER_PAGE_LIMIT); page_size = stm->params->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,6 +155,7 @@ static int stmicro_write(struct spi_flash *flash,
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);
chunk_len = min(chunk_len, CONTROLLER_PAGE_LIMIT);
cmd[0] = CMD_M25PXX_PP; cmd[0] = CMD_M25PXX_PP;
cmd[1] = (offset >> 16) & 0xff; cmd[1] = (offset >> 16) & 0xff;

View File

@ -122,7 +122,7 @@ static int winbond_write(struct spi_flash *flash,
int ret; int ret;
u8 cmd[4]; u8 cmd[4];
page_size = min(1 << stm->params->l2_page_size, CONTROLLER_PAGE_LIMIT); page_size = 1 << stm->params->l2_page_size;
byte_addr = offset % page_size; byte_addr = offset % page_size;
flash->spi->rw = SPI_WRITE_FLAG; flash->spi->rw = SPI_WRITE_FLAG;
@ -134,6 +134,7 @@ static int winbond_write(struct spi_flash *flash,
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);
chunk_len = min(chunk_len, CONTROLLER_PAGE_LIMIT);
cmd[0] = CMD_W25_PP; cmd[0] = CMD_W25_PP;
cmd[1] = (offset >> 16) & 0xff; cmd[1] = (offset >> 16) & 0xff;