v2 changes: * Major v1 bug fixed: Partial reads and writes are now supported. Read, Erase, Write tested up to 8MiB on Winbond W25Q64BV part. * Trivial v1 bug fixed: Block and Sector erase commands functional (previously only Chip Erase commands were functional).
Signed-off-by: Pablo Cases <pablo.cases at flatfrog.com>
Index: dediprog.c =================================================================== --- dediprog.c (revision 1846) +++ dediprog.c (working copy) @@ -101,8 +101,13 @@ target_leds = leds; }
- ret = usb_control_msg(dediprog_handle, 0x42, 0x07, 0x09, target_leds, + if (dediprog_firmwareversion >= FIRMWARE_VERSION(5,5,1)) + ret = usb_control_msg(dediprog_handle, 0x42, 0x07, (target_leds << 8) | 0x09, 0x0, NULL, 0x0, DEFAULT_TIMEOUT); + else + ret = usb_control_msg(dediprog_handle, 0x42, 0x07, 0x09, target_leds, + NULL, 0x0, DEFAULT_TIMEOUT); + if (ret != 0x0) { msg_perr("Command Set LED 0x%x failed (%s)!\n", leds, usb_strerror()); @@ -216,8 +221,28 @@ const char count_and_chunk[] = {count & 0xff, (count >> 8) & 0xff, chunksize & 0xff, - (chunksize >> 8) & 0xff}; + (chunksize >> 8) & 0xff, + 0xff, + 0x00, + (start % 0x10000) & 0xff, + ((start % 0x10000) >> 8) & 0xff, + (start / 0x10000) & 0xff, + ((start / 0x10000) >> 8) & 0xff}; + unsigned int count_and_chunk_size;
+ /* Reverse engineering note: + * ======================== + * Omitting the added 6 bytes to count_and_chunk[] on SF100 FW 5.5.1 + * results in SF100 to incorrectly issue 0x0B (Fast Read) command with + * start at SPI address 0xF30000 instead of the expected address 0x0. + * (On a 8MiB W25Q64.V chip this wraps around to physical address 0x730000). + * Possibly a result of SF100 FW 5.5.1 receive data buffer initialization. + */ + if (dediprog_firmwareversion >= FIRMWARE_VERSION(5,5,1)) + count_and_chunk_size = 10; + else + count_and_chunk_size = 4; + if ((start % chunksize) || (len % chunksize)) { msg_perr("%s: Unaligned start=%i, len=%i! Please report a bug " "at flashrom@flashrom.org\n", __func__, start, len); @@ -230,10 +255,15 @@ /* Command Read SPI Bulk. No idea which read command is used on the * SPI side. */ - ret = usb_control_msg(dediprog_handle, 0x42, 0x20, start % 0x10000, + if (dediprog_firmwareversion >= FIRMWARE_VERSION(5,5,1)) + ret = usb_control_msg(dediprog_handle, 0x42, 0x20, 0x00, + 0x00, (char *)count_and_chunk, + count_and_chunk_size, DEFAULT_TIMEOUT); + else + ret = usb_control_msg(dediprog_handle, 0x42, 0x20, start % 0x10000, start / 0x10000, (char *)count_and_chunk, - sizeof(count_and_chunk), DEFAULT_TIMEOUT); - if (ret != sizeof(count_and_chunk)) { + count_and_chunk_size, DEFAULT_TIMEOUT); + if (ret != count_and_chunk_size) { msg_perr("Command Read SPI Bulk failed, %i %s!\n", ret, usb_strerror()); return 1; @@ -316,9 +346,37 @@ * space in a USB bulk transfer must be filled with 0xff padding. */ const unsigned int count = len / chunksize; - const char count_and_cmd[] = {count & 0xff, (count >> 8) & 0xff, 0x00, dedi_spi_cmd}; + const char count_and_cmd[] = {count & 0xff, + (count >> 8) & 0xff, + 0x00, + dedi_spi_cmd, + 0xff, + 0x00, + (start % 0x10000) & 0xff, + ((start % 0x10000) >> 8) & 0xff, + (start / 0x10000) & 0xff, + ((start / 0x10000) >> 8) & 0xff}; + unsigned int count_and_cmd_size; char usbbuf[512]; - + + /* Reverse engineering note: + * ======================== + * Omitting the added 6 bytes to count_and_cmd[] on SF100 FW 5.5.1 + * results in SF100 to incorrectly issue 0x02 (Page Program) command with + * start at SPI address 0xF30000 instead of the expected address 0x0. + * (On a 8MiB W25Q64.V chip this wraps around to physical address 0x730000). + * Possibly a result of SF100 FW 5.5.1 receive data buffer initialization. + * + * Issuing a single spi_bulk_write() command with this appendage will + * correct the addressing so that all further spi_bulk_write() commands + * (with or without the appendage) will start at SPI address 0x0. + * Only a power cycle of the SF100 will reintroduce the error. + */ + if (dediprog_firmwareversion >= FIRMWARE_VERSION(5,5,1)) + count_and_cmd_size = 10; + else + count_and_cmd_size = 4; + /* * We should change this check to * chunksize > 512 @@ -342,9 +400,13 @@ /* Command Write SPI Bulk. No idea which write command is used on the * SPI side. */ - ret = usb_control_msg(dediprog_handle, 0x42, 0x30, start % 0x10000, start / 0x10000, - (char *)count_and_cmd, sizeof(count_and_cmd), DEFAULT_TIMEOUT); - if (ret != sizeof(count_and_cmd)) { + if (dediprog_firmwareversion >= FIRMWARE_VERSION(5,5,1)) + ret = usb_control_msg(dediprog_handle, 0x42, 0x30, 0x00, 0x00, + (char *)count_and_cmd, count_and_cmd_size, DEFAULT_TIMEOUT); + else + ret = usb_control_msg(dediprog_handle, 0x42, 0x30, start % 0x10000, start / 0x10000, + (char *)count_and_cmd, count_and_cmd_size, DEFAULT_TIMEOUT); + if (ret != count_and_cmd_size) { msg_perr("Command Write SPI Bulk failed, %i %s!\n", ret, usb_strerror()); return 1; @@ -447,10 +509,28 @@ msg_perr("Untested readcnt=%i, aborting.\n", readcnt); return 1; } - - ret = usb_control_msg(dediprog_handle, 0x42, 0x1, 0xff, - readcnt ? 0x1 : 0x0, (char *)writearr, writecnt, - DEFAULT_TIMEOUT); + + if (dediprog_firmwareversion >= FIRMWARE_VERSION(5,5,1)) + if (*writearr == 0x6 || // Write Enable + *writearr == 0x60 || *writearr == 0xc7 || // Chip Erase + *writearr == 0x52 || *writearr == 0xd8 || // Block Erase + *writearr == 0x20) // Sector Erase + /* These commands are treated differently otherwise + * Read Status Register-1 (05h) will return incorrect + * results for WEL and WIP bits + * (at least on Winbond W25Q64BV Flash) + */ + ret = usb_control_msg(dediprog_handle, 0x42, 0x1, 0x0, + 0x0, (char *)writearr, writecnt, + DEFAULT_TIMEOUT); + else + ret = usb_control_msg(dediprog_handle, 0x42, 0x1, 0x1, + 0x0, (char *)writearr, writecnt, + DEFAULT_TIMEOUT); + else + ret = usb_control_msg(dediprog_handle, 0x42, 0x1, 0xff, + readcnt ? 0x1 : 0x0, (char *)writearr, writecnt, + DEFAULT_TIMEOUT); if (ret != writecnt) { msg_perr("Send SPI failed, expected %i, got %i %s!\n", writecnt, ret, usb_strerror()); @@ -459,8 +539,13 @@ if (!readcnt) return 0; memset(readarr, 0, readcnt); - ret = usb_control_msg(dediprog_handle, 0xc2, 0x01, 0xbb8, 0x0000, - (char *)readarr, readcnt, DEFAULT_TIMEOUT); + + if (dediprog_firmwareversion >= FIRMWARE_VERSION(5,5,1)) + ret = usb_control_msg(dediprog_handle, 0xc2, 0x1, 0x1, 0x0, + (char *)readarr, readcnt, DEFAULT_TIMEOUT); + else + ret = usb_control_msg(dediprog_handle, 0xc2, 0x1, 0xbb8, 0x0000, + (char *)readarr, readcnt, DEFAULT_TIMEOUT); if (ret != readcnt) { msg_perr("Receive SPI failed, expected %i, got %i %s!\n", readcnt, ret, usb_strerror()); @@ -485,6 +570,12 @@ " String!\n"); return 1; } + /* Reverse engineering note: + * ======================== + * Dediprog Software SF6.0.4.33 application sends the devicestring + * command with wValue and wIndex values of 0x0 instead of 0xff. + * Both commands yield the same result, so nothing is changed for now. + */ /* Command Receive Device String. */ memset(buf, 0, sizeof(buf)); ret = usb_control_msg(dediprog_handle, 0xc2, 0x8, 0xff, 0xff, buf,