diff mbox

mmc: host: pxamci: switch over to dmaengine use

Message ID 1433625322-28449-1-git-send-email-robert.jarzmik@free.fr (mailing list archive)
State New, archived
Headers show

Commit Message

Robert Jarzmik June 6, 2015, 9:15 p.m. UTC
From: Daniel Mack <zonque@gmail.com>

Switch over pxamci to dmaengine. This prepares the devicetree full
support of pxamci.

This was successfully tested on a PXA3xx board, as well as PXA27x.

Signed-off-by: Daniel Mack <zonque@gmail.com>
[adapted to pxa-dma]
Signed-off-by: Robert Jarzmik <robert.jarzmik@free.fr>
---
 drivers/mmc/host/pxamci.c | 200 ++++++++++++++++++++++++++--------------------
 1 file changed, 114 insertions(+), 86 deletions(-)

Comments

Ulf Hansson June 8, 2015, 8:17 a.m. UTC | #1
On 6 June 2015 at 23:15, Robert Jarzmik <robert.jarzmik@free.fr> wrote:
> From: Daniel Mack <zonque@gmail.com>
>
> Switch over pxamci to dmaengine. This prepares the devicetree full
> support of pxamci.
>
> This was successfully tested on a PXA3xx board, as well as PXA27x.
>
> Signed-off-by: Daniel Mack <zonque@gmail.com>
> [adapted to pxa-dma]
> Signed-off-by: Robert Jarzmik <robert.jarzmik@free.fr>
> ---
>  drivers/mmc/host/pxamci.c | 200 ++++++++++++++++++++++++++--------------------
>  1 file changed, 114 insertions(+), 86 deletions(-)
>
> diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c
> index 1b6d0bf..1420f29 100644
> --- a/drivers/mmc/host/pxamci.c
> +++ b/drivers/mmc/host/pxamci.c
> @@ -22,7 +22,9 @@
>  #include <linux/platform_device.h>
>  #include <linux/delay.h>
>  #include <linux/interrupt.h>
> +#include <linux/dmaengine.h>
>  #include <linux/dma-mapping.h>
> +#include <linux/dma/pxa-dma.h>

I can't find this header file in my tree, but apparantly it's in
linux-next. Probably it went through Vinod's dma tree, right?

Anyway, I can pick it up for the next-next release cycle or you may
ask Vinod to pick it up right now. Please tell me what you prefer.
Here's my ack.

Acked-by: Ulf Hansson <ulf.hansson@linaro.org>

Kind regards
Uffe

>  #include <linux/clk.h>
>  #include <linux/err.h>
>  #include <linux/mmc/host.h>
> @@ -37,7 +39,6 @@
>  #include <asm/sizes.h>
>
>  #include <mach/hardware.h>
> -#include <mach/dma.h>
>  #include <linux/platform_data/mmc-pxamci.h>
>
>  #include "pxamci.h"
> @@ -58,7 +59,6 @@ struct pxamci_host {
>         struct clk              *clk;
>         unsigned long           clkrate;
>         int                     irq;
> -       int                     dma;
>         unsigned int            clkrt;
>         unsigned int            cmdat;
>         unsigned int            imask;
> @@ -69,8 +69,10 @@ struct pxamci_host {
>         struct mmc_command      *cmd;
>         struct mmc_data         *data;
>
> +       struct dma_chan         *dma_chan_rx;
> +       struct dma_chan         *dma_chan_tx;
> +       dma_cookie_t            dma_cookie;
>         dma_addr_t              sg_dma;
> -       struct pxa_dma_desc     *sg_cpu;
>         unsigned int            dma_len;
>
>         unsigned int            dma_dir;
> @@ -173,14 +175,18 @@ static void pxamci_disable_irq(struct pxamci_host *host, unsigned int mask)
>         spin_unlock_irqrestore(&host->lock, flags);
>  }
>
> +static void pxamci_dma_irq(void *param);
> +
>  static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data)
>  {
> +       struct dma_async_tx_descriptor *tx;
> +       enum dma_data_direction direction;
> +       struct dma_slave_config config;
> +       struct dma_chan *chan;
>         unsigned int nob = data->blocks;
>         unsigned long long clks;
>         unsigned int timeout;
> -       bool dalgn = 0;
> -       u32 dcmd;
> -       int i;
> +       int ret;
>
>         host->data = data;
>
> @@ -195,54 +201,48 @@ static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data)
>         timeout = (unsigned int)clks + (data->timeout_clks << host->clkrt);
>         writel((timeout + 255) / 256, host->base + MMC_RDTO);
>
> +       memset(&config, 0, sizeof(config));
> +       config.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
> +       config.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
> +       config.src_addr = host->res->start + MMC_RXFIFO;
> +       config.dst_addr = host->res->start + MMC_TXFIFO;
> +       config.src_maxburst = 32;
> +       config.dst_maxburst = 32;
> +
>         if (data->flags & MMC_DATA_READ) {
>                 host->dma_dir = DMA_FROM_DEVICE;
> -               dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC;
> -               DRCMR(host->dma_drcmrtx) = 0;
> -               DRCMR(host->dma_drcmrrx) = host->dma | DRCMR_MAPVLD;
> +               direction = DMA_DEV_TO_MEM;
> +               chan = host->dma_chan_rx;
>         } else {
>                 host->dma_dir = DMA_TO_DEVICE;
> -               dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG;
> -               DRCMR(host->dma_drcmrrx) = 0;
> -               DRCMR(host->dma_drcmrtx) = host->dma | DRCMR_MAPVLD;
> +               direction = DMA_MEM_TO_DEV;
> +               chan = host->dma_chan_tx;
>         }
>
> -       dcmd |= DCMD_BURST32 | DCMD_WIDTH1;
> +       config.direction = direction;
> +
> +       ret = dmaengine_slave_config(chan, &config);
> +       if (ret < 0) {
> +               dev_err(mmc_dev(host->mmc), "dma slave config failed\n");
> +               return;
> +       }
>
> -       host->dma_len = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
> +       host->dma_len = dma_map_sg(chan->device->dev, data->sg, data->sg_len,
>                                    host->dma_dir);
>
> -       for (i = 0; i < host->dma_len; i++) {
> -               unsigned int length = sg_dma_len(&data->sg[i]);
> -               host->sg_cpu[i].dcmd = dcmd | length;
> -               if (length & 31 && !(data->flags & MMC_DATA_READ))
> -                       host->sg_cpu[i].dcmd |= DCMD_ENDIRQEN;
> -               /* Not aligned to 8-byte boundary? */
> -               if (sg_dma_address(&data->sg[i]) & 0x7)
> -                       dalgn = 1;
> -               if (data->flags & MMC_DATA_READ) {
> -                       host->sg_cpu[i].dsadr = host->res->start + MMC_RXFIFO;
> -                       host->sg_cpu[i].dtadr = sg_dma_address(&data->sg[i]);
> -               } else {
> -                       host->sg_cpu[i].dsadr = sg_dma_address(&data->sg[i]);
> -                       host->sg_cpu[i].dtadr = host->res->start + MMC_TXFIFO;
> -               }
> -               host->sg_cpu[i].ddadr = host->sg_dma + (i + 1) *
> -                                       sizeof(struct pxa_dma_desc);
> +       tx = dmaengine_prep_slave_sg(chan, data->sg, host->dma_len, direction,
> +                                    DMA_PREP_INTERRUPT);
> +       if (!tx) {
> +               dev_err(mmc_dev(host->mmc), "prep_slave_sg() failed\n");
> +               return;
>         }
> -       host->sg_cpu[host->dma_len - 1].ddadr = DDADR_STOP;
> -       wmb();
>
> -       /*
> -        * The PXA27x DMA controller encounters overhead when working with
> -        * unaligned (to 8-byte boundaries) data, so switch on byte alignment
> -        * mode only if we have unaligned data.
> -        */
> -       if (dalgn)
> -               DALGN |= (1 << host->dma);
> -       else
> -               DALGN &= ~(1 << host->dma);
> -       DDADR(host->dma) = host->sg_dma;
> +       if (!(data->flags & MMC_DATA_READ)) {
> +               tx->callback = pxamci_dma_irq;
> +               tx->callback_param = host;
> +       }
> +
> +       host->dma_cookie = dmaengine_submit(tx);
>
>         /*
>          * workaround for erratum #91:
> @@ -251,7 +251,7 @@ static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data)
>          * before starting DMA.
>          */
>         if (!cpu_is_pxa27x() || data->flags & MMC_DATA_READ)
> -               DCSR(host->dma) = DCSR_RUN;
> +               dma_async_issue_pending(chan);
>  }
>
>  static void pxamci_start_cmd(struct pxamci_host *host, struct mmc_command *cmd, unsigned int cmdat)
> @@ -343,7 +343,7 @@ static int pxamci_cmd_done(struct pxamci_host *host, unsigned int stat)
>                  * enable DMA late
>                  */
>                 if (cpu_is_pxa27x() && host->data->flags & MMC_DATA_WRITE)
> -                       DCSR(host->dma) = DCSR_RUN;
> +                       dma_async_issue_pending(host->dma_chan_tx);
>         } else {
>                 pxamci_finish_request(host, host->mrq);
>         }
> @@ -354,13 +354,17 @@ static int pxamci_cmd_done(struct pxamci_host *host, unsigned int stat)
>  static int pxamci_data_done(struct pxamci_host *host, unsigned int stat)
>  {
>         struct mmc_data *data = host->data;
> +       struct dma_chan *chan;
>
>         if (!data)
>                 return 0;
>
> -       DCSR(host->dma) = 0;
> -       dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
> -                    host->dma_dir);
> +       if (data->flags & MMC_DATA_READ)
> +               chan = host->dma_chan_rx;
> +       else
> +               chan = host->dma_chan_tx;
> +       dma_unmap_sg(chan->device->dev,
> +                    data->sg, data->sg_len, host->dma_dir);
>
>         if (stat & STAT_READ_TIME_OUT)
>                 data->error = -ETIMEDOUT;
> @@ -552,20 +556,37 @@ static const struct mmc_host_ops pxamci_ops = {
>         .enable_sdio_irq        = pxamci_enable_sdio_irq,
>  };
>
> -static void pxamci_dma_irq(int dma, void *devid)
> +static void pxamci_dma_irq(void *param)
>  {
> -       struct pxamci_host *host = devid;
> -       int dcsr = DCSR(dma);
> -       DCSR(dma) = dcsr & ~DCSR_STOPIRQEN;
> +       struct pxamci_host *host = param;
> +       struct dma_tx_state state;
> +       enum dma_status status;
> +       struct dma_chan *chan;
> +       unsigned long flags;
> +
> +       spin_lock_irqsave(&host->lock, flags);
> +
> +       if (!host->data)
> +               goto out_unlock;
>
> -       if (dcsr & DCSR_ENDINTR) {
> +       if (host->data->flags & MMC_DATA_READ)
> +               chan = host->dma_chan_rx;
> +       else
> +               chan = host->dma_chan_tx;
> +
> +       status = dmaengine_tx_status(chan, host->dma_cookie, &state);
> +
> +       if (likely(status == DMA_COMPLETE)) {
>                 writel(BUF_PART_FULL, host->base + MMC_PRTBUF);
>         } else {
> -               pr_err("%s: DMA error on channel %d (DCSR=%#x)\n",
> -                      mmc_hostname(host->mmc), dma, dcsr);
> +               pr_err("%s: DMA error on %s channel\n", mmc_hostname(host->mmc),
> +                       host->data->flags & MMC_DATA_READ ? "rx" : "tx");
>                 host->data->error = -EIO;
>                 pxamci_data_done(host, 0);
>         }
> +
> +out_unlock:
> +       spin_unlock_irqrestore(&host->lock, flags);
>  }
>
>  static irqreturn_t pxamci_detect_irq(int irq, void *devid)
> @@ -625,7 +646,9 @@ static int pxamci_probe(struct platform_device *pdev)
>         struct mmc_host *mmc;
>         struct pxamci_host *host = NULL;
>         struct resource *r, *dmarx, *dmatx;
> +       struct pxad_param param_rx, param_tx;
>         int ret, irq, gpio_cd = -1, gpio_ro = -1, gpio_power = -1;
> +       dma_cap_mask_t mask;
>
>         ret = pxamci_of_init(pdev);
>         if (ret)
> @@ -671,7 +694,6 @@ static int pxamci_probe(struct platform_device *pdev)
>
>         host = mmc_priv(mmc);
>         host->mmc = mmc;
> -       host->dma = -1;
>         host->pdata = pdev->dev.platform_data;
>         host->clkrt = CLKRT_OFF;
>
> @@ -702,12 +724,6 @@ static int pxamci_probe(struct platform_device *pdev)
>                                      MMC_CAP_SD_HIGHSPEED;
>         }
>
> -       host->sg_cpu = dma_alloc_coherent(&pdev->dev, PAGE_SIZE, &host->sg_dma, GFP_KERNEL);
> -       if (!host->sg_cpu) {
> -               ret = -ENOMEM;
> -               goto out;
> -       }
> -
>         spin_lock_init(&host->lock);
>         host->res = r;
>         host->irq = irq;
> @@ -728,32 +744,45 @@ static int pxamci_probe(struct platform_device *pdev)
>         writel(64, host->base + MMC_RESTO);
>         writel(host->imask, host->base + MMC_I_MASK);
>
> -       host->dma = pxa_request_dma(DRIVER_NAME, DMA_PRIO_LOW,
> -                                   pxamci_dma_irq, host);
> -       if (host->dma < 0) {
> -               ret = -EBUSY;
> -               goto out;
> -       }
> -
>         ret = request_irq(host->irq, pxamci_irq, 0, DRIVER_NAME, host);
>         if (ret)
>                 goto out;
>
>         platform_set_drvdata(pdev, mmc);
>
> -       dmarx = platform_get_resource(pdev, IORESOURCE_DMA, 0);
> -       if (!dmarx) {
> -               ret = -ENXIO;
> +       if (!pdev->dev.of_node) {
> +               dmarx = platform_get_resource(pdev, IORESOURCE_DMA, 0);
> +               dmatx = platform_get_resource(pdev, IORESOURCE_DMA, 1);
> +               if (!dmarx || !dmatx) {
> +                       ret = -ENXIO;
> +                       goto out;
> +               }
> +               param_rx.prio = PXAD_PRIO_LOWEST;
> +               param_rx.drcmr = dmarx->start;
> +               param_tx.prio = PXAD_PRIO_LOWEST;
> +               param_tx.drcmr = dmatx->start;
> +       }
> +
> +       dma_cap_zero(mask);
> +       dma_cap_set(DMA_SLAVE, mask);
> +
> +       host->dma_chan_rx =
> +               dma_request_slave_channel_compat(mask, pxad_filter_fn,
> +                                                &param_rx, &pdev->dev, "rx");
> +       if (host->dma_chan_rx == NULL) {
> +               dev_err(&pdev->dev, "unable to request rx dma channel\n");
> +               ret = -ENODEV;
>                 goto out;
>         }
> -       host->dma_drcmrrx = dmarx->start;
>
> -       dmatx = platform_get_resource(pdev, IORESOURCE_DMA, 1);
> -       if (!dmatx) {
> -               ret = -ENXIO;
> +       host->dma_chan_tx =
> +               dma_request_slave_channel_compat(mask, pxad_filter_fn,
> +                                                &param_tx,  &pdev->dev, "tx");
> +       if (host->dma_chan_tx == NULL) {
> +               dev_err(&pdev->dev, "unable to request tx dma channel\n");
> +               ret = -ENODEV;
>                 goto out;
>         }
> -       host->dma_drcmrtx = dmatx->start;
>
>         if (host->pdata) {
>                 gpio_cd = host->pdata->gpio_card_detect;
> @@ -814,12 +843,12 @@ err_gpio_ro:
>         gpio_free(gpio_power);
>   out:
>         if (host) {
> -               if (host->dma >= 0)
> -                       pxa_free_dma(host->dma);
> +               if (host->dma_chan_rx)
> +                       dma_release_channel(host->dma_chan_rx);
> +               if (host->dma_chan_tx)
> +                       dma_release_channel(host->dma_chan_tx);
>                 if (host->base)
>                         iounmap(host->base);
> -               if (host->sg_cpu)
> -                       dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
>                 if (host->clk)
>                         clk_put(host->clk);
>         }
> @@ -863,13 +892,12 @@ static int pxamci_remove(struct platform_device *pdev)
>                        END_CMD_RES|PRG_DONE|DATA_TRAN_DONE,
>                        host->base + MMC_I_MASK);
>
> -               DRCMR(host->dma_drcmrrx) = 0;
> -               DRCMR(host->dma_drcmrtx) = 0;
> -
>                 free_irq(host->irq, host);
> -               pxa_free_dma(host->dma);
> +               dmaengine_terminate_all(host->dma_chan_rx);
> +               dmaengine_terminate_all(host->dma_chan_tx);
> +               dma_release_channel(host->dma_chan_rx);
> +               dma_release_channel(host->dma_chan_tx);
>                 iounmap(host->base);
> -               dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
>
>                 clk_put(host->clk);
>
> --
> 2.1.4
>
--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Robert Jarzmik June 8, 2015, 5:14 p.m. UTC | #2
Ulf Hansson <ulf.hansson@linaro.org> writes:

> On 6 June 2015 at 23:15, Robert Jarzmik <robert.jarzmik@free.fr> wrote:
>> +#include <linux/dma/pxa-dma.h>
>
> I can't find this header file in my tree, but apparantly it's in
> linux-next. Probably it went through Vinod's dma tree, right?
Right.

> Anyway, I can pick it up for the next-next release cycle or you may
> ask Vinod to pick it up right now. Please tell me what you prefer.
> Here's my ack.
I'd rather have it through your tree, next-next is perfectly fine by me.

Thanks.

--
Robert
--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Ulf Hansson July 20, 2015, 11:19 a.m. UTC | #3
On 6 June 2015 at 23:15, Robert Jarzmik <robert.jarzmik@free.fr> wrote:
> From: Daniel Mack <zonque@gmail.com>
>
> Switch over pxamci to dmaengine. This prepares the devicetree full
> support of pxamci.
>
> This was successfully tested on a PXA3xx board, as well as PXA27x.
>
> Signed-off-by: Daniel Mack <zonque@gmail.com>
> [adapted to pxa-dma]
> Signed-off-by: Robert Jarzmik <robert.jarzmik@free.fr>

Thanks, applied!

Kind regards
Uffe

> ---
>  drivers/mmc/host/pxamci.c | 200 ++++++++++++++++++++++++++--------------------
>  1 file changed, 114 insertions(+), 86 deletions(-)
>
> diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c
> index 1b6d0bf..1420f29 100644
> --- a/drivers/mmc/host/pxamci.c
> +++ b/drivers/mmc/host/pxamci.c
> @@ -22,7 +22,9 @@
>  #include <linux/platform_device.h>
>  #include <linux/delay.h>
>  #include <linux/interrupt.h>
> +#include <linux/dmaengine.h>
>  #include <linux/dma-mapping.h>
> +#include <linux/dma/pxa-dma.h>
>  #include <linux/clk.h>
>  #include <linux/err.h>
>  #include <linux/mmc/host.h>
> @@ -37,7 +39,6 @@
>  #include <asm/sizes.h>
>
>  #include <mach/hardware.h>
> -#include <mach/dma.h>
>  #include <linux/platform_data/mmc-pxamci.h>
>
>  #include "pxamci.h"
> @@ -58,7 +59,6 @@ struct pxamci_host {
>         struct clk              *clk;
>         unsigned long           clkrate;
>         int                     irq;
> -       int                     dma;
>         unsigned int            clkrt;
>         unsigned int            cmdat;
>         unsigned int            imask;
> @@ -69,8 +69,10 @@ struct pxamci_host {
>         struct mmc_command      *cmd;
>         struct mmc_data         *data;
>
> +       struct dma_chan         *dma_chan_rx;
> +       struct dma_chan         *dma_chan_tx;
> +       dma_cookie_t            dma_cookie;
>         dma_addr_t              sg_dma;
> -       struct pxa_dma_desc     *sg_cpu;
>         unsigned int            dma_len;
>
>         unsigned int            dma_dir;
> @@ -173,14 +175,18 @@ static void pxamci_disable_irq(struct pxamci_host *host, unsigned int mask)
>         spin_unlock_irqrestore(&host->lock, flags);
>  }
>
> +static void pxamci_dma_irq(void *param);
> +
>  static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data)
>  {
> +       struct dma_async_tx_descriptor *tx;
> +       enum dma_data_direction direction;
> +       struct dma_slave_config config;
> +       struct dma_chan *chan;
>         unsigned int nob = data->blocks;
>         unsigned long long clks;
>         unsigned int timeout;
> -       bool dalgn = 0;
> -       u32 dcmd;
> -       int i;
> +       int ret;
>
>         host->data = data;
>
> @@ -195,54 +201,48 @@ static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data)
>         timeout = (unsigned int)clks + (data->timeout_clks << host->clkrt);
>         writel((timeout + 255) / 256, host->base + MMC_RDTO);
>
> +       memset(&config, 0, sizeof(config));
> +       config.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
> +       config.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
> +       config.src_addr = host->res->start + MMC_RXFIFO;
> +       config.dst_addr = host->res->start + MMC_TXFIFO;
> +       config.src_maxburst = 32;
> +       config.dst_maxburst = 32;
> +
>         if (data->flags & MMC_DATA_READ) {
>                 host->dma_dir = DMA_FROM_DEVICE;
> -               dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC;
> -               DRCMR(host->dma_drcmrtx) = 0;
> -               DRCMR(host->dma_drcmrrx) = host->dma | DRCMR_MAPVLD;
> +               direction = DMA_DEV_TO_MEM;
> +               chan = host->dma_chan_rx;
>         } else {
>                 host->dma_dir = DMA_TO_DEVICE;
> -               dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG;
> -               DRCMR(host->dma_drcmrrx) = 0;
> -               DRCMR(host->dma_drcmrtx) = host->dma | DRCMR_MAPVLD;
> +               direction = DMA_MEM_TO_DEV;
> +               chan = host->dma_chan_tx;
>         }
>
> -       dcmd |= DCMD_BURST32 | DCMD_WIDTH1;
> +       config.direction = direction;
> +
> +       ret = dmaengine_slave_config(chan, &config);
> +       if (ret < 0) {
> +               dev_err(mmc_dev(host->mmc), "dma slave config failed\n");
> +               return;
> +       }
>
> -       host->dma_len = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
> +       host->dma_len = dma_map_sg(chan->device->dev, data->sg, data->sg_len,
>                                    host->dma_dir);
>
> -       for (i = 0; i < host->dma_len; i++) {
> -               unsigned int length = sg_dma_len(&data->sg[i]);
> -               host->sg_cpu[i].dcmd = dcmd | length;
> -               if (length & 31 && !(data->flags & MMC_DATA_READ))
> -                       host->sg_cpu[i].dcmd |= DCMD_ENDIRQEN;
> -               /* Not aligned to 8-byte boundary? */
> -               if (sg_dma_address(&data->sg[i]) & 0x7)
> -                       dalgn = 1;
> -               if (data->flags & MMC_DATA_READ) {
> -                       host->sg_cpu[i].dsadr = host->res->start + MMC_RXFIFO;
> -                       host->sg_cpu[i].dtadr = sg_dma_address(&data->sg[i]);
> -               } else {
> -                       host->sg_cpu[i].dsadr = sg_dma_address(&data->sg[i]);
> -                       host->sg_cpu[i].dtadr = host->res->start + MMC_TXFIFO;
> -               }
> -               host->sg_cpu[i].ddadr = host->sg_dma + (i + 1) *
> -                                       sizeof(struct pxa_dma_desc);
> +       tx = dmaengine_prep_slave_sg(chan, data->sg, host->dma_len, direction,
> +                                    DMA_PREP_INTERRUPT);
> +       if (!tx) {
> +               dev_err(mmc_dev(host->mmc), "prep_slave_sg() failed\n");
> +               return;
>         }
> -       host->sg_cpu[host->dma_len - 1].ddadr = DDADR_STOP;
> -       wmb();
>
> -       /*
> -        * The PXA27x DMA controller encounters overhead when working with
> -        * unaligned (to 8-byte boundaries) data, so switch on byte alignment
> -        * mode only if we have unaligned data.
> -        */
> -       if (dalgn)
> -               DALGN |= (1 << host->dma);
> -       else
> -               DALGN &= ~(1 << host->dma);
> -       DDADR(host->dma) = host->sg_dma;
> +       if (!(data->flags & MMC_DATA_READ)) {
> +               tx->callback = pxamci_dma_irq;
> +               tx->callback_param = host;
> +       }
> +
> +       host->dma_cookie = dmaengine_submit(tx);
>
>         /*
>          * workaround for erratum #91:
> @@ -251,7 +251,7 @@ static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data)
>          * before starting DMA.
>          */
>         if (!cpu_is_pxa27x() || data->flags & MMC_DATA_READ)
> -               DCSR(host->dma) = DCSR_RUN;
> +               dma_async_issue_pending(chan);
>  }
>
>  static void pxamci_start_cmd(struct pxamci_host *host, struct mmc_command *cmd, unsigned int cmdat)
> @@ -343,7 +343,7 @@ static int pxamci_cmd_done(struct pxamci_host *host, unsigned int stat)
>                  * enable DMA late
>                  */
>                 if (cpu_is_pxa27x() && host->data->flags & MMC_DATA_WRITE)
> -                       DCSR(host->dma) = DCSR_RUN;
> +                       dma_async_issue_pending(host->dma_chan_tx);
>         } else {
>                 pxamci_finish_request(host, host->mrq);
>         }
> @@ -354,13 +354,17 @@ static int pxamci_cmd_done(struct pxamci_host *host, unsigned int stat)
>  static int pxamci_data_done(struct pxamci_host *host, unsigned int stat)
>  {
>         struct mmc_data *data = host->data;
> +       struct dma_chan *chan;
>
>         if (!data)
>                 return 0;
>
> -       DCSR(host->dma) = 0;
> -       dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
> -                    host->dma_dir);
> +       if (data->flags & MMC_DATA_READ)
> +               chan = host->dma_chan_rx;
> +       else
> +               chan = host->dma_chan_tx;
> +       dma_unmap_sg(chan->device->dev,
> +                    data->sg, data->sg_len, host->dma_dir);
>
>         if (stat & STAT_READ_TIME_OUT)
>                 data->error = -ETIMEDOUT;
> @@ -552,20 +556,37 @@ static const struct mmc_host_ops pxamci_ops = {
>         .enable_sdio_irq        = pxamci_enable_sdio_irq,
>  };
>
> -static void pxamci_dma_irq(int dma, void *devid)
> +static void pxamci_dma_irq(void *param)
>  {
> -       struct pxamci_host *host = devid;
> -       int dcsr = DCSR(dma);
> -       DCSR(dma) = dcsr & ~DCSR_STOPIRQEN;
> +       struct pxamci_host *host = param;
> +       struct dma_tx_state state;
> +       enum dma_status status;
> +       struct dma_chan *chan;
> +       unsigned long flags;
> +
> +       spin_lock_irqsave(&host->lock, flags);
> +
> +       if (!host->data)
> +               goto out_unlock;
>
> -       if (dcsr & DCSR_ENDINTR) {
> +       if (host->data->flags & MMC_DATA_READ)
> +               chan = host->dma_chan_rx;
> +       else
> +               chan = host->dma_chan_tx;
> +
> +       status = dmaengine_tx_status(chan, host->dma_cookie, &state);
> +
> +       if (likely(status == DMA_COMPLETE)) {
>                 writel(BUF_PART_FULL, host->base + MMC_PRTBUF);
>         } else {
> -               pr_err("%s: DMA error on channel %d (DCSR=%#x)\n",
> -                      mmc_hostname(host->mmc), dma, dcsr);
> +               pr_err("%s: DMA error on %s channel\n", mmc_hostname(host->mmc),
> +                       host->data->flags & MMC_DATA_READ ? "rx" : "tx");
>                 host->data->error = -EIO;
>                 pxamci_data_done(host, 0);
>         }
> +
> +out_unlock:
> +       spin_unlock_irqrestore(&host->lock, flags);
>  }
>
>  static irqreturn_t pxamci_detect_irq(int irq, void *devid)
> @@ -625,7 +646,9 @@ static int pxamci_probe(struct platform_device *pdev)
>         struct mmc_host *mmc;
>         struct pxamci_host *host = NULL;
>         struct resource *r, *dmarx, *dmatx;
> +       struct pxad_param param_rx, param_tx;
>         int ret, irq, gpio_cd = -1, gpio_ro = -1, gpio_power = -1;
> +       dma_cap_mask_t mask;
>
>         ret = pxamci_of_init(pdev);
>         if (ret)
> @@ -671,7 +694,6 @@ static int pxamci_probe(struct platform_device *pdev)
>
>         host = mmc_priv(mmc);
>         host->mmc = mmc;
> -       host->dma = -1;
>         host->pdata = pdev->dev.platform_data;
>         host->clkrt = CLKRT_OFF;
>
> @@ -702,12 +724,6 @@ static int pxamci_probe(struct platform_device *pdev)
>                                      MMC_CAP_SD_HIGHSPEED;
>         }
>
> -       host->sg_cpu = dma_alloc_coherent(&pdev->dev, PAGE_SIZE, &host->sg_dma, GFP_KERNEL);
> -       if (!host->sg_cpu) {
> -               ret = -ENOMEM;
> -               goto out;
> -       }
> -
>         spin_lock_init(&host->lock);
>         host->res = r;
>         host->irq = irq;
> @@ -728,32 +744,45 @@ static int pxamci_probe(struct platform_device *pdev)
>         writel(64, host->base + MMC_RESTO);
>         writel(host->imask, host->base + MMC_I_MASK);
>
> -       host->dma = pxa_request_dma(DRIVER_NAME, DMA_PRIO_LOW,
> -                                   pxamci_dma_irq, host);
> -       if (host->dma < 0) {
> -               ret = -EBUSY;
> -               goto out;
> -       }
> -
>         ret = request_irq(host->irq, pxamci_irq, 0, DRIVER_NAME, host);
>         if (ret)
>                 goto out;
>
>         platform_set_drvdata(pdev, mmc);
>
> -       dmarx = platform_get_resource(pdev, IORESOURCE_DMA, 0);
> -       if (!dmarx) {
> -               ret = -ENXIO;
> +       if (!pdev->dev.of_node) {
> +               dmarx = platform_get_resource(pdev, IORESOURCE_DMA, 0);
> +               dmatx = platform_get_resource(pdev, IORESOURCE_DMA, 1);
> +               if (!dmarx || !dmatx) {
> +                       ret = -ENXIO;
> +                       goto out;
> +               }
> +               param_rx.prio = PXAD_PRIO_LOWEST;
> +               param_rx.drcmr = dmarx->start;
> +               param_tx.prio = PXAD_PRIO_LOWEST;
> +               param_tx.drcmr = dmatx->start;
> +       }
> +
> +       dma_cap_zero(mask);
> +       dma_cap_set(DMA_SLAVE, mask);
> +
> +       host->dma_chan_rx =
> +               dma_request_slave_channel_compat(mask, pxad_filter_fn,
> +                                                &param_rx, &pdev->dev, "rx");
> +       if (host->dma_chan_rx == NULL) {
> +               dev_err(&pdev->dev, "unable to request rx dma channel\n");
> +               ret = -ENODEV;
>                 goto out;
>         }
> -       host->dma_drcmrrx = dmarx->start;
>
> -       dmatx = platform_get_resource(pdev, IORESOURCE_DMA, 1);
> -       if (!dmatx) {
> -               ret = -ENXIO;
> +       host->dma_chan_tx =
> +               dma_request_slave_channel_compat(mask, pxad_filter_fn,
> +                                                &param_tx,  &pdev->dev, "tx");
> +       if (host->dma_chan_tx == NULL) {
> +               dev_err(&pdev->dev, "unable to request tx dma channel\n");
> +               ret = -ENODEV;
>                 goto out;
>         }
> -       host->dma_drcmrtx = dmatx->start;
>
>         if (host->pdata) {
>                 gpio_cd = host->pdata->gpio_card_detect;
> @@ -814,12 +843,12 @@ err_gpio_ro:
>         gpio_free(gpio_power);
>   out:
>         if (host) {
> -               if (host->dma >= 0)
> -                       pxa_free_dma(host->dma);
> +               if (host->dma_chan_rx)
> +                       dma_release_channel(host->dma_chan_rx);
> +               if (host->dma_chan_tx)
> +                       dma_release_channel(host->dma_chan_tx);
>                 if (host->base)
>                         iounmap(host->base);
> -               if (host->sg_cpu)
> -                       dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
>                 if (host->clk)
>                         clk_put(host->clk);
>         }
> @@ -863,13 +892,12 @@ static int pxamci_remove(struct platform_device *pdev)
>                        END_CMD_RES|PRG_DONE|DATA_TRAN_DONE,
>                        host->base + MMC_I_MASK);
>
> -               DRCMR(host->dma_drcmrrx) = 0;
> -               DRCMR(host->dma_drcmrtx) = 0;
> -
>                 free_irq(host->irq, host);
> -               pxa_free_dma(host->dma);
> +               dmaengine_terminate_all(host->dma_chan_rx);
> +               dmaengine_terminate_all(host->dma_chan_tx);
> +               dma_release_channel(host->dma_chan_rx);
> +               dma_release_channel(host->dma_chan_tx);
>                 iounmap(host->base);
> -               dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
>
>                 clk_put(host->clk);
>
> --
> 2.1.4
>
--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Robert Jarzmik July 20, 2015, 7:22 p.m. UTC | #4
Ulf Hansson <ulf.hansson@linaro.org> writes:

> On 6 June 2015 at 23:15, Robert Jarzmik <robert.jarzmik@free.fr> wrote:
>> From: Daniel Mack <zonque@gmail.com>
>>
>> Switch over pxamci to dmaengine. This prepares the devicetree full
>> support of pxamci.
>>
>> This was successfully tested on a PXA3xx board, as well as PXA27x.
>>
>> Signed-off-by: Daniel Mack <zonque@gmail.com>
>> [adapted to pxa-dma]
>> Signed-off-by: Robert Jarzmik <robert.jarzmik@free.fr>
>
> Thanks, applied!
Great, thanks Ulf.

Cheers.

--
Robert
--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c
index 1b6d0bf..1420f29 100644
--- a/drivers/mmc/host/pxamci.c
+++ b/drivers/mmc/host/pxamci.c
@@ -22,7 +22,9 @@ 
 #include <linux/platform_device.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
+#include <linux/dmaengine.h>
 #include <linux/dma-mapping.h>
+#include <linux/dma/pxa-dma.h>
 #include <linux/clk.h>
 #include <linux/err.h>
 #include <linux/mmc/host.h>
@@ -37,7 +39,6 @@ 
 #include <asm/sizes.h>
 
 #include <mach/hardware.h>
-#include <mach/dma.h>
 #include <linux/platform_data/mmc-pxamci.h>
 
 #include "pxamci.h"
@@ -58,7 +59,6 @@  struct pxamci_host {
 	struct clk		*clk;
 	unsigned long		clkrate;
 	int			irq;
-	int			dma;
 	unsigned int		clkrt;
 	unsigned int		cmdat;
 	unsigned int		imask;
@@ -69,8 +69,10 @@  struct pxamci_host {
 	struct mmc_command	*cmd;
 	struct mmc_data		*data;
 
+	struct dma_chan		*dma_chan_rx;
+	struct dma_chan		*dma_chan_tx;
+	dma_cookie_t		dma_cookie;
 	dma_addr_t		sg_dma;
-	struct pxa_dma_desc	*sg_cpu;
 	unsigned int		dma_len;
 
 	unsigned int		dma_dir;
@@ -173,14 +175,18 @@  static void pxamci_disable_irq(struct pxamci_host *host, unsigned int mask)
 	spin_unlock_irqrestore(&host->lock, flags);
 }
 
+static void pxamci_dma_irq(void *param);
+
 static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data)
 {
+	struct dma_async_tx_descriptor *tx;
+	enum dma_data_direction direction;
+	struct dma_slave_config	config;
+	struct dma_chan *chan;
 	unsigned int nob = data->blocks;
 	unsigned long long clks;
 	unsigned int timeout;
-	bool dalgn = 0;
-	u32 dcmd;
-	int i;
+	int ret;
 
 	host->data = data;
 
@@ -195,54 +201,48 @@  static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data)
 	timeout = (unsigned int)clks + (data->timeout_clks << host->clkrt);
 	writel((timeout + 255) / 256, host->base + MMC_RDTO);
 
+	memset(&config, 0, sizeof(config));
+	config.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+	config.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+	config.src_addr = host->res->start + MMC_RXFIFO;
+	config.dst_addr = host->res->start + MMC_TXFIFO;
+	config.src_maxburst = 32;
+	config.dst_maxburst = 32;
+
 	if (data->flags & MMC_DATA_READ) {
 		host->dma_dir = DMA_FROM_DEVICE;
-		dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC;
-		DRCMR(host->dma_drcmrtx) = 0;
-		DRCMR(host->dma_drcmrrx) = host->dma | DRCMR_MAPVLD;
+		direction = DMA_DEV_TO_MEM;
+		chan = host->dma_chan_rx;
 	} else {
 		host->dma_dir = DMA_TO_DEVICE;
-		dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG;
-		DRCMR(host->dma_drcmrrx) = 0;
-		DRCMR(host->dma_drcmrtx) = host->dma | DRCMR_MAPVLD;
+		direction = DMA_MEM_TO_DEV;
+		chan = host->dma_chan_tx;
 	}
 
-	dcmd |= DCMD_BURST32 | DCMD_WIDTH1;
+	config.direction = direction;
+
+	ret = dmaengine_slave_config(chan, &config);
+	if (ret < 0) {
+		dev_err(mmc_dev(host->mmc), "dma slave config failed\n");
+		return;
+	}
 
-	host->dma_len = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
+	host->dma_len = dma_map_sg(chan->device->dev, data->sg, data->sg_len,
 				   host->dma_dir);
 
-	for (i = 0; i < host->dma_len; i++) {
-		unsigned int length = sg_dma_len(&data->sg[i]);
-		host->sg_cpu[i].dcmd = dcmd | length;
-		if (length & 31 && !(data->flags & MMC_DATA_READ))
-			host->sg_cpu[i].dcmd |= DCMD_ENDIRQEN;
-		/* Not aligned to 8-byte boundary? */
-		if (sg_dma_address(&data->sg[i]) & 0x7)
-			dalgn = 1;
-		if (data->flags & MMC_DATA_READ) {
-			host->sg_cpu[i].dsadr = host->res->start + MMC_RXFIFO;
-			host->sg_cpu[i].dtadr = sg_dma_address(&data->sg[i]);
-		} else {
-			host->sg_cpu[i].dsadr = sg_dma_address(&data->sg[i]);
-			host->sg_cpu[i].dtadr = host->res->start + MMC_TXFIFO;
-		}
-		host->sg_cpu[i].ddadr = host->sg_dma + (i + 1) *
-					sizeof(struct pxa_dma_desc);
+	tx = dmaengine_prep_slave_sg(chan, data->sg, host->dma_len, direction,
+				     DMA_PREP_INTERRUPT);
+	if (!tx) {
+		dev_err(mmc_dev(host->mmc), "prep_slave_sg() failed\n");
+		return;
 	}
-	host->sg_cpu[host->dma_len - 1].ddadr = DDADR_STOP;
-	wmb();
 
-	/*
-	 * The PXA27x DMA controller encounters overhead when working with
-	 * unaligned (to 8-byte boundaries) data, so switch on byte alignment
-	 * mode only if we have unaligned data.
-	 */
-	if (dalgn)
-		DALGN |= (1 << host->dma);
-	else
-		DALGN &= ~(1 << host->dma);
-	DDADR(host->dma) = host->sg_dma;
+	if (!(data->flags & MMC_DATA_READ)) {
+		tx->callback = pxamci_dma_irq;
+		tx->callback_param = host;
+	}
+
+	host->dma_cookie = dmaengine_submit(tx);
 
 	/*
 	 * workaround for erratum #91:
@@ -251,7 +251,7 @@  static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data)
 	 * before starting DMA.
 	 */
 	if (!cpu_is_pxa27x() || data->flags & MMC_DATA_READ)
-		DCSR(host->dma) = DCSR_RUN;
+		dma_async_issue_pending(chan);
 }
 
 static void pxamci_start_cmd(struct pxamci_host *host, struct mmc_command *cmd, unsigned int cmdat)
@@ -343,7 +343,7 @@  static int pxamci_cmd_done(struct pxamci_host *host, unsigned int stat)
 		 * enable DMA late
 		 */
 		if (cpu_is_pxa27x() && host->data->flags & MMC_DATA_WRITE)
-			DCSR(host->dma) = DCSR_RUN;
+			dma_async_issue_pending(host->dma_chan_tx);
 	} else {
 		pxamci_finish_request(host, host->mrq);
 	}
@@ -354,13 +354,17 @@  static int pxamci_cmd_done(struct pxamci_host *host, unsigned int stat)
 static int pxamci_data_done(struct pxamci_host *host, unsigned int stat)
 {
 	struct mmc_data *data = host->data;
+	struct dma_chan *chan;
 
 	if (!data)
 		return 0;
 
-	DCSR(host->dma) = 0;
-	dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
-		     host->dma_dir);
+	if (data->flags & MMC_DATA_READ)
+		chan = host->dma_chan_rx;
+	else
+		chan = host->dma_chan_tx;
+	dma_unmap_sg(chan->device->dev,
+		     data->sg, data->sg_len, host->dma_dir);
 
 	if (stat & STAT_READ_TIME_OUT)
 		data->error = -ETIMEDOUT;
@@ -552,20 +556,37 @@  static const struct mmc_host_ops pxamci_ops = {
 	.enable_sdio_irq	= pxamci_enable_sdio_irq,
 };
 
-static void pxamci_dma_irq(int dma, void *devid)
+static void pxamci_dma_irq(void *param)
 {
-	struct pxamci_host *host = devid;
-	int dcsr = DCSR(dma);
-	DCSR(dma) = dcsr & ~DCSR_STOPIRQEN;
+	struct pxamci_host *host = param;
+	struct dma_tx_state state;
+	enum dma_status status;
+	struct dma_chan *chan;
+	unsigned long flags;
+
+	spin_lock_irqsave(&host->lock, flags);
+
+	if (!host->data)
+		goto out_unlock;
 
-	if (dcsr & DCSR_ENDINTR) {
+	if (host->data->flags & MMC_DATA_READ)
+		chan = host->dma_chan_rx;
+	else
+		chan = host->dma_chan_tx;
+
+	status = dmaengine_tx_status(chan, host->dma_cookie, &state);
+
+	if (likely(status == DMA_COMPLETE)) {
 		writel(BUF_PART_FULL, host->base + MMC_PRTBUF);
 	} else {
-		pr_err("%s: DMA error on channel %d (DCSR=%#x)\n",
-		       mmc_hostname(host->mmc), dma, dcsr);
+		pr_err("%s: DMA error on %s channel\n", mmc_hostname(host->mmc),
+			host->data->flags & MMC_DATA_READ ? "rx" : "tx");
 		host->data->error = -EIO;
 		pxamci_data_done(host, 0);
 	}
+
+out_unlock:
+	spin_unlock_irqrestore(&host->lock, flags);
 }
 
 static irqreturn_t pxamci_detect_irq(int irq, void *devid)
@@ -625,7 +646,9 @@  static int pxamci_probe(struct platform_device *pdev)
 	struct mmc_host *mmc;
 	struct pxamci_host *host = NULL;
 	struct resource *r, *dmarx, *dmatx;
+	struct pxad_param param_rx, param_tx;
 	int ret, irq, gpio_cd = -1, gpio_ro = -1, gpio_power = -1;
+	dma_cap_mask_t mask;
 
 	ret = pxamci_of_init(pdev);
 	if (ret)
@@ -671,7 +694,6 @@  static int pxamci_probe(struct platform_device *pdev)
 
 	host = mmc_priv(mmc);
 	host->mmc = mmc;
-	host->dma = -1;
 	host->pdata = pdev->dev.platform_data;
 	host->clkrt = CLKRT_OFF;
 
@@ -702,12 +724,6 @@  static int pxamci_probe(struct platform_device *pdev)
 				     MMC_CAP_SD_HIGHSPEED;
 	}
 
-	host->sg_cpu = dma_alloc_coherent(&pdev->dev, PAGE_SIZE, &host->sg_dma, GFP_KERNEL);
-	if (!host->sg_cpu) {
-		ret = -ENOMEM;
-		goto out;
-	}
-
 	spin_lock_init(&host->lock);
 	host->res = r;
 	host->irq = irq;
@@ -728,32 +744,45 @@  static int pxamci_probe(struct platform_device *pdev)
 	writel(64, host->base + MMC_RESTO);
 	writel(host->imask, host->base + MMC_I_MASK);
 
-	host->dma = pxa_request_dma(DRIVER_NAME, DMA_PRIO_LOW,
-				    pxamci_dma_irq, host);
-	if (host->dma < 0) {
-		ret = -EBUSY;
-		goto out;
-	}
-
 	ret = request_irq(host->irq, pxamci_irq, 0, DRIVER_NAME, host);
 	if (ret)
 		goto out;
 
 	platform_set_drvdata(pdev, mmc);
 
-	dmarx = platform_get_resource(pdev, IORESOURCE_DMA, 0);
-	if (!dmarx) {
-		ret = -ENXIO;
+	if (!pdev->dev.of_node) {
+		dmarx = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+		dmatx = platform_get_resource(pdev, IORESOURCE_DMA, 1);
+		if (!dmarx || !dmatx) {
+			ret = -ENXIO;
+			goto out;
+		}
+		param_rx.prio = PXAD_PRIO_LOWEST;
+		param_rx.drcmr = dmarx->start;
+		param_tx.prio = PXAD_PRIO_LOWEST;
+		param_tx.drcmr = dmatx->start;
+	}
+
+	dma_cap_zero(mask);
+	dma_cap_set(DMA_SLAVE, mask);
+
+	host->dma_chan_rx =
+		dma_request_slave_channel_compat(mask, pxad_filter_fn,
+						 &param_rx, &pdev->dev, "rx");
+	if (host->dma_chan_rx == NULL) {
+		dev_err(&pdev->dev, "unable to request rx dma channel\n");
+		ret = -ENODEV;
 		goto out;
 	}
-	host->dma_drcmrrx = dmarx->start;
 
-	dmatx = platform_get_resource(pdev, IORESOURCE_DMA, 1);
-	if (!dmatx) {
-		ret = -ENXIO;
+	host->dma_chan_tx =
+		dma_request_slave_channel_compat(mask, pxad_filter_fn,
+						 &param_tx,  &pdev->dev, "tx");
+	if (host->dma_chan_tx == NULL) {
+		dev_err(&pdev->dev, "unable to request tx dma channel\n");
+		ret = -ENODEV;
 		goto out;
 	}
-	host->dma_drcmrtx = dmatx->start;
 
 	if (host->pdata) {
 		gpio_cd = host->pdata->gpio_card_detect;
@@ -814,12 +843,12 @@  err_gpio_ro:
 	gpio_free(gpio_power);
  out:
 	if (host) {
-		if (host->dma >= 0)
-			pxa_free_dma(host->dma);
+		if (host->dma_chan_rx)
+			dma_release_channel(host->dma_chan_rx);
+		if (host->dma_chan_tx)
+			dma_release_channel(host->dma_chan_tx);
 		if (host->base)
 			iounmap(host->base);
-		if (host->sg_cpu)
-			dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
 		if (host->clk)
 			clk_put(host->clk);
 	}
@@ -863,13 +892,12 @@  static int pxamci_remove(struct platform_device *pdev)
 		       END_CMD_RES|PRG_DONE|DATA_TRAN_DONE,
 		       host->base + MMC_I_MASK);
 
-		DRCMR(host->dma_drcmrrx) = 0;
-		DRCMR(host->dma_drcmrtx) = 0;
-
 		free_irq(host->irq, host);
-		pxa_free_dma(host->dma);
+		dmaengine_terminate_all(host->dma_chan_rx);
+		dmaengine_terminate_all(host->dma_chan_tx);
+		dma_release_channel(host->dma_chan_rx);
+		dma_release_channel(host->dma_chan_tx);
 		iounmap(host->base);
-		dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
 
 		clk_put(host->clk);