diff options
| author | Nico Huber <nico.h@gmx.de> | 2022-05-28 16:48:26 +0200 | 
|---|---|---|
| committer | Nico Huber <nico.h@gmx.de> | 2022-06-20 16:36:20 +0000 | 
| commit | f6d702e2d09f604830070fc0079374955481be5d (patch) | |
| tree | 506d2cccec587cc64278e956c554fb9201bf324a | |
| parent | 7db2baa77d41c3a74449a3f2b907025f69b776b9 (diff) | |
| download | flashrom-f6d702e2d09f604830070fc0079374955481be5d.tar.gz flashrom-f6d702e2d09f604830070fc0079374955481be5d.tar.bz2 flashrom-f6d702e2d09f604830070fc0079374955481be5d.zip | |
spi25_statusreg: Allow WRSR_EXT for Status Register 3
Spansion flash chips S25FL128L and S25FL256L use the WRSR instruction to
write more than 2 registers. So align SR2 and SR3 support: The current
FEATURE_WRSR_EXT is renamed to FEATURE_WRSR_EXT2 and FEATURE_WRSR_EXT3
is added. Also, WRSR3 needs a separate flag now.
Verified that FEATURE_WRSR_EXT2 still works using the `dummy_flasher`.
Signed-off-by: Nico Huber <nico.h@gmx.de>
Change-Id: Ibdfc6eb3d2cfecbf8da0493d067031ddb079a094
Reviewed-on: https://review.coreboot.org/c/flashrom/+/64746
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Nikolai Artemiev <nartemiev@google.com>
Reviewed-by: Arthur Heymans <arthur@aheymans.xyz>
Reviewed-by: Thomas Heijligen <src@posteo.de>
| -rw-r--r-- | dummyflasher.c | 23 | ||||
| -rw-r--r-- | flashchips.c | 12 | ||||
| -rw-r--r-- | include/flash.h | 4 | ||||
| -rw-r--r-- | include/spi.h | 1 | ||||
| -rw-r--r-- | spi25_statusreg.c | 79 | ||||
| -rw-r--r-- | tests/chip_wp.c | 2 | 
6 files changed, 83 insertions, 38 deletions
| diff --git a/dummyflasher.c b/dummyflasher.c index 0a2d9210..6f0a589b 100644 --- a/dummyflasher.c +++ b/dummyflasher.c @@ -44,8 +44,9 @@ struct emu_data {  	unsigned int emu_chip_size;  	/* Note: W25Q128FV doesn't change value of SR2 if it's not provided, but  	 *       even its previous generations do, so don't forget to update -	 *       WRSR code on enabling WRSR_EXT for more chips. */ -	bool emu_wrsr_ext; +	 *       WRSR code on enabling WRSR_EXT2 for more chips. */ +	bool emu_wrsr_ext2; +	bool emu_wrsr_ext3;  	int erase_to_zero;  	int emu_modified;	/* is the image modified since reading it? */  	uint8_t emu_status[3]; @@ -350,7 +351,7 @@ static int emulate_spi_chip_response(unsigned int writecnt,  {  	unsigned int offs, i, toread;  	uint8_t ro_bits; -	bool wrsr_ext; +	bool wrsr_ext2, wrsr_ext3;  	static int unsigned aai_offs;  	const unsigned char sst25vf040_rems_response[2] = {0xbf, 0x44};  	const unsigned char sst25vf032b_rems_response[2] = {0xbf, 0x4a}; @@ -511,20 +512,28 @@ static int emulate_spi_chip_response(unsigned int writecnt,  			break;  		} -		wrsr_ext = (writecnt == 3 && data->emu_wrsr_ext); +		wrsr_ext2 = (writecnt == 3 && data->emu_wrsr_ext2); +		wrsr_ext3 = (writecnt == 4 && data->emu_wrsr_ext3);  		/* FIXME: add some reasonable simulation of the busy flag */  		ro_bits = get_reg_ro_bit_mask(data, STATUS1);  		data->emu_status[0] &= ro_bits;  		data->emu_status[0] |= writearr[1] & ~ro_bits; -		if (wrsr_ext) { +		if (wrsr_ext2 || wrsr_ext3) {  			ro_bits = get_reg_ro_bit_mask(data, STATUS2);  			data->emu_status[1] &= ro_bits;  			data->emu_status[1] |= writearr[2] & ~ro_bits;  		} +		if (wrsr_ext3) { +			ro_bits = get_reg_ro_bit_mask(data, STATUS3); +			data->emu_status[2] &= ro_bits; +			data->emu_status[2] |= writearr[3] & ~ro_bits; +		} -		if (wrsr_ext) +		if (wrsr_ext3) +			msg_pdbg2("WRSR wrote 0x%02x%02x%02x.\n", data->emu_status[2], data->emu_status[1], data->emu_status[0]); +		else if (wrsr_ext2)  			msg_pdbg2("WRSR wrote 0x%02x%02x.\n", data->emu_status[1], data->emu_status[0]);  		else  			msg_pdbg2("WRSR wrote 0x%02x.\n", data->emu_status[0]); @@ -1154,7 +1163,7 @@ static int init_data(struct emu_data *data, enum chipbustype *dummy_buses_suppor  	}  	if (!strcmp(tmp, "W25Q128FV")) {  		data->emu_chip = EMULATE_WINBOND_W25Q128FV; -		data->emu_wrsr_ext = true; +		data->emu_wrsr_ext2 = true;  		data->emu_chip_size = 16 * 1024 * 1024;  		data->emu_max_byteprogram_size = 256;  		data->emu_max_aai_size = 0; diff --git a/flashchips.c b/flashchips.c index 33df792b..0579b79a 100644 --- a/flashchips.c +++ b/flashchips.c @@ -6334,7 +6334,7 @@ const struct flashchip flashchips[] = {  		.total_size	= 16384,  		.page_size	= 256,  		/* OTP: 1024B total, 256B reserved; read 0x48; write 0x42, erase 0x44 */ -		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_WRSR_EXT, +		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_WRSR_EXT2,  		.tested		= TEST_OK_PREW,  		.probe		= probe_spi_rdid,  		.probe_timing	= TIMING_ZERO, @@ -6500,7 +6500,7 @@ const struct flashchip flashchips[] = {  		.total_size	= 8192,  		.page_size	= 256,  		/* OTP: 1024B total, 256B reserved; read 0x48; write 0x42, erase 0x44 */ -		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_WRSR_EXT, +		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_WRSR_EXT2,  		.tested		= TEST_OK_PREW,  		.probe		= probe_spi_rdid,  		.probe_timing	= TIMING_ZERO, @@ -6754,7 +6754,7 @@ const struct flashchip flashchips[] = {  		.total_size	= 32768,  		.page_size	= 256,  		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_4BA_WREN | -				  FEATURE_WRSR_EXT | FEATURE_WRSR2, +				  FEATURE_WRSR_EXT2 | FEATURE_WRSR2 | FEATURE_WRSR3,  		.tested		= TEST_OK_PREW,  		.probe		= probe_spi_rdid,  		.probe_timing	= TIMING_ZERO, @@ -17181,7 +17181,8 @@ const struct flashchip flashchips[] = {  		.page_size	= 256,  		/* supports SFDP */  		/* OTP: 1024B total, 256B reserved; read 0x48; write 0x42, erase 0x44, read ID 0x4B */ -		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_WRSR2, +		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP | +				  FEATURE_WRSR_EXT2 | FEATURE_WRSR2 | FEATURE_WRSR3,  		.tested		= TEST_OK_PREW,  		.probe		= probe_spi_rdid,  		.probe_timing	= TIMING_ZERO, @@ -18071,7 +18072,8 @@ const struct flashchip flashchips[] = {  		.page_size	= 256,  		/* supports SFDP */  		/* OTP: 1024B total, 256B reserved; read 0x48; write 0x42, erase 0x44, read ID 0x4B */ -		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_WRSR2, +		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP | +				  FEATURE_WRSR_EXT2 | FEATURE_WRSR2 | FEATURE_WRSR3,  		.tested		= TEST_OK_PREW,  		.probe		= probe_spi_rdid,  		.probe_timing	= TIMING_ZERO, diff --git a/include/flash.h b/include/flash.h index da238471..4fa59492 100644 --- a/include/flash.h +++ b/include/flash.h @@ -143,8 +143,10 @@ enum write_granularity {  #define FEATURE_ERASED_ZERO	(1 << 17)  #define FEATURE_NO_ERASE	(1 << 18) -#define FEATURE_WRSR_EXT	(1 << 19) +#define FEATURE_WRSR_EXT2	(1 << 19)  #define FEATURE_WRSR2		(1 << 20) +#define FEATURE_WRSR_EXT3	((1 << 21) | FEATURE_WRSR_EXT2) +#define FEATURE_WRSR3		(1 << 22)  #define ERASED_VALUE(flash)	(((flash)->chip->feature_bits & FEATURE_ERASED_ZERO) ? 0x00 : 0xff) diff --git a/include/spi.h b/include/spi.h index 14f71aa0..05d2239a 100644 --- a/include/spi.h +++ b/include/spi.h @@ -156,7 +156,6 @@  #define JEDEC_WRSR		0x01  #define JEDEC_WRSR_OUTSIZE	0x02  #define JEDEC_WRSR_INSIZE	0x00 -#define JEDEC_WRSR_EXT_OUTSIZE	0x03  /* Write Status Register 2 */  #define JEDEC_WRSR2		0x31 diff --git a/spi25_statusreg.c b/spi25_statusreg.c index 0f430565..4cd19aba 100644 --- a/spi25_statusreg.c +++ b/spi25_statusreg.c @@ -22,11 +22,44 @@  #include "spi.h"  /* === Generic functions === */ + +/* + * Writing SR2 or higher with an extended WRSR command requires + * writing all lower SRx along with it, so just read the lower + * SRx and write them back. + */ +static int spi_prepare_wrsr_ext( +		uint8_t write_cmd[4], size_t *const write_cmd_len, +		const struct flashctx *const flash, +		const enum flash_reg reg, const uint8_t value) +{ +	enum flash_reg reg_it; +	size_t i = 0; + +	write_cmd[i++] = JEDEC_WRSR; + +	for (reg_it = STATUS1; reg_it < reg; ++reg_it) { +		uint8_t sr; + +		if (spi_read_register(flash, reg_it, &sr)) { +			msg_cerr("Writing SR%d failed: failed to read SR%d for writeback.\n", +				 reg - STATUS1 + 1, reg_it - STATUS1 + 1); +			return 1; +		} +		write_cmd[i++] = sr; +	} + +	write_cmd[i++] = value; +	*write_cmd_len = i; + +	return 0; +} +  int spi_write_register(const struct flashctx *flash, enum flash_reg reg, uint8_t value)  {  	int feature_bits = flash->chip->feature_bits; -	uint8_t write_cmd[3]; +	uint8_t write_cmd[4];  	size_t write_cmd_len = 0;  	/* @@ -46,31 +79,27 @@ int spi_write_register(const struct flashctx *flash, enum flash_reg reg, uint8_t  			write_cmd_len = JEDEC_WRSR2_OUTSIZE;  			break;  		} -		if (feature_bits & FEATURE_WRSR_EXT) { -			/* -			 * Writing SR2 with an extended WRSR command requires -			 * writing SR1 along with SR2, so just read SR1 and -			 * write it back -			 */ -			uint8_t sr1; - -			if (spi_read_register(flash, STATUS1, &sr1)) { -				msg_cerr("Writing SR2 failed: failed to read SR1 for writeback.\n"); +		if (feature_bits & FEATURE_WRSR_EXT2) { +			if (spi_prepare_wrsr_ext(write_cmd, &write_cmd_len, flash, reg, value))  				return 1; -			} -			write_cmd[0] = JEDEC_WRSR; -			write_cmd[1] = sr1; -			write_cmd[2] = value; -			write_cmd_len = JEDEC_WRSR_EXT_OUTSIZE;  			break;  		}  		msg_cerr("Cannot write SR2: unsupported by chip\n");  		return 1;  	case STATUS3: -		write_cmd[0] = JEDEC_WRSR3; -		write_cmd[1] = value; -		write_cmd_len = JEDEC_WRSR3_OUTSIZE; -		break; +		if (feature_bits & FEATURE_WRSR3) { +			write_cmd[0] = JEDEC_WRSR3; +			write_cmd[1] = value; +			write_cmd_len = JEDEC_WRSR3_OUTSIZE; +			break; +		} +		if (feature_bits & FEATURE_WRSR_EXT3) { +			if (spi_prepare_wrsr_ext(write_cmd, &write_cmd_len, flash, reg, value)) +				return 1; +			break; +		} +		msg_cerr("Cannot write SR3: unsupported by chip\n"); +		return 1;  	default:  		msg_cerr("Cannot write register: unknown register\n");  		return 1; @@ -152,15 +181,19 @@ int spi_read_register(const struct flashctx *flash, enum flash_reg reg, uint8_t  		read_cmd = JEDEC_RDSR;  		break;  	case STATUS2: -		if (feature_bits & (FEATURE_WRSR_EXT | FEATURE_WRSR2)) { +		if (feature_bits & (FEATURE_WRSR_EXT2 | FEATURE_WRSR2)) {  			read_cmd = JEDEC_RDSR2;  			break;  		}  		msg_cerr("Cannot read SR2: unsupported by chip\n");  		return 1;  	case STATUS3: -		read_cmd = JEDEC_RDSR3; -		break; +		if (feature_bits & (FEATURE_WRSR_EXT3 | FEATURE_WRSR3)) { +			read_cmd = JEDEC_RDSR3; +			break; +		} +		msg_cerr("Cannot read SR3: unsupported by chip\n"); +		return 1;  	default:  		msg_cerr("Cannot read register: unknown register\n");  		return 1; diff --git a/tests/chip_wp.c b/tests/chip_wp.c index 8b209bd3..95e6b05c 100644 --- a/tests/chip_wp.c +++ b/tests/chip_wp.c @@ -67,7 +67,7 @@ static const struct flashchip chip_W25Q128_V = {  	.read		= spi_chip_read,  	.write		= spi_chip_write_256,  	.unlock         = spi_disable_blockprotect, -	.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_WRSR2, +	.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_WRSR_EXT2 | FEATURE_WRSR2 | FEATURE_WRSR3,  	.block_erasers  =  	{  		{ | 
