diff --git a/src/drivers/spi/spi_flash.c b/src/drivers/spi/spi_flash.c index d737ee9e61..607fb214a8 100644 --- a/src/drivers/spi/spi_flash.c +++ b/src/drivers/spi/spi_flash.c @@ -79,8 +79,8 @@ int spi_flash_cmd(struct spi_slave *spi, u8 cmd, void *response, size_t len) return ret; } -int spi_flash_cmd_read(struct spi_slave *spi, const u8 *cmd, - size_t cmd_len, void *data, size_t data_len) +static int spi_flash_cmd_read(struct spi_slave *spi, const u8 *cmd, + size_t cmd_len, void *data, size_t data_len) { int ret = do_spi_flash_cmd(spi, cmd, cmd_len, data, data_len); if (ret) { @@ -108,41 +108,51 @@ int spi_flash_cmd_write(struct spi_slave *spi, const u8 *cmd, size_t cmd_len, return ret; } -int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd, - size_t cmd_len, void *data, size_t data_len) +static int spi_flash_cmd_read_array(struct spi_slave *spi, u8 *cmd, + size_t cmd_len, u32 offset, + size_t len, void *data) { - struct spi_slave *spi = flash->spi; - int ret; + while (len) { + size_t transfer_size; - spi->rw = SPI_READ_FLAG; - ret = spi_flash_cmd_read(spi, cmd, cmd_len, data, data_len); + if (spi->max_transfer_size) + transfer_size = min(len, spi->max_transfer_size); + else + transfer_size = len; - return ret; + spi_flash_addr(offset, cmd); + + if (spi_flash_cmd_read(spi, cmd, cmd_len, data, transfer_size)) + break; + + offset += transfer_size; + data = (void *)((uintptr_t)data + transfer_size); + len -= transfer_size; + } + + return len != 0; } int spi_flash_cmd_read_fast(struct spi_flash *flash, u32 offset, size_t len, void *data) { - struct spi_slave *spi = flash->spi; u8 cmd[5]; cmd[0] = CMD_READ_ARRAY_FAST; - spi_flash_addr(offset, cmd); cmd[4] = 0x00; - return spi_flash_cmd_read(spi, cmd, sizeof(cmd), data, len); + return spi_flash_cmd_read_array(flash->spi, cmd, sizeof(cmd), + offset, len, data); } int spi_flash_cmd_read_slow(struct spi_flash *flash, u32 offset, - size_t len, void *data) + size_t len, void *data) { - struct spi_slave *spi = flash->spi; u8 cmd[4]; cmd[0] = CMD_READ_ARRAY_SLOW; - spi_flash_addr(offset, cmd); - - return spi_flash_cmd_read(spi, cmd, sizeof(cmd), data, len); + return spi_flash_cmd_read_array(flash->spi, cmd, sizeof(cmd), + offset, len, data); } int spi_flash_cmd_poll_bit(struct spi_flash *flash, unsigned long timeout, diff --git a/src/drivers/spi/spi_flash_internal.h b/src/drivers/spi/spi_flash_internal.h index 6f184848b6..4798b10925 100644 --- a/src/drivers/spi/spi_flash_internal.h +++ b/src/drivers/spi/spi_flash_internal.h @@ -32,13 +32,6 @@ /* Send a single-byte command to the device and read the response */ int spi_flash_cmd(struct spi_slave *spi, u8 cmd, void *response, size_t len); -/* - * Send a multi-byte command to the device and read the response. Used - * for flash array reads, etc. - */ -int spi_flash_cmd_read(struct spi_slave *spi, const u8 *cmd, - size_t cmd_len, void *data, size_t data_len); - int spi_flash_cmd_read_fast(struct spi_flash *flash, u32 offset, size_t len, void *data); @@ -52,13 +45,6 @@ int spi_flash_cmd_read_slow(struct spi_flash *flash, u32 offset, int spi_flash_cmd_write(struct spi_slave *spi, const u8 *cmd, size_t cmd_len, const void *data, size_t data_len); -/* - * Same as spi_flash_cmd_read() except it also claims/releases the SPI - * bus. Used as common part of the ->read() operation. - */ -int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd, - size_t cmd_len, void *data, size_t data_len); - /* Send a command to the device and wait for some bit to clear itself. */ int spi_flash_cmd_poll_bit(struct spi_flash *flash, unsigned long timeout, u8 cmd, u8 poll_bit); diff --git a/src/include/spi-generic.h b/src/include/spi-generic.h index bd0020f5d2..4de138cf09 100644 --- a/src/include/spi-generic.h +++ b/src/include/spi-generic.h @@ -43,11 +43,16 @@ * bus: ID of the bus that the slave is attached to. * cs: ID of the chip select connected to the slave. * rw: Read or Write flag + * max_transfer_size: maximum amount of bytes which can be sent in a single + * read or write transaction, usually this is a controller + * property, kept in the slave structure for convenience. Zero in + * this field means 'unlimited'. */ struct spi_slave { unsigned int bus; unsigned int cs; unsigned int rw; + unsigned int max_transfer_size; int force_programmer_specific; struct spi_flash * (*programmer_specific_probe) (struct spi_slave *spi); }; diff --git a/src/soc/imgtec/pistachio/spi.c b/src/soc/imgtec/pistachio/spi.c index 69682d0456..5522f2408e 100644 --- a/src/soc/imgtec/pistachio/spi.c +++ b/src/soc/imgtec/pistachio/spi.c @@ -25,6 +25,9 @@ #error "Unsupported SPI driver API" #endif +/* Imgtec controller uses 16 bit packet length. */ +#define IMGTEC_SPI_MAX_TRANSFER_SIZE ((1 << 16) - 1) + struct img_spi_slave { struct spi_slave slave; /* SPIM instance device parameters */ @@ -441,6 +444,8 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs) slave->bus = bus; slave->cs = cs; slave->rw = SPI_READ_FLAG | SPI_WRITE_FLAG; + slave->max_transfer_size = IMGTEC_SPI_MAX_TRANSFER_SIZE; + device_parameters->bitrate = 64; device_parameters->cs_setup = 0; device_parameters->cs_hold = 0;