Hello,
I would like to submit a patch, that enables extra argument when using FT2232 external programmer, a frequency divider. For FT2232 programmer we have this divider set to 3 by default by DIVIDE_BY constant, which will result in 10MHz (H-chips) or 2MHz (non H-chips) SPI speeds.
By providing divider as parameter, SPI interface frequency culd be overridden by user, resulting in different speeds (H-chip example):
divider | freq ---------+-------- 1 | 30Mhz 2 | 15Mhz 3 | 10Mhz 4 | 7.5Mhz 5 | 6Mhz 6 | 5Mhz 15 | 2Mhz 30 | 1Mhz 60 | 0.5Mhz 600 | 0.05Mhz (and so on)
These lower than default SPI speeds can be very useful when we have flawed flash chips that would not support 10Mhz or bad quality or too long cabling between programmer and the chip. Higher than default speeds might also be useful (if only flashrom AAI implementation was faster).
Please note that this parameter is arbitrary integer, maybe only a value up to 255 would really make sense, but i can not be sure about that since it may be programmer hardware dependent. All values between 1-255 worked for me (PicoTAP programmer), as well as 300 & 600 (these resulted in extremely slow flash reads, as expected, 2MB flash that usually takes 16s to read @2-10Mhz, took more than 6 minutes @0.05Mhz). Others values i haven't tested.
Signed-off-by: Samir Ibradžić sibradzic@gmail.com --- $ svn diff Index: ft2232_spi.c =================================================================== --- ft2232_spi.c (revision 1451) +++ ft2232_spi.c (working copy) @@ -168,6 +168,7 @@ enum ftdi_interface ft2232_interface = INTERFACE_B; char *arg; double mpsse_clk; + int divider = DIVIDE_BY;
arg = extract_programmer_param("type"); if (arg) { @@ -237,6 +238,17 @@ } } free(arg); + arg = extract_programmer_param("divider"); + if (arg) { + if (isdigit(*arg) && (atoi(arg) > 0)) + divider = atoi(arg); + else { + msg_perr("Error: Invalid frequency divider specified.\n"); + free(arg); + return -2; + } + } + free(arg); msg_pdbg("Using device type %s %s ", get_ft2232_vendorname(ft2232_vid, ft2232_type), get_ft2232_devicename(ft2232_vid, ft2232_type)); @@ -298,16 +310,16 @@ msg_pdbg("Set clock divisor\n"); buf[0] = 0x86; /* command "set divisor" */ /* valueL/valueH are (desired_divisor - 1) */ - buf[1] = (DIVIDE_BY - 1) & 0xff; - buf[2] = ((DIVIDE_BY - 1) >> 8) & 0xff; + buf[1] = (divider - 1) & 0xff; + buf[2] = ((divider - 1) >> 8) & 0xff; if (send_buf(ftdic, buf, 3)) { ret = -6; goto ftdi_err; }
msg_pdbg("MPSSE clock: %f MHz divisor: %d " - "SPI clock: %f MHz\n", mpsse_clk, DIVIDE_BY, - (double)(mpsse_clk / (((DIVIDE_BY - 1) + 1) * 2))); + "SPI clock: %f MHz\n", mpsse_clk, divider, + (double)(mpsse_clk / (((divider - 1) + 1) * 2)));
/* Disconnect TDI/DO to TDO/DI for loopback. */ msg_pdbg("No loopback of TDI/DO TDO/DI\n"); -- R, S
On 2011年10月17日 04:04, Samir Ibradžić wrote:
Hello,
I would like to submit a patch, that enables extra argument when using FT2232 external programmer, a frequency divider. For FT2232 programmer we have this divider set to 3 by default by DIVIDE_BY constant, which will result in 10MHz (H-chips) or 2MHz (non H-chips) SPI speeds.
By providing divider as parameter, SPI interface frequency culd be overridden by user, resulting in different speeds (H-chip example):
divider | freq ---------+-------- 1 | 30Mhz 2 | 15Mhz 3 | 10Mhz 4 | 7.5Mhz 5 | 6Mhz 6 | 5Mhz 15 | 2Mhz 30 | 1Mhz 60 | 0.5Mhz 600 | 0.05Mhz (and so on)
These lower than default SPI speeds can be very useful when we have flawed flash chips that would not support 10Mhz or bad quality or too long cabling between programmer and the chip. Higher than default speeds might also be useful (if only flashrom AAI implementation was faster).
Please note that this parameter is arbitrary integer, maybe only a value up to 255 would really make sense, but i can not be sure about that since it may be programmer hardware dependent. All values between 1-255 worked for me (PicoTAP programmer), as well as 300 & 600 (these resulted in extremely slow flash reads, as expected, 2MB flash that usually takes 16s to read @2-10Mhz, took more than 6 minutes @0.05Mhz). Others values i haven't tested.
After re-reading some FT2232 data sheets, it looks like the valid value for divider is any integer between 1 and 65535. Tested a lot of values in here (including 65535), and i can confirm that at least PicoTAP supports this parameter correctly, no reason other FT2232 devices wouldn't work too. I also added some simple divider parameter validation. Re-submitting this patch.
Signed-off-by: Samir Ibradžić sibradzic@gmail.com Tested-by: Samir Ibradžić sibradzic@gmail.com --- $ svn diff Index: ft2232_spi.c =================================================================== --- ft2232_spi.c (revision 1457) +++ ft2232_spi.c (working copy) @@ -168,6 +168,7 @@ enum ftdi_interface ft2232_interface = INTERFACE_B; char *arg; double mpsse_clk; + uint16_t divider = DIVIDE_BY;
arg = extract_programmer_param("type"); if (arg) { @@ -237,6 +238,20 @@ } } free(arg); + arg = extract_programmer_param("divider"); + if (arg && strlen(arg)) { + unsigned int temp = 0; + char *trailing_char; + temp = strtoul(arg, &trailing_char, 10); + if (*trailing_char || !temp || temp > 65535) { + msg_perr("Error: Invalid frequency divider specified.\n"); + free(arg); + return -2; + } else { + divider = (uint16_t)temp; + } + } + free(arg); msg_pdbg("Using device type %s %s ", get_ft2232_vendorname(ft2232_vid, ft2232_type), get_ft2232_devicename(ft2232_vid, ft2232_type)); @@ -298,16 +313,16 @@ msg_pdbg("Set clock divisor\n"); buf[0] = 0x86; /* command "set divisor" */ /* valueL/valueH are (desired_divisor - 1) */ - buf[1] = (DIVIDE_BY - 1) & 0xff; - buf[2] = ((DIVIDE_BY - 1) >> 8) & 0xff; + buf[1] = (divider - 1) & 0xff; + buf[2] = ((divider - 1) >> 8) & 0xff; if (send_buf(ftdic, buf, 3)) { ret = -6; goto ftdi_err; }
msg_pdbg("MPSSE clock: %f MHz divisor: %d " - "SPI clock: %f MHz\n", mpsse_clk, DIVIDE_BY, - (double)(mpsse_clk / (((DIVIDE_BY - 1) + 1) * 2))); + "SPI clock: %f MHz\n", mpsse_clk, divider, + (double)(mpsse_clk / (((divider - 1) + 1) * 2)));
/* Disconnect TDI/DO to TDO/DI for loopback. */ msg_pdbg("No loopback of TDI/DO TDO/DI\n"); --
R, S
This adds an extra argument when using the ft2232_spi programmer to set the frequency divider. The valid values for the divider is any even integer between 2 and 131072.
Signed-off-by: Samir Ibradžić sibradzic@gmail.com Signed-off-by: Stefan Tauner stefan.tauner@student.tuwien.ac.at
--- this was totally broken even without Samir's version of the patch applied. it might be a better idea to let the user specify the actual frequency instead of the divisor like some other programmers do (serprog and buspirate). TODO: man page --- ft2232_spi.c | 54 +++++++++++++++++++++++++++++++++++++----------------- 1 files changed, 37 insertions(+), 17 deletions(-)
diff --git a/ft2232_spi.c b/ft2232_spi.c index 122866f..7d598b1 100644 --- a/ft2232_spi.c +++ b/ft2232_spi.c @@ -64,17 +64,8 @@ const struct usbdev_status devs_ft2232spi[] = { {}, };
-/* - * The 'H' chips can run internally at either 12MHz or 60MHz. - * The non-H chips can only run at 12MHz. - */ -static uint8_t clock_5x = 1;
-/* - * In either case, the divisor is a simple integer clock divider. - * If clock_5x is set, this divisor divides 30MHz, else it divides 6MHz. - */ -#define DIVIDE_BY 3 /* e.g. '3' will give either 10MHz or 2MHz SPI clock. */ +#define DEFAULT_DIVISOR 2
#define BITMODE_BITBANG_NORMAL 1 #define BITMODE_BITBANG_SPI 2 @@ -162,12 +153,28 @@ static const struct spi_programmer spi_programmer_ft2232 = { /* Returns 0 upon success, a negative number upon errors. */ int ft2232_spi_init(void) { - int f, ret = 0; + int ret = 0; struct ftdi_context *ftdic = &ftdic_context; unsigned char buf[512]; int ft2232_vid = FTDI_VID; int ft2232_type = FTDI_FT4232H_PID; enum ftdi_interface ft2232_interface = INTERFACE_B; + /* + * The 'H' chips can run with an internal clock of either 12 MHz or 60 MHz, + * but the non-H chips can only run at 12 MHz. We enable the divide-by-5 + * prescaler on the former to run on the same speed. + */ + uint8_t clock_5x = 1; + /* In addition to the prescaler mentioned above there is also another + * configurable one on all versions of the chips. Its divisor div can be + * set by a 16 bit value x according to the following formula: + * div = (1 + x) * 2 <-> x = div / 2 - 1 + * Hence the expressible divisors are all even numbers between 2 and + * 2^17 (=131072) resulting in SCK frequencies of 2 MHz down to about + * 92 Hz for 12 MHz inputs. + */ + uint32_t divisor = DEFAULT_DIVISOR; + int f; char *arg; double mpsse_clk;
@@ -243,6 +250,21 @@ int ft2232_spi_init(void) } } free(arg); + arg = extract_programmer_param("divisor"); + if (arg && strlen(arg)) { + unsigned int temp = 0; + char *endptr; + temp = strtoul(arg, &endptr, 10); + if (*endptr || temp < 2 || temp > 131072 || temp & 0x1) { + 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 { + divisor = (uint32_t)temp; + } + } + free(arg); msg_pdbg("Using device type %s %s ", get_ft2232_vendorname(ft2232_vid, ft2232_type), get_ft2232_devicename(ft2232_vid, ft2232_type)); @@ -303,17 +325,15 @@ int ft2232_spi_init(void)
msg_pdbg("Set clock divisor\n"); buf[0] = 0x86; /* command "set divisor" */ - /* valueL/valueH are (desired_divisor - 1) */ - buf[1] = (DIVIDE_BY - 1) & 0xff; - buf[2] = ((DIVIDE_BY - 1) >> 8) & 0xff; if (send_buf(ftdic, buf, 3)) { ret = -6; goto ftdi_err; } + buf[1] = (divisor / 2 - 1) & 0xff; + buf[2] = ((divisor / 2 - 1) >> 8) & 0xff;
- msg_pdbg("MPSSE clock: %f MHz divisor: %d " - "SPI clock: %f MHz\n", mpsse_clk, DIVIDE_BY, - (double)(mpsse_clk / (((DIVIDE_BY - 1) + 1) * 2))); + msg_pdbg("MPSSE clock: %f MHz, divisor: %u, SPI clock: %f MHz\n", + mpsse_clk, divisor, (double)(mpsse_clk / divisor));
/* Disconnect TDI/DO to TDO/DI for loopback. */ msg_pdbg("No loopback of TDI/DO TDO/DI\n");