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
>

Reply via email to