Check for failed SPI command execution in flashrom. Although SPI itself

does not have a mechanism to signal command failure, the SPI host may be
unable to send a given command over the wire due to security or hardware
limitations. The current code ignores these mechanisms completely and
simply assumes almost every command succeeds. Complain if SPI command
execution fails.

Since locked down Intel chipsets (like the one we had problems with
earlier) only allow a small subset of commands, find the common subset
of commands between the chipset and the ROM in the chip erase case. That
is accomplished by the new spi_chip_erase_60_c7() which can be used for
chips supporting both 0x60 and 0xc7 chip erase commands.

Both parts of the patch address problems seen in the real world. The
increased verbosity for the error case will help us diagnose and address
problems better.

Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
Otherwise: Acked-by: Stefan Reinauer <stepan@coresystems.de>


git-svn-id: svn://svn.coreboot.org/coreboot/trunk@3757 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
This commit is contained in:
Carl-Daniel Hailfinger 2008-11-18 00:41:02 +00:00
parent 9648351d75
commit 7cb70d9abd
2 changed files with 71 additions and 21 deletions

View File

@ -452,19 +452,20 @@ int probe_spi_rdid4(struct flashchip *flash);
int probe_spi_res(struct flashchip *flash);
int spi_command(unsigned int writecnt, unsigned int readcnt,
const unsigned char *writearr, unsigned char *readarr);
void spi_write_enable();
void spi_write_disable();
int spi_write_enable();
int spi_write_disable();
int spi_chip_erase_60(struct flashchip *flash);
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_chip_write(struct flashchip *flash, uint8_t *buf);
int spi_chip_read(struct flashchip *flash, uint8_t *buf);
uint8_t spi_read_status_register();
void spi_disable_blockprotect(void);
int spi_disable_blockprotect(void);
void spi_byte_program(int address, uint8_t byte);
void spi_nbyte_read(int address, uint8_t *bytes, int len);
int spi_nbyte_read(int address, uint8_t *bytes, int len);
/* 82802ab.c */
int probe_82802ab(struct flashchip *flash);

View File

@ -71,20 +71,20 @@ static int spi_res(unsigned char *readarr)
return 0;
}
void spi_write_enable()
int spi_write_enable()
{
const unsigned char cmd[JEDEC_WREN_OUTSIZE] = { JEDEC_WREN };
/* Send WREN (Write Enable) */
spi_command(sizeof(cmd), 0, cmd, NULL);
return spi_command(sizeof(cmd), 0, cmd, NULL);
}
void spi_write_disable()
int spi_write_disable()
{
const unsigned char cmd[JEDEC_WRDI_OUTSIZE] = { JEDEC_WRDI };
/* Send WRDI (Write Disable) */
spi_command(sizeof(cmd), 0, cmd, NULL);
return spi_command(sizeof(cmd), 0, cmd, NULL);
}
static int probe_spi_rdid_generic(struct flashchip *flash, int bytes)
@ -274,14 +274,28 @@ void spi_prettyprint_status_register(struct flashchip *flash)
int spi_chip_erase_60(struct flashchip *flash)
{
const unsigned char cmd[JEDEC_CE_60_OUTSIZE] = {JEDEC_CE_60};
int result;
spi_disable_blockprotect();
spi_write_enable();
result = spi_disable_blockprotect();
if (result) {
printf_debug("spi_disable_blockprotect failed\n");
return result;
}
result = spi_write_enable();
if (result) {
printf_debug("spi_write_enable failed\n");
return result;
}
/* Send CE (Chip Erase) */
spi_command(sizeof(cmd), 0, cmd, NULL);
result = spi_command(sizeof(cmd), 0, cmd, NULL);
if (result) {
printf_debug("spi_chip_erase_60 failed sending erase\n");
return result;
}
/* Wait until the Write-In-Progress bit is cleared.
* This usually takes 1-85 s, so wait in 1 s steps.
*/
/* FIXME: We assume spi_read_status_register will never fail. */
while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP)
sleep(1);
return 0;
@ -290,19 +304,44 @@ int spi_chip_erase_60(struct flashchip *flash)
int spi_chip_erase_c7(struct flashchip *flash)
{
const unsigned char cmd[JEDEC_CE_C7_OUTSIZE] = { JEDEC_CE_C7 };
int result;
spi_disable_blockprotect();
spi_write_enable();
result = spi_disable_blockprotect();
if (result) {
printf_debug("spi_disable_blockprotect failed\n");
return result;
}
result = spi_write_enable();
if (result) {
printf_debug("spi_write_enable failed\n");
return result;
}
/* Send CE (Chip Erase) */
spi_command(sizeof(cmd), 0, cmd, NULL);
result = spi_command(sizeof(cmd), 0, cmd, NULL);
if (result) {
printf_debug("spi_chip_erase_60 failed sending erase\n");
return result;
}
/* Wait until the Write-In-Progress bit is cleared.
* This usually takes 1-85 s, so wait in 1 s steps.
*/
/* FIXME: We assume spi_read_status_register will never fail. */
while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP)
sleep(1);
return 0;
}
int spi_chip_erase_60_c7(struct flashchip *flash)
{
int result;
result = spi_chip_erase_60(flash);
if (result) {
printf_debug("spi_chip_erase_60 failed, trying c7\n");
result = spi_chip_erase_c7(flash);
}
return result;
}
int spi_block_erase_52(const struct flashchip *flash, unsigned long addr)
{
unsigned char cmd[JEDEC_BE_52_OUTSIZE] = {JEDEC_BE_52};
@ -390,13 +429,13 @@ int spi_sector_erase(const struct flashchip *flash, unsigned long addr)
* This is according the SST25VF016 datasheet, who knows it is more
* generic that this...
*/
void spi_write_status_register(int status)
int spi_write_status_register(int status)
{
const unsigned char cmd[JEDEC_WRSR_OUTSIZE] =
{ JEDEC_WRSR, (unsigned char)status };
/* Send WRSR (Write Status Register) */
spi_command(sizeof(cmd), 0, cmd, NULL);
return spi_command(sizeof(cmd), 0, cmd, NULL);
}
void spi_byte_program(int address, uint8_t byte)
@ -413,20 +452,30 @@ void spi_byte_program(int address, uint8_t byte)
spi_command(sizeof(cmd), 0, cmd, NULL);
}
void spi_disable_blockprotect(void)
int spi_disable_blockprotect(void)
{
uint8_t status;
int result;
status = spi_read_status_register();
/* If there is block protection in effect, unprotect it first. */
if ((status & 0x3c) != 0) {
printf_debug("Some block protection in effect, disabling\n");
spi_write_enable();
spi_write_status_register(status & ~0x3c);
result = spi_write_enable();
if (result) {
printf_debug("spi_write_enable failed\n");
return result;
}
result = spi_write_status_register(status & ~0x3c);
if (result) {
printf_debug("spi_write_status_register failed\n");
return result;
}
}
return 0;
}
void spi_nbyte_read(int address, uint8_t *bytes, int len)
int spi_nbyte_read(int address, uint8_t *bytes, int len)
{
const unsigned char cmd[JEDEC_READ_OUTSIZE] = {
JEDEC_READ,
@ -436,7 +485,7 @@ void spi_nbyte_read(int address, uint8_t *bytes, int len)
};
/* Send Read */
spi_command(sizeof(cmd), len, cmd, bytes);
return spi_command(sizeof(cmd), len, cmd, bytes);
}
int spi_chip_read(struct flashchip *flash, uint8_t *buf)