[flashrom] [PATCH 4/10] 4BA: Support for 4-bytes addressing via Extended Address Register

Boris Baykov dev at borisbaykov.com
Sun Jan 11 00:22:54 CET 2015


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 <dev at borisbaykov.com>, Russia, Jan 2014
---
diff -U 5 -N ./flashrom/chipdrivers.h ./flashrom-1868-4ba-4/chipdrivers.h
--- ./flashrom/chipdrivers.h    2015-01-11 01:55:15.000000000 +0300
+++ ./flashrom-1868-4ba-4/chipdrivers.h 2015-01-10 18:04:52.000000000 +0300
@@ -201,7 +201,13 @@
 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);
 
 #endif /* !__CHIPDRIVERS_H__ */
diff -U 5 -N ./flashrom/flash.h ./flashrom-1868-4ba-4/flash.h
--- ./flashrom/flash.h  2015-01-11 01:55:15.000000000 +0300
+++ ./flashrom-1868-4ba-4/flash.h       2015-01-10 19:00:01.000000000 +0300
@@ -124,10 +124,11 @@
 #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)
 
 enum test_state {
        OK = 0,
        NT = 1, /* Not tested */
        BAD,    /* Known to not work */
diff -U 5 -N ./flashrom/flashrom.c ./flashrom-1868-4ba-4/flashrom.c
--- ./flashrom/flashrom.c       2015-01-11 01:55:15.000000000 +0300
+++ ./flashrom-1868-4ba-4/flashrom.c    2015-01-10 15:41:29.000000000 +0300
@@ -1940,10 +1940,14 @@
        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 */
                else {
                        if (!flash->chip->four_bytes_addr_funcs.enter_4ba) {
                                msg_cerr("No function for Enter 4-bytes addressing mode for this flash chip.\n"
                                        "Please report to flashrom at flashrom.org\n");
diff -U 5 -N ./flashrom/spi4ba.c ./flashrom-1868-4ba-4/spi4ba.c
--- ./flashrom/spi4ba.c 2015-01-11 01:55:15.000000000 +0300
+++ ./flashrom-1868-4ba-4/spi4ba.c      2015-01-10 18:24:36.000000000 +0300
@@ -323,5 +323,333 @@
        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;
+}
diff -U 5 -N ./flashrom/spi4ba.h ./flashrom-1868-4ba-4/spi4ba.h
--- ./flashrom/spi4ba.h 2015-01-11 01:55:15.000000000 +0300
+++ ./flashrom-1868-4ba-4/spi4ba.h      2015-01-10 18:18:52.000000000 +0300
@@ -34,10 +34,20 @@
 /* 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
+
 /* 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 */
@@ -48,7 +58,17 @@
 /* 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);
+
 
 #endif /* __SPI_4BA_H__ */
-------------- next part --------------
A non-text attachment was scrubbed...
Name: flashrom-r1868-4ba-part-4.patch.tar.bz2
Type: application/octet-stream
Size: 3074 bytes
Desc: not available
URL: <http://www.flashrom.org/pipermail/flashrom/attachments/20150111/66fc3b06/attachment.obj>


More information about the flashrom mailing list