Second revision:
This adds a programmer parameter 'spispeed' to the dediprog driver to control the transfer rate on the spi bus. The following rates are available (in Hz): 375k, 750k, 1.5M, 2.18M, 3M, 8M, 12M and 24M
The original driver reinitializes the programmer after setting the speed, so the initialization calls have moved into a new function dediprog_setup() which is called twice.
Signed-off-by: Nico Huber nico.huber@secunet.com
Index: dediprog.c =================================================================== --- dediprog.c (Revision 1596) +++ dediprog.c (Arbeitskopie) @@ -152,7 +152,23 @@ return 0; }
-#if 0 +struct dediprog_spispeeds { + const char *const name; + const int speed; +}; + +static const struct dediprog_spispeeds spispeeds[] = { + { "24M", 0x0 }, + { "12M", 0x2 }, + { "8M", 0x1 }, + { "3M", 0x3 }, + { "2.18M", 0x4 }, + { "1.5M", 0x5 }, + { "750k", 0x6 }, + { "375k", 0x7 }, + { NULL, 0x0 }, +}; + /* After dediprog_set_spi_speed, the original app always calls * dediprog_set_spi_voltage(0) and then * dediprog_check_devicestring() four times in a row. @@ -160,56 +176,20 @@ * This looks suspiciously like the microprocessor in the SF100 has to be * restarted/reinitialized in case the speed changes. */ -static int dediprog_set_spi_speed(uint16_t speed) +static int dediprog_set_spi_speed(unsigned int spispeed_idx) { int ret; - unsigned int khz;
- /* Case 1 and 2 are in weird order. Probably an organically "grown" - * interface. - * Base frequency is 24000 kHz, divisors are (in order) - * 1, 3, 2, 8, 11, 16, 32, 64. - */ - switch (speed) { - case 0x0: - khz = 24000; - break; - case 0x1: - khz = 8000; - break; - case 0x2: - khz = 12000; - break; - case 0x3: - khz = 3000; - break; - case 0x4: - khz = 2180; - break; - case 0x5: - khz = 1500; - break; - case 0x6: - khz = 750; - break; - case 0x7: - khz = 375; - break; - default: - msg_perr("Unknown frequency selector 0x%x! Aborting.\n", speed); - return 1; - } - msg_pdbg("Setting SPI speed to %u kHz\n", khz); + msg_pdbg("SPI speed is %sHz\n", spispeeds[spispeed_idx].name);
- ret = usb_control_msg(dediprog_handle, 0x42, 0x61, speed, 0xff, NULL, - 0x0, DEFAULT_TIMEOUT); + ret = usb_control_msg(dediprog_handle, 0x42, 0x61, spispeeds[spispeed_idx].speed, 0xff, + NULL, 0x0, DEFAULT_TIMEOUT); if (ret != 0x0) { - msg_perr("Command Set SPI Speed 0x%x failed!\n", speed); + msg_perr("Command Set SPI Speed 0x%x failed!\n", spispeeds[spispeed_idx].speed); return 1; } return 0; } -#endif
/* Bulk read interface, will read multiple 512 byte chunks aligned to 512 bytes. * @start start address @@ -736,6 +716,28 @@ return millivolt; }
+static int dediprog_setup(void) +{ + /* URB 6. Command A. */ + if (dediprog_command_a()) { + return 1; + } + /* URB 7. Command A. */ + if (dediprog_command_a()) { + return 1; + } + /* URB 8. Command Prepare Receive Device String. */ + /* URB 9. Command Receive Device String. */ + if (dediprog_check_devicestring()) { + return 1; + } + /* URB 10. Command C. */ + if (dediprog_command_c()) { + return 1; + } + return 0; +} + static const struct spi_programmer spi_programmer_dediprog = { .type = SPI_CONTROLLER_DEDIPROG, .max_data_read = MAX_DATA_UNSPECIFIED, @@ -777,12 +779,21 @@ int dediprog_init(void) { struct usb_device *dev; - char *voltage; - int millivolt = 3500; - int ret; + char *voltage, *spispeed; + int spispeed_idx = 2, millivolt = 3500; + int i, ret;
msg_pspew("%s\n", __func__);
+ spispeed = extract_programmer_param("spispeed"); + if (spispeed) { + for (i = 0; spispeeds[i].name; ++i) { + if (!strcasecmp(spispeeds[i].name, spispeed)) { + spispeed_idx = i; + break; + } + } + } voltage = extract_programmer_param("voltage"); if (voltage) { millivolt = parse_voltage(voltage); @@ -821,33 +832,26 @@ return 1; } dediprog_endpoint = 2; - + if (register_shutdown(dediprog_shutdown, NULL)) return 1;
dediprog_set_leds(PASS_ON|BUSY_ON|ERROR_ON);
- /* URB 6. Command A. */ - if (dediprog_command_a()) { + /* Perform basic setup. */ + if (dediprog_setup()) { dediprog_set_leds(PASS_OFF|BUSY_OFF|ERROR_ON); return 1; } - /* URB 7. Command A. */ - if (dediprog_command_a()) { + + /* After setting voltage and speed, perform setup again. */ + if (dediprog_set_spi_voltage(0) || + dediprog_set_spi_speed(spispeed_idx) || + dediprog_setup()) { dediprog_set_leds(PASS_OFF|BUSY_OFF|ERROR_ON); return 1; } - /* URB 8. Command Prepare Receive Device String. */ - /* URB 9. Command Receive Device String. */ - if (dediprog_check_devicestring()) { - dediprog_set_leds(PASS_OFF|BUSY_OFF|ERROR_ON); - return 1; - } - /* URB 10. Command C. */ - if (dediprog_command_c()) { - dediprog_set_leds(PASS_OFF|BUSY_OFF|ERROR_ON); - return 1; - } + /* URB 11. Command Set SPI Voltage. */ if (dediprog_set_spi_voltage(millivolt)) { dediprog_set_leds(PASS_OFF|BUSY_OFF|ERROR_ON); Index: flashrom.8 =================================================================== --- flashrom.8 (Revision 1596) +++ flashrom.8 (Arbeitskopie) @@ -641,6 +641,18 @@ can be .BR 0V ", " 1.8V ", " 2.5V ", " 3.5V or the equivalent in mV. +.sp +An optional +.B spispeed +parameter specifies the frequency of the SPI bus. Syntax is +.sp +.B " flashrom -p dediprog:spispeed=frequency" +.sp +where +.B frequency +can be +.BR 375k ", " 750k ", " 1.5M ", " 2.18M ", " 3M ", " 8M ", " 12M " or " 24M +(in Hz). The default is a frequency of 12 MHz. .SS .BR "rayer_spi " programmer The default I/O base address used for the parallel port is 0x378 and you can use