diff --git a/hw/ssi/esp32_spi.c b/hw/ssi/esp32_spi.c index f47bfca4a822e..e40e9c9863838 100644 --- a/hw/ssi/esp32_spi.c +++ b/hw/ssi/esp32_spi.c @@ -146,6 +146,7 @@ typedef struct Esp32SpiTransaction { uint32_t cmd; int addr_bytes; uint32_t addr; + int dummy_bytes; int data_tx_bytes; int data_rx_bytes; uint32_t* data; @@ -157,11 +158,11 @@ static void esp32_spi_txrx_buffer(Esp32SpiState *s, void *buf, int tx_bytes, int uint8_t *c_buf = (uint8_t*) buf; for (int i = 0; i < bytes; ++i) { uint8_t byte = 0; - if (byte < tx_bytes) { + if (i < tx_bytes) { memcpy(&byte, c_buf + i, 1); } uint32_t res = ssi_transfer(s->spi, byte); - if (byte < rx_bytes) { + if (i < rx_bytes) { memcpy(c_buf + i, &res, 1); } } @@ -174,11 +175,19 @@ static void esp32_spi_cs_set(Esp32SpiState *s, int value) } } +static void esp32_spi_dummy_cycles(Esp32SpiState *s, int dummy_bytes) +{ + for (int i = 0; i < dummy_bytes; i++) { + ssi_transfer(s->spi, 0); + } +} + static void esp32_spi_transaction(Esp32SpiState *s, Esp32SpiTransaction *t) { esp32_spi_cs_set(s, 0); esp32_spi_txrx_buffer(s, &t->cmd, t->cmd_bytes, 0); esp32_spi_txrx_buffer(s, &t->addr, t->addr_bytes, 0); + esp32_spi_dummy_cycles(s, t->dummy_bytes); esp32_spi_txrx_buffer(s, t->data, t->data_tx_bytes, t->data_rx_bytes); esp32_spi_cs_set(s, 1); } @@ -285,6 +294,23 @@ static void esp32_spi_do_command(Esp32SpiState* s, uint32_t cmd_reg) t.addr_bytes = bitlen_to_bytes(FIELD_EX32(s->user1_reg, SPI_USER1, ADDR_BITLEN)); t.addr = bswap32(s->addr_reg); } + /* Inject 1 dummy byte for SPI flash fast-read commands when DUMMY + * phase is enabled. The m25p80 flash model expects this byte + * between address and data for DOR/QOR/FastRead etc. + * PSRAM commands handle dummy internally - don't inject for them. */ + if (FIELD_EX32(s->user_reg, SPI_USER, DUMMY)) { + switch (FIELD_EX32(s->user2_reg, SPI_USER2, COMMAND_VALUE)) { + case 0x0b: case 0x0c: /* Fast Read / Fast Read 4B */ + case 0x3b: case 0x3c: /* DOR / DOR 4B */ + case 0x6b: case 0x6c: /* QOR / QOR 4B */ + case 0xbb: case 0xbc: /* DIOR / DIOR 4B */ + case 0xeb: case 0xec: /* QIOR / QIOR 4B */ + t.dummy_bytes = 1; + break; + default: + break; + } + } if (FIELD_EX32(s->user_reg, SPI_USER, MOSI)) { t.data = &s->data_reg[0]; t.data_tx_bytes = bitlen_to_bytes(s->mosi_dlen_reg); diff --git a/hw/ssi/esp32c3_spi.c b/hw/ssi/esp32c3_spi.c index e8bd33aad07c6..a5b6f3784a8bc 100644 --- a/hw/ssi/esp32c3_spi.c +++ b/hw/ssi/esp32c3_spi.c @@ -127,11 +127,11 @@ static void esp32c3_spi_txrx_buffer(ESP32C3SpiState *s, int bytes = MAX(tx_bytes, rx_bytes); for (int i = 0; i < bytes; ++i) { uint8_t byte = 0; - if (byte < tx_bytes) { + if (i < tx_bytes) { memcpy(&byte, tx + i, 1); } uint32_t res = ssi_transfer(s->spi, byte); - if (byte < rx_bytes) { + if (i < rx_bytes) { memcpy(rx + i, &res, 1); } } diff --git a/hw/ssi/esp32s3_spi.c b/hw/ssi/esp32s3_spi.c index 90250e7e254ce..735d2cf5ebb76 100644 --- a/hw/ssi/esp32s3_spi.c +++ b/hw/ssi/esp32s3_spi.c @@ -142,11 +142,11 @@ static void esp32s3_spi_txrx_buffer(ESP32S3SpiState *s, int bytes = MAX(tx_bytes, rx_bytes); for (int i = 0; i < bytes; ++i) { uint8_t byte = 0; - if (byte < tx_bytes) { + if (i < tx_bytes) { memcpy(&byte, tx + i, 1); } uint32_t res = ssi_transfer(s->spi, byte); - if (byte < rx_bytes) { + if (i < rx_bytes) { memcpy(rx + i, &res, 1); } }