[PATCH 12/15] spi/s3c64xx: Add support DMA engine API

Alim Akhtar alim.akhtar at gmail.com
Fri Aug 19 06:30:49 EDT 2011


On Tue, Aug 9, 2011 at 9:43 AM, Alim Akhtar <alim.akhtar at gmail.com> wrote:
> On Mon, Aug 8, 2011 at 11:17 PM, Jassi Brar <jassisinghbrar at gmail.com> wrote:
>> On Wed, Jul 27, 2011 at 11:01 AM, Boojin Kim <boojin.kim at samsung.com> wrote:
>>> This patch adds to support DMA generic API to transfer raw
>>> SPI data. Basiclly the spi driver uses DMA generic API if
>>> architecture supports it. Otherwise, uses Samsung specific
>>> S3C-PL330 APIs.
>>>
>>> Signed-off-by: Boojin Kim <boojin.kim at samsung.com>
>>> Acked-by: Grant Likely <grant.likely at secretlab.ca>
>>> Signed-off-by: Kukjin Kim <kgene.kim at samsung.com>
>>> ---
>>>  drivers/spi/spi_s3c64xx.c |  141 ++++++++++++++++++++++-----------------------
>>>  1 files changed, 69 insertions(+), 72 deletions(-)
>>>
>>> diff --git a/drivers/spi/spi_s3c64xx.c b/drivers/spi/spi_s3c64xx.c
>>> index 8945e20..a4cf76a 100644
>>> --- a/drivers/spi/spi_s3c64xx.c
>>> +++ b/drivers/spi/spi_s3c64xx.c
>>> @@ -172,6 +172,9 @@ struct s3c64xx_spi_driver_data {
>>>        unsigned                        state;
>>>        unsigned                        cur_mode, cur_bpw;
>>>        unsigned                        cur_speed;
>>> +       unsigned                        rx_ch;
>>> +       unsigned                        tx_ch;
>>> +       struct samsung_dma_ops          *ops;
>>>  };
>>>
>>>  static struct s3c2410_dma_client s3c64xx_spi_dma_client = {
>>> @@ -227,6 +230,38 @@ static void flush_fifo(struct s3c64xx_spi_driver_data *sdd)
>>>        writel(val, regs + S3C64XX_SPI_CH_CFG);
>>>  }
>>>
>>> +static void s3c64xx_spi_dma_rxcb(void *data)
>>> +{
>>> +       struct s3c64xx_spi_driver_data *sdd
>>> +               = (struct s3c64xx_spi_driver_data *)data;
>> void* doesn't need typecasting (same for all such occurances)
>> IIRC someone already pointed it out?
>>
>>
>>> +       unsigned long flags;
>>> +
>>> +       spin_lock_irqsave(&sdd->lock, flags);
>>> +
>>> +       sdd->state &= ~RXBUSY;
>>> +       /* If the other done */
>>> +       if (!(sdd->state & TXBUSY))
>>> +               complete(&sdd->xfer_completion);
>>> +
>>> +       spin_unlock_irqrestore(&sdd->lock, flags);
>>> +}
>>> +
>>> +static void s3c64xx_spi_dma_txcb(void *data)
>>> +{
>>> +       struct s3c64xx_spi_driver_data *sdd
>>> +               = (struct s3c64xx_spi_driver_data *)data;
>>> +       unsigned long flags;
>>> +
>>> +       spin_lock_irqsave(&sdd->lock, flags);
>>> +
>>> +       sdd->state &= ~TXBUSY;
>>> +       /* If the other done */
>>> +       if (!(sdd->state & RXBUSY))
>>> +               complete(&sdd->xfer_completion);
>>> +
>>> +       spin_unlock_irqrestore(&sdd->lock, flags);
>>> +}
>>> +
>>>  static void enable_datapath(struct s3c64xx_spi_driver_data *sdd,
>>>                                struct spi_device *spi,
>>>                                struct spi_transfer *xfer, int dma_mode)
>>> @@ -234,6 +269,7 @@ static void enable_datapath(struct s3c64xx_spi_driver_data *sdd,
>>>        struct s3c64xx_spi_info *sci = sdd->cntrlr_info;
>>>        void __iomem *regs = sdd->regs;
>>>        u32 modecfg, chcfg;
>>> +       struct samsung_dma_prep_info info;
>>>
>>>        modecfg = readl(regs + S3C64XX_SPI_MODE_CFG);
>>>        modecfg &= ~(S3C64XX_SPI_MODE_TXDMA_ON | S3C64XX_SPI_MODE_RXDMA_ON);
>>> @@ -259,10 +295,14 @@ static void enable_datapath(struct s3c64xx_spi_driver_data *sdd,
>>>                chcfg |= S3C64XX_SPI_CH_TXCH_ON;
>>>                if (dma_mode) {
>>>                        modecfg |= S3C64XX_SPI_MODE_TXDMA_ON;
>>> -                       s3c2410_dma_config(sdd->tx_dmach, sdd->cur_bpw / 8);
>>> -                       s3c2410_dma_enqueue(sdd->tx_dmach, (void *)sdd,
>>> -                                               xfer->tx_dma, xfer->len);
>>> -                       s3c2410_dma_ctrl(sdd->tx_dmach, S3C2410_DMAOP_START);
>>> +                       info.cap = DMA_SLAVE;
>>> +                       info.direction = DMA_TO_DEVICE;
>>> +                       info.buf = xfer->tx_dma;
>>> +                       info.len = xfer->len;
>>> +                       info.fp = s3c64xx_spi_dma_txcb;
>>> +                       info.fp_param = sdd;
>>> +                       sdd->ops->prepare(sdd->tx_ch, &info);
>>> +                       sdd->ops->trigger(sdd->tx_ch);
>>>                } else {
>>>                        switch (sdd->cur_bpw) {
>>>                        case 32:
>>> @@ -294,10 +334,14 @@ static void enable_datapath(struct s3c64xx_spi_driver_data *sdd,
>>>                        writel(((xfer->len * 8 / sdd->cur_bpw) & 0xffff)
>>>                                        | S3C64XX_SPI_PACKET_CNT_EN,
>>>                                        regs + S3C64XX_SPI_PACKET_CNT);
>>> -                       s3c2410_dma_config(sdd->rx_dmach, sdd->cur_bpw / 8);
>>> -                       s3c2410_dma_enqueue(sdd->rx_dmach, (void *)sdd,
>>> -                                               xfer->rx_dma, xfer->len);
>>> -                       s3c2410_dma_ctrl(sdd->rx_dmach, S3C2410_DMAOP_START);
>>> +                       info.cap = DMA_SLAVE;
>>> +                       info.direction = DMA_FROM_DEVICE;
>>> +                       info.buf = xfer->rx_dma;
>>> +                       info.len = xfer->len;
>>> +                       info.fp = s3c64xx_spi_dma_rxcb;
>>> +                       info.fp_param = sdd;
>>> +                       sdd->ops->prepare(sdd->rx_ch, &info);
>>> +                       sdd->ops->trigger(sdd->rx_ch);
>>>                }
>>>        }
>>>
>>> @@ -483,46 +527,6 @@ static void s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd)
>>>        }
>>>  }
>>>
>>> -static void s3c64xx_spi_dma_rxcb(struct s3c2410_dma_chan *chan, void *buf_id,
>>> -                                int size, enum s3c2410_dma_buffresult res)
>>> -{
>>> -       struct s3c64xx_spi_driver_data *sdd = buf_id;
>>> -       unsigned long flags;
>>> -
>>> -       spin_lock_irqsave(&sdd->lock, flags);
>>> -
>>> -       if (res == S3C2410_RES_OK)
>>> -               sdd->state &= ~RXBUSY;
>>> -       else
>>> -               dev_err(&sdd->pdev->dev, "DmaAbrtRx-%d\n", size);
>>> -
>>> -       /* If the other done */
>>> -       if (!(sdd->state & TXBUSY))
>>> -               complete(&sdd->xfer_completion);
>>> -
>>> -       spin_unlock_irqrestore(&sdd->lock, flags);
>>> -}
>>> -
>>> -static void s3c64xx_spi_dma_txcb(struct s3c2410_dma_chan *chan, void *buf_id,
>>> -                                int size, enum s3c2410_dma_buffresult res)
>>> -{
>>> -       struct s3c64xx_spi_driver_data *sdd = buf_id;
>>> -       unsigned long flags;
>>> -
>>> -       spin_lock_irqsave(&sdd->lock, flags);
>>> -
>>> -       if (res == S3C2410_RES_OK)
>>> -               sdd->state &= ~TXBUSY;
>>> -       else
>>> -               dev_err(&sdd->pdev->dev, "DmaAbrtTx-%d \n", size);
>>> -
>>> -       /* If the other done */
>>> -       if (!(sdd->state & RXBUSY))
>>> -               complete(&sdd->xfer_completion);
>>> -
>>> -       spin_unlock_irqrestore(&sdd->lock, flags);
>>> -}
>>> -
>>>  #define XFER_DMAADDR_INVALID DMA_BIT_MASK(32)
>>>
>>>  static int s3c64xx_spi_map_mssg(struct s3c64xx_spi_driver_data *sdd,
>>> @@ -697,12 +701,10 @@ static void handle_msg(struct s3c64xx_spi_driver_data *sdd,
>>>                        if (use_dma) {
>>>                                if (xfer->tx_buf != NULL
>>>                                                && (sdd->state & TXBUSY))
>>> -                                       s3c2410_dma_ctrl(sdd->tx_dmach,
>>> -                                                       S3C2410_DMAOP_FLUSH);
>>> +                                       sdd->ops->stop(sdd->tx_ch);
>>>                                if (xfer->rx_buf != NULL
>>>                                                && (sdd->state & RXBUSY))
>>> -                                       s3c2410_dma_ctrl(sdd->rx_dmach,
>>> -                                                       S3C2410_DMAOP_FLUSH);
>>> +                                       sdd->ops->stop(sdd->rx_ch);
>>>                        }
>>>
>>>                        goto out;
>>> @@ -742,24 +744,19 @@ out:
>>>
>>>  static int acquire_dma(struct s3c64xx_spi_driver_data *sdd)
>>>  {
>>> -       if (s3c2410_dma_request(sdd->rx_dmach,
>>> -                                       &s3c64xx_spi_dma_client, NULL) < 0) {
>>> -               dev_err(&sdd->pdev->dev, "cannot get RxDMA\n");
>>> -               return 0;
>>> -       }
>>> -       s3c2410_dma_set_buffdone_fn(sdd->rx_dmach, s3c64xx_spi_dma_rxcb);
>>> -       s3c2410_dma_devconfig(sdd->rx_dmach, S3C2410_DMASRC_HW,
>>> -                                       sdd->sfr_start + S3C64XX_SPI_RX_DATA);
>>> -
>>> -       if (s3c2410_dma_request(sdd->tx_dmach,
>>> -                                       &s3c64xx_spi_dma_client, NULL) < 0) {
>>> -               dev_err(&sdd->pdev->dev, "cannot get TxDMA\n");
>>> -               s3c2410_dma_free(sdd->rx_dmach, &s3c64xx_spi_dma_client);
>>> -               return 0;
>>> -       }
>>> -       s3c2410_dma_set_buffdone_fn(sdd->tx_dmach, s3c64xx_spi_dma_txcb);
>>> -       s3c2410_dma_devconfig(sdd->tx_dmach, S3C2410_DMASRC_MEM,
>>> -                                       sdd->sfr_start + S3C64XX_SPI_TX_DATA);
>>> +
>>> +       struct samsung_dma_info info;
>>> +       sdd->ops = samsung_dma_get_ops();
>>> +
>>> +       info.cap = DMA_SLAVE;
>>> +       info.client = &s3c64xx_spi_dma_client;
>>> +       info.direction = DMA_FROM_DEVICE;
>>> +       info.fifo = sdd->sfr_start + S3C64XX_SPI_RX_DATA;
>>> +       info.width = sdd->cur_bpw / 8;
>>> +       sdd->rx_ch = sdd->ops->request(sdd->rx_dmach, &info);
>>> +       info.direction = DMA_TO_DEVICE;
>>> +       info.fifo = sdd->sfr_start + S3C64XX_SPI_TX_DATA;
>>> +       sdd->tx_ch = sdd->ops->request(sdd->tx_dmach, &info);
>>>
>>>        return 1;
>>>  }
>>> @@ -800,8 +797,8 @@ static void s3c64xx_spi_work(struct work_struct *work)
>>>        spin_unlock_irqrestore(&sdd->lock, flags);
>>>
>>>        /* Free DMA channels */
>>> -       s3c2410_dma_free(sdd->tx_dmach, &s3c64xx_spi_dma_client);
>>> -       s3c2410_dma_free(sdd->rx_dmach, &s3c64xx_spi_dma_client);
>>> +       sdd->ops->release(sdd->rx_ch, &s3c64xx_spi_dma_client);
>>> +       sdd->ops->release(sdd->tx_ch, &s3c64xx_spi_dma_client);
>>>  }
>>
>> Btw, this spi driver is for S3C64xx(with pl080) and S5P(with pl330)
>> series, both of which
>> have DMAENGINE drivers. May be it could be directly switched to using
>> those, rather than
>> via Samsung's wrapper driver.
>> Or am I overlooking something ?
> Exactly, spi_s3c64xx.c (including Sound driver) can not be used with
> pl080 and pl330 (DMAENGINE drivers) as it is.
> Recently I was trying to use PL080 DMAENGINE driver, and i was ended
> up using some #ifdef in the spi driver.
> something like
> #ifdef CONFIG_PL080
> sdd->tx_dmac.bus_id = dmatx_res->name;
> sdd->rx_dmac.bus_id = dmarx_res->name;
> #else
> sdd->tx_dmac.bus_id = dmatx_res->start;
> sdd->tx_dmac.bus_id = dmatx_res->start;
> #endif
>
> This is because, Pl080 handle the channel as a char *(name) and pl330
> expect the channel to be enum (a number).
>
> I think the solution could be changes in the either of these drivers
> to follow some symmetry or we will be ending up with
> two client driver for the same device or writing up some unnecessary
> warper code or finally using some #ifdef.
>
> Please suggest if you guys have any other idea/approach to handle such
> kind of situation.
>
> Below is the git diff of spi_s3c64xx driver using with PL080 DMAENGINE driver.
> This patch is against kgene's next-samsung-dma-v4
> ------------------------------------------------------------------------------------------------------------------
> diff --git a/drivers/spi/spi_s3c64xx.c b/drivers/spi/spi_s3c64xx.c
> index a4cf76a..f7b9c37 100644
> --- a/drivers/spi/spi_s3c64xx.c
> +++ b/drivers/spi/spi_s3c64xx.c
> @@ -24,6 +24,7 @@
>  #include <linux/delay.h>
>  #include <linux/clk.h>
>  #include <linux/dma-mapping.h>
> +#include <linux/amba/pl08x.h>
>  #include <linux/platform_device.h>
>  #include <linux/spi/spi.h>
>
> @@ -165,8 +166,13 @@ struct s3c64xx_spi_driver_data {
>        struct work_struct              work;
>        struct list_head                queue;
>        spinlock_t                      lock;
> +#ifdef CONFIG_DMADEV_PL080
> +       struct pl08x_channel_data       rx_dmach;
> +       struct pl08x_channel_data       tx_dmach;
> +#else
>        enum dma_ch                     rx_dmach;
>        enum dma_ch                     tx_dmach;
> +#endif
>        unsigned long                   sfr_start;
>        struct completion               xfer_completion;
>        unsigned                        state;
> @@ -753,10 +759,18 @@ static int acquire_dma(struct
> s3c64xx_spi_driver_data *sdd)
>        info.direction = DMA_FROM_DEVICE;
>        info.fifo = sdd->sfr_start + S3C64XX_SPI_RX_DATA;
>        info.width = sdd->cur_bpw / 8;
> +#ifdef CONFIG_DMADEV_PL080
> +       sdd->rx_ch = sdd->ops->request(sdd->rx_dmach.bus_id, &info);
> +#else
>        sdd->rx_ch = sdd->ops->request(sdd->rx_dmach, &info);
> +#endif
>        info.direction = DMA_TO_DEVICE;
>        info.fifo = sdd->sfr_start + S3C64XX_SPI_TX_DATA;
> -       sdd->tx_ch = sdd->ops->request(sdd->tx_dmach, &info);
> +#ifdef CONFIG_DMADEV_PL080
> +       sdd->tx_ch = sdd->ops->request(sdd->tx_dmach.bus_id, &info);
> +#else
> +               sdd->tx_ch = sdd->ops->request(sdd->tx_dmach, &info);
> +#endif
>
>        return 1;
>  }
> @@ -982,7 +996,6 @@ static int __init s3c64xx_spi_probe(struct
> platform_device *pdev)
>        }
>
>        /* Check for availability of necessary resource */
> -
>        dmatx_res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
>        if (dmatx_res == NULL) {
>                dev_err(&pdev->dev, "Unable to get SPI-Tx dma resource\n");
> @@ -1015,9 +1028,13 @@ static int __init s3c64xx_spi_probe(struct
> platform_device *pdev)
>        sdd->cntrlr_info = sci;
>        sdd->pdev = pdev;
>        sdd->sfr_start = mem_res->start;
> +#ifdef CONFIG_DMADEV_PL080
> +       sdd->tx_dmach.bus_id = dmatx_res->name;
> +       sdd->rx_dmach.bus_id = dmarx_res->name;
> +#else
>        sdd->tx_dmach = dmatx_res->start;
>        sdd->rx_dmach = dmarx_res->start;
> -
> +#endif
>        sdd->cur_bpw = 8;
>
>        master->bus_num = pdev->id;
> @@ -1105,7 +1122,6 @@ static int __init s3c64xx_spi_probe(struct
> platform_device *pdev)
>        dev_dbg(&pdev->dev, "\tIOmem=[0x%x-0x%x]\tDMA=[Rx-%d, Tx-%d]\n",
>                                        mem_res->end, mem_res->start,
>                                        sdd->rx_dmach, sdd->tx_dmach);
> -
>        return 0;
>
>  err8:
> ----------------------------------------------------------------------------------------------------------------------
>
Hi All,
Any suggestions/comments on my concerns?

Thanks!
> Regards,
> Alim
>
>
>
>> _______________________________________________
>> linux-arm-kernel mailing list
>> linux-arm-kernel at lists.infradead.org
>> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>>
>



More information about the linux-arm-kernel mailing list