diff options
author | Simon Buhrow <simon.buhrow@sieb-meyer.de> | 2021-04-09 14:48:39 +0200 |
---|---|---|
committer | Nico Huber <nico.h@gmx.de> | 2021-06-25 12:47:47 +0000 |
commit | 4d5a3b5eb03ad73d7eab16cf158513c1ed013c14 (patch) | |
tree | 25e53c4c2baee8b61703628a748fc20c49c45bc5 | |
parent | d3e778f8ab1694d9c93c2c290fdcd8929c7151f9 (diff) | |
download | flashrom-4d5a3b5eb03ad73d7eab16cf158513c1ed013c14.tar.gz flashrom-4d5a3b5eb03ad73d7eab16cf158513c1ed013c14.tar.bz2 flashrom-4d5a3b5eb03ad73d7eab16cf158513c1ed013c14.zip |
ft2232_spi.c: Implement spi_send_multicommand()
Every ftdi_write_data() call is quite time consuming as the ftdi-chips
seems to take always 2-3ms to respond. This leads to what the comment
already says: Minimize USB transfers by packing as many commands as
possible together. So I packed the WREN command together with the
following operation which can be program or erase operation.
This saves about 1 minute when programming a 128MBit Flash within a
virtualized setup.
Signed-off-by: Simon Buhrow <simon.buhrow@posteo.de>
Change-Id: Ie4a07499ec5ef0af23818593f45dc427285a9e8a
Reviewed-on: https://review.coreboot.org/c/flashrom/+/40477
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Nico Huber <nico.h@gmx.de>
Reviewed-by: Angel Pons <th3fanbus@gmail.com>
-rw-r--r-- | ft2232_spi.c | 91 |
1 files changed, 90 insertions, 1 deletions
diff --git a/ft2232_spi.c b/ft2232_spi.c index 082f5ffe4..3fe7ea4dd 100644 --- a/ft2232_spi.c +++ b/ft2232_spi.c @@ -79,6 +79,8 @@ static const struct dev_entry devs_ft2232spi[] = { {0}, }; +#define FTDI_HW_BUFFER_SIZE 4096 /* in bytes */ + #define DEFAULT_DIVISOR 2 #define BITMODE_BITBANG_NORMAL 1 @@ -276,12 +278,99 @@ static int ft2232_spi_send_command(const struct flashctx *flash, return failed ? -1 : 0; } +static bool ft2232_spi_command_fits(const struct spi_command *cmd, size_t buffer_size) +{ + const size_t cmd_len = 3; /* same length for any ft2232 command */ + return + /* commands for CS# assertion and de-assertion: */ + cmd_len + cmd_len + /* commands for either a write, a read or both: */ + + (cmd->writecnt && cmd->readcnt ? cmd_len + cmd_len : cmd_len) + /* payload (only writecnt; readcnt concerns another buffer): */ + + cmd->writecnt + <= buffer_size; +} + +/* Returns 0 upon success, a negative number upon errors. */ +static int ft2232_spi_send_multicommand(const struct flashctx *flash, struct spi_command *cmds) +{ + struct ft2232_data *spi_data = flash->mst->spi.data; + struct ftdi_context *ftdic = &spi_data->ftdic_context; + static unsigned char buf[FTDI_HW_BUFFER_SIZE]; + size_t i = 0; + int ret = 0; + + /* + * Minimize FTDI-calls by packing as many commands as possible together. + */ + for (; cmds->writecnt || cmds->readcnt; cmds++) { + + if (cmds->writecnt > 65536 || cmds->readcnt > 65536) + return SPI_INVALID_LENGTH; + + if (!ft2232_spi_command_fits(cmds, FTDI_HW_BUFFER_SIZE - i)) { + msg_perr("Command does not fit\n"); + return SPI_GENERIC_ERROR; + } + + msg_pspew("Assert CS#\n"); + buf[i++] = SET_BITS_LOW; + buf[i++] = ~ 0x08 & spi_data->pinlvl; /* assert CS (3rd) bit only */ + buf[i++] = spi_data->pindir; + + /* WREN, OP(PROGRAM, ERASE), ADDR, DATA */ + if (cmds->writecnt) { + buf[i++] = MPSSE_DO_WRITE | MPSSE_WRITE_NEG; + buf[i++] = (cmds->writecnt - 1) & 0xff; + buf[i++] = ((cmds->writecnt - 1) >> 8) & 0xff; + memcpy(buf + i, cmds->writearr, cmds->writecnt); + i += cmds->writecnt; + } + + /* An optional read command */ + if (cmds->readcnt) { + buf[i++] = MPSSE_DO_READ; + buf[i++] = (cmds->readcnt - 1) & 0xff; + buf[i++] = ((cmds->readcnt - 1) >> 8) & 0xff; + } + + /* Add final de-assert CS# */ + msg_pspew("De-assert CS#\n"); + buf[i++] = SET_BITS_LOW; + buf[i++] = spi_data->pinlvl; + buf[i++] = spi_data->pindir; + + /* continue if there is no read-cmd and further cmds exist */ + if (!cmds->readcnt && + ((cmds + 1)->writecnt || (cmds + 1)->readcnt) && + ft2232_spi_command_fits((cmds + 1), FTDI_HW_BUFFER_SIZE - i)) { + continue; + } + + ret = send_buf(ftdic, buf, i); + i = 0; + if (ret) { + msg_perr("send_buf failed: %i\n", ret); + break; + } + + if (cmds->readcnt) { + ret = get_buf(ftdic, cmds->readarr, cmds->readcnt); + if (ret) { + msg_perr("get_buf failed: %i\n", ret); + break; + } + } + } + return ret ? -1 : 0; +} + static const struct spi_master spi_master_ft2232 = { .features = SPI_MASTER_4BA, .max_data_read = 64 * 1024, .max_data_write = 256, .command = ft2232_spi_send_command, - .multicommand = default_spi_send_multicommand, + .multicommand = ft2232_spi_send_multicommand, .read = default_spi_read, .write_256 = default_spi_write_256, .write_aai = default_spi_write_aai, |