diff --git a/MAINTAINERS b/MAINTAINERS index e3d5b7e09c..32e495e165 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1915,7 +1915,7 @@ SSI M: Alistair Francis S: Maintained F: hw/ssi/* -F: hw/block/m25p80.c +F: hw/block/m25p80* F: include/hw/ssi/ssi.h X: hw/ssi/xilinx_* F: tests/qtest/m25p80-test.c diff --git a/hw/block/m25p80.c b/hw/block/m25p80.c index a8d2519141..abdc4c0b0d 100644 --- a/hw/block/m25p80.c +++ b/hw/block/m25p80.c @@ -35,6 +35,7 @@ #include "qapi/error.h" #include "trace.h" #include "qom/object.h" +#include "m25p80_sfdp.h" /* 16 MiB max in 3 byte address mode */ #define MAX_3BYTES_SIZE 0x1000000 @@ -72,6 +73,7 @@ typedef struct FlashPartInfo { * This field inform how many die is in the chip. */ uint8_t die_cnt; + uint8_t (*sfdp_read)(uint32_t sfdp_addr); } FlashPartInfo; /* adapted from linux */ @@ -355,6 +357,7 @@ typedef enum { BULK_ERASE = 0xc7, READ_FSR = 0x70, RDCR = 0x15, + RDSFDP = 0x5a, READ = 0x03, READ4 = 0x13, @@ -421,6 +424,7 @@ typedef enum { STATE_COLLECTING_DATA, STATE_COLLECTING_VAR_LEN_DATA, STATE_READING_DATA, + STATE_READING_SFDP, } CMDState; typedef enum { @@ -679,6 +683,8 @@ static inline int get_addr_length(Flash *s) } switch (s->cmd_in_progress) { + case RDSFDP: + return 3; case PP4: case PP4_4: case QPP_4: @@ -823,6 +829,11 @@ static void complete_collecting_data(Flash *s) " by device\n"); } break; + + case RDSFDP: + s->state = STATE_READING_SFDP; + break; + default: break; } @@ -1431,6 +1442,16 @@ static void decode_new_cmd(Flash *s, uint32_t value) qemu_log_mask(LOG_GUEST_ERROR, "M25P80: Unknown cmd %x\n", value); } break; + case RDSFDP: + if (s->pi->sfdp_read) { + s->needed_bytes = get_addr_length(s) + 1; /* SFDP addr + dummy */ + s->pos = 0; + s->len = 0; + s->state = STATE_COLLECTING_DATA; + break; + } + /* Fallthrough */ + default: s->pos = 0; s->len = 1; @@ -1538,6 +1559,12 @@ static uint32_t m25p80_transfer8(SSIPeripheral *ss, uint32_t tx) } } break; + case STATE_READING_SFDP: + assert(s->pi->sfdp_read); + r = s->pi->sfdp_read(s->cur_addr); + trace_m25p80_read_sfdp(s, s->cur_addr, (uint8_t)r); + s->cur_addr = (s->cur_addr + 1) & (M25P80_SFDP_MAX_SIZE - 1); + break; default: case STATE_IDLE: diff --git a/hw/block/m25p80_sfdp.h b/hw/block/m25p80_sfdp.h new file mode 100644 index 0000000000..230b07ef33 --- /dev/null +++ b/hw/block/m25p80_sfdp.h @@ -0,0 +1,18 @@ +/* + * M25P80 SFDP + * + * Copyright (c) 2020, IBM Corporation. + * + * This code is licensed under the GPL version 2 or later. See the + * COPYING file in the top-level directory. + */ + +#ifndef HW_M25P80_SFDP_H +#define HW_M25P80_SFDP_H + +/* + * SFDP area has a 3 bytes address space. + */ +#define M25P80_SFDP_MAX_SIZE (1 << 24) + +#endif diff --git a/hw/block/trace-events b/hw/block/trace-events index d86b53520c..2c45a62bd5 100644 --- a/hw/block/trace-events +++ b/hw/block/trace-events @@ -80,5 +80,6 @@ m25p80_page_program(void *s, uint32_t addr, uint8_t tx) "[%p] page program cur_a m25p80_transfer(void *s, uint8_t state, uint32_t len, uint8_t needed, uint32_t pos, uint32_t cur_addr, uint8_t t) "[%p] Transfer state 0x%"PRIx8" len 0x%"PRIx32" needed 0x%"PRIx8" pos 0x%"PRIx32" addr 0x%"PRIx32" tx 0x%"PRIx8 m25p80_read_byte(void *s, uint32_t addr, uint8_t v) "[%p] Read byte 0x%"PRIx32"=0x%"PRIx8 m25p80_read_data(void *s, uint32_t pos, uint8_t v) "[%p] Read data 0x%"PRIx32"=0x%"PRIx8 +m25p80_read_sfdp(void *s, uint32_t addr, uint8_t v) "[%p] Read SFDP 0x%"PRIx32"=0x%"PRIx8 m25p80_binding(void *s) "[%p] Binding to IF_MTD drive" m25p80_binding_no_bdrv(void *s) "[%p] No BDRV - binding to RAM"