Merge branch 'for-linus' of git://git.infradead.org/users/vkoul/slave-dma
Linus Torvalds [Mon, 1 Aug 2011 23:46:37 +0000 (13:46 -1000)]
* 'for-linus' of git://git.infradead.org/users/vkoul/slave-dma: (37 commits)
  Improve slave/cyclic DMA engine documentation
  dmaengine: pl08x: handle the rest of enums in pl08x_width
  DMA: PL08x: cleanup selection of burst size
  DMA: PL08x: avoid recalculating cctl at each prepare
  DMA: PL08x: cleanup selection of buswidth
  DMA: PL08x: constify plchan->cd and plat->slave_channels
  DMA: PL08x: separately store source/destination cctl
  DMA: PL08x: separately store source/destination slave address
  DMA: PL08x: clean up LLI debugging
  DMA: PL08x: select LLI bus only once per LLI setup
  DMA: PL08x: remove unused constants
  ARM: mxs-dma: reset after disable channel
  dma: intel_mid_dma: remove redundant pci_set_drvdata calls
  dma: mxs-dma: fix unterminated platform_device_id table
  dmaengine: pl330: make platform data optional
  dmaengine: imx-sdma: return proper error if kzalloc fails
  pch_dma: Fix CTL register access issue
  dmaengine: mxs-dma: skip request_irq for NO_IRQ
  dmaengine/coh901318: fix slave submission semantics
  dmaengine/ste_dma40: allow memory buswidth/burst to be configured
  ...

Fix trivial whitespace conflict in drivers/dma/mv_xor.c

1  2 
drivers/dma/coh901318.c
drivers/dma/dmaengine.c
drivers/dma/imx-sdma.c
drivers/dma/ipu/ipu_idmac.c
drivers/dma/ste_dma40.c

diff --combined drivers/dma/coh901318.c
@@@ -11,7 -11,6 +11,7 @@@
  #include <linux/module.h>
  #include <linux/kernel.h> /* printk() */
  #include <linux/fs.h> /* everything... */
 +#include <linux/scatterlist.h>
  #include <linux/slab.h> /* kmalloc() */
  #include <linux/dmaengine.h>
  #include <linux/platform_device.h>
@@@ -41,6 -40,8 +41,8 @@@ struct coh901318_desc 
        struct coh901318_lli *lli;
        enum dma_data_direction dir;
        unsigned long flags;
+       u32 head_config;
+       u32 head_ctrl;
  };
  
  struct coh901318_base {
@@@ -661,6 -662,9 +663,9 @@@ static struct coh901318_desc *coh901318
  
                coh901318_desc_submit(cohc, cohd);
  
+               /* Program the transaction head */
+               coh901318_set_conf(cohc, cohd->head_config);
+               coh901318_set_ctrl(cohc, cohd->head_ctrl);
                coh901318_prep_linked_list(cohc, cohd->lli);
  
                /* start dma job on this channel */
@@@ -1091,8 -1095,6 +1096,6 @@@ coh901318_prep_slave_sg(struct dma_cha
        } else
                goto err_direction;
  
-       coh901318_set_conf(cohc, config);
        /* The dma only supports transmitting packages up to
         * MAX_DMA_PACKET_SIZE. Calculate to total number of
         * dma elemts required to send the entire sg list
        if (ret)
                goto err_lli_fill;
  
-       /*
-        * Set the default ctrl for the channel to the one from the lli,
-        * things may have changed due to odd buffer alignment etc.
-        */
-       coh901318_set_ctrl(cohc, lli->control);
  
        COH_DBG(coh901318_list_print(cohc, lli));
  
        /* Pick a descriptor to handle this transfer */
        cohd = coh901318_desc_get(cohc);
+       cohd->head_config = config;
+       /*
+        * Set the default head ctrl for the channel to the one from the
+        * lli, things may have changed due to odd buffer alignment
+        * etc.
+        */
+       cohd->head_ctrl = lli->control;
        cohd->dir = direction;
        cohd->flags = flags;
        cohd->desc.tx_submit = coh901318_tx_submit;
diff --combined drivers/dma/dmaengine.c
@@@ -45,7 -45,6 +45,7 @@@
   * See Documentation/dmaengine.txt for more details
   */
  
 +#include <linux/dma-mapping.h>
  #include <linux/init.h>
  #include <linux/module.h>
  #include <linux/mm.h>
@@@ -510,8 -509,8 +510,8 @@@ struct dma_chan *__dma_request_channel(
                                         dma_chan_name(chan));
                                list_del_rcu(&device->global_node);
                        } else if (err)
-                               pr_err("dmaengine: failed to get %s: (%d)\n",
-                                      dma_chan_name(chan), err);
+                               pr_debug("dmaengine: failed to get %s: (%d)\n",
+                                        dma_chan_name(chan), err);
                        else
                                break;
                        if (--device->privatecnt == 0)
diff --combined drivers/dma/imx-sdma.c
@@@ -32,8 -32,6 +32,8 @@@
  #include <linux/slab.h>
  #include <linux/platform_device.h>
  #include <linux/dmaengine.h>
 +#include <linux/of.h>
 +#include <linux/of_device.h>
  
  #include <asm/irq.h>
  #include <mach/sdma.h>
@@@ -67,8 -65,8 +67,8 @@@
  #define SDMA_ONCE_RTB         0x060
  #define SDMA_XTRIG_CONF1      0x070
  #define SDMA_XTRIG_CONF2      0x074
 -#define SDMA_CHNENBL0_V2      0x200
 -#define SDMA_CHNENBL0_V1      0x080
 +#define SDMA_CHNENBL0_IMX35   0x200
 +#define SDMA_CHNENBL0_IMX31   0x080
  #define SDMA_CHNPRI_0         0x100
  
  /*
@@@ -301,18 -299,13 +301,18 @@@ struct sdma_firmware_header 
        u32     ram_code_size;
  };
  
 +enum sdma_devtype {
 +      IMX31_SDMA,     /* runs on i.mx31 */
 +      IMX35_SDMA,     /* runs on i.mx35 and later */
 +};
 +
  struct sdma_engine {
        struct device                   *dev;
        struct device_dma_parameters    dma_parms;
        struct sdma_channel             channel[MAX_DMA_CHANNELS];
        struct sdma_channel_control     *channel_control;
        void __iomem                    *regs;
 -      unsigned int                    version;
 +      enum sdma_devtype               devtype;
        unsigned int                    num_events;
        struct sdma_context_data        *context;
        dma_addr_t                      context_phys;
        struct sdma_script_start_addrs  *script_addrs;
  };
  
 +static struct platform_device_id sdma_devtypes[] = {
 +      {
 +              .name = "imx31-sdma",
 +              .driver_data = IMX31_SDMA,
 +      }, {
 +              .name = "imx35-sdma",
 +              .driver_data = IMX35_SDMA,
 +      }, {
 +              /* sentinel */
 +      }
 +};
 +MODULE_DEVICE_TABLE(platform, sdma_devtypes);
 +
 +static const struct of_device_id sdma_dt_ids[] = {
 +      { .compatible = "fsl,imx31-sdma", .data = &sdma_devtypes[IMX31_SDMA], },
 +      { .compatible = "fsl,imx35-sdma", .data = &sdma_devtypes[IMX35_SDMA], },
 +      { /* sentinel */ }
 +};
 +MODULE_DEVICE_TABLE(of, sdma_dt_ids);
 +
  #define SDMA_H_CONFIG_DSPDMA  (1 << 12) /* indicates if the DSPDMA is used */
  #define SDMA_H_CONFIG_RTD_PINS        (1 << 11) /* indicates if Real-Time Debug pins are enabled */
  #define SDMA_H_CONFIG_ACR     (1 << 4)  /* indicates if AHB freq /core freq = 2 or 1 */
  
  static inline u32 chnenbl_ofs(struct sdma_engine *sdma, unsigned int event)
  {
 -      u32 chnenbl0 = (sdma->version == 2 ? SDMA_CHNENBL0_V2 : SDMA_CHNENBL0_V1);
 -
 +      u32 chnenbl0 = (sdma->devtype == IMX31_SDMA ? SDMA_CHNENBL0_IMX31 :
 +                                                    SDMA_CHNENBL0_IMX35);
        return chnenbl0 + event * 4;
  }
  
@@@ -1132,17 -1105,25 +1132,17 @@@ static void sdma_add_scripts(struct sdm
  }
  
  static int __init sdma_get_firmware(struct sdma_engine *sdma,
 -              const char *cpu_name, int to_version)
 +              const char *fw_name)
  {
        const struct firmware *fw;
 -      char *fwname;
        const struct sdma_firmware_header *header;
        int ret;
        const struct sdma_script_start_addrs *addr;
        unsigned short *ram_code;
  
 -      fwname = kasprintf(GFP_KERNEL, "sdma-%s-to%d.bin", cpu_name, to_version);
 -      if (!fwname)
 -              return -ENOMEM;
 -
 -      ret = request_firmware(&fw, fwname, sdma->dev);
 -      if (ret) {
 -              kfree(fwname);
 +      ret = request_firmware(&fw, fw_name, sdma->dev);
 +      if (ret)
                return ret;
 -      }
 -      kfree(fwname);
  
        if (fw->size < sizeof(*header))
                goto err_firmware;
@@@ -1181,16 -1162,15 +1181,16 @@@ static int __init sdma_init(struct sdma
        int i, ret;
        dma_addr_t ccb_phys;
  
 -      switch (sdma->version) {
 -      case 1:
 +      switch (sdma->devtype) {
 +      case IMX31_SDMA:
                sdma->num_events = 32;
                break;
 -      case 2:
 +      case IMX35_SDMA:
                sdma->num_events = 48;
                break;
        default:
 -              dev_err(sdma->dev, "Unknown version %d. aborting\n", sdma->version);
 +              dev_err(sdma->dev, "Unknown sdma type %d. aborting\n",
 +                      sdma->devtype);
                return -ENODEV;
        }
  
@@@ -1259,10 -1239,6 +1259,10 @@@ err_dma_alloc
  
  static int __init sdma_probe(struct platform_device *pdev)
  {
 +      const struct of_device_id *of_id =
 +                      of_match_device(sdma_dt_ids, &pdev->dev);
 +      struct device_node *np = pdev->dev.of_node;
 +      const char *fw_name;
        int ret;
        int irq;
        struct resource *iores;
  
        iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        irq = platform_get_irq(pdev, 0);
 -      if (!iores || irq < 0 || !pdata) {
 +      if (!iores || irq < 0) {
                ret = -EINVAL;
                goto err_irq;
        }
                goto err_request_irq;
  
        sdma->script_addrs = kzalloc(sizeof(*sdma->script_addrs), GFP_KERNEL);
-       if (!sdma->script_addrs)
+       if (!sdma->script_addrs) {
+               ret = -ENOMEM;
                goto err_alloc;
+       }
  
 -      sdma->version = pdata->sdma_version;
 +      if (of_id)
 +              pdev->id_entry = of_id->data;
 +      sdma->devtype = pdev->id_entry->driver_data;
  
        dma_cap_set(DMA_SLAVE, sdma->dma_device.cap_mask);
        dma_cap_set(DMA_CYCLIC, sdma->dma_device.cap_mask);
        if (ret)
                goto err_init;
  
 -      if (pdata->script_addrs)
 +      if (pdata && pdata->script_addrs)
                sdma_add_scripts(sdma, pdata->script_addrs);
  
 -      sdma_get_firmware(sdma, pdata->cpu_name, pdata->to_version);
 +      if (pdata) {
 +              sdma_get_firmware(sdma, pdata->fw_name);
 +      } else {
 +              /*
 +               * Because that device tree does not encode ROM script address,
 +               * the RAM script in firmware is mandatory for device tree
 +               * probe, otherwise it fails.
 +               */
 +              ret = of_property_read_string(np, "fsl,sdma-ram-script-name",
 +                                            &fw_name);
 +              if (ret) {
 +                      dev_err(&pdev->dev, "failed to get firmware name\n");
 +                      goto err_init;
 +              }
 +
 +              ret = sdma_get_firmware(sdma, fw_name);
 +              if (ret) {
 +                      dev_err(&pdev->dev, "failed to get firmware\n");
 +                      goto err_init;
 +              }
 +      }
  
        sdma->dma_device.dev = &pdev->dev;
  
@@@ -1411,9 -1367,7 +1413,9 @@@ static int __exit sdma_remove(struct pl
  static struct platform_driver sdma_driver = {
        .driver         = {
                .name   = "imx-sdma",
 +              .of_match_table = sdma_dt_ids,
        },
 +      .id_table       = sdma_devtypes,
        .remove         = __exit_p(sdma_remove),
  };
  
@@@ -9,7 -9,6 +9,7 @@@
   * published by the Free Software Foundation.
   */
  
 +#include <linux/dma-mapping.h>
  #include <linux/init.h>
  #include <linux/platform_device.h>
  #include <linux/err.h>
@@@ -1706,16 -1705,14 +1706,14 @@@ static int __init ipu_probe(struct plat
                ipu_data.irq_fn, ipu_data.irq_err, ipu_data.irq_base);
  
        /* Remap IPU common registers */
-       ipu_data.reg_ipu = ioremap(mem_ipu->start,
-                                  mem_ipu->end - mem_ipu->start + 1);
+       ipu_data.reg_ipu = ioremap(mem_ipu->start, resource_size(mem_ipu));
        if (!ipu_data.reg_ipu) {
                ret = -ENOMEM;
                goto err_ioremap_ipu;
        }
  
        /* Remap Image Converter and Image DMA Controller registers */
-       ipu_data.reg_ic = ioremap(mem_ic->start,
-                                 mem_ic->end - mem_ic->start + 1);
+       ipu_data.reg_ic = ioremap(mem_ic->start, resource_size(mem_ic));
        if (!ipu_data.reg_ic) {
                ret = -ENOMEM;
                goto err_ioremap_ic;
diff --combined drivers/dma/ste_dma40.c
@@@ -6,7 -6,6 +6,7 @@@
   * License terms: GNU General Public License (GPL) version 2
   */
  
 +#include <linux/dma-mapping.h>
  #include <linux/kernel.h>
  #include <linux/slab.h>
  #include <linux/dmaengine.h>
@@@ -14,6 -13,7 +14,7 @@@
  #include <linux/clk.h>
  #include <linux/delay.h>
  #include <linux/err.h>
+ #include <linux/amba/bus.h>
  
  #include <plat/ste_dma40.h>
  
@@@ -45,9 -45,6 +46,6 @@@
  #define D40_ALLOC_PHY         (1 << 30)
  #define D40_ALLOC_LOG_FREE    0
  
- /* Hardware designer of the block */
- #define D40_HW_DESIGNER 0x8
  /**
   * enum 40_command - The different commands and/or statuses.
   *
@@@ -186,6 -183,8 +184,8 @@@ struct d40_base
   * @log_def: Default logical channel settings.
   * @lcla: Space for one dst src pair for logical channel transfers.
   * @lcpa: Pointer to dst and src lcpa settings.
+  * @runtime_addr: runtime configured address.
+  * @runtime_direction: runtime configured direction.
   *
   * This struct can either "be" a logical or a physical channel.
   */
@@@ -200,6 -199,7 +200,7 @@@ struct d40_chan 
        struct dma_chan                  chan;
        struct tasklet_struct            tasklet;
        struct list_head                 client;
+       struct list_head                 pending_queue;
        struct list_head                 active;
        struct list_head                 queue;
        struct stedma40_chan_cfg         dma_cfg;
@@@ -645,7 -645,20 +646,20 @@@ static struct d40_desc *d40_first_activ
  
  static void d40_desc_queue(struct d40_chan *d40c, struct d40_desc *desc)
  {
-       list_add_tail(&desc->node, &d40c->queue);
+       list_add_tail(&desc->node, &d40c->pending_queue);
+ }
+ static struct d40_desc *d40_first_pending(struct d40_chan *d40c)
+ {
+       struct d40_desc *d;
+       if (list_empty(&d40c->pending_queue))
+               return NULL;
+       d = list_first_entry(&d40c->pending_queue,
+                            struct d40_desc,
+                            node);
+       return d;
  }
  
  static struct d40_desc *d40_first_queued(struct d40_chan *d40c)
@@@ -802,6 -815,11 +816,11 @@@ static void d40_term_all(struct d40_cha
                d40_desc_free(d40c, d40d);
        }
  
+       /* Release pending descriptors */
+       while ((d40d = d40_first_pending(d40c))) {
+               d40_desc_remove(d40d);
+               d40_desc_free(d40c, d40d);
+       }
  
        d40c->pending_tx = 0;
        d40c->busy = false;
@@@ -2092,7 -2110,7 +2111,7 @@@ dma40_prep_dma_cyclic(struct dma_chan *
        struct scatterlist *sg;
        int i;
  
-       sg = kcalloc(periods + 1, sizeof(struct scatterlist), GFP_KERNEL);
+       sg = kcalloc(periods + 1, sizeof(struct scatterlist), GFP_NOWAIT);
        for (i = 0; i < periods; i++) {
                sg_dma_address(&sg[i]) = dma_addr;
                sg_dma_len(&sg[i]) = period_len;
@@@ -2152,24 -2170,87 +2171,87 @@@ static void d40_issue_pending(struct dm
  
        spin_lock_irqsave(&d40c->lock, flags);
  
-       /* Busy means that pending jobs are already being processed */
+       list_splice_tail_init(&d40c->pending_queue, &d40c->queue);
+       /* Busy means that queued jobs are already being processed */
        if (!d40c->busy)
                (void) d40_queue_start(d40c);
  
        spin_unlock_irqrestore(&d40c->lock, flags);
  }
  
+ static int
+ dma40_config_to_halfchannel(struct d40_chan *d40c,
+                           struct stedma40_half_channel_info *info,
+                           enum dma_slave_buswidth width,
+                           u32 maxburst)
+ {
+       enum stedma40_periph_data_width addr_width;
+       int psize;
+       switch (width) {
+       case DMA_SLAVE_BUSWIDTH_1_BYTE:
+               addr_width = STEDMA40_BYTE_WIDTH;
+               break;
+       case DMA_SLAVE_BUSWIDTH_2_BYTES:
+               addr_width = STEDMA40_HALFWORD_WIDTH;
+               break;
+       case DMA_SLAVE_BUSWIDTH_4_BYTES:
+               addr_width = STEDMA40_WORD_WIDTH;
+               break;
+       case DMA_SLAVE_BUSWIDTH_8_BYTES:
+               addr_width = STEDMA40_DOUBLEWORD_WIDTH;
+               break;
+       default:
+               dev_err(d40c->base->dev,
+                       "illegal peripheral address width "
+                       "requested (%d)\n",
+                       width);
+               return -EINVAL;
+       }
+       if (chan_is_logical(d40c)) {
+               if (maxburst >= 16)
+                       psize = STEDMA40_PSIZE_LOG_16;
+               else if (maxburst >= 8)
+                       psize = STEDMA40_PSIZE_LOG_8;
+               else if (maxburst >= 4)
+                       psize = STEDMA40_PSIZE_LOG_4;
+               else
+                       psize = STEDMA40_PSIZE_LOG_1;
+       } else {
+               if (maxburst >= 16)
+                       psize = STEDMA40_PSIZE_PHY_16;
+               else if (maxburst >= 8)
+                       psize = STEDMA40_PSIZE_PHY_8;
+               else if (maxburst >= 4)
+                       psize = STEDMA40_PSIZE_PHY_4;
+               else
+                       psize = STEDMA40_PSIZE_PHY_1;
+       }
+       info->data_width = addr_width;
+       info->psize = psize;
+       info->flow_ctrl = STEDMA40_NO_FLOW_CTRL;
+       return 0;
+ }
  /* Runtime reconfiguration extension */
- static void d40_set_runtime_config(struct dma_chan *chan,
-                              struct dma_slave_config *config)
+ static int d40_set_runtime_config(struct dma_chan *chan,
+                                 struct dma_slave_config *config)
  {
        struct d40_chan *d40c = container_of(chan, struct d40_chan, chan);
        struct stedma40_chan_cfg *cfg = &d40c->dma_cfg;
-       enum dma_slave_buswidth config_addr_width;
+       enum dma_slave_buswidth src_addr_width, dst_addr_width;
        dma_addr_t config_addr;
-       u32 config_maxburst;
-       enum stedma40_periph_data_width addr_width;
-       int psize;
+       u32 src_maxburst, dst_maxburst;
+       int ret;
+       src_addr_width = config->src_addr_width;
+       src_maxburst = config->src_maxburst;
+       dst_addr_width = config->dst_addr_width;
+       dst_maxburst = config->dst_maxburst;
  
        if (config->direction == DMA_FROM_DEVICE) {
                dma_addr_t dev_addr_rx =
                                cfg->dir);
                cfg->dir = STEDMA40_PERIPH_TO_MEM;
  
-               config_addr_width = config->src_addr_width;
-               config_maxburst = config->src_maxburst;
+               /* Configure the memory side */
+               if (dst_addr_width == DMA_SLAVE_BUSWIDTH_UNDEFINED)
+                       dst_addr_width = src_addr_width;
+               if (dst_maxburst == 0)
+                       dst_maxburst = src_maxburst;
  
        } else if (config->direction == DMA_TO_DEVICE) {
                dma_addr_t dev_addr_tx =
                                cfg->dir);
                cfg->dir = STEDMA40_MEM_TO_PERIPH;
  
-               config_addr_width = config->dst_addr_width;
-               config_maxburst = config->dst_maxburst;
+               /* Configure the memory side */
+               if (src_addr_width == DMA_SLAVE_BUSWIDTH_UNDEFINED)
+                       src_addr_width = dst_addr_width;
+               if (src_maxburst == 0)
+                       src_maxburst = dst_maxburst;
        } else {
                dev_err(d40c->base->dev,
                        "unrecognized channel direction %d\n",
                        config->direction);
-               return;
+               return -EINVAL;
        }
  
-       switch (config_addr_width) {
-       case DMA_SLAVE_BUSWIDTH_1_BYTE:
-               addr_width = STEDMA40_BYTE_WIDTH;
-               break;
-       case DMA_SLAVE_BUSWIDTH_2_BYTES:
-               addr_width = STEDMA40_HALFWORD_WIDTH;
-               break;
-       case DMA_SLAVE_BUSWIDTH_4_BYTES:
-               addr_width = STEDMA40_WORD_WIDTH;
-               break;
-       case DMA_SLAVE_BUSWIDTH_8_BYTES:
-               addr_width = STEDMA40_DOUBLEWORD_WIDTH;
-               break;
-       default:
+       if (src_maxburst * src_addr_width != dst_maxburst * dst_addr_width) {
                dev_err(d40c->base->dev,
-                       "illegal peripheral address width "
-                       "requested (%d)\n",
-                       config->src_addr_width);
-               return;
+                       "src/dst width/maxburst mismatch: %d*%d != %d*%d\n",
+                       src_maxburst,
+                       src_addr_width,
+                       dst_maxburst,
+                       dst_addr_width);
+               return -EINVAL;
        }
  
-       if (chan_is_logical(d40c)) {
-               if (config_maxburst >= 16)
-                       psize = STEDMA40_PSIZE_LOG_16;
-               else if (config_maxburst >= 8)
-                       psize = STEDMA40_PSIZE_LOG_8;
-               else if (config_maxburst >= 4)
-                       psize = STEDMA40_PSIZE_LOG_4;
-               else
-                       psize = STEDMA40_PSIZE_LOG_1;
-       } else {
-               if (config_maxburst >= 16)
-                       psize = STEDMA40_PSIZE_PHY_16;
-               else if (config_maxburst >= 8)
-                       psize = STEDMA40_PSIZE_PHY_8;
-               else if (config_maxburst >= 4)
-                       psize = STEDMA40_PSIZE_PHY_4;
-               else if (config_maxburst >= 2)
-                       psize = STEDMA40_PSIZE_PHY_2;
-               else
-                       psize = STEDMA40_PSIZE_PHY_1;
-       }
+       ret = dma40_config_to_halfchannel(d40c, &cfg->src_info,
+                                         src_addr_width,
+                                         src_maxburst);
+       if (ret)
+               return ret;
  
-       /* Set up all the endpoint configs */
-       cfg->src_info.data_width = addr_width;
-       cfg->src_info.psize = psize;
-       cfg->src_info.big_endian = false;
-       cfg->src_info.flow_ctrl = STEDMA40_NO_FLOW_CTRL;
-       cfg->dst_info.data_width = addr_width;
-       cfg->dst_info.psize = psize;
-       cfg->dst_info.big_endian = false;
-       cfg->dst_info.flow_ctrl = STEDMA40_NO_FLOW_CTRL;
+       ret = dma40_config_to_halfchannel(d40c, &cfg->dst_info,
+                                         dst_addr_width,
+                                         dst_maxburst);
+       if (ret)
+               return ret;
  
        /* Fill in register values */
        if (chan_is_logical(d40c))
        d40c->runtime_addr = config_addr;
        d40c->runtime_direction = config->direction;
        dev_dbg(d40c->base->dev,
-               "configured channel %s for %s, data width %d, "
-               "maxburst %d bytes, LE, no flow control\n",
+               "configured channel %s for %s, data width %d/%d, "
+               "maxburst %d/%d elements, LE, no flow control\n",
                dma_chan_name(chan),
                (config->direction == DMA_FROM_DEVICE) ? "RX" : "TX",
-               config_addr_width,
-               config_maxburst);
+               src_addr_width, dst_addr_width,
+               src_maxburst, dst_maxburst);
+       return 0;
  }
  
  static int d40_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
        case DMA_RESUME:
                return d40_resume(d40c);
        case DMA_SLAVE_CONFIG:
-               d40_set_runtime_config(chan,
+               return d40_set_runtime_config(chan,
                        (struct dma_slave_config *) arg);
-               return 0;
        default:
                break;
        }
@@@ -2341,6 -2397,7 +2398,7 @@@ static void __init d40_chan_init(struc
  
                INIT_LIST_HEAD(&d40c->active);
                INIT_LIST_HEAD(&d40c->queue);
+               INIT_LIST_HEAD(&d40c->pending_queue);
                INIT_LIST_HEAD(&d40c->client);
  
                tasklet_init(&d40c->tasklet, dma_tasklet,
@@@ -2502,25 -2559,6 +2560,6 @@@ static int __init d40_phy_res_init(stru
  
  static struct d40_base * __init d40_hw_detect_init(struct platform_device *pdev)
  {
-       static const struct d40_reg_val dma_id_regs[] = {
-               /* Peripheral Id */
-               { .reg = D40_DREG_PERIPHID0, .val = 0x0040},
-               { .reg = D40_DREG_PERIPHID1, .val = 0x0000},
-               /*
-                * D40_DREG_PERIPHID2 Depends on HW revision:
-                *  DB8500ed has 0x0008,
-                *  ? has 0x0018,
-                *  DB8500v1 has 0x0028
-                *  DB8500v2 has 0x0038
-                */
-               { .reg = D40_DREG_PERIPHID3, .val = 0x0000},
-               /* PCell Id */
-               { .reg = D40_DREG_CELLID0, .val = 0x000d},
-               { .reg = D40_DREG_CELLID1, .val = 0x00f0},
-               { .reg = D40_DREG_CELLID2, .val = 0x0005},
-               { .reg = D40_DREG_CELLID3, .val = 0x00b1}
-       };
        struct stedma40_platform_data *plat_data;
        struct clk *clk = NULL;
        void __iomem *virtbase = NULL;
        int num_log_chans = 0;
        int num_phy_chans;
        int i;
-       u32 val;
-       u32 rev;
+       u32 pid;
+       u32 cid;
+       u8 rev;
  
        clk = clk_get(&pdev->dev, NULL);
  
        if (!virtbase)
                goto failure;
  
-       /* HW version check */
-       for (i = 0; i < ARRAY_SIZE(dma_id_regs); i++) {
-               if (dma_id_regs[i].val !=
-                   readl(virtbase + dma_id_regs[i].reg)) {
-                       d40_err(&pdev->dev,
-                               "Unknown hardware! Expected 0x%x at 0x%x but got 0x%x\n",
-                               dma_id_regs[i].val,
-                               dma_id_regs[i].reg,
-                               readl(virtbase + dma_id_regs[i].reg));
-                       goto failure;
-               }
-       }
+       /* This is just a regular AMBA PrimeCell ID actually */
+       for (pid = 0, i = 0; i < 4; i++)
+               pid |= (readl(virtbase + resource_size(res) - 0x20 + 4 * i)
+                       & 255) << (i * 8);
+       for (cid = 0, i = 0; i < 4; i++)
+               cid |= (readl(virtbase + resource_size(res) - 0x10 + 4 * i)
+                       & 255) << (i * 8);
  
-       /* Get silicon revision and designer */
-       val = readl(virtbase + D40_DREG_PERIPHID2);
-       if ((val & D40_DREG_PERIPHID2_DESIGNER_MASK) !=
-           D40_HW_DESIGNER) {
+       if (cid != AMBA_CID) {
+               d40_err(&pdev->dev, "Unknown hardware! No PrimeCell ID\n");
+               goto failure;
+       }
+       if (AMBA_MANF_BITS(pid) != AMBA_VENDOR_ST) {
                d40_err(&pdev->dev, "Unknown designer! Got %x wanted %x\n",
-                       val & D40_DREG_PERIPHID2_DESIGNER_MASK,
-                       D40_HW_DESIGNER);
+                       AMBA_MANF_BITS(pid),
+                       AMBA_VENDOR_ST);
                goto failure;
        }
-       rev = (val & D40_DREG_PERIPHID2_REV_MASK) >>
-               D40_DREG_PERIPHID2_REV_POS;
+       /*
+        * HW revision:
+        * DB8500ed has revision 0
+        * ? has revision 1
+        * DB8500v1 has revision 2
+        * DB8500v2 has revision 3
+        */
+       rev = AMBA_REV_BITS(pid);
  
        /* The number of physical channels on this HW */
        num_phy_chans = 4 * (readl(virtbase + D40_DREG_ICFG) & 0x7) + 4;