diff options
Diffstat (limited to 'hw/block')
-rw-r--r-- | hw/block/m25p80.c | 158 |
1 files changed, 129 insertions, 29 deletions
diff --git a/hw/block/m25p80.c b/hw/block/m25p80.c index d09a811767..c45afdd2cb 100644 --- a/hw/block/m25p80.c +++ b/hw/block/m25p80.c @@ -136,7 +136,7 @@ typedef struct FlashPartInfo { #define VCFG_WRAP_SEQUENTIAL 0x2 #define NVCFG_XIP_MODE_DISABLED (7 << 9) #define NVCFG_XIP_MODE_MASK (7 << 9) -#define VCFG_XIP_MODE_ENABLED (1 << 3) +#define VCFG_XIP_MODE_DISABLED (1 << 3) #define CFG_DUMMY_CLK_LEN 4 #define NVCFG_DUMMY_CLK_POS 12 #define VCFG_DUMMY_CLK_POS 4 @@ -144,9 +144,9 @@ typedef struct FlashPartInfo { #define EVCFG_VPP_ACCELERATOR (1 << 3) #define EVCFG_RESET_HOLD_ENABLED (1 << 4) #define NVCFG_DUAL_IO_MASK (1 << 2) -#define EVCFG_DUAL_IO_ENABLED (1 << 6) +#define EVCFG_DUAL_IO_DISABLED (1 << 6) #define NVCFG_QUAD_IO_MASK (1 << 3) -#define EVCFG_QUAD_IO_ENABLED (1 << 7) +#define EVCFG_QUAD_IO_DISABLED (1 << 7) #define NVCFG_4BYTE_ADDR_MASK (1 << 0) #define NVCFG_LOWER_SEGMENT_MASK (1 << 1) @@ -413,6 +413,12 @@ typedef enum { MAN_GENERIC, } Manufacturer; +typedef enum { + MODE_STD = 0, + MODE_DIO = 1, + MODE_QIO = 2 +} SPIMode; + #define M25P80_INTERNAL_DATA_BUFFER_SZ 16 struct Flash { @@ -768,8 +774,8 @@ static void reset_memory(Flash *s) s->volatile_cfg |= VCFG_DUMMY; s->volatile_cfg |= VCFG_WRAP_SEQUENTIAL; if ((s->nonvolatile_cfg & NVCFG_XIP_MODE_MASK) - != NVCFG_XIP_MODE_DISABLED) { - s->volatile_cfg |= VCFG_XIP_MODE_ENABLED; + == NVCFG_XIP_MODE_DISABLED) { + s->volatile_cfg |= VCFG_XIP_MODE_DISABLED; } s->volatile_cfg |= deposit32(s->volatile_cfg, VCFG_DUMMY_CLK_POS, @@ -784,10 +790,10 @@ static void reset_memory(Flash *s) s->enh_volatile_cfg |= EVCFG_VPP_ACCELERATOR; s->enh_volatile_cfg |= EVCFG_RESET_HOLD_ENABLED; if (s->nonvolatile_cfg & NVCFG_DUAL_IO_MASK) { - s->enh_volatile_cfg |= EVCFG_DUAL_IO_ENABLED; + s->enh_volatile_cfg |= EVCFG_DUAL_IO_DISABLED; } if (s->nonvolatile_cfg & NVCFG_QUAD_IO_MASK) { - s->enh_volatile_cfg |= EVCFG_QUAD_IO_ENABLED; + s->enh_volatile_cfg |= EVCFG_QUAD_IO_DISABLED; } if (!(s->nonvolatile_cfg & NVCFG_4BYTE_ADDR_MASK)) { s->four_bytes_address_mode = true; @@ -820,6 +826,41 @@ static void reset_memory(Flash *s) trace_m25p80_reset_done(s); } +static uint8_t numonyx_mode(Flash *s) +{ + if (!(s->enh_volatile_cfg & EVCFG_QUAD_IO_DISABLED)) { + return MODE_QIO; + } else if (!(s->enh_volatile_cfg & EVCFG_DUAL_IO_DISABLED)) { + return MODE_DIO; + } else { + return MODE_STD; + } +} + +static uint8_t numonyx_extract_cfg_num_dummies(Flash *s) +{ + uint8_t num_dummies; + uint8_t mode; + assert(get_man(s) == MAN_NUMONYX); + + mode = numonyx_mode(s); + num_dummies = extract32(s->volatile_cfg, 4, 4); + + if (num_dummies == 0x0 || num_dummies == 0xf) { + switch (s->cmd_in_progress) { + case QIOR: + case QIOR4: + num_dummies = 10; + break; + default: + num_dummies = (mode == MODE_QIO) ? 10 : 8; + break; + } + } + + return num_dummies; +} + static void decode_fast_read_cmd(Flash *s) { s->needed_bytes = get_addr_length(s); @@ -829,7 +870,7 @@ static void decode_fast_read_cmd(Flash *s) s->needed_bytes += 8; break; case MAN_NUMONYX: - s->needed_bytes += extract32(s->volatile_cfg, 4, 4); + s->needed_bytes += numonyx_extract_cfg_num_dummies(s); break; case MAN_MACRONIX: if (extract32(s->volatile_cfg, 6, 2) == 1) { @@ -868,7 +909,7 @@ static void decode_dio_read_cmd(Flash *s) ); break; case MAN_NUMONYX: - s->needed_bytes += extract32(s->volatile_cfg, 4, 4); + s->needed_bytes += numonyx_extract_cfg_num_dummies(s); break; case MAN_MACRONIX: switch (extract32(s->volatile_cfg, 6, 2)) { @@ -908,7 +949,7 @@ static void decode_qio_read_cmd(Flash *s) ); break; case MAN_NUMONYX: - s->needed_bytes += extract32(s->volatile_cfg, 4, 4); + s->needed_bytes += numonyx_extract_cfg_num_dummies(s); break; case MAN_MACRONIX: switch (extract32(s->volatile_cfg, 6, 2)) { @@ -950,14 +991,8 @@ static void decode_new_cmd(Flash *s, uint32_t value) case ERASE4_32K: case ERASE_SECTOR: case ERASE4_SECTOR: - case READ: - case READ4: - case DPP: - case QPP: - case QPP_4: case PP: case PP4: - case PP4_4: case DIE_ERASE: case RDID_90: case RDID_AB: @@ -966,24 +1001,84 @@ static void decode_new_cmd(Flash *s, uint32_t value) 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: - decode_fast_read_cmd(s); + 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: - decode_dio_read_cmd(s); + 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: - decode_qio_read_cmd(s); + 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: @@ -1035,17 +1130,22 @@ static void decode_new_cmd(Flash *s, uint32_t value) break; case JEDEC_READ: - 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; - } + 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; + 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: |