stm32h7:stm32_spi Restores internal DMA buffer broken in 574b25
574b25 broke the internal DMA buffers usage that solved the following problem: The DMA capable interface does not know the buffers extent. It calulates it from size. The user may need to transfer less than a cachline bytes, but STILL have a DMA cabable buffer. The user is therefore foreced to transfer more data then needed to "trick" the DMA cabable function. This is a wast of bus bandwith and may not work will all devices. The internal buffer, solve this issue. stm32h7:stm32_spi review changes Added sugestion from jlaitine to support RX only.
This commit is contained in:
parent
f47151f8a7
commit
1b8c072802
@ -515,7 +515,7 @@ static const struct spi_ops_s g_sp3iops =
|
||||
#ifdef CONFIG_SPI_CALLBACK
|
||||
.registercallback = stm32_spi3register, /* provided externally */
|
||||
#else
|
||||
.registercallback = 0, /* not implemented */
|
||||
.registercallback = 0, /* not implemented */
|
||||
#endif
|
||||
};
|
||||
|
||||
@ -583,7 +583,7 @@ static const struct spi_ops_s g_sp4iops =
|
||||
#ifdef CONFIG_SPI_CALLBACK
|
||||
.registercallback = stm32_spi4register, /* provided externally */
|
||||
#else
|
||||
.registercallback = 0, /* not implemented */
|
||||
.registercallback = 0, /* not implemented */
|
||||
#endif
|
||||
};
|
||||
|
||||
@ -651,7 +651,7 @@ static const struct spi_ops_s g_sp5iops =
|
||||
#ifdef CONFIG_SPI_CALLBACK
|
||||
.registercallback = stm32_spi5register, /* provided externally */
|
||||
#else
|
||||
.registercallback = 0, /* not implemented */
|
||||
.registercallback = 0, /* not implemented */
|
||||
#endif
|
||||
};
|
||||
|
||||
@ -719,7 +719,7 @@ static const struct spi_ops_s g_sp6iops =
|
||||
#ifdef CONFIG_SPI_CALLBACK
|
||||
.registercallback = stm32_spi6register, /* provided externally */
|
||||
#else
|
||||
.registercallback = 0, /* not implemented */
|
||||
.registercallback = 0, /* not implemented */
|
||||
#endif
|
||||
};
|
||||
|
||||
@ -1924,6 +1924,7 @@ static void spi_exchange(FAR struct spi_dev_s *dev, FAR const void *txbuffer,
|
||||
static uint8_t rxdummy[ARMV7M_DCACHE_LINESIZE]
|
||||
__attribute__((aligned(ARMV7M_DCACHE_LINESIZE)));
|
||||
static const uint16_t txdummy = 0xffff;
|
||||
FAR void * orig_rxbuffer = rxbuffer;
|
||||
|
||||
DEBUGASSERT(priv != NULL);
|
||||
|
||||
@ -1955,39 +1956,60 @@ static void spi_exchange(FAR struct spi_dev_s *dev, FAR const void *txbuffer,
|
||||
return;
|
||||
}
|
||||
|
||||
/* Setup the DMA configs */
|
||||
/* If this bus uses the driver's DMA aligned buffers (priv->txbuf != NULL)
|
||||
* we will incur 2 copies. However the copy cost is much less the non
|
||||
* DMA transfer time. Having the buffer in the driver ensures DMA can be
|
||||
* used. This is needed because the stm32_dmacapable API does not support
|
||||
* passing the buffer extent. So the only extent calculated is buffer
|
||||
* plus the transfer size. The sizes can be less than a cache line size,
|
||||
* and not aligned and are typically greater then 4 bytes, which is
|
||||
* about the break even point for the DMA IO overhead.
|
||||
*/
|
||||
|
||||
/* Does bus support in driver DMA buffering? */
|
||||
|
||||
if (priv->txbuf)
|
||||
{
|
||||
if (nbytes > priv->buflen)
|
||||
{
|
||||
/* Buffer is too big for internal DMA buffer so fall back. */
|
||||
|
||||
spi_exchange_nodma(dev, txbuffer, rxbuffer, nwords);
|
||||
return;
|
||||
}
|
||||
|
||||
/* First copy: If provided, copy caller's buffer to the internal DMA
|
||||
* txbuf
|
||||
*/
|
||||
|
||||
if (txbuffer)
|
||||
{
|
||||
memcpy(priv->txbuf, txbuffer, nbytes);
|
||||
|
||||
/* Adjust pointers to internal DMA buffers */
|
||||
|
||||
txbuffer = priv->txbuf;
|
||||
}
|
||||
|
||||
/* orig_rxbuffer holds the callers return buffer */
|
||||
|
||||
rxbuffer = rxbuffer ? priv->rxbuf : rxbuffer;
|
||||
}
|
||||
|
||||
/* Setup the DMA configs using the internal or external set of buffers */
|
||||
|
||||
spi_dmatxsetup(priv, txbuffer, &txdummy, nwords, &txdmacfg);
|
||||
spi_dmarxsetup(priv, rxbuffer, (uint16_t *)rxdummy, nwords, &rxdmacfg);
|
||||
|
||||
#ifdef CONFIG_STM32H7_DMACAPABLE
|
||||
|
||||
/* Setup DMAs */
|
||||
|
||||
/* If this bus uses a in driver buffers we will incur 2 copies,
|
||||
* The copy cost is << less the non DMA transfer time and having
|
||||
* the buffer in the driver ensures DMA can be used. This is bacause
|
||||
* the API does not support passing the buffer extent so the only
|
||||
* extent is buffer + the transfer size. These can sizes be less than
|
||||
* the cache line size, and not aligned and tyicaly greater then 4
|
||||
* bytes, which is about the break even point for the DMA IO overhead.
|
||||
/* Test for DMA capability of only callers buffers, internal buffers are
|
||||
* guaranteed capable.
|
||||
*/
|
||||
|
||||
if (txbuffer && priv->txbuf)
|
||||
{
|
||||
if (nbytes > priv->buflen)
|
||||
{
|
||||
nbytes = priv->buflen;
|
||||
}
|
||||
|
||||
memcpy(priv->txbuf, txbuffer, nbytes);
|
||||
txbuffer = priv->txbuf;
|
||||
rxbuffer = rxbuffer ? priv->rxbuf : rxbuffer;
|
||||
}
|
||||
|
||||
if ((priv->config != SIMPLEX_RX &&
|
||||
if ((priv->config != SIMPLEX_RX && priv->txbuf == 0 &&
|
||||
!stm32_dmacapable(priv->txdma, &txdmacfg)) ||
|
||||
(priv->config != SIMPLEX_TX &&
|
||||
(priv->config != SIMPLEX_TX && priv->rxbuf == 0 &&
|
||||
!stm32_dmacapable(priv->rxdma, &rxdmacfg)))
|
||||
{
|
||||
/* Unsupported memory region fall back to non-DMA method. */
|
||||
@ -2009,29 +2031,6 @@ static void spi_exchange(FAR struct spi_dev_s *dev, FAR const void *txbuffer,
|
||||
* 4. Enable the SPI by setting the SPE bit.
|
||||
*/
|
||||
|
||||
spi_enable(priv, false);
|
||||
spi_modifyreg(priv, STM32_SPI_CFG1_OFFSET, SPI_CFG1_TXDMAEN,
|
||||
SPI_CFG1_RXDMAEN);
|
||||
|
||||
spiinfo("txbuffer=%p rxbuffer=%p nwords=%d\n",
|
||||
txbuffer, rxbuffer, nwords);
|
||||
DEBUGASSERT(priv->spibase != 0);
|
||||
|
||||
/* Setup the DMA */
|
||||
|
||||
if (priv->config != SIMPLEX_RX)
|
||||
{
|
||||
stm32_dmasetup(priv->txdma, &txdmacfg);
|
||||
}
|
||||
|
||||
if (priv->config != SIMPLEX_TX)
|
||||
{
|
||||
stm32_dmasetup(priv->rxdma, &rxdmacfg);
|
||||
}
|
||||
|
||||
spi_modifyreg(priv, STM32_SPI_CFG1_OFFSET, 0, SPI_CFG1_TXDMAEN |
|
||||
SPI_CFG1_RXDMAEN);
|
||||
|
||||
/* Flush cache to physical memory */
|
||||
|
||||
if (txbuffer)
|
||||
@ -2045,6 +2044,35 @@ static void spi_exchange(FAR struct spi_dev_s *dev, FAR const void *txbuffer,
|
||||
(uintptr_t)rxbuffer + nbytes);
|
||||
}
|
||||
|
||||
/* N.B. the H7 tri-states the clock output on SPI disable and
|
||||
* unfortunately the Chip Select (CS) is active. So we keep
|
||||
* the device disabled for the minimum time, that meets the
|
||||
* setup sequence criteria.
|
||||
*/
|
||||
|
||||
spi_enable(priv, false);
|
||||
spi_modifyreg(priv, STM32_SPI_CFG1_OFFSET, SPI_CFG1_TXDMAEN,
|
||||
SPI_CFG1_RXDMAEN);
|
||||
|
||||
spiinfo("txbuffer=%p rxbuffer=%p nwords=%d\n",
|
||||
txbuffer, rxbuffer, nwords);
|
||||
DEBUGASSERT(priv->spibase != 0);
|
||||
|
||||
/* Setup the DMA */
|
||||
|
||||
if (priv->config != SIMPLEX_TX)
|
||||
{
|
||||
stm32_dmasetup(priv->rxdma, &rxdmacfg);
|
||||
}
|
||||
|
||||
if (priv->config != SIMPLEX_RX)
|
||||
{
|
||||
stm32_dmasetup(priv->txdma, &txdmacfg);
|
||||
}
|
||||
|
||||
spi_modifyreg(priv, STM32_SPI_CFG1_OFFSET, 0, SPI_CFG1_TXDMAEN |
|
||||
SPI_CFG1_RXDMAEN);
|
||||
|
||||
#ifdef CONFIG_SPI_TRIGGER
|
||||
/* Is deferred triggering in effect? */
|
||||
|
||||
@ -2078,7 +2106,7 @@ static void spi_exchange(FAR struct spi_dev_s *dev, FAR const void *txbuffer,
|
||||
spi_dmatxwait(priv);
|
||||
|
||||
/* To close communication it is mandatory to follow these steps in
|
||||
* order:
|
||||
* this order:
|
||||
* 1. Disable DMA request for Tx and Rx in the DMA registers, if the
|
||||
* DMA issued.
|
||||
* 2. Disable the SPI by following the SPI disable procedure.
|
||||
@ -2091,10 +2119,17 @@ static void spi_exchange(FAR struct spi_dev_s *dev, FAR const void *txbuffer,
|
||||
SPI_CFG1_RXDMAEN, 0);
|
||||
spi_enable(priv, true);
|
||||
|
||||
/* Second copy: Copy the DMA internal buffer to caller's buffer */
|
||||
|
||||
if (orig_rxbuffer && priv->rxbuf)
|
||||
{
|
||||
memcpy(orig_rxbuffer, priv->rxbuf, nbytes);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SPI_TRIGGER
|
||||
priv->trigarmed = false;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_STM32H7_SPI_DMA */
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user