Author: hailfinger
Date: Wed Oct  6 00:06:05 2010
New Revision: 1193
URL: http://flashrom.org/trac/flashrom/changeset/1193

Log:
Implement on-the-fly reprogramming of the ICH SPI OPCODE table.

Signed-off-by: Helge Wagner <[email protected]>
Acked-by: Carl-Daniel Hailfinger <[email protected]>

Modified:
   trunk/ichspi.c

Modified: trunk/ichspi.c
==============================================================================
--- trunk/ichspi.c      Tue Oct  5 23:48:43 2010        (r1192)
+++ trunk/ichspi.c      Wed Oct  6 00:06:05 2010        (r1193)
@@ -30,6 +30,7 @@
  * ST M25P32 already tested
  * ST M25P64
  * AT 25DF321 already tested
+ * ... and many more SPI flash devices
  *
  */
 
@@ -197,8 +198,76 @@
        }
 };
 
+/* 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 @@
        /* 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 @@
                                 * 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;
                                }
                        }

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

Reply via email to