- 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 <[email protected]>
---
 flash.h  |    1 +
 ichspi.c |  347 +++++++++++++++++++++++++++++++++++---------------------------
 2 files changed, 196 insertions(+), 152 deletions(-)

diff --git a/flash.h b/flash.h
index 4913536..3230849 100644
--- a/flash.h
+++ b/flash.h
@@ -24,6 +24,7 @@
 #ifndef __FLASH_H__
 #define __FLASH_H__ 1
 
+#include <stdbool.h>
 #include <stdint.h>
 #include <stddef.h>
 #ifdef _WIN32
diff --git a/ichspi.c b/ichspi.c
index 8dd1893..e60913c 100644
--- a/ichspi.c
+++ b/ichspi.c
@@ -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;
                }
 
-- 
Kind regards, Stefan Tauner


_______________________________________________
flashrom mailing list
[email protected]
http://www.flashrom.org/mailman/listinfo/flashrom

Reply via email to