@@ -24,6 +24,7 @@
#ifndef __FLASH_H__
#define __FLASH_H__ 1
+#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>
#ifdef _WIN32
@@ -135,10 +135,10 @@
#define FPB_FPBA (0x1FFF << FPB_FPBA_OFF)
// ICH9R SPI commands
-#define SPI_OPCODE_TYPE_READ_NO_ADDRESS 0
-#define SPI_OPCODE_TYPE_WRITE_NO_ADDRESS 1
-#define SPI_OPCODE_TYPE_READ_WITH_ADDRESS 2
-#define SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS 3
+#define READING_OP_NO_ADDR 0
+#define WRITING_OP_NO_ADDR 1
+#define READING_OP_WITH_ADDR 2
+#define WRITING_OP_WITH_ADDR 3
// ICH7 registers
#define ICH7_REG_SPIS 0x00 /* 16 Bits */
@@ -261,14 +261,14 @@ static OPCODES O_ST_M25P = {
JEDEC_EWSR,
},
{
- {JEDEC_BYTE_PROGRAM, SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS, 0}, // Write Byte
- {JEDEC_READ, SPI_OPCODE_TYPE_READ_WITH_ADDRESS, 0}, // Read Data
- {JEDEC_BE_D8, SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS, 0}, // Erase Sector
- {JEDEC_RDSR, SPI_OPCODE_TYPE_READ_NO_ADDRESS, 0}, // Read Device Status Reg
- {JEDEC_REMS, SPI_OPCODE_TYPE_READ_WITH_ADDRESS, 0}, // Read Electronic Manufacturer Signature
- {JEDEC_WRSR, SPI_OPCODE_TYPE_WRITE_NO_ADDRESS, 0}, // Write Status Register
- {JEDEC_RDID, SPI_OPCODE_TYPE_READ_NO_ADDRESS, 0}, // Read JDEC ID
- {JEDEC_CE_C7, SPI_OPCODE_TYPE_WRITE_NO_ADDRESS, 0}, // Bulk erase
+ {JEDEC_BYTE_PROGRAM, WRITING_OP_WITH_ADDR, 0}, // Write Byte
+ {JEDEC_READ, READING_OP_WITH_ADDR, 0}, // Read Data
+ {JEDEC_BE_D8, WRITING_OP_WITH_ADDR, 0}, // Erase Sector
+ {JEDEC_RDSR, READING_OP_NO_ADDR, 0}, // Read Device Status Reg
+ {JEDEC_REMS, READING_OP_WITH_ADDR, 0}, // Read Electronic Manufacturer Signature
+ {JEDEC_WRSR, WRITING_OP_NO_ADDR, 0}, // Write Status Register
+ {JEDEC_RDID, READING_OP_NO_ADDR, 0}, // Read JDEC ID
+ {JEDEC_CE_C7, WRITING_OP_NO_ADDR, 0}, // Bulk erase
}
};
@@ -277,17 +277,17 @@ static OPCODES O_ST_M25P = {
* is needed which is currently not in the chipset OPCODE table
*/
static OPCODE POSSIBLE_OPCODES[] = {
- {JEDEC_BYTE_PROGRAM, SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS, 0}, // Write Byte
- {JEDEC_READ, SPI_OPCODE_TYPE_READ_WITH_ADDRESS, 0}, // Read Data
- {JEDEC_BE_D8, SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS, 0}, // Erase Sector
- {JEDEC_RDSR, SPI_OPCODE_TYPE_READ_NO_ADDRESS, 0}, // Read Device Status Reg
- {JEDEC_REMS, SPI_OPCODE_TYPE_READ_WITH_ADDRESS, 0}, // Read Electronic Manufacturer Signature
- {JEDEC_WRSR, SPI_OPCODE_TYPE_WRITE_NO_ADDRESS, 0}, // Write Status Register
- {JEDEC_RDID, SPI_OPCODE_TYPE_READ_NO_ADDRESS, 0}, // Read JDEC ID
- {JEDEC_CE_C7, SPI_OPCODE_TYPE_WRITE_NO_ADDRESS, 0}, // Bulk erase
- {JEDEC_SE, SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS, 0}, // Sector erase
- {JEDEC_BE_52, SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS, 0}, // Block erase
- {JEDEC_AAI_WORD_PROGRAM, SPI_OPCODE_TYPE_WRITE_NO_ADDRESS, 0}, // Auto Address Increment
+ {JEDEC_BYTE_PROGRAM, WRITING_OP_WITH_ADDR, 0}, // Write Byte
+ {JEDEC_READ, READING_OP_WITH_ADDR, 0}, // Read Data
+ {JEDEC_BE_D8, WRITING_OP_WITH_ADDR, 0}, // Erase Sector
+ {JEDEC_RDSR, READING_OP_NO_ADDR, 0}, // Read Device Status Reg
+ {JEDEC_REMS, READING_OP_WITH_ADDR, 0}, // Read Electronic Manufacturer Signature
+ {JEDEC_WRSR, WRITING_OP_NO_ADDR, 0}, // Write Status Register
+ {JEDEC_RDID, READING_OP_NO_ADDR, 0}, // Read JDEC ID
+ {JEDEC_CE_C7, WRITING_OP_NO_ADDR, 0}, // Bulk erase
+ {JEDEC_SE, WRITING_OP_WITH_ADDR, 0}, // Sector erase
+ {JEDEC_BE_52, WRITING_OP_WITH_ADDR, 0}, // Block erase
+ {JEDEC_AAI_WORD_PROGRAM, WRITING_OP_NO_ADDR, 0}, // Auto Address Increment
};
static OPCODES O_EXISTING = {};
@@ -370,66 +370,61 @@ static void prettyprint_ich9_reg_ssfc(uint32_t reg_val)
pprint_reg(SSFC, SCF, reg_val, "\n");
}
-static uint8_t lookup_spi_type(uint8_t opcode)
+static uint8_t determine_spitype(uint8_t opcode, unsigned int writecnt, unsigned int readcnt)
{
- int a;
-
- for (a = 0; a < ARRAY_SIZE(POSSIBLE_OPCODES); a++) {
- if (POSSIBLE_OPCODES[a].opcode == opcode)
- return POSSIBLE_OPCODES[a].spi_type;
+ int i;
+ for (i = 0; i < ARRAY_SIZE(POSSIBLE_OPCODES); i++) {
+ if (POSSIBLE_OPCODES[i].opcode == opcode)
+ return POSSIBLE_OPCODES[i].spi_type;
}
- return 0xFF;
+ /* Try to guess spi type from read/write sizes.
+ * The following valid writecnt/readcnt combinations exist:
+ * writecnt = 4, readcnt >= 0
+ * writecnt = 1, readcnt >= 0
+ * writecnt >= 4, readcnt = 0
+ * writecnt >= 1, readcnt = 0
+ * writecnt >= 1 is guaranteed for all commands.
+ */
+ msg_pspew("Need to guess spitype from payload lengths.\n");
+ if (readcnt == 0)
+ /* if readcnt=0 and writecount >= 4, we don't know if it is WRITE_NO_ADDRESS
+ * or WRITE_WITH_ADDRESS. But if we use WRITE_NO_ADDRESS and the first 3 data
+ * bytes are actual the address, they go to the bus anyhow
+ */
+ return WRITING_OP_NO_ADDR;
+ else if (writecnt == 1) // and readcnt is > 0
+ return READING_OP_NO_ADDR;
+ else if (writecnt == 4) // and readcnt is > 0
+ return READING_OP_WITH_ADDR;
+ else // we have an invalid case
+ return 0xFF;
}
-static int reprogram_opcode_on_the_fly(uint8_t opcode, unsigned int writecnt, unsigned int readcnt)
+static int reprogram_opcode_on_the_fly(uint8_t opcode, uint8_t spi_type, unsigned int writecnt, unsigned int readcnt)
{
- uint8_t spi_type;
-
- spi_type = lookup_spi_type(opcode);
- if (spi_type > 3) {
- /* Try to guess spi type from read/write sizes.
- * The following valid writecnt/readcnt combinations exist:
- * writecnt = 4, readcnt >= 0
- * writecnt = 1, readcnt >= 0
- * writecnt >= 4, readcnt = 0
- * writecnt >= 1, readcnt = 0
- * writecnt >= 1 is guaranteed for all commands.
- */
- if (readcnt == 0)
- /* if readcnt=0 and writecount >= 4, we don't know if it is WRITE_NO_ADDRESS
- * or WRITE_WITH_ADDRESS. But if we use WRITE_NO_ADDRESS and the first 3 data
- * bytes are actual the address, they go to the bus anyhow
- */
- spi_type = SPI_OPCODE_TYPE_WRITE_NO_ADDRESS;
- else if (writecnt == 1) // and readcnt is > 0
- spi_type = SPI_OPCODE_TYPE_READ_NO_ADDRESS;
- else if (writecnt == 4) // and readcnt is > 0
- spi_type = SPI_OPCODE_TYPE_READ_WITH_ADDRESS;
- else // we have an invalid case
- return SPI_INVALID_LENGTH;
- }
- int oppos = 2; // use original JEDEC_BE_D8 offset
+ int ret;
+ const int oppos = 2; // use original JEDEC_BE_D8 offset
curopcodes->opcode[oppos].opcode = opcode;
curopcodes->opcode[oppos].spi_type = spi_type;
- program_opcodes(curopcodes, 0);
- oppos = find_opcode(curopcodes, opcode);
- msg_pdbg2("on-the-fly OPCODE (0x%02X) re-programmed, op-pos=%d\n", opcode, oppos);
- return oppos;
+ ret = program_opcodes(curopcodes, 0);
+ if (ret == 0)
+ msg_pdbg2("OPCODE (0x%02X) re-programmed on-the-fly, op-pos=%d\n", opcode, oppos);
+ return ret;
}
static int find_opcode(OPCODES *op, uint8_t opcode)
{
- int a;
+ int i;
if (op == NULL) {
msg_perr("\n%s: null OPCODES pointer!\n", __func__);
return -1;
}
- for (a = 0; a < 8; a++) {
- if (op->opcode[a].opcode == opcode)
- return a;
+ for (i = 0; i < 8; i++) {
+ if (op->opcode[i].opcode == opcode)
+ return i;
}
return -1;
@@ -549,6 +544,14 @@ static int program_opcodes(OPCODES *op, int enable_undo)
mmio_writew(optype, ich_spibar + ICH7_REG_OPTYPE);
mmio_writel(opmenu[0], ich_spibar + ICH7_REG_OPMENU);
mmio_writel(opmenu[1], ich_spibar + ICH7_REG_OPMENU + 4);
+
+ if ((preop != mmio_readw(ich_spibar + ICH7_REG_PREOP)) ||
+ (optype != mmio_readw(ich_spibar + ICH7_REG_OPTYPE)) ||
+ (opmenu[0] != mmio_readl(ich_spibar + ICH7_REG_OPMENU)) ||
+ (opmenu[1] != mmio_readl(ich_spibar + ICH7_REG_OPMENU + 4))) {
+ msg_perr("Programming opcodes failed.\n");
+ return 1;
+ }
break;
case CHIPSET_ICH8:
default: /* Future version might behave the same */
@@ -563,6 +566,13 @@ static int program_opcodes(OPCODES *op, int enable_undo)
mmio_writew(optype, ich_spibar + ICH9_REG_OPTYPE);
mmio_writel(opmenu[0], ich_spibar + ICH9_REG_OPMENU);
mmio_writel(opmenu[1], ich_spibar + ICH9_REG_OPMENU + 4);
+ if ((preop != mmio_readw(ich_spibar + ICH9_REG_PREOP)) ||
+ (optype != mmio_readw(ich_spibar + ICH9_REG_OPTYPE)) ||
+ (opmenu[0] != mmio_readl(ich_spibar + ICH9_REG_OPMENU)) ||
+ (opmenu[1] != mmio_readl(ich_spibar + ICH9_REG_OPMENU + 4))) {
+ msg_perr("Programming opcodes failed.\n");
+ return 1;
+ }
break;
}
@@ -720,11 +730,11 @@ static int ich7_run_opcode(OPCODE op, uint32_t offset,
uint32_t temp32;
uint16_t temp16;
uint64_t opmenu;
- int opcode_index;
+ int oppos;
/* Is it a write command? */
- if ((op.spi_type == SPI_OPCODE_TYPE_WRITE_NO_ADDRESS)
- || (op.spi_type == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS)) {
+ if ((op.spi_type == WRITING_OP_NO_ADDR)
+ || (op.spi_type == WRITING_OP_WITH_ADDR)) {
write_cmd = 1;
}
@@ -765,17 +775,17 @@ static int ich7_run_opcode(OPCODE op, uint32_t offset,
opmenu = REGREAD32(ICH7_REG_OPMENU);
opmenu |= ((uint64_t)REGREAD32(ICH7_REG_OPMENU + 4)) << 32;
- for (opcode_index = 0; opcode_index < 8; opcode_index++) {
+ for (oppos = 0; oppos < 8; oppos++) {
if ((opmenu & 0xff) == op.opcode) {
break;
}
opmenu >>= 8;
}
- if (opcode_index == 8) {
+ if (oppos == 8) {
msg_pdbg("Opcode %x not found.\n", op.opcode);
return 1;
}
- temp16 |= ((uint16_t) (opcode_index & 0x07)) << 4;
+ temp16 |= ((uint16_t) (oppos & 0x07)) << 4;
timeout = 100 * 60; /* 60 ms are 9.6 million cycles at 16 MHz. */
/* Handle Atomic. Atomic commands include three steps:
@@ -837,11 +847,10 @@ static int ich9_run_opcode(OPCODE op, uint32_t offset,
int timeout;
uint32_t temp32;
uint64_t opmenu;
- int opcode_index;
+ int oppos;
/* Is it a write command? */
- if ((op.spi_type == SPI_OPCODE_TYPE_WRITE_NO_ADDRESS)
- || (op.spi_type == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS)) {
+ if ((op.spi_type == WRITING_OP_NO_ADDR) || (op.spi_type == WRITING_OP_WITH_ADDR)) {
write_cmd = 1;
}
@@ -887,17 +896,17 @@ static int ich9_run_opcode(OPCODE op, uint32_t offset,
opmenu = REGREAD32(ICH9_REG_OPMENU);
opmenu |= ((uint64_t)REGREAD32(ICH9_REG_OPMENU + 4)) << 32;
- for (opcode_index = 0; opcode_index < 8; opcode_index++) {
+ for (oppos = 0; oppos < 8; oppos++) {
if ((opmenu & 0xff) == op.opcode) {
break;
}
opmenu >>= 8;
}
- if (opcode_index == 8) {
+ if (oppos == 8) {
msg_pdbg("Opcode %x not found.\n", op.opcode);
return 1;
}
- temp32 |= ((uint32_t) (opcode_index & 0x07)) << (8 + 4);
+ temp32 |= ((uint32_t) (oppos & 0x07)) << (8 + 4);
timeout = 100 * 60; /* 60 ms are 9.6 million cycles at 16 MHz. */
/* Handle Atomic. Atomic commands include three steps:
@@ -982,86 +991,114 @@ static int run_opcode(const struct flashctx *flash, OPCODE op, uint32_t offset,
}
}
-static int ich_spi_send_command(struct flashctx *flash, unsigned int writecnt,
- unsigned int readcnt,
- const unsigned char *writearr,
- unsigned char *readarr)
+/* Check command and prepare the appropriate opcode.
+ * The selected OPCODE will be returned in opcodep if it can be determined.
+ * If the dryrun flag is set, try do determine opcode sanity and availability only, do not change hw state
+ * (i.e. do not touch OPMENU). In that case opcodep is unused. */
+static int prepare_opcode(struct flashctx *flash, unsigned int writecnt, unsigned int readcnt,
+ const unsigned char *writearr, bool dryrun, OPCODE **opcodep)
{
- int result;
- int opcode_index = -1;
- const unsigned char cmd = *writearr;
- OPCODE *opcode;
- uint32_t addr = 0;
- uint8_t *data;
- int count;
+ OPCODE *opcode = NULL;
+ OPCODE emu_op = {0};
+ if (writecnt == 0)
+ return SPI_INVALID_LENGTH;
- /* find cmd in opcodes-table */
- opcode_index = find_opcode(curopcodes, cmd);
- if (opcode_index == -1) {
- if (!ichspi_lock)
- opcode_index = reprogram_opcode_on_the_fly(cmd, writecnt, readcnt);
- if (opcode_index == SPI_INVALID_LENGTH) {
- msg_pdbg("OPCODE 0x%02x has unsupported length, will not execute.\n", cmd);
+ /* ensure that the requested opcode is available */
+ int oppos = find_opcode(curopcodes, writearr[0]);
+ if (oppos >= 0) {
+ opcode = &(curopcodes->opcode[oppos]);
+ } else {
+ uint8_t spi_type = determine_spitype(writearr[0], writecnt, readcnt);
+ if (spi_type == 0xFF) {
+ if (!dryrun)
+ msg_pdbg("Could not determine spitype for opcode 0x%02x.\n", writearr[0]);
return SPI_INVALID_LENGTH;
- } else if (opcode_index == -1) {
- msg_pdbg("Invalid OPCODE 0x%02x, will not execute.\n",
- cmd);
+ }
+ if (ichspi_lock) {
+ if (!dryrun)
+ msg_pdbg("OPCODES locked down and do not contain 0x%02x, can not execute.\n",
+ writearr[0]);
return SPI_INVALID_OPCODE;
+ } else {
+ /* In a dryrun we expect that reprogramming works successfully, but we need to create
+ * an OPCODE object for the tests below. */
+ if (dryrun) {
+ emu_op.opcode = writearr[0];
+ emu_op.spi_type = spi_type;
+ opcode = &emu_op;
+ } else {
+ if (reprogram_opcode_on_the_fly(writearr[0], spi_type, writecnt, readcnt) != 0)
+ return SPI_GENERIC_ERROR;
+ oppos = find_opcode(curopcodes, writearr[0]);
+ opcode = &(curopcodes->opcode[oppos]);
+ }
}
}
- opcode = &(curopcodes->opcode[opcode_index]);
-
/* The following valid writecnt/readcnt combinations exist:
* writecnt = 4, readcnt >= 0
* writecnt = 1, readcnt >= 0
* writecnt >= 4, readcnt = 0
* writecnt >= 1, readcnt = 0
- * writecnt >= 1 is guaranteed for all commands.
- */
- if ((opcode->spi_type == SPI_OPCODE_TYPE_READ_WITH_ADDRESS) &&
- (writecnt != 4)) {
- msg_perr("%s: Internal command size error for opcode "
- "0x%02x, got writecnt=%i, want =4\n", __func__, cmd,
- writecnt);
+ * writecnt >= 1 is guaranteed for all commands. */
+ if ((opcode->spi_type == READING_OP_WITH_ADDR) && (writecnt != 4)) {
+ if (!dryrun)
+ msg_perr("%s: Reading command requires an opcode (0x%02x) and exactly 3 address bytes, "
+ "but writecnt=%i.\n", __func__, writearr[0], writecnt);
return SPI_INVALID_LENGTH;
}
- if ((opcode->spi_type == SPI_OPCODE_TYPE_READ_NO_ADDRESS) &&
- (writecnt != 1)) {
- msg_perr("%s: Internal command size error for opcode "
- "0x%02x, got writecnt=%i, want =1\n", __func__, cmd,
- writecnt);
+ if ((opcode->spi_type == READING_OP_NO_ADDR) && (writecnt != 1)) {
+ if (!dryrun)
+ msg_perr("%s: Reading command requires an opcode (0x%02x) without address bytes, "
+ "but writecnt=%i.\n", __func__, writearr[0], writecnt);
return SPI_INVALID_LENGTH;
}
- if ((opcode->spi_type == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS) &&
- (writecnt < 4)) {
- msg_perr("%s: Internal command size error for opcode "
- "0x%02x, got writecnt=%i, want >=4\n", __func__, cmd,
- writecnt);
+ if ((opcode->spi_type == WRITING_OP_WITH_ADDR) && (writecnt < 4)) {
+ if (!dryrun)
+ msg_perr("%s: Writing command requires at least an opcode (0x%02x) and exactly "
+ "3 address bytes, but writecnt=%i.\n", __func__, writearr[0], writecnt);
return SPI_INVALID_LENGTH;
}
- if (((opcode->spi_type == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS) ||
- (opcode->spi_type == SPI_OPCODE_TYPE_WRITE_NO_ADDRESS)) &&
- (readcnt)) {
- msg_perr("%s: Internal command size error for opcode "
- "0x%02x, got readcnt=%i, want =0\n", __func__, cmd,
- readcnt);
+ if (((opcode->spi_type == WRITING_OP_WITH_ADDR) || (opcode->spi_type == WRITING_OP_NO_ADDR)) &&
+ (readcnt > 0)) {
+ if (!dryrun)
+ msg_perr("%s: Writing command with opcode (0x%02x) can read not bytes, "
+ "but readcnt=%i.\n", __func__, writearr[0], readcnt);
return SPI_INVALID_LENGTH;
}
- /* if opcode-type requires an address */
- if (opcode->spi_type == SPI_OPCODE_TYPE_READ_WITH_ADDRESS ||
- opcode->spi_type == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS) {
- addr = (writearr[1] << 16) |
- (writearr[2] << 8) | (writearr[3] << 0);
+ /* If the opcode type requires an address we check if it is below the allowed base. */
+ if (opcode->spi_type == READING_OP_WITH_ADDR || opcode->spi_type == WRITING_OP_WITH_ADDR) {
+ uint32_t addr = (writearr[1] << 16) | (writearr[2] << 8) | (writearr[3] << 0);
if (addr < ichspi_bbar) {
- msg_perr("%s: Address 0x%06x below allowed "
- "range 0x%06x-0xffffff\n", __func__,
- addr, ichspi_bbar);
+ msg_perr("%s: Address 0x%06x below allowed range 0x%06x-0xffffff\n",
+ __func__, addr, ichspi_bbar);
return SPI_INVALID_ADDRESS;
}
}
+ if (opcodep != NULL)
+ *opcodep = opcode;
+ return 0;
+}
+
+static int ich_spi_send_command(struct flashctx *flash, unsigned int writecnt,
+ unsigned int readcnt,
+ const unsigned char *writearr,
+ unsigned char *readarr)
+{
+ OPCODE *opcode;
+ uint32_t addr;
+ uint8_t *data;
+ int count;
+
+ int result = prepare_opcode(flash, writecnt, readcnt, writearr, false, &opcode);
+ if (result != 0) {
+ msg_pspew("%s called with an unsupported transaction layout: readcnt = %d, writecnt = %d.\n",
+ __func__, readcnt, writecnt);
+ return result;
+ }
+
/* Translate read/write array/count.
* The maximum data length is identical for the maximum read length and
* for the maximum write length excluding opcode and address. Opcode and
@@ -1069,10 +1106,10 @@ static int ich_spi_send_command(struct flashctx *flash, unsigned int writecnt,
* and are thus not counted towards data length. The only exception
* applies if the opcode definition (un)intentionally classifies said
* opcode incorrectly as non-address opcode or vice versa. */
- if (opcode->spi_type == SPI_OPCODE_TYPE_WRITE_NO_ADDRESS) {
+ if (opcode->spi_type == WRITING_OP_NO_ADDR) {
data = (uint8_t *) (writearr + 1);
count = writecnt - 1;
- } else if (opcode->spi_type == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS) {
+ } else if (opcode->spi_type == WRITING_OP_WITH_ADDR) {
data = (uint8_t *) (writearr + 4);
count = writecnt - 4;
} else {
@@ -1080,11 +1117,11 @@ static int ich_spi_send_command(struct flashctx *flash, unsigned int writecnt,
count = readcnt;
}
+ addr = (writearr[1] << 16) | (writearr[2] << 8) | (writearr[3] << 0);
result = run_opcode(flash, *opcode, addr, count, data);
if (result) {
msg_pdbg("Running OPCODE 0x%02x failed ", opcode->opcode);
- if ((opcode->spi_type == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS) ||
- (opcode->spi_type == SPI_OPCODE_TYPE_READ_WITH_ADDRESS)) {
+ if ((opcode->spi_type == WRITING_OP_WITH_ADDR) || (opcode->spi_type == READING_OP_WITH_ADDR)) {
msg_pdbg("at address 0x%06x ", addr);
}
msg_pdbg("(payload length was %d).\n", count);
@@ -1092,8 +1129,7 @@ static int ich_spi_send_command(struct flashctx *flash, unsigned int writecnt,
/* Print out the data array if it contains data to write.
* Errors are detected before the received data is read back into
* the array so it won't make sense to print it then. */
- if ((opcode->spi_type == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS) ||
- (opcode->spi_type == SPI_OPCODE_TYPE_WRITE_NO_ADDRESS)) {
+ if ((opcode->spi_type == WRITING_OP_WITH_ADDR) || (opcode->spi_type == WRITING_OP_NO_ADDR)) {
int i;
msg_pspew("The data was:\n");
for (i = 0; i < count; i++){
@@ -1358,17 +1394,17 @@ static int ich_hwseq_write(struct flashctx *flash, uint8_t *buf,
return 0;
}
-static int ich_spi_send_multicommand(struct flashctx *flash,
- struct spi_command *cmds)
+static int ich_spi_send_multicommand(struct flashctx *flash, struct spi_command *cmds)
{
int ret = 0;
int i;
int oppos, preoppos;
for (; (cmds->writecnt || cmds->readcnt) && !ret; cmds++) {
- if ((cmds + 1)->writecnt || (cmds + 1)->readcnt) {
+ struct spi_command *cmd_nxt = cmds + 1;
+ if (cmd_nxt->writecnt || cmd_nxt->readcnt) {
/* Next command is valid. */
preoppos = find_preop(curopcodes, cmds->writearr[0]);
- oppos = find_opcode(curopcodes, (cmds + 1)->writearr[0]);
+ oppos = find_opcode(curopcodes, cmd_nxt->writearr[0]);
if ((oppos == -1) && (preoppos != -1)) {
/* Current command is listed as preopcode in
* ICH struct OPCODES, but next command is not
@@ -1376,13 +1412,10 @@ static int ich_spi_send_multicommand(struct flashctx *flash,
* Check for command sanity, then
* try to reprogram the ICH opcode list.
*/
- if (find_preop(curopcodes,
- (cmds + 1)->writearr[0]) != -1) {
- msg_perr("%s: Two subsequent "
- "preopcodes 0x%02x and 0x%02x, "
+ if (find_preop(curopcodes, cmd_nxt->writearr[0]) != -1) {
+ msg_perr("%s: Two subsequent preopcodes 0x%02x and 0x%02x, "
"ignoring the first.\n",
- __func__, cmds->writearr[0],
- (cmds + 1)->writearr[0]);
+ __func__, cmds->writearr[0], cmd_nxt->writearr[0]);
continue;
}
/* If the chipset is locked down, we'll fail
@@ -1390,7 +1423,19 @@ static int ich_spi_send_multicommand(struct flashctx *flash,
* No need to bother with fixups.
*/
if (!ichspi_lock) {
- oppos = reprogram_opcode_on_the_fly((cmds + 1)->writearr[0], (cmds + 1)->writecnt, (cmds + 1)->readcnt);
+ uint8_t spi_type = determine_spitype(cmd_nxt->writearr[0],
+ cmd_nxt->writecnt,
+ cmd_nxt->readcnt);
+ if (spi_type == 0xFF) {
+ msg_pdbg("Could not determine spitype for opcode 0x%02x.\n",
+ cmd_nxt->writearr[0]);
+ return SPI_INVALID_LENGTH;
+ }
+ ret = reprogram_opcode_on_the_fly(cmd_nxt->writearr[0], spi_type,
+ cmd_nxt->writecnt, cmd_nxt->readcnt);
+ if (ret == -1)
+ continue;
+ oppos = find_opcode(curopcodes, cmd_nxt->writearr[0]);
if (oppos == -1)
continue;
curopcodes->opcode[oppos].atomic = preoppos + 1;
@@ -1793,10 +1838,8 @@ int ich_init_spi(struct pci_dev *dev, uint32_t base, void *rcrb,
}
}
- if (ich_spi_mode == ich_auto && ichspi_lock &&
- ich_missing_opcodes()) {
- msg_pinfo("Enabling hardware sequencing because "
- "some important opcode is locked.\n");
+ if (ich_spi_mode == ich_auto && ichspi_lock && ich_missing_opcodes()) {
+ msg_pinfo("Enabling hardware sequencing because an important opcode is unavailable.\n");
ich_spi_mode = ich_hwseq;
}
- Introduce prepare_opcode() which does: * find the offset of an opcode or reprogram the OPMENU as necessary * check if the writecnt and readcnt are legit for the transaction type * ensure that the allowed BBAR is obeyed. - Merge lookup_spi_type() and parts of reprogram_opcode_on_the_fly() into determine_spitype(). - Verify the writes in program_opcodes() and use it in error handling. - Refactor ich_spi_send_multicommand() to utilize above changes. - General cleanup of variable and constant names, among others: * opcode_index -> oppos everywhere * shortening of SPI_OPCODE_TYPE_* Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at> --- flash.h | 1 + ichspi.c | 347 +++++++++++++++++++++++++++++++++++--------------------------- 2 files changed, 196 insertions(+), 152 deletions(-)