@samitouri / QOSamiQemu / commits / 7017b47701

hw/ssi: xilinx_spips: Fix dummy phase handling

The ZynqMP generic FIFO encodes dummy phases as a number of dummy cycles. QEMU's SSI bus transfers whole bytes, so the controller model must convert the programmed cycle count to the number of SSI byte transfers needed for the selected SPI, dual SPI or quad SPI mode. The legacy Xilinx QSPI snoop paths had the opposite problem after the m25p80 dummy handling was fixed. They still treated each dummy byte queued through the FIFO as a request to generate several SSI transfers based on the current link width. The flash model now consumes dummy phases as byte counts, so the manual FIFO path should forward one SSI transfer per dummy byte. Update the Xilinx QSPI dummy accounting consistently for the generic FIFO, manual FIFO and LQSPI direct-read paths. Also make the command table report the dummy byte counts consumed by m25p80 for dual and quad output reads, and account for the mode byte before LQSPI data reads begin. This matches the ZynqMP TRM (ug1085, v2.2 [1]) description of the generic FIFO dummy cycle entry and keeps the controller side aligned with the flash model's dummy byte ownership. The description of the generic command fifo register says: When [receive, transmit, data_xfer] = [0,0,1], the [immediate_data] field represents the number of dummy cycle sent on the SPI interface. [1] https://www.xilinx.com/support/documentation/user_guides/ug1085-zynq-ultrascale-trm.pdf table 24‐22, an example of Generic FIFO Contents for Quad I/O Read Command (EBh) Fixes: ef06ca3946e2 ("xilinx_spips: Add support for RX discard and RX drain") Fixes: c95997a39de6 ("xilinx_spips: Add support for the ZynqMP Generic QSPI") Signed-off-by: Bin Meng <bin.meng@processmission.com> Tested-by: Cédric Le Goater <clg@redhat.com> Message-ID: <20260707083431.219671-7-bin.meng@processmission.com> Signed-off-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>

Bin Meng committed Jul 7, 2026 at 16:34 UTC 7017b477013554e8b6616c6ceff1168b933d6de5
2 files changed +91 -34
hw/ssi/xilinx_spips.c
+90 -33
@@ -192,6 +192,10 @@
192 FIELD(GQSPI_GF_SNAPSHOT, EXPONENT, 9, 1)
193 FIELD(GQSPI_GF_SNAPSHOT, DATA_XFER, 8, 1)
194 FIELD(GQSPI_GF_SNAPSHOT, IMMEDIATE_DATA, 0, 8)
195 +#define GQSPI_GF_MODE_SPI 1
196 +#define GQSPI_GF_MODE_DSPI 2
197 +#define GQSPI_GF_MODE_QSPI 3
198 +
199 #define R_GQSPI_MOD_ID (0x1fc / 4)
200 #define R_GQSPI_MOD_ID_RESET (0x10a0000)
201
@@ -237,7 +241,7 @@ static void xilinx_spips_update_cs(XilinxSPIPS *s, int field)
241 }
242 if (!(field & ((1 << (s->num_cs * s->num_busses)) - 1))) {
243 s->snoop_state = SNOOP_CHECKING;
240 - s->cmd_dummies = 0;
244 + s->cmd_dummy_bytes = 0;
245 s->link_state = 1;
246 s->link_state_next = 1;
247 s->link_state_next_when = 0;
@@ -382,7 +386,7 @@ static void xilinx_spips_reset(DeviceState *d)
386 s->link_state_next = 1;
387 s->link_state_next_when = 0;
388 s->snoop_state = SNOOP_CHECKING;
385 - s->cmd_dummies = 0;
389 + s->cmd_dummy_bytes = 0;
390 s->man_start_com = false;
391 xilinx_spips_update_ixr(s);
392 xilinx_spips_update_cs_lines(s);
@@ -457,6 +461,7 @@ static void xlnx_zynqmp_qspips_flush_fifo_g(XlnxZynqMPQSPIPS *s)
461 int i;
462
463 if (!s->regs[R_GQSPI_DATA_STS]) {
464 + uint32_t prev_gf_snapshot = s->regs[R_GQSPI_GF_SNAPSHOT];
465 uint8_t imm;
466
467 s->regs[R_GQSPI_GF_SNAPSHOT] = fifo32_pop(&s->fifo_g);
@@ -484,7 +489,57 @@ static void xlnx_zynqmp_qspips_flush_fifo_g(XlnxZynqMPQSPIPS *s)
489 }
490 s->regs[R_GQSPI_DATA_STS] = 1ul << imm;
491 } else {
487 - s->regs[R_GQSPI_DATA_STS] = imm;
492 + /*
493 + * When [receive, transmit, data_xfer] = [0,0,1], it represents
494 + * the number of dummy cycle sent on the SPI interface. We need
495 + * to convert the number of dummy cycles to bytes according to
496 + * the SPI mode being used.
497 + *
498 + * Ref: ug1085 v2.2 (December 2020) table 24‐22, an example of
499 + * Generic FIFO Contents for Quad I/O Read Command (EBh)
500 + */
501 + if (!ARRAY_FIELD_EX32(s->regs, GQSPI_GF_SNAPSHOT, TRANSMIT) &&
502 + !ARRAY_FIELD_EX32(s->regs, GQSPI_GF_SNAPSHOT, RECIEVE)) {
503 + uint8_t spi_mode = ARRAY_FIELD_EX32(s->regs,
504 + GQSPI_GF_SNAPSHOT,
505 + SPI_MODE);
506 + /*
507 + * Some ZynqMP GQSPI drivers, such as Linux, use the data
508 + * bus width in the dummy GENFIFO entry only to configure
509 + * the controller mode. The immediate value is already
510 + * the number of dummy cycles for the dummy phase, which
511 + * follows the address bus width. Reuse the previous TX
512 + * phase mode to convert cycles to SSI bytes.
513 + *
514 + * This does not make the model Linux-only. U-Boot emits
515 + * the dummy entry with op->dummy.buswidth, so the entry
516 + * mode already matches the dummy phase. Its opcode and
517 + * address phases are immediate entries, not DATA_XFER TX
518 + * entries, so the override below is not taken for U-Boot.
519 + */
520 + if (FIELD_EX32(prev_gf_snapshot, GQSPI_GF_SNAPSHOT,
521 + DATA_XFER) &&
522 + FIELD_EX32(prev_gf_snapshot, GQSPI_GF_SNAPSHOT,
523 + TRANSMIT) &&
524 + !FIELD_EX32(prev_gf_snapshot, GQSPI_GF_SNAPSHOT,
525 + RECIEVE)) {
526 + spi_mode = FIELD_EX32(prev_gf_snapshot,
527 + GQSPI_GF_SNAPSHOT, SPI_MODE);
528 + }
529 +
530 + if (spi_mode == GQSPI_GF_MODE_QSPI) {
531 + s->regs[R_GQSPI_DATA_STS] = ROUND_UP(imm * 4, 8) / 8;
532 + } else if (spi_mode == GQSPI_GF_MODE_DSPI) {
533 + s->regs[R_GQSPI_DATA_STS] = ROUND_UP(imm * 2, 8) / 8;
534 + } else if (spi_mode == GQSPI_GF_MODE_SPI) {
535 + s->regs[R_GQSPI_DATA_STS] = ROUND_UP(imm * 1, 8) / 8;
536 + } else {
537 + qemu_log_mask(LOG_GUEST_ERROR,
538 + "Unknown SPI MODE: 0x%x ", spi_mode);
539 + }
540 + } else {
541 + s->regs[R_GQSPI_DATA_STS] = imm;
542 + }
543 }
544 }
545 /* Zero length transfer check */
@@ -550,7 +605,7 @@ static void xlnx_zynqmp_qspips_flush_fifo_g(XlnxZynqMPQSPIPS *s)
605 }
606 }
607
553 -static int xilinx_spips_num_dummies(XilinxQSPIPS *qs, uint8_t command)
608 +static int xilinx_spips_num_dummy_bytes(XilinxQSPIPS *qs, uint8_t command)
609 {
610 if (!qs) {
611 /* The SPI device is not a QSPI device */
@@ -567,10 +622,11 @@ static int xilinx_spips_num_dummies(XilinxQSPIPS *qs, uint8_t command)
622 case QPP_4:
623 return 0;
624 case FAST_READ:
570 - case DOR:
571 - case QOR:
625 case FAST_READ_4:
626 + return 1;
627 + case DOR:
628 case DOR_4:
629 + case QOR:
630 case QOR_4:
631 return 1;
632 case DIOR:
@@ -611,7 +667,6 @@ static void xilinx_spips_flush_txfifo(XilinxSPIPS *s)
667 int i;
668 uint8_t tx = 0;
669 uint8_t tx_rx[MAX_NUM_BUSSES] = { 0 };
614 - uint8_t dummy_cycles = 0;
670 uint8_t addr_length;
671
672 if (fifo8_is_empty(&s->tx_fifo)) {
@@ -631,26 +686,18 @@ static void xilinx_spips_flush_txfifo(XilinxSPIPS *s)
686 tx_rx[i] = tx;
687 }
688 } else {
634 - /*
635 - * Extract a dummy byte and generate dummy cycles according to the
636 - * link state
637 - */
689 tx = fifo8_pop(&s->tx_fifo);
639 - dummy_cycles = 8 / s->link_state;
690 + for (i = 0; i < num_effective_busses(s); ++i) {
691 + tx_rx[i] = tx;
692 + }
693 }
694
695 for (i = 0; i < num_effective_busses(s); ++i) {
696 int bus = num_effective_busses(s) - 1 - i;
644 - if (dummy_cycles) {
645 - int d;
646 - for (d = 0; d < dummy_cycles; ++d) {
647 - tx_rx[0] = ssi_transfer(s->spi[bus], (uint32_t)tx_rx[0]);
648 - }
649 - } else {
650 - DB_PRINT_L(debug_level, "tx = %02x\n", tx_rx[i]);
651 - tx_rx[i] = ssi_transfer(s->spi[bus], (uint32_t)tx_rx[i]);
652 - DB_PRINT_L(debug_level, "rx = %02x\n", tx_rx[i]);
653 - }
697 +
698 + DB_PRINT_L(debug_level, "tx = %02x\n", tx_rx[i]);
699 + tx_rx[i] = ssi_transfer(s->spi[bus], (uint32_t)tx_rx[i]);
700 + DB_PRINT_L(debug_level, "rx = %02x\n", tx_rx[i]);
701 }
702
703 if (s->regs[R_CMND] & R_CMND_RXFIFO_DRAIN) {
@@ -685,9 +732,9 @@ static void xilinx_spips_flush_txfifo(XilinxSPIPS *s)
732 switch (s->snoop_state) {
733 case (SNOOP_CHECKING):
734 /* Store the count of dummy bytes in the txfifo */
688 - s->cmd_dummies = xilinx_spips_num_dummies(q, tx);
735 + s->cmd_dummy_bytes = xilinx_spips_num_dummy_bytes(q, tx);
736 addr_length = get_addr_length(s, tx);
690 - if (s->cmd_dummies < 0) {
737 + if (s->cmd_dummy_bytes < 0) {
738 s->snoop_state = SNOOP_NONE;
739 } else {
740 s->snoop_state = SNOOP_ADDR + addr_length - 1;
@@ -697,14 +744,14 @@ static void xilinx_spips_flush_txfifo(XilinxSPIPS *s)
744 case DOR:
745 case DOR_4:
746 s->link_state_next = 2;
700 - s->link_state_next_when = addr_length + s->cmd_dummies;
747 + s->link_state_next_when = addr_length + s->cmd_dummy_bytes;
748 break;
749 case QPP:
750 case QPP_4:
751 case QOR:
752 case QOR_4:
753 s->link_state_next = 4;
707 - s->link_state_next_when = addr_length + s->cmd_dummies;
754 + s->link_state_next_when = addr_length + s->cmd_dummy_bytes;
755 break;
756 case DIOR:
757 case DIOR_4:
@@ -720,10 +767,10 @@ static void xilinx_spips_flush_txfifo(XilinxSPIPS *s)
767 /*
768 * Address has been transmitted, transmit dummy cycles now if needed
769 */
723 - if (s->cmd_dummies < 0) {
770 + if (s->cmd_dummy_bytes < 0) {
771 s->snoop_state = SNOOP_NONE;
772 } else {
726 - s->snoop_state = s->cmd_dummies;
773 + s->snoop_state = s->cmd_dummy_bytes;
774 }
775 break;
776 case (SNOOP_STRIPING):
@@ -1152,11 +1199,13 @@ static void lqspi_load_cache(void *opaque, hwaddr addr)
1199 XilinxQSPIPS *q = opaque;
1200 XilinxSPIPS *s = opaque;
1201 int i;
1202 + int dummy_bytes;
1203 int flash_addr = ((addr & ~(LQSPI_CACHE_SIZE - 1))
1204 / num_effective_busses(s));
1205 int peripheral = flash_addr >> LQSPI_ADDRESS_BITS;
1206 int cache_entry = 0;
1207 uint32_t u_page_save = s->regs[R_LQSPI_STS] & ~LQSPI_CFG_U_PAGE;
1208 + uint8_t command;
1209
1210 if (addr < q->lqspi_cached_addr ||
1211 addr > q->lqspi_cached_addr + LQSPI_CACHE_SIZE - 4) {
@@ -1170,10 +1219,10 @@ static void lqspi_load_cache(void *opaque, hwaddr addr)
1219 fifo8_reset(&s->rx_fifo);
1220
1221 /* instruction */
1222 + command = s->regs[R_LQSPI_CFG] & LQSPI_CFG_INST_CODE;
1223 DB_PRINT_L(0, "pushing read instruction: %02x\n",
1174 - (unsigned)(uint8_t)(s->regs[R_LQSPI_CFG] &
1175 - LQSPI_CFG_INST_CODE));
1176 - fifo8_push(&s->tx_fifo, s->regs[R_LQSPI_CFG] & LQSPI_CFG_INST_CODE);
1224 + (unsigned)command);
1225 + fifo8_push(&s->tx_fifo, command);
1226 /* read address */
1227 DB_PRINT_L(0, "pushing read address %06x\n", flash_addr);
1228 if (s->regs[R_LQSPI_CFG] & LQSPI_CFG_ADDR4) {
@@ -1183,14 +1232,22 @@ static void lqspi_load_cache(void *opaque, hwaddr addr)
1232 fifo8_push(&s->tx_fifo, (uint8_t)(flash_addr >> 8));
1233 fifo8_push(&s->tx_fifo, (uint8_t)flash_addr);
1234 /* mode bits */
1235 + dummy_bytes = xilinx_spips_num_dummy_bytes(q, command);
1236 if (s->regs[R_LQSPI_CFG] & LQSPI_CFG_MODE_EN) {
1237 fifo8_push(&s->tx_fifo, extract32(s->regs[R_LQSPI_CFG],
1238 LQSPI_CFG_MODE_SHIFT,
1239 LQSPI_CFG_MODE_WIDTH));
1240 + if (dummy_bytes > 0) {
1241 + dummy_bytes--;
1242 + }
1243 + }
1244 + if (dummy_bytes < 0) {
1245 + dummy_bytes = extract32(s->regs[R_LQSPI_CFG],
1246 + LQSPI_CFG_DUMMY_SHIFT,
1247 + LQSPI_CFG_DUMMY_WIDTH);
1248 }
1249 /* dummy bytes */
1192 - for (i = 0; i < (extract32(s->regs[R_LQSPI_CFG], LQSPI_CFG_DUMMY_SHIFT,
1193 - LQSPI_CFG_DUMMY_WIDTH)); ++i) {
1250 + for (i = 0; i < dummy_bytes; ++i) {
1251 DB_PRINT_L(0, "pushing dummy byte\n");
1252 fifo8_push(&s->tx_fifo, 0);
1253 }
include/hw/ssi/xilinx_spips.h
+1 -1
@@ -69,7 +69,7 @@ struct XilinxSPIPS {
69 uint8_t num_busses;
70
71 uint8_t snoop_state;
72 - int cmd_dummies;
72 + int cmd_dummy_bytes;
73 uint8_t link_state;
74 uint8_t link_state_next;
75 uint8_t link_state_next_when;