[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [PATCH v5 2/2] hw/block: m25p80: Implement AAI-WP command support fo
From: |
Francisco Iglesias |
Subject: |
Re: [PATCH v5 2/2] hw/block: m25p80: Implement AAI-WP command support for SST flashes |
Date: |
Wed, 23 Dec 2020 14:18:42 +0100 |
User-agent: |
Mutt/1.10.1 (2018-07-13) |
On [2020 Dec 23] Wed 10:00:25, Bin Meng wrote:
> From: Xuzhou Cheng <xuzhou.cheng@windriver.com>
>
> Auto Address Increment (AAI) Word-Program is a special command of
> SST flashes. AAI-WP allows multiple bytes of data to be programmed
> without re-issuing the next sequential address location.
>
> Signed-off-by: Xuzhou Cheng <xuzhou.cheng@windriver.com>
> Signed-off-by: Bin Meng <bin.meng@windriver.com>
Reviewed-by: Francisco Iglesias <frasse.iglesias@gmail.com>
>
> ---
>
> Changes in v5:
> - remove the guest error logging when address wrap is detected in AAI
> - change to return s->aai_enable in m25p80_aai_enable_needed()
>
> Changes in v4:
> - simplify is_valid_aai_cmd()
> - use a subsection for s->aai_enable vm state
>
> Changes in v3:
> - initialize aai_enable to false in reset_memory()
>
> Changes in v2:
> - add aai_enable into the vmstate
> - validate AAI command before decoding a new command
> - log guest errors during AAI_WP command handling
> - report AAI status in the status register
> - abort AAI programming when address is wrapped
> - make sure AAI programming starts from the even address
>
> hw/block/m25p80.c | 73
> +++++++++++++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 73 insertions(+)
>
> diff --git a/hw/block/m25p80.c b/hw/block/m25p80.c
> index 29598b4..c64852f 100644
> --- a/hw/block/m25p80.c
> +++ b/hw/block/m25p80.c
> @@ -359,6 +359,7 @@ typedef enum {
> QPP_4 = 0x34,
> RDID_90 = 0x90,
> RDID_AB = 0xab,
> + AAI_WP = 0xad,
>
> ERASE_4K = 0x20,
> ERASE4_4K = 0x21,
> @@ -455,6 +456,7 @@ struct Flash {
> bool four_bytes_address_mode;
> bool reset_enable;
> bool quad_enable;
> + bool aai_enable;
> uint8_t ear;
>
> int64_t dirty_page;
> @@ -670,6 +672,11 @@ static void complete_collecting_data(Flash *s)
> case PP4_4:
> s->state = STATE_PAGE_PROGRAM;
> break;
> + case AAI_WP:
> + /* AAI programming starts from the even address */
> + s->cur_addr &= ~BIT(0);
> + s->state = STATE_PAGE_PROGRAM;
> + break;
> case READ:
> case READ4:
> case FAST_READ:
> @@ -768,6 +775,7 @@ static void reset_memory(Flash *s)
> s->write_enable = false;
> s->reset_enable = false;
> s->quad_enable = false;
> + s->aai_enable = false;
>
> switch (get_man(s)) {
> case MAN_NUMONYX:
> @@ -973,6 +981,11 @@ static void decode_qio_read_cmd(Flash *s)
> s->state = STATE_COLLECTING_DATA;
> }
>
> +static bool is_valid_aai_cmd(uint32_t cmd)
> +{
> + return cmd == AAI_WP || cmd == WRDI || cmd == RDSR;
> +}
> +
> static void decode_new_cmd(Flash *s, uint32_t value)
> {
> int i;
> @@ -984,6 +997,11 @@ static void decode_new_cmd(Flash *s, uint32_t value)
> s->reset_enable = false;
> }
>
> + if (get_man(s) == MAN_SST && s->aai_enable && !is_valid_aai_cmd(value)) {
> + qemu_log_mask(LOG_GUEST_ERROR,
> + "M25P80: Invalid cmd within AAI programming sequence");
> + }
> +
> switch (value) {
>
> case ERASE_4K:
> @@ -1103,6 +1121,9 @@ static void decode_new_cmd(Flash *s, uint32_t value)
>
> case WRDI:
> s->write_enable = false;
> + if (get_man(s) == MAN_SST) {
> + s->aai_enable = false;
> + }
> break;
> case WREN:
> s->write_enable = true;
> @@ -1113,6 +1134,10 @@ static void decode_new_cmd(Flash *s, uint32_t value)
> if (get_man(s) == MAN_MACRONIX) {
> s->data[0] |= (!!s->quad_enable) << 6;
> }
> + if (get_man(s) == MAN_SST) {
> + s->data[0] |= (!!s->aai_enable) << 6;
> + }
> +
> s->pos = 0;
> s->len = 1;
> s->data_read_loop = true;
> @@ -1260,6 +1285,24 @@ static void decode_new_cmd(Flash *s, uint32_t value)
> case RSTQIO:
> s->quad_enable = false;
> break;
> + case AAI_WP:
> + if (get_man(s) == MAN_SST) {
> + if (s->write_enable) {
> + if (s->aai_enable) {
> + s->state = STATE_PAGE_PROGRAM;
> + } else {
> + s->aai_enable = true;
> + s->needed_bytes = get_addr_length(s);
> + s->state = STATE_COLLECTING_DATA;
> + }
> + } else {
> + qemu_log_mask(LOG_GUEST_ERROR,
> + "M25P80: AAI_WP with write protect\n");
> + }
> + } else {
> + qemu_log_mask(LOG_GUEST_ERROR, "M25P80: Unknown cmd %x\n",
> value);
> + }
> + break;
> default:
> s->pos = 0;
> s->len = 1;
> @@ -1305,6 +1348,17 @@ static uint32_t m25p80_transfer8(SSIPeripheral *ss,
> uint32_t tx)
> trace_m25p80_page_program(s, s->cur_addr, (uint8_t)tx);
> flash_write8(s, s->cur_addr, (uint8_t)tx);
> s->cur_addr = (s->cur_addr + 1) & (s->size - 1);
> +
> + if (get_man(s) == MAN_SST && s->aai_enable && s->cur_addr == 0) {
> + /*
> + * There is no wrap mode during AAI programming once the highest
> + * unprotected memory address is reached. The Write-Enable-Latch
> + * bit is automatically reset, and AAI programming mode aborts.
> + */
> + s->write_enable = false;
> + s->aai_enable = false;
> + }
> +
> break;
>
> case STATE_READ:
> @@ -1450,6 +1504,24 @@ static const VMStateDescription
> vmstate_m25p80_data_read_loop = {
> }
> };
>
> +static bool m25p80_aai_enable_needed(void *opaque)
> +{
> + Flash *s = (Flash *)opaque;
> +
> + return s->aai_enable;
> +}
> +
> +static const VMStateDescription vmstate_m25p80_aai_enable = {
> + .name = "m25p80/aai_enable",
> + .version_id = 1,
> + .minimum_version_id = 1,
> + .needed = m25p80_aai_enable_needed,
> + .fields = (VMStateField[]) {
> + VMSTATE_BOOL(aai_enable, Flash),
> + VMSTATE_END_OF_LIST()
> + }
> +};
> +
> static const VMStateDescription vmstate_m25p80 = {
> .name = "m25p80",
> .version_id = 0,
> @@ -1480,6 +1552,7 @@ static const VMStateDescription vmstate_m25p80 = {
> },
> .subsections = (const VMStateDescription * []) {
> &vmstate_m25p80_data_read_loop,
> + &vmstate_m25p80_aai_enable,
> NULL
> }
> };
> --
> 2.7.4
>