mirror of
https://github.com/torvalds/linux.git
synced 2024-11-26 22:21:42 +00:00
spi: dw: Use DMA max burst to set the request thresholds
Each channel of DMA controller may have a limited length of burst transaction (number of IO operations performed at ones in a single DMA client request). This parameter can be used to setup the most optimal DMA Tx/Rx data level values. In order to avoid the Tx buffer overrun we can set the DMA Tx level to be of FIFO depth minus the maximum burst transactions length. To prevent the Rx buffer underflow the DMA Rx level should be set to the maximum burst transactions length. This commit setups the DMA channels and the DW SPI DMA Tx/Rx levels in accordance with these rules. Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Cc: Alexey Malahov <Alexey.Malahov@baikalelectronics.ru> Cc: Thomas Bogendoerfer <tsbogend@alpha.franken.de> Cc: Arnd Bergmann <arnd@arndb.de> Cc: Feng Tang <feng.tang@intel.com> Cc: Rob Herring <robh+dt@kernel.org> Cc: linux-mips@vger.kernel.org Cc: devicetree@vger.kernel.org Link: https://lore.kernel.org/r/20200529131205.31838-8-Sergey.Semin@baikalelectronics.ru Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
parent
c534df9d62
commit
0b2b66514f
@ -36,6 +36,31 @@ static bool mid_spi_dma_chan_filter(struct dma_chan *chan, void *param)
|
||||
return true;
|
||||
}
|
||||
|
||||
static void mid_spi_maxburst_init(struct dw_spi *dws)
|
||||
{
|
||||
struct dma_slave_caps caps;
|
||||
u32 max_burst, def_burst;
|
||||
int ret;
|
||||
|
||||
def_burst = dws->fifo_len / 2;
|
||||
|
||||
ret = dma_get_slave_caps(dws->rxchan, &caps);
|
||||
if (!ret && caps.max_burst)
|
||||
max_burst = caps.max_burst;
|
||||
else
|
||||
max_burst = RX_BURST_LEVEL;
|
||||
|
||||
dws->rxburst = min(max_burst, def_burst);
|
||||
|
||||
ret = dma_get_slave_caps(dws->txchan, &caps);
|
||||
if (!ret && caps.max_burst)
|
||||
max_burst = caps.max_burst;
|
||||
else
|
||||
max_burst = TX_BURST_LEVEL;
|
||||
|
||||
dws->txburst = min(max_burst, def_burst);
|
||||
}
|
||||
|
||||
static int mid_spi_dma_init_mfld(struct device *dev, struct dw_spi *dws)
|
||||
{
|
||||
struct dw_dma_slave slave = {
|
||||
@ -73,6 +98,8 @@ static int mid_spi_dma_init_mfld(struct device *dev, struct dw_spi *dws)
|
||||
|
||||
init_completion(&dws->dma_completion);
|
||||
|
||||
mid_spi_maxburst_init(dws);
|
||||
|
||||
return 0;
|
||||
|
||||
free_rxchan:
|
||||
@ -100,6 +127,8 @@ static int mid_spi_dma_init_generic(struct device *dev, struct dw_spi *dws)
|
||||
|
||||
init_completion(&dws->dma_completion);
|
||||
|
||||
mid_spi_maxburst_init(dws);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -229,7 +258,7 @@ static struct dma_async_tx_descriptor *dw_spi_dma_prepare_tx(struct dw_spi *dws,
|
||||
memset(&txconf, 0, sizeof(txconf));
|
||||
txconf.direction = DMA_MEM_TO_DEV;
|
||||
txconf.dst_addr = dws->dma_addr;
|
||||
txconf.dst_maxburst = TX_BURST_LEVEL;
|
||||
txconf.dst_maxburst = dws->txburst;
|
||||
txconf.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
|
||||
txconf.dst_addr_width = convert_dma_width(dws->n_bytes);
|
||||
txconf.device_fc = false;
|
||||
@ -321,7 +350,7 @@ static struct dma_async_tx_descriptor *dw_spi_dma_prepare_rx(struct dw_spi *dws,
|
||||
memset(&rxconf, 0, sizeof(rxconf));
|
||||
rxconf.direction = DMA_DEV_TO_MEM;
|
||||
rxconf.src_addr = dws->dma_addr;
|
||||
rxconf.src_maxburst = RX_BURST_LEVEL;
|
||||
rxconf.src_maxburst = dws->rxburst;
|
||||
rxconf.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
|
||||
rxconf.src_addr_width = convert_dma_width(dws->n_bytes);
|
||||
rxconf.device_fc = false;
|
||||
@ -346,8 +375,8 @@ static int mid_spi_dma_setup(struct dw_spi *dws, struct spi_transfer *xfer)
|
||||
{
|
||||
u16 imr = 0, dma_ctrl = 0;
|
||||
|
||||
dw_writel(dws, DW_SPI_DMARDLR, RX_BURST_LEVEL - 1);
|
||||
dw_writel(dws, DW_SPI_DMATDLR, TX_BURST_LEVEL);
|
||||
dw_writel(dws, DW_SPI_DMARDLR, dws->rxburst - 1);
|
||||
dw_writel(dws, DW_SPI_DMATDLR, dws->fifo_len - dws->txburst);
|
||||
|
||||
if (xfer->tx_buf) {
|
||||
dma_ctrl |= SPI_DMA_TDMAE;
|
||||
|
@ -142,7 +142,9 @@ struct dw_spi {
|
||||
|
||||
/* DMA info */
|
||||
struct dma_chan *txchan;
|
||||
u32 txburst;
|
||||
struct dma_chan *rxchan;
|
||||
u32 rxburst;
|
||||
unsigned long dma_chan_busy;
|
||||
dma_addr_t dma_addr; /* phy address of the Data register */
|
||||
const struct dw_spi_dma_ops *dma_ops;
|
||||
|
Loading…
Reference in New Issue
Block a user