David Hendricks has submitted this change and it was merged. ( https://review.coreboot.org/23836 )
Change subject: dediprog: implement command spec for firmware >= 7.2.30 ......................................................................
dediprog: implement command spec for firmware >= 7.2.30
This adds support for the latest command spec for Dediprog SF100/SF600 programmers. Since we now have more than two protocols to deal with the is_new_prot() function is replaced with protocol() which returns an enum specifying which protocol is supported.
The latest spec (FW >= 7.2.30) updates read and write packets. It's been tested on an SF600 using firmware 7.2.21 and SF600Plus using FW 7.2.30.
The latest command protocol has a few small but important changes: - Read packets have two more bytes: 11: B4Addr: address len (3 or 4) 12: Dummy cycle /2
- Write packets have four more bytes: 11, 12: 16 HSBs of page size 13, 14: 16 LSBs of page size
(The spec seems to be mistaken, though, as 11 and 12 are actually LSBs instead of HSBs)
Change-Id: I1a53c143948ec40d40433621891a2871d8815f2f Signed-off-by: David Hendricks dhendricks@fb.com Reviewed-on: https://review.coreboot.org/23836 Tested-by: build bot (Jenkins) no-reply@coreboot.org Reviewed-by: Nico Huber nico.h@gmx.de --- M dediprog.c 1 file changed, 83 insertions(+), 18 deletions(-)
Approvals: build bot (Jenkins): Verified Nico Huber: Looks good to me, approved
diff --git a/dediprog.c b/dediprog.c index 2f5b441..146b3e7 100644 --- a/dediprog.c +++ b/dediprog.c @@ -144,6 +144,17 @@ LEAVE_STANDALONE_MODE = 1, };
+/* + * These are not official designations; they are for use in flashrom only. + * Order must be preserved so that comparison operators work. + */ +enum protocol { + PROTOCOL_UNKNOWN, + PROTOCOL_V1, + PROTOCOL_V2, + PROTOCOL_V3, +}; + const struct dev_entry devs_dediprog[] = { {0x0483, 0xDADA, OK, "Dediprog", "SF100/SF600"},
@@ -169,16 +180,24 @@ } #endif
-/* Returns true if firmware (and thus hardware) supports the "new" protocol */ -static bool is_new_prot(void) +static enum protocol protocol(void) { + /* Firmware version < 5.0.0 is handled explicitly in some cases. */ switch (dediprog_devicetype) { case DEV_SF100: - return dediprog_firmwareversion >= FIRMWARE_VERSION(5, 5, 0); + if (dediprog_firmwareversion < FIRMWARE_VERSION(5, 5, 0)) + return PROTOCOL_V1; + else + return PROTOCOL_V2; case DEV_SF600: - return dediprog_firmwareversion >= FIRMWARE_VERSION(6, 9, 0); + if (dediprog_firmwareversion < FIRMWARE_VERSION(6, 9, 0)) + return PROTOCOL_V1; + else if (dediprog_firmwareversion <= FIRMWARE_VERSION(7, 2, 21)) + return PROTOCOL_V2; + else + return PROTOCOL_V3; default: - return 0; + return PROTOCOL_UNKNOWN; } }
@@ -287,7 +306,7 @@ * FIXME: take IO pins into account */ int target_leds, ret; - if (is_new_prot()) { + if (protocol() >= PROTOCOL_V2) { target_leds = (leds ^ 7) << 8; ret = dediprog_write(CMD_SET_IO_LED, target_leds, 0, NULL, 0); } else { @@ -387,7 +406,8 @@ return 0; }
-static void fill_rw_cmd_payload(uint8_t *data_packet, unsigned int count, uint8_t dedi_spi_cmd, unsigned int *value, unsigned int *idx, unsigned int start) { +static void fill_rw_cmd_payload(uint8_t *data_packet, unsigned int count, uint8_t dedi_spi_cmd, + unsigned int *value, unsigned int *idx, unsigned int start, int is_read) { /* First 5 bytes are common in both generations. */ data_packet[0] = count & 0xff; data_packet[1] = (count >> 8) & 0xff; @@ -395,13 +415,26 @@ data_packet[3] = dedi_spi_cmd; /* Read/Write Mode (currently READ_MODE_STD, WRITE_MODE_PAGE_PGM or WRITE_MODE_2B_AAI) */ data_packet[4] = 0; /* "Opcode". Specs imply necessity only for READ_MODE_4B_ADDR_FAST and WRITE_MODE_4B_ADDR_256B_PAGE_PGM */
- if (is_new_prot()) { + if (protocol() >= PROTOCOL_V2) { *value = *idx = 0; data_packet[5] = 0; /* RFU */ data_packet[6] = (start >> 0) & 0xff; data_packet[7] = (start >> 8) & 0xff; data_packet[8] = (start >> 16) & 0xff; data_packet[9] = (start >> 24) & 0xff; + if (protocol() >= PROTOCOL_V3) { + if (is_read) { + data_packet[10] = 0x00; /* address length (3 or 4) */ + data_packet[11] = 0x00; /* dummy cycle / 2 */ + } else { + /* 16 LSBs and 16 HSBs of page size */ + /* FIXME: This assumes page size of 256. */ + data_packet[10] = 0x00; + data_packet[11] = 0x01; + data_packet[12] = 0x00; + data_packet[13] = 0x00; + } + } } else { *value = start % 0x10000; *idx = start / 0x10000; @@ -434,10 +467,24 @@ if (len == 0) return 0;
- /* Command packet size of protocols: new 10 B, old 5 B. */ - uint8_t data_packet[is_new_prot() ? 10 : 5]; + int command_packet_size; + switch (protocol()) { + case PROTOCOL_V1: + command_packet_size = 5; + break; + case PROTOCOL_V2: + command_packet_size = 10; + break; + case PROTOCOL_V3: + command_packet_size = 12; + break; + default: + return 1; + } + + uint8_t data_packet[command_packet_size]; unsigned int value, idx; - fill_rw_cmd_payload(data_packet, count, READ_MODE_STD, &value, &idx, start); + fill_rw_cmd_payload(data_packet, count, READ_MODE_STD, &value, &idx, start, 1);
int ret = dediprog_write(CMD_READ, value, idx, data_packet, sizeof(data_packet)); if (ret != sizeof(data_packet)) { @@ -576,10 +623,24 @@ if (len == 0) return 0;
- /* Command packet size of protocols: new 10 B, old 5 B. */ - uint8_t data_packet[is_new_prot() ? 10 : 5]; + int command_packet_size; + switch (protocol()) { + case PROTOCOL_V1: + command_packet_size = 5; + break; + case PROTOCOL_V2: + command_packet_size = 10; + break; + case PROTOCOL_V3: + command_packet_size = 14; + break; + default: + return 1; + } + + uint8_t data_packet[command_packet_size]; unsigned int value, idx; - fill_rw_cmd_payload(data_packet, count, dedi_spi_cmd, &value, &idx, start); + fill_rw_cmd_payload(data_packet, count, dedi_spi_cmd, &value, &idx, start, 0); int ret = dediprog_write(CMD_WRITE, value, idx, data_packet, sizeof(data_packet)); if (ret != sizeof(data_packet)) { msg_perr("Command Write SPI Bulk failed, %s!\n", libusb_error_name(ret)); @@ -686,7 +747,7 @@ unsigned int idx, value; /* New protocol has options and timeout combined as value while the old one used the value field for * timeout and the index field for options. */ - if (is_new_prot()) { + if (protocol() >= PROTOCOL_V2) { idx = 0; value = readcnt ? 0x1 : 0x0; // Indicate if we require a read } else { @@ -711,7 +772,7 @@ * The specification also uses only 0 in its examples, so the lesson to learn here: * "Never trust the description of an interface in the documentation but use the example code and pray." const uint8_t read_timeout = 10 + readcnt/512; - if (is_new_prot()) { + if (protocol() >= PROTOCOL_V2) { idx = 0; value = min(read_timeout, 0xFF) | (0 << 8) ; // Timeout in lower byte, option in upper byte } else { @@ -762,7 +823,12 @@ 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]); + if (protocol() == PROTOCOL_UNKNOWN) { + msg_perr("Internal error: Unable to determine protocol version.\n"); + return 1; + }
return 0; } @@ -922,7 +988,6 @@
static int dediprog_shutdown(void *data) { - dediprog_firmwareversion = FIRMWARE_VERSION(0, 0, 0); dediprog_devicetype = DEV_UNKNOWN;
/* URB 28. Command Set SPI Voltage to 0. */ @@ -1083,7 +1148,7 @@
/* Set all possible LEDs as soon as possible to indicate activity. * Because knowing the firmware version is required to set the LEDs correctly we need to this after - * dediprog_check_devicestring() has queried the device and set dediprog_firmwareversion. */ + * dediprog_check_devicestring() has queried the device. */ dediprog_set_leds(LED_ALL);
/* Select target/socket, frequency and VCC. */