
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@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
