Nico Huber has uploaded this change for review. ( https://review.coreboot.org/28804
Change subject: [WIP]dediprog: Implement 4-byte-address support ......................................................................
[WIP]dediprog: Implement 4-byte-address support
Assumes the V1 protocol can't handle 4BAs at all. 4BA AAI chips won't be handled well for V2+ protocols (but haven't seen any such chips so far). Completely untested.
Change-Id: I665d0806aec469a3509620a760815861fbe22841 Signed-off-by: Nico Huber nico.h@gmx.de --- M chipdrivers.h M dediprog.c M spi.h M spi25.c 4 files changed, 75 insertions(+), 12 deletions(-)
git pull ssh://review.coreboot.org:29418/flashrom refs/changes/04/28804/1
diff --git a/chipdrivers.h b/chipdrivers.h index 134ed26..27b151c 100644 --- a/chipdrivers.h +++ b/chipdrivers.h @@ -56,6 +56,7 @@ int spi_nbyte_read(struct flashctx *flash, unsigned int addr, uint8_t *bytes, unsigned int len); int spi_read_chunked(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len, unsigned int chunksize); int spi_write_chunked(struct flashctx *flash, const uint8_t *buf, unsigned int start, unsigned int len, unsigned int chunksize); +int spi_set_extended_address(struct flashctx *flash, uint8_t addr_high); int spi_enter_4ba(struct flashctx *flash); int spi_exit_4ba(struct flashctx *flash);
diff --git a/dediprog.c b/dediprog.c index 1a469a7..b769b5e 100644 --- a/dediprog.c +++ b/dediprog.c @@ -358,8 +358,22 @@ 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, int is_read) { +static int prepare_ext_addr(struct flashctx *const flash, const unsigned int start) +{ + if (flash->chip->feature_bits & FEATURE_4BA_EXT_ADDR) { + if (spi_set_extended_address(flash, start >> 24)) + return 1; + } else if (start >> 24) { + msg_perr("Can't handle 4-byte address for this chip.\n"); + return 1; + } + + return 0; +} + +static int prepare_rw_cmd( + struct flashctx *const flash, 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; @@ -368,15 +382,47 @@ data_packet[4] = 0; /* "Opcode". Specs imply necessity only for READ_MODE_4B_ADDR_FAST and WRITE_MODE_4B_ADDR_256B_PAGE_PGM */
if (protocol() >= PROTOCOL_V2) { + bool use_4ba = false; + if (is_read) { + if (flash->chip->feature_bits & FEATURE_4BA_FAST_READ) { + data_packet[3] = READ_MODE_4B_ADDR_FAST_0x0C; + data_packet[4] = JEDEC_READ_4BA_FAST; + use_4ba = true; + } else if (flash->in_4ba_mode) { + /* FIXME: Chip database should indicate support. */ + data_packet[3] = READ_MODE_4B_ADDR_FAST; + data_packet[4] = JEDEC_READ_FAST; + use_4ba = true; + } + } else if (dedi_spi_cmd == WRITE_MODE_PAGE_PGM) { + if (flash->chip->feature_bits & FEATURE_4BA_WRITE) { + data_packet[3] = WRITE_MODE_4B_ADDR_256B_PAGE_PGM_0x12; + data_packet[4] = JEDEC_BYTE_PROGRAM_4BA; + use_4ba = true; + } else if (flash->in_4ba_mode) { + data_packet[3] = WRITE_MODE_4B_ADDR_256B_PAGE_PGM; + data_packet[4] = JEDEC_BYTE_PROGRAM; + use_4ba = true; + } + } else if (dedi_spi_cmd == WRITE_MODE_2B_AAI) { + if (flash->in_4ba_mode) { + msg_perr("Can't handle 4-byte address for AAI command.\n"); + return 1; + } + } + if (!use_4ba && prepare_ext_addr(flash, start)) + return 1; + *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; + data_packet[9] = use_4ba ? (start >> 24) & 0xff : 0; if (protocol() >= PROTOCOL_V3) { if (is_read) { - data_packet[10] = 0x00; /* address length (3 or 4) */ + /* address length (3 or 4), encoding guessed */ + data_packet[10] = use_4ba ? 0x01 : 0x00; data_packet[11] = 0x00; /* dummy cycle / 2 */ } else { /* 16 LSBs and 16 HSBs of page size */ @@ -388,9 +434,13 @@ } } } else { - *value = start % 0x10000; - *idx = start / 0x10000; + if (prepare_ext_addr(flash, start)) + return 1; + *value = start & 0xffff; + *idx = start >> 16 & 0xff; } + + return 0; }
/* Bulk read interface, will read multiple 512 byte chunks aligned to 512 bytes. @@ -436,7 +486,8 @@
uint8_t data_packet[command_packet_size]; unsigned int value, idx; - fill_rw_cmd_payload(data_packet, count, READ_MODE_STD, &value, &idx, start, 1); + if (prepare_rw_cmd(flash, data_packet, count, READ_MODE_STD, &value, &idx, start, 1)) + return 1;
int ret = dediprog_write(CMD_READ, value, idx, data_packet, sizeof(data_packet)); if (ret != sizeof(data_packet)) { @@ -592,7 +643,8 @@
uint8_t data_packet[command_packet_size]; unsigned int value, idx; - fill_rw_cmd_payload(data_packet, count, dedi_spi_cmd, &value, &idx, start, 0); + if (prepare_rw_cmd(flash, data_packet, count, dedi_spi_cmd, &value, &idx, start, 0)) + return 1; 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)); @@ -637,7 +689,7 @@ msg_pdbg("Slow write for partial block from 0x%x, length 0x%x\n", start, residue); /* No idea about the real limit. Maybe 12, maybe more. */ - ret = spi_write_chunked(flash, buf, start, residue, 12); + ret = spi_write_chunked(flash, buf, start, residue, 11); if (ret) { dediprog_set_leds(LED_ERROR); return ret; @@ -657,7 +709,7 @@ msg_pdbg("Slow write for partial block from 0x%x, length 0x%x\n", start, len); ret = spi_write_chunked(flash, buf + residue + bulklen, - start + residue + bulklen, len, 12); + start + residue + bulklen, len, 11); if (ret) { dediprog_set_leds(LED_ERROR); return ret; @@ -927,7 +979,7 @@ return millivolt; }
-static const struct spi_master spi_master_dediprog = { +static struct spi_master spi_master_dediprog = { .type = SPI_CONTROLLER_DEDIPROG, .max_data_read = 16, /* 18 seems to work fine as well, but 19 times out sometimes with FW 5.15. */ .max_data_write = 16, @@ -1114,6 +1166,9 @@ if (dediprog_standalone_mode()) return 1;
+ if (protocol() >= PROTOCOL_V2) + spi_master_dediprog.features |= SPI_MASTER_4BA; + if (register_spi_master(&spi_master_dediprog) || dediprog_set_leds(LED_NONE)) return 1;
diff --git a/spi.h b/spi.h index 422e6a0..0073c71 100644 --- a/spi.h +++ b/spi.h @@ -151,6 +151,9 @@ #define JEDEC_READ_OUTSIZE 0x04 /* JEDEC_READ_INSIZE : any length */
+/* Read the memory (with delay after sending address) */ +#define JEDEC_READ_FAST 0x0b + /* Write memory byte */ #define JEDEC_BYTE_PROGRAM 0x02 #define JEDEC_BYTE_PROGRAM_OUTSIZE 0x05 @@ -166,6 +169,10 @@ From ANY mode (3-bytes or 4-bytes) it works with 4-byte address */ #define JEDEC_READ_4BA 0x13
+/* Read the memory with 4-byte address (and delay after sending address) + From ANY mode (3-bytes or 4-bytes) it works with 4-byte address */ +#define JEDEC_READ_4BA_FAST 0x0c + /* Write memory byte with 4-byte address From ANY mode (3-bytes or 4-bytes) it works with 4-byte address */ #define JEDEC_BYTE_PROGRAM_4BA 0x12 diff --git a/spi25.c b/spi25.c index c403570..be89a5e 100644 --- a/spi25.c +++ b/spi25.c @@ -358,7 +358,7 @@ return result; }
-static int spi_set_extended_address(struct flashctx *const flash, const uint8_t addr_high) +int spi_set_extended_address(struct flashctx *const flash, const uint8_t addr_high) { if (flash->address_high_byte != addr_high && spi_write_extended_address_register(flash, addr_high))