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 <dev(a)borisbaykov.com>, 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 <ctype.h>
#include "flash.h"
#include "programmer.h"
#include "spi.h"
#include <ftdi.h>
+#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