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