static void imx_spi_update_irq(IMXSPIState *s) { int level; if (fifo32_is_empty(&s->rx_fifo)) { s->regs[ECSPI_STATREG] &= ~ECSPI_STATREG_RR; } else { s->regs[ECSPI_STATREG] |= ECSPI_STATREG_RR; } if (fifo32_is_full(&s->rx_fifo)) { s->regs[ECSPI_STATREG] |= ECSPI_STATREG_RF; } else { s->regs[ECSPI_STATREG] &= ~ECSPI_STATREG_RF; } if (fifo32_is_empty(&s->tx_fifo)) { s->regs[ECSPI_STATREG] |= ECSPI_STATREG_TE; } else { s->regs[ECSPI_STATREG] &= ~ECSPI_STATREG_TE; } if (fifo32_is_full(&s->tx_fifo)) { s->regs[ECSPI_STATREG] |= ECSPI_STATREG_TF; } else { s->regs[ECSPI_STATREG] &= ~ECSPI_STATREG_TF; } level = s->regs[ECSPI_STATREG] & s->regs[ECSPI_INTREG] ? 1 : 0; qemu_set_irq(s->irq, level); DPRINTF("IRQ level is %d\n", level); }
static void xlnx_zynqmp_qspips_update_ixr(XlnxZynqMPQSPIPS *s) { uint32_t gqspi_int; int new_irqline; s->regs[R_GQSPI_ISR] &= ~IXR_SELF_CLEAR; s->regs[R_GQSPI_ISR] |= (fifo32_is_empty(&s->fifo_g) ? IXR_GENERIC_FIFO_EMPTY : 0) | (fifo32_is_full(&s->fifo_g) ? IXR_GENERIC_FIFO_FULL : 0) | (s->fifo_g.fifo.num < s->regs[R_GQSPI_GFIFO_THRESH] ? IXR_GENERIC_FIFO_NOT_FULL : 0) | (fifo8_is_empty(&s->rx_fifo_g) ? IXR_RX_FIFO_EMPTY : 0) | (fifo8_is_full(&s->rx_fifo_g) ? IXR_RX_FIFO_FULL : 0) | (s->rx_fifo_g.num >= s->regs[R_GQSPI_RX_THRESH] ? IXR_RX_FIFO_NOT_EMPTY : 0) | (fifo8_is_empty(&s->tx_fifo_g) ? IXR_TX_FIFO_EMPTY : 0) | (fifo8_is_full(&s->tx_fifo_g) ? IXR_TX_FIFO_FULL : 0) | (s->tx_fifo_g.num < s->regs[R_GQSPI_TX_THRESH] ? IXR_TX_FIFO_NOT_FULL : 0); /* GQSPI Interrupt Trigger Status */ gqspi_int = (~s->regs[R_GQSPI_IMR]) & s->regs[R_GQSPI_ISR] & GQSPI_IXR_MASK; new_irqline = !!(gqspi_int & IXR_ALL); /* drive external interrupt pin */ if (new_irqline != s->gqspi_irqline) { s->gqspi_irqline = new_irqline; qemu_set_irq(XILINX_SPIPS(s)->irq, s->gqspi_irqline); } }
static void imx_spi_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { IMXSPIState *s = opaque; uint32_t index = offset >> 2; uint32_t change_mask; if (index >= ECSPI_MAX) { qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%" HWADDR_PRIx "\n", TYPE_IMX_SPI, __func__, offset); return; } DPRINTF("reg[%s] <= 0x%" PRIx32 "\n", imx_spi_reg_name(index), (uint32_t)value); change_mask = s->regs[index] ^ value; switch (index) { case ECSPI_RXDATA: qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Trying to write to RX FIFO\n", TYPE_IMX_SPI, __func__); break; case ECSPI_TXDATA: case ECSPI_MSGDATA: /* Is there any difference between TXDATA and MSGDATA ? */ /* I'll have to look in the linux driver */ if (!imx_spi_is_enabled(s)) { /* Ignore writes if device is disabled */ break; } else if (fifo32_is_full(&s->tx_fifo)) { /* Ignore writes if queue is full */ break; } fifo32_push(&s->tx_fifo, (uint32_t)value); if (imx_spi_channel_is_master(s) && (s->regs[ECSPI_CONREG] & ECSPI_CONREG_SMC)) { /* * Start emitting if current channel is master and SMC bit is * set. */ imx_spi_flush_txfifo(s); } break; case ECSPI_STATREG: /* the RO and TC bits are write-one-to-clear */ value &= ECSPI_STATREG_RO | ECSPI_STATREG_TC; s->regs[ECSPI_STATREG] &= ~value; break; case ECSPI_CONREG: s->regs[ECSPI_CONREG] = value; if (!imx_spi_is_enabled(s)) { /* device is disabled, so this is a reset */ imx_spi_reset(DEVICE(s)); return; } if (imx_spi_channel_is_master(s)) { int i; /* We are in master mode */ for (i = 0; i < 4; i++) { qemu_set_irq(s->cs_lines[i], i == imx_spi_selected_channel(s) ? 0 : 1); } if ((value & change_mask & ECSPI_CONREG_SMC) && !fifo32_is_empty(&s->tx_fifo)) { /* SMC bit is set and TX FIFO has some slots filled in */ imx_spi_flush_txfifo(s); } else if ((value & change_mask & ECSPI_CONREG_XCH) && !(value & ECSPI_CONREG_SMC)) { /* This is a request to start emitting */ imx_spi_flush_txfifo(s); } } break; default: s->regs[index] = value; break; } imx_spi_update_irq(s); }
static void imx_spi_flush_txfifo(IMXSPIState *s) { uint32_t tx; uint32_t rx; DPRINTF("Begin: TX Fifo Size = %d, RX Fifo Size = %d\n", fifo32_num_used(&s->tx_fifo), fifo32_num_used(&s->rx_fifo)); while (!fifo32_is_empty(&s->tx_fifo)) { int tx_burst = 0; int index = 0; if (s->burst_length <= 0) { s->burst_length = imx_spi_burst_length(s); DPRINTF("Burst length = %d\n", s->burst_length); if (imx_spi_is_multiple_master_burst(s)) { s->regs[ECSPI_CONREG] |= ECSPI_CONREG_XCH; } } tx = fifo32_pop(&s->tx_fifo); DPRINTF("data tx:0x%08x\n", tx); tx_burst = MIN(s->burst_length, 32); rx = 0; while (tx_burst) { uint8_t byte = tx & 0xff; DPRINTF("writing 0x%02x\n", (uint32_t)byte); /* We need to write one byte at a time */ byte = ssi_transfer(s->bus, byte); DPRINTF("0x%02x read\n", (uint32_t)byte); tx = tx >> 8; rx |= (byte << (index * 8)); /* Remove 8 bits from the actual burst */ tx_burst -= 8; s->burst_length -= 8; index++; } DPRINTF("data rx:0x%08x\n", rx); if (fifo32_is_full(&s->rx_fifo)) { s->regs[ECSPI_STATREG] |= ECSPI_STATREG_RO; } else { fifo32_push(&s->rx_fifo, (uint8_t)rx); } if (s->burst_length <= 0) { s->regs[ECSPI_CONREG] &= ~ECSPI_CONREG_XCH; if (!imx_spi_is_multiple_master_burst(s)) { s->regs[ECSPI_STATREG] |= ECSPI_STATREG_TC; break; } } } if (fifo32_is_empty(&s->tx_fifo)) { s->regs[ECSPI_STATREG] |= ECSPI_STATREG_TC; } /* TODO: We should also use TDR and RDR bits */ DPRINTF("End: TX Fifo Size = %d, RX Fifo Size = %d\n", fifo32_num_used(&s->tx_fifo), fifo32_num_used(&s->rx_fifo)); }