From: Boris Baykov <[email protected]>

On some flash chips data with addresses more than 24-bit field
can address may be accessed by using Extended Address Register.
The register has 1-byte size and stores high byte of 32-bit address.
Then flash can be read from 3-bytes addressing mode with writing
high byte of address to this Register. By using this way we have
access to full memory of a chip. Some chips may support this method
only.

This patch provides code use Extended Address Register.

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

flash.h
+ feature definitions added

flashrom.c
+ modified switch to 4-bytes addressing to support extended address register

spi4ba.h
+ definitions for 4-bytes addressing JEDEC commands
+ functions declarations from spi4ba.c (same as in chipdrivers.h, just to see)

spi4ba.c
+ functions for write Extended Address Register
+ functions for read/write/erase with Extended Address Register

Signed-off-by: Boris Baykov <[email protected]>, Russia, Jan 2014
[clg: ported from
      https://www.flashrom.org/pipermail/flashrom/2015-January/013200.html ]
Signed-off-by: Cédric Le Goater <[email protected]>
---
 chipdrivers.h |   6 ++
 flash.h       |   1 +
 flashrom.c    |   4 +
 spi4ba.c      | 328 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 spi4ba.h      |  20 ++++
 5 files changed, 359 insertions(+)

diff --git a/chipdrivers.h b/chipdrivers.h
index dccd1ff92ec1..a3da86570c42 100644
--- a/chipdrivers.h
+++ b/chipdrivers.h
@@ -204,5 +204,11 @@ int spi_nbyte_read_4ba(struct flashctx *flash, unsigned 
int addr, uint8_t *bytes
 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);
 
 #endif /* !__CHIPDRIVERS_H__ */
diff --git a/flash.h b/flash.h
index 38b30f8d8a51..cc374b798f07 100644
--- a/flash.h
+++ b/flash.h
@@ -126,6 +126,7 @@ enum write_granularity {
 /* 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)
 
 enum test_state {
        OK = 0,
diff --git a/flashrom.c b/flashrom.c
index c84843fa7c4a..79ddf76ad3d6 100644
--- a/flashrom.c
+++ b/flashrom.c
@@ -2007,6 +2007,10 @@ int doit(struct flashctx *flash, int force, const char 
*filename, int read_it,
                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 */
                else {
                        if (!flash->chip->four_bytes_addr_funcs.enter_4ba) {
diff --git a/spi4ba.c b/spi4ba.c
index 72df874275c9..db31cd2064ca 100644
--- a/spi4ba.c
+++ b/spi4ba.c
@@ -325,3 +325,331 @@ int spi_block_erase_d8_4ba(struct flashctx *flash, 
unsigned int addr,
        /* 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;
+}
diff --git a/spi4ba.h b/spi4ba.h
index 15feecb40802..f2e7bc54c669 100644
--- a/spi4ba.h
+++ b/spi4ba.h
@@ -36,6 +36,16 @@
 #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
+
 /* enter 4-bytes addressing mode */
 int spi_enter_4ba_b7(struct flashctx *flash);
 int spi_enter_4ba_b7_we(struct flashctx *flash);
@@ -50,5 +60,15 @@ int spi_block_erase_20_4ba(struct flashctx *flash, unsigned 
int addr, unsigned i
 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);
+
 
 #endif /* __SPI_4BA_H__ */
-- 
2.1.4


_______________________________________________
flashrom mailing list
[email protected]
https://www.flashrom.org/mailman/listinfo/flashrom

Reply via email to