These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / drivers / mmc / host / pxamci.c
index 1b6d0bf..28a057f 100644 (file)
 #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>
+#include <linux/mmc/slot-gpio.h>
 #include <linux/io.h>
 #include <linux/regulator/consumer.h>
 #include <linux/gpio.h>
@@ -37,7 +40,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 +60,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 +70,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 +176,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 +202,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;
 
-       host->dma_len = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
+       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(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 +252,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 +344,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 +355,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;
@@ -450,12 +455,8 @@ static int pxamci_get_ro(struct mmc_host *mmc)
 {
        struct pxamci_host *host = mmc_priv(mmc);
 
-       if (host->pdata && gpio_is_valid(host->pdata->gpio_card_ro)) {
-               if (host->pdata->gpio_card_ro_invert)
-                       return !gpio_get_value(host->pdata->gpio_card_ro);
-               else
-                       return gpio_get_value(host->pdata->gpio_card_ro);
-       }
+       if (host->pdata && gpio_is_valid(host->pdata->gpio_card_ro))
+               return mmc_gpio_get_ro(mmc);
        if (host->pdata && host->pdata->get_ro)
                return !!host->pdata->get_ro(mmc_dev(mmc));
        /*
@@ -547,25 +548,43 @@ static void pxamci_enable_sdio_irq(struct mmc_host *host, int enable)
 
 static const struct mmc_host_ops pxamci_ops = {
        .request                = pxamci_request,
+       .get_cd                 = mmc_gpio_get_cd,
        .get_ro                 = pxamci_get_ro,
        .set_ios                = pxamci_set_ios,
        .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 (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 (dcsr & DCSR_ENDINTR) {
+       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 +644,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 +692,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 +722,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 +742,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;
@@ -761,37 +788,31 @@ static int pxamci_probe(struct platform_device *pdev)
                gpio_power = host->pdata->gpio_power;
        }
        if (gpio_is_valid(gpio_power)) {
-               ret = gpio_request(gpio_power, "mmc card power");
+               ret = devm_gpio_request(&pdev->dev, gpio_power,
+                                       "mmc card power");
                if (ret) {
-                       dev_err(&pdev->dev, "Failed requesting gpio_power %d\n", gpio_power);
+                       dev_err(&pdev->dev, "Failed requesting gpio_power %d\n",
+                               gpio_power);
                        goto out;
                }
                gpio_direction_output(gpio_power,
                                      host->pdata->gpio_power_invert);
        }
-       if (gpio_is_valid(gpio_ro)) {
-               ret = gpio_request(gpio_ro, "mmc card read only");
-               if (ret) {
-                       dev_err(&pdev->dev, "Failed requesting gpio_ro %d\n", gpio_ro);
-                       goto err_gpio_ro;
-               }
-               gpio_direction_input(gpio_ro);
+       if (gpio_is_valid(gpio_ro))
+               ret = mmc_gpio_request_ro(mmc, gpio_ro);
+       if (ret) {
+               dev_err(&pdev->dev, "Failed requesting gpio_ro %d\n", gpio_ro);
+               goto out;
+       } else {
+               mmc->caps2 |= host->pdata->gpio_card_ro_invert ?
+                       0 : MMC_CAP2_RO_ACTIVE_HIGH;
        }
-       if (gpio_is_valid(gpio_cd)) {
-               ret = gpio_request(gpio_cd, "mmc card detect");
-               if (ret) {
-                       dev_err(&pdev->dev, "Failed requesting gpio_cd %d\n", gpio_cd);
-                       goto err_gpio_cd;
-               }
-               gpio_direction_input(gpio_cd);
 
-               ret = request_irq(gpio_to_irq(gpio_cd), pxamci_detect_irq,
-                                 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
-                                 "mmc card detect", mmc);
-               if (ret) {
-                       dev_err(&pdev->dev, "failed to request card detect IRQ\n");
-                       goto err_request_irq;
-               }
+       if (gpio_is_valid(gpio_cd))
+               ret = mmc_gpio_request_cd(mmc, gpio_cd, 0);
+       if (ret) {
+               dev_err(&pdev->dev, "Failed requesting gpio_cd %d\n", gpio_cd);
+               goto out;
        }
 
        if (host->pdata && host->pdata->init)
@@ -806,20 +827,14 @@ static int pxamci_probe(struct platform_device *pdev)
 
        return 0;
 
-err_request_irq:
-       gpio_free(gpio_cd);
-err_gpio_cd:
-       gpio_free(gpio_ro);
-err_gpio_ro:
-       gpio_free(gpio_power);
- out:
+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);
        }
@@ -844,14 +859,6 @@ static int pxamci_remove(struct platform_device *pdev)
                        gpio_ro = host->pdata->gpio_card_ro;
                        gpio_power = host->pdata->gpio_power;
                }
-               if (gpio_is_valid(gpio_cd)) {
-                       free_irq(gpio_to_irq(gpio_cd), mmc);
-                       gpio_free(gpio_cd);
-               }
-               if (gpio_is_valid(gpio_ro))
-                       gpio_free(gpio_ro);
-               if (gpio_is_valid(gpio_power))
-                       gpio_free(gpio_power);
                if (host->vcc)
                        regulator_put(host->vcc);
 
@@ -863,13 +870,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);