hw/block:m25p80: Support write status register 2 command (0x31) for w25q01jvq

According to the w25q01jv datasheet at page 16, it is required to set QE bit
in "Status Register 2" to enable quad mode.

Currently, m25p80 support users utilize "Write Status Register 1(0x01)" command
to set QE bit in "Status Register 2" and utilize "Read Status Register 2(0x35)"
command to get the QE bit status.

However, some firmware directly utilize "Status Register 2(0x31)" command to
set QE bit. To fully support quad mode for w25q01jvq, adds WRSR2 command.

Update collecting data needed 1 byte for WRSR2 command in decode_new_cmd
function and verify QE bit at the first byte of collecting data bit 2 in
complete_collecting_data.

Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
Reviewed-by: Cédric Le Goater <clg@redhat.com>
This commit is contained in:
Jamin Lin 2024-10-22 17:40:55 +08:00 committed by Cédric Le Goater
parent c0400e3ac6
commit 9785731ec4

View File

@ -430,6 +430,11 @@ typedef enum {
RDCR_EQIO = 0x35,
RSTQIO = 0xf5,
/*
* Winbond: 0x31 - write status register 2
*/
WRSR2 = 0x31,
RNVCR = 0xB5,
WNVCR = 0xB1,
@ -821,6 +826,15 @@ static void complete_collecting_data(Flash *s)
s->write_enable = false;
}
break;
case WRSR2:
switch (get_man(s)) {
case MAN_WINBOND:
s->quad_enable = !!(s->data[0] & 0x02);
break;
default:
break;
}
break;
case BRWR:
case EXTEND_ADDR_WRITE:
s->ear = s->data[0];
@ -1280,7 +1294,31 @@ static void decode_new_cmd(Flash *s, uint32_t value)
}
s->pos = 0;
break;
case WRSR2:
/*
* If WP# is low and status_register_write_disabled is high,
* status register writes are disabled.
* This is also called "hardware protected mode" (HPM). All other
* combinations of the two states are called "software protected mode"
* (SPM), and status register writes are permitted.
*/
if ((s->wp_level == 0 && s->status_register_write_disabled)
|| !s->write_enable) {
qemu_log_mask(LOG_GUEST_ERROR,
"M25P80: Status register 2 write is disabled!\n");
break;
}
switch (get_man(s)) {
case MAN_WINBOND:
s->needed_bytes = 1;
s->state = STATE_COLLECTING_DATA;
s->pos = 0;
break;
default:
break;
}
break;
case WRDI:
s->write_enable = false;
if (get_man(s) == MAN_SST) {