Add 4BA support in SFDP parsing
Tested: "Found Unknown flash chip "SFDP-capable chip" (32768 kB, SPI) on
internal." on a W25Q256JW.
Also tested MX25L25645G, probe/read/erase/write.
Change-Id: I26d161bcfd16053716e8319c3d978a245390545e
Signed-off-by: Arthur Heymans <arthur@aheymans.xyz>
Reviewed-on: https://review.sourcearcade.org/c/flashprog/+/336
Reviewed-by: Nico Huber <nico.h@gmx.de>
Tested-by: Nico Huber <nico.h@gmx.de>
diff --git a/sfdp.c b/sfdp.c
index ca64b74..df939ae 100644
--- a/sfdp.c
+++ b/sfdp.c
@@ -208,9 +208,94 @@
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;
+ msg_cdbg2("Flash chip size is bigger than what 3-Byte addressing "
+ "can access, checking for 4-byte addressing support.\n");
+
+ /* Check if we have the 16th DWORD (4-byte addressing info) */
+ if (len < 16 * 4) {
+ msg_cdbg("Flash chip size requires 4-byte addressing but "
+ "SFDP table too short to contain 4BA information.\n");
+ return 1;
+ }
+
+ /* Parse 16th DWORD (offset 15 * 4 = 60) */
+ 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;
+
+ uint8_t enter_4ba = (tmp32 >> 24) & 0xFF;
+ uint16_t exit_4ba = (tmp32 >> 14) & 0x3FF;
+
+ msg_cdbg2(" 4BA Enter methods: 0x%02x, Exit methods: 0x%03x\n",
+ enter_4ba, exit_4ba);
+
+ /* Sanity check: validate exit methods correspond to enter methods */
+ if ((enter_4ba & 0x01) && !(exit_4ba & 0x01)) {
+ msg_cwarn(" Warning: Enter via B7h supported but exit via E9h not supported\n");
+ }
+ if ((enter_4ba & 0x02) && !(exit_4ba & 0x02)) {
+ msg_cwarn(" Warning: Enter via WREN+B7h supported but exit via WREN+E9h not supported\n");
+ }
+ if ((enter_4ba & 0x04) && !(exit_4ba & 0x04)) {
+ msg_cwarn(" Warning: Extended address register enter supported but exit not supported\n");
+ }
+ if ((enter_4ba & 0x08) && !(exit_4ba & 0x08)) {
+ msg_cwarn(" Warning: Bank register enter supported but exit not supported\n");
+ }
+ if ((enter_4ba & 0x10) && !(exit_4ba & 0x10)) {
+ msg_cwarn(" Warning: Nonvolatile config register enter supported but exit not supported\n");
+ }
+
+ /* Parse Enter 4-Byte Addressing methods */
+ if (enter_4ba & 0x01) {
+ /* Issue instruction B7h (no WREN required) */
+ chip->feature_bits |= FEATURE_4BA_ENTER;
+ msg_cdbg2(" Supports 4BA enter via B7h instruction\n");
+ }
+ if (enter_4ba & 0x02) {
+ /* Issue WREN (06h), then B7h */
+ chip->feature_bits |= FEATURE_4BA_ENTER_WREN;
+ /* If both bits are set, clear the conflicting FEATURE_4BA_ENTER */
+ if (enter_4ba & 0x01) {
+ msg_cwarn(" Warning: Both B7h (no WREN) and WREN+B7h methods specified - this should not happen\n");
+ chip->feature_bits &= ~FEATURE_4BA_ENTER;
+ }
+ msg_cdbg2(" Supports 4BA enter via WREN + B7h\n");
+ }
+ if (enter_4ba & 0x04) {
+ /* Extended address register (C8h read, C5h write) */
+ chip->feature_bits |= FEATURE_4BA_EAR_C5C8;
+ msg_cdbg2(" Supports extended address register (C5h/C8h)\n");
+ }
+ if (enter_4ba & 0x08) {
+ /* Bank register (16h read, 17h write) */
+ chip->feature_bits |= FEATURE_4BA_EAR_1716 | FEATURE_4BA_ENTER_EAR7;
+ msg_cdbg2(" Supports bank register (17h/16h)\n");
+ }
+ if (enter_4ba & 0x20) {
+ /* Dedicated 4-byte instruction set */
+ msg_cdbg(" Supports dedicated 4-byte instruction set (not supported by flashprog yet)\n");
+ }
+ if (enter_4ba & 0x40) {
+ /* Always operates in 4-byte mode */
+ msg_cdbg(" Always operates in 4-byte address mode\n"
+ " not supported by flashprog.\n");
+ return 1;
+
+ }
+
+ /* Check if any 4BA method is supported */
+ if (!(chip->feature_bits & (FEATURE_4BA_ENTER | FEATURE_4BA_ENTER_WREN |
+ FEATURE_4BA_EAR_C5C8 | FEATURE_4BA_EAR_1716 |
+ FEATURE_4BA_NATIVE))) {
+ msg_cdbg("Flash chip size requires 4-byte addressing but "
+ "no supported 4BA methods found in SFDP.\n");
+ return 1;
+ }
+
+ chip->prepare_access = spi_prepare_io;
+ chip->finish_access = spi_finish_io;
}
if (opcode_4k_erase != 0xFF)