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;
}
}