SAMA7G5 SoC uses a slightly different variant of the AT_XDMAC.
Added support by a new compatible and a layout struct that copes
to the specific version considering the compatible string.
Only the differences in register map are present in the layout struct.
I reworked the register access for this part that has the differences.
Also the Source/Destination Interface bits are no longer valid for this
variant of the XDMAC. Thus, the layout also has a bool for specifying
whether these bits are required or not.

Signed-off-by: Eugen Hristev <[email protected]>
---
 drivers/dma/at_xdmac.c      | 99 ++++++++++++++++++++++++++++++-------
 drivers/dma/at_xdmac_regs.h |  9 ----
 2 files changed, 82 insertions(+), 26 deletions(-)

diff --git a/drivers/dma/at_xdmac.c b/drivers/dma/at_xdmac.c
index 81bb90206092..874484a4e79f 100644
--- a/drivers/dma/at_xdmac.c
+++ b/drivers/dma/at_xdmac.c
@@ -38,6 +38,27 @@ enum atc_status {
        AT_XDMAC_CHAN_IS_PAUSED,
 };
 
+struct at_xdmac_layout {
+       /* Global Channel Read Suspend Register */
+       u8                              grs;
+       /* Global Write Suspend Register */
+       u8                              gws;
+       /* Global Channel Read Write Suspend Register */
+       u8                              grws;
+       /* Global Channel Read Write Resume Register */
+       u8                              grwr;
+       /* Global Channel Software Request Register */
+       u8                              gswr;
+       /* Global channel Software Request Status Register */
+       u8                              gsws;
+       /* Global Channel Software Flush Request Register */
+       u8                              gswf;
+       /* Channel reg base */
+       u8                              chan_cc_reg_base;
+       /* Source/Destination Interface must be specified or not */
+       bool                            sdif;
+};
+
 /* ----- Channels ----- */
 struct at_xdmac_chan {
        struct dma_chan                 chan;
@@ -71,6 +92,7 @@ struct at_xdmac {
        struct clk              *clk;
        u32                     save_gim;
        struct dma_pool         *at_xdmac_desc_pool;
+       const struct at_xdmac_layout    *layout;
        struct at_xdmac_chan    chan[];
 };
 
@@ -103,9 +125,33 @@ struct at_xdmac_desc {
        struct list_head                xfer_node;
 } __aligned(sizeof(u64));
 
+static struct at_xdmac_layout at_xdmac_sama5d4_layout = {
+       .grs = 0x28,
+       .gws = 0x2C,
+       .grws = 0x30,
+       .grwr = 0x34,
+       .gswr = 0x38,
+       .gsws = 0x3C,
+       .gswf = 0x40,
+       .chan_cc_reg_base = 0x50,
+       .sdif = true,
+};
+
+static struct at_xdmac_layout at_xdmac_sama7g5_layout = {
+       .grs = 0x30,
+       .gws = 0x38,
+       .grws = 0x40,
+       .grwr = 0x44,
+       .gswr = 0x48,
+       .gsws = 0x4C,
+       .gswf = 0x50,
+       .chan_cc_reg_base = 0x60,
+       .sdif = false,
+};
+
 static inline void __iomem *at_xdmac_chan_reg_base(struct at_xdmac *atxdmac, 
unsigned int chan_nb)
 {
-       return atxdmac->regs + (AT_XDMAC_CHAN_REG_BASE + chan_nb * 0x40);
+       return atxdmac->regs + (atxdmac->layout->chan_cc_reg_base + chan_nb * 
0x40);
 }
 
 #define at_xdmac_read(atxdmac, reg) readl_relaxed((atxdmac)->regs + (reg))
@@ -204,8 +250,10 @@ static void at_xdmac_start_xfer(struct at_xdmac_chan 
*atchan,
        first->active_xfer = true;
 
        /* Tell xdmac where to get the first descriptor. */
-       reg = AT_XDMAC_CNDA_NDA(first->tx_dma_desc.phys)
-             | AT_XDMAC_CNDA_NDAIF(atchan->memif);
+       reg = AT_XDMAC_CNDA_NDA(first->tx_dma_desc.phys);
+       if (atxdmac->layout->sdif)
+               reg |= AT_XDMAC_CNDA_NDAIF(atchan->memif);
+
        at_xdmac_chan_write(atchan, AT_XDMAC_CNDA, reg);
 
        /*
@@ -400,6 +448,7 @@ static int at_xdmac_compute_chan_conf(struct dma_chan *chan,
                                      enum dma_transfer_direction direction)
 {
        struct at_xdmac_chan    *atchan = to_at_xdmac_chan(chan);
+       struct at_xdmac         *atxdmac = to_at_xdmac(atchan->chan.device);
        int                     csize, dwidth;
 
        if (direction == DMA_DEV_TO_MEM) {
@@ -407,12 +456,14 @@ static int at_xdmac_compute_chan_conf(struct dma_chan 
*chan,
                        AT91_XDMAC_DT_PERID(atchan->perid)
                        | AT_XDMAC_CC_DAM_INCREMENTED_AM
                        | AT_XDMAC_CC_SAM_FIXED_AM
-                       | AT_XDMAC_CC_DIF(atchan->memif)
-                       | AT_XDMAC_CC_SIF(atchan->perif)
                        | AT_XDMAC_CC_SWREQ_HWR_CONNECTED
                        | AT_XDMAC_CC_DSYNC_PER2MEM
                        | AT_XDMAC_CC_MBSIZE_SIXTEEN
                        | AT_XDMAC_CC_TYPE_PER_TRAN;
+               if (atxdmac->layout->sdif)
+                       atchan->cfg |= AT_XDMAC_CC_DIF(atchan->memif)
+                               | AT_XDMAC_CC_SIF(atchan->perif);
+
                csize = ffs(atchan->sconfig.src_maxburst) - 1;
                if (csize < 0) {
                        dev_err(chan2dev(chan), "invalid src maxburst value\n");
@@ -430,12 +481,14 @@ static int at_xdmac_compute_chan_conf(struct dma_chan 
*chan,
                        AT91_XDMAC_DT_PERID(atchan->perid)
                        | AT_XDMAC_CC_DAM_FIXED_AM
                        | AT_XDMAC_CC_SAM_INCREMENTED_AM
-                       | AT_XDMAC_CC_DIF(atchan->perif)
-                       | AT_XDMAC_CC_SIF(atchan->memif)
                        | AT_XDMAC_CC_SWREQ_HWR_CONNECTED
                        | AT_XDMAC_CC_DSYNC_MEM2PER
                        | AT_XDMAC_CC_MBSIZE_SIXTEEN
                        | AT_XDMAC_CC_TYPE_PER_TRAN;
+               if (atxdmac->layout->sdif)
+                       atchan->cfg |=  AT_XDMAC_CC_DIF(atchan->perif)
+                               | AT_XDMAC_CC_SIF(atchan->memif);
+
                csize = ffs(atchan->sconfig.dst_maxburst) - 1;
                if (csize < 0) {
                        dev_err(chan2dev(chan), "invalid src maxburst value\n");
@@ -711,6 +764,7 @@ at_xdmac_interleaved_queue_desc(struct dma_chan *chan,
                                struct data_chunk *chunk)
 {
        struct at_xdmac_desc    *desc;
+       struct at_xdmac         *atxdmac = to_at_xdmac(atchan->chan.device);
        u32                     dwidth;
        unsigned long           flags;
        size_t                  ublen;
@@ -727,10 +781,10 @@ at_xdmac_interleaved_queue_desc(struct dma_chan *chan,
         * flag status.
         */
        u32                     chan_cc = AT_XDMAC_CC_PERID(0x7f)
-                                       | AT_XDMAC_CC_DIF(0)
-                                       | AT_XDMAC_CC_SIF(0)
                                        | AT_XDMAC_CC_MBSIZE_SIXTEEN
                                        | AT_XDMAC_CC_TYPE_MEM_TRAN;
+       if (atxdmac->layout->sdif)
+               chan_cc |= AT_XDMAC_CC_DIF(0) | AT_XDMAC_CC_SIF(0);
 
        dwidth = at_xdmac_align_width(chan, src | dst | chunk->size);
        if (chunk->size >= (AT_XDMAC_MBR_UBC_UBLEN_MAX << dwidth)) {
@@ -893,6 +947,7 @@ at_xdmac_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t 
dest, dma_addr_t src,
                         size_t len, unsigned long flags)
 {
        struct at_xdmac_chan    *atchan = to_at_xdmac_chan(chan);
+       struct at_xdmac         *atxdmac = to_at_xdmac(atchan->chan.device);
        struct at_xdmac_desc    *first = NULL, *prev = NULL;
        size_t                  remaining_size = len, xfer_size = 0, ublen;
        dma_addr_t              src_addr = src, dst_addr = dest;
@@ -911,12 +966,13 @@ at_xdmac_prep_dma_memcpy(struct dma_chan *chan, 
dma_addr_t dest, dma_addr_t src,
        u32                     chan_cc = AT_XDMAC_CC_PERID(0x7f)
                                        | AT_XDMAC_CC_DAM_INCREMENTED_AM
                                        | AT_XDMAC_CC_SAM_INCREMENTED_AM
-                                       | AT_XDMAC_CC_DIF(0)
-                                       | AT_XDMAC_CC_SIF(0)
                                        | AT_XDMAC_CC_MBSIZE_SIXTEEN
                                        | AT_XDMAC_CC_TYPE_MEM_TRAN;
        unsigned long           irqflags;
 
+       if (atxdmac->layout->sdif)
+               chan_cc |= AT_XDMAC_CC_DIF(0) | AT_XDMAC_CC_SIF(0);
+
        dev_dbg(chan2dev(chan), "%s: src=%pad, dest=%pad, len=%zd, 
flags=0x%lx\n",
                __func__, &src, &dest, len, flags);
 
@@ -999,6 +1055,7 @@ static struct at_xdmac_desc 
*at_xdmac_memset_create_desc(struct dma_chan *chan,
                                                         int value)
 {
        struct at_xdmac_desc    *desc;
+       struct at_xdmac         *atxdmac = to_at_xdmac(atchan->chan.device);
        unsigned long           flags;
        size_t                  ublen;
        u32                     dwidth;
@@ -1017,11 +1074,11 @@ static struct at_xdmac_desc 
*at_xdmac_memset_create_desc(struct dma_chan *chan,
        u32                     chan_cc = AT_XDMAC_CC_PERID(0x7f)
                                        | AT_XDMAC_CC_DAM_UBS_AM
                                        | AT_XDMAC_CC_SAM_INCREMENTED_AM
-                                       | AT_XDMAC_CC_DIF(0)
-                                       | AT_XDMAC_CC_SIF(0)
                                        | AT_XDMAC_CC_MBSIZE_SIXTEEN
                                        | AT_XDMAC_CC_MEMSET_HW_MODE
                                        | AT_XDMAC_CC_TYPE_MEM_TRAN;
+       if (atxdmac->layout->sdif)
+               chan_cc |= AT_XDMAC_CC_DIF(0) | AT_XDMAC_CC_SIF(0);
 
        dwidth = at_xdmac_align_width(chan, dst_addr);
 
@@ -1297,7 +1354,7 @@ at_xdmac_tx_status(struct dma_chan *chan, dma_cookie_t 
cookie,
        mask = AT_XDMAC_CC_TYPE | AT_XDMAC_CC_DSYNC;
        value = AT_XDMAC_CC_TYPE_PER_TRAN | AT_XDMAC_CC_DSYNC_PER2MEM;
        if ((desc->lld.mbr_cfg & mask) == value) {
-               at_xdmac_write(atxdmac, AT_XDMAC_GSWF, atchan->mask);
+               at_xdmac_write(atxdmac, atxdmac->layout->gswf, atchan->mask);
                while (!(at_xdmac_chan_read(atchan, AT_XDMAC_CIS) & 
AT_XDMAC_CIS_FIS))
                        cpu_relax();
        }
@@ -1355,7 +1412,7 @@ at_xdmac_tx_status(struct dma_chan *chan, dma_cookie_t 
cookie,
         * FIFO flush ensures that data are really written.
         */
        if ((desc->lld.mbr_cfg & mask) == value) {
-               at_xdmac_write(atxdmac, AT_XDMAC_GSWF, atchan->mask);
+               at_xdmac_write(atxdmac, atxdmac->layout->gswf, atchan->mask);
                while (!(at_xdmac_chan_read(atchan, AT_XDMAC_CIS) & 
AT_XDMAC_CIS_FIS))
                        cpu_relax();
        }
@@ -1620,7 +1677,7 @@ static int at_xdmac_device_pause(struct dma_chan *chan)
                return 0;
 
        spin_lock_irqsave(&atchan->lock, flags);
-       at_xdmac_write(atxdmac, AT_XDMAC_GRWS, atchan->mask);
+       at_xdmac_write(atxdmac, atxdmac->layout->grws, atchan->mask);
        while (at_xdmac_chan_read(atchan, AT_XDMAC_CC)
               & (AT_XDMAC_CC_WRIP | AT_XDMAC_CC_RDIP))
                cpu_relax();
@@ -1643,7 +1700,7 @@ static int at_xdmac_device_resume(struct dma_chan *chan)
                return 0;
        }
 
-       at_xdmac_write(atxdmac, AT_XDMAC_GRWR, atchan->mask);
+       at_xdmac_write(atxdmac, atxdmac->layout->grwr, atchan->mask);
        clear_bit(AT_XDMAC_CHAN_IS_PAUSED, &atchan->status);
        spin_unlock_irqrestore(&atchan->lock, flags);
 
@@ -1845,6 +1902,10 @@ static int at_xdmac_probe(struct platform_device *pdev)
        atxdmac->regs = base;
        atxdmac->irq = irq;
 
+       atxdmac->layout = of_device_get_match_data(&pdev->dev);
+       if (!atxdmac->layout)
+               return -ENODEV;
+
        atxdmac->clk = devm_clk_get(&pdev->dev, "dma_clk");
        if (IS_ERR(atxdmac->clk)) {
                dev_err(&pdev->dev, "can't get dma_clk\n");
@@ -1988,6 +2049,10 @@ static const struct dev_pm_ops atmel_xdmac_dev_pm_ops = {
 static const struct of_device_id atmel_xdmac_dt_ids[] = {
        {
                .compatible = "atmel,sama5d4-dma",
+               .data = &at_xdmac_sama5d4_layout,
+       }, {
+               .compatible = "microchip,sama7g5-dma",
+               .data = &at_xdmac_sama7g5_layout,
        }, {
                /* sentinel */
        }
diff --git a/drivers/dma/at_xdmac_regs.h b/drivers/dma/at_xdmac_regs.h
index 3f7dda4c5743..7b4b4e24de70 100644
--- a/drivers/dma/at_xdmac_regs.h
+++ b/drivers/dma/at_xdmac_regs.h
@@ -22,13 +22,6 @@
 #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 */
@@ -134,8 +127,6 @@
 #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 */
-- 
2.25.1

Reply via email to