Dear Ludovic

Check the comments in below:

On 5/27/2014 4:35 PM, Ludovic Desroches wrote:
Introduction of a new atmel DMA controller known as xdmac.

Signed-off-by: Ludovic Desroches <[email protected]>
---

Hi,

All comments are welcomed to improve this driver!

Thanks

  .../devicetree/bindings/dma/atmel-xdma.txt         |   44 +
  drivers/dma/Kconfig                                |    7 +
  drivers/dma/Makefile                               |    1 +
  drivers/dma/at_xdmac.c                             | 1053 ++++++++++++++++++++
  drivers/dma/at_xdmac.h                             |  257 +++++
  include/dt-bindings/dma/at91.h                     |   46 +
  6 files changed, 1408 insertions(+)
  create mode 100644 Documentation/devicetree/bindings/dma/atmel-xdma.txt
  create mode 100644 drivers/dma/at_xdmac.c
  create mode 100644 drivers/dma/at_xdmac.h
[snip]

+
+static int __init at_xdmac_probe(struct platform_device *pdev)
+{
+       struct resource *res;
+       struct at_xdmac *atxdmac;
+       int irq, size, nr_channels, i, ret;
+       void __iomem    *base;
+       u32 reg;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res)
+               return -EINVAL;
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0)
+               return irq;
+
+       base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(base))
+               return PTR_ERR(base);
+
+       /*
+        * Read number of xdmac channels, read helper function can't be used
+        * since atxdmac is not yet allocated and we need to know the number
+        * of channels to do the allocation.
+        */
+       reg = __raw_readl(base + AT_XDMAC_GTYPE);

readl_relaxed() is better.

+       nr_channels = AT_XDMAC_NB_CH(reg);
+       if (nr_channels > AT_XDMAC_MAX_CHAN) {
+               dev_err(&pdev->dev, "invalid number of channels (%u)\n",
+                       nr_channels);
+               return -EINVAL;
+       }
+
+       size = sizeof(*atxdmac);
+       size += nr_channels * sizeof(struct at_xdmac_chan);
+       atxdmac = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
+       if (!atxdmac) {
+               dev_err(&pdev->dev, "can't allocate at_xdmac structure\n");
+               return -ENOMEM;
+       }
+
+       atxdmac->regs = base;
+
+       ret = devm_request_irq(&pdev->dev, irq, at_xdmac_interrupt, 0,
+                              "at_xdmac", atxdmac);
+       if (ret) {
+               dev_err(&pdev->dev, "can't request irq\n");
+               return ret;
+       }
+
+       atxdmac->clk = devm_clk_get(&pdev->dev, "dma_clk");
+       if (IS_ERR(atxdmac->clk)) {
+               dev_err(&pdev->dev, "can't get dma_clk\n");
+               return PTR_ERR(atxdmac->clk);
+       }
+
+       ret = clk_prepare_enable(atxdmac->clk);
+       if (ret) {
+               dev_err(&pdev->dev, "can't prepare or enable clock\n");
+               return ret;
+       }
+
+       atxdmac->at_xdmac_desc_pool =
+               dmam_pool_create(dev_name(&pdev->dev), &pdev->dev,
+                               sizeof(struct at_xdmac_desc), 4, 0);
+       if (!atxdmac->at_xdmac_desc_pool) {
+               dev_err(&pdev->dev, "no memory for descriptors dma pool\n");
+               ret = -ENOMEM;
+               goto err_clk_disable;
+       }
+
+       dma_cap_set(DMA_CYCLIC, atxdmac->dma.cap_mask);
+       dma_cap_set(DMA_MEMCPY, atxdmac->dma.cap_mask);
+       dma_cap_set(DMA_SLAVE, atxdmac->dma.cap_mask);
+       atxdmac->dma.dev                             = &pdev->dev;
+       atxdmac->dma.device_alloc_chan_resources     = 
at_xdmac_alloc_chan_resources;
+       atxdmac->dma.device_free_chan_resources              = 
at_xdmac_free_chan_resources;
+       atxdmac->dma.device_tx_status                        = 
at_xdmac_tx_status;
+       atxdmac->dma.device_issue_pending            = at_xdmac_issue_pending;
+       atxdmac->dma.device_prep_dma_cyclic          = at_xdmac_prep_dma_cyclic;
+       atxdmac->dma.device_prep_dma_memcpy          = at_xdmac_prep_dma_memcpy;
+       atxdmac->dma.device_prep_slave_sg            = at_xdmac_prep_slave_sg;
+       atxdmac->dma.device_control                  = at_xdmac_control;
+       atxdmac->dma.chancnt                         = nr_channels;
+
+       /* Disable all chans and interrupts. */
+       at_xdmac_off(atxdmac);
+
+       /* Init channels. */
+       INIT_LIST_HEAD(&atxdmac->dma.channels);
+       for (i = 0; i < nr_channels; i++) {
+               struct at_xdmac_chan *atchan = &atxdmac->chan[i];
+
+               atchan->chan.device = &atxdmac->dma;
+               list_add_tail(&atchan->chan.device_node,
+                             &atxdmac->dma.channels);
+
+               atchan->ch_regs = at_xdmac_chan_reg_base(atxdmac, i);
+               atchan->mask = 1 << i;
+
+               spin_lock_init(&atchan->lock);
+               INIT_LIST_HEAD(&atchan->xfers_list);
+               INIT_LIST_HEAD(&atchan->free_descs_list);
+               tasklet_init(&atchan->tasklet, at_xdmac_tasklet,
+                            (unsigned long)atchan);
+
+               /* Clear pending interrupts. */
+               while (at_xdmac_chan_read(atchan, AT_XDMAC_CIS))
+                       cpu_relax();
+       }
+       platform_set_drvdata(pdev, atxdmac);
+
+       ret = dma_async_device_register(&atxdmac->dma);
+       if (ret) {
+               dev_err(&pdev->dev, "Failed to register DMA engine device\n");
+               goto err_clk_disable;
+       }
+
+       ret = of_dma_controller_register(pdev->dev.of_node,
+                                        at_xdmac_xlate, atxdmac);
+       if (ret) {
+               dev_err(&pdev->dev, "could not register of dma controller\n");
+               goto err_dma_unregister;
+       }
+
+       dev_info(&pdev->dev, "%d channels, mapped at 0x%p\n",
+                nr_channels, atxdmac->regs);
+
+       return 0;
+
+err_dma_unregister:
+       dma_async_device_unregister(&atxdmac->dma);
+err_clk_disable:
+       clk_disable_unprepare(atxdmac->clk);
+       return ret;
+}
+
+static int at_xdmac_remove(struct platform_device *pdev)
+{
+       struct at_xdmac *atxdmac = (struct at_xdmac 
*)platform_get_drvdata(pdev);
+       int             i;
+
+       at_xdmac_off(atxdmac);
+       of_dma_controller_free(pdev->dev.of_node);
+       dma_async_device_unregister(&atxdmac->dma);
+       clk_disable_unprepare(atxdmac->clk);
+
+       for (i = 0; i < atxdmac->dma.chancnt; i++) {
+               struct at_xdmac_chan *atchan = &atxdmac->chan[i];
+
+               tasklet_kill(&atchan->tasklet);
+               at_xdmac_free_chan_resources(&atchan->chan);
+       }
+
+       return 0;
+}
+
+static const struct of_device_id atmel_xdmac_dt_ids[] = {
+       {
+               .compatible = "atmel,sama5d4-dma",
+       }, {
+               /* sentinel */
+       }
+};
+MODULE_DEVICE_TABLE(of, atmel_xdmac_dt_ids);
+
+static struct platform_driver at_xdmac_driver = {
+       .probe          = at_xdmac_probe,

This line can be removed. Otherwise you will get section mismatch warning.

+       .remove         = at_xdmac_remove,
+       .driver = {
+               .name           = "at_xdmac",
+               .of_match_table = of_match_ptr(atmel_xdmac_dt_ids),
+       }
+};
+
+static int __init at_xdmac_init(void)
+{
+       return platform_driver_probe(&at_xdmac_driver, at_xdmac_probe);
+}
+subsys_initcall(at_xdmac_init);
+
+MODULE_DESCRIPTION("Atmel Extended DMA Controller driver");
+MODULE_AUTHOR("Ludovic Desroches <[email protected]>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/dma/at_xdmac.h b/drivers/dma/at_xdmac.h
new file mode 100644
index 0000000..79e5ad8
--- /dev/null
+++ b/drivers/dma/at_xdmac.h
@@ -0,0 +1,257 @@
+#ifndef __AT_XDMAC_H__
+#define __AT_XDMAC_H__
+
+#include <linux/clk.h>
+#include <linux/dmaengine.h>
+#include <linux/dmapool.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/of_dma.h>
+#include <linux/platform_device.h>
+
+#include "dmaengine.h"
+
+/* Global registers */
+#define AT_XDMAC_GTYPE         0x00    /* Global Type Register */
+#define                AT_XDMAC_NB_CH(i)       (((i) & 0x1F) + 1)          /* 
Number of Channels Minus One */
+#define                AT_XDMAC_FIFO_SZ(i)     (((i) >> 5) & 0x7FF)          
/* Number of Bytes */
+#define                AT_XDMAC_NB_REQ(i)      ((((i) >> 16) & 0x3F) + 1)    
/* Number of Peripheral Requests Minus One */
+#define AT_XDMAC_GCFG          0x04    /* Global Configuration Register */
+#define AT_XDMAC_GWAC          0x08    /* Global Weighted Arbiter 
Configuration Register */
+#define AT_XDMAC_GIE           0x0C    /* Global Interrupt Enable Register */
+#define AT_XDMAC_GID           0x10    /* Global Interrupt Disable Register */
+#define AT_XDMAC_GIM           0x14    /* Global Interrupt Mask Register */
+#define AT_XDMAC_GIS           0x18    /* Global Interrupt Status Register */
+#define AT_XDMAC_GE            0x1C    /* Global Channel Enable Register */
+#define AT_XDMAC_GD            0x20    /* Global Channel Disable Register */
+#define AT_XDMAC_GS            0x24    /* Global Channel Status Register */
+#define AT_XDMAC_GRS           0x28    /* Global Channel Read Suspend Register 
*/
+#define AT_XDMAC_GWS           0x2C    /* Global Write Suspend Register */
+#define AT_XDMAC_GRWS          0x30    /* Global Channel Read Write Suspend 
Register */
+#define AT_XDMAC_GRWR          0x34    /* Global Channel Read Write Resume 
Register */
+#define AT_XDMAC_GSWR          0x38    /* Global Channel Software Request 
Register */
+#define AT_XDMAC_GSWS          0x3C    /* Global channel Software Request 
Status Register */
+#define AT_XDMAC_GSWF          0x40    /* Global Channel Software Flush 
Request Register */
+#define AT_XDMAC_VERSION       0xFFC   /* XDMAC Version Register */
+
+/* Channel relative registers offsets */
+#define AT_XDMAC_CIE           0x00    /* Channel Interrupt Enable Register */
+#define                AT_XDMAC_CIE_BIE        (0x1 << 0)        /* End of 
Block Interrupt Enable Bit */
+#define                AT_XDMAC_CIE_LIE        (0x1 << 1)        /* End of 
Linked List Interrupt Enable Bit */
+#define                AT_XDMAC_CIE_DIE        (0x1 << 2)        /* End of 
Disable Interrupt Enable Bit */
+#define                AT_XDMAC_CIE_FIE        (0x1 << 3)        /* End of 
Flush Interrupt Enable Bit */
+#define                AT_XDMAC_CIE_RBEIE      (0x1 << 4)        /* Read Bus 
Error Interrupt Enable Bit */
+#define                AT_XDMAC_CIE_WBEIE      (0x1 << 5)        /* Write Bus 
Error Interrupt Enable Bit */
+#define                AT_XDMAC_CIE_ROIE       (0x1 << 6)        /* Request 
Overflow Interrupt Enable Bit */
+#define AT_XDMAC_CID           0x04    /* Channel Interrupt Disable Register */
+#define                AT_XDMAC_CID_BID        (0x1 << 0)        /* End of 
Block Interrupt Disable Bit */
+#define                AT_XDMAC_CID_LID        (0x1 << 1)        /* End of 
Linked List Interrupt Disable Bit */
+#define                AT_XDMAC_CID_DID        (0x1 << 2)        /* End of 
Disable Interrupt Disable Bit */
+#define                AT_XDMAC_CID_FID        (0x1 << 3)        /* End of 
Flush Interrupt Disable Bit */
+#define                AT_XDMAC_CID_RBEID      (0x1 << 4)        /* Read Bus 
Error Interrupt Disable Bit */
+#define                AT_XDMAC_CID_WBEID      (0x1 << 5)        /* Write Bus 
Error Interrupt Disable Bit */
+#define                AT_XDMAC_CID_ROID       (0x1 << 6)        /* Request 
Overflow Interrupt Disable Bit */
+#define AT_XDMAC_CIM           0x08    /* Channel Interrupt Mask Register */
+#define                AT_XDMAC_CIM_BIM        (0x1 << 0)        /* End of 
Block Interrupt Mask Bit */
+#define                AT_XDMAC_CIM_LIM        (0x1 << 1)        /* End of 
Linked List Interrupt Mask Bit */
+#define                AT_XDMAC_CIM_DIM        (0x1 << 2)        /* End of 
Disable Interrupt Mask Bit */
+#define                AT_XDMAC_CIM_FIM        (0x1 << 3)        /* End of 
Flush Interrupt Mask Bit */
+#define                AT_XDMAC_CIM_RBEIM      (0x1 << 4)        /* Read Bus 
Error Interrupt Mask Bit */
+#define                AT_XDMAC_CIM_WBEIM      (0x1 << 5)        /* Write Bus 
Error Interrupt Mask Bit */
+#define                AT_XDMAC_CIM_ROIM       (0x1 << 6)        /* Request 
Overflow Interrupt Mask Bit */
+#define AT_XDMAC_CIS           0x0C    /* Channel Interrupt Status Register */
+#define                AT_XDMAC_CIS_BIS        (0x1 << 0)        /* End of 
Block Interrupt Status Bit */
+#define                AT_XDMAC_CIS_LIS        (0x1 << 1)        /* End of 
Linked List Interrupt Status Bit */
+#define                AT_XDMAC_CIS_DIS        (0x1 << 2)        /* End of 
Disable Interrupt Status Bit */
+#define                AT_XDMAC_CIS_FIS        (0x1 << 3)        /* End of 
Flush Interrupt Status Bit */
+#define                AT_XDMAC_CIS_RBEIS      (0x1 << 4)        /* Read Bus 
Error Interrupt Status Bit */
+#define                AT_XDMAC_CIS_WBEIS      (0x1 << 5)        /* Write Bus 
Error Interrupt Status Bit */
+#define                AT_XDMAC_CIS_ROIS       (0x1 << 6)        /* Request 
Overflow Interrupt Status Bit */
+#define AT_XDMAC_CSA           0x10    /* Channel Source Address Register */
+#define AT_XDMAC_CDA           0x14    /* Channel Destination Address Register 
*/
+#define AT_XDMAC_CNDA          0x18    /* Channel Next Descriptor Address 
Register */
+#define                AT_XDMAC_CNDA_NDAIF(i)  ((i) & 0x1)                 /* 
Channel x Next Descriptor Interface */
+#define                AT_XDMAC_CNDA_NDA(i)    ((i) & 0xfffffffc)          /* 
Channel x Next Descriptor Address */
+#define AT_XDMAC_CNDC          0x1C    /* Channel Next Descriptor Control 
Register */
+#define                AT_XDMAC_CNDC_NDE               (0x1 << 0)              
  /* Channel x Next Descriptor Enable */
+#define                AT_XDMAC_CNDC_NDSUP             (0x1 << 1)              
  /* Channel x Next Descriptor Source Update */
+#define                AT_XDMAC_CNDC_NDDUP             (0x1 << 2)              
  /* Channel x Next Descriptor Destination Update */
+#define                AT_XDMAC_CNDC_NDVIEW_NDV0       (0x0 << 3)              
  /* Channel x Next Descriptor View 0 */
+#define                AT_XDMAC_CNDC_NDVIEW_NDV1       (0x1 << 3)              
  /* Channel x Next Descriptor View 1 */
+#define                AT_XDMAC_CNDC_NDVIEW_NDV2       (0x2 << 3)              
  /* Channel x Next Descriptor View 2 */
+#define                AT_XDMAC_CNDC_NDVIEW_NDV3       (0x3 << 3)              
  /* Channel x Next Descriptor View 3 */
+#define AT_XDMAC_CUBC          0x20    /* Channel Microblock Control Register 
*/
+#define AT_XDMAC_CBC           0x24    /* Channel Block Control Register */
+#define AT_XDMAC_CC            0x28    /* Channel Configuration Register */
+#define                AT_XDMAC_CC_TYPE        (0x1 << 0)        /* Channel 
Transfer Type */
+#define                        AT_XDMAC_CC_TYPE_MEM_TRAN       (0x0 << 0)      
  /* Memory to Memory Transfer */
+#define                        AT_XDMAC_CC_TYPE_PER_TRAN       (0x1 << 0)      
  /* Peripheral to Memory or Memory to Peripheral Transfer */
+#define                AT_XDMAC_CC_MBSIZE_MASK (0x3 << 1)
+#define                        AT_XDMAC_CC_MBSIZE_SINGLE       (0x0 << 1)
+#define                        AT_XDMAC_CC_MBSIZE_FOUR         (0x1 << 1)
+#define                        AT_XDMAC_CC_MBSIZE_EIGHT        (0x2 << 1)
+#define                        AT_XDMAC_CC_MBSIZE_SIXTEEN      (0x3 << 1)
+#define                AT_XDMAC_CC_DSYNC       (0x1 << 4)        /* Channel 
Synchronization */
+#define                        AT_XDMAC_CC_DSYNC_PER2MEM       (0x0 << 4)
+#define                        AT_XDMAC_CC_DSYNC_MEM2PER       (0x1 << 4)
+#define                AT_XDMAC_CC_PROT        (0x1 << 5)        /* Channel 
Protection */
+#define                        AT_XDMAC_CC_PROT_SEC            (0x0 << 5)
+#define                        AT_XDMAC_CC_PROT_UNSEC          (0x1 << 5)
+#define                AT_XDMAC_CC_SWREQ       (0x1 << 6)        /* Channel 
Software Request Trigger */
+#define                        AT_XDMAC_CC_SWREQ_HWR_CONNECTED (0x0 << 6)
+#define                        AT_XDMAC_CC_SWREQ_SWR_CONNECTED (0x1 << 6)
+#define                AT_XDMAC_CC_MEMSET      (0x1 << 7)        /* Channel 
Fill Block of memory */
+#define                        AT_XDMAC_CC_MEMSET_NORMAL_MODE  (0x0 << 7)
+#define                        AT_XDMAC_CC_MEMSET_HW_MODE      (0x1 << 7)
+#define                AT_XDMAC_CC_CSIZE_MASK  (0x7 << 8)        /* Channel 
Chunk Size */
+#define                        AT_XDMAC_CC_CSIZE_CHK_1         (0x0 << 8)
+#define                        AT_XDMAC_CC_CSIZE_CHK_2         (0x1 << 8)
+#define                        AT_XDMAC_CC_CSIZE_CHK_4         (0x2 << 8)
+#define                        AT_XDMAC_CC_CSIZE_CHK_8         (0x3 << 8)
+#define                        AT_XDMAC_CC_CSIZE_CHK_16        (0x4 << 8)
+#define                AT_XDMAC_CC_DWIDTH(i)   ((i) << 11)       /* Channel 
Data Width */
+#define                        AT_XDMAC_CC_DWIDTH_BYTE         0x0
+#define                        AT_XDMAC_CC_DWIDTH_HALFWORD     0x1
+#define                        AT_XDMAC_CC_DWIDTH_WORD         0x2
+#define                        AT_XDMAC_CC_DWIDTH_DWORD        0x3
+#define                AT_XDMAC_CC_SIF(i)      ((0x1 & (i)) << 13)   /* 
Channel Source Interface Identifier */
+#define                AT_XDMAC_CC_DIF(i)      ((0x1 & (i)) << 14)   /* 
Channel Destination Interface Identifier */
+#define                AT_XDMAC_CC_SAM_MASK    (0x3 << 16)       /* Channel 
Source Addressing Mode */
+#define                        AT_XDMAC_CC_SAM_FIXED_AM        (0x0 << 16)
+#define                        AT_XDMAC_CC_SAM_INCREMENTED_AM  (0x1 << 16)
+#define                        AT_XDMAC_CC_SAM_UBS_AM          (0x2 << 16)
+#define                        AT_XDMAC_CC_SAM_UBS_DS_AM       (0x3 << 16)
+#define                AT_XDMAC_CC_DAM_MASK    (0x3 << 18)       /* Channel 
Source Addressing Mode */
+#define                        AT_XDMAC_CC_DAM_FIXED_AM        (0x0 << 18)
+#define                        AT_XDMAC_CC_DAM_INCREMENTED_AM  (0x1 << 18)
+#define                        AT_XDMAC_CC_DAM_UBS_AM          (0x2 << 18)
+#define                        AT_XDMAC_CC_DAM_UBS_DS_AM       (0x3 << 18)
+#define                AT_XDMAC_CC_INITD       (0x1 << 21)       /* Channel 
Initialization Terminated (read only) */
+#define                        AT_XDMAC_CC_INITD_TERMINATED    (0x0 << 21)
+#define                        AT_XDMAC_CC_INITD_IN_PROGRESS   (0x1 << 21)
+#define                AT_XDMAC_CC_RDIP        (0x1 << 22)       /* Read in 
Progress (read only) */
+#define                        AT_XDMAC_CC_RDIP_DONE           (0x0 << 22)
+#define                        AT_XDMAC_CC_RDIP_IN_PROGRESS    (0x1 << 22)
+#define                AT_XDMAC_CC_WDIP        (0x1 << 23)       /* Write in 
Progress (read only) */
+#define                        AT_XDMAC_CC_WDIP_DONE           (0x0 << 23)
+#define                        AT_XDMAC_CC_WDIP_IN_PROGRESS    (0x1 << 23)
+#define                AT_XDMAC_CC_PERID(i)    (0x7f & (h) << 24)    /* 
Channel Peripheral Identifier */
+#define AT_XDMAC_CDS_MSP       0x2C    /* Channel Data Stride Memory Set 
Pattern */
+#define AT_XDMAC_CSUS          0x30    /* Channel Source Microblock Stride */
+#define AT_XDMAC_CDUS          0x34    /* Channel Destination Microblock 
Stride */
+
+#define AT_XDMAC_CHAN_REG_BASE 0x50    /* Channel registers base address */
+
+/* Microblock control members */
+#define AT_XDMAC_MBR_UBC_UBLEN_MAX     0xFFFFFFUL      /* Maximum Microblock 
Length */
+#define AT_XDMAC_MBR_UBC_NDE           (0x1 << 24)       /* Next Descriptor 
Enable */
+#define AT_XDMAC_MBR_UBC_NSEN          (0x1 << 25)       /* Next Descriptor 
Source Update */
+#define AT_XDMAC_MBR_UBC_NDEN          (0x1 << 26)       /* Next Descriptor 
Destination Update */
+#define AT_XDMAC_MBR_UBC_NDV0          (0x0 << 27)       /* Next Descriptor 
View 0 */
+#define AT_XDMAC_MBR_UBC_NDV1          (0x1 << 27)       /* Next Descriptor 
View 1 */
+#define AT_XDMAC_MBR_UBC_NDV2          (0x2 << 27)       /* Next Descriptor 
View 2 */
+#define AT_XDMAC_MBR_UBC_NDV3          (0x3 << 27)       /* Next Descriptor 
View 3 */
+
+#define AT_XDMAC_MAX_CHAN      0x20
+
+enum atc_status {
+       AT_XDMAC_CHAN_IS_CYCLIC = 0,
+};
+
+/* ----- Channels ----- */
+struct at_xdmac_chan {
+       struct dma_chan chan;
+       void __iomem    *ch_regs;
+       u32             mask;           /* Channel Mask */
+       u32             cfg;            /* Channel Configuration Register */
+       u8              perid;          /* Peripheral ID */
+       u8              dwidth;         /* Data Width */
+       u8              csize;          /* Chunk Size */
+       u8              mbsize;         /* Memory Burst Size */
+       u8              perif;          /* Peripheral Interface */
+       u8              memif;          /* Memory Interface */
+       unsigned long   status;
+       struct tasklet_struct   tasklet;
+       struct dma_slave_config dma_sconfig;
+
+       spinlock_t              lock;
+
+       struct list_head        xfers_list;
+       struct list_head        free_descs_list;
+};
+
+
+/* ----- Controller ----- */
+struct at_xdmac {
+       struct dma_device       dma;
+       void __iomem            *regs;
+       struct clk              *clk;
+       struct dma_pool         *at_xdmac_desc_pool;
+       struct at_xdmac_chan    chan[0];
+};
+
+
+/* ----- Descriptors ----- */
+
+/* Linked List Descriptor */
+struct at_xdmac_lld {
+       dma_addr_t      mbr_nda;        /* Next Descriptor Member */
+       u32             mbr_ubc;        /* Microblock Control Member */
+       dma_addr_t      mbr_sa;         /* Source Address Member */
+       dma_addr_t      mbr_da;         /* Destination Address Member */
+       u32             mbr_cfg;        /* Configuration Register */
+};
+
+
+struct at_xdmac_desc {
+       struct at_xdmac_lld             lld;
+       enum dma_transfer_direction     direction;
+       struct dma_async_tx_descriptor  tx_dma_desc;
+       struct list_head                desc_node;
+       /* Following members are only used by the first descriptor */
+       bool                            active_xfer;
+       unsigned int                    xfer_size;
+       struct list_head                descs_list;
+       struct list_head                xfer_node;
+};
+
+static inline void __iomem *at_xdmac_chan_reg_base(struct at_xdmac *atxdmac, 
unsigned int chan_nb)
+{
+       return (void __iomem *)(atxdmac->regs + (AT_XDMAC_CHAN_REG_BASE + 
chan_nb * 0x40));
+}
+
+#define at_xdmac_read(atxdmac, reg) __raw_readl((atxdmac)->regs + (reg))
+#define at_xdmac_write(atxdmac, reg, value) \
+       __raw_writel((value), (atxdmac)->regs + (reg))
+
+#define at_xdmac_chan_read(atchan, reg) __raw_readl((atchan)->ch_regs + (reg))
+#define at_xdmac_chan_write(atchan, reg, value) __raw_writel((value), 
(atchan)->ch_regs + (reg))

It's better to use readl_relaxed/writel_relaxed for the register access.
The xxx_relaxed() can be optimized, such like put to different CPU to execute parallely, If you don't want that happen, you can use writel() instead, not __raw_writel().

Best Regards,
Josh Wu

+
+static inline struct at_xdmac_chan *to_at_xdmac_chan(struct dma_chan *dchan)
+{
+       return container_of(dchan, struct at_xdmac_chan, chan);
+}
+
+static struct device *chan2dev(struct dma_chan *chan)
+{
+       return &chan->dev->device;
+}
+
+static inline struct at_xdmac *to_at_xdmac(struct dma_device *ddev)
+{
+       return container_of(ddev, struct at_xdmac, dma);
+}
+
+static inline struct at_xdmac_desc *txd_to_at_desc(struct 
dma_async_tx_descriptor *txd)
+{
+       return container_of(txd, struct at_xdmac_desc, tx_dma_desc);
+}
+
+static inline int at_xdmac_chan_is_cyclic(struct at_xdmac_chan *atchan)
+{
+       return test_bit(AT_XDMAC_CHAN_IS_CYCLIC, &atchan->status);
+}
+
+#endif /* __AT_XDMAC_H__ */
diff --git a/include/dt-bindings/dma/at91.h b/include/dt-bindings/dma/at91.h
index e835037..bef5b68 100644
--- a/include/dt-bindings/dma/at91.h
+++ b/include/dt-bindings/dma/at91.h
@@ -9,6 +9,8 @@
  #ifndef __DT_BINDINGS_AT91_DMA_H__
  #define __DT_BINDINGS_AT91_DMA_H__
+/* ---------- HDMAC ---------- */
+
  /*
   * Source and/or destination peripheral ID
   */
@@ -24,4 +26,48 @@
  #define AT91_DMA_CFG_FIFOCFG_ALAP     (0x1 << AT91_DMA_CFG_FIFOCFG_OFFSET)    
  /* largest defined AHB burst */
  #define AT91_DMA_CFG_FIFOCFG_ASAP     (0x2 << AT91_DMA_CFG_FIFOCFG_OFFSET)    
  /* single AHB access */
+
+/* ---------- XDMAC ---------- */
+#define AT91_XDMAC_DT_MEM_IF_MASK      (0x1)
+#define AT91_XDMAC_DT_MEM_IF_OFFSET    (16)
+#define AT91_XDMAC_DT_MEM_IF(mem_if)   (((mem_if) & AT91_XDMAC_DT_MEM_IF_MASK) 
\
+                                       << AT91_XDMAC_DT_MEM_IF_OFFSET)
+#define AT91_XDMAC_DT_GET_MEM_IF(cfg)  (((cfg) >> AT91_XDMAC_DT_MEM_IF_OFFSET) 
\
+                                       & AT91_XDMAC_DT_MEM_IF_MASK)
+
+#define AT91_XDMAC_DT_PER_IF_MASK      (0x1)
+#define AT91_XDMAC_DT_PER_IF_OFFSET    (0)
+#define AT91_XDMAC_DT_PER_IF(per_if)   (((per_if) & AT91_XDMAC_DT_PER_IF_MASK) 
\
+                                       << AT91_XDMAC_DT_PER_IF_OFFSET)
+#define AT91_XDMAC_DT_GET_PER_IF(cfg)  (((cfg) >> AT91_XDMAC_DT_PER_IF_OFFSET) 
\
+                                       & AT91_XDMAC_DT_PER_IF_MASK)
+
+#define AT91_XDMAC_DT_PERID_MASK       (0x7f)
+#define AT91_XDMAC_DT_PERID_OFFSET     (24)
+#define AT91_XDMAC_DT_PERID(perid)     (((perid) & AT91_XDMAC_DT_PERID_MASK) \
+                                       << AT91_XDMAC_DT_PERID_OFFSET)
+#define AT91_XDMAC_DT_GET_PERID(cfg)   (((cfg) >> AT91_XDMAC_DT_PERID_OFFSET) \
+                                       & AT91_XDMAC_DT_PERID_MASK)
+
+#define AT91_XDMAC_DT_DWIDTH_MASK      (0x3)
+#define AT91_XDMAC_DT_DWIDTH_OFFSET    (11)
+#define AT91_XDMAC_DT_DWIDTH(dwidth)   (((dwidth) & AT91_XDMAC_DT_DWIDTH_MASK) 
\
+                                       << AT91_XDMAC_DT_DWIDTH_OFFSET)
+#define AT91_XDMAC_DT_GET_DWIDTH(cfg)  (((cfg) >> AT91_XDMAC_DT_DWIDTH_OFFSET) 
\
+                                       & AT91_XDMAC_DT_DWIDTH_MASK)
+
+#define AT91_XDMAC_DT_CSIZE_MASK       (0x7)
+#define AT91_XDMAC_DT_CSIZE_OFFSET     (8)
+#define AT91_XDMAC_DT_CSIZE(csize)     (((csize) & AT91_XDMAC_DT_CSIZE_MASK)  \
+                                       << AT91_XDMAC_DT_CSIZE_OFFSET)
+#define AT91_XDMAC_DT_GET_CSIZE(cfg)   (((cfg) >> AT91_XDMAC_DT_CSIZE_OFFSET) \
+                                       & AT91_XDMAC_DT_CSIZE_MASK)
+
+#define AT91_XDMAC_DT_MBSIZE_MASK      (0x3)
+#define AT91_XDMAC_DT_MBSIZE_OFFSET    (1)
+#define AT91_XDMAC_DT_MBSIZE(mbsize)   (((mbsize) & AT91_XDMAC_DT_MBSIZE_MASK) 
\
+                                       << AT91_XDMAC_DT_MBSIZE_OFFSET)
+#define AT91_XDMAC_DT_GET_MBSIZE(cfg)  (((cfg) >> AT91_XDMAC_DT_MBSIZE_OFFSET) 
\
+                                       & AT91_XDMAC_DT_MBSIZE_MASK)
+
  #endif /* __DT_BINDINGS_AT91_DMA_H__ */

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to