summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--flash.h25
-rw-r--r--flashchips.c46
-rw-r--r--flashrom.c80
-rw-r--r--ft2232_spi.c2
-rw-r--r--it87spi.c2
-rw-r--r--sb600spi.c2
-rw-r--r--spi.c4
-rw-r--r--w39v040c.c2
8 files changed, 130 insertions, 33 deletions
diff --git a/flash.h b/flash.h
index 8752c4a..dce0e41 100644
--- a/flash.h
+++ b/flash.h
@@ -149,6 +149,17 @@ enum chipbustype {
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;
@@ -177,6 +188,19 @@ struct flashchip {
/* 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, int start, int len);
@@ -417,6 +441,7 @@ extern const char *flashrom_version;
#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 start, int len);
+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);
diff --git a/flashchips.c b/flashchips.c
index 3b72cdf..33ebd04 100644
--- a/flashchips.c
+++ b/flashchips.c
@@ -1229,7 +1229,30 @@ struct flashchip flashchips[] = {
.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,
},
@@ -1245,7 +1268,26 @@ struct flashchip flashchips[] = {
.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,
},
diff --git a/flashrom.c b/flashrom.c
index 6da6741..6c03d93 100644
--- a/flashrom.c
+++ b/flashrom.c
@@ -474,36 +474,66 @@ int read_flash(struct flashchip *flash, char *filename)
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, 0, size);
-
- 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;
}
void emergency_help_message()
diff --git a/ft2232_spi.c b/ft2232_spi.c
index 9bf1af3..ee8d67d 100644
--- a/ft2232_spi.c
+++ b/ft2232_spi.c
@@ -271,7 +271,7 @@ int ft2232_spi_write_256(struct flashchip *flash, uint8_t *buf)
spi_disable_blockprotect();
/* Erase first */
printf("Erasing flash before programming... ");
- if (flash->erase(flash)) {
+ if (erase_flash(flash)) {
fprintf(stderr, "ERASE FAILED!\n");
return -1;
}
diff --git a/it87spi.c b/it87spi.c
index d58f837..a5dc06e 100644
--- a/it87spi.c
+++ b/it87spi.c
@@ -279,7 +279,7 @@ int it8716f_spi_chip_write_256(struct flashchip *flash, uint8_t *buf)
spi_disable_blockprotect();
/* Erase first */
printf("Erasing flash before programming... ");
- if (flash->erase(flash)) {
+ if (erase_flash(flash)) {
fprintf(stderr, "ERASE FAILED!\n");
return -1;
}
diff --git a/sb600spi.c b/sb600spi.c
index c853f42..0738a86 100644
--- a/sb600spi.c
+++ b/sb600spi.c
@@ -55,7 +55,7 @@ int sb600_spi_write_1(struct flashchip *flash, uint8_t *buf)
spi_disable_blockprotect();
/* Erase first */
printf("Erasing flash before programming... ");
- if (flash->erase(flash)) {
+ if (erase_flash(flash)) {
fprintf(stderr, "ERASE FAILED!\n");
return -1;
}
diff --git a/spi.c b/spi.c
index 7a17b24..86ffe69 100644
--- a/spi.c
+++ b/spi.c
@@ -972,7 +972,7 @@ int spi_chip_write_1(struct flashchip *flash, uint8_t *buf)
spi_disable_blockprotect();
/* Erase first */
printf("Erasing flash before programming... ");
- if (flash->erase(flash)) {
+ if (erase_flash(flash)) {
fprintf(stderr, "ERASE FAILED!\n");
return -1;
}
@@ -1021,7 +1021,7 @@ int spi_aai_write(struct flashchip *flash, uint8_t *buf)
default:
break;
}
- if (flash->erase(flash)) {
+ if (erase_flash(flash)) {
fprintf(stderr, "ERASE FAILED!\n");
return -1;
}
diff --git a/w39v040c.c b/w39v040c.c
index bfa9853..722ae29 100644
--- a/w39v040c.c
+++ b/w39v040c.c
@@ -72,7 +72,7 @@ int write_w39v040c(struct flashchip *flash, uint8_t *buf)
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;
}
OpenPOWER on IntegriCloud