===================================================================
@@ -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 \
- opaque.o sfdp.o en29lv640b.o at45db.o
+ spi4ba.o opaque.o sfdp.o en29lv640b.o at45db.o
###############################################################################
# Library code.
LIB_OBJS = layout.o flashrom.o udelay.o programmer.o helpers.o
===================================================================
@@ -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_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);
+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);
+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);
+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_block_erase_21_4ba_direct(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
+int spi_block_erase_5c_4ba_direct(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
+int spi_block_erase_dc_4ba_direct(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
+erasefunc_t *spi_get_erasefn_from_opcode_4ba(uint8_t opcode);
+erasefunc_t *spi_get_erasefn_from_opcode_4ba_direct(uint8_t opcode);
+int spi_block_erase_20_4ba_selector(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
+int spi_block_erase_52_4ba_selector(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
+int spi_block_erase_d8_4ba_selector(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
+
#endif /* !__CHIPDRIVERS_H__ */
===================================================================
@@ -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);
===================================================================
@@ -121,10 +121,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_4BA_SUPPORT (1 << 10)
+#define FEATURE_4BA_ONLY (1 << 11)
+#define FEATURE_4BA_EXTENDED_ADDR_REG (1 << 12)
+#define FEATURE_4BA_DIRECT_READ (1 << 13)
+#define FEATURE_4BA_DIRECT_WRITE (1 << 14)
+#define FEATURE_4BA_ALL_ERASERS_DIRECT (1 << 15)
+#define FEATURE_4BA_ALL_DIRECT (FEATURE_4BA_DIRECT_READ | FEATURE_4BA_DIRECT_WRITE | FEATURE_4BA_ALL_ERASERS_DIRECT)
enum test_state {
OK = 0,
NT = 1, /* Not tested */
BAD, /* Known to not work */
@@ -165,10 +173,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;
@@ -188,10 +204,11 @@
* The first one that fits will be chosen. There is currently no way to
* influence that behaviour. For testing just comment out the other
* elements or set the function pointer to NULL.
*/
struct block_eraser {
+ int type; /* eraser type 1,2,3 or 4 */
struct eraseblock {
unsigned int size; /* Eraseblock size in bytes */
unsigned int count; /* Number of contiguous blocks with that size */
} eraseblocks[NUM_ERASEREGIONS];
/* a block_erase function should try to erase one block of size
@@ -339,10 +356,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);
===================================================================
@@ -13320,10 +13320,58 @@
.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_4BA_SUPPORT | FEATURE_4BA_DIRECT_READ,
+ .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,
===================================================================
@@ -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@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)
@@ -1934,10 +1957,48 @@
* erase and write.
*/
if (flash->chip->unlock)
flash->chip->unlock(flash);
+ /* Switching to 4-Bytes Addressing mode if flash chip supports it */
+ if(flash->chip->feature_bits & FEATURE_4BA_SUPPORT) {
+ /* Do not switch if chip is already in 4-bytes addressing mode */
+ if (flash->chip->feature_bits & FEATURE_4BA_ONLY) {
+ msg_cdbg("Flash chip is already in 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_4BA_EXTENDED_ADDR_REG) {
+ msg_cdbg("Using 4-bytes addressing with extended address register.\n");
+ }
+ /* Go to 4-Bytes Addressing mode if selected
+ operation requires 4-Bytes Addressing mode
+ (no need if functions are direct-4BA) */
+ else if(((read_it || verify_it)
+ && (!(flash->chip->feature_bits & FEATURE_4BA_DIRECT_READ)))
+ || ((erase_it || write_it)
+ && ((flash->chip->feature_bits & FEATURE_4BA_ALL_DIRECT) != FEATURE_4BA_ALL_DIRECT))) {
+
+ 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@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 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);
===================================================================
@@ -935,11 +935,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_4BA_SUPPORT) == 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;
}
===================================================================
@@ -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_4BA_SUPPORT) ?
+ spi_get_erasefn_from_opcode_4ba(opcode) : spi_get_erasefn_from_opcode(opcode);
if (erasefn == NULL || total_size == 0 || block_size == 0 ||
total_size % block_size != 0) {
msg_cdbg("%s: invalid input, please report to "
"flashrom@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,107 @@
" Please report this at flashrom@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@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@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_4BA_SUPPORT;
+ chip->four_bytes_addr_funcs.enter_4ba = spi_enter_4ba_b7_we;
+ chip->four_bytes_addr_funcs.program_byte = spi_byte_program_4ba;
+ chip->four_bytes_addr_funcs.program_nbyte = spi_nbyte_program_4ba;
+ chip->four_bytes_addr_funcs.read_nbyte = spi_nbyte_read_4ba;
+#else /* if FBA_USE_EXT_ADDR_REG_BY_DEFAULT defined */
+ /* assuming that 4-bytes addressing is working using
+ extended address register which can be assigned
+ throught CMD C5h and then all commands will use
+ 3-bytes address as usual */
+ chip->feature_bits |= ( FEATURE_4BA_SUPPORT |
+ FEATURE_4BA_EXTENDED_ADDR_REG );
+ chip->four_bytes_addr_funcs.enter_4ba = NULL;
+ chip->four_bytes_addr_funcs.program_byte = spi_byte_program_4ba_ereg;
+ chip->four_bytes_addr_funcs.program_nbyte = spi_nbyte_program_4ba_ereg;
+ chip->four_bytes_addr_funcs.read_nbyte = spi_nbyte_read_4ba_ereg;
+#endif /* FBA_USE_EXT_ADDR_REG_BY_DEFAULT */
break;
case 0x2:
- msg_cdbg(" 4-Byte only addressing (not supported by "
- "flashrom).\n");
- return 1;
+ msg_cdbg2(" 4-Byte only addressing.\n");
+ chip->feature_bits |= ( FEATURE_4BA_SUPPORT |
+ FEATURE_4BA_ONLY );
+ chip->four_bytes_addr_funcs.enter_4ba = NULL;
+ chip->four_bytes_addr_funcs.program_byte = spi_byte_program_4ba;
+ chip->four_bytes_addr_funcs.program_nbyte = spi_nbyte_program_4ba;
+ chip->four_bytes_addr_funcs.read_nbyte = spi_nbyte_read_4ba;
+ break;
default:
msg_cdbg(" Required addressing mode (0x%x) not supported.\n",
tmp8);
return 1;
}
@@ -168,21 +251,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 +295,305 @@
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 add the default 4k eraser after parsing erasers info.
+ In most cases this eraser has already been added before. */
+ if (opcode_4k_erase != 0xFF)
+ sfdp_add_uniform_eraser(chip, 0, opcode_4k_erase, 4 * 1024);
+
+ /* Trying to read the exact page size if it's available */
+ if (len >= 11 * 4) {
+ /* 11. double word */
+ tmp8 = buf[(4*10) + 0] >> 4; /* get upper nibble of LSB of 11th dword */
+ chip->page_size = 1 << tmp8; /* page_size = 2 ^ N */
+ msg_cdbg2(" Page size is %d B.\n", chip->page_size);
+ }
+
+ /* If the chip doesn't support 4-bytes addressing mode we don't have
+ to read and analyze 16th DWORD of Basic Flash Parameter Table */
+ if (!(chip->feature_bits & FEATURE_4BA_SUPPORT))
+ goto done;
+
+ /* In the case if the chip is working in 4-bytes addressing mode ONLY we
+ don't have to read and analyze 16th DWORD of Basic Flash Parameter Table
+ because we don't have to know how to switch to 4-bytes mode and back
+ when we are already in 4-bytes mode permanently. */
+ if (chip->feature_bits & FEATURE_4BA_ONLY)
+ goto done;
+
+ /* If the SFDP revision supported by the chip is lower that 1.6 (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;
+ }
+
+ /* 16. double word */
+ tmp32 = ((unsigned int)buf[(4 * 15) + 0]);
+ tmp32 |= ((unsigned int)buf[(4 * 15) + 1]) << 8;
+ tmp32 |= ((unsigned int)buf[(4 * 15) + 2]) << 16;
+ tmp32 |= ((unsigned int)buf[(4 * 15) + 3]) << 24;
+
+ /* Parsing 16th DWORD of Basic Flash Parameter Table according to JESD216B */
+
+ if(tmp32 & JEDEC_BFPT_DW16_ENTER_B7) {
+ msg_cdbg2(" Enter 4-bytes addressing mode by CMD B7h\n");
+ chip->four_bytes_addr_funcs.enter_4ba = spi_enter_4ba_b7;
+ chip->four_bytes_addr_funcs.program_byte = spi_byte_program_4ba;
+ chip->four_bytes_addr_funcs.program_nbyte = spi_nbyte_program_4ba;
+ chip->four_bytes_addr_funcs.read_nbyte = spi_nbyte_read_4ba;
+ /* if can go to 4BA-mode -> not need to use Ext.Addr.Reg */
+ chip->feature_bits &= ~FEATURE_4BA_EXTENDED_ADDR_REG;
+ }
+ else if(tmp32 & JEDEC_BFPT_DW16_ENTER_B7_WE) {
+ msg_cdbg2(" Enter 4-bytes addressing mode by CMD B7h with WREN\n");
+ chip->four_bytes_addr_funcs.enter_4ba = spi_enter_4ba_b7_we;
+ chip->four_bytes_addr_funcs.program_byte = spi_byte_program_4ba;
+ chip->four_bytes_addr_funcs.program_nbyte = spi_nbyte_program_4ba;
+ chip->four_bytes_addr_funcs.read_nbyte = spi_nbyte_read_4ba;
+ /* if can go to 4BA-mode -> not need to use Ext.Addr.Reg */
+ chip->feature_bits &= ~FEATURE_4BA_EXTENDED_ADDR_REG;
+ }
+ else if(tmp32 & JEDEC_BFPT_DW16_ENTER_EXTENDED_ADDR_REG) {
+ msg_cdbg2(" Extended Address Register used for 4-bytes addressing\n");
+ chip->four_bytes_addr_funcs.enter_4ba = NULL;
+ chip->four_bytes_addr_funcs.program_byte = spi_byte_program_4ba_ereg;
+ chip->four_bytes_addr_funcs.program_nbyte = spi_nbyte_program_4ba_ereg;
+ chip->four_bytes_addr_funcs.read_nbyte = spi_nbyte_read_4ba_ereg;
+ /* this flag signals to all '*_selector' functions
+ to use Ext.Addr.Reg while erase operations */
+ chip->feature_bits |= FEATURE_4BA_EXTENDED_ADDR_REG;
+ }
+ else {
+ msg_cerr("ERROR: Unable to use 4-bytes addressing for this chip.\n"
+ " Please report this at flashrom@flashrom.org\n\n");
+ return 1;
}
done:
msg_cdbg("done.\n");
return 0;
}
+/* Parse of JEDEC SFDP 4-byte address instruction table. From SFDP revision 1.6 only.
+ This parsing shoukd be called after basic flash parameter table is parsed. */
+static int sfdp_parse_4ba_table(struct flashchip *chip, uint8_t *buf, uint16_t len)
+{
+ uint32_t tmp32;
+ uint8_t tmp8;
+ int j, direct_erasers;
+ int direct_count;
+
+ msg_cdbg("Parsing JEDEC 4-byte address instuction table... ");
+ if (len != 2 * 4) {
+ msg_cdbg("%s: len out of spec\n", __func__);
+ return 1;
+ }
+ msg_cdbg2("\n");
+
+ /* 1. double word */
+ tmp32 = ((unsigned int)buf[(4 * 0) + 0]);
+ tmp32 |= ((unsigned int)buf[(4 * 0) + 1]) << 8;
+ tmp32 |= ((unsigned int)buf[(4 * 0) + 2]) << 16;
+ tmp32 |= ((unsigned int)buf[(4 * 0) + 3]) << 24;
+
+ direct_count = 0;
+
+ if(tmp32 & JEDEC_4BAIT_READ_SUPPORT) {
+ msg_cdbg2(" Found Read CMD 13h with 4-bytes address\n");
+ chip->four_bytes_addr_funcs.read_nbyte = spi_nbyte_read_4ba_direct;
+ /* read function has changed to direct 4-bytes function,
+ so entering 4-bytes mode isn't required for reading bytes */
+ chip->feature_bits |= FEATURE_4BA_DIRECT_READ;
+ direct_count++;
+ }
+
+ if(tmp32 & JEDEC_4BAIT_PROGRAM_SUPPORT) {
+ msg_cdbg2(" Found Write CMD 12h with 4-bytes address\n");
+ chip->four_bytes_addr_funcs.program_byte = spi_byte_program_4ba_direct;
+ chip->four_bytes_addr_funcs.program_nbyte = spi_nbyte_program_4ba_direct;
+ /* write (program) functions have changed to direct 4-bytes functions,
+ so entering 4-bytes mode isn't required for writing bytes */
+ chip->feature_bits |= FEATURE_4BA_DIRECT_WRITE;
+ direct_count++;
+ }
+
+ direct_erasers = 0;
+
+ /* 2. double word */
+ for (j = 0; j < 4; j++) {
+ if(!(tmp32 & (JEDEC_4BAIT_ERASE_TYPE_1_SUPPORT << j)))
+ continue;
+
+ tmp8 = buf[(4 * 1) + j];
+
+ msg_cdbg2(" Found Erase (type %d) CMD %02Xh with 4-bytes address\n", j + 1, tmp8);
+
+ if(tmp8 == 0xFF) {
+ msg_cdbg("%s: Eraser (type %d) is supported, but opcode = 0xFF\n"
+ " Please report to flashrom@flashrom.org\n\n", __func__, j + 1);
+ continue;
+ }
+
+ /* try of replacing the eraser with direct 4-bytes eraser */
+ if(!sfdp_change_uniform_eraser_4ba_direct(chip, j + 1, tmp8))
+ direct_erasers++;
+ }
+
+ for (j = 0; j < NUM_ERASEFUNCTIONS; j++) {
+ if (chip->block_erasers[j].eraseblocks[0].size == 0)
+ break;
+ }
+
+ if( j == direct_erasers ) {
+ /* if all erasers have been changed to direct 4-bytes ones,
+ then we don't have to enter 4-bytes mode for erase */
+ chip->feature_bits |= FEATURE_4BA_ALL_ERASERS_DIRECT;
+ direct_count++;
+ msg_cspew("All erasers have changed to direct ones.\n");
+ }
+
+ if( direct_count == 3 ) {
+ /* if all read/write/erase functions are direct 4-bytes now,
+ then we don't have to use extended address register */
+ chip->feature_bits &= ~FEATURE_4BA_EXTENDED_ADDR_REG;
+ msg_cspew("All read/write/erase functions have changed to direct ones.\n");
+ }
+
+ msg_cdbg("done.\n");
+ return 0;
+}
+
+#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 +601,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 +629,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 +673,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 +726,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;
}
+
===================================================================
@@ -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_4BA_SUPPORT) &&
+ 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;
}
===================================================================
@@ -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_4BA_SUPPORT) == 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_4BA_SUPPORT) == 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_4BA_SUPPORT) == 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);
}
===================================================================
@@ -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;
+}
+
+/* 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);
+}
+
+/* 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;
+}
+
+/* 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;
+}
+
+/* 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;
+}
+
+/* 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 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);
+}
+
+/* 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;
+}
+
+/* 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);
+}
+
+/* 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;
+}
+
+/* Selector for 4k eraser that chooses between 4-bytes addressing mode
+ and use of Extended Address Register from 3-bytes addressing mode */
+int spi_block_erase_20_4ba_selector(struct flashctx *flash, unsigned int addr,
+ unsigned int blocklen)
+{
+ msg_trace("-> %s\n", __func__);
+
+ return (flash->chip->feature_bits & FEATURE_4BA_EXTENDED_ADDR_REG) ?
+ spi_block_erase_20_4ba_ereg(flash, addr, blocklen) :
+ spi_block_erase_20_4ba(flash, addr, blocklen);
+}
+
+/* Selector for 32k eraser that chooses between 4-bytes addressing mode
+ and use of Extended Address Register from 3-bytes addressing mode */
+int spi_block_erase_52_4ba_selector(struct flashctx *flash, unsigned int addr,
+ unsigned int blocklen)
+{
+ msg_trace("-> %s\n", __func__);
+
+ return (flash->chip->feature_bits & FEATURE_4BA_EXTENDED_ADDR_REG) ?
+ spi_block_erase_52_4ba_ereg(flash, addr, blocklen) :
+ spi_block_erase_52_4ba(flash, addr, blocklen);
+}
+
+/* Selector for 64k eraser that chooses between 4-bytes addressing mode
+ and use of Extended Address Register from 3-bytes addressing mode */
+int spi_block_erase_d8_4ba_selector(struct flashctx *flash, unsigned int addr,
+ unsigned int blocklen)
+{
+ msg_trace("-> %s\n", __func__);
+
+ return (flash->chip->feature_bits & FEATURE_4BA_EXTENDED_ADDR_REG) ?
+ spi_block_erase_d8_4ba_ereg(flash, addr, blocklen) :
+ spi_block_erase_d8_4ba(flash, addr, blocklen);
+}
+
+/* Chooser for erase function by instruction opcode for block eraser instructions
+ to work with 4-bytes addressing flash chips. This chooser is called from sfdp.c
+ during parse of 8th & 9th dwords of SFDP Basic Flash Parameter Table */
+erasefunc_t *spi_get_erasefn_from_opcode_4ba(uint8_t opcode)
+{
+ msg_trace("-> %s\n", __func__);
+
+ switch(opcode){
+ case 0xff:
+ case 0x00:
+ /* Not specified, assuming "not supported". */
+ return NULL;
+ case 0x20:
+ return &spi_block_erase_20_4ba_selector; /* selector */
+ case 0x52:
+ return &spi_block_erase_52_4ba_selector; /* selector */
+ case 0x60:
+ return &spi_block_erase_60;
+ case 0x62:
+ return &spi_block_erase_62;
+ case 0xc7:
+ return &spi_block_erase_c7;
+ case 0xd8:
+ return &spi_block_erase_d8_4ba_selector; /* selector */
+ case 0x50:
+ case 0x81:
+ case 0xc4:
+ case 0xd7:
+ case 0xdb:
+ msg_cinfo("%s: erase opcode (0x%02x) doesn't have its 4-bytes addressing version."
+ " Please report this at flashrom@flashrom.org\n", __func__, opcode);
+ return NULL;
+ default:
+ msg_cinfo("%s: unknown erase opcode (0x%02x). Please report "
+ "this at flashrom@flashrom.org\n", __func__, opcode);
+ return NULL;
+ }
+}
+
+/* Chooser for erase function by instruction opcode for block eraser instructions
+ which can be used from ANY mode (3-bytes or 4-bytes). This chooser is called
+ from sfdp.c during parse of SFDP 4-Bytes Address Instruction Table (JESD216B) */
+erasefunc_t *spi_get_erasefn_from_opcode_4ba_direct(uint8_t opcode)
+{
+ msg_trace("-> %s\n", __func__);
+
+ switch(opcode){
+ case 0xff:
+ case 0x00:
+ /* Not specified, assuming "not supported". */
+ return NULL;
+ case 0x21:
+ return &spi_block_erase_21_4ba_direct; /* direct */
+ case 0x5C:
+ return &spi_block_erase_5c_4ba_direct; /* direct */
+ case 0xdc:
+ return &spi_block_erase_dc_4ba_direct; /* direct */
+ default:
+ msg_cinfo("%s: unknown erase opcode (0x%02x). Please report "
+ "this at flashrom@flashrom.org\n", __func__, opcode);
+ return NULL;
+ }
+}
Property changes on: spi4ba.c
___________________________________________________________________
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
===================================================================
@@ -0,0 +1,157 @@
+/*
+ * 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
+
+/* 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
+
+/* 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
+
+/* JEDEC Basic Flash Parameters Table definition */
+#define JEDEC_BFPT_ID 0xFF00
+
+/* JEDEC Basic Flash Parameters Table 16th dword according to JESD216B */
+/* 16th dword of BFPT, bits 24:31 (Enter 4-Byte Addressing) */
+#define JEDEC_BFPT_DW16_ENTER_B7 (1UL << 24)
+#define JEDEC_BFPT_DW16_ENTER_B7_WE (1UL << 25)
+#define JEDEC_BFPT_DW16_ENTER_EXTENDED_ADDR_REG (1UL << 26)
+#define JEDEC_BFPT_DW16_ENTER_BANK_ADDR_REG_EN_BIT (1UL << 27)
+#define JEDEC_BFPT_DW16_ENTER_NV_CONFIG_REG (1UL << 28)
+#define JEDEC_BFPT_DW16_VENDOR_SET (1UL << 29)
+#define JEDEC_BFPT_DW16_4_BYTES_ADDRESS_ONLY (1UL << 30)
+#define JEDEC_BFPT_DW16_ENTER_RESERVED (1UL << 31)
+/* 16th dword of BFPT, bits 14:23 (Exit 4-Byte Addressing) */
+#define JEDEC_BFPT_DW16_EXIT_E9 (1UL << 14)
+#define JEDEC_BFPT_DW16_EXIT_E9_WE (1UL << 15)
+#define JEDEC_BFPT_DW16_EXIT_EXTENDED_ADDR_REG (1UL << 16)
+#define JEDEC_BFPT_DW16_EXIT_BANK_ADDR_REG_EN_BIT (1UL << 17)
+#define JEDEC_BFPT_DW16_EXIT_NV_CONFIG_REG (1UL << 18)
+#define JEDEC_BFPT_DW16_EXIT_HARD_RESET (1UL << 19)
+#define JEDEC_BFPT_DW16_EXIT_SOFT_RESET (1UL << 20)
+#define JEDEC_BFPT_DW16_EXIT_POWER_CYCLE (1UL << 21)
+#define JEDEC_BFPT_DW16_EXIT_RESERVED_1 (1UL << 22)
+#define JEDEC_BFPT_DW16_EXIT_RESERVED_2 (1UL << 23)
+
+/* JEDEC 4-Bytes Addressing Table 1st dword according to JESD216B */
+#define JEDEC_4BAIT_ID 0xFF84
+#define JEDEC_4BAIT_READ_SUPPORT (1UL << 0)
+#define JEDEC_4BAIT_PROGRAM_SUPPORT (1UL << 6)
+#define JEDEC_4BAIT_ERASE_TYPE_1_SUPPORT (1UL << 9)
+#define JEDEC_4BAIT_ERASE_TYPE_2_SUPPORT (1UL << 10)
+#define JEDEC_4BAIT_ERASE_TYPE_3_SUPPORT (1UL << 11)
+#define JEDEC_4BAIT_ERASE_TYPE_4_SUPPORT (1UL << 12)
+
+/* enter 4-bytes addressing mode */
+int spi_enter_4ba_b7(struct flashctx *flash);
+int spi_enter_4ba_b7_we(struct flashctx *flash);
+
+/* read/write flash bytes in 4-bytes addressing mode */
+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);
+
+/* 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);
+
+/* 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);
+
+/* 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);
+
+/* 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);
+
+/* erase flash bytes with 4-bytes address from any mode (3-byte or 4-byte) */
+int spi_block_erase_21_4ba_direct(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
+int spi_block_erase_5c_4ba_direct(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
+int spi_block_erase_dc_4ba_direct(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
+
+/* erase functions choosers for 4-bytes addressing mode */
+erasefunc_t *spi_get_erasefn_from_opcode_4ba(uint8_t opcode);
+erasefunc_t *spi_get_erasefn_from_opcode_4ba_direct(uint8_t opcode);
+
+/* selection of erase function between 4-bytes addressing mode and use of extended address register */
+int spi_block_erase_20_4ba_selector(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
+int spi_block_erase_52_4ba_selector(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
+int spi_block_erase_d8_4ba_selector(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
+
+
+#endif /* __SPI_4BA_H__ */