From patchwork Sun Jan 18 05:50:57 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: Fast flash read speed with FTDI FT2232H programmer Date: Sun, 18 Jan 2015 05:50:57 -0000 From: Boris Baykov X-Patchwork-Id: 4273 Message-Id: <74681267.20150118085057@borisbaykov.com> To: flashrom@flashrom.org The patch increases flash read speed via FTDI FT2232H programmer. New ft2232_spi_read function used instead of spi_read_chunked to read by 64k chunks instead of 256b chunks. According to 3-7 ms FTDI delay for each flash instruction this patch makes read operation faster in about 10 times. To have stable transfers with 64k buffer SPI frequency should be decreased to 5 MHz. I don't know why but higher freqs aren't working correct. DEFAULT_DIVISOR is changed to 12. Signed-off-by: Boris Baykov , Russia, Jan 2015 --- The patch increases flash read speed via FTDI FT2232H programmer. New ft2232_spi_read function used instead of spi_read_chunked to read by 64k chunks instead of 256b chunks. According to 3-7 ms FTDI delay for each flash instruction this patch makes read operation faster in about 10 times. To have stable transfers with 64k buffer SPI frequency should be decreased to 5 MHz. I don't know why but higher freqs aren't working correct. DEFAULT_DIVISOR is changed to 12. Signed-off-by: Boris Baykov , Russia, Jan 2015 --- diff -U 5 -N ./flashrom/ft2232_spi.c ./flashrom.fast_ftdi/ft2232_spi.c --- ./flashrom/ft2232_spi.c 2015-01-08 15:21:54.000000000 +0300 +++ ./flashrom.fast_ftdi/ft2232_spi.c 2015-01-18 08:44:26.000000000 +0300 @@ -27,10 +27,11 @@ #include #include "flash.h" #include "programmer.h" #include "spi.h" #include +#include "chipdrivers.h" /* This is not defined in libftdi.h <0.20 (c7e4c09e68cfa6f5e112334aa1b3bb23401c8dc7 to be exact). * Some tests indicate that his is the only change that it is needed to support the FT232H in flashrom. */ #if !defined(HAVE_FT232H) #define TYPE_232H 6 @@ -73,11 +74,14 @@ {OLIMEX_VID, OLIMEX_ARM_TINY_H_PID, OK, "Olimex", "ARM-USB-TINY-H"}, {0}, }; -#define DEFAULT_DIVISOR 2 +/* Default divisor has been changed to 12 to provide 5 MHz frequency. + * This frequency is maximum stable frequency for operate with 64k buffer. + */ +#define DEFAULT_DIVISOR 12 #define BITMODE_BITBANG_NORMAL 1 #define BITMODE_BITBANG_SPI 2 /* Set data bits low-byte command: @@ -144,17 +148,20 @@ static int ft2232_spi_send_command(struct flashctx *flash, unsigned int writecnt, unsigned int readcnt, const unsigned char *writearr, unsigned char *readarr); +static int ft2232_spi_read(struct flashctx *flash, uint8_t *buf, + unsigned int start, unsigned int len); + static const struct spi_master spi_master_ft2232 = { .type = SPI_CONTROLLER_FT2232, .max_data_read = 64 * 1024, .max_data_write = 256, .command = ft2232_spi_send_command, .multicommand = default_spi_send_multicommand, - .read = default_spi_read, + .read = ft2232_spi_read, .write_256 = default_spi_write_256, .write_aai = default_spi_write_aai, }; /* Returns 0 upon success, a negative number upon errors. */ @@ -294,10 +301,15 @@ msg_perr("Error: Invalid SPI frequency divisor specified: \"%s\".\n" "Valid are even values between 2 and 131072.\n", arg); free(arg); return -2; } else { + if (temp < DEFAULT_DIVISOR) { + msg_pinfo("\nWarning: SPI frequency is too high for FT2232H with 64k buffer.\n" + "Some data from SPI may be lost. To ensure stability please\n" + "encrease the divisor value at least to %d.\n\n", DEFAULT_DIVISOR); + } divisor = (uint32_t)temp; } } free(arg); @@ -486,6 +498,53 @@ msg_perr("send_buf failed at end: %i\n", ret); return failed ? -1 : 0; } +/* FIXME: This function is optimized so that it does not split each transaction + * into chip page_size long blocks unnecessarily like spi_read_chunked. This has + * the advantage that it is much faster for most chips, but breaks those with + * non-continuous reads. When spi_read_chunked is fixed this method can be removed. */ +static int ft2232_spi_read(struct flashctx *flash, uint8_t *buf, + unsigned int start, unsigned int len) +{ + int ret; + unsigned int i, cur_len; + const unsigned int max_read = spi_master_ft2232.max_data_read; + int show_progress = 0; + unsigned int percent_last = 0, percent_current = 0; + + /* progress visualizaion init */ + if(len >= MIN_LENGTH_TO_SHOW_READ_PROGRESS) { + msg_cinfo(" "); /* only this space will go to logfile but + all strings with \b wont. */ + msg_cinfo("\b 0%%"); + percent_last = percent_current = 0; + show_progress = 1; /* enable progress visualizaion */ + } + + for (i = 0; i < len; i += cur_len) { + cur_len = min(max_read, (len - i)); + ret = (flash->chip->feature_bits & FEATURE_4BA_SUPPORT) == 0 + ? spi_nbyte_read(flash, start + i, buf + i, cur_len) + : flash->chip->four_bytes_addr_funcs.read_nbyte(flash, + start + i, buf + i, cur_len); + if (ret) + break; + + if(show_progress) { + percent_current = (unsigned int) + (((unsigned long long)(i + cur_len)) * 100 / len); + if(percent_current != percent_last) { + msg_cinfo("\b\b\b%2d%%", percent_current); + percent_last = percent_current; + } + } + } + + if(show_progress && !ret) + msg_cinfo("\b\b\b\b"); /* remove progress percents from the screen */ + + return ret; +} + #endif