static void decode_new_cmd()

in hw/block/m25p80.c [1065:1401]


static void decode_new_cmd(Flash *s, uint32_t value)
{
    int i;

    s->cmd_in_progress = value;
    trace_m25p80_command_decoded(s, value);

    if (value != RESET_MEMORY) {
        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:
    case ERASE4_4K:
    case ERASE_32K:
    case ERASE4_32K:
    case ERASE_SECTOR:
    case ERASE4_SECTOR:
    case PP:
    case PP4:
    case DIE_ERASE:
    case RDID_90:
    case RDID_AB:
        s->needed_bytes = get_addr_length(s);
        s->pos = 0;
        s->len = 0;
        s->state = STATE_COLLECTING_DATA;
        break;
    case READ:
    case READ4:
        if (get_man(s) != MAN_NUMONYX || numonyx_mode(s) == MODE_STD) {
            s->needed_bytes = get_addr_length(s);
            s->pos = 0;
            s->len = 0;
            s->state = STATE_COLLECTING_DATA;
        } else {
            qemu_log_mask(LOG_GUEST_ERROR, "M25P80: Cannot execute cmd %x in "
                          "DIO or QIO mode\n", s->cmd_in_progress);
        }
        break;
    case DPP:
        if (get_man(s) != MAN_NUMONYX || numonyx_mode(s) != MODE_QIO) {
            s->needed_bytes = get_addr_length(s);
            s->pos = 0;
            s->len = 0;
            s->state = STATE_COLLECTING_DATA;
        } else {
            qemu_log_mask(LOG_GUEST_ERROR, "M25P80: Cannot execute cmd %x in "
                          "QIO mode\n", s->cmd_in_progress);
        }
        break;
    case QPP:
    case QPP_4:
    case PP4_4:
        if (get_man(s) != MAN_NUMONYX || numonyx_mode(s) != MODE_DIO) {
            s->needed_bytes = get_addr_length(s);
            s->pos = 0;
            s->len = 0;
            s->state = STATE_COLLECTING_DATA;
        } else {
            qemu_log_mask(LOG_GUEST_ERROR, "M25P80: Cannot execute cmd %x in "
                          "DIO mode\n", s->cmd_in_progress);
        }
        break;

    case FAST_READ:
    case FAST_READ4:
        decode_fast_read_cmd(s);
        break;
    case DOR:
    case DOR4:
        if (get_man(s) != MAN_NUMONYX || numonyx_mode(s) != MODE_QIO) {
            decode_fast_read_cmd(s);
        } else {
            qemu_log_mask(LOG_GUEST_ERROR, "M25P80: Cannot execute cmd %x in "
                          "QIO mode\n", s->cmd_in_progress);
        }
        break;
    case QOR:
    case QOR4:
        if (get_man(s) != MAN_NUMONYX || numonyx_mode(s) != MODE_DIO) {
            decode_fast_read_cmd(s);
        } else {
            qemu_log_mask(LOG_GUEST_ERROR, "M25P80: Cannot execute cmd %x in "
                          "DIO mode\n", s->cmd_in_progress);
        }
        break;

    case DIOR:
    case DIOR4:
        if (get_man(s) != MAN_NUMONYX || numonyx_mode(s) != MODE_QIO) {
            decode_dio_read_cmd(s);
        } else {
            qemu_log_mask(LOG_GUEST_ERROR, "M25P80: Cannot execute cmd %x in "
                          "QIO mode\n", s->cmd_in_progress);
        }
        break;

    case QIOR:
    case QIOR4:
        if (get_man(s) != MAN_NUMONYX || numonyx_mode(s) != MODE_DIO) {
            decode_qio_read_cmd(s);
        } else {
            qemu_log_mask(LOG_GUEST_ERROR, "M25P80: Cannot execute cmd %x in "
                          "DIO mode\n", s->cmd_in_progress);
        }
        break;

    case WRSR:
        if (s->write_enable && !s->status_register_write_disabled) {
            switch (get_man(s)) {
            case MAN_SPANSION:
                s->needed_bytes = 2;
                s->state = STATE_COLLECTING_DATA;
                break;
            case MAN_MACRONIX:
                s->needed_bytes = 2;
                s->state = STATE_COLLECTING_VAR_LEN_DATA;
                break;
            default:
                s->needed_bytes = 1;
                s->state = STATE_COLLECTING_DATA;
            }
            s->pos = 0;
        }
        break;

    case WRDI:
        s->write_enable = false;
        if (get_man(s) == MAN_SST) {
            s->aai_enable = false;
        }
        break;
    case WREN:
        s->write_enable = true;
        break;

    case RDSR:
        s->data[0] = (!!s->write_enable) << 1;
        s->data[0] |= (!!s->block_protect0) << 2;
        s->data[0] |= (!!s->block_protect1) << 3;
        s->data[0] |= (!!s->block_protect2) << 4;
        s->data[0] |= (!!s->block_protect3) << 5;
        s->data[0] |= (!!s->status_register_write_disabled) << 7;
        switch (get_man(s)) {
        case MAN_MACRONIX:
        case MAN_ISSI:
            s->data[0] |= (!!s->quad_enable) << 6;
            break;
        case MAN_SST:
            s->data[0] |= (!!s->aai_enable) << 6;
            break;
        default:
            break;
        }

        s->pos = 0;
        s->len = 1;
        s->data_read_loop = true;
        s->state = STATE_READING_DATA;
        break;

    case READ_FSR:
        s->data[0] = FSR_FLASH_READY;
        if (s->four_bytes_address_mode) {
            s->data[0] |= FSR_4BYTE_ADDR_MODE_ENABLED;
        }
        s->pos = 0;
        s->len = 1;
        s->data_read_loop = true;
        s->state = STATE_READING_DATA;
        break;

    case JEDEC_READ:
        if (get_man(s) != MAN_NUMONYX || numonyx_mode(s) == MODE_STD) {
            trace_m25p80_populated_jedec(s);
            for (i = 0; i < s->pi->id_len; i++) {
                s->data[i] = s->pi->id[i];
            }
            for (; i < SPI_NOR_MAX_ID_LEN; i++) {
                s->data[i] = 0;
            }

            s->len = SPI_NOR_MAX_ID_LEN;
            s->pos = 0;
            s->state = STATE_READING_DATA;
        } else {
            qemu_log_mask(LOG_GUEST_ERROR, "M25P80: Cannot execute JEDEC read "
                          "in DIO or QIO mode\n");
        }
        break;

    case RDCR:
        s->data[0] = s->volatile_cfg & 0xFF;
        s->data[0] |= (!!s->four_bytes_address_mode) << 5;
        s->pos = 0;
        s->len = 1;
        s->state = STATE_READING_DATA;
        break;

    case BULK_ERASE_60:
    case BULK_ERASE:
        if (s->write_enable) {
            trace_m25p80_chip_erase(s);
            flash_erase(s, 0, BULK_ERASE);
        } else {
            qemu_log_mask(LOG_GUEST_ERROR, "M25P80: chip erase with write "
                          "protect!\n");
        }
        break;
    case NOP:
        break;
    case EN_4BYTE_ADDR:
        s->four_bytes_address_mode = true;
        break;
    case EX_4BYTE_ADDR:
        s->four_bytes_address_mode = false;
        break;
    case BRRD:
    case EXTEND_ADDR_READ:
        s->data[0] = s->ear;
        s->pos = 0;
        s->len = 1;
        s->state = STATE_READING_DATA;
        break;
    case BRWR:
    case EXTEND_ADDR_WRITE:
        if (s->write_enable) {
            s->needed_bytes = 1;
            s->pos = 0;
            s->len = 0;
            s->state = STATE_COLLECTING_DATA;
        }
        break;
    case RNVCR:
        s->data[0] = s->nonvolatile_cfg & 0xFF;
        s->data[1] = (s->nonvolatile_cfg >> 8) & 0xFF;
        s->pos = 0;
        s->len = 2;
        s->state = STATE_READING_DATA;
        break;
    case WNVCR:
        if (s->write_enable && get_man(s) == MAN_NUMONYX) {
            s->needed_bytes = 2;
            s->pos = 0;
            s->len = 0;
            s->state = STATE_COLLECTING_DATA;
        }
        break;
    case RVCR:
        s->data[0] = s->volatile_cfg & 0xFF;
        s->pos = 0;
        s->len = 1;
        s->state = STATE_READING_DATA;
        break;
    case WVCR:
        if (s->write_enable) {
            s->needed_bytes = 1;
            s->pos = 0;
            s->len = 0;
            s->state = STATE_COLLECTING_DATA;
        }
        break;
    case REVCR:
        s->data[0] = s->enh_volatile_cfg & 0xFF;
        s->pos = 0;
        s->len = 1;
        s->state = STATE_READING_DATA;
        break;
    case WEVCR:
        if (s->write_enable) {
            s->needed_bytes = 1;
            s->pos = 0;
            s->len = 0;
            s->state = STATE_COLLECTING_DATA;
        }
        break;
    case RESET_ENABLE:
        s->reset_enable = true;
        break;
    case RESET_MEMORY:
        if (s->reset_enable) {
            reset_memory(s);
        }
        break;
    case RDCR_EQIO:
        switch (get_man(s)) {
        case MAN_SPANSION:
            s->data[0] = (!!s->quad_enable) << 1;
            s->pos = 0;
            s->len = 1;
            s->state = STATE_READING_DATA;
            break;
        case MAN_MACRONIX:
            s->quad_enable = true;
            break;
        default:
            break;
        }
        break;
    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;
        s->state = STATE_READING_DATA;
        s->data_read_loop = true;
        s->data[0] = 0;
        qemu_log_mask(LOG_GUEST_ERROR, "M25P80: Unknown cmd %x\n", value);
        break;
    }
}