From 9be93addea69850defa8fbba77416efb363f8b46 Mon Sep 17 00:00:00 2001 From: Ville Juven Date: Fri, 22 Sep 2023 14:34:22 +0300 Subject: [PATCH] mpfs/mpfs_corespi: Several speed optimizations to the FPGA driver This is a collection of tweaks / optimizations to the driver to limit CPU usage as well as interrupt processing times. The changes are as follows: - setfrequency is now no-op if the frequency does not change. Accessing MPFS_SPI_CONTROL requires synchronization to the FIC domain, which takes unnecessary time if nothing changes - load/unload FIFO loops optimized so !buffer, priv->nbits and i==last are only tested once (instead of for every word written in loop). - Disable the RX interrupt only once (again, FIC domain access is slow) - In case a spurious MPFS_SPI_DATA_RX interrupt arrives, just wipe the whole RX FIFO, instead of trying to read it byte-by-byte --- arch/risc-v/src/mpfs/mpfs_corespi.c | 143 ++++++++++++---------------- 1 file changed, 59 insertions(+), 84 deletions(-) diff --git a/arch/risc-v/src/mpfs/mpfs_corespi.c b/arch/risc-v/src/mpfs/mpfs_corespi.c index a14b5cb634..65c566a6d5 100644 --- a/arch/risc-v/src/mpfs/mpfs_corespi.c +++ b/arch/risc-v/src/mpfs/mpfs_corespi.c @@ -529,6 +529,13 @@ static uint32_t mpfs_spi_setfrequency(struct spi_dev_s *dev, DEBUGASSERT(frequency > 0); + if (priv->frequency == frequency) + { + /* Nothing changes */ + + return priv->actual; + } + if (priv->enabled) { modifyreg32(MPFS_SPI_CONTROL, MPFS_SPI_ENABLE, 0); @@ -739,54 +746,38 @@ static void mpfs_spi_load_tx_fifo(struct mpfs_spi_priv_s *priv, { uint16_t *data16; uint8_t *data8; - int last; int i; DEBUGASSERT(nwords > 0); data16 = (uint16_t *)txbuffer; data8 = (uint8_t *)txbuffer; - last = nwords - 1; - for (i = 0; i < nwords; i++) + if (!txbuffer) { - if (txbuffer) + for (i = 0; i < nwords - 1; i++) { - if (priv->nbits == 8) - { - if (i == last) - { - putreg32((uint32_t)data8[priv->tx_pos], MPFS_SPI_TX_LAST); - } - else - { - putreg32((uint32_t)data8[priv->tx_pos], MPFS_SPI_TX_DATA); - } - } - else - { - if (i == last) - { - putreg32((uint32_t)data16[priv->tx_pos], MPFS_SPI_TX_LAST); - } - else - { - putreg32((uint32_t)data16[priv->tx_pos], MPFS_SPI_TX_DATA); - } - } - } - else - { - if (i == last) - { - putreg32(0, MPFS_SPI_TX_LAST); - } - else - { - putreg32(0, MPFS_SPI_TX_DATA); - } + putreg32(0, MPFS_SPI_TX_DATA); } - priv->tx_pos++; + putreg32(0, MPFS_SPI_TX_LAST); + } + else if (priv->nbits == 8) + { + for (i = 0; i < nwords - 1; i++) + { + putreg32((uint32_t)data8[priv->tx_pos++], MPFS_SPI_TX_DATA); + } + + putreg32((uint32_t)data8[priv->tx_pos++], MPFS_SPI_TX_LAST); + } + else + { + for (i = 0; i < nwords - 1; i++) + { + putreg32((uint32_t)data16[priv->tx_pos++], MPFS_SPI_TX_DATA); + } + + putreg32((uint32_t)data16[priv->tx_pos++], MPFS_SPI_TX_LAST); } } @@ -813,48 +804,40 @@ static void mpfs_spi_unload_rx_fifo(struct mpfs_spi_priv_s *priv, { uint16_t *data16; uint8_t *data8; - int last; int i; DEBUGASSERT(nwords > 0); data16 = (uint16_t *)rxbuffer; data8 = (uint8_t *)rxbuffer; - last = nwords - 1; - for (i = 0; i < nwords; i++) + if (!rxbuffer) { - /* The last character might not be available yet due to bus delays */ - - if (i == last) + modifyreg32(MPFS_SPI_COMMAND, 0, MPFS_SPI_RXFIFORST); + } + else if (priv->nbits == 8) + { + for (i = 0; i < nwords - 1; i++) { - if (mpfs_rx_wait_last_frame(priv) < 0) - { - /* Nothing came, get out */ - - return; - } + data8[priv->rx_pos++] = getreg32(MPFS_SPI_RX_DATA); } - if (rxbuffer) + if (mpfs_rx_wait_last_frame(priv) == 0) { - if (priv->nbits == 8) - { - data8[priv->rx_pos] = getreg32(MPFS_SPI_RX_DATA); - } - else - { - data16[priv->rx_pos] = getreg32(MPFS_SPI_RX_DATA); - } + data8[priv->rx_pos++] = getreg32(MPFS_SPI_RX_DATA); } - else + } + else if (priv->nbits == 16) + { + for (i = 0; i < nwords - 1; i++) { - getreg32(MPFS_SPI_RX_DATA); + data16[priv->rx_pos++] = getreg32(MPFS_SPI_RX_DATA); } - priv->rx_pos++; - - DEBUGASSERT(priv->rx_pos <= priv->rxwords); + if (mpfs_rx_wait_last_frame(priv) == 0) + { + data16[priv->rx_pos++] = getreg32(MPFS_SPI_RX_DATA); + } } } @@ -935,10 +918,6 @@ static void mpfs_spi_irq_exchange(struct mpfs_spi_priv_s *priv, MPFS_SPI_INTRXOVRFLOW | MPFS_SPI_INTTXDONE); - /* Make sure the RX interrupt is disabled */ - - modifyreg32(MPFS_SPI_CONTROL2, MPFS_SPI_INTEN_DATA_RX, 0); - if (mpfs_spi_sem_waitdone(priv) < 0) { spiinfo("Message timed out\n"); @@ -1304,22 +1283,6 @@ static int mpfs_spi_irq(int cpuint, void *context, void *arg) spiinfo("irq status=%x\n", status); - if (status & MPFS_SPI_DATA_RX) - { - remaining = priv->rxwords - priv->rx_pos; - - if (remaining <= priv->fifosize) - { - mpfs_spi_unload_rx_fifo(priv, priv->rxbuf, remaining); - } - else - { - mpfs_spi_unload_rx_fifo(priv, priv->rxbuf, priv->fifolevel); - } - - putreg32(MPFS_SPI_DATA_RX, MPFS_SPI_INT_CLEAR); - } - if (status & MPFS_SPI_TXDONE) { /* TX is done, we know RX is done too -> offload the RX FIFO */ @@ -1357,6 +1320,14 @@ static int mpfs_spi_irq(int cpuint, void *context, void *arg) } } + if (status & MPFS_SPI_DATA_RX) + { + /* We don't expect data RX interrupts, just reset RX FIFO */ + + modifyreg32(MPFS_SPI_COMMAND, 0, MPFS_SPI_RXFIFORST); + putreg32(MPFS_SPI_DATA_RX, MPFS_SPI_INT_CLEAR); + } + if (status & MPFS_SPI_RXCHOVRFLW) { /* Handle receive overflow */ @@ -1449,6 +1420,10 @@ static void mpfs_spi_init(struct spi_dev_s *dev) 0); modifyreg32(MPFS_SYSREG_SUBBLK_CLOCK_CR, 0, MPFS_SYSREG_SUBBLK_CORESPI); + /* Make sure the RX interrupt is disabled (we don't use it) */ + + modifyreg32(MPFS_SPI_CONTROL2, MPFS_SPI_INTEN_DATA_RX, 0); + /* Install some default values, mode and nbits for read back */ mpfs_spi_setfrequency(dev, config->clk_freq);