+static void xlnx_zynqmp_qspips_flush_fifo_g(XlnxZynqMPQSPIPS *s)
+{
+ while (s->regs[R_GQSPI_DATA_STS] || !fifo32_is_empty(&s->fifo_g)) {
+ uint8_t tx_rx[2] = { 0 };
+ int num_stripes = 1;
+ uint8_t busses;
+ int i;
+
+ if (!s->regs[R_GQSPI_DATA_STS]) {
+ uint8_t imm;
+
+ s->regs[R_GQSPI_GF_SNAPSHOT] = fifo32_pop(&s->fifo_g);
+ DB_PRINT_L(0, "GQSPI command: %x\n", s->regs[R_GQSPI_GF_SNAPSHOT]);
+ if (!s->regs[R_GQSPI_GF_SNAPSHOT]) {
+ DB_PRINT_L(0, "Dummy GQSPI Delay Command Entry, Do nothing");
+ continue;
+ }
+ xlnx_zynqmp_qspips_update_cs_lines(s);
+
+ imm = ARRAY_FIELD_EX32(s->regs, GQSPI_GF_SNAPSHOT, IMMEDIATE_DATA);
+ if (!ARRAY_FIELD_EX32(s->regs, GQSPI_GF_SNAPSHOT, DATA_XFER)) {
+ /* immedate transfer */
+ if (ARRAY_FIELD_EX32(s->regs, GQSPI_GF_SNAPSHOT, TRANSMIT) ||
+ ARRAY_FIELD_EX32(s->regs, GQSPI_GF_SNAPSHOT, RECIEVE)) {
+ s->regs[R_GQSPI_DATA_STS] = 1;
+ /* CS setup/hold - do nothing */
+ } else {
+ s->regs[R_GQSPI_DATA_STS] = 0;
+ }
+ } else if (ARRAY_FIELD_EX32(s->regs, GQSPI_GF_SNAPSHOT, EXPONENT)) {
+ if (imm > 31) {
+ qemu_log_mask(LOG_UNIMP, "QSPI exponential transfer too"
+ " long - 2 ^ %" PRId8 " requested\n", imm);
+ }
+ s->regs[R_GQSPI_DATA_STS] = 1ul << imm;
+ } else {
+ s->regs[R_GQSPI_DATA_STS] = imm;
+ }
+ }
+ /* Zero length transfer check */
+ if (!s->regs[R_GQSPI_DATA_STS]) {
+ continue;
+ }
+ if (ARRAY_FIELD_EX32(s->regs, GQSPI_GF_SNAPSHOT, RECIEVE) &&
+ fifo8_is_full(&s->rx_fifo_g)) {
+ /* No space in RX fifo for transfer - try again later */
+ return;
+ }
+ if (ARRAY_FIELD_EX32(s->regs, GQSPI_GF_SNAPSHOT, STRIPE) &&
+ (ARRAY_FIELD_EX32(s->regs, GQSPI_GF_SNAPSHOT, TRANSMIT) ||
+ ARRAY_FIELD_EX32(s->regs, GQSPI_GF_SNAPSHOT, RECIEVE))) {
+ num_stripes = 2;
+ }
+ if (!ARRAY_FIELD_EX32(s->regs, GQSPI_GF_SNAPSHOT, DATA_XFER)) {
+ tx_rx[0] = ARRAY_FIELD_EX32(s->regs,
+ GQSPI_GF_SNAPSHOT, IMMEDIATE_DATA);
+ } else if (ARRAY_FIELD_EX32(s->regs, GQSPI_GF_SNAPSHOT, TRANSMIT)) {
+ for (i = 0; i < num_stripes; ++i) {
+ if (!fifo8_is_empty(&s->tx_fifo_g)) {
+ tx_rx[i] = fifo8_pop(&s->tx_fifo_g);
+ s->tx_fifo_g_align++;
+ } else {
+ return;
+ }
+ }
+ }
+ if (num_stripes == 1) {
+ /* mirror */
+ tx_rx[1] = tx_rx[0];
+ }
+ busses = ARRAY_FIELD_EX32(s->regs, GQSPI_GF_SNAPSHOT, DATA_BUS_SELECT);
+ for (i = 0; i < 2; ++i) {
+ DB_PRINT_L(1, "bus %d tx = %02x\n", i, tx_rx[i]);
+ tx_rx[i] = ssi_transfer(XILINX_SPIPS(s)->spi[i], tx_rx[i]);
+ DB_PRINT_L(1, "bus %d rx = %02x\n", i, tx_rx[i]);
+ }
+ if (s->regs[R_GQSPI_DATA_STS] > 1 &&
+ busses == 0x3 && num_stripes == 2) {
+ s->regs[R_GQSPI_DATA_STS] -= 2;
+ } else if (s->regs[R_GQSPI_DATA_STS] > 0) {
+ s->regs[R_GQSPI_DATA_STS]--;
+ }
+ if (ARRAY_FIELD_EX32(s->regs, GQSPI_GF_SNAPSHOT, RECIEVE)) {
+ for (i = 0; i < 2; ++i) {
+ if (busses & (1 << i)) {
+ DB_PRINT_L(1, "bus %d push_byte = %02x\n", i, tx_rx[i]);
+ fifo8_push(&s->rx_fifo_g, tx_rx[i]);
+ s->rx_fifo_g_align++;
+ }
+ }
+ }
+ if (!s->regs[R_GQSPI_DATA_STS]) {
+ for (; s->tx_fifo_g_align % 4; s->tx_fifo_g_align++) {
+ fifo8_pop(&s->tx_fifo_g);
+ }
+ for (; s->rx_fifo_g_align % 4; s->rx_fifo_g_align++) {
+ fifo8_push(&s->rx_fifo_g, 0);
+ }
+ }
+ }
+}
+
+static int xilinx_spips_num_dummies(XilinxQSPIPS *qs, uint8_t command)
+{
+ if (!qs) {
+ /* The SPI device is not a QSPI device */
+ return -1;
+ }
+
+ switch (command) { /* check for dummies */
+ case READ: /* no dummy bytes/cycles */
+ case PP:
+ case DPP:
+ case QPP:
+ case READ_4:
+ case PP_4:
+ case QPP_4:
+ return 0;
+ case FAST_READ:
+ case DOR:
+ case QOR:
+ case DOR_4:
+ case QOR_4:
+ return 1;
+ case DIOR:
+ case FAST_READ_4:
+ case DIOR_4:
+ return 2;
+ case QIOR:
+ case QIOR_4:
+ return 4;
+ default:
+ return -1;
+ }
+}
+
+static inline uint8_t get_addr_length(XilinxSPIPS *s, uint8_t cmd)
+{
+ switch (cmd) {
+ case PP_4:
+ case QPP_4:
+ case READ_4:
+ case QIOR_4:
+ case FAST_READ_4:
+ case DOR_4:
+ case QOR_4:
+ case DIOR_4:
+ return 4;
+ default:
+ return (s->regs[R_CMND] & R_CMND_EXT_ADD) ? 4 : 3;
+ }
+}
+