Example #1
0
static void spi_flush_txfifo(XilinxSPI *s)
{
    uint32_t tx;
    uint32_t rx;

    while (!fifo8_is_empty(&s->tx_fifo)) {
        tx = (uint32_t)fifo8_pop(&s->tx_fifo);
        DB_PRINT("data tx:%x\n", tx);
        rx = ssi_transfer(s->spi, tx);
        DB_PRINT("data rx:%x\n", rx);
        if (fifo8_is_full(&s->rx_fifo)) {
            s->regs[R_IPISR] |= IRQ_DRR_OVERRUN;
        } else {
            fifo8_push(&s->rx_fifo, (uint8_t)rx);
            if (fifo8_is_full(&s->rx_fifo)) {
                s->regs[R_SPISR] |= SR_RX_FULL;
                s->regs[R_IPISR] |= IRQ_DRR_FULL;
            }
        }

        s->regs[R_SPISR] &= ~SR_RX_EMPTY;
        s->regs[R_SPISR] &= ~SR_TX_FULL;
        s->regs[R_SPISR] |= SR_TX_EMPTY;

        s->regs[R_IPISR] |= IRQ_DTR_EMPTY;
        s->regs[R_IPISR] |= IRQ_DRR_NOT_EMPTY;
    }

}
Example #2
0
static void xilinx_spips_flush_txfifo(XilinxSPIPS *s)
{
    for (;;) {
        int i;
        uint8_t rx;
        uint8_t tx = 0;

        for (i = 0; i < num_effective_busses(s); ++i) {
            if (!i || s->snoop_state == SNOOP_STRIPING) {
                if (fifo8_is_empty(&s->tx_fifo)) {
                    s->regs[R_INTR_STATUS] |= IXR_TX_FIFO_UNDERFLOW;
                    xilinx_spips_update_ixr(s);
                    return;
                } else {
                    tx = fifo8_pop(&s->tx_fifo);
                }
            }
            rx = ssi_transfer(s->spi[i], (uint32_t)tx);
            DB_PRINT("tx = %02x rx = %02x\n", tx, rx);
            if (!i || s->snoop_state == SNOOP_STRIPING) {
                if (fifo8_is_full(&s->rx_fifo)) {
                    s->regs[R_INTR_STATUS] |= IXR_RX_FIFO_OVERFLOW;
                    DB_PRINT("rx FIFO overflow");
                } else {
                    fifo8_push(&s->rx_fifo, (uint8_t)rx);
                }
            }
        }

        switch (s->snoop_state) {
        case (SNOOP_CHECKING):
            switch (tx) { /* new instruction code */
            case READ: /* 3 address bytes, no dummy bytes/cycles */
            case PP:
            case DPP:
            case QPP:
                s->snoop_state = 3;
                break;
            case FAST_READ: /* 3 address bytes, 1 dummy byte */
            case DOR:
            case QOR:
            case DIOR: /* FIXME: these vary between vendor - set to spansion */
                s->snoop_state = 4;
                break;
            case QIOR: /* 3 address bytes, 2 dummy bytes */
                s->snoop_state = 6;
                break;
            default:
                s->snoop_state = SNOOP_NONE;
            }
            break;
        case (SNOOP_STRIPING):
        case (SNOOP_NONE):
            break;
        default:
            s->snoop_state--;
        }
    }
}
Example #3
0
static void pl022_xfer(pl022_state *s)
{
    int i;
    int o;
    int val;

    if ((s->cr1 & PL022_CR1_SSE) == 0) {
        pl022_update(s);
        DPRINTF("Disabled\n");
        return;
    }

    DPRINTF("Maybe xfer %d/%d\n", s->tx_fifo_len, s->rx_fifo_len);
    i = (s->tx_fifo_head - s->tx_fifo_len) & 7;
    o = s->rx_fifo_head;
    /* ??? We do not emulate the line speed.
       This may break some applications.  The are two problematic cases:
        (a) A driver feeds data into the TX FIFO until it is full,
         and only then drains the RX FIFO.  On real hardware the CPU can
         feed data fast enough that the RX fifo never gets chance to overflow.
        (b) A driver transmits data, deliberately allowing the RX FIFO to
         overflow because it ignores the RX data anyway.

       We choose to support (a) by stalling the transmit engine if it would
       cause the RX FIFO to overflow.  In practice much transmit-only code
       falls into (a) because it flushes the RX FIFO to determine when
       the transfer has completed.  */
    while (s->tx_fifo_len && s->rx_fifo_len < 8) {
        DPRINTF("xfer\n");
        val = s->tx_fifo[i];
        if (s->cr1 & PL022_CR1_LBM) {
            /* Loopback mode.  */
        } else {
            val = ssi_transfer(s->ssi, val);
        }
        s->rx_fifo[o] = val & s->bitmask;
        i = (i + 1) & 7;
        o = (o + 1) & 7;
        s->tx_fifo_len--;
        s->rx_fifo_len++;
    }
    s->rx_fifo_head = o;
    pl022_update(s);
}
Example #4
0
static void xilinx_spips_flush_txfifo(XilinxSPIPS *s)
{
    int debug_level = 0;

    for (;;) {
        int i;
        uint8_t tx = 0;
        uint8_t tx_rx[num_effective_busses(s)];

        if (fifo8_is_empty(&s->tx_fifo)) {
            if (!(s->regs[R_LQSPI_CFG] & LQSPI_CFG_LQ_MODE)) {
                s->regs[R_INTR_STATUS] |= IXR_TX_FIFO_UNDERFLOW;
            }
            xilinx_spips_update_ixr(s);
            return;
        } else if (s->snoop_state == SNOOP_STRIPING) {
            for (i = 0; i < num_effective_busses(s); ++i) {
                tx_rx[i] = fifo8_pop(&s->tx_fifo);
            }
            stripe8(tx_rx, num_effective_busses(s), false);
        } else {
            tx = fifo8_pop(&s->tx_fifo);
            for (i = 0; i < num_effective_busses(s); ++i) {
                tx_rx[i] = tx;
            }
        }

        for (i = 0; i < num_effective_busses(s); ++i) {
            DB_PRINT_L(debug_level, "tx = %02x\n", tx_rx[i]);
            tx_rx[i] = ssi_transfer(s->spi[i], (uint32_t)tx_rx[i]);
            DB_PRINT_L(debug_level, "rx = %02x\n", tx_rx[i]);
        }

        if (fifo8_is_full(&s->rx_fifo)) {
            s->regs[R_INTR_STATUS] |= IXR_RX_FIFO_OVERFLOW;
            DB_PRINT_L(0, "rx FIFO overflow");
        } else if (s->snoop_state == SNOOP_STRIPING) {
            stripe8(tx_rx, num_effective_busses(s), true);
            for (i = 0; i < num_effective_busses(s); ++i) {
                fifo8_push(&s->rx_fifo, (uint8_t)tx_rx[i]);
            }
        } else {
           fifo8_push(&s->rx_fifo, (uint8_t)tx_rx[0]);
        }

        DB_PRINT_L(debug_level, "initial snoop state: %x\n",
                   (unsigned)s->snoop_state);
        switch (s->snoop_state) {
        case (SNOOP_CHECKING):
            switch (tx) { /* new instruction code */
            case READ: /* 3 address bytes, no dummy bytes/cycles */
            case PP:
            case DPP:
            case QPP:
                s->snoop_state = 3;
                break;
            case FAST_READ: /* 3 address bytes, 1 dummy byte */
            case DOR:
            case QOR:
            case DIOR: /* FIXME: these vary between vendor - set to spansion */
                s->snoop_state = 4;
                break;
            case QIOR: /* 3 address bytes, 2 dummy bytes */
                s->snoop_state = 6;
                break;
            default:
                s->snoop_state = SNOOP_NONE;
            }
            break;
        case (SNOOP_STRIPING):
        case (SNOOP_NONE):
            /* Once we hit the boring stuff - squelch debug noise */
            if (!debug_level) {
                DB_PRINT_L(0, "squelching debug info ....\n");
                debug_level = 1;
            }
            break;
        default:
            s->snoop_state--;
        }
        DB_PRINT_L(debug_level, "final snoop state: %x\n",
                   (unsigned)s->snoop_state);
    }
}
Example #5
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));
}
Example #6
0
static void xilinx_spips_flush_txfifo(XilinxSPIPS *s)
{
    int debug_level = 0;
    XilinxQSPIPS *q = (XilinxQSPIPS *) object_dynamic_cast(OBJECT(s),
                                                           TYPE_XILINX_QSPIPS);

    for (;;) {
        int i;
        uint8_t tx = 0;
        uint8_t tx_rx[MAX_NUM_BUSSES] = { 0 };
        uint8_t dummy_cycles = 0;
        uint8_t addr_length;

        if (fifo8_is_empty(&s->tx_fifo)) {
            xilinx_spips_update_ixr(s);
            return;
        } else if (s->snoop_state == SNOOP_STRIPING) {
            for (i = 0; i < num_effective_busses(s); ++i) {
                tx_rx[i] = fifo8_pop(&s->tx_fifo);
            }
            stripe8(tx_rx, num_effective_busses(s), false);
        } else if (s->snoop_state >= SNOOP_ADDR) {
            tx = fifo8_pop(&s->tx_fifo);
            for (i = 0; i < num_effective_busses(s); ++i) {
                tx_rx[i] = tx;
            }
        } else {
            /* Extract a dummy byte and generate dummy cycles according to the
             * link state */
            tx = fifo8_pop(&s->tx_fifo);
            dummy_cycles = 8 / s->link_state;
        }

        for (i = 0; i < num_effective_busses(s); ++i) {
            int bus = num_effective_busses(s) - 1 - i;
            if (dummy_cycles) {
                int d;
                for (d = 0; d < dummy_cycles; ++d) {
                    tx_rx[0] = ssi_transfer(s->spi[bus], (uint32_t)tx_rx[0]);
                }
            } else {
                DB_PRINT_L(debug_level, "tx = %02x\n", tx_rx[i]);
                tx_rx[i] = ssi_transfer(s->spi[bus], (uint32_t)tx_rx[i]);
                DB_PRINT_L(debug_level, "rx = %02x\n", tx_rx[i]);
            }
        }

        if (s->regs[R_CMND] & R_CMND_RXFIFO_DRAIN) {
            DB_PRINT_L(debug_level, "dircarding drained rx byte\n");
            /* Do nothing */
        } else if (s->rx_discard) {
            DB_PRINT_L(debug_level, "dircarding discarded rx byte\n");
            s->rx_discard -= 8 / s->link_state;
        } else if (fifo8_is_full(&s->rx_fifo)) {
            s->regs[R_INTR_STATUS] |= IXR_RX_FIFO_OVERFLOW;
            DB_PRINT_L(0, "rx FIFO overflow");
        } else if (s->snoop_state == SNOOP_STRIPING) {
            stripe8(tx_rx, num_effective_busses(s), true);
            for (i = 0; i < num_effective_busses(s); ++i) {
                fifo8_push(&s->rx_fifo, (uint8_t)tx_rx[i]);
                DB_PRINT_L(debug_level, "pushing striped rx byte\n");
            }
        } else {
           DB_PRINT_L(debug_level, "pushing unstriped rx byte\n");
           fifo8_push(&s->rx_fifo, (uint8_t)tx_rx[0]);
        }

        if (s->link_state_next_when) {
            s->link_state_next_when--;
            if (!s->link_state_next_when) {
                s->link_state = s->link_state_next;
            }
        }

        DB_PRINT_L(debug_level, "initial snoop state: %x\n",
                   (unsigned)s->snoop_state);
        switch (s->snoop_state) {
        case (SNOOP_CHECKING):
            /* Store the count of dummy bytes in the txfifo */
            s->cmd_dummies = xilinx_spips_num_dummies(q, tx);
            addr_length = get_addr_length(s, tx);
            if (s->cmd_dummies < 0) {
                s->snoop_state = SNOOP_NONE;
            } else {
                s->snoop_state = SNOOP_ADDR + addr_length - 1;
            }
            switch (tx) {
            case DPP:
            case DOR:
            case DOR_4:
                s->link_state_next = 2;
                s->link_state_next_when = addr_length + s->cmd_dummies;
                break;
            case QPP:
            case QPP_4:
            case QOR:
            case QOR_4:
                s->link_state_next = 4;
                s->link_state_next_when = addr_length + s->cmd_dummies;
                break;
            case DIOR:
            case DIOR_4:
                s->link_state = 2;
                break;
            case QIOR:
            case QIOR_4:
                s->link_state = 4;
                break;
            }
            break;
        case (SNOOP_ADDR):
            /* Address has been transmitted, transmit dummy cycles now if
             * needed */
            if (s->cmd_dummies < 0) {
                s->snoop_state = SNOOP_NONE;
            } else {
                s->snoop_state = s->cmd_dummies;
            }
            break;
        case (SNOOP_STRIPING):
        case (SNOOP_NONE):
            /* Once we hit the boring stuff - squelch debug noise */
            if (!debug_level) {
                DB_PRINT_L(0, "squelching debug info ....\n");
                debug_level = 1;
            }
            break;
        default:
            s->snoop_state--;
        }
        DB_PRINT_L(debug_level, "final snoop state: %x\n",
                   (unsigned)s->snoop_state);
    }
}
Example #7
0
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);
            }
        }
    }
}