On 15.06.2009 16:12, Carl-Daniel Hailfinger wrote:
> This is a patch which stores eraseblock sizes and corresponding block
> erase functions in struct flashchip. I decided to fill in the info for a
> few chips to illustrate how this works both for uniform and non-uniform
> sector sizes.
>
> struct eraseblock{
> int size; /* Eraseblock size */
> int count; /* Number of contiguous blocks with that size */
> };
>
> struct eraseblock doesn't correspond with a single erase block, but with
> a group of contiguous erase blocks having the same size.
> Given a (top boot block) flash chip with the following weird, but
> real-life structure:
>
> top
> 16384
> 8192
> 8192
> 32768
> 65536
> 65536
> 65536
> 65536
> 65536
> 65536
> 65536
> bottom
>
> we get the following encoding:
> {65536,7},{32768,1},{8192,2},{16384,1}
>
> Although the number of blocks is bigger than 4, the number of block
> groups is only 4. If you ever add some flash chips with more than 4
> contiguous block groups, the definition will not fit into the 4-member
> array anymore and gcc will recognize that and error out. No undetected
> overflow possible. In that case, you simply increase array size a bit.
> For modern flash chips with uniform erase block size, you only need one
> array member anyway.
>
> Of course data types will need to be changed if you ever get flash chips
> with more than 2^30 erase blocks, but even with the lowest known erase
> granularity of 256 bytes, these flash chips will have to have a size of
> a quarter Terabyte. I'm pretty confident we won't see such big EEPROMs
> in the near future (or at least not attached in a way that makes
> flashrom usable). For SPI chips, we even have a guaranteed safety factor
> of 4096 over the maximum SPI chip size (which is 2^24). And if such a
> big flash chip has uniform erase block size, you could even split it
> among the 4 array members. If you change int count to unsigned int
> count, the storable size doubles. So with a split and a slight change of
> data type, the maximum ROM chip size is 2 Terabytes.
>
> Since many chips have multiple block erase functions where the
> eraseblock layout depends on the block erase function, this patch
> couples the block erase functions with their eraseblock layouts.
> struct block_eraser {
>         struct eraseblock{
>                 unsigned int size; /* Eraseblock size */
>                 unsigned int count; /* Number of contiguous blocks with
> that size */
>         } eraseblocks[NUM_ERASEREGIONS];
>         int (*block_erase) (struct flashchip *flash, unsigned int
> blockaddr, unsigned int blocklen);
> } block_erasers[NUM_ERASEFUNCTIONS];
>
> This patch is an improved version of the patch I sent 7 months ago which
> received favourable reviews back then, but it seems nobody acked it. The
> original version was posted 8 months ago.
>
> The additional improvements are:
> - Chip erase is now simply a block erase with blocklength of the chip size.
> - Cleanups in flashrom.c.
>
> Signed-off-by: Carl-Daniel Hailfinger <[email protected]>
>   

Updated patch against svn HEAD attached.
It has one feature which should help debug an oddity Uwe is seeing.

Regards,
Carl-Daniel

-- 
http://www.hailfinger.org/

Index: flashrom-eraseblocks/flash.h
===================================================================
--- flashrom-eraseblocks/flash.h        (Revision 595)
+++ flashrom-eraseblocks/flash.h        (Arbeitskopie)
@@ -138,6 +138,17 @@
        CHIP_BUSTYPE_UNKNOWN    = CHIP_BUSTYPE_PARALLEL | CHIP_BUSTYPE_LPC | 
CHIP_BUSTYPE_FWH | CHIP_BUSTYPE_SPI,
 };
 
+/*
+ * How many different contiguous runs of erase blocks with one size each do
+ * we have for a given erase function?
+ */
+#define NUM_ERASEREGIONS 5
+
+/*
+ * How many different erase functions do we have per chip?
+ */
+#define NUM_ERASEFUNCTIONS 5
+
 struct flashchip {
        const char *vendor;
        const char *name;
@@ -166,6 +177,19 @@
        /* Delay after "enter/exit ID mode" commands in microseconds. */
        int probe_timing;
        int (*erase) (struct flashchip *flash);
+
+       /*
+        * Erase blocks and associated erase function. The default entry is a
+        * chip-sized virtual block together with the chip erase function.
+        */
+       struct block_eraser {
+               struct eraseblock{
+                       unsigned int size; /* Eraseblock size */
+                       unsigned int count; /* Number of contiguous blocks with 
that size */
+               } eraseblocks[NUM_ERASEREGIONS];
+               int (*block_erase) (struct flashchip *flash, unsigned int 
blockaddr, unsigned int blocklen);
+       } block_erasers[NUM_ERASEFUNCTIONS];
+
        int (*write) (struct flashchip *flash, uint8_t *buf);
        int (*read) (struct flashchip *flash, uint8_t *buf);
 
@@ -363,6 +387,7 @@
 #define printf_debug(x...) { if (verbose) printf(x); }
 void map_flash_registers(struct flashchip *flash);
 int read_memmapped(struct flashchip *flash, uint8_t *buf);
+int erase_flash(struct flashchip *flash);
 int min(int a, int b);
 int max(int a, int b);
 int check_erased_range(struct flashchip *flash, int start, int len);
@@ -404,8 +429,11 @@
 int spi_chip_erase_c7(struct flashchip *flash);
 int spi_chip_erase_60_c7(struct flashchip *flash);
 int spi_chip_erase_d8(struct flashchip *flash);
-int spi_block_erase_52(const struct flashchip *flash, unsigned long addr);
-int spi_block_erase_d8(const struct flashchip *flash, unsigned long addr);
+int spi_block_erase_20(struct flashchip *flash, unsigned int addr, unsigned 
int blocklen);
+int spi_block_erase_52(struct flashchip *flash, unsigned int addr, unsigned 
int blocklen);
+int spi_block_erase_d8(struct flashchip *flash, unsigned int addr, unsigned 
int blocklen);
+int spi_block_erase_60(struct flashchip *flash, unsigned int addr, unsigned 
int blocklen);
+int spi_block_erase_c7(struct flashchip *flash, unsigned int addr, unsigned 
int blocklen);
 int spi_chip_write_1(struct flashchip *flash, uint8_t *buf);
 int spi_chip_write_256(struct flashchip *flash, uint8_t *buf);
 int spi_chip_read(struct flashchip *flash, uint8_t *buf);
Index: flashrom-eraseblocks/flashchips.c
===================================================================
--- flashrom-eraseblocks/flashchips.c   (Revision 595)
+++ flashrom-eraseblocks/flashchips.c   (Arbeitskopie)
@@ -1204,7 +1204,30 @@
                .tested         = TEST_UNTESTED,
                .probe          = probe_spi_rdid,
                .probe_timing   = TIMING_ZERO,
-               .erase          = spi_chip_erase_60_c7,
+               .erase          = NULL,
+               .block_erasers  =
+               {
+                       {
+                               .eraseblocks = { {4 * 1024, 16} },
+                               .block_erase = spi_block_erase_20,
+                       },
+                       {
+                               .eraseblocks = { {64 * 1024, 1} },
+                               .block_erase = spi_block_erase_52,
+                       },
+                       {
+                               .eraseblocks = { {64 * 1024, 1} },
+                               .block_erase = spi_block_erase_d8,
+                       },
+                       {
+                               .eraseblocks = { {64 * 1024, 1} },
+                               .block_erase = spi_block_erase_60,
+                       },
+                       {
+                               .eraseblocks = { {64 * 1024, 1} },
+                               .block_erase = spi_block_erase_c7,
+                       },
+               },
                .write          = spi_chip_write_256,
                .read           = spi_chip_read,
        },
@@ -1220,7 +1243,26 @@
                .tested         = TEST_UNTESTED,
                .probe          = probe_spi_rdid,
                .probe_timing   = TIMING_ZERO,
-               .erase          = spi_chip_erase_60_c7,
+               .erase          = NULL,
+               .block_erasers  =
+               {
+                       {
+                               .eraseblocks = { {4 * 1024, 32} },
+                               .block_erase = spi_block_erase_20,
+                       },
+                       {
+                               .eraseblocks = { {64 * 1024, 2} },
+                               .block_erase = spi_block_erase_d8,
+                       },
+                       {
+                               .eraseblocks = { {128 * 1024, 1} },
+                               .block_erase = spi_block_erase_60,
+                       },
+                       {
+                               .eraseblocks = { {128 * 1024, 1} },
+                               .block_erase = spi_block_erase_c7,
+                       },
+               },
                .write          = spi_chip_write_256,
                .read           = spi_chip_read,
        },
Index: flashrom-eraseblocks/spi.c
===================================================================
--- flashrom-eraseblocks/spi.c  (Revision 595)
+++ flashrom-eraseblocks/spi.c  (Arbeitskopie)
@@ -469,11 +469,34 @@
        return result;
 }
 
-int spi_block_erase_52(const struct flashchip *flash, unsigned long addr)
+/* Sector size is usually 4k, though Macronix eliteflash has 64k */
+int spi_block_erase_20(struct flashchip *flash, unsigned int addr, unsigned 
int blocklen)
 {
-       unsigned char cmd[JEDEC_BE_52_OUTSIZE] = {JEDEC_BE_52};
+       unsigned char cmd[JEDEC_SE_OUTSIZE] = { JEDEC_SE, };
        int result;
+       
+       cmd[1] = (addr & 0x00ff0000) >> 16;
+       cmd[2] = (addr & 0x0000ff00) >> 8;
+       cmd[3] = (addr & 0x000000ff);
 
+       result = spi_write_enable();
+       if (result)
+               return result;
+       /* Send SE (Sector Erase) */
+       spi_command(sizeof(cmd), 0, cmd, NULL);
+       /* 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() & JEDEC_RDSR_BIT_WIP)
+               programmer_delay(10 * 1000);
+       return 0;
+}
+
+int spi_block_erase_52(struct flashchip *flash, unsigned int addr, unsigned 
int blocklen)
+{
+       unsigned char cmd[JEDEC_BE_52_OUTSIZE] = {JEDEC_BE_52, };
+       int result;
+
        cmd[1] = (addr & 0x00ff0000) >> 16;
        cmd[2] = (addr & 0x0000ff00) >> 8;
        cmd[3] = (addr & 0x000000ff);
@@ -495,9 +518,9 @@
  * 32k for SST
  * 4-32k non-uniform for EON
  */
-int spi_block_erase_d8(const struct flashchip *flash, unsigned long addr)
+int spi_block_erase_d8(struct flashchip *flash, unsigned int addr, unsigned 
int blocklen)
 {
-       unsigned char cmd[JEDEC_BE_D8_OUTSIZE] = { JEDEC_BE_D8 };
+       unsigned char cmd[JEDEC_BE_D8_OUTSIZE] = { JEDEC_BE_D8, };
        int result;
 
        cmd[1] = (addr & 0x00ff0000) >> 16;
@@ -527,7 +550,7 @@
        printf("Erasing chip: \n");
 
        for (i = 0; i < total_size / erase_size; i++) {
-               rc = spi_block_erase_d8(flash, i * erase_size);
+               rc = spi_block_erase_d8(flash, i * erase_size, erase_size);
                if (rc) {
                        printf("Error erasing block at 0x%x\n", i);
                        break;
@@ -539,27 +562,22 @@
        return rc;
 }
 
-/* Sector size is usually 4k, though Macronix eliteflash has 64k */
-int spi_sector_erase(const struct flashchip *flash, unsigned long addr)
+int spi_block_erase_60(struct flashchip *flash, unsigned int addr, unsigned 
int blocklen)
 {
-       unsigned char cmd[JEDEC_SE_OUTSIZE] = { JEDEC_SE };
-       int result;
-       
-       cmd[1] = (addr & 0x00ff0000) >> 16;
-       cmd[2] = (addr & 0x0000ff00) >> 8;
-       cmd[3] = (addr & 0x000000ff);
+       if ((addr != 0) || (blocklen != flash->total_size * 1024)) {
+               fprintf(stderr, "%s called with incorrect arguments\n", 
__func__);
+               return -1;
+       }
+       return spi_chip_erase_60(flash);
+}
 
-       result = spi_write_enable();
-       if (result)
-               return result;
-       /* Send SE (Sector Erase) */
-       spi_command(sizeof(cmd), 0, cmd, NULL);
-       /* 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() & JEDEC_RDSR_BIT_WIP)
-               programmer_delay(10 * 1000);
-       return 0;
+int spi_block_erase_c7(struct flashchip *flash, unsigned int addr, unsigned 
int blocklen)
+{
+       if ((addr != 0) || (blocklen != flash->total_size * 1024)) {
+               fprintf(stderr, "%s called with incorrect arguments\n", 
__func__);
+               return -1;
+       }
+       return spi_chip_erase_c7(flash);
 }
 
 int spi_write_status_enable(void)
@@ -663,6 +681,7 @@
 
 int spi_nbyte_read(int address, uint8_t *bytes, int len)
 {
+       printf_debug("%s: len=%i\n", __func__, len);
        const unsigned char cmd[JEDEC_READ_OUTSIZE] = {
                JEDEC_READ,
                (address >> 16) & 0xff,
@@ -791,7 +810,10 @@
        default:
                break;
        }
-       flash->erase(flash);
+       if (erase_flash(flash)) {
+               fprintf(stderr, "ERASE FAILED!\n");
+               return -1;
+       }
        result = spi_write_enable();
        if (result)
                return result;
Index: flashrom-eraseblocks/wbsio_spi.c
===================================================================
--- flashrom-eraseblocks/wbsio_spi.c    (Revision 595)
+++ flashrom-eraseblocks/wbsio_spi.c    (Arbeitskopie)
@@ -196,7 +196,7 @@
                return 1;
        }
 
-       if (flash->erase(flash)) {
+       if (erase_flash(flash)) {
                fprintf(stderr, "ERASE FAILED!\n");
                return -1;
        }
Index: flashrom-eraseblocks/w39v040c.c
===================================================================
--- flashrom-eraseblocks/w39v040c.c     (Revision 595)
+++ flashrom-eraseblocks/w39v040c.c     (Arbeitskopie)
@@ -78,7 +78,7 @@
        int page_size = flash->page_size;
        chipaddr bios = flash->virtual_memory;
 
-       if (flash->erase(flash)) {
+       if (erase_flash(flash)) {
                fprintf(stderr, "ERASE FAILED!\n");
                return -1;
        }
Index: flashrom-eraseblocks/sb600spi.c
===================================================================
--- flashrom-eraseblocks/sb600spi.c     (Revision 595)
+++ flashrom-eraseblocks/sb600spi.c     (Arbeitskopie)
@@ -63,7 +63,7 @@
 
        /* Erase first */
        printf("Erasing flash before programming... ");
-       if (flash->erase(flash)) {
+       if (erase_flash(flash)) {
                fprintf(stderr, "ERASE FAILED!\n");
                return -1;
        }
Index: flashrom-eraseblocks/flashrom.c
===================================================================
--- flashrom-eraseblocks/flashrom.c     (Revision 595)
+++ flashrom-eraseblocks/flashrom.c     (Arbeitskopie)
@@ -463,36 +463,66 @@
 
 int erase_flash(struct flashchip *flash)
 {
-       uint32_t erasedbytes;
-       unsigned long size = flash->total_size * 1024;
-       unsigned char *buf = calloc(size, sizeof(char));
+       int i, j, k, ret = 0, found = 0;
+
        printf("Erasing flash chip... ");
-       if (NULL == flash->erase) {
-               printf("FAILED!\n");
+       for (k = 0; k < NUM_ERASEFUNCTIONS; k++) {
+               unsigned long done = 0;
+               struct block_eraser eraser = flash->block_erasers[k];
+
+               printf_debug("Looking at blockwise erase function %i... ", k);
+               if (!eraser.block_erase && !eraser.eraseblocks[0].count) {
+                       printf_debug("not defined. "
+                               "Looking for another erase function.\n");
+                       continue;
+               }
+               if (!eraser.block_erase && eraser.eraseblocks[0].count) {
+                       printf_debug("eraseblock layout is known, but no "
+                               "matching block erase function found. "
+                               "Looking for another erase function.\n");
+                       continue;
+               }
+               if (eraser.block_erase && !eraser.eraseblocks[0].count) {
+                       printf_debug("block erase function found, but "
+                               "eraseblock layout is unknown. "
+                               "Looking for another erase function.\n");
+                       continue;
+               }
+               found = 1;
+               printf_debug("trying... ");
+               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.
+                        */
+                       for (j = 0; j < eraser.eraseblocks[i].count; j++) {
+                               ret = eraser.block_erase(flash, done + 
eraser.eraseblocks[i].size * j, eraser.eraseblocks[i].size);
+                               if (ret)
+                                       break;
+                       }
+                       if (ret)
+                               break;
+               }
+               /* If everything is OK, don't try another erase function. */
+               if (!ret)
+                       break;
+       }
+       /* If no block erase function was found or block erase failed, retry. */
+       if ((!found || ret) && (flash->erase)) {
+               found = 1;
+               printf_debug("Trying whole-chip erase function... ");
+               ret = flash->erase(flash);
+       }
+       if (!found) {
                fprintf(stderr, "ERROR: flashrom has no erase function for this 
flash chip.\n");
                return 1;
        }
-       flash->erase(flash);
 
-       /* FIXME: The lines below are superfluous. We should check the result
-        * of flash->erase(flash) instead.
-        */
-       if (!flash->read) {
-               printf("FAILED!\n");
-               fprintf(stderr, "ERROR: flashrom has no read function for this 
flash chip.\n");
-               return 1;
-       } else
-               flash->read(flash, buf);
-
-       for (erasedbytes = 0; erasedbytes < size; erasedbytes++)
-               if (0xff != buf[erasedbytes]) {
-                       printf("FAILED!\n");
-                       fprintf(stderr, "ERROR at 0x%08x: Expected=0xff, 
Read=0x%02x\n",
-                               erasedbytes, buf[erasedbytes]);
-                       return 1;
-               }
-       printf("SUCCESS.\n");
-       return 0;
+       if (ret) {
+               fprintf(stderr, "FAILED!\n");
+       } else {
+               printf("SUCCESS.\n");
+       }
+       return ret;
 }
 
 #ifndef MAX
Index: flashrom-eraseblocks/ichspi.c
===================================================================
--- flashrom-eraseblocks/ichspi.c       (Revision 595)
+++ flashrom-eraseblocks/ichspi.c       (Arbeitskopie)
@@ -674,7 +674,7 @@
                 * For this, we need to add a block erase function to
                 * struct flashchip.
                 */
-               rc = spi_block_erase_d8(flash, i * erase_size);
+               rc = spi_block_erase_d8(flash, i * erase_size, erase_size);
                if (rc) {
                        printf("Error erasing block at 0x%x\n", i);
                        break;
-- 
coreboot mailing list: [email protected]
http://www.coreboot.org/mailman/listinfo/coreboot

Reply via email to