From 738e252112271f63c8ad4c9a135cfe17ff98e87d Mon Sep 17 00:00:00 2001 From: Helge Wagner Date: Tue, 5 Oct 2010 22:06:05 +0000 Subject: Implement on-the-fly reprogramming of the ICH SPI OPCODE table Corresponding to flashrom svn r1193. Signed-off-by: Helge Wagner Acked-by: Carl-Daniel Hailfinger --- ichspi.c | 99 +++++++++++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 79 insertions(+), 20 deletions(-) (limited to 'ichspi.c') diff --git a/ichspi.c b/ichspi.c index bb6007e..c26366e 100644 --- a/ichspi.c +++ b/ichspi.c @@ -30,6 +30,7 @@ * ST M25P32 already tested * ST M25P64 * AT 25DF321 already tested + * ... and many more SPI flash devices * */ @@ -197,8 +198,76 @@ static OPCODES O_ST_M25P = { } }; +/* List of opcodes with their corresponding spi_type + * It is used to reprogram the chipset OPCODE table on-the-fly if an opcode + * 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 +}; + static OPCODES O_EXISTING = {}; +static uint8_t lookup_spi_type(uint8_t opcode) +{ + int a; + + for (a = 0; a < sizeof(POSSIBLE_OPCODES)/sizeof(POSSIBLE_OPCODES[0]); a++) { + if (POSSIBLE_OPCODES[a].opcode == opcode) + return POSSIBLE_OPCODES[a].spi_type; + } + + return 0xFF; +} + +static int reprogram_opcode_on_the_fly(uint8_t opcode, 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, will be handled below + } + if (spi_type <= 3) { + int oppos=2; // use original JEDEC_BE_D8 offset + curopcodes->opcode[oppos].opcode = opcode; + curopcodes->opcode[oppos].spi_type = spi_type; + program_opcodes(curopcodes); + oppos = find_opcode(curopcodes, opcode); + msg_pdbg ("on-the-fly OPCODE (0x%02X) re-programmed, op-pos=%d\n", opcode, oppos); + return oppos; + } + return -1; +} + static int find_opcode(OPCODES *op, uint8_t opcode) { int a; @@ -710,11 +779,12 @@ int ich_spi_send_command(unsigned int writecnt, unsigned int readcnt, /* find cmd in opcodes-table */ opcode_index = find_opcode(curopcodes, cmd); if (opcode_index == -1) { - /* FIXME: Reprogram opcodes if possible. Autodetect type of - * opcode by checking readcnt/writecnt. - */ - msg_pdbg("Invalid OPCODE 0x%02x\n", cmd); - return SPI_INVALID_OPCODE; + if (!ichspi_lock) + opcode_index = reprogram_opcode_on_the_fly(cmd, writecnt, readcnt); + if (opcode_index == -1) { + msg_pdbg("Invalid OPCODE 0x%02x\n", cmd); + return SPI_INVALID_OPCODE; + } } opcode = &(curopcodes->opcode[opcode_index]); @@ -827,21 +897,10 @@ int ich_spi_send_multicommand(struct spi_command *cmds) * No need to bother with fixups. */ if (!ichspi_lock) { - msg_pdbg("%s: FIXME: Add on-the-fly" - " reprogramming of the " - "chipset opcode list.\n", - __func__); - /* FIXME: Reprogram opcode menu. - * Find a less-useful opcode, replace it - * with the wanted opcode, detect optype - * and reprogram the opcode menu. - * Update oppos so the next if-statement - * can do something useful. - */ - //curopcodes.opcode[lessusefulindex] = (cmds + 1)->writearr[0]); - //update_optypes(curopcodes); - //program_opcodes(curopcodes); - //oppos = find_opcode(curopcodes, (cmds + 1)->writearr[0]); + oppos = reprogram_opcode_on_the_fly((cmds + 1)->writearr[0], (cmds + 1)->writecnt, (cmds + 1)->readcnt); + if (oppos == -1) + continue; + curopcodes->opcode[oppos].atomic = preoppos + 1; continue; } } -- cgit v1.1