Hello Josh
I dove into the code yesterday and here is what I found. When the bits BP0 and BP1 in the status register need to be cleared the function spi_disable_blockprotect(flash) is called. To clear these bits (for the sst25lf080a ROM chip) the commands EWSR and WRSR need to be sent to the chip. In the function spi_write_status_register(...) the function spi_write_status_register_flag(...) is call to send the commands WREN and WRSR. The expectation seems to be that if this function fails to clear BP0 and BP1 bits it will return a no-zerero value and then spi_write_status_register_flag(...) will be call again to send the commands EWSR and WRSR. But spi_write_status_register_flag(...) returns a zero value for the first case so the second calll is never made. The EWSR and WRSR commands are never sent and the chip remains in protected mode.
To correct the code the commands EWSR and WRSR must be sent to the sst25lf080a. How this should be done so that the code works for other chips I leave to the people at flashrom.
Still a mystery is how the code works for the sst25lf040a chip and not the sst25lf080a chip.
Thanks Boyce
int spi_write_status_register_flag(struct flashctx *flash,int status,const unsigned char enable_opcode) { . . . result = spi_send_multicommand(flash,cmds); if (result) { . . . return result; } . . . return 0; }
int spi_write_status_register(struct flashctx *flash,int status) { int feature_bits = flash->chip->feature_bits; . . . if (feature_bits & FEATURE_WRSR_WREN) ret = spi_write_status_register_flag(flash,status,JEDEC_WREN); if (ret && feature_bits & FEATURE_WRSR_EWSR) ret = spi_write_status_register_flag(flash,status,JEDEC_EWSR); return ret; }
int spi_disable_blockprotect_generic(struct flashctx *flash,uint8_t bp_mask,uint8_t lock_mask,uint8_t wp_mask, uint8_t unprotect_mask) { . . . /* Global unprotect. ... */ result = spi_write_status_register(flash,status & ~(bp_mask | lock_mask) & unprotect_mask); if (result) { . . . return result; } . . . return 0; } int spi_disable_blockprotect(struct flashctx *flash) { return spi_disable_blockprotect_generic(flash,0x3c,0,0,0xFF); }
Hi Boyce, Josh,
On 13.06.2017 16:24, Boyce Humphries via flashrom wrote:
Hello Josh
I dove into the code yesterday and here is what I found. When the bits BP0 and BP1 in the status register need to be cleared the function spi_disable_blockprotect(flash) is called. To clear these bits (for the sst25lf080a ROM chip) the commands EWSR and WRSR need to be sent to the chip. In the function spi_write_status_register(...) the function spi_write_status_register_flag(...) is call to send the commands WREN and WRSR. The expectation seems to be that if this function fails to clear BP0 and BP1 bits it will return a no-zerero value and then spi_write_status_register_flag(...) will be call again to send the commands EWSR and WRSR. But spi_write_status_register_flag(...) returns a zero value for the first case so the second calll is never made. The EWSR and WRSR commands are never sent and the chip remains in protected mode.
this looks very odd indeed, but it can be explained: There is at least one programmer supported by flashrom (Intel southbridges) that can limit the opcodes. If a chip would support both sequences, the first call could indeed fail while the second could work. I'm not 100% sure but this could be why this code is written as is, and why there is a FEATURE_WRSR_EITHER (see below).
To correct the code the commands EWSR and WRSR must be sent to the sst25lf080a. How this should be done so that the code works for other chips I leave to the people at flashrom.
Very simple set FEATURE_WRSR_EWSR instead of FEATURE_WRSR_EITHER in flashchips.c for SST25LF080A. Maybe there really is a SST25LF080 that supports (WREN, WRSR), but I couldn't find a clue and doubt it.
Please try that and report back. Preferably with a log taken with `flashrom -o logfile.txt ...` if it works.
Still a mystery is how the code works for the sst25lf040a chip and not the sst25lf080a chip.
The former has FEATURE_WRSR_EWSR set correctly.
Nico