SPI: Split writes using spi_crop_chunk()

SPI controllers in Intel and AMD bridges have a slightly different
restriction on how long transactions they can handle.

Change-Id: I3d149d4b7e7e9633482a153d5e380a86c553d871
Signed-off-by: Kyösti Mälkki <kyosti.malkki@gmail.com>
Reviewed-on: http://review.coreboot.org/6163
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:17:33 +03:00
parent 77d1280d0c
commit 1110495de9
13 changed files with 45 additions and 24 deletions

View File

@ -100,7 +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); chunk_len = spi_crop_chunk(sizeof(cmd), chunk_len);
cmd[0] = CMD_AT25DF_PP; cmd[0] = CMD_AT25DF_PP;
cmd[1] = (offset >> 16) & 0xff; cmd[1] = (offset >> 16) & 0xff;
@ -118,7 +118,7 @@ static int adesto_write(struct spi_flash *flash,
goto out; goto out;
} }
ret = spi_flash_cmd_write(flash->spi, cmd, 4, ret = spi_flash_cmd_write(flash->spi, cmd, sizeof(cmd),
buf + actual, chunk_len); buf + actual, chunk_len);
if (ret < 0) { if (ret < 0) {
printk(BIOS_WARNING, "SF: adesto Page Program failed\n"); printk(BIOS_WARNING, "SF: adesto Page Program failed\n");

View File

@ -82,7 +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); chunk_len = spi_crop_chunk(sizeof(cmd), chunk_len);
cmd[0] = CMD_A25_PP; cmd[0] = CMD_A25_PP;
cmd[1] = (offset >> 16) & 0xff; cmd[1] = (offset >> 16) & 0xff;
@ -100,7 +100,7 @@ static int amic_write(struct spi_flash *flash,
goto out; goto out;
} }
ret = spi_flash_cmd_write(flash->spi, cmd, 4, ret = spi_flash_cmd_write(flash->spi, cmd, sizeof(cmd),
buf + actual, chunk_len); buf + actual, chunk_len);
if (ret < 0) { if (ret < 0) {
printk(BIOS_WARNING, "SF: AMIC Page Program failed\n"); printk(BIOS_WARNING, "SF: AMIC Page Program failed\n");

View File

@ -141,7 +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); chunk_len = spi_crop_chunk(sizeof(cmd), chunk_len);
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) {
@ -161,7 +161,7 @@ static int gigadevice_write(struct spi_flash *flash, u32 offset,
cmd[0], cmd[1], cmd[2], cmd[3], chunk_len); cmd[0], cmd[1], cmd[2], cmd[3], chunk_len);
#endif #endif
ret = spi_flash_cmd_write(flash->spi, cmd, 4, ret = spi_flash_cmd_write(flash->spi, cmd, sizeof(cmd),
buf + actual, chunk_len); buf + actual, chunk_len);
if (ret < 0) { if (ret < 0) {
printk(BIOS_WARNING, printk(BIOS_WARNING,

View File

@ -144,13 +144,12 @@ 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); chunk_len = spi_crop_chunk(sizeof(cmd), chunk_len);
cmd[0] = CMD_MX25XX_PP; cmd[0] = CMD_MX25XX_PP;
cmd[1] = (offset >> 16) & 0xff; cmd[1] = (offset >> 16) & 0xff;
cmd[2] = (offset >> 8) & 0xff; cmd[2] = (offset >> 8) & 0xff;
cmd[3] = offset & 0xff; 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",
@ -163,7 +162,7 @@ static int macronix_write(struct spi_flash *flash,
break; break;
} }
ret = spi_flash_cmd_write(flash->spi, cmd, 4, ret = spi_flash_cmd_write(flash->spi, cmd, sizeof(cmd),
buf + actual, chunk_len); buf + actual, chunk_len);
if (ret < 0) { if (ret < 0) {
printk(BIOS_WARNING, "SF: Macronix Page Program failed\n"); printk(BIOS_WARNING, "SF: Macronix Page Program failed\n");

View File

@ -155,7 +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); chunk_len = spi_crop_chunk(sizeof(cmd), chunk_len);
cmd[0] = CMD_M25PXX_PP; cmd[0] = CMD_M25PXX_PP;
cmd[1] = (offset >> 16) & 0xff; cmd[1] = (offset >> 16) & 0xff;
@ -173,7 +173,7 @@ static int stmicro_write(struct spi_flash *flash,
goto out; goto out;
} }
ret = spi_flash_cmd_write(flash->spi, cmd, 4, ret = spi_flash_cmd_write(flash->spi, cmd, sizeof(cmd),
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");

View File

@ -134,7 +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); chunk_len = spi_crop_chunk(sizeof(cmd), chunk_len);
cmd[0] = CMD_W25_PP; cmd[0] = CMD_W25_PP;
cmd[1] = (offset >> 16) & 0xff; cmd[1] = (offset >> 16) & 0xff;
@ -152,7 +152,7 @@ static int winbond_write(struct spi_flash *flash,
goto out; goto out;
} }
ret = spi_flash_cmd_write(flash->spi, cmd, 4, ret = spi_flash_cmd_write(flash->spi, cmd, sizeof(cmd),
buf + actual, chunk_len); buf + actual, chunk_len);
if (ret < 0) { if (ret < 0) {
printk(BIOS_WARNING, "SF: Winbond Page Program failed\n"); printk(BIOS_WARNING, "SF: Winbond Page Program failed\n");

View File

@ -168,6 +168,8 @@ void spi_cs_deactivate(struct spi_slave *slave);
*/ */
void spi_set_speed(struct spi_slave *slave, uint32_t hz); void spi_set_speed(struct spi_slave *slave, uint32_t hz);
unsigned int spi_crop_chunk(unsigned int cmd_len, unsigned int buf_len);
/*----------------------------------------------------------------------- /*-----------------------------------------------------------------------
* Write 8 bits, then read 8 bits. * Write 8 bits, then read 8 bits.
* slave: The SPI slave we're communicating with * slave: The SPI slave we're communicating with

View File

@ -39,14 +39,6 @@
const typeof( ((type *)0)->member ) *__mptr = (ptr); \ const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );}) (type *)( (char *)__mptr - offsetof(type,member) );})
#define CONFIG_ICH_SPI
#ifdef CONFIG_ICH_SPI
#define CONTROLLER_PAGE_LIMIT 64
#else
/* any number larger than 4K would do, actually */
#define CONTROLLER_PAGE_LIMIT ((int)(~0U>>1))
#endif
struct spi_flash { struct spi_flash {
struct spi_slave *spi; struct spi_slave *spi;

View File

@ -499,6 +499,11 @@ static int ich_status_poll(u16 bitmask, int wait_til_set)
return -1; return -1;
} }
unsigned int spi_crop_chunk(unsigned int cmd_len, unsigned int buf_len)
{
return min(cntlr.databytes, buf_len);
}
int spi_xfer(struct spi_slave *slave, const void *dout, int spi_xfer(struct spi_slave *slave, const void *dout,
unsigned int bytesout, void *din, unsigned int bytesin) unsigned int bytesout, void *din, unsigned int bytesin)
{ {
@ -588,7 +593,7 @@ int spi_xfer(struct spi_slave *slave, const void *dout,
*/ */
if (trans.bytesout > cntlr.databytes) { if (trans.bytesout > cntlr.databytes) {
printk(BIOS_DEBUG, "ICH SPI: Too much to write. Does your SPI chip driver use" printk(BIOS_DEBUG, "ICH SPI: Too much to write. Does your SPI chip driver use"
" CONTROLLER_PAGE_LIMIT?\n"); " spi_crop_chunk()?\n");
return -1; return -1;
} }

View File

@ -497,6 +497,11 @@ static int ich_status_poll(u16 bitmask, int wait_til_set)
return -1; return -1;
} }
unsigned int spi_crop_chunk(unsigned int cmd_len, unsigned int buf_len)
{
return min(cntlr.databytes, buf_len);
}
int spi_xfer(struct spi_slave *slave, const void *dout, int spi_xfer(struct spi_slave *slave, const void *dout,
unsigned int bytesout, void *din, unsigned int bytesin) unsigned int bytesout, void *din, unsigned int bytesin)
{ {
@ -585,7 +590,7 @@ int spi_xfer(struct spi_slave *slave, const void *dout,
*/ */
if (trans.bytesout > cntlr.databytes) { if (trans.bytesout > cntlr.databytes) {
printk(BIOS_DEBUG, "ICH SPI: Too much to write. Does your SPI chip driver use" printk(BIOS_DEBUG, "ICH SPI: Too much to write. Does your SPI chip driver use"
" CONTROLLER_PAGE_LIMIT?\n"); " spi_crop_chunk()?\n");
return -1; return -1;
} }

View File

@ -42,6 +42,7 @@ static int bus_claimed = 0;
#define SPI_REG_CNTRL11 0xd #define SPI_REG_CNTRL11 0xd
#define CNTRL11_FIFOPTR_MASK 0x07 #define CNTRL11_FIFOPTR_MASK 0x07
#define AMD_SB_SPI_TX_LEN 64
static u32 spibar; static u32 spibar;
@ -86,6 +87,11 @@ void spi_init(void)
spibar = pci_read_config32(dev, 0xA0) & ~0x1F; spibar = pci_read_config32(dev, 0xA0) & ~0x1F;
} }
unsigned int spi_crop_chunk(unsigned int cmd_len, unsigned int buf_len)
{
return min(AMD_SB_SPI_TX_LEN - cmd_len, buf_len);
}
int spi_xfer(struct spi_slave *slave, const void *dout, int spi_xfer(struct spi_slave *slave, const void *dout,
unsigned int bytesout, void *din, unsigned int bytesin) unsigned int bytesout, void *din, unsigned int bytesin)
{ {

View File

@ -32,6 +32,8 @@
static int bus_claimed = 0; static int bus_claimed = 0;
#endif #endif
#define AMD_SB_SPI_TX_LEN 8
static u32 spibar; static u32 spibar;
static void reset_internal_fifo_pointer(void) static void reset_internal_fifo_pointer(void)
@ -56,6 +58,11 @@ void spi_init()
spibar = pci_read_config32(dev, 0xA0) & ~0x1F; spibar = pci_read_config32(dev, 0xA0) & ~0x1F;
} }
unsigned int spi_crop_chunk(unsigned int cmd_len, unsigned int buf_len)
{
return min(AMD_SB_SPI_TX_LEN - cmd_len, buf_len);
}
int spi_xfer(struct spi_slave *slave, const void *dout, int spi_xfer(struct spi_slave *slave, const void *dout,
unsigned int bytesout, void *din, unsigned int bytesin) unsigned int bytesout, void *din, unsigned int bytesin)
{ {

View File

@ -550,6 +550,11 @@ static int spi_is_multichip (void)
return !!((cntlr.flmap0 >> 8) & 3); return !!((cntlr.flmap0 >> 8) & 3);
} }
unsigned int spi_crop_chunk(unsigned int cmd_len, unsigned int buf_len)
{
return min(cntlr.databytes, buf_len);
}
int spi_xfer(struct spi_slave *slave, const void *dout, int spi_xfer(struct spi_slave *slave, const void *dout,
unsigned int bytesout, void *din, unsigned int bytesin) unsigned int bytesout, void *din, unsigned int bytesin)
{ {
@ -639,7 +644,7 @@ int spi_xfer(struct spi_slave *slave, const void *dout,
*/ */
if (trans.bytesout > cntlr.databytes) { if (trans.bytesout > cntlr.databytes) {
printk(BIOS_DEBUG, "ICH SPI: Too much to write. Does your SPI chip driver use" printk(BIOS_DEBUG, "ICH SPI: Too much to write. Does your SPI chip driver use"
" CONTROLLER_PAGE_LIMIT?\n"); " spi_crop_chunk()?\n");
return -1; return -1;
} }