UPSTREAM: mmc: dw_mmc: change the DW_MCI_FREQ_MIN from 400K to 100K
[firefly-linux-kernel-4.4.55.git] / drivers / mmc / host / tmio_mmc_dma.c
index 491e9ecc92c2501c9adcd4cc545eed85942e6754..e4b05dbb9ca822f003f566d07a60c508721bc68c 100644 (file)
@@ -28,10 +28,8 @@ void tmio_mmc_enable_dma(struct tmio_mmc_host *host, bool enable)
        if (!host->chan_tx || !host->chan_rx)
                return;
 
-#if defined(CONFIG_SUPERH) || defined(CONFIG_ARCH_SHMOBILE)
-       /* Switch DMA mode on or off - SuperH specific? */
-       sd_ctrl_write16(host, CTL_DMA_ENABLE, enable ? 2 : 0);
-#endif
+       if (host->dma->enable)
+               host->dma->enable(host, enable);
 }
 
 void tmio_mmc_abort_dma(struct tmio_mmc_host *host)
@@ -51,11 +49,10 @@ static void tmio_mmc_start_dma_rx(struct tmio_mmc_host *host)
        struct scatterlist *sg = host->sg_ptr, *sg_tmp;
        struct dma_async_tx_descriptor *desc = NULL;
        struct dma_chan *chan = host->chan_rx;
-       struct tmio_mmc_data *pdata = host->pdata;
        dma_cookie_t cookie;
        int ret, i;
        bool aligned = true, multiple = true;
-       unsigned int align = (1 << pdata->dma->alignment_shift) - 1;
+       unsigned int align = (1 << host->pdata->alignment_shift) - 1;
 
        for_each_sg(sg, sg_tmp, host->sg_len, i) {
                if (sg_tmp->offset & align)
@@ -128,11 +125,10 @@ static void tmio_mmc_start_dma_tx(struct tmio_mmc_host *host)
        struct scatterlist *sg = host->sg_ptr, *sg_tmp;
        struct dma_async_tx_descriptor *desc = NULL;
        struct dma_chan *chan = host->chan_tx;
-       struct tmio_mmc_data *pdata = host->pdata;
        dma_cookie_t cookie;
        int ret, i;
        bool aligned = true, multiple = true;
-       unsigned int align = (1 << pdata->dma->alignment_shift) - 1;
+       unsigned int align = (1 << host->pdata->alignment_shift) - 1;
 
        for_each_sg(sg, sg_tmp, host->sg_len, i) {
                if (sg_tmp->offset & align)
@@ -261,42 +257,64 @@ out:
        spin_unlock_irq(&host->lock);
 }
 
-/* It might be necessary to make filter MFD specific */
-static bool tmio_mmc_filter(struct dma_chan *chan, void *arg)
-{
-       dev_dbg(chan->device->dev, "%s: slave data %p\n", __func__, arg);
-       chan->private = arg;
-       return true;
-}
-
 void tmio_mmc_request_dma(struct tmio_mmc_host *host, struct tmio_mmc_data *pdata)
 {
        /* We can only either use DMA for both Tx and Rx or not use it at all */
-       if (!pdata->dma)
+       if (!host->dma || (!host->pdev->dev.of_node &&
+               (!pdata->chan_priv_tx || !pdata->chan_priv_rx)))
                return;
 
        if (!host->chan_tx && !host->chan_rx) {
+               struct resource *res = platform_get_resource(host->pdev,
+                                                            IORESOURCE_MEM, 0);
+               struct dma_slave_config cfg = {};
                dma_cap_mask_t mask;
+               int ret;
+
+               if (!res)
+                       return;
 
                dma_cap_zero(mask);
                dma_cap_set(DMA_SLAVE, mask);
 
-               host->chan_tx = dma_request_channel(mask, tmio_mmc_filter,
-                                                   pdata->dma->chan_priv_tx);
+               host->chan_tx = dma_request_slave_channel_compat(mask,
+                                       host->dma->filter, pdata->chan_priv_tx,
+                                       &host->pdev->dev, "tx");
                dev_dbg(&host->pdev->dev, "%s: TX: got channel %p\n", __func__,
                        host->chan_tx);
 
                if (!host->chan_tx)
                        return;
 
-               host->chan_rx = dma_request_channel(mask, tmio_mmc_filter,
-                                                   pdata->dma->chan_priv_rx);
+               cfg.direction = DMA_MEM_TO_DEV;
+               cfg.dst_addr = res->start + (CTL_SD_DATA_PORT << host->bus_shift);
+               cfg.dst_addr_width = host->dma->dma_buswidth;
+               if (!cfg.dst_addr_width)
+                       cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
+               cfg.src_addr = 0;
+               ret = dmaengine_slave_config(host->chan_tx, &cfg);
+               if (ret < 0)
+                       goto ecfgtx;
+
+               host->chan_rx = dma_request_slave_channel_compat(mask,
+                                       host->dma->filter, pdata->chan_priv_rx,
+                                       &host->pdev->dev, "rx");
                dev_dbg(&host->pdev->dev, "%s: RX: got channel %p\n", __func__,
                        host->chan_rx);
 
                if (!host->chan_rx)
                        goto ereqrx;
 
+               cfg.direction = DMA_DEV_TO_MEM;
+               cfg.src_addr = cfg.dst_addr + host->pdata->dma_rx_offset;
+               cfg.src_addr_width = host->dma->dma_buswidth;
+               if (!cfg.src_addr_width)
+                       cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
+               cfg.dst_addr = 0;
+               ret = dmaengine_slave_config(host->chan_rx, &cfg);
+               if (ret < 0)
+                       goto ecfgrx;
+
                host->bounce_buf = (u8 *)__get_free_page(GFP_KERNEL | GFP_DMA);
                if (!host->bounce_buf)
                        goto ebouncebuf;
@@ -310,9 +328,11 @@ void tmio_mmc_request_dma(struct tmio_mmc_host *host, struct tmio_mmc_data *pdat
        return;
 
 ebouncebuf:
+ecfgrx:
        dma_release_channel(host->chan_rx);
        host->chan_rx = NULL;
 ereqrx:
+ecfgtx:
        dma_release_channel(host->chan_tx);
        host->chan_tx = NULL;
 }