[flashrom] [PATCH 1/2] Read/erase/program 4-bytes addressing SPI flash chips 32MB+ for build 0.9.7-r1861

Boris Baykov dev at borisbaykov.com
Fri Jan 9 20:22:05 CET 2015


Current patch is for the last 0.9.7-r1861 build taken by SVN
from svn://flashrom.org. The patch is made by SVN diff.

Two same patches for different builds (one patch per letter)
------------------------------------------------------------
[1/2] Patch for Flashrom 0.9.7 (build 1861) by SVN diff
[2/2] Patch for last 0.9.7 release (build 1711) by Linux diff

Brief description
-----------------
This patch adds ability to read, write and erase flash chips
which require 4-bytes (32-bit) addressing to access to them.
These are 32MB (256Mb) and larger new flash chips. Flashrom
with this patch can support and program all (or most of all)
of them. Besides of manually definable chips in flashchips.c
this patch adds compliance to new JEDEC JESD216B standard
which describes SFDP revision 1.6 procedure to read flash
chip 4-bytes addressing details.

Full description
----------------
This patch includes code for three types of 4-byte addressing:

1. Flash chip can be switched to 4-bytes addressing mode and
then all read/erase/program instructions will be switched from
3-bytes mode to 4-bytes mode. So, well known instructions like
03h (Read), 02h (Program) and 20h,52h,D8h (Erase) are becoming
one byte longer and accept 4-bytes address instead of 3-bytes.
4-bytes addressing mode is entered by the instruction B7h with 
preceding Write Enable (WREN). This is default method. 

2. Also Flash chip data with addresses more than 24-bit field
can address may be accessed by use of Extended Address Register
that has 1-byte size and stores high byte of 32-bit address.
So, we read flash from old 3-bytes addressing mode and write
high byte of address to special register. Then we have access
to full memory of a chip. Some chips may support this method
only.

3. Also some new commands avalable and implemented. Large size
flash chips support special instructions to use 4-bytes address
directly from 3-bytes addressing mode and without do switching
to 4-bytes mode. There are 13h (4BA Read), 12h (4BA Program) 
and 21h,5Ch,DCh (4BA Erase), correspondingly. However not all
these commands are supported by all large flash chips. Some
chips support 13h only, some 13h,12h,21h and DCh, but not 5Ch. 
This depends on the manufacturer of the chip.

The patch adds code for all 3 types of 4-bytes address access
and the exact method should be choosen by person who will
manage to add new large chips to flashchips.c source file.

I've added one new flash chip: Winbond W25Q256FV (32MB)
because this is the only chip I have now for testing.

Besides of manual including of new chips to Flashrom we may
use SFDP procedure to discover parameters of the exact flash
chip. More than a year before 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 thing 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.

To test my parser code for SFDP revision 1.6 (from JESD216B)
I've added some simulation code to sfdp.c. This code builds
fake SFDP 1.6 tables in memory and passes them to the SFDP
parser. Surely this simulation code is switched off by default
and can be activated via hidden define on the top of sfdp.c

Also I've added progress visualization for read, erase and
write operations. It's turned out that seeing progress is
essential for reading and especially writing 32 MB оf data
via SPI. The operation can take more then 10 minutes on
15 MHz frequency of SPI. So, it's good to see its progress.
I've added percents and slightly modified cli_output.c to
send percents to screen only but not to logfile.

Testing results
---------------
Both patches are tested with Winbond W25Q256FV flash chip
using Olimex ARM-USB-OCD-H programmer.

Read, Erase and Program functions are fully tested for
4-bytes addressing type 1 (4-bytes mode), type 2 (extended
addr. register) and partially tested for type 3 (new 4-bytes
instructions with 4-bytes address). My W25Q256FV has support
for 4BA_Read (13h) only, but doesn't support 4BA_Program (12h)
and 4BA_Erase instructions. So, direct 4BA program and erase
should be tested after.

Also I should make an excuse about testing of SFDP rev 1.6
parser. I've tested it as good as I can using the simulation
code I described above but I'm not able to test it on real
flash chips because I don't have a chip complied to JESD216B
with SFDP 1.6 now. This should be tested later too.

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

cli_output.c 
- print() patched to skip strings which are starting from '\b'
to prevent writing progress percents to logfile

flash.h
- feature definitions added
- added set of 4-bytes address functions to flashchip structure definition
- added type field to block_eraser structure
- added some definitions for progress visialization

flashchips.c 
- added definition for Winbond W25Q256BV/W25Q256FV chips

flashrom.c
- added switch to 4-bytes addressing more for chips which support it
- added progress visualization for erase/write (essensial for 32MB+ chips)
- changed in address print %06x to %08x to support 32MB+ chips
- added line to the flashrom's banner about this patch (temporary)

Makefile 
- added spi4ba.c

serprog.c 
- added 4-bytes addressing spi_nbyte_read call to serprog_spi_read

spi.c
- fixed flash chip size check in spi_chip_read

spi25.c
- added 4-bytes addressing spi_nbyte_read call to spi_read_chunked
- added 4-bytes addressing spi_nbyte_program call to spi_write_chunked
- added 4-bytes addressing spi_byte_program call to spi_chip_write_1
- added progress visualization for read operation (essensial for 32MB+ chips)

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
- added fix for Micron chips to read 16th dword stating from SFDP revision 1.5
- added simulation of JESD216B for any flash chips (just for testing)

Added files
-----------
spi4ba.h
- definitions for 4-bytes addressing JEDEC commands
- 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 for enter 4-bytes addressing mode
- functions for write Extended Address Register
- functions for read/write/erase in 4-bytes addressing mode
- functions for read/write/erase with Extended Address Register
- functions for read/write/erase directly with 4-bytes address (from any mode)
- 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
---
Index: Makefile
===================================================================
--- Makefile        (revision 1861)
+++ Makefile        (working copy)
@@ -355,11 +355,11 @@
###############################################################################
# Flash chip drivers and bus support infrastructure.

CHIP_OBJS = jedec.o stm50.o w39.o w29ee011.o \
    sst28sf040.o 82802ab.o \
-        sst49lfxxxc.o sst_fwhub.o flashchips.o spi.o spi25.o spi25_statusreg.o \
+        sst49lfxxxc.o sst_fwhub.o flashchips.o spi.o spi25.o spi25_statusreg.o spi4ba.o \
    opaque.o sfdp.o en29lv640b.o at45db.o

###############################################################################
# Library code.

Index: chipdrivers.h
===================================================================
--- chipdrivers.h        (revision 1861)
+++ chipdrivers.h        (working copy)
@@ -192,6 +192,33 @@

/* en29lv640b.c */
int probe_en29lv640b(struct flashctx *flash);
int write_en29lv640b(struct flashctx *flash, const uint8_t *buf, unsigned int start, unsigned int len);

+/* spi4ba.c */
+int spi_enter_4ba_b7(struct flashctx *flash);
+int spi_enter_4ba_b7_we(struct flashctx *flash);
+int spi_byte_program_4ba(struct flashctx *flash, unsigned int addr, uint8_t databyte);
+int spi_nbyte_program_4ba(struct flashctx *flash, unsigned int addr, const uint8_t *bytes, unsigned int len);
+int spi_nbyte_read_4ba(struct flashctx *flash, unsigned int addr, uint8_t *bytes, unsigned int len);
+int spi_byte_program_4ba_direct(struct flashctx *flash, unsigned int addr, uint8_t databyte);
+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_byte_program_4ba_ereg(struct flashctx *flash, unsigned int addr, uint8_t databyte);
+int spi_nbyte_program_4ba_ereg(struct flashctx *flash, unsigned int addr, const uint8_t *bytes, unsigned int len);
+int spi_nbyte_read_4ba_ereg(struct flashctx *flash, unsigned int addr, uint8_t *bytes, unsigned int len);
+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(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
+int spi_block_erase_20_4ba_ereg(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
+int spi_block_erase_20_4ba_selector(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
+int spi_block_erase_52_4ba(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
+int spi_block_erase_52_4ba_ereg(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(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
+int spi_block_erase_d8_4ba_ereg(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);
+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);
+
#endif /* !__CHIPDRIVERS_H__ */
Index: cli_output.c
===================================================================
--- cli_output.c        (revision 1861)
+++ cli_output.c        (working copy)
@@ -88,11 +88,12 @@
             * time-critical operations. Don't slow them down by flushing. */
            if (level != MSG_SPEW)
                    fflush(output_type);
    }
#ifndef STANDALONE
-        if ((level <= verbose_logfile) && logfile) {
+        /* skip of msgs starting from '\b' added to skip progress percents */
+        if ((level <= verbose_logfile) && logfile && (!fmt || fmt[0] != '\b')) {
            va_start(ap, fmt);
            ret = vfprintf(logfile, fmt, ap);
            va_end(ap);
            if (level != MSG_SPEW)
                    fflush(logfile);
Index: flash.h
===================================================================
--- flash.h        (revision 1861)
+++ flash.h        (working copy)
@@ -119,10 +119,18 @@
#define FEATURE_WRSR_EWSR        (1 << 6)
#define FEATURE_WRSR_WREN        (1 << 7)
#define FEATURE_WRSR_EITHER        (FEATURE_WRSR_EWSR | FEATURE_WRSR_WREN)
#define FEATURE_OTP                (1 << 8)
#define FEATURE_QPI                (1 << 9)
+/* Feature bits used for 4-bytes addressing mode */
+#define FEATURE_FOUR_BYTE_ADDR                        (1 << 10)
+#define FEATURE_FOUR_BYTE_ADDR_ONLY                (1 << 11)
+#define FEATURE_NEED_ENTER_4BA_FOR_READ                (1 << 12)
+#define FEATURE_NEED_ENTER_4BA_FOR_WRITE        (1 << 13)
+#define FEATURE_NEED_ENTER_4BA_FOR_ERASE            (1 << 14)
+#define FEATURE_NEED_USE_EXTENDED_ADDR_REG        (1 << 15)
+#define FEATURE_ENTER_4BA_ALL        (FEATURE_NEED_ENTER_4BA_FOR_READ | FEATURE_NEED_ENTER_4BA_FOR_WRITE | FEATURE_NEED_ENTER_4BA_FOR_ERASE | FEATURE_NEED_USE_EXTENDED_ADDR_REG)

enum test_state {
    OK = 0,
    NT = 1,        /* Not tested */
    BAD,        /* Known to not work */
@@ -163,10 +171,18 @@
    unsigned int total_size;
    /* Chip page size in bytes */
    unsigned int page_size;
    int feature_bits;

+        /* set of function pointers to use in 4-bytes addressing mode */
+        struct four_bytes_addr_funcs_set {
+                int (*enter_4ba) (struct flashctx *flash);
+                int (*read_nbyte) (struct flashctx *flash, unsigned int addr, uint8_t *bytes, unsigned int len);
+                int (*program_byte) (struct flashctx *flash, unsigned int addr, const uint8_t databyte);
+                int (*program_nbyte) (struct flashctx *flash, unsigned int addr, const uint8_t *bytes, unsigned int len);
+        } four_bytes_addr_funcs;
+
    /* Indicate how well flashrom supports different operations of this flash chip. */
    struct tested {
            enum test_state probe;
            enum test_state read;
            enum test_state erase;
@@ -186,10 +202,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
@@ -337,10 +354,15 @@
#define msg_cdbg2(...)        print(MSG_DEBUG2, __VA_ARGS__)        /* chip debug2 */
#define msg_gspew(...)        print(MSG_SPEW, __VA_ARGS__)        /* general debug spew  */
#define msg_pspew(...)        print(MSG_SPEW, __VA_ARGS__)        /* programmer debug spew  */
#define msg_cspew(...)        print(MSG_SPEW, __VA_ARGS__)        /* chip debug spew  */

+/* Read progress will be shown for reads more than 256KB */
+#define MIN_LENGTH_TO_SHOW_READ_PROGRESS 256 * 1024
+/* Read progress will be shown for erases and writes more than 64KB */
+#define MIN_LENGTH_TO_SHOW_ERASE_AND_WRITE_PROGRESS 64 * 1024
+
/* layout.c */
int register_include_arg(char *name);
int process_include_args(void);
int read_romlayout(const char *name);
int normalize_romentries(const struct flashctx *flash);
Index: flashchips.c
===================================================================
--- flashchips.c        (revision 1861)
+++ flashchips.c        (working copy)
@@ -13282,10 +13282,59 @@
            .voltage        = {2700, 3600},
    },

    {
            .vendor                = "Winbond",
+                .name                = "W25Q256.V",
+                .bustype        = BUS_SPI,
+                .manufacture_id        = WINBOND_NEX_ID,
+                .model_id        = WINBOND_NEX_W25Q256_V,
+                .total_size        = 32768,
+                .page_size        = 256,
+                /* supports SFDP */
+                /* OTP: 1024B total, 256B reserved; read 0x48; write 0x42, erase 0x44, read ID 0x4B */
+                /* FOUR_BYTE_ADDR: supports 4-bytes addressing mode */
+                .feature_bits        = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_FOUR_BYTE_ADDR |
+                                  FEATURE_NEED_ENTER_4BA_FOR_ERASE | FEATURE_NEED_ENTER_4BA_FOR_WRITE,
+                .four_bytes_addr_funcs = 
+                {
+                        .enter_4ba = spi_enter_4ba_b7_we, /* enter 4-bytes addressing mode by CMD B7 + WREN */
+                        .read_nbyte = spi_nbyte_read_4ba_direct, /* read directly from any mode, no need to enter 4ba */
+                        .program_byte = spi_byte_program_4ba, /* write from 4-bytes addressing mode */
+                        .program_nbyte = spi_nbyte_program_4ba /* write from 4-bytes addressing mode */
+                },
+                .tested                = TEST_OK_PREW,
+                .probe                = probe_spi_rdid,
+                .probe_timing        = TIMING_ZERO,
+                .block_erasers        =
+                {
+                        {
+                                .eraseblocks = { {4 * 1024, 8192} },
+                                .block_erase = spi_block_erase_20_4ba, /* erases 4k from 4-bytes addressing mode */
+                        }, {
+                                .eraseblocks = { {32 * 1024, 1024} },
+                                .block_erase = spi_block_erase_52_4ba, /* erases 32k from 4-bytes addressing mode */
+                        }, {
+                                .eraseblocks = { {64 * 1024, 512} },
+                                .block_erase = spi_block_erase_d8_4ba, /* erases 64k from 4-bytes addressing mode */
+                        }, {
+                                .eraseblocks = { {32 * 1024 * 1024, 1} },
+                                .block_erase = spi_block_erase_60,
+                        }, {
+                                .eraseblocks = { {32 * 1024 * 1024, 1} },
+                                .block_erase = spi_block_erase_c7,
+                        }
+                },
+                .printlock        = spi_prettyprint_status_register_plain, /* TODO: improve */
+                .unlock                = spi_disable_blockprotect,
+                .write                = spi_chip_write_256,
+                .read                = spi_chip_read,
+                .voltage        = {2700, 3600},
+        },
+
+        {
+                .vendor                = "Winbond",
            .name                = "W25Q20.W",
            .bustype        = BUS_SPI,
            .manufacture_id        = WINBOND_NEX_ID,
            .model_id        = WINBOND_NEX_W25Q20_W,
            .total_size        = 256,
Index: flashrom.c
===================================================================
--- flashrom.c        (revision 1861)
+++ flashrom.c        (working copy)
@@ -1366,12 +1366,12 @@
                              "non-empty erase function. Not an error.\n");
            if (!done)
                    continue;
            if (done != chip->total_size * 1024) {
                    msg_gerr("ERROR: Flash chip %s erase function %i "
-                                "region walking resulted in 0x%06x bytes total,"
-                                " expected 0x%06x bytes. Please report a bug at"
+                                "region walking resulted in 0x%08x bytes total,"
+                                " expected 0x%08x bytes. Please report a bug at"
                            " flashrom at flashrom.org\n", chip->name, k,
                            done, chip->total_size * 1024);
                    ret = 1;
            }
            if (!eraser.block_erase)
@@ -1460,29 +1460,52 @@
{
    int i, j;
    unsigned int start = 0;
    unsigned int len;
    struct block_eraser eraser = flash->chip->block_erasers[erasefunction];
+        int show_progress = 0;
+        unsigned int percent_last, percent_current;
+        unsigned long size = flash->chip->total_size * 1024;
+
+        /* progress visualizaion init */
+        if(size >= MIN_LENGTH_TO_SHOW_ERASE_AND_WRITE_PROGRESS) {
+                msg_cinfo(" "); /* only this space will go to logfile but all strings with \b wont. */
+                msg_cinfo("\b 0%%");
+                percent_last = percent_current = 0;
+                show_progress = 1; /* enable progress visualizaion */
+        }

    for (i = 0; i < NUM_ERASEREGIONS; i++) {
            /* count==0 for all automatically initialized array
             * members so the loop below won't be executed for them.
             */
            len = eraser.eraseblocks[i].size;
            for (j = 0; j < eraser.eraseblocks[i].count; j++) {
                    /* Print this for every block except the first one. */
                    if (i || j)
                            msg_cdbg(", ");
-                        msg_cdbg("0x%06x-0x%06x", start,
+                        msg_cdbg("0x%08x-0x%08x", start,
                                 start + len - 1);
                    if (do_something(flash, start, len, param1, param2,
                                     eraser.block_erase)) {
                            return 1;
                    }
                    start += len;
+
+                        if(show_progress) {
+                                percent_current = (unsigned int) ((unsigned long long)start * 100 / size);
+                                if(percent_current != percent_last) {
+                                        msg_cinfo("\b\b\b%2d%%", percent_current);
+                                        percent_last = percent_current;
+                                }
+                        }
            }
    }
+
+        if(show_progress)
+                msg_cinfo("\b\b\b\b"); /* remove progress percents from the screen */
+
    msg_cdbg("\n");
    return 0;
}

static int check_block_eraser(const struct flashctx *flash, int k, int log)
@@ -1735,12 +1758,15 @@
}

void print_version(void)
{
    msg_ginfo("flashrom v%s", flashrom_version);
+        msg_ginfo("-4ba"); /* temporary to indicate that version is patched */
    print_sysinfo();
    msg_ginfo("\n");
+        /* temporary to indicate that version is patched */
+        msg_ginfo("with patch for support SPI flash chips with 4-bytes addressing\n");
}

void print_banner(void)
{
    msg_ginfo("flashrom is free software, get the source code at "
@@ -1934,10 +1960,42 @@
     * erase and write.
     */
    if (flash->chip->unlock)
            flash->chip->unlock(flash);

+        if(flash->chip->feature_bits & FEATURE_FOUR_BYTE_ADDR) {
+                /* Switching to 4-Bytes Addressing mode if flash chip supports it 
+                   and selected operation requires 4-Bytes Addressing mode 
+                   (no need for direct and ext.addr.reg operation) */
+                if(((read_it || verify_it) && (flash->chip->feature_bits & FEATURE_NEED_ENTER_4BA_FOR_READ)) ||
+                   ((erase_it || write_it) && (flash->chip->feature_bits & (FEATURE_NEED_ENTER_4BA_FOR_READ |
+                                        FEATURE_NEED_ENTER_4BA_FOR_WRITE | FEATURE_NEED_ENTER_4BA_FOR_ERASE))) ) {
+                
+                        if (!flash->chip->four_bytes_addr_funcs.enter_4ba) {
+                                msg_cerr("No function for Enter 4-bytes addressing mode for this flash chip.\n"
+                                        "Please report to flashrom at flashrom.org\n");
+                                return 1;
+                        }
+
+                        if(flash->chip->four_bytes_addr_funcs.enter_4ba(flash)) {
+                                msg_cerr("Switching to 4-bytes addressing mode failed!\n");
+                                return 1;
+                        }
+
+                        msg_cdbg("Switched to 4-bytes addressing mode.\n");
+                }
+                /* Do not switch to 4-Bytes Addressing mode if using Extended Address Register */
+                else if(flash->chip->feature_bits & FEATURE_NEED_USE_EXTENDED_ADDR_REG) {
+                        msg_cdbg("Using 4-bytes addressing with extended address register.\n");
+                }
+                /* Do not switch to 4-Bytes Addressing mode if all instructions are direct-4BA 
+                   or if the flash chip is 4-Bytes Addressing Only and always in 4BA-mode */
+                else {
+                        msg_cdbg2("No need to switch to 4-bytes addressing mode.\n");
+                }
+        }
+
    if (read_it) {
            return read_flash_to_file(flash, filename);
    }

    oldcontents = malloc(size);
Index: serprog.c
===================================================================
--- serprog.c        (revision 1861)
+++ serprog.c        (working copy)
@@ -933,11 +933,14 @@
    unsigned int i, cur_len;
    const unsigned int max_read = spi_master_serprog.max_data_read;
    for (i = 0; i < len; i += cur_len) {
            int ret;
            cur_len = min(max_read, (len - i));
-                ret = spi_nbyte_read(flash, start + i, buf + i, cur_len);
+                ret = (flash->chip->feature_bits & FEATURE_FOUR_BYTE_ADDR) == 0
+                        ? spi_nbyte_read(flash, start + i, buf + i, cur_len)
+                        : flash->chip->four_bytes_addr_funcs.read_nbyte(flash, 
+                                                 start + i, buf + i, cur_len);
            if (ret)
                    return ret;
    }
    return 0;
}
Index: sfdp.c
===================================================================
--- sfdp.c        (revision 1861)
+++ sfdp.c        (working copy)
@@ -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,32 @@
* 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
+ *        07/01/2014  Modified to support SFDP revision 1.5 (for Micron flash chips)
+ */
+
#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 */
+
+/* For testing purposes only. Tests JESD216B SFDP compliance without proper flash chip */
+/* #define JESD216B_SIMULATION 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 +88,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_FOUR_BYTE_ADDR) ? 
+                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 +128,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 +143,110 @@
              " 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_15)
{
    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_FOUR_BYTE_ADDR | 
+                                        FEATURE_NEED_ENTER_4BA_FOR_READ | 
+                                        FEATURE_NEED_ENTER_4BA_FOR_WRITE | 
+                                        FEATURE_NEED_ENTER_4BA_FOR_ERASE );
+                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_FOUR_BYTE_ADDR | 
+                                        FEATURE_NEED_USE_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_FOUR_BYTE_ADDR | 
+                                        FEATURE_FOUR_BYTE_ADDR_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 +254,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 +298,306 @@
            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_15) {
+                        msg_cdbg("Flash chip size is bigger than what 3-Byte addressing "
+                                 "can access but chip's SFDP revision is lower than 1.6 "
+                                 "(1.5).\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 adding 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);
+
+        /* 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_FOUR_BYTE_ADDR))
+                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_FOUR_BYTE_ADDR_ONLY)
+                goto done;
+
+        /* If the SFDP revision supported by the chip is lower that 1.6 (1.5)
+           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_15)
+                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;
+        }
+
+        /* 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);
+
+        /* 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;
+                chip->feature_bits &= ~FEATURE_ENTER_4BA_ALL; // clear defaults
+                chip->feature_bits |= ( FEATURE_NEED_ENTER_4BA_FOR_READ | 
+                                        FEATURE_NEED_ENTER_4BA_FOR_WRITE | 
+                                        FEATURE_NEED_ENTER_4BA_FOR_ERASE );
+        }
+        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;
+                chip->feature_bits &= ~FEATURE_ENTER_4BA_ALL; // clear defaults
+                chip->feature_bits |= ( FEATURE_NEED_ENTER_4BA_FOR_READ | 
+                                        FEATURE_NEED_ENTER_4BA_FOR_WRITE | 
+                                        FEATURE_NEED_ENTER_4BA_FOR_ERASE );
+        }
+        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.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;
+                chip->feature_bits &= ~FEATURE_ENTER_4BA_ALL; // clear defaults
+                /* this flag signals to all '*_selector' functions 
+                   to use Ext.Addr.Reg while erase operations */
+                chip->feature_bits |= FEATURE_NEED_USE_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_NEED_ENTER_4BA_FOR_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_NEED_ENTER_4BA_FOR_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_NEED_ENTER_4BA_FOR_ERASE;
+                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_NEED_USE_EXTENDED_ADDR_REG;
+                msg_cspew("All read/write/erase functions have changed to direct ones.\n");
+        }
+
+        msg_cdbg("done.\n");
+        return 0;
+}
+
+#ifdef JESD216B_SIMULATION
+/* This simulation increases size of Basic Flash Parameter Table
+   to have 16 dwords size and fills 16th dword with fake information
+   that is required to test JESD216B compliance. */
+int sfdp_jesd216b_simulation_dw16(uint8_t** ptbuf, uint16_t* plen)
+{
+        uint8_t* tbufsim;
+        uint16_t lensim = 16 * 4;
+
+        tbufsim = malloc(lensim);
+        if (tbufsim == NULL) {
+                msg_gerr("Out of memory!\n");
+                return 1;
+        }
+
+        msg_cdbg("\n=== SIMULATION of JESD216B 16th Dword of Basic Flash Parameter Table\n");
+
+        memset(tbufsim, 0, 16 * 4);
+        memcpy(tbufsim, *ptbuf, min(*plen, 15 * 4));
+
+        tbufsim[(4*10) + 0] = 8 << 4; /* page size = 256 */
+
+        *((uint32_t*)&tbufsim[15 * 4]) = /*JEDEC_BFPT_DW16_ENTER_B7 | */
+                                         JEDEC_BFPT_DW16_ENTER_B7_WE | 
+                                         JEDEC_BFPT_DW16_ENTER_EXTENDED_ADDR_REG /* |
+                                         JEDEC_BFPT_DW16_ENTER_BANK_ADDR_REG_EN_BIT |
+                                         JEDEC_BFPT_DW16_ENTER_NV_CONFIG_REG |
+                                         JEDEC_BFPT_DW16_VENDOR_SET |
+                                         JEDEC_BFPT_DW16_4_BYTES_ADDRESS_ONLY */ ; 
+
+        free(*ptbuf);
+        *ptbuf = tbufsim;
+        *plen = lensim;
+        return 0;
+}
+
+/* This simulation created fake 4-bytes Address Instruction Table
+   with features information to test JESD216B compliance. */
+int sfdp_jesd216b_simulation_4bait(uint8_t** ptbuf, uint16_t* plen)
+{
+        uint8_t* tbufsim;
+        uint16_t lensim = 2 * 4;
+
+        tbufsim = malloc(lensim);
+        if (tbufsim == NULL) {
+                msg_gerr("Out of memory!\n");
+                return 1;
+        }
+
+        msg_cdbg("\n=== SIMULATION of JESD216B 4-bytes Address Instruction Table\n");
+
+        *((uint32_t*)&tbufsim[0]) = JEDEC_4BAIT_READ_SUPPORT /*| 
+                                    JEDEC_4BAIT_PROGRAM_SUPPORT | 
+                                    JEDEC_4BAIT_ERASE_TYPE_1_SUPPORT | 
+                                    JEDEC_4BAIT_ERASE_TYPE_2_SUPPORT | 
+                                    JEDEC_4BAIT_ERASE_TYPE_3_SUPPORT |
+                                    JEDEC_4BAIT_ERASE_TYPE_4_SUPPORT */;
+        *((uint32_t*)&tbufsim[4]) = 0xFFFFFFFF;
+        /* *((uint32_t*)&tbufsim[4]) = 0xFFDC5C21; */
+
+        free(*ptbuf);
+        *ptbuf = tbufsim;
+        *plen = lensim;
+        return 0;
+}
+#endif
+
int probe_spi_sfdp(struct flashctx *flash)
{
    int ret = 0;
    uint8_t buf[8];
    uint32_t tmp32;
@@ -269,10 +605,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, sfdp_rev_15 = 0;

    if (spi_sfdp_read_sfdp(flash, 0x00, buf, 4)) {
            msg_cdbg("Receiving SFDP signature failed.\n");
            return 0;
    }
@@ -296,10 +633,36 @@
    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
+
+                  However we can see in the datasheet for Micron's
+           MT25Q 512Mb chip (MT25QL512AB/MT25QU512AB) that the 
+           chip returnes SFDP revision 1.5 and has 16 dwords
+           in its Basic Flash Paramater Table. Also the information
+           about addressing mode switch is exist in the 16th dword. 
+           But 4-Bytes Address Instruction Table is absent.
+
+                So we will use 16th dword from SFDP revision 1.5
+           but 4-Bytes Address Instruction Table from SFDP 1.6 only. 
+           This assumption is made for better support of Micron
+           flash chips.
+                  
+                FIXME: SFDP revisions compliance should be checked
+           more carefully after more information about JESD216B
+           SFDP tables will be known from real flash chips.
+        */
+        sfdp_rev_16 = (buf[1] == 1 && buf[0] >= 6) || buf[1] > 1;
+        sfdp_rev_15 = (buf[1] == 1 && buf[0] >= 5) || 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 +677,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 +730,51 @@
                    }
            }
            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");
+#ifdef JESD216B_SIMULATION
+                        if(!sfdp_jesd216b_simulation_dw16(&tbuf, &len))
+                                sfdp_rev_16 = sfdp_rev_15 = 1; /* pretend as SFDP rev 1.6 */
+#endif
                    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_15) == 0)
                            ret = 1;
+#ifdef JESD216B_SIMULATION
+                        if(ret == 1 && !sfdp_jesd216b_simulation_4bait(&tbuf, &len))
+                                sfdp_parse_4ba_table(flash->chip, tbuf, len);
+#endif
+                }
+                /* 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;
}
+
Index: spi.c
===================================================================
--- spi.c        (revision 1861)
+++ spi.c        (working copy)
@@ -108,11 +108,14 @@
    /* Check if the chip fits between lowest valid and highest possible
     * address. Highest possible address with the current SPI implementation
     * means 0xffffff, the highest unsigned 24bit number.
     */
    addrbase = spi_get_valid_read_addr(flash);
-        if (addrbase + flash->chip->total_size * 1024 > (1 << 24)) {
+        /* Show flash chip size warning if flash chip doesn't support 
+           4-Bytes Addressing mode and last address excedes 24 bits */
+        if (!(flash->chip->feature_bits & FEATURE_FOUR_BYTE_ADDR) &&
+            addrbase + flash->chip->total_size * 1024 > (1 << 24)) {
            msg_perr("Flash chip size exceeds the allowed access window. ");
            msg_perr("Read will probably fail.\n");
            /* Try to get the best alignment subject to constraints. */
            addrbase = (1 << 24) - flash->chip->total_size * 1024;
    }
Index: spi25.c
===================================================================
--- spi25.c        (revision 1861)
+++ spi25.c        (working copy)
@@ -26,10 +26,11 @@
#include "flash.h"
#include "flashchips.h"
#include "chipdrivers.h"
#include "programmer.h"
#include "spi.h"
+#include "spi4ba.h"

static int spi_rdid(struct flashctx *flash, unsigned char *readarr, int bytes)
{
    static const unsigned char cmd[JEDEC_RDID_OUTSIZE] = { JEDEC_RDID };
    int ret;
@@ -946,10 +947,20 @@
                 unsigned int len, unsigned int chunksize)
{
    int rc = 0;
    unsigned int i, j, starthere, lenhere, toread;
    unsigned int page_size = flash->chip->page_size;
+        int show_progress = 0;
+        unsigned int percent_last, percent_current;
+
+        /* progress visualizaion init */
+        if(len >= MIN_LENGTH_TO_SHOW_READ_PROGRESS) {
+                msg_cinfo(" "); /* only this space will go to logfile but all strings with \b wont. */
+                msg_cinfo("\b 0%%");
+                percent_last = percent_current = 0;
+                show_progress = 1; /* enable progress visualizaion */
+        }

    /* Warning: This loop has a very unusual condition and body.
     * The loop needs to go through each page with at least one affected
     * byte. The lowest page number is (start / page_size) since that
     * division rounds down. The highest page number we want is the page
@@ -964,18 +975,33 @@
            starthere = max(start, i * page_size);
            /* Length of bytes in the range in this page. */
            lenhere = min(start + len, (i + 1) * page_size) - starthere;
            for (j = 0; j < lenhere; j += chunksize) {
                    toread = min(chunksize, lenhere - j);
-                        rc = spi_nbyte_read(flash, starthere + j, buf + starthere - start + j, toread);
+                        rc = (flash->chip->feature_bits & FEATURE_FOUR_BYTE_ADDR) == 0
+                                ? spi_nbyte_read(flash, starthere + j, buf + starthere - start + j, toread)
+                                : flash->chip->four_bytes_addr_funcs.read_nbyte(flash, starthere + j, 
+                                        buf + starthere - start + j, toread);
                    if (rc)
                            break;
            }
            if (rc)
                    break;
+
+                if(show_progress) {
+                        percent_current = (unsigned int) ((unsigned long long)(starthere + 
+                                                                        lenhere - start) * 100 / len);
+                        if(percent_current != percent_last) {
+                                msg_cinfo("\b\b\b%2d%%", percent_current);
+                                percent_last = percent_current;
+                        }
+                }        
    }

+        if(show_progress && !rc)
+                msg_cinfo("\b\b\b\b"); /* remove progress percents from the screen */
+
    return rc;
}

/*
* Write a part of the flash chip.
@@ -1009,11 +1035,14 @@
            starthere = max(start, i * page_size);
            /* Length of bytes in the range in this page. */
            lenhere = min(start + len, (i + 1) * page_size) - starthere;
            for (j = 0; j < lenhere; j += chunksize) {
                    towrite = min(chunksize, lenhere - j);
-                        rc = spi_nbyte_program(flash, starthere + j, buf + starthere - start + j, towrite);
+                        rc = (flash->chip->feature_bits & FEATURE_FOUR_BYTE_ADDR) == 0
+                                ? spi_nbyte_program(flash, starthere + j, buf + starthere - start + j, towrite)
+                                : flash->chip->four_bytes_addr_funcs.program_nbyte(flash, starthere + j, 
+                                        buf + starthere - start + j, towrite);
                    if (rc)
                            break;
                    while (spi_read_status_register(flash) & SPI_SR_WIP)
                            programmer_delay(10);
            }
@@ -1035,11 +1064,13 @@
{
    unsigned int i;
    int result = 0;

    for (i = start; i < start + len; i++) {
-                result = spi_byte_program(flash, i, buf[i - start]);
+                result = (flash->chip->feature_bits & FEATURE_FOUR_BYTE_ADDR) == 0
+                        ? spi_byte_program(flash, i, buf[i - start])
+                        : flash->chip->four_bytes_addr_funcs.program_byte(flash, i, buf[i - start]);
            if (result)
                    return 1;
            while (spi_read_status_register(flash) & SPI_SR_WIP)
                    programmer_delay(10);
    }
Index: spi4ba.c
===================================================================
--- spi4ba.c        (revision 0)
+++ spi4ba.c        (working copy)
@@ -0,0 +1,1020 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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
+ */
+
+/*
+ * SPI chip driver functions for 4-bytes addressing
+ */
+
+#include <string.h>
+#include "flash.h"
+#include "chipdrivers.h"
+#include "spi.h"
+#include "programmer.h"
+#include "spi4ba.h"
+
+/* #define MSG_TRACE_4BA_FUNCS 1 */
+
+#ifdef MSG_TRACE_4BA_FUNCS
+#define msg_trace(...) print(MSG_DEBUG, __VA_ARGS__)
+#else 
+#define msg_trace(...)
+#endif
+
+/* Enter 4-bytes addressing mode (without sending WREN before) */
+int spi_enter_4ba_b7(struct flashctx *flash)
+{
+        const unsigned char cmd[JEDEC_ENTER_4_BYTE_ADDR_MODE_OUTSIZE] = { JEDEC_ENTER_4_BYTE_ADDR_MODE };
+
+        msg_trace("-> %s\n", __func__);
+
+        /* Switch to 4-bytes addressing mode  */
+        return spi_send_command(flash, sizeof(cmd), 0, cmd, NULL);
+}
+
+/* Enter 4-bytes addressing mode with sending WREN before */
+int spi_enter_4ba_b7_we(struct flashctx *flash)
+{
+        int result;
+        struct spi_command cmds[] = {
+        {
+                .writecnt        = JEDEC_WREN_OUTSIZE,
+                .writearr        = (const unsigned char[]){ JEDEC_WREN },
+                .readcnt        = 0,
+                .readarr        = NULL,
+        }, {
+                .writecnt        = JEDEC_ENTER_4_BYTE_ADDR_MODE_OUTSIZE,
+                .writearr        = (const unsigned char[]){ JEDEC_ENTER_4_BYTE_ADDR_MODE },
+                .readcnt        = 0,
+                .readarr        = NULL,
+        }, {
+                .writecnt        = 0,
+                .writearr        = NULL,
+                .readcnt        = 0,
+                .readarr        = NULL,
+        }};
+
+        msg_trace("-> %s\n", __func__);
+
+        /* Switch to 4-bytes addressing mode  */
+        result = spi_send_multicommand(flash, cmds);
+        if (result) {
+                msg_cerr("%s failed during command execution\n", __func__);
+        }
+        return result;
+}
+
+/* Write Extended Address Register value */
+int spi_write_extended_address_register(struct flashctx *flash, uint8_t regdata)
+{
+        int result;
+        struct spi_command cmds[] = {
+        {
+                .writecnt        = JEDEC_WREN_OUTSIZE,
+                .writearr        = (const unsigned char[]){ JEDEC_WREN },
+                .readcnt        = 0,
+                .readarr        = NULL,
+        }, {
+                .writecnt        = JEDEC_WRITE_EXT_ADDR_REG_OUTSIZE,
+                .writearr        = (const unsigned char[]){ 
+                                        JEDEC_WRITE_EXT_ADDR_REG, 
+                                        regdata 
+                                },
+                .readcnt        = 0,
+                .readarr        = NULL,
+        }, {
+                .writecnt        = 0,
+                .writearr        = NULL,
+                .readcnt        = 0,
+                .readarr        = NULL,
+        }};
+
+        msg_trace("-> %s (%02X)\n", __func__, regdata);
+
+        result = spi_send_multicommand(flash, cmds);
+        if (result) {
+                msg_cerr("%s failed during command execution\n", __func__);
+                return result;
+        }
+        return 0;
+}
+
+/* Assign required value of Extended Address Register. This function 
+   keeps last value of the register and writes the register if the 
+   value has to be changed only. */
+int set_extended_address_register(struct flashctx *flash, uint8_t data)
+{
+        static uint8_t ext_addr_reg_state; /* memory for last register state */
+        static int ext_addr_reg_state_valid = 0;
+        int result;
+
+        if (ext_addr_reg_state_valid == 0 || data != ext_addr_reg_state) {
+                result = spi_write_extended_address_register(flash, data);
+                if (result) {
+                        ext_addr_reg_state_valid = 0;
+                        return result;
+                }
+                ext_addr_reg_state = data;
+                ext_addr_reg_state_valid = 1;
+        }
+        return 0;
+}
+
+/* Program one flash byte from 4-bytes addressing mode */
+int spi_byte_program_4ba(struct flashctx *flash, unsigned int addr,
+                                 uint8_t databyte)
+{
+        int result;
+        struct spi_command cmds[] = {
+        {
+                .writecnt        = JEDEC_WREN_OUTSIZE,
+                .writearr        = (const unsigned char[]){ JEDEC_WREN },
+                .readcnt        = 0,
+                .readarr        = NULL,
+        }, {
+                .writecnt        = JEDEC_BYTE_PROGRAM_OUTSIZE + 1,
+                .writearr        = (const unsigned char[]){
+                                        JEDEC_BYTE_PROGRAM,
+                                        (addr >> 24) & 0xff,
+                                        (addr >> 16) & 0xff,
+                                        (addr >> 8) & 0xff,
+                                        (addr & 0xff),
+                                        databyte
+                                },
+                .readcnt        = 0,
+                .readarr        = NULL,
+        }, {
+                .writecnt        = 0,
+                .writearr        = NULL,
+                .readcnt        = 0,
+                .readarr        = NULL,
+        }};
+
+        msg_trace("-> %s (0x%08X)\n", __func__, addr);
+
+        result = spi_send_multicommand(flash, cmds);
+        if (result) {
+                msg_cerr("%s failed during command execution at address 0x%x\n",
+                        __func__, addr);
+        }
+        return result;
+}
+
+/* Program flash bytes from 4-bytes addressing mode */
+int spi_nbyte_program_4ba(struct flashctx *flash, unsigned int addr,
+                          const uint8_t *bytes, unsigned int len)
+{
+        int result;
+        unsigned char cmd[(JEDEC_BYTE_PROGRAM_OUTSIZE + 1) - 1 + 256] = {
+                JEDEC_BYTE_PROGRAM,
+                (addr >> 24) & 0xff,
+                (addr >> 16) & 0xff,
+                (addr >> 8) & 0xff,
+                (addr >> 0) & 0xff
+        };
+        struct spi_command cmds[] = {
+        {
+                .writecnt        = JEDEC_WREN_OUTSIZE,
+                .writearr        = (const unsigned char[]){ JEDEC_WREN },
+                .readcnt        = 0,
+                .readarr        = NULL,
+        }, {
+                .writecnt        = (JEDEC_BYTE_PROGRAM_OUTSIZE + 1) - 1 + len,
+                .writearr        = cmd,
+                .readcnt        = 0,
+                .readarr        = NULL,
+        }, {
+                .writecnt        = 0,
+                .writearr        = NULL,
+                .readcnt        = 0,
+                .readarr        = NULL,
+        }};
+
+        msg_trace("-> %s (0x%08X-0x%08X)\n", __func__, addr, addr + len - 1);
+
+        if (!len) {
+                msg_cerr("%s called for zero-length write\n", __func__);
+                return 1;
+        }
+        if (len > 256) {
+                msg_cerr("%s called for too long a write\n", __func__);
+                return 1;
+        }
+
+        memcpy(&cmd[(JEDEC_BYTE_PROGRAM_OUTSIZE + 1) - 1], bytes, len);
+
+        result = spi_send_multicommand(flash, cmds);
+        if (result) {
+                msg_cerr("%s failed during command execution at address 0x%x\n",
+                        __func__, addr);
+        }
+        return result;
+}
+
+/* Read flash bytes from 4-bytes addressing mode */
+int spi_nbyte_read_4ba(struct flashctx *flash, unsigned int addr,
+                   uint8_t *bytes, unsigned int len)
+{
+        const unsigned char cmd[JEDEC_READ_OUTSIZE + 1] = {
+                JEDEC_READ,
+                (addr >> 24) & 0xff,
+                (addr >> 16) & 0xff,
+                (addr >> 8) & 0xff,
+                (addr >> 0) & 0xff
+        };
+
+        msg_trace("-> %s (0x%08X-0x%08X)\n", __func__, addr, addr + len - 1);
+
+        /* Send Read */
+        return spi_send_command(flash, sizeof(cmd), len, cmd, bytes);
+}
+
+/* Program one flash byte with 4-bytes address from ANY mode (3-bytes or 4-bytes)
+   JEDEC_BYTE_PROGRAM_4BA (12h) instruction is new for 4-bytes addressing flash chips.
+   The presence of this instruction for an exact chip should be checked 
+   by its datasheet or from SFDP 4-Bytes Address Instruction Table (JESD216B). */
+int spi_byte_program_4ba_direct(struct flashctx *flash, unsigned int addr,
+                                 uint8_t databyte)
+{
+        int result;
+        struct spi_command cmds[] = {
+        {
+                .writecnt        = JEDEC_WREN_OUTSIZE,
+                .writearr        = (const unsigned char[]){ JEDEC_WREN },
+                .readcnt        = 0,
+                .readarr        = NULL,
+        }, {
+                .writecnt        = JEDEC_BYTE_PROGRAM_4BA_OUTSIZE,
+                .writearr        = (const unsigned char[]){
+                                        JEDEC_BYTE_PROGRAM_4BA,
+                                        (addr >> 24) & 0xff,
+                                        (addr >> 16) & 0xff,
+                                        (addr >> 8) & 0xff,
+                                        (addr & 0xff),
+                                        databyte
+                                },
+                .readcnt        = 0,
+                .readarr        = NULL,
+        }, {
+                .writecnt        = 0,
+                .writearr        = NULL,
+                .readcnt        = 0,
+                .readarr        = NULL,
+        }};
+
+        msg_trace("-> %s (0x%08X)\n", __func__, addr);
+
+        result = spi_send_multicommand(flash, cmds);
+        if (result) {
+                msg_cerr("%s failed during command execution at address 0x%x\n",
+                        __func__, addr);
+        }
+        return result;
+}
+
+/* Program flash bytes with 4-bytes address from ANY mode (3-bytes or 4-bytes)
+   JEDEC_BYTE_PROGRAM_4BA (12h) instruction is new for 4-bytes addressing flash chips.
+   The presence of this instruction for an exact chip should be checked 
+   by its datasheet or from SFDP 4-Bytes Address Instruction Table (JESD216B). */
+int spi_nbyte_program_4ba_direct(struct flashctx *flash, unsigned int addr,
+                                  const uint8_t *bytes, unsigned int len)
+{
+        int result;
+        unsigned char cmd[JEDEC_BYTE_PROGRAM_4BA_OUTSIZE - 1 + 256] = {
+                JEDEC_BYTE_PROGRAM_4BA,
+                (addr >> 24) & 0xff,
+                (addr >> 16) & 0xff,
+                (addr >> 8) & 0xff,
+                (addr >> 0) & 0xff
+        };
+        struct spi_command cmds[] = {
+        {
+                .writecnt        = JEDEC_WREN_OUTSIZE,
+                .writearr        = (const unsigned char[]){ JEDEC_WREN },
+                .readcnt        = 0,
+                .readarr        = NULL,
+        }, {
+                .writecnt        = JEDEC_BYTE_PROGRAM_4BA_OUTSIZE - 1 + len,
+                .writearr        = cmd,
+                .readcnt        = 0,
+                .readarr        = NULL,
+        }, {
+                .writecnt        = 0,
+                .writearr        = NULL,
+                .readcnt        = 0,
+                .readarr        = NULL,
+        }};
+
+        msg_trace("-> %s (0x%08X-0x%08X)\n", __func__, addr, addr + len - 1);
+
+        if (!len) {
+                msg_cerr("%s called for zero-length write\n", __func__);
+                return 1;
+        }
+        if (len > 256) {
+                msg_cerr("%s called for too long a write\n", __func__);
+                return 1;
+        }
+
+        memcpy(&cmd[JEDEC_BYTE_PROGRAM_4BA_OUTSIZE - 1], bytes, len);
+
+        result = spi_send_multicommand(flash, cmds);
+        if (result) {
+                msg_cerr("%s failed during command execution at address 0x%x\n",
+                        __func__, addr);
+        }
+        return result;
+}
+
+/* Read flash bytes with 4-bytes address from ANY mode (3-bytes or 4-bytes)
+   JEDEC_READ_4BA (13h) instruction is new for 4-bytes addressing flash chips.
+   The presence of this instruction for an exact chip should be checked 
+   by its datasheet or from SFDP 4-Bytes Address Instruction Table (JESD216B). */
+int spi_nbyte_read_4ba_direct(struct flashctx *flash, unsigned int addr,
+                   uint8_t *bytes, unsigned int len)
+{
+        const unsigned char cmd[JEDEC_READ_4BA_OUTSIZE] = {
+                JEDEC_READ_4BA,
+                (addr >> 24) & 0xff,
+                (addr >> 16) & 0xff,
+                (addr >> 8) & 0xff,
+                (addr >> 0) & 0xff
+        };
+
+        msg_trace("-> %s (0x%08X-0x%08X)\n", __func__, addr, addr + len - 1);
+
+        /* Send Read */
+        return spi_send_command(flash, sizeof(cmd), len, cmd, bytes);
+}
+
+/* Program one flash byte using Extended Address Register 
+   from 3-bytes addressing mode */
+int spi_byte_program_4ba_ereg(struct flashctx *flash, unsigned int addr,
+                                 uint8_t databyte)
+{
+        int result;
+        struct spi_command cmds[] = {
+        {
+                .writecnt        = JEDEC_WREN_OUTSIZE,
+                .writearr        = (const unsigned char[]){ JEDEC_WREN },
+                .readcnt        = 0,
+                .readarr        = NULL,
+        }, {
+                .writecnt        = JEDEC_BYTE_PROGRAM_OUTSIZE,
+                .writearr        = (const unsigned char[]){
+                                        JEDEC_BYTE_PROGRAM,
+                                        (addr >> 16) & 0xff,
+                                        (addr >> 8) & 0xff,
+                                        (addr & 0xff),
+                                        databyte
+                                },
+                .readcnt        = 0,
+                .readarr        = NULL,
+        }, {
+                .writecnt        = 0,
+                .writearr        = NULL,
+                .readcnt        = 0,
+                .readarr        = NULL,
+        }};
+
+        msg_trace("-> %s (0x%08X)\n", __func__, addr);
+
+        result = set_extended_address_register(flash, (addr >> 24) & 0xff);
+        if (result)
+                return result;
+
+        result = spi_send_multicommand(flash, cmds);
+        if (result) {
+                msg_cerr("%s failed during command execution at address 0x%x\n",
+                        __func__, addr);
+        }
+        return result;
+}
+
+/* Program flash bytes using Extended Address Register
+   from 3-bytes addressing mode */
+int spi_nbyte_program_4ba_ereg(struct flashctx *flash, unsigned int addr,
+                                  const uint8_t *bytes, unsigned int len)
+{
+        int result;
+        unsigned char cmd[JEDEC_BYTE_PROGRAM_OUTSIZE - 1 + 256] = {
+                JEDEC_BYTE_PROGRAM,
+                (addr >> 16) & 0xff,
+                (addr >> 8) & 0xff,
+                (addr >> 0) & 0xff
+        };
+        struct spi_command cmds[] = {
+        {
+                .writecnt        = JEDEC_WREN_OUTSIZE,
+                .writearr        = (const unsigned char[]){ JEDEC_WREN },
+                .readcnt        = 0,
+                .readarr        = NULL,
+        }, {
+                .writecnt        = JEDEC_BYTE_PROGRAM_OUTSIZE - 1 + len,
+                .writearr        = cmd,
+                .readcnt        = 0,
+                .readarr        = NULL,
+        }, {
+                .writecnt        = 0,
+                .writearr        = NULL,
+                .readcnt        = 0,
+                .readarr        = NULL,
+        }};
+
+        msg_trace("-> %s (0x%08X-0x%08X)\n", __func__, addr, addr + len - 1);
+
+        if (!len) {
+                msg_cerr("%s called for zero-length write\n", __func__);
+                return 1;
+        }
+        if (len > 256) {
+                msg_cerr("%s called for too long a write\n", __func__);
+                return 1;
+        }
+
+        memcpy(&cmd[JEDEC_BYTE_PROGRAM_OUTSIZE - 1], bytes, len);
+
+        result = set_extended_address_register(flash, (addr >> 24) & 0xff);
+        if (result)
+                return result;
+
+        result = spi_send_multicommand(flash, cmds);
+        if (result) {
+                msg_cerr("%s failed during command execution at address 0x%x\n",
+                        __func__, addr);
+        }
+        return result;
+}
+
+/* Read flash bytes using Extended Address Register
+   from 3-bytes addressing mode */
+int spi_nbyte_read_4ba_ereg(struct flashctx *flash, unsigned int addr,
+                   uint8_t *bytes, unsigned int len)
+{
+        int result;
+        const unsigned char cmd[JEDEC_READ_OUTSIZE] = {
+                JEDEC_READ,
+                (addr >> 16) & 0xff,
+                (addr >> 8) & 0xff,
+                (addr >> 0) & 0xff
+        };
+
+        msg_trace("-> %s (0x%08X-0x%08X)\n", __func__, addr, addr + len - 1);
+
+        result = set_extended_address_register(flash, (addr >> 24) & 0xff);
+        if (result)
+                return result;
+
+        /* Send Read */
+        return spi_send_command(flash, sizeof(cmd), len, cmd, bytes);
+}
+
+/* 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;
+        }
+}
+
+/* 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_NEED_USE_EXTENDED_ADDR_REG) ?
+                spi_block_erase_20_4ba_ereg(flash, addr, blocklen) :
+                spi_block_erase_20_4ba(flash, addr, blocklen);
+}
+
+/* Erases 4 KB of flash from 4-bytes addressing mode */
+int spi_block_erase_20_4ba(struct flashctx *flash, unsigned int addr,
+                       unsigned int blocklen)
+{
+        int result;
+        struct spi_command cmds[] = {
+        {
+                .writecnt        = JEDEC_WREN_OUTSIZE,
+                .writearr        = (const unsigned char[]){ JEDEC_WREN },
+                .readcnt        = 0,
+                .readarr        = NULL,
+        }, {
+                .writecnt        = JEDEC_SE_OUTSIZE + 1,
+                .writearr        = (const unsigned char[]){
+                                        JEDEC_SE,
+                                        (addr >> 24) & 0xff,
+                                        (addr >> 16) & 0xff,
+                                        (addr >> 8) & 0xff,
+                                        (addr & 0xff)
+                                },
+                .readcnt        = 0,
+                .readarr        = NULL,
+        }, {
+                .writecnt        = 0,
+                .writearr        = NULL,
+                .readcnt        = 0,
+                .readarr        = NULL,
+        }};
+
+        msg_trace("-> %s (0x%08X-0x%08X)\n", __func__, addr, addr + blocklen - 1);
+
+        result = spi_send_multicommand(flash, cmds);
+        if (result) {
+                msg_cerr("%s failed during command execution at address 0x%x\n",
+                        __func__, addr);
+                return result;
+        }
+        /* Wait until the Write-In-Progress bit is cleared.
+         * This usually takes 15-800 ms, so wait in 10 ms steps.
+         */
+        while (spi_read_status_register(flash) & SPI_SR_WIP)
+                programmer_delay(10 * 1000);
+        /* FIXME: Check the status register for errors. */
+        return 0;
+}
+
+/* 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_NEED_USE_EXTENDED_ADDR_REG) ?
+                spi_block_erase_52_4ba_ereg(flash, addr, blocklen) :
+                spi_block_erase_52_4ba(flash, addr, blocklen);
+}
+
+/* Erases 32 KB of flash from 4-bytes addressing mode */
+int spi_block_erase_52_4ba(struct flashctx *flash, unsigned int addr,
+                       unsigned int blocklen)
+{
+        int result;
+        struct spi_command cmds[] = {
+        {
+                .writecnt        = JEDEC_WREN_OUTSIZE,
+                .writearr        = (const unsigned char[]){ JEDEC_WREN },
+                .readcnt        = 0,
+                .readarr        = NULL,
+        }, {
+                .writecnt        = JEDEC_BE_52_OUTSIZE + 1,
+                .writearr        = (const unsigned char[]){
+                                        JEDEC_BE_52,
+                                        (addr >> 24) & 0xff,
+                                        (addr >> 16) & 0xff,
+                                        (addr >> 8) & 0xff,
+                                        (addr & 0xff)
+                                },
+                .readcnt        = 0,
+                .readarr        = NULL,
+        }, {
+                .writecnt        = 0,
+                .writearr        = NULL,
+                .readcnt        = 0,
+                .readarr        = NULL,
+        }};
+
+        msg_trace("-> %s (0x%08X-0x%08X)\n", __func__, addr, addr + blocklen - 1);
+
+        result = spi_send_multicommand(flash, cmds);
+        if (result) {
+                msg_cerr("%s failed during command execution at address 0x%x\n",
+                        __func__, addr);
+                return result;
+        }
+        /* Wait until the Write-In-Progress bit is cleared.
+         * This usually takes 100-4000 ms, so wait in 100 ms steps.
+         */
+        while (spi_read_status_register(flash) & SPI_SR_WIP)
+                programmer_delay(100 * 1000);
+        /* FIXME: Check the status register for errors. */
+        return 0;
+}
+
+/* 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_NEED_USE_EXTENDED_ADDR_REG) ?
+                spi_block_erase_d8_4ba_ereg(flash, addr, blocklen) :
+                spi_block_erase_d8_4ba(flash, addr, blocklen);
+}
+
+/* Erases 64 KB of flash from 4-bytes addressing mode */
+int spi_block_erase_d8_4ba(struct flashctx *flash, unsigned int addr,
+                       unsigned int blocklen)
+{
+        int result;
+        struct spi_command cmds[] = {
+        {
+                .writecnt        = JEDEC_WREN_OUTSIZE,
+                .writearr        = (const unsigned char[]){ JEDEC_WREN },
+                .readcnt        = 0,
+                .readarr        = NULL,
+        }, {
+                .writecnt        = JEDEC_BE_D8_OUTSIZE + 1,
+                .writearr        = (const unsigned char[]){
+                                        JEDEC_BE_D8,
+                                        (addr >> 24) & 0xff,
+                                        (addr >> 16) & 0xff,
+                                        (addr >> 8) & 0xff,
+                                        (addr & 0xff)
+                                },
+                .readcnt        = 0,
+                .readarr        = NULL,
+        }, {
+                .writecnt        = 0,
+                .writearr        = NULL,
+                .readcnt        = 0,
+                .readarr        = NULL,
+        }};
+
+        msg_trace("-> %s (0x%08X-0x%08X)\n", __func__, addr, addr + blocklen - 1);
+
+        result = spi_send_multicommand(flash, cmds);
+        if (result) {
+                msg_cerr("%s failed during command execution at address 0x%x\n",
+                        __func__, addr);
+                return result;
+        }
+        /* Wait until the Write-In-Progress bit is cleared.
+         * This usually takes 100-4000 ms, so wait in 100 ms steps.
+         */
+        while (spi_read_status_register(flash) & SPI_SR_WIP)
+                programmer_delay(100 * 1000);
+        /* FIXME: Check the status register for errors. */
+        return 0;
+}
+
+/* Erases 4 KB of flash using Extended Address Register
+   from 3-bytes addressing mode */
+int spi_block_erase_20_4ba_ereg(struct flashctx *flash, unsigned int addr,
+                       unsigned int blocklen)
+{
+        int result;
+        struct spi_command cmds[] = {
+        {
+                .writecnt        = JEDEC_WREN_OUTSIZE,
+                .writearr        = (const unsigned char[]){ JEDEC_WREN },
+                .readcnt        = 0,
+                .readarr        = NULL,
+        }, {
+                .writecnt        = JEDEC_SE_OUTSIZE,
+                .writearr        = (const unsigned char[]){
+                                        JEDEC_SE,
+                                        (addr >> 16) & 0xff,
+                                        (addr >> 8) & 0xff,
+                                        (addr & 0xff)
+                                },
+                .readcnt        = 0,
+                .readarr        = NULL,
+        }, {
+                .writecnt        = 0,
+                .writearr        = NULL,
+                .readcnt        = 0,
+                .readarr        = NULL,
+        }};
+
+        msg_trace("-> %s (0x%08X-0x%08X)\n", __func__, addr, addr + blocklen - 1);
+
+        result = set_extended_address_register(flash, (addr >> 24) & 0xff);
+        if (result)
+                return result;
+
+        result = spi_send_multicommand(flash, cmds);
+        if (result) {
+                msg_cerr("%s failed during command execution at address 0x%x\n",
+                        __func__, addr);
+                return result;
+        }
+        /* Wait until the Write-In-Progress bit is cleared.
+         * This usually takes 15-800 ms, so wait in 10 ms steps.
+         */
+        while (spi_read_status_register(flash) & SPI_SR_WIP)
+                programmer_delay(10 * 1000);
+        /* FIXME: Check the status register for errors. */
+        return 0;
+}
+
+/* Erases 32 KB of flash using Extended Address Register 
+   from 3-bytes addressing mode */
+int spi_block_erase_52_4ba_ereg(struct flashctx *flash, unsigned int addr,
+                       unsigned int blocklen)
+{
+        int result;
+        struct spi_command cmds[] = {
+        {
+                .writecnt        = JEDEC_WREN_OUTSIZE,
+                .writearr        = (const unsigned char[]){ JEDEC_WREN },
+                .readcnt        = 0,
+                .readarr        = NULL,
+        }, {
+                .writecnt        = JEDEC_BE_52_OUTSIZE,
+                .writearr        = (const unsigned char[]){
+                                        JEDEC_BE_52,
+                                        (addr >> 16) & 0xff,
+                                        (addr >> 8) & 0xff,
+                                        (addr & 0xff)
+                                },
+                .readcnt        = 0,
+                .readarr        = NULL,
+        }, {
+                .writecnt        = 0,
+                .writearr        = NULL,
+                .readcnt        = 0,
+                .readarr        = NULL,
+        }};
+
+        msg_trace("-> %s (0x%08X-0x%08X)\n", __func__, addr, addr + blocklen - 1);
+
+        result = set_extended_address_register(flash, (addr >> 24) & 0xff);
+        if (result)
+                return result;
+
+        result = spi_send_multicommand(flash, cmds);
+        if (result) {
+                msg_cerr("%s failed during command execution at address 0x%x\n",
+                        __func__, addr);
+                return result;
+        }
+        /* Wait until the Write-In-Progress bit is cleared.
+         * This usually takes 100-4000 ms, so wait in 100 ms steps.
+         */
+        while (spi_read_status_register(flash) & SPI_SR_WIP)
+                programmer_delay(100 * 1000);
+        /* FIXME: Check the status register for errors. */
+        return 0;
+}
+
+/* Erases 64 KB of flash using Extended Address Register 
+   from 3-bytes addressing mode */
+int spi_block_erase_d8_4ba_ereg(struct flashctx *flash, unsigned int addr,
+                       unsigned int blocklen)
+{
+        int result;
+        struct spi_command cmds[] = {
+        {
+                .writecnt        = JEDEC_WREN_OUTSIZE,
+                .writearr        = (const unsigned char[]){ JEDEC_WREN },
+                .readcnt        = 0,
+                .readarr        = NULL,
+        }, {
+                .writecnt        = JEDEC_BE_D8_OUTSIZE,
+                .writearr        = (const unsigned char[]){
+                                        JEDEC_BE_D8,
+                                        (addr >> 16) & 0xff,
+                                        (addr >> 8) & 0xff,
+                                        (addr & 0xff)
+                                },
+                .readcnt        = 0,
+                .readarr        = NULL,
+        }, {
+                .writecnt        = 0,
+                .writearr        = NULL,
+                .readcnt        = 0,
+                .readarr        = NULL,
+        }};
+
+        msg_trace("-> %s (0x%08X-0x%08X)\n", __func__, addr, addr + blocklen - 1);
+
+        result = set_extended_address_register(flash, (addr >> 24) & 0xff);
+        if (result)
+                return result;
+
+        result = spi_send_multicommand(flash, cmds);
+        if (result) {
+                msg_cerr("%s failed during command execution at address 0x%x\n",
+                        __func__, addr);
+                return result;
+        }
+        /* Wait until the Write-In-Progress bit is cleared.
+         * This usually takes 100-4000 ms, so wait in 100 ms steps.
+         */
+        while (spi_read_status_register(flash) & SPI_SR_WIP)
+                programmer_delay(100 * 1000);
+        /* FIXME: Check the status register for errors. */
+        return 0;
+}
+
+/* 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;
+        }
+}
+
+/* Erase 4 KB of flash with 4-bytes address from ANY mode (3-bytes or 4-bytes)
+   JEDEC_SE_4BA (21h) instruction is new for 4-bytes addressing flash chips.
+   The presence of this instruction for an exact chip should be checked 
+   by its datasheet or from SFDP 4-Bytes Address Instruction Table (JESD216B). */
+int spi_block_erase_21_4ba_direct(struct flashctx *flash, unsigned int addr,
+                                   unsigned int blocklen)
+{
+        int result;
+        struct spi_command cmds[] = {
+        {
+                .writecnt        = JEDEC_WREN_OUTSIZE,
+                .writearr        = (const unsigned char[]){ JEDEC_WREN },
+                .readcnt        = 0,
+                .readarr        = NULL,
+        }, {
+                .writecnt        = JEDEC_SE_4BA_OUTSIZE,
+                .writearr        = (const unsigned char[]){
+                                        JEDEC_SE_4BA,
+                                        (addr >> 24) & 0xff,
+                                        (addr >> 16) & 0xff,
+                                        (addr >> 8) & 0xff,
+                                        (addr & 0xff)
+                                },
+                .readcnt        = 0,
+                .readarr        = NULL,
+        }, {
+                .writecnt        = 0,
+                .writearr        = NULL,
+                .readcnt        = 0,
+                .readarr        = NULL,
+        }};
+
+        msg_trace("-> %s (0x%08X-0x%08X)\n", __func__, addr, addr + blocklen - 1);
+
+        result = spi_send_multicommand(flash, cmds);
+        if (result) {
+                msg_cerr("%s failed during command execution at address 0x%x\n",
+                        __func__, addr);
+                return result;
+        }
+        /* Wait until the Write-In-Progress bit is cleared.
+         * This usually takes 15-800 ms, so wait in 10 ms steps.
+         */
+        while (spi_read_status_register(flash) & SPI_SR_WIP)
+                programmer_delay(10 * 1000);
+        /* FIXME: Check the status register for errors. */
+        return 0;
+}
+
+/* Erase 32 KB of flash with 4-bytes address from ANY mode (3-bytes or 4-bytes)
+   JEDEC_BE_5C_4BA (5Ch) instruction is new for 4-bytes addressing flash chips.
+   The presence of this instruction for an exact chip should be checked 
+   by its datasheet or from SFDP 4-Bytes Address Instruction Table (JESD216B). */
+int spi_block_erase_5c_4ba_direct(struct flashctx *flash, unsigned int addr,
+                       unsigned int blocklen)
+{
+        int result;
+        struct spi_command cmds[] = {
+        {
+                .writecnt        = JEDEC_WREN_OUTSIZE,
+                .writearr        = (const unsigned char[]){ JEDEC_WREN },
+                .readcnt        = 0,
+                .readarr        = NULL,
+        }, {
+                .writecnt        = JEDEC_BE_5C_4BA_OUTSIZE,
+                .writearr        = (const unsigned char[]){
+                                        JEDEC_BE_5C_4BA,
+                                        (addr >> 24) & 0xff,
+                                        (addr >> 16) & 0xff,
+                                        (addr >> 8) & 0xff,
+                                        (addr & 0xff)
+                                },
+                .readcnt        = 0,
+                .readarr        = NULL,
+        }, {
+                .writecnt        = 0,
+                .writearr        = NULL,
+                .readcnt        = 0,
+                .readarr        = NULL,
+        }};
+
+        msg_trace("-> %s (0x%08X-0x%08X)\n", __func__, addr, addr + blocklen - 1);
+
+        result = spi_send_multicommand(flash, cmds);
+        if (result) {
+                msg_cerr("%s failed during command execution at address 0x%x\n",
+                        __func__, addr);
+                return result;
+        }
+        /* Wait until the Write-In-Progress bit is cleared.
+         * This usually takes 100-4000 ms, so wait in 100 ms steps.
+         */
+        while (spi_read_status_register(flash) & SPI_SR_WIP)
+                programmer_delay(100 * 1000);
+        /* FIXME: Check the status register for errors. */
+        return 0;
+}
+
+/* Erase 64 KB of flash with 4-bytes address from ANY mode (3-bytes or 4-bytes)
+   JEDEC_BE_DC_4BA (DCh) instruction is new for 4-bytes addressing flash chips.
+   The presence of this instruction for an exact chip should be checked 
+   by its datasheet or from SFDP 4-Bytes Address Instruction Table (JESD216B). */
+int spi_block_erase_dc_4ba_direct(struct flashctx *flash, unsigned int addr,
+                                   unsigned int blocklen)
+{
+        int result;
+        struct spi_command cmds[] = {
+        {
+                .writecnt        = JEDEC_WREN_OUTSIZE,
+                .writearr        = (const unsigned char[]){ JEDEC_WREN },
+                .readcnt        = 0,
+                .readarr        = NULL,
+        }, {
+                .writecnt        = JEDEC_BE_DC_4BA_OUTSIZE,
+                .writearr        = (const unsigned char[]){
+                                        JEDEC_BE_DC_4BA,
+                                        (addr >> 24) & 0xff,
+                                        (addr >> 16) & 0xff,
+                                        (addr >> 8) & 0xff,
+                                        (addr & 0xff)
+                                },
+                .readcnt        = 0,
+                .readarr        = NULL,
+        }, {
+                .writecnt        = 0,
+                .writearr        = NULL,
+                .readcnt        = 0,
+                .readarr        = NULL,
+        }};
+
+        msg_trace("-> %s (0x%08X-0x%08X)\n", __func__, addr, addr + blocklen - 1);
+
+        result = spi_send_multicommand(flash, cmds);
+        if (result) {
+                msg_cerr("%s failed during command execution at address 0x%x\n",
+                        __func__, addr);
+                return result;
+        }
+        /* Wait until the Write-In-Progress bit is cleared.
+         * This usually takes 100-4000 ms, so wait in 100 ms steps.
+         */
+        while (spi_read_status_register(flash) & SPI_SR_WIP)
+                programmer_delay(100 * 1000);
+        /* FIXME: Check the status register for errors. */
+        return 0;
+}

Property changes on: spi4ba.c
___________________________________________________________________
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: spi4ba.h
===================================================================
--- spi4ba.h        (revision 0)
+++ spi4ba.h        (working copy)
@@ -0,0 +1,158 @@
+/*  
+ * This file is part of the flashrom project.
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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
+*/
+
+/*
+ * JEDEC flash chips instructions for 4-bytes addressing
+ * SPI chip driver functions for 4-bytes addressing
+ */
+
+#ifndef __SPI_4BA_H__
+#define __SPI_4BA_H__ 1
+
+/* Read the memory with 4-byte address
+   From ANY mode (3-bytes or 4-bytes) it works with 4-byte address */
+#define JEDEC_READ_4BA                0x13
+#define JEDEC_READ_4BA_OUTSIZE        0x05
+/*      JEDEC_READ_4BA_INSIZE : any length */
+
+/* Write memory byte with 4-byte address 
+   From ANY mode (3-bytes or 4-bytes) it works with 4-byte address */
+#define JEDEC_BYTE_PROGRAM_4BA                0x12
+#define JEDEC_BYTE_PROGRAM_4BA_OUTSIZE        0x06
+#define JEDEC_BYTE_PROGRAM_4BA_INSIZE        0x00
+
+/* Sector Erase 0x21 (with 4-byte address), usually 4k size.
+   From ANY mode (3-bytes or 4-bytes) it works with 4-byte address */
+#define JEDEC_SE_4BA                0x21
+#define JEDEC_SE_4BA_OUTSIZE        0x05
+#define JEDEC_SE_4BA_INSIZE        0x00
+
+/* Block Erase 0x5C (with 4-byte address), usually 32k size.
+   From ANY mode (3-bytes or 4-bytes) it works with 4-byte address */
+#define JEDEC_BE_5C_4BA                0x5C
+#define JEDEC_BE_5C_4BA_OUTSIZE        0x05
+#define JEDEC_BE_5C_4BA_INSIZE        0x00
+
+/* Block Erase 0xDC (with 4-byte address), usually 64k size.
+   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
+
+/* Enter 4-byte Address Mode */
+#define JEDEC_ENTER_4_BYTE_ADDR_MODE                0xB7
+#define JEDEC_ENTER_4_BYTE_ADDR_MODE_OUTSIZE        0x01
+#define JEDEC_ENTER_4_BYTE_ADDR_MODE_INSIZE        0x00
+
+/* Exit 4-byte Address Mode */
+#define JEDEC_EXIT_4_BYTE_ADDR_MODE                0xE9
+#define JEDEC_EXIT_4_BYTE_ADDR_MODE_OUTSIZE        0x01
+#define JEDEC_EXIT_4_BYTE_ADDR_MODE_INSIZE        0x00
+
+/* Write Extended Address Register */
+#define JEDEC_WRITE_EXT_ADDR_REG                0xC5
+#define JEDEC_WRITE_EXT_ADDR_REG_OUTSIZE        0x02
+#define JEDEC_WRITE_EXT_ADDR_REG_INSIZE                0x00
+
+/* Read Extended Address Register */
+#define JEDEC_READ_EXT_ADDR_REG                        0xC8
+#define JEDEC_READ_EXT_ADDR_REG_OUTSIZE                0x01
+#define JEDEC_READ_EXT_ADDR_REG_INSIZE                0x01
+
+
+/* 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)
+
+/* read/write flash bytes in 4-bytes addressing mode */
+int spi_byte_program_4ba(struct flashctx *flash, unsigned int addr, uint8_t databyte);
+int spi_nbyte_program_4ba(struct flashctx *flash, unsigned int addr, const uint8_t *bytes, unsigned int len);
+int spi_nbyte_read_4ba(struct flashctx *flash, unsigned int addr, uint8_t *bytes, unsigned int len);
+
+/* read/write flash bytes with 4-bytes address from any mode (3-byte or 4-byte) */
+int spi_byte_program_4ba_direct(struct flashctx *flash, unsigned int addr, uint8_t databyte);
+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);
+
+/* read/write flash bytes from 3-bytes addressing mode using extended address register */
+int spi_byte_program_4ba_ereg(struct flashctx *flash, unsigned int addr, uint8_t databyte);
+int spi_nbyte_program_4ba_ereg(struct flashctx *flash, unsigned int addr, const uint8_t *bytes, unsigned int len);
+int spi_nbyte_read_4ba_ereg(struct flashctx *flash, unsigned int addr, uint8_t *bytes, unsigned int len);
+
+/* enter 4-bytes addressing mode */
+int spi_enter_4ba_b7(struct flashctx *flash);
+int spi_enter_4ba_b7_we(struct flashctx *flash);
+
+/* 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);
+
+/* erase flash bytes in 4-bytes addressing mode */
+int spi_block_erase_20_4ba(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
+int spi_block_erase_52_4ba(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
+int spi_block_erase_d8_4ba(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
+
+/* erase flash bytes from 3-bytes addressing mode using extended address register */
+int spi_block_erase_20_4ba_ereg(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
+int spi_block_erase_52_4ba_ereg(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
+int spi_block_erase_d8_4ba_ereg(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
+
+/* 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);
+
+/* 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);
+
+
+#endif /* __SPI_4BA_H__ */

Property changes on: spi4ba.h
___________________________________________________________________
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property 





More information about the flashrom mailing list