Nico Huber has uploaded this change for review.

View Change

[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))

To view, visit change 28804. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: flashrom
Gerrit-Branch: master
Gerrit-MessageType: newchange
Gerrit-Change-Id: I665d0806aec469a3509620a760815861fbe22841
Gerrit-Change-Number: 28804
Gerrit-PatchSet: 1
Gerrit-Owner: Nico Huber <nico.h@gmx.de>