[flashrom] [PATCH 7/10] 4BA: SFDP 1.6 parser for compliance with JESD216B

Boris Baykov dev at borisbaykov.com
Sun Jan 11 00:22:25 CET 2015


More than a year ago JEDEC released new standard
JESD216 (revision B) which describes in detail how to receive
4-bytes addressing settings from the chip. This patch provides
new code to add compliance to JESD216B to Flashrom. This means
that Flashrom now can automatically detect 4-bytes addressing
features of large flash chips and use them to access data.

However not all things are so good. Unfortunately JESD216B
had come to manufacturer's production lines just 2-3 months
ago. So, we have many chips that have large size requires
32-bit addressing but their SFDP tables have revision lower
than 1.6 (described in JESD216B standard). For example my
W25Q256FV returns SFDP info with revision 1.0, first one :-)
This situation leads us to requirement to try to work now
without new SFDP info. And it's implemented in the patch too.

Also I have to make an excuse about testing of SFDP rev 1.6
parser. I've tested it as good as I can using the simulation
code which is in the next patch but I don't have ability to
test it on real flash chips because I don't have a chip
complied to JESD216B with SFDP 1.6 now.

This code should be tested later.

Patched files
-------------
chipdrivers.h 
+ added functions declarations for spi4ba.c

flash.h
+ feature definitions added
+ added type field to block_eraser structure

sfdp.c
+ added compliance to JEDEC JESD216B standard (SFDP revision 1.6)
+ added parse of SFDP 4-Bytes Addressing features (probe_spi_sfdp,sfdp_fill_flash)
+ added parse of SFDP 4-Bytes Addressing Instruction Table (sfdp_parse_4ba_table)
+ added choosing of block_erasers for 4-bytes addressing (sfdp_*_uniform_eraser*)
+ added exact flash page_size recognision from 11th dword in SFDP rev 1.6

spi4ba.h
+ definitions for 16th dword bits of SFDP Basic Flash Param Table (JESD216B)
+ definitions for SFDP 4-Bytes Addressing Instruction Table (JESD216B)
+ functions declarations from spi4ba.c (same as in chipdrivers.h, just to see)

spi4ba.c
+ functions to choose block_eraser by opcode for 4-bytes addressing for sfdp.c
+ functions to select proper block_eraser (ext.reg or 4-bytes addr) for sfdp.c


Signed-off-by: Boris Baykov <dev at borisbaykov.com>, Russia, Jan 2014
---
diff -U 5 -N ./flashrom/chipdrivers.h ./flashrom-1868-4ba-7/chipdrivers.h
--- ./flashrom/chipdrivers.h    2015-01-11 01:55:15.000000000 +0300
+++ ./flashrom-1868-4ba-7/chipdrivers.h 2015-01-10 18:06:19.000000000 +0300
@@ -213,7 +213,12 @@
 int spi_nbyte_program_4ba_direct(struct flashctx *flash, unsigned int addr, const uint8_t *bytes, unsigned int len);
 int spi_nbyte_read_4ba_direct(struct flashctx *flash, unsigned int addr, uint8_t *bytes, unsigned int len);
 int spi_block_erase_21_4ba_direct(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
 int spi_block_erase_5c_4ba_direct(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
 int spi_block_erase_dc_4ba_direct(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
+erasefunc_t *spi_get_erasefn_from_opcode_4ba(uint8_t opcode);
+erasefunc_t *spi_get_erasefn_from_opcode_4ba_direct(uint8_t opcode);
+int spi_block_erase_20_4ba_selector(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
+int spi_block_erase_52_4ba_selector(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
+int spi_block_erase_d8_4ba_selector(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
 
 #endif /* !__CHIPDRIVERS_H__ */
diff -U 5 -N ./flashrom/flash.h ./flashrom-1868-4ba-7/flash.h
--- ./flashrom/flash.h  2015-01-11 01:55:15.000000000 +0300
+++ ./flashrom-1868-4ba-7/flash.h       2015-01-10 15:17:53.000000000 +0300
@@ -204,10 +204,11 @@
         * The first one that fits will be chosen. There is currently no way to
         * influence that behaviour. For testing just comment out the other
         * elements or set the function pointer to NULL.
         */
        struct block_eraser {
+               int type; /* eraser type 1,2,3 or 4 */
                struct eraseblock {
                        unsigned int size; /* Eraseblock size in bytes */
                        unsigned int count; /* Number of contiguous blocks with that size */
                } eraseblocks[NUM_ERASEREGIONS];
                /* a block_erase function should try to erase one block of size
diff -U 5 -N ./flashrom/sfdp.c ./flashrom-1868-4ba-7/sfdp.c
--- ./flashrom/sfdp.c   2015-01-11 01:55:15.000000000 +0300
+++ ./flashrom-1868-4ba-7/sfdp.c        2015-01-10 21:32:48.000000000 +0300
@@ -1,9 +1,10 @@
 /*
  * This file is part of the flashrom project.
  *
  * Copyright (C) 2011-2012 Stefan Tauner
+ * Copyright (C) 2014 Boris Baykov
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; version 2 of the License.
  *
@@ -15,17 +16,28 @@
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
  */
 
+/*   
+ *   History of changes:
+ *     05/01/2014  Added compliance to JESD216B standard and SFDP revision 1.6
+ */
+
 #include <stdint.h>
 #include <stdlib.h>
 #include <string.h>
 #include "flash.h"
 #include "spi.h"
+#include "spi4ba.h"
 #include "chipdrivers.h"
 
+/* Default four bytes addressing behavior: 
+   1) 4-Bytes Addressing Mode (FBA_USE_EXT_ADDR_REG_BY_DEFAULT not defined)
+   2) 3-bytes mode with Ext.Addr.Register (FBA_USE_EXT_ADDR_REG_BY_DEFAULT defined) */
+/* #define FBA_USE_EXT_ADDR_REG_BY_DEFAULT 1 */
+
 static int spi_sfdp_read_sfdp_chunk(struct flashctx *flash, uint32_t address, uint8_t *buf, int len)
 {
        int i, ret;
        uint8_t *newbuf;
        const unsigned char cmd[JEDEC_SFDP_OUTSIZE] = {
@@ -72,22 +84,25 @@
        }
        return ret;
 }
 
 struct sfdp_tbl_hdr {
-       uint8_t id;
+       uint16_t id;
        uint8_t v_minor;
        uint8_t v_major;
        uint8_t len;
        uint32_t ptp; /* 24b pointer */
 };
 
-static int sfdp_add_uniform_eraser(struct flashchip *chip, uint8_t opcode, uint32_t block_size)
+static int sfdp_add_uniform_eraser(struct flashchip *chip, int eraser_type, uint8_t opcode, uint32_t block_size)
 {
        int i;
        uint32_t total_size = chip->total_size * 1024;
-       erasefunc_t *erasefn = spi_get_erasefn_from_opcode(opcode);
+
+       /* choosing different eraser functions for 3-bytes and 4-bytes addressing */
+       erasefunc_t *erasefn = (chip->feature_bits & FEATURE_4BA_SUPPORT) ? 
+               spi_get_erasefn_from_opcode_4ba(opcode) : spi_get_erasefn_from_opcode(opcode);
 
        if (erasefn == NULL || total_size == 0 || block_size == 0 ||
            total_size % block_size != 0) {
                msg_cdbg("%s: invalid input, please report to "
                         "flashrom at flashrom.org\n", __func__);
@@ -109,10 +124,11 @@
                        msg_cspew("  Block Eraser %d is already occupied.\n",
                                  i);
                        continue;
                }
 
+               eraser->type = eraser_type;
                eraser->block_erase = erasefn;
                eraser->eraseblocks[0].size = block_size;
                eraser->eraseblocks[0].count = total_size/block_size;
                msg_cdbg2("  Block eraser %d: %d x %d B with opcode "
                          "0x%02x\n", i, total_size/block_size, block_size,
@@ -123,44 +139,107 @@
                  " Please report this at flashrom at flashrom.org\n",
                  __func__, i);
        return 1;
 }
 
-static int sfdp_fill_flash(struct flashchip *chip, uint8_t *buf, uint16_t len)
+/* Try of replace exist erasers to new direct 4-bytes addressing erasers
+   which can be called from ANY addressing mode: 3-byte or 4-bytes. 
+   These erasers opcodes defines in SFDP 4-byte address instruction table
+   from SFDP revision 1.6 that is defined by JESD216B standard. */
+static int sfdp_change_uniform_eraser_4ba_direct(struct flashchip *chip, int eraser_type, uint8_t opcode)
+{
+       int i;
+       erasefunc_t *erasefn = spi_get_erasefn_from_opcode_4ba_direct(opcode);
+
+       if (erasefn == NULL) {
+               msg_cdbg("%s: invalid input, please report to "
+                        "flashrom at flashrom.org\n", __func__);
+               return 1;
+       }
+
+       for (i = 0; i < NUM_ERASEFUNCTIONS; i++) {
+               struct block_eraser *eraser = &chip->block_erasers[i];
+               if (eraser->eraseblocks[0].size == 0)
+                       break;
+               if (eraser->type != eraser_type)
+                       continue;
+
+               eraser->block_erase = erasefn;
+               msg_cdbg2("  Block eraser %d (type %d) changed to opcode "
+                         "0x%02x\n", i, eraser_type, opcode);
+               return 0;
+       }
+                       
+       msg_cspew("%s: Block Eraser type %d isn't found."                 
+                 " Please report this at flashrom at flashrom.org\n",
+                 __func__, eraser_type);
+       return 1;
+}
+
+/* Parse of JEDEC SFDP Basic Flash Parameter Table */
+static int sfdp_fill_flash(struct flashchip *chip, uint8_t *buf, uint16_t len, int sfdp_rev_16)
 {
        uint8_t opcode_4k_erase = 0xFF;
        uint32_t tmp32;
        uint8_t tmp8;
        uint32_t total_size; /* in bytes */
        uint32_t block_size;
        int j;
 
        msg_cdbg("Parsing JEDEC flash parameter table... ");
-       if (len != 9 * 4 && len != 4 * 4) {
+       if (len != 16 * 4 && len != 9 * 4 && len != 4 * 4) {
                msg_cdbg("%s: len out of spec\n", __func__);
                return 1;
        }
        msg_cdbg2("\n");
-       
+
        /* 1. double word */
        tmp32 =  ((unsigned int)buf[(4 * 0) + 0]);
        tmp32 |= ((unsigned int)buf[(4 * 0) + 1]) << 8;
        tmp32 |= ((unsigned int)buf[(4 * 0) + 2]) << 16;
        tmp32 |= ((unsigned int)buf[(4 * 0) + 3]) << 24;
 
+       chip->feature_bits = 0;
+
        tmp8 = (tmp32 >> 17) & 0x3;
        switch (tmp8) {
        case 0x0:
                msg_cdbg2("  3-Byte only addressing.\n");
                break;
        case 0x1:
                msg_cdbg2("  3-Byte (and optionally 4-Byte) addressing.\n");
+#ifndef FBA_USE_EXT_ADDR_REG_BY_DEFAULT
+               /* assuming that 4-bytes addressing mode can be entered
+                  by CMD B7h preceded with WREN and all read, write and 
+                  erase commands will be able to receive 4-bytes address */
+               chip->feature_bits |= FEATURE_4BA_SUPPORT;
+               chip->four_bytes_addr_funcs.enter_4ba = spi_enter_4ba_b7_we;
+               chip->four_bytes_addr_funcs.program_byte = spi_byte_program_4ba;
+               chip->four_bytes_addr_funcs.program_nbyte = spi_nbyte_program_4ba;
+               chip->four_bytes_addr_funcs.read_nbyte = spi_nbyte_read_4ba;
+#else /* if FBA_USE_EXT_ADDR_REG_BY_DEFAULT defined */
+               /* assuming that 4-bytes addressing is working using 
+                  extended address register which can be assigned
+                  throught CMD C5h and then all commands will use
+                  3-bytes address as usual */
+               chip->feature_bits |= ( FEATURE_4BA_SUPPORT | 
+                                       FEATURE_4BA_EXTENDED_ADDR_REG );
+               chip->four_bytes_addr_funcs.enter_4ba = NULL;
+               chip->four_bytes_addr_funcs.program_byte = spi_byte_program_4ba_ereg;
+               chip->four_bytes_addr_funcs.program_nbyte = spi_nbyte_program_4ba_ereg;
+               chip->four_bytes_addr_funcs.read_nbyte = spi_nbyte_read_4ba_ereg;
+#endif /* FBA_USE_EXT_ADDR_REG_BY_DEFAULT */
                break;
        case 0x2:
-               msg_cdbg("  4-Byte only addressing (not supported by "
-                        "flashrom).\n");
-               return 1;
+               msg_cdbg2("  4-Byte only addressing.\n");
+               chip->feature_bits |= ( FEATURE_4BA_SUPPORT | 
+                                       FEATURE_4BA_ONLY );
+               chip->four_bytes_addr_funcs.enter_4ba = NULL;
+               chip->four_bytes_addr_funcs.program_byte = spi_byte_program_4ba;
+               chip->four_bytes_addr_funcs.program_nbyte = spi_nbyte_program_4ba;
+               chip->four_bytes_addr_funcs.read_nbyte = spi_nbyte_read_4ba;
+               break;
        default:
                msg_cdbg("  Required addressing mode (0x%x) not supported.\n",
                         tmp8);
                return 1;
        }
@@ -168,21 +247,21 @@
        msg_cdbg2("  Status register is ");
        if (tmp32 & (1 << 3)) {
                msg_cdbg2("volatile and writes to the status register have to "
                          "be enabled with ");
                if (tmp32 & (1 << 4)) {
-                       chip->feature_bits = FEATURE_WRSR_WREN;
+                       chip->feature_bits |= FEATURE_WRSR_WREN;
                        msg_cdbg2("WREN (0x06).\n");
                } else {
-                       chip->feature_bits = FEATURE_WRSR_EWSR;
+                       chip->feature_bits |= FEATURE_WRSR_EWSR;
                        msg_cdbg2("EWSR (0x50).\n");
                }
        } else {
                msg_cdbg2("non-volatile and the standard does not allow "
                          "vendors to tell us whether EWSR/WREN is needed for "
                          "status register writes - assuming EWSR.\n");
-                       chip->feature_bits = FEATURE_WRSR_EWSR;
+                       chip->feature_bits |= FEATURE_WRSR_EWSR;
                }
 
        msg_cdbg2("  Write chunk size is ");
        if (tmp32 & (1 << 2)) {
                msg_cdbg2("at least 64 B.\n");
@@ -212,56 +291,238 @@
                return 1;
        }
        total_size = ((tmp32 & 0x7FFFFFFF) + 1) / 8;
        chip->total_size = total_size / 1024;
        msg_cdbg2("  Flash chip size is %d kB.\n", chip->total_size);
+       
        if (total_size > (1 << 24)) {
-               msg_cdbg("Flash chip size is bigger than what 3-Byte addressing "
-                        "can access.\n");
-               return 1;
+               if(!sfdp_rev_16) {
+                       msg_cdbg("Flash chip size is bigger than what 3-Byte addressing "
+                                "can access but chip's SFDP revision is lower than 1.6 "
+                                "\nConsequently 4-bytes addressing can NOT be "
+                                "properly configured using current SFDP information.\n");
+#ifndef FBA_USE_EXT_ADDR_REG_BY_DEFAULT
+                       msg_cdbg("Assuming that 4-bytes addressing mode can be "
+                                "entered by CMD B7h with WREN.\n");
+#else
+                       msg_cdbg("Assuming that 4-bytes addressing is working via "
+                                "an Extended Address Register which can be written "
+                                "by CMD C5h.\n");
+#endif
+               }
        }
 
-       if (opcode_4k_erase != 0xFF)
-               sfdp_add_uniform_eraser(chip, opcode_4k_erase, 4 * 1024);
-
        /* FIXME: double words 3-7 contain unused fast read information */
 
-       if (len == 4 * 4) {
+       if (len < 9 * 4) {
                msg_cdbg("  It seems like this chip supports the preliminary "
                         "Intel version of SFDP, skipping processing of double "
                         "words 3-9.\n");
+
+               /* in the case if BFPT erasers array is not present
+                  trying to add default 4k-eraser */
+               if (opcode_4k_erase != 0xFF)
+                       sfdp_add_uniform_eraser(chip, 0, opcode_4k_erase, 4 * 1024);
+
                goto done;
        }
 
-       /* 8. double word */
+       /* 8. double word & 9. double word */
+       /* for by block eraser types, from Type 1 to Type 4 */
        for (j = 0; j < 4; j++) {
                /* 7 double words from the start + 2 bytes for every eraser */
                tmp8 = buf[(4 * 7) + (j * 2)];
-               msg_cspew("   Erase Sector Type %d Size: 0x%02x\n", j + 1,
-                         tmp8);
+               msg_cspew("   Erase Sector (Type %d) Size: 0x%02x\n", j + 1, tmp8);
                if (tmp8 == 0) {
-                       msg_cspew("  Erase Sector Type %d is unused.\n", j);
+                       msg_cspew("  Erase Sector (Type %d) is unused.\n", j + 1);
                        continue;
                }
                if (tmp8 >= 31) {
-                       msg_cdbg2("  Block size of erase Sector Type %d (2^%d) "
-                                "is too big for flashrom.\n", j, tmp8);
+                       msg_cdbg2("  Block size of erase Sector (Type %d): 2^%d "
+                                "is too big for flashrom.\n", j + 1, tmp8);
                        continue;
                }
                block_size = 1 << (tmp8); /* block_size = 2 ^ field */
 
                tmp8 = buf[(4 * 7) + (j * 2) + 1];
-               msg_cspew("   Erase Sector Type %d Opcode: 0x%02x\n", j + 1,
-                         tmp8);
-               sfdp_add_uniform_eraser(chip, tmp8, block_size);
+               msg_cspew("   Erase Sector (Type %d) Opcode: 0x%02x\n", j + 1, tmp8);
+               sfdp_add_uniform_eraser(chip, j + 1, tmp8, block_size);
+       }
+
+       /* Trying to add the default 4k eraser after parsing erasers info.
+          In most cases this eraser has already been added before. */
+       if (opcode_4k_erase != 0xFF)
+               sfdp_add_uniform_eraser(chip, 0, opcode_4k_erase, 4 * 1024);
+
+       /* Trying to read the exact page size if it's available */
+       if (len >= 11 * 4) {
+               /* 11. double word */
+               tmp8 = buf[(4*10) + 0] >> 4; /* get upper nibble of LSB of 11th dword */
+               chip->page_size = 1 << tmp8; /* page_size = 2 ^ N */
+               msg_cdbg2("  Page size is %d B.\n", chip->page_size);
+       }
+
+       /* If the chip doesn't support 4-bytes addressing mode we don't have 
+          to read and analyze 16th DWORD of Basic Flash Parameter Table */
+       if (!(chip->feature_bits & FEATURE_4BA_SUPPORT))
+               goto done;
+
+       /* In the case if the chip is working in 4-bytes addressing mode ONLY we 
+          don't have to read and analyze 16th DWORD of Basic Flash Parameter Table
+          because we don't have to know how to switch to 4-bytes mode and back 
+          when we are already in 4-bytes mode permanently. */
+       if (chip->feature_bits & FEATURE_4BA_ONLY)
+               goto done;
+
+       /* If the SFDP revision supported by the chip is lower that 1.6
+          we can not read and analyze 16th DWORD of Basic Flash Parameter Table.
+          Using defaults by FBA_USE_EXT_ADDR_REG_BY_DEFAULT define. */
+       if(!sfdp_rev_16)
+               goto done;
+
+       if (len < 16 * 4) {
+               msg_cdbg("%s: len of BFPT is out of spec\n", __func__);
+               msg_cerr("ERROR: Unable read 4-bytes addressing parameters.\n");
+               return 1;
+       }
+
+       /* 16. double word */
+       tmp32 =  ((unsigned int)buf[(4 * 15) + 0]);
+       tmp32 |= ((unsigned int)buf[(4 * 15) + 1]) << 8;
+       tmp32 |= ((unsigned int)buf[(4 * 15) + 2]) << 16;
+       tmp32 |= ((unsigned int)buf[(4 * 15) + 3]) << 24;
+
+       /* Parsing 16th DWORD of Basic Flash Parameter Table according to JESD216B */
+
+       if(tmp32 & JEDEC_BFPT_DW16_ENTER_B7) { 
+               msg_cdbg2("  Enter 4-bytes addressing mode by CMD B7h\n");
+               chip->four_bytes_addr_funcs.enter_4ba = spi_enter_4ba_b7;
+               chip->four_bytes_addr_funcs.program_byte = spi_byte_program_4ba;
+               chip->four_bytes_addr_funcs.program_nbyte = spi_nbyte_program_4ba;
+               chip->four_bytes_addr_funcs.read_nbyte = spi_nbyte_read_4ba;
+               /* if can go to 4BA-mode -> not need to use Ext.Addr.Reg */
+               chip->feature_bits &= ~FEATURE_4BA_EXTENDED_ADDR_REG; 
+       }
+       else if(tmp32 & JEDEC_BFPT_DW16_ENTER_B7_WE) { 
+               msg_cdbg2("  Enter 4-bytes addressing mode by CMD B7h with WREN\n");
+               chip->four_bytes_addr_funcs.enter_4ba = spi_enter_4ba_b7_we;
+               chip->four_bytes_addr_funcs.program_byte = spi_byte_program_4ba;
+               chip->four_bytes_addr_funcs.program_nbyte = spi_nbyte_program_4ba;
+               chip->four_bytes_addr_funcs.read_nbyte = spi_nbyte_read_4ba;
+               /* if can go to 4BA-mode -> not need to use Ext.Addr.Reg */
+               chip->feature_bits &= ~FEATURE_4BA_EXTENDED_ADDR_REG; 
+       }
+       else if(tmp32 & JEDEC_BFPT_DW16_ENTER_EXTENDED_ADDR_REG) { 
+               msg_cdbg2("  Extended Address Register used for 4-bytes addressing\n");
+               chip->four_bytes_addr_funcs.enter_4ba = NULL;
+               chip->four_bytes_addr_funcs.program_byte = spi_byte_program_4ba_ereg;
+               chip->four_bytes_addr_funcs.program_nbyte = spi_nbyte_program_4ba_ereg;
+               chip->four_bytes_addr_funcs.read_nbyte = spi_nbyte_read_4ba_ereg;
+               /* this flag signals to all '*_selector' functions 
+                  to use Ext.Addr.Reg while erase operations */
+               chip->feature_bits |= FEATURE_4BA_EXTENDED_ADDR_REG;
+       }
+       else {
+               msg_cerr("ERROR: Unable to use 4-bytes addressing for this chip.\n"
+                        " Please report this at flashrom at flashrom.org\n\n");
+               return 1;
        }
 
 done:
        msg_cdbg("done.\n");
        return 0;
 }
 
+/* Parse of JEDEC SFDP 4-byte address instruction table. From SFDP revision 1.6 only.
+   This parsing shoukd be called after basic flash parameter table is parsed. */
+static int sfdp_parse_4ba_table(struct flashchip *chip, uint8_t *buf, uint16_t len)
+{
+       uint32_t tmp32;
+       uint8_t tmp8;
+       int j, direct_erasers;
+       int direct_count;
+
+       msg_cdbg("Parsing JEDEC 4-byte address instuction table... ");
+       if (len != 2 * 4) {
+               msg_cdbg("%s: len out of spec\n", __func__);
+               return 1;
+       }
+       msg_cdbg2("\n");
+
+       /* 1. double word */
+       tmp32 =  ((unsigned int)buf[(4 * 0) + 0]);
+       tmp32 |= ((unsigned int)buf[(4 * 0) + 1]) << 8;
+       tmp32 |= ((unsigned int)buf[(4 * 0) + 2]) << 16;
+       tmp32 |= ((unsigned int)buf[(4 * 0) + 3]) << 24;
+
+       direct_count = 0;
+
+       if(tmp32 & JEDEC_4BAIT_READ_SUPPORT) { 
+               msg_cdbg2("  Found Read CMD 13h with 4-bytes address\n");
+               chip->four_bytes_addr_funcs.read_nbyte = spi_nbyte_read_4ba_direct;
+               /* read function has changed to direct 4-bytes function,
+                  so entering 4-bytes mode isn't required for reading bytes */
+               chip->feature_bits |= FEATURE_4BA_DIRECT_READ;
+               direct_count++;
+       }
+
+       if(tmp32 & JEDEC_4BAIT_PROGRAM_SUPPORT) {  
+               msg_cdbg2("  Found Write CMD 12h with 4-bytes address\n");
+               chip->four_bytes_addr_funcs.program_byte = spi_byte_program_4ba_direct;
+               chip->four_bytes_addr_funcs.program_nbyte = spi_nbyte_program_4ba_direct;
+               /* write (program) functions have changed to direct 4-bytes functions,
+                  so entering 4-bytes mode isn't required for writing bytes */
+               chip->feature_bits |= FEATURE_4BA_DIRECT_WRITE;
+               direct_count++;
+       }
+
+       direct_erasers = 0;
+
+       /* 2. double word */
+       for (j = 0; j < 4; j++) {
+               if(!(tmp32 & (JEDEC_4BAIT_ERASE_TYPE_1_SUPPORT << j)))
+                       continue;
+
+               tmp8 = buf[(4 * 1) + j];
+
+               msg_cdbg2("  Found Erase (type %d) CMD %02Xh with 4-bytes address\n", j + 1, tmp8);
+
+               if(tmp8 == 0xFF) {
+                       msg_cdbg("%s: Eraser (type %d) is supported, but opcode = 0xFF\n"
+                                "  Please report to flashrom at flashrom.org\n\n", __func__, j + 1);
+                       continue;
+               }
+               
+               /* try of replacing the eraser with direct 4-bytes eraser */
+               if(!sfdp_change_uniform_eraser_4ba_direct(chip, j + 1, tmp8))
+                       direct_erasers++;
+       }
+
+       for (j = 0; j < NUM_ERASEFUNCTIONS; j++) {
+               if (chip->block_erasers[j].eraseblocks[0].size == 0)
+                       break;
+       }
+
+       if( j == direct_erasers ) {
+               /* if all erasers have been changed to direct 4-bytes ones,
+                  then we don't have to enter 4-bytes mode for erase */
+               chip->feature_bits |= FEATURE_4BA_ALL_ERASERS_DIRECT;
+               direct_count++;
+               msg_cspew("All erasers have changed to direct ones.\n");
+       }
+
+       if( direct_count == 3 ) {
+               /* if all read/write/erase functions are direct 4-bytes now,
+                  then we don't have to use extended address register */
+               chip->feature_bits &= ~FEATURE_4BA_EXTENDED_ADDR_REG;
+               msg_cspew("All read/write/erase functions have changed to direct ones.\n");
+       }
+
+       msg_cdbg("done.\n");
+       return 0;
+}
+
 int probe_spi_sfdp(struct flashctx *flash)
 {
        int ret = 0;
        uint8_t buf[8];
        uint32_t tmp32;
@@ -269,10 +530,11 @@
        /* need to limit the table loop by comparing i to uint8_t nph hence: */
        uint16_t i;
        struct sfdp_tbl_hdr *hdrs;
        uint8_t *hbuf;
        uint8_t *tbuf;
+       int sfdp_rev_16 = 0;
 
        if (spi_sfdp_read_sfdp(flash, 0x00, buf, 4)) {
                msg_cdbg("Receiving SFDP signature failed.\n");
                return 0;
        }
@@ -296,10 +558,19 @@
        if (buf[1] != 0x01) {
                msg_cdbg("The chip supports an unknown version of SFDP. "
                          "Aborting SFDP probe!\n");
                return 0;
        }
+
+       /* JEDEC JESD216B defines SFDP revision 1.6 and includes:
+          1) 16 dwords in Basic Flash Parameter Table
+          2) 16th dword has information how to enter 
+               and exit 4-bytes addressing mode
+          3) 4-Bytes Address Instruction Table with ID 0xFF84
+       */
+       sfdp_rev_16 = (buf[1] == 1 && buf[0] >= 6) || buf[1] > 1;
+
        nph = buf[2];
        msg_cdbg2("SFDP number of parameter headers is %d (NPH = %d).\n",
                  nph + 1, nph);
 
        /* Fetch all parameter headers, even if we don't use them all (yet). */
@@ -314,17 +585,18 @@
                goto cleanup_hdrs;
        }
 
        for (i = 0; i <= nph; i++) {
                uint16_t len;
-               hdrs[i].id = hbuf[(8 * i) + 0];
+               hdrs[i].id = hbuf[(8 * i) + 0]; /* ID LSB read */
                hdrs[i].v_minor = hbuf[(8 * i) + 1];
                hdrs[i].v_major = hbuf[(8 * i) + 2];
                hdrs[i].len = hbuf[(8 * i) + 3];
                hdrs[i].ptp = hbuf[(8 * i) + 4];
                hdrs[i].ptp |= ((unsigned int)hbuf[(8 * i) + 5]) << 8;
                hdrs[i].ptp |= ((unsigned int)hbuf[(8 * i) + 6]) << 16;
+               hdrs[i].id |= ((uint16_t)hbuf[(8 * i) + 7]) << 8; /* ID MSB read */
                msg_cdbg2("\nSFDP parameter table header %d/%d:\n", i, nph);
                msg_cdbg2("  ID 0x%02x, version %d.%d\n", hdrs[i].id,
                          hdrs[i].v_major, hdrs[i].v_minor);
                len = hdrs[i].len * 4;
                tmp32 = hdrs[i].ptp;
@@ -366,29 +638,43 @@
                        }
                }
                msg_cspew("\n");
 
                if (i == 0) { /* Mandatory JEDEC SFDP parameter table */
-                       if (hdrs[i].id != 0)
+                       if (hdrs[i].id != JEDEC_BFPT_ID)
                                msg_cdbg("ID of the mandatory JEDEC SFDP "
-                                        "parameter table is not 0 as demanded "
-                                        "by JESD216 (warning only).\n");
-
+                                        "parameter table is not 0xFF00 as"
+                                        "demanded by JESD216 (warning only)."
+                                        "\n");
                        if (hdrs[i].v_major != 0x01) {
                                msg_cdbg("The chip contains an unknown "
                                          "version of the JEDEC flash "
                                          "parameters table, skipping it.\n");
-                       } else if (len != 9 * 4 && len != 4 * 4) {
+                       } else if (len != 16 * 4 && len != 9 * 4 && len != 4 * 4) {
                                msg_cdbg("Length of the mandatory JEDEC SFDP "
                                         "parameter table is wrong (%d B), "
                                         "skipping it.\n", len);
-                       } else if (sfdp_fill_flash(flash->chip, tbuf, len) == 0)
+                       } else if (sfdp_fill_flash(flash->chip, tbuf, len, sfdp_rev_16) == 0)
                                ret = 1;
                }
+               /* JEDEC SFDP 4-byte address instruction table. From SFDP revision 1.6 only.
+                  This parsing shoukd be called after basic flash parameter table is parsed. */
+               else if(sfdp_rev_16 && hdrs[i].id == JEDEC_4BAIT_ID && ret == 1) {
+                       if (hdrs[i].v_major != 0x01) {
+                               msg_cdbg("The chip contains an unknown "
+                                         "version of the JEDEC 4-bytes "
+                                         "address instruction table, "
+                                         "skipping it.\n");
+                       }
+                       else {  /* no result check because this table is optional */
+                               sfdp_parse_4ba_table(flash->chip, tbuf, len);
+                       }
+               }
                free(tbuf);
        }
 
 cleanup_hdrs:
        free(hdrs);
        free(hbuf);
        return ret;
 }
+
diff -U 5 -N ./flashrom/spi4ba.c ./flashrom-1868-4ba-7/spi4ba.c
--- ./flashrom/spi4ba.c 2015-01-11 01:55:15.000000000 +0300
+++ ./flashrom-1868-4ba-7/spi4ba.c      2015-01-10 18:23:12.000000000 +0300
@@ -916,5 +916,105 @@
        while (spi_read_status_register(flash) & SPI_SR_WIP)
                programmer_delay(100 * 1000);
        /* FIXME: Check the status register for errors. */
        return 0;
 }
+
+/* Selector for 4k eraser that chooses between 4-bytes addressing mode
+   and use of Extended Address Register from 3-bytes addressing mode */
+int spi_block_erase_20_4ba_selector(struct flashctx *flash, unsigned int addr,
+                      unsigned int blocklen)
+{
+       msg_trace("-> %s\n", __func__);
+
+       return (flash->chip->feature_bits & FEATURE_4BA_EXTENDED_ADDR_REG) ?
+               spi_block_erase_20_4ba_ereg(flash, addr, blocklen) :
+               spi_block_erase_20_4ba(flash, addr, blocklen);
+}
+
+/* Selector for 32k eraser that chooses between 4-bytes addressing mode
+   and use of Extended Address Register from 3-bytes addressing mode */
+int spi_block_erase_52_4ba_selector(struct flashctx *flash, unsigned int addr,
+                      unsigned int blocklen)
+{
+       msg_trace("-> %s\n", __func__);
+
+       return (flash->chip->feature_bits & FEATURE_4BA_EXTENDED_ADDR_REG) ?
+               spi_block_erase_52_4ba_ereg(flash, addr, blocklen) :
+               spi_block_erase_52_4ba(flash, addr, blocklen);
+}
+
+/* Selector for 64k eraser that chooses between 4-bytes addressing mode
+   and use of Extended Address Register from 3-bytes addressing mode */
+int spi_block_erase_d8_4ba_selector(struct flashctx *flash, unsigned int addr,
+                      unsigned int blocklen)
+{
+       msg_trace("-> %s\n", __func__);
+
+       return (flash->chip->feature_bits & FEATURE_4BA_EXTENDED_ADDR_REG) ?
+               spi_block_erase_d8_4ba_ereg(flash, addr, blocklen) :
+               spi_block_erase_d8_4ba(flash, addr, blocklen);
+}
+
+/* Chooser for erase function by instruction opcode for block eraser instructions
+   to work with 4-bytes addressing flash chips. This chooser is called from sfdp.c
+   during parse of 8th & 9th dwords of SFDP Basic Flash Parameter Table */
+erasefunc_t *spi_get_erasefn_from_opcode_4ba(uint8_t opcode)
+{
+       msg_trace("-> %s\n", __func__);
+
+       switch(opcode){
+       case 0xff:
+       case 0x00:
+               /* Not specified, assuming "not supported". */
+               return NULL;
+       case 0x20:
+               return &spi_block_erase_20_4ba_selector; /* selector */
+       case 0x52:
+               return &spi_block_erase_52_4ba_selector; /* selector */
+       case 0x60:
+               return &spi_block_erase_60;
+       case 0x62:
+               return &spi_block_erase_62;
+       case 0xc7:
+               return &spi_block_erase_c7;
+       case 0xd8:
+               return &spi_block_erase_d8_4ba_selector; /* selector */
+       case 0x50:
+       case 0x81:
+       case 0xc4:
+       case 0xd7:
+       case 0xdb:
+               msg_cinfo("%s: erase opcode (0x%02x) doesn't have its 4-bytes addressing version."
+                         " Please report this at flashrom at flashrom.org\n", __func__, opcode);
+               return NULL;
+       default:
+               msg_cinfo("%s: unknown erase opcode (0x%02x). Please report "
+                         "this at flashrom at flashrom.org\n", __func__, opcode);
+               return NULL;
+       }
+}
+
+/* Chooser for erase function by instruction opcode for block eraser instructions
+   which can be used from ANY mode (3-bytes or 4-bytes). This chooser is called
+   from sfdp.c during parse of SFDP 4-Bytes Address Instruction Table (JESD216B) */
+erasefunc_t *spi_get_erasefn_from_opcode_4ba_direct(uint8_t opcode)
+{
+       msg_trace("-> %s\n", __func__);
+
+       switch(opcode){
+       case 0xff:
+       case 0x00:
+               /* Not specified, assuming "not supported". */
+               return NULL;
+       case 0x21:
+               return &spi_block_erase_21_4ba_direct;                  /* direct */
+       case 0x5C:
+               return &spi_block_erase_5c_4ba_direct;                  /* direct */
+       case 0xdc:
+               return &spi_block_erase_dc_4ba_direct;                  /* direct */
+       default:
+               msg_cinfo("%s: unknown erase opcode (0x%02x). Please report "
+                         "this at flashrom at flashrom.org\n", __func__, opcode);
+               return NULL;
+       }
+}
diff -U 5 -N ./flashrom/spi4ba.h ./flashrom-1868-4ba-7/spi4ba.h
--- ./flashrom/spi4ba.h 2015-01-11 01:55:15.000000000 +0300
+++ ./flashrom-1868-4ba-7/spi4ba.h      2015-01-10 18:18:38.000000000 +0300
@@ -74,10 +74,44 @@
    From ANY mode (3-bytes or 4-bytes) it works with 4-byte address */
 #define JEDEC_BE_DC_4BA                0xdc
 #define JEDEC_BE_DC_4BA_OUTSIZE        0x05
 #define JEDEC_BE_DC_4BA_INSIZE 0x00
 
+/* JEDEC Basic Flash Parameters Table definition */
+#define JEDEC_BFPT_ID                                  0xFF00
+
+/* JEDEC Basic Flash Parameters Table 16th dword according to JESD216B */
+/* 16th dword of BFPT, bits 24:31 (Enter 4-Byte Addressing) */
+#define JEDEC_BFPT_DW16_ENTER_B7                       (1UL << 24)
+#define JEDEC_BFPT_DW16_ENTER_B7_WE                    (1UL << 25)
+#define JEDEC_BFPT_DW16_ENTER_EXTENDED_ADDR_REG                (1UL << 26)
+#define JEDEC_BFPT_DW16_ENTER_BANK_ADDR_REG_EN_BIT     (1UL << 27)
+#define JEDEC_BFPT_DW16_ENTER_NV_CONFIG_REG            (1UL << 28)
+#define JEDEC_BFPT_DW16_VENDOR_SET                     (1UL << 29)
+#define JEDEC_BFPT_DW16_4_BYTES_ADDRESS_ONLY           (1UL << 30)
+#define JEDEC_BFPT_DW16_ENTER_RESERVED                 (1UL << 31)
+/* 16th dword of BFPT, bits 14:23 (Exit 4-Byte Addressing) */
+#define JEDEC_BFPT_DW16_EXIT_E9                                (1UL << 14)
+#define JEDEC_BFPT_DW16_EXIT_E9_WE                     (1UL << 15)
+#define JEDEC_BFPT_DW16_EXIT_EXTENDED_ADDR_REG         (1UL << 16)
+#define JEDEC_BFPT_DW16_EXIT_BANK_ADDR_REG_EN_BIT      (1UL << 17)
+#define JEDEC_BFPT_DW16_EXIT_NV_CONFIG_REG             (1UL << 18)
+#define JEDEC_BFPT_DW16_EXIT_HARD_RESET                (1UL << 19)
+#define JEDEC_BFPT_DW16_EXIT_SOFT_RESET                (1UL << 20)
+#define JEDEC_BFPT_DW16_EXIT_POWER_CYCLE               (1UL << 21)
+#define JEDEC_BFPT_DW16_EXIT_RESERVED_1                (1UL << 22)
+#define JEDEC_BFPT_DW16_EXIT_RESERVED_2                (1UL << 23)
+
+/* JEDEC 4-Bytes Addressing Table 1st dword according to JESD216B */
+#define JEDEC_4BAIT_ID                                         0xFF84
+#define JEDEC_4BAIT_READ_SUPPORT                       (1UL << 0)
+#define JEDEC_4BAIT_PROGRAM_SUPPORT                    (1UL << 6)
+#define JEDEC_4BAIT_ERASE_TYPE_1_SUPPORT               (1UL << 9)
+#define JEDEC_4BAIT_ERASE_TYPE_2_SUPPORT               (1UL << 10)
+#define JEDEC_4BAIT_ERASE_TYPE_3_SUPPORT               (1UL << 11)
+#define JEDEC_4BAIT_ERASE_TYPE_4_SUPPORT               (1UL << 12)
+
 /* enter 4-bytes addressing mode */
 int spi_enter_4ba_b7(struct flashctx *flash);
 int spi_enter_4ba_b7_we(struct flashctx *flash);
 
 /* read/write flash bytes in 4-bytes addressing mode */
@@ -108,7 +142,16 @@
 /* erase flash bytes with 4-bytes address from any mode (3-byte or 4-byte) */
 int spi_block_erase_21_4ba_direct(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
 int spi_block_erase_5c_4ba_direct(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
 int spi_block_erase_dc_4ba_direct(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
 
+/* erase functions choosers for 4-bytes addressing mode */
+erasefunc_t *spi_get_erasefn_from_opcode_4ba(uint8_t opcode);
+erasefunc_t *spi_get_erasefn_from_opcode_4ba_direct(uint8_t opcode);
+
+/* selection of erase function between 4-bytes addressing mode and use of extended address register */
+int spi_block_erase_20_4ba_selector(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
+int spi_block_erase_52_4ba_selector(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
+int spi_block_erase_d8_4ba_selector(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
+
 
 #endif /* __SPI_4BA_H__ */
-------------- next part --------------
A non-text attachment was scrubbed...
Name: flashrom-r1868-4ba-part-7.patch.tar.bz2
Type: application/octet-stream
Size: 8101 bytes
Desc: not available
URL: <http://www.flashrom.org/pipermail/flashrom/attachments/20150111/c3c98b3c/attachment.obj>


More information about the flashrom mailing list