Merge branch 'next' of git://git.infradead.org/users/vkoul/slave-dma
authorLinus Torvalds <torvalds@linux-foundation.org>
Sun, 3 Mar 2013 18:20:22 +0000 (10:20 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sun, 3 Mar 2013 18:20:22 +0000 (10:20 -0800)
Pull second set of slave-dmaengine updates from Vinod Koul:
 "Arnd's patch moves the dw_dmac to use generic DMA binding.  I agreed
  to merge this late as it will avoid the conflicts between trees.

  The second patch from Matt adding a dma_request_slave_channel_compat
  API was supposed to be picked up, but somehow never got picked up.
  Some patches dependent on this are already in -next :("

* 'next' of git://git.infradead.org/users/vkoul/slave-dma:
  dmaengine: dw_dmac: move to generic DMA binding
  dmaengine: add dma_request_slave_channel_compat()

1  2 
drivers/dma/dw_dmac.c

diff --combined drivers/dma/dw_dmac.c
  #include <linux/dmaengine.h>
  #include <linux/dma-mapping.h>
  #include <linux/dmapool.h>
 +#include <linux/err.h>
  #include <linux/init.h>
  #include <linux/interrupt.h>
  #include <linux/io.h>
  #include <linux/of.h>
+ #include <linux/of_dma.h>
  #include <linux/mm.h>
  #include <linux/module.h>
  #include <linux/platform_device.h>
@@@ -171,7 -171,13 +172,13 @@@ static void dwc_initialize(struct dw_dm
        if (dwc->initialized == true)
                return;
  
-       if (dws) {
+       if (dws && dws->cfg_hi == ~0 && dws->cfg_lo == ~0) {
+               /* autoconfigure based on request line from DT */
+               if (dwc->direction == DMA_MEM_TO_DEV)
+                       cfghi = DWC_CFGH_DST_PER(dwc->request_line);
+               else if (dwc->direction == DMA_DEV_TO_MEM)
+                       cfghi = DWC_CFGH_SRC_PER(dwc->request_line);
+       } else if (dws) {
                /*
                 * We need controller-specific data to set up slave
                 * transfers.
@@@ -1226,49 -1232,64 +1233,64 @@@ static void dwc_free_chan_resources(str
        dev_vdbg(chan2dev(chan), "%s: done\n", __func__);
  }
  
- bool dw_dma_generic_filter(struct dma_chan *chan, void *param)
+ struct dw_dma_filter_args {
+       struct dw_dma *dw;
+       unsigned int req;
+       unsigned int src;
+       unsigned int dst;
+ };
+ static bool dw_dma_generic_filter(struct dma_chan *chan, void *param)
  {
+       struct dw_dma_chan *dwc = to_dw_dma_chan(chan);
        struct dw_dma *dw = to_dw_dma(chan->device);
-       static struct dw_dma *last_dw;
-       static char *last_bus_id;
-       int i = -1;
+       struct dw_dma_filter_args *fargs = param;
+       struct dw_dma_slave *dws = &dwc->slave;
  
-       /*
-        * dmaengine framework calls this routine for all channels of all dma
-        * controller, until true is returned. If 'param' bus_id is not
-        * registered with a dma controller (dw), then there is no need of
-        * running below function for all channels of dw.
-        *
-        * This block of code does this by saving the parameters of last
-        * failure. If dw and param are same, i.e. trying on same dw with
-        * different channel, return false.
-        */
-       if ((last_dw == dw) && (last_bus_id == param))
-               return false;
-       /*
-        * Return true:
-        * - If dw_dma's platform data is not filled with slave info, then all
-        *   dma controllers are fine for transfer.
-        * - Or if param is NULL
-        */
-       if (!dw->sd || !param)
-               return true;
+       /* ensure the device matches our channel */
+         if (chan->device != &fargs->dw->dma)
+                 return false;
  
-       while (++i < dw->sd_count) {
-               if (!strcmp(dw->sd[i].bus_id, param)) {
-                       chan->private = &dw->sd[i];
-                       last_dw = NULL;
-                       last_bus_id = NULL;
+       dws->dma_dev    = dw->dma.dev;
+       dws->cfg_hi     = ~0;
+       dws->cfg_lo     = ~0;
+       dws->src_master = fargs->src;
+       dws->dst_master = fargs->dst;
  
-                       return true;
-               }
-       }
+       dwc->request_line = fargs->req;
+       chan->private = dws;
+       return true;
+ }
+ static struct dma_chan *dw_dma_xlate(struct of_phandle_args *dma_spec,
+                                        struct of_dma *ofdma)
+ {
+       struct dw_dma *dw = ofdma->of_dma_data;
+       struct dw_dma_filter_args fargs = {
+               .dw = dw,
+       };
+       dma_cap_mask_t cap;
+       if (dma_spec->args_count != 3)
+               return NULL;
+       fargs.req = be32_to_cpup(dma_spec->args+0);
+       fargs.src = be32_to_cpup(dma_spec->args+1);
+       fargs.dst = be32_to_cpup(dma_spec->args+2);
+       if (WARN_ON(fargs.req >= DW_DMA_MAX_NR_REQUESTS ||
+                   fargs.src >= dw->nr_masters ||
+                   fargs.dst >= dw->nr_masters))
+               return NULL;
  
-       last_dw = dw;
-       last_bus_id = param;
-       return false;
+       dma_cap_zero(cap);
+       dma_cap_set(DMA_SLAVE, cap);
+       /* TODO: there should be a simpler way to do this */
+       return dma_request_channel(cap, dw_dma_generic_filter, &fargs);
  }
- EXPORT_SYMBOL(dw_dma_generic_filter);
  
  /* --------------------- Cyclic DMA API extensions -------------------- */
  
@@@ -1554,9 -1575,8 +1576,8 @@@ static void dw_dma_off(struct dw_dma *d
  static struct dw_dma_platform_data *
  dw_dma_parse_dt(struct platform_device *pdev)
  {
-       struct device_node *sn, *cn, *np = pdev->dev.of_node;
+       struct device_node *np = pdev->dev.of_node;
        struct dw_dma_platform_data *pdata;
-       struct dw_dma_slave *sd;
        u32 tmp, arr[4];
  
        if (!np) {
        if (!pdata)
                return NULL;
  
-       if (of_property_read_u32(np, "nr_channels", &pdata->nr_channels))
+       if (of_property_read_u32(np, "dma-channels", &pdata->nr_channels))
                return NULL;
  
        if (of_property_read_bool(np, "is_private"))
        if (!of_property_read_u32(np, "block_size", &tmp))
                pdata->block_size = tmp;
  
-       if (!of_property_read_u32(np, "nr_masters", &tmp)) {
+       if (!of_property_read_u32(np, "dma-masters", &tmp)) {
                if (tmp > 4)
                        return NULL;
  
                for (tmp = 0; tmp < pdata->nr_masters; tmp++)
                        pdata->data_width[tmp] = arr[tmp];
  
-       /* parse slave data */
-       sn = of_find_node_by_name(np, "slave_info");
-       if (!sn)
-               return pdata;
-       /* calculate number of slaves */
-       tmp = of_get_child_count(sn);
-       if (!tmp)
-               return NULL;
-       sd = devm_kzalloc(&pdev->dev, sizeof(*sd) * tmp, GFP_KERNEL);
-       if (!sd)
-               return NULL;
-       pdata->sd = sd;
-       pdata->sd_count = tmp;
-       for_each_child_of_node(sn, cn) {
-               sd->dma_dev = &pdev->dev;
-               of_property_read_string(cn, "bus_id", &sd->bus_id);
-               of_property_read_u32(cn, "cfg_hi", &sd->cfg_hi);
-               of_property_read_u32(cn, "cfg_lo", &sd->cfg_lo);
-               if (!of_property_read_u32(cn, "src_master", &tmp))
-                       sd->src_master = tmp;
-               if (!of_property_read_u32(cn, "dst_master", &tmp))
-                       sd->dst_master = tmp;
-               sd++;
-       }
        return pdata;
  }
  #else
@@@ -1658,9 -1648,9 +1649,9 @@@ static int dw_probe(struct platform_dev
        if (irq < 0)
                return irq;
  
 -      regs = devm_request_and_ioremap(&pdev->dev, io);
 -      if (!regs)
 -              return -EBUSY;
 +      regs = devm_ioremap_resource(&pdev->dev, io);
 +      if (IS_ERR(regs))
 +              return PTR_ERR(regs);
  
        /* Apply default dma_mask if needed */
        if (!pdev->dev.dma_mask) {
        clk_prepare_enable(dw->clk);
  
        dw->regs = regs;
-       dw->sd = pdata->sd;
-       dw->sd_count = pdata->sd_count;
  
        /* get hardware configuration parameters */
        if (autocfg) {
  
        dma_async_device_register(&dw->dma);
  
+       if (pdev->dev.of_node) {
+               err = of_dma_controller_register(pdev->dev.of_node,
+                                                dw_dma_xlate, dw);
+               if (err && err != -ENODEV)
+                       dev_err(&pdev->dev,
+                               "could not register of_dma_controller\n");
+       }
        return 0;
  }
  
 -static int __devexit dw_remove(struct platform_device *pdev)
 +static int dw_remove(struct platform_device *pdev)
  {
        struct dw_dma           *dw = platform_get_drvdata(pdev);
        struct dw_dma_chan      *dwc, *_dwc;
  
+       if (pdev->dev.of_node)
+               of_dma_controller_free(pdev->dev.of_node);
        dw_dma_off(dw);
        dma_async_device_unregister(&dw->dma);