David Hendricks has uploaded a new change for review. ( https://review.coreboot.org/19858 )
Change subject: dediprog: 4BA support ......................................................................
dediprog: 4BA support
This updates Dediprog code so that it can read/write the entire address space of large chips: - The ILength field in the read and write command packets is two bytes, so the max bulk transfer size is 0xffff packets which works out to be 32MB - 512 bytes. This patch breaks up very large bulk transfers as needed.
- The command spec only lists a few supported commands which can be used in 4BA mode. So this patch adds logic in the read and write functions which substitutes the opcode passed in from the caller with one can work.
Tested using SF600 and MX25L25635F.
Change-Id: Ia7a27c97bc736e6f3dc9a5c3b44b52270f638a8f Signed-off-by: David Hendricks dhendricks@fb.com --- M dediprog.c 1 file changed, 79 insertions(+), 17 deletions(-)
git pull ssh://review.coreboot.org:29418/flashrom refs/changes/58/19858/1
diff --git a/dediprog.c b/dediprog.c index 6f82772..a09a701 100644 --- a/dediprog.c +++ b/dediprog.c @@ -31,6 +31,7 @@ #include "chipdrivers.h" #include "programmer.h" #include "spi.h" +#include "spi4ba.h"
/* LIBUSB_CALL ensures the right calling conventions on libusb callbacks. * However, the macro is not defined everywhere. m( @@ -46,6 +47,10 @@ #define REQTYPE_OTHER_IN (LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_OTHER) /* 0xC3 */ #define REQTYPE_EP_OUT (LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_ENDPOINT) /* 0x42 */ #define REQTYPE_EP_IN (LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_ENDPOINT) /* 0xC2 */ + +/* ILength for bulk transfers is 2-bytes wide, value is in units if 512-bytes */ +#define MAX_BULK_XFER_SIZE (0xffff * 512) + struct libusb_context *usb_ctx; static libusb_device_handle *dediprog_handle; static int dediprog_in_endpoint; @@ -386,13 +391,13 @@ 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, uint8_t opcode, unsigned int *value, unsigned int *idx, unsigned int start) { /* First 5 bytes are common in both generations. */ data_packet[0] = count & 0xff; data_packet[1] = (count >> 8) & 0xff; data_packet[2] = 0; /* RFU */ 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 */ + data_packet[4] = opcode; /* Specs imply necessity only for READ_MODE_4B_ADDR_FAST and WRITE_MODE_4B_ADDR_256B_PAGE_PGM */
if (is_new_prot()) { *value = *idx = 0; @@ -408,11 +413,13 @@ }
/* Bulk read interface, will read multiple 512 byte chunks aligned to 512 bytes. - * @start start address - * @len length - * @return 0 on success, 1 on failure + * @start start address + * @len length + * @dedi_spi_cmd dediprog specific command for spi bus + * @opcode opcode to send to the chip + * @return 0 on success, 1 on failure */ -static int dediprog_spi_bulk_read(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len) +static int dediprog_spi_bulk_read(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len, uint8_t dedi_spi_cmd, uint8_t opcode) { int err = 1;
@@ -436,7 +443,7 @@ /* Command packet size of protocols: new 10 B, old 5 B. */ uint8_t data_packet[is_new_prot() ? 10 : 5]; unsigned int value, idx; - fill_rw_cmd_payload(data_packet, count, READ_MODE_STD, &value, &idx, start); + fill_rw_cmd_payload(data_packet, count, dedi_spi_cmd, opcode, &value, &idx, start);
int ret = dediprog_write(CMD_READ, value, idx, data_packet, sizeof(data_packet)); if (ret != sizeof(data_packet)) { @@ -504,6 +511,25 @@ const unsigned int chunksize = 0x200; unsigned int residue = start % chunksize ? chunksize - start % chunksize : 0; unsigned int bulklen; + uint8_t opcode = JEDEC_READ; + uint8_t dedi_spi_cmd = READ_MODE_STD; + + if (len == 0) + return 0; + + /* Programmer only supports a few 4BA read methods, adjust as needed */ + if (start + len - 1 >= 0x1000000) { + if (flash->chip->feature_bits & (FEATURE_4BA_ONLY | FEATURE_4BA_DIRECT_READ)) { + opcode = JEDEC_READ_4BA_DIRECT; + dedi_spi_cmd = READ_MODE_4B_ADDR_FAST_0x0C; + } else { + opcode = JEDEC_FAST_READ; + dedi_spi_cmd = READ_MODE_4B_ADDR_FAST; + } + } + + msg_pspew("%s: start: 0x%06x, len: 0x%06x, dediprog read command: 0x%02x, opcode: 0x%02x\n", + __func__, start, len, dedi_spi_cmd, opcode);
dediprog_set_leds(LED_BUSY);
@@ -517,9 +543,16 @@
/* Round down. */ bulklen = (len - residue) / chunksize * chunksize; - ret = dediprog_spi_bulk_read(flash, buf + residue, start + residue, bulklen); - if (ret) - goto err; + unsigned int bulklen_remaining = bulklen; + unsigned int offset = residue; + do { + unsigned int xfer_size = min(bulklen_remaining, MAX_BULK_XFER_SIZE); + ret = dediprog_spi_bulk_read(flash, buf + offset, start + offset, xfer_size, dedi_spi_cmd, opcode); + if (ret) + goto err; + offset += xfer_size; + bulklen_remaining -= xfer_size; + } while (bulklen_remaining);
len -= residue + bulklen; if (len != 0) { @@ -543,10 +576,11 @@ * @start start address * @len length * @dedi_spi_cmd dediprog specific write command for spi bus + * @opcode opcode to send to the chip * @return 0 on success, 1 on failure */ static int dediprog_spi_bulk_write(struct flashctx *flash, const uint8_t *buf, unsigned int chunksize, - unsigned int start, unsigned int len, uint8_t dedi_spi_cmd) + unsigned int start, unsigned int len, uint8_t dedi_spi_cmd, uint8_t opcode) { /* USB transfer size must be 512, other sizes will NOT work at all. * chunksize is the real data size per USB bulk transfer. The remaining @@ -578,7 +612,7 @@ /* Command packet size of protocols: new 10 B, old 5 B. */ uint8_t data_packet[is_new_prot() ? 10 : 5]; 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, 0, &value, &idx, start); 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)); @@ -609,8 +643,27 @@ const unsigned int chunksize = flash->chip->page_size; unsigned int residue = start % chunksize ? chunksize - start % chunksize : 0; unsigned int bulklen; + uint8_t opcode = JEDEC_BYTE_PROGRAM;
dediprog_set_leds(LED_BUSY); + + /* Programmer only supports a few 4BA write methods, adjust as needed */ + if (start + len - 1 >= 0x1000000) { + if (flash->chip->feature_bits & (FEATURE_4BA_ONLY | FEATURE_4BA_DIRECT_WRITE)) { + /* + * Warning: This failed on MX25L25635F with + * FEATURE_4BA_DIRECT_WRITE set as a feature bit. Needs + * more testing... + */ + opcode = JEDEC_BYTE_PROGRAM_4BA; + dedi_spi_cmd = WRITE_MODE_4B_ADDR_256B_PAGE_PGM_0x12; + } else { + dedi_spi_cmd = WRITE_MODE_4B_ADDR_256B_PAGE_PGM; + } + } + + msg_pspew("%s: start: 0x%06x, len: 0x%06x, dediprog write command: 0x%02x, opcode: 0x%02x\n", + __func__, start, len, dedi_spi_cmd, opcode);
if (chunksize != 256) { msg_pdbg("Page sizes other than 256 bytes are unsupported as " @@ -632,11 +685,19 @@
/* Round down. */ bulklen = (len - residue) / chunksize * chunksize; - ret = dediprog_spi_bulk_write(flash, buf + residue, chunksize, start + residue, bulklen, dedi_spi_cmd); - if (ret) { - dediprog_set_leds(LED_ERROR); - return ret; - } + unsigned int bulklen_remaining = bulklen; + unsigned int offset = residue; + do { + unsigned int xfer_size = min(bulklen_remaining, MAX_BULK_XFER_SIZE); + + ret = dediprog_spi_bulk_write(flash, buf + offset, chunksize, start + offset, xfer_size, dedi_spi_cmd, opcode); + if (ret) { + dediprog_set_leds(LED_ERROR); + return ret; + } + offset += xfer_size; + bulklen_remaining -= xfer_size; + } while (bulklen_remaining);
len -= residue + bulklen; if (len) { @@ -661,6 +722,7 @@
static int dediprog_spi_write_aai(struct flashctx *flash, const uint8_t *buf, unsigned int start, unsigned int len) { + /* FIXME: How to handle 4BA? */ return dediprog_spi_write(flash, buf, start, len, WRITE_MODE_2B_AAI); }