summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCarl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>2009-05-09 02:09:45 +0000
committerCarl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>2009-05-09 02:09:45 +0000
commit03adbe12691d512c0d9f28caa93cb35e468fd5d3 (patch)
tree9bd6460e4a69d0647706ab139184870b32244441
parentc3129208648f241c0b6538235cd4e9854ae6539d (diff)
downloadast2050-flashrom-03adbe12691d512c0d9f28caa93cb35e468fd5d3.zip
ast2050-flashrom-03adbe12691d512c0d9f28caa93cb35e468fd5d3.tar.gz
Refine handling of spi_write_enable() failures to fix chip erases on ichspi
Until the ICH SPI driver can handle preopcodes as standalone opcodes, we should handle such special opcode failure gracefully on ICH and compatible chipsets. This fixes chip erase on almost all ICH+VIA SPI masters. Thanks to Ali Nadalizadeh for helping track down this bug! Corresponding to flashrom svn r484. Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net> Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
-rw-r--r--it87spi.c13
-rw-r--r--sb600spi.c5
-rw-r--r--spi.c47
-rw-r--r--wbsio_spi.c5
4 files changed, 54 insertions, 16 deletions
diff --git a/it87spi.c b/it87spi.c
index f95f88d..d7f1833 100644
--- a/it87spi.c
+++ b/it87spi.c
@@ -196,11 +196,14 @@ int it8716f_spi_command(unsigned int writecnt, unsigned int readcnt,
}
/* Page size is usually 256 bytes */
-static void it8716f_spi_page_program(int block, uint8_t *buf, uint8_t *bios)
+static int it8716f_spi_page_program(int block, uint8_t *buf, uint8_t *bios)
{
int i;
+ int result;
- spi_write_enable();
+ result = spi_write_enable();
+ if (result)
+ return result;
OUTB(0x06, it8716f_flashport + 1);
OUTB(((2 + (fast_spi ? 1 : 0)) << 4), it8716f_flashport);
for (i = 0; i < 256; i++) {
@@ -212,6 +215,7 @@ static void it8716f_spi_page_program(int block, uint8_t *buf, uint8_t *bios)
*/
while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP)
usleep(1000);
+ return 0;
}
/*
@@ -222,12 +226,15 @@ int it8716f_over512k_spi_chip_write(struct flashchip *flash, uint8_t *buf)
{
int total_size = 1024 * flash->total_size;
int i;
+ int result;
fast_spi = 0;
spi_disable_blockprotect();
for (i = 0; i < total_size; i++) {
- spi_write_enable();
+ result = spi_write_enable();
+ if (result)
+ return result;
spi_byte_program(i, buf[i]);
while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP)
myusec_delay(10);
diff --git a/sb600spi.c b/sb600spi.c
index 9a3e99d..095fba1 100644
--- a/sb600spi.c
+++ b/sb600spi.c
@@ -68,6 +68,7 @@ int sb600_spi_write(struct flashchip *flash, uint8_t *buf)
{
int rc = 0, i;
int total_size = flash->total_size * 1024;
+ int result;
/* Erase first */
printf("Erasing flash before programming... ");
@@ -77,7 +78,9 @@ int sb600_spi_write(struct flashchip *flash, uint8_t *buf)
printf("Programming flash");
for (i = 0; i < total_size; i++, buf++) {
spi_disable_blockprotect();
- spi_write_enable();
+ result = spi_write_enable();
+ if (result)
+ return result;
spi_byte_program(i, *buf);
/* wait program complete. */
if (i % 0x8000 == 0)
diff --git a/spi.c b/spi.c
index 0a7fd2e..e6d438c 100644
--- a/spi.c
+++ b/spi.c
@@ -88,9 +88,24 @@ static int spi_res(unsigned char *readarr)
int spi_write_enable(void)
{
const unsigned char cmd[JEDEC_WREN_OUTSIZE] = { JEDEC_WREN };
+ int result;
/* Send WREN (Write Enable) */
- return spi_command(sizeof(cmd), 0, cmd, NULL);
+ result = spi_command(sizeof(cmd), 0, cmd, NULL);
+ if (result) {
+ printf_debug("spi_write_enable failed");
+ switch (flashbus) {
+ case BUS_TYPE_ICH7_SPI:
+ case BUS_TYPE_ICH9_SPI:
+ case BUS_TYPE_VIA_SPI:
+ printf_debug(" due to SPI master limitation, ignoring"
+ " and hoping it will be run as PREOP\n");
+ return 0;
+ default:
+ printf_debug("\n");
+ }
+ }
+ return result;
}
int spi_write_disable(void)
@@ -361,10 +376,8 @@ int spi_chip_erase_60(struct flashchip *flash)
return result;
}
result = spi_write_enable();
- if (result) {
- printf_debug("spi_write_enable failed\n");
+ if (result)
return result;
- }
/* Send CE (Chip Erase) */
result = spi_command(sizeof(cmd), 0, cmd, NULL);
if (result) {
@@ -391,10 +404,8 @@ int spi_chip_erase_c7(struct flashchip *flash)
return result;
}
result = spi_write_enable();
- if (result) {
- printf_debug("spi_write_enable failed\n");
+ if (result)
return result;
- }
/* Send CE (Chip Erase) */
result = spi_command(sizeof(cmd), 0, cmd, NULL);
if (result) {
@@ -424,11 +435,14 @@ int spi_chip_erase_60_c7(struct flashchip *flash)
int spi_block_erase_52(const struct flashchip *flash, unsigned long addr)
{
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);
- spi_write_enable();
+ result = spi_write_enable();
+ if (result)
+ return result;
/* Send BE (Block Erase) */
spi_command(sizeof(cmd), 0, cmd, NULL);
/* Wait until the Write-In-Progress bit is cleared.
@@ -447,11 +461,14 @@ int spi_block_erase_52(const struct flashchip *flash, unsigned long addr)
int spi_block_erase_d8(const struct flashchip *flash, unsigned long addr)
{
unsigned char cmd[JEDEC_BE_D8_OUTSIZE] = { JEDEC_BE_D8 };
+ int result;
cmd[1] = (addr & 0x00ff0000) >> 16;
cmd[2] = (addr & 0x0000ff00) >> 8;
cmd[3] = (addr & 0x000000ff);
- spi_write_enable();
+ result = spi_write_enable();
+ if (result)
+ return result;
/* Send BE (Block Erase) */
spi_command(sizeof(cmd), 0, cmd, NULL);
/* Wait until the Write-In-Progress bit is cleared.
@@ -489,11 +506,15 @@ int spi_chip_erase_d8(struct flashchip *flash)
int spi_sector_erase(const struct flashchip *flash, unsigned long addr)
{
unsigned char cmd[JEDEC_SE_OUTSIZE] = { JEDEC_SE };
+ int result;
+
cmd[1] = (addr & 0x00ff0000) >> 16;
cmd[2] = (addr & 0x0000ff00) >> 8;
cmd[3] = (addr & 0x000000ff);
- spi_write_enable();
+ 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.
@@ -623,6 +644,8 @@ int spi_aai_write(struct flashchip *flash, uint8_t *buf)
{
uint32_t pos = 2, size = flash->total_size * 1024;
unsigned char w[6] = {0xad, 0, 0, 0, buf[0], buf[1]};
+ int result;
+
switch (flashbus) {
case BUS_TYPE_WBSIO_SPI:
fprintf(stderr, "%s: impossible with Winbond SPI masters,"
@@ -632,7 +655,9 @@ int spi_aai_write(struct flashchip *flash, uint8_t *buf)
break;
}
flash->erase(flash);
- spi_write_enable();
+ result = spi_write_enable();
+ if (result)
+ return result;
spi_command(6, 0, w, NULL);
while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP)
myusec_delay(5); /* SST25VF040B Tbp is max 10us */
diff --git a/wbsio_spi.c b/wbsio_spi.c
index a3e96fd..6ab277a 100644
--- a/wbsio_spi.c
+++ b/wbsio_spi.c
@@ -189,6 +189,7 @@ int wbsio_spi_read(struct flashchip *flash, uint8_t *buf)
int wbsio_spi_write(struct flashchip *flash, uint8_t *buf)
{
int pos, size = flash->total_size * 1024;
+ int result;
if (flash->total_size > 1024) {
fprintf(stderr, "%s: Winbond saved on 4 register bits so max chip size is 1024 KB!\n", __func__);
@@ -196,7 +197,9 @@ int wbsio_spi_write(struct flashchip *flash, uint8_t *buf)
}
flash->erase(flash);
- spi_write_enable();
+ result = spi_write_enable();
+ if (result)
+ return result;
for (pos = 0; pos < size; pos++) {
spi_byte_program(pos, buf[pos]);
while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP)
OpenPOWER on IntegriCloud