Exemplo n.º 1
0
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);
}
Exemplo n.º 2
0
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);
    }
}
Exemplo n.º 3
0
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);
}
Exemplo n.º 4
0
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));
}