On Tue, Dec 02, 2025 at 03:55:03PM +0800, Carlos Song wrote: > Enable DMA mode for SPI IMX in target mode. Disable the word delay feature > for target mode, because target mode should always keep high performance > to make sure it can follow the master. Target mode continues to operate in > dynamic burst mode. > > Signed-off-by: Carlos Song <[email protected]> > ---
Reviewed-by: Frank Li <[email protected]> > drivers/spi/spi-imx.c | 77 ++++++++++++++++++++++++++++++++----------- > 1 file changed, 57 insertions(+), 20 deletions(-) > > diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c > index 045f4ffd680a..e37d786a5276 100644 > --- a/drivers/spi/spi-imx.c > +++ b/drivers/spi/spi-imx.c > @@ -264,7 +264,13 @@ static bool spi_imx_can_dma(struct spi_controller > *controller, struct spi_device > if (!controller->dma_rx) > return false; > > - if (spi_imx->target_mode) > + /* > + * Due to Freescale errata ERR003775 "eCSPI: Burst completion by Chip > + * Select (SS) signal in Slave mode is not functional" burst size must > + * be set exactly to the size of the transfer. This limit SPI > transaction > + * with maximum 2^12 bits. > + */ > + if (transfer->len > MX53_MAX_TRANSFER_BYTES && spi_imx->target_mode) > return false; > > if (transfer->len < spi_imx->devtype_data->fifo_size) > @@ -1763,23 +1769,51 @@ static int spi_imx_dma_submit(struct spi_imx_data > *spi_imx, > > transfer_timeout = spi_imx_calculate_timeout(spi_imx, transfer->len); > > - /* Wait SDMA to finish the data transfer.*/ > - time_left = wait_for_completion_timeout(&spi_imx->dma_tx_completion, > - transfer_timeout); > - if (!time_left) { > - dev_err(spi_imx->dev, "I/O Error in DMA TX\n"); > - dmaengine_terminate_all(controller->dma_tx); > - dmaengine_terminate_all(controller->dma_rx); > - return -ETIMEDOUT; > - } > + if (!spi_imx->target_mode) { > + /* Wait SDMA to finish the data transfer.*/ > + time_left = > wait_for_completion_timeout(&spi_imx->dma_tx_completion, > + transfer_timeout); > + if (!time_left) { > + dev_err(spi_imx->dev, "I/O Error in DMA TX\n"); > + dmaengine_terminate_all(controller->dma_tx); > + dmaengine_terminate_all(controller->dma_rx); > + return -ETIMEDOUT; > + } > > - time_left = wait_for_completion_timeout(&spi_imx->dma_rx_completion, > - transfer_timeout); > - if (!time_left) { > - dev_err(&controller->dev, "I/O Error in DMA RX\n"); > - spi_imx->devtype_data->reset(spi_imx); > - dmaengine_terminate_all(controller->dma_rx); > - return -ETIMEDOUT; > + time_left = > wait_for_completion_timeout(&spi_imx->dma_rx_completion, > + transfer_timeout); > + if (!time_left) { > + dev_err(&controller->dev, "I/O Error in DMA RX\n"); > + spi_imx->devtype_data->reset(spi_imx); > + dmaengine_terminate_all(controller->dma_rx); > + return -ETIMEDOUT; > + } > + } else { > + spi_imx->target_aborted = false; > + > + if > (wait_for_completion_interruptible(&spi_imx->dma_tx_completion) || > + READ_ONCE(spi_imx->target_aborted)) { > + dev_dbg(spi_imx->dev, "I/O Error in DMA TX > interrupted\n"); > + dmaengine_terminate_all(controller->dma_tx); > + dmaengine_terminate_all(controller->dma_rx); > + return -EINTR; > + } > + > + if > (wait_for_completion_interruptible(&spi_imx->dma_rx_completion) || > + READ_ONCE(spi_imx->target_aborted)) { > + dev_dbg(spi_imx->dev, "I/O Error in DMA RX > interrupted\n"); > + dmaengine_terminate_all(controller->dma_rx); > + return -EINTR; > + } > + > + /* > + * ECSPI has a HW issue when works in Target mode, after 64 > words > + * writtern to TXFIFO, even TXFIFO becomes empty, ECSPI_TXDATA > keeps > + * shift out the last word data, so we have to disable ECSPI > when in > + * target mode after the transfer completes. > + */ > + if (spi_imx->devtype_data->disable) > + spi_imx->devtype_data->disable(spi_imx); > } > > return 0; > @@ -1902,7 +1936,7 @@ static int spi_imx_dma_package_transfer(struct > spi_imx_data *spi_imx, > static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx, > struct spi_transfer *transfer) > { > - bool word_delay = transfer->word_delay.value != 0; > + bool word_delay = transfer->word_delay.value != 0 && > !spi_imx->target_mode; > int ret; > int i; > > @@ -2108,7 +2142,7 @@ static int spi_imx_transfer_one(struct spi_controller > *controller, > while (spi_imx->devtype_data->rx_available(spi_imx)) > readl(spi_imx->base + MXC_CSPIRXDATA); > > - if (spi_imx->target_mode) > + if (spi_imx->target_mode && !spi_imx->usedma) > return spi_imx_pio_transfer_target(spi, transfer); > > /* > @@ -2120,7 +2154,10 @@ static int spi_imx_transfer_one(struct spi_controller > *controller, > ret = spi_imx_dma_transfer(spi_imx, transfer); > if (transfer->error & SPI_TRANS_FAIL_NO_START) { > spi_imx->usedma = false; > - return spi_imx_pio_transfer(spi, transfer); > + if (spi_imx->target_mode) > + return spi_imx_pio_transfer_target(spi, > transfer); > + else > + return spi_imx_pio_transfer(spi, transfer); > } > return ret; > } > -- > 2.34.1 >
