mirror of
https://github.com/apache/nuttx.git
synced 2025-01-13 10:58:49 +08:00
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
This commit is contained in:
parent
ded321a515
commit
9be93addea
1 changed files with 59 additions and 84 deletions
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue