On Sun, 2015-07-05 at 19:09 +0200, Stefan Tauner wrote:
On Sun, 28 Jun 2015 16:52:51 -0700 David Hendricks david.hendricks@gmail.com wrote:
Sounds good to me.
Acked-by: David Hendricks dhendrix@chromium.org
Thanks, r1896.
Here's an updated version of the next patch in the sequence. I've tested this with an SF100 V:5.2.00 and a Winbind W25Q128.V in an Intel Skylake board, and it seems to be working.
Have we now resolved the issue discussed at http://www.flashrom.org/pipermail/flashrom/2013-June/011074.html which was preventing us from enabling dediprog (SF100) support by default?
----- From: Stefan Tauner stefan.tauner@alumni.tuwien.ac.at Date: Mon, 22 Jun 2015 03:37:23 +0200 Subject: [PATCH] dediprog: Support new communication protocol.
There are some changed commands, so adjust the code to support these. Use helper functions to reduce duplication in libusb calls.
Based on the following chromiumos change: Change-Id: Ibd1e27d9e8273ba879b9b5d95675b99596255c89
Signed-off-by: Simon Glass sjg@chromium.org Signed-off-by: Stefan Tauner stefan.tauner@alumni.tuwien.ac.at --- dediprog.c | 125 +++++++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 84 insertions(+), 41 deletions(-)
diff --git a/dediprog.c b/dediprog.c index 996d2d7..7ccac12 100644 --- a/dediprog.c +++ b/dediprog.c @@ -141,6 +141,27 @@ static void print_hex(void *buf, size_t len) } #endif
+/* Returns true if firmware (and thus hardware) supports the "new" protocol */ +static bool is_new_prot(void) +{ + /* if (SF100) */ + return dediprog_firmwareversion >= FIRMWARE_VERSION(5, 5, 0); + /* else if (SF600) + return dediprog_firmwareversion >= FIRMWARE_VERSION(6, 9, 0); */ +} + +static int dediprog_read(enum dediprog_cmds cmd, unsigned int value, unsigned int idx, uint8_t *bytes, size_t size) +{ + return usb_control_msg(dediprog_handle, REQTYPE_EP_IN, cmd, value, idx, + (char *)bytes, size, DEFAULT_TIMEOUT); +} + +static int dediprog_write(enum dediprog_cmds cmd, unsigned int value, unsigned int idx, const uint8_t *bytes, size_t size) +{ + return usb_control_msg(dediprog_handle, REQTYPE_EP_OUT, cmd, value, idx, + (char *)bytes, size, DEFAULT_TIMEOUT); +} + /* Might be useful for other USB devices as well. static for now. */ /* device parameter allows user to specify one device of multiple installed */ static struct usb_device *get_device_by_vid_pid(uint16_t vid, uint16_t pid, unsigned int device) @@ -166,24 +187,30 @@ static int dediprog_set_leds(int leds) if (leds < LED_NONE || leds > LED_ALL) leds = LED_ALL;
- /* Older Dediprogs with 2.x.x and 3.x.x firmware only had - * two LEDs, and they were reversed. So map them around if - * we have an old device. On those devices the LEDs map as - * follows: + /* Older Dediprogs with 2.x.x and 3.x.x firmware only had two LEDs, assigned to different bits. So map + * them around if we have an old device. On those devices the LEDs map as follows: * bit 2 == 0: green light is on. - * bit 0 == 0: red light is on. + * bit 0 == 0: red light is on. + * + * Additionally, the command structure has changed with the "new" protocol. + * + * FIXME: take IO pins into account */ - int target_leds; - if (dediprog_firmwareversion < FIRMWARE_VERSION(5,0,0)) { - target_leds = ((leds & LED_ERROR) >> 2) | - ((leds & LED_PASS) << 2); + int target_leds, ret; + if (is_new_prot()) { + target_leds = (leds ^ 7) << 8; + ret = dediprog_write(CMD_SET_IO_LED, target_leds, 0, NULL, 0); } else { - target_leds = leds; + if (dediprog_firmwareversion < FIRMWARE_VERSION(5, 0, 0)) { + target_leds = ((leds & LED_ERROR) >> 2) | ((leds & LED_PASS) << 2); + } else { + target_leds = leds; + } + target_leds ^= 7; + + ret = dediprog_write(CMD_SET_IO_LED, 0x9, target_leds, NULL, 0); }
- target_leds ^= 7; - int ret = usb_control_msg(dediprog_handle, REQTYPE_EP_OUT, CMD_SET_IO_LED, 0x09, target_leds, - NULL, 0x0, DEFAULT_TIMEOUT); if (ret != 0x0) { msg_perr("Command Set LED 0x%x failed (%s)!\n", leds, usb_strerror()); return 1; @@ -222,8 +249,7 @@ static int dediprog_set_spi_voltage(int millivolt) /* Wait some time as the original driver does. */ programmer_delay(200 * 1000); } - ret = usb_control_msg(dediprog_handle, REQTYPE_EP_OUT, CMD_SET_VCC, voltage_selector, 0, - NULL, 0x0, DEFAULT_TIMEOUT); + ret = dediprog_write(CMD_SET_VCC, voltage_selector, 0, NULL, 0); if (ret != 0x0) { msg_perr("Command Set SPI Voltage 0x%x failed!\n", voltage_selector); @@ -263,8 +289,7 @@ static int dediprog_set_spi_speed(unsigned int spispeed_idx) const struct dediprog_spispeeds *spispeed = &spispeeds[spispeed_idx]; msg_pdbg("SPI speed is %sHz\n", spispeed->name);
- int ret = usb_control_msg(dediprog_handle, REQTYPE_EP_OUT, CMD_SET_SPI_CLK, spispeed->speed, 0xff, - NULL, 0x0, DEFAULT_TIMEOUT); + int ret = dediprog_write(CMD_SET_SPI_CLK, spispeed->speed, 0, NULL, 0); if (ret != 0x0) { msg_perr("Command Set SPI Speed 0x%x failed!\n", spispeed->speed); return 1; @@ -285,10 +310,7 @@ static int dediprog_spi_bulk_read(struct flashctx *flash, uint8_t *buf, /* chunksize must be 512, other sizes will NOT work at all. */ const unsigned int chunksize = 0x200; const unsigned int count = len / chunksize; - const char count_and_chunk[] = {count & 0xff, - (count >> 8) & 0xff, - chunksize & 0xff, - (chunksize >> 8) & 0xff}; + unsigned int cmd_len;
if ((start % chunksize) || (len % chunksize)) { msg_perr("%s: Unaligned start=%i, len=%i! Please report a bug " @@ -299,15 +321,34 @@ static int dediprog_spi_bulk_read(struct flashctx *flash, uint8_t *buf, /* No idea if the hardware can handle empty reads, so chicken out. */ if (!len) return 0; - /* Command Read SPI Bulk. No idea which read command is used on the - * SPI side. - */ - ret = usb_control_msg(dediprog_handle, REQTYPE_EP_OUT, CMD_READ, start % 0x10000, - start / 0x10000, (char *)count_and_chunk, - sizeof(count_and_chunk), DEFAULT_TIMEOUT); - if (ret != sizeof(count_and_chunk)) { - msg_perr("Command Read SPI Bulk failed, %i %s!\n", ret, - usb_strerror()); + /* Command Read SPI Bulk. */ + if (is_new_prot()) { + const uint8_t read_cmd[] = { + count & 0xff, + (count >> 8) & 0xff, + 0, + READ_MODE_FAST, + 0, + 0, + start & 0xff, + (start >> 8) & 0xff, + (start >> 16) & 0xff, + (start >> 24) & 0xff, + }; + + cmd_len = sizeof(read_cmd); + ret = dediprog_write(CMD_READ, 0, 0, read_cmd, cmd_len); + } else { + const uint8_t read_cmd[] = {count & 0xff, + (count >> 8) & 0xff, + chunksize & 0xff, + (chunksize >> 8) & 0xff}; + + cmd_len = sizeof(read_cmd); + ret = dediprog_write(CMD_READ, start % 0x10000, start / 0x10000, read_cmd, cmd_len); + } + if (ret != cmd_len) { + msg_perr("Command Read SPI Bulk failed, %i %s!\n", ret, usb_strerror()); return 1; }
@@ -515,8 +556,12 @@ static int dediprog_spi_send_command(struct flashctx *flash, return 1; } - ret = usb_control_msg(dediprog_handle, REQTYPE_EP_OUT, CMD_TRANSCEIVE, 0, readcnt ? 0x1 : 0x0, - (char *)writearr, writecnt, DEFAULT_TIMEOUT); + /* New protocol has the read flag as value while the old protocol had it in the index field. */ + if (is_new_prot()) { + ret = dediprog_write(CMD_TRANSCEIVE, readcnt ? 1 : 0, 0, writearr, writecnt); + } else { + ret = dediprog_write(CMD_TRANSCEIVE, 0, readcnt ? 1 : 0, writearr, writecnt); + } if (ret != writecnt) { msg_perr("Send SPI failed, expected %i, got %i %s!\n", writecnt, ret, usb_strerror()); @@ -525,8 +570,7 @@ static int dediprog_spi_send_command(struct flashctx *flash, if (readcnt == 0) return 0;
- ret = usb_control_msg(dediprog_handle, REQTYPE_EP_IN, CMD_TRANSCEIVE, 0, 0, - (char *)readarr, readcnt, DEFAULT_TIMEOUT); + ret = dediprog_read(CMD_TRANSCEIVE, 0, 0, readarr, readcnt); if (ret != readcnt) { msg_perr("Receive SPI failed, expected %i, got %i %s!\n", readcnt, ret, usb_strerror()); @@ -553,8 +597,7 @@ static int dediprog_check_devicestring(void) } #endif /* Command Receive Device String. */ - ret = usb_control_msg(dediprog_handle, REQTYPE_EP_IN, CMD_READ_PROG_INFO, 0, 0, - buf, 0x10, DEFAULT_TIMEOUT); + ret = dediprog_read(CMD_READ_PROG_INFO, 0, 0, (uint8_t *)buf, 0x10); if (ret != 0x10) { msg_perr("Incomplete/failed Command Receive Device String!\n"); return 1; @@ -566,16 +609,16 @@ static int dediprog_check_devicestring(void) return 1; } if (sscanf(buf, "SF100 V:%d.%d.%d ", &fw[0], &fw[1], &fw[2]) != 3) { - msg_perr("Unexpected firmware version string!\n"); + msg_perr("Unexpected firmware version string '%s'\n", buf); return 1; } - /* Only these versions were tested. */ - if (fw[0] < 2 || fw[0] > 5) { - msg_perr("Unexpected firmware version %d.%d.%d!\n", fw[0], - fw[1], fw[2]); + /* Only these major versions were tested. */ + if (fw[0] < 2 || fw[0] > 6) { + msg_perr("Unexpected firmware version %d.%d.%d!\n", fw[0], fw[1], fw[2]); return 1; } dediprog_firmwareversion = FIRMWARE_VERSION(fw[0], fw[1], fw[2]); + return 0; }