mmc: davinci_mmc: convert to DMA engine API
authorMatt Porter <mporter@ti.com>
Thu, 23 Aug 2012 01:09:35 +0000 (01:09 +0000)
committerChris Ball <cjb@laptop.org>
Wed, 19 Sep 2012 08:29:44 +0000 (16:29 +0800)
Removes use of the DaVinci EDMA private DMA API and replaces
it with use of the DMA engine API.

Signed-off-by: Matt Porter <mporter@ti.com>
Tested-by: Koen Kooi <koen@dominion.thruhere.net>
Signed-off-by: Chris Ball <cjb@laptop.org>
drivers/mmc/host/davinci_mmc.c

index 7cf6c624bf737fd1858422a0b6237b74de50fb83..c5e1eebcd5888bdf6186f27e17213d33dee08401 100644 (file)
 #include <linux/io.h>
 #include <linux/irq.h>
 #include <linux/delay.h>
+#include <linux/dmaengine.h>
 #include <linux/dma-mapping.h>
+#include <linux/edma.h>
 #include <linux/mmc/mmc.h>
 
 #include <mach/mmc.h>
-#include <mach/edma.h>
 
 /*
  * Register Definitions
@@ -200,21 +201,13 @@ struct mmc_davinci_host {
        u32 bytes_left;
 
        u32 rxdma, txdma;
+       struct dma_chan *dma_tx;
+       struct dma_chan *dma_rx;
        bool use_dma;
        bool do_dma;
        bool sdio_int;
        bool active_request;
 
-       /* Scatterlist DMA uses one or more parameter RAM entries:
-        * the main one (associated with rxdma or txdma) plus zero or
-        * more links.  The entries for a given transfer differ only
-        * by memory buffer (address, length) and link field.
-        */
-       struct edmacc_param     tx_template;
-       struct edmacc_param     rx_template;
-       unsigned                n_link;
-       u32                     links[MAX_NR_SG - 1];
-
        /* For PIO we walk scatterlists one segment at a time. */
        unsigned int            sg_len;
        struct scatterlist *sg;
@@ -410,153 +403,74 @@ static void mmc_davinci_start_command(struct mmc_davinci_host *host,
 
 static void davinci_abort_dma(struct mmc_davinci_host *host)
 {
-       int sync_dev;
+       struct dma_chan *sync_dev;
 
        if (host->data_dir == DAVINCI_MMC_DATADIR_READ)
-               sync_dev = host->rxdma;
+               sync_dev = host->dma_rx;
        else
-               sync_dev = host->txdma;
-
-       edma_stop(sync_dev);
-       edma_clean_channel(sync_dev);
-}
-
-static void
-mmc_davinci_xfer_done(struct mmc_davinci_host *host, struct mmc_data *data);
-
-static void mmc_davinci_dma_cb(unsigned channel, u16 ch_status, void *data)
-{
-       if (DMA_COMPLETE != ch_status) {
-               struct mmc_davinci_host *host = data;
-
-               /* Currently means:  DMA Event Missed, or "null" transfer
-                * request was seen.  In the future, TC errors (like bad
-                * addresses) might be presented too.
-                */
-               dev_warn(mmc_dev(host->mmc), "DMA %s error\n",
-                       (host->data->flags & MMC_DATA_WRITE)
-                               ? "write" : "read");
-               host->data->error = -EIO;
-               mmc_davinci_xfer_done(host, host->data);
-       }
-}
-
-/* Set up tx or rx template, to be modified and updated later */
-static void __init mmc_davinci_dma_setup(struct mmc_davinci_host *host,
-               bool tx, struct edmacc_param *template)
-{
-       unsigned        sync_dev;
-       const u16       acnt = 4;
-       const u16       bcnt = rw_threshold >> 2;
-       const u16       ccnt = 0;
-       u32             src_port = 0;
-       u32             dst_port = 0;
-       s16             src_bidx, dst_bidx;
-       s16             src_cidx, dst_cidx;
-
-       /*
-        * A-B Sync transfer:  each DMA request is for one "frame" of
-        * rw_threshold bytes, broken into "acnt"-size chunks repeated
-        * "bcnt" times.  Each segment needs "ccnt" such frames; since
-        * we tell the block layer our mmc->max_seg_size limit, we can
-        * trust (later) that it's within bounds.
-        *
-        * The FIFOs are read/written in 4-byte chunks (acnt == 4) and
-        * EDMA will optimize memory operations to use larger bursts.
-        */
-       if (tx) {
-               sync_dev = host->txdma;
-
-               /* src_prt, ccnt, and link to be set up later */
-               src_bidx = acnt;
-               src_cidx = acnt * bcnt;
-
-               dst_port = host->mem_res->start + DAVINCI_MMCDXR;
-               dst_bidx = 0;
-               dst_cidx = 0;
-       } else {
-               sync_dev = host->rxdma;
-
-               src_port = host->mem_res->start + DAVINCI_MMCDRR;
-               src_bidx = 0;
-               src_cidx = 0;
-
-               /* dst_prt, ccnt, and link to be set up later */
-               dst_bidx = acnt;
-               dst_cidx = acnt * bcnt;
-       }
-
-       /*
-        * We can't use FIFO mode for the FIFOs because MMC FIFO addresses
-        * are not 256-bit (32-byte) aligned.  So we use INCR, and the W8BIT
-        * parameter is ignored.
-        */
-       edma_set_src(sync_dev, src_port, INCR, W8BIT);
-       edma_set_dest(sync_dev, dst_port, INCR, W8BIT);
+               sync_dev = host->dma_tx;
 
-       edma_set_src_index(sync_dev, src_bidx, src_cidx);
-       edma_set_dest_index(sync_dev, dst_bidx, dst_cidx);
-
-       edma_set_transfer_params(sync_dev, acnt, bcnt, ccnt, 8, ABSYNC);
-
-       edma_read_slot(sync_dev, template);
-
-       /* don't bother with irqs or chaining */
-       template->opt |= EDMA_CHAN_SLOT(sync_dev) << 12;
+       dmaengine_terminate_all(sync_dev);
 }
 
-static void mmc_davinci_send_dma_request(struct mmc_davinci_host *host,
+static int mmc_davinci_send_dma_request(struct mmc_davinci_host *host,
                struct mmc_data *data)
 {
-       struct edmacc_param     *template;
-       int                     channel, slot;
-       unsigned                link;
-       struct scatterlist      *sg;
-       unsigned                sg_len;
-       unsigned                bytes_left = host->bytes_left;
-       const unsigned          shift = ffs(rw_threshold) - 1;
+       struct dma_chan *chan;
+       struct dma_async_tx_descriptor *desc;
+       int ret = 0;
 
        if (host->data_dir == DAVINCI_MMC_DATADIR_WRITE) {
-               template = &host->tx_template;
-               channel = host->txdma;
+               struct dma_slave_config dma_tx_conf = {
+                       .direction = DMA_MEM_TO_DEV,
+                       .dst_addr = host->mem_res->start + DAVINCI_MMCDXR,
+                       .dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES,
+                       .dst_maxburst =
+                               rw_threshold / DMA_SLAVE_BUSWIDTH_4_BYTES,
+               };
+               chan = host->dma_tx;
+               dmaengine_slave_config(host->dma_tx, &dma_tx_conf);
+
+               desc = dmaengine_prep_slave_sg(host->dma_tx,
+                               data->sg,
+                               host->sg_len,
+                               DMA_MEM_TO_DEV,
+                               DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+               if (!desc) {
+                       dev_dbg(mmc_dev(host->mmc),
+                               "failed to allocate DMA TX descriptor");
+                       ret = -1;
+                       goto out;
+               }
        } else {
-               template = &host->rx_template;
-               channel = host->rxdma;
-       }
-
-       /* We know sg_len and ccnt will never be out of range because
-        * we told the mmc layer which in turn tells the block layer
-        * to ensure that it only hands us one scatterlist segment
-        * per EDMA PARAM entry.  Update the PARAM
-        * entries needed for each segment of this scatterlist.
-        */
-       for (slot = channel, link = 0, sg = data->sg, sg_len = host->sg_len;
-                       sg_len-- != 0 && bytes_left;
-                       sg = sg_next(sg), slot = host->links[link++]) {
-               u32             buf = sg_dma_address(sg);
-               unsigned        count = sg_dma_len(sg);
-
-               template->link_bcntrld = sg_len
-                               ? (EDMA_CHAN_SLOT(host->links[link]) << 5)
-                               : 0xffff;
-
-               if (count > bytes_left)
-                       count = bytes_left;
-               bytes_left -= count;
-
-               if (host->data_dir == DAVINCI_MMC_DATADIR_WRITE)
-                       template->src = buf;
-               else
-                       template->dst = buf;
-               template->ccnt = count >> shift;
-
-               edma_write_slot(slot, template);
+               struct dma_slave_config dma_rx_conf = {
+                       .direction = DMA_DEV_TO_MEM,
+                       .src_addr = host->mem_res->start + DAVINCI_MMCDRR,
+                       .src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES,
+                       .src_maxburst =
+                               rw_threshold / DMA_SLAVE_BUSWIDTH_4_BYTES,
+               };
+               chan = host->dma_rx;
+               dmaengine_slave_config(host->dma_rx, &dma_rx_conf);
+
+               desc = dmaengine_prep_slave_sg(host->dma_rx,
+                               data->sg,
+                               host->sg_len,
+                               DMA_DEV_TO_MEM,
+                               DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+               if (!desc) {
+                       dev_dbg(mmc_dev(host->mmc),
+                               "failed to allocate DMA RX descriptor");
+                       ret = -1;
+                       goto out;
+               }
        }
 
-       if (host->version == MMC_CTLR_VERSION_2)
-               edma_clear_event(channel);
+       dmaengine_submit(desc);
+       dma_async_issue_pending(chan);
 
-       edma_start(channel);
+out:
+       return ret;
 }
 
 static int mmc_davinci_start_dma_transfer(struct mmc_davinci_host *host,
@@ -564,6 +478,7 @@ static int mmc_davinci_start_dma_transfer(struct mmc_davinci_host *host,
 {
        int i;
        int mask = rw_threshold - 1;
+       int ret = 0;
 
        host->sg_len = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
                                ((data->flags & MMC_DATA_WRITE)
@@ -583,70 +498,48 @@ static int mmc_davinci_start_dma_transfer(struct mmc_davinci_host *host,
        }
 
        host->do_dma = 1;
-       mmc_davinci_send_dma_request(host, data);
+       ret = mmc_davinci_send_dma_request(host, data);
 
-       return 0;
+       return ret;
 }
 
 static void __init_or_module
 davinci_release_dma_channels(struct mmc_davinci_host *host)
 {
-       unsigned        i;
-
        if (!host->use_dma)
                return;
 
-       for (i = 0; i < host->n_link; i++)
-               edma_free_slot(host->links[i]);
-
-       edma_free_channel(host->txdma);
-       edma_free_channel(host->rxdma);
+       dma_release_channel(host->dma_tx);
+       dma_release_channel(host->dma_rx);
 }
 
 static int __init davinci_acquire_dma_channels(struct mmc_davinci_host *host)
 {
-       u32 link_size;
-       int r, i;
-
-       /* Acquire master DMA write channel */
-       r = edma_alloc_channel(host->txdma, mmc_davinci_dma_cb, host,
-                       EVENTQ_DEFAULT);
-       if (r < 0) {
-               dev_warn(mmc_dev(host->mmc), "alloc %s channel err %d\n",
-                               "tx", r);
-               return r;
-       }
-       mmc_davinci_dma_setup(host, true, &host->tx_template);
-
-       /* Acquire master DMA read channel */
-       r = edma_alloc_channel(host->rxdma, mmc_davinci_dma_cb, host,
-                       EVENTQ_DEFAULT);
-       if (r < 0) {
-               dev_warn(mmc_dev(host->mmc), "alloc %s channel err %d\n",
-                               "rx", r);
-               goto free_master_write;
+       int r;
+       dma_cap_mask_t mask;
+
+       dma_cap_zero(mask);
+       dma_cap_set(DMA_SLAVE, mask);
+
+       host->dma_tx =
+               dma_request_channel(mask, edma_filter_fn, &host->txdma);
+       if (!host->dma_tx) {
+               dev_err(mmc_dev(host->mmc), "Can't get dma_tx channel\n");
+               return -ENODEV;
        }
-       mmc_davinci_dma_setup(host, false, &host->rx_template);
 
-       /* Allocate parameter RAM slots, which will later be bound to a
-        * channel as needed to handle a scatterlist.
-        */
-       link_size = min_t(unsigned, host->nr_sg, ARRAY_SIZE(host->links));
-       for (i = 0; i < link_size; i++) {
-               r = edma_alloc_slot(EDMA_CTLR(host->txdma), EDMA_SLOT_ANY);
-               if (r < 0) {
-                       dev_dbg(mmc_dev(host->mmc), "dma PaRAM alloc --> %d\n",
-                               r);
-                       break;
-               }
-               host->links[i] = r;
+       host->dma_rx =
+               dma_request_channel(mask, edma_filter_fn, &host->rxdma);
+       if (!host->dma_rx) {
+               dev_err(mmc_dev(host->mmc), "Can't get dma_rx channel\n");
+               r = -ENODEV;
+               goto free_master_write;
        }
-       host->n_link = i;
 
        return 0;
 
 free_master_write:
-       edma_free_channel(host->txdma);
+       dma_release_channel(host->dma_tx);
 
        return r;
 }
@@ -1359,7 +1252,7 @@ static int __init davinci_mmcsd_probe(struct platform_device *pdev)
         * Each hw_seg uses one EDMA parameter RAM slot, always one
         * channel and then usually some linked slots.
         */
-       mmc->max_segs           = 1 + host->n_link;
+       mmc->max_segs           = MAX_NR_SG;
 
        /* EDMA limit per hw segment (one or two MBytes) */
        mmc->max_seg_size       = MAX_CCNT * rw_threshold;