dmaengine: dw-axi-dmac: Add support DMAX_NUM_CHANNELS > 16
authorSergey Khimich <serghox@gmail.com>
Tue, 10 Oct 2023 10:14:50 +0000 (13:14 +0300)
committerVinod Koul <vkoul@kernel.org>
Mon, 16 Oct 2023 11:08:10 +0000 (16:38 +0530)
Added support for DMA controller with more than 16 channels.

Signed-off-by: Sergey Khimich <serghox@gmail.com>
Link: https://lore.kernel.org/r/20231010101450.2949126-2-serghox@gmail.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>
drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
drivers/dma/dw-axi-dmac/dw-axi-dmac.h

index 974da2fda2e43265e891fa90047ad85d2d6dce8b..a86a81ff0caa62e7467012a6a273325f5efad5dd 100644 (file)
@@ -62,6 +62,17 @@ static inline u32 axi_dma_ioread32(struct axi_dma_chip *chip, u32 reg)
        return ioread32(chip->regs + reg);
 }
 
+static inline void
+axi_dma_iowrite64(struct axi_dma_chip *chip, u32 reg, u64 val)
+{
+       iowrite64(val, chip->regs + reg);
+}
+
+static inline u64 axi_dma_ioread64(struct axi_dma_chip *chip, u32 reg)
+{
+       return ioread64(chip->regs + reg);
+}
+
 static inline void
 axi_chan_iowrite32(struct axi_dma_chan *chan, u32 reg, u32 val)
 {
@@ -182,38 +193,73 @@ static inline u32 axi_chan_irq_read(struct axi_dma_chan *chan)
 
 static inline void axi_chan_disable(struct axi_dma_chan *chan)
 {
-       u32 val;
-
-       val = axi_dma_ioread32(chan->chip, DMAC_CHEN);
-       val &= ~(BIT(chan->id) << DMAC_CHAN_EN_SHIFT);
-       if (chan->chip->dw->hdata->reg_map_8_channels)
-               val |=   BIT(chan->id) << DMAC_CHAN_EN_WE_SHIFT;
-       else
-               val |=   BIT(chan->id) << DMAC_CHAN_EN2_WE_SHIFT;
-       axi_dma_iowrite32(chan->chip, DMAC_CHEN, val);
+       u64 val;
+
+       if (chan->chip->dw->hdata->nr_channels >= DMAC_CHAN_16) {
+               val = axi_dma_ioread64(chan->chip, DMAC_CHEN);
+               if (chan->id >= DMAC_CHAN_16) {
+                       val &= ~((u64)(BIT(chan->id) >> DMAC_CHAN_16)
+                               << (DMAC_CHAN_EN_SHIFT + DMAC_CHAN_BLOCK_SHIFT));
+                       val |=   (u64)(BIT(chan->id) >> DMAC_CHAN_16)
+                               << (DMAC_CHAN_EN2_WE_SHIFT + DMAC_CHAN_BLOCK_SHIFT);
+               } else {
+                       val &= ~(BIT(chan->id) << DMAC_CHAN_EN_SHIFT);
+                       val |=   BIT(chan->id) << DMAC_CHAN_EN2_WE_SHIFT;
+               }
+               axi_dma_iowrite64(chan->chip, DMAC_CHEN, val);
+       } else {
+               val = axi_dma_ioread32(chan->chip, DMAC_CHEN);
+               val &= ~(BIT(chan->id) << DMAC_CHAN_EN_SHIFT);
+               if (chan->chip->dw->hdata->reg_map_8_channels)
+                       val |=   BIT(chan->id) << DMAC_CHAN_EN_WE_SHIFT;
+               else
+                       val |=   BIT(chan->id) << DMAC_CHAN_EN2_WE_SHIFT;
+               axi_dma_iowrite32(chan->chip, DMAC_CHEN, (u32)val);
+       }
 }
 
 static inline void axi_chan_enable(struct axi_dma_chan *chan)
 {
-       u32 val;
-
-       val = axi_dma_ioread32(chan->chip, DMAC_CHEN);
-       if (chan->chip->dw->hdata->reg_map_8_channels)
-               val |= BIT(chan->id) << DMAC_CHAN_EN_SHIFT |
-                       BIT(chan->id) << DMAC_CHAN_EN_WE_SHIFT;
-       else
-               val |= BIT(chan->id) << DMAC_CHAN_EN_SHIFT |
+       u64 val;
+
+       if (chan->chip->dw->hdata->nr_channels >= DMAC_CHAN_16) {
+               val = axi_dma_ioread64(chan->chip, DMAC_CHEN);
+               if (chan->id >= DMAC_CHAN_16) {
+                       val |= (u64)(BIT(chan->id) >> DMAC_CHAN_16)
+                               << (DMAC_CHAN_EN_SHIFT + DMAC_CHAN_BLOCK_SHIFT) |
+                               (u64)(BIT(chan->id) >> DMAC_CHAN_16)
+                               << (DMAC_CHAN_EN2_WE_SHIFT + DMAC_CHAN_BLOCK_SHIFT);
+               } else {
+                       val |= BIT(chan->id) << DMAC_CHAN_EN_SHIFT |
                        BIT(chan->id) << DMAC_CHAN_EN2_WE_SHIFT;
-       axi_dma_iowrite32(chan->chip, DMAC_CHEN, val);
+               }
+               axi_dma_iowrite64(chan->chip, DMAC_CHEN, val);
+       } else {
+               val = axi_dma_ioread32(chan->chip, DMAC_CHEN);
+               if (chan->chip->dw->hdata->reg_map_8_channels) {
+                       val |= BIT(chan->id) << DMAC_CHAN_EN_SHIFT |
+                       BIT(chan->id) << DMAC_CHAN_EN_WE_SHIFT;
+               } else {
+                       val |= BIT(chan->id) << DMAC_CHAN_EN_SHIFT |
+                               BIT(chan->id) << DMAC_CHAN_EN2_WE_SHIFT;
+               }
+               axi_dma_iowrite32(chan->chip, DMAC_CHEN, (u32)val);
+       }
 }
 
 static inline bool axi_chan_is_hw_enable(struct axi_dma_chan *chan)
 {
-       u32 val;
+       u64 val;
 
-       val = axi_dma_ioread32(chan->chip, DMAC_CHEN);
+       if (chan->chip->dw->hdata->nr_channels >= DMAC_CHAN_16)
+               val = axi_dma_ioread64(chan->chip, DMAC_CHEN);
+       else
+               val = axi_dma_ioread32(chan->chip, DMAC_CHEN);
 
-       return !!(val & (BIT(chan->id) << DMAC_CHAN_EN_SHIFT));
+       if (chan->id >= DMAC_CHAN_16)
+               return !!(val & ((u64)(BIT(chan->id) >> DMAC_CHAN_16) << DMAC_CHAN_BLOCK_SHIFT));
+       else
+               return !!(val & (BIT(chan->id) << DMAC_CHAN_EN_SHIFT));
 }
 
 static void axi_dma_hw_init(struct axi_dma_chip *chip)
@@ -1175,20 +1221,34 @@ static int dma_chan_pause(struct dma_chan *dchan)
        struct axi_dma_chan *chan = dchan_to_axi_dma_chan(dchan);
        unsigned long flags;
        unsigned int timeout = 20; /* timeout iterations */
-       u32 val;
+       u64 val;
 
        spin_lock_irqsave(&chan->vc.lock, flags);
 
-       if (chan->chip->dw->hdata->reg_map_8_channels) {
-               val = axi_dma_ioread32(chan->chip, DMAC_CHEN);
-               val |= BIT(chan->id) << DMAC_CHAN_SUSP_SHIFT |
-                       BIT(chan->id) << DMAC_CHAN_SUSP_WE_SHIFT;
-               axi_dma_iowrite32(chan->chip, DMAC_CHEN, val);
+       if (chan->chip->dw->hdata->nr_channels >= DMAC_CHAN_16) {
+               val = axi_dma_ioread64(chan->chip, DMAC_CHSUSPREG);
+               if (chan->id >= DMAC_CHAN_16) {
+                       val |= (u64)(BIT(chan->id) >> DMAC_CHAN_16)
+                               << (DMAC_CHAN_SUSP2_SHIFT + DMAC_CHAN_BLOCK_SHIFT) |
+                               (u64)(BIT(chan->id) >> DMAC_CHAN_16)
+                               << (DMAC_CHAN_SUSP2_WE_SHIFT + DMAC_CHAN_BLOCK_SHIFT);
+               } else {
+                       val |= BIT(chan->id) << DMAC_CHAN_SUSP2_SHIFT |
+                              BIT(chan->id) << DMAC_CHAN_SUSP2_WE_SHIFT;
+                       }
+                       axi_dma_iowrite64(chan->chip, DMAC_CHSUSPREG, val);
        } else {
-               val = axi_dma_ioread32(chan->chip, DMAC_CHSUSPREG);
-               val |= BIT(chan->id) << DMAC_CHAN_SUSP2_SHIFT |
+               if (chan->chip->dw->hdata->reg_map_8_channels) {
+                       val = axi_dma_ioread32(chan->chip, DMAC_CHEN);
+                       val |= BIT(chan->id) << DMAC_CHAN_SUSP_SHIFT |
+                       BIT(chan->id) << DMAC_CHAN_SUSP_WE_SHIFT;
+                       axi_dma_iowrite32(chan->chip, DMAC_CHEN, (u32)val);
+               } else {
+                       val = axi_dma_ioread32(chan->chip, DMAC_CHSUSPREG);
+                       val |= BIT(chan->id) << DMAC_CHAN_SUSP2_SHIFT |
                        BIT(chan->id) << DMAC_CHAN_SUSP2_WE_SHIFT;
-               axi_dma_iowrite32(chan->chip, DMAC_CHSUSPREG, val);
+                       axi_dma_iowrite32(chan->chip, DMAC_CHSUSPREG, (u32)val);
+               }
        }
 
        do  {
@@ -1210,18 +1270,32 @@ static int dma_chan_pause(struct dma_chan *dchan)
 /* Called in chan locked context */
 static inline void axi_chan_resume(struct axi_dma_chan *chan)
 {
-       u32 val;
-
-       if (chan->chip->dw->hdata->reg_map_8_channels) {
-               val = axi_dma_ioread32(chan->chip, DMAC_CHEN);
-               val &= ~(BIT(chan->id) << DMAC_CHAN_SUSP_SHIFT);
-               val |=  (BIT(chan->id) << DMAC_CHAN_SUSP_WE_SHIFT);
-               axi_dma_iowrite32(chan->chip, DMAC_CHEN, val);
+       u64 val;
+
+       if (chan->chip->dw->hdata->nr_channels >= DMAC_CHAN_16) {
+               val = axi_dma_ioread64(chan->chip, DMAC_CHSUSPREG);
+               if (chan->id >= DMAC_CHAN_16) {
+                       val &= ~((u64)(BIT(chan->id) >> DMAC_CHAN_16)
+                               << (DMAC_CHAN_SUSP2_SHIFT + DMAC_CHAN_BLOCK_SHIFT));
+                       val |=  ((u64)(BIT(chan->id) >> DMAC_CHAN_16)
+                               << (DMAC_CHAN_SUSP2_WE_SHIFT + DMAC_CHAN_BLOCK_SHIFT));
+               } else {
+                       val &= ~(BIT(chan->id) << DMAC_CHAN_SUSP2_SHIFT);
+                       val |=  (BIT(chan->id) << DMAC_CHAN_SUSP2_WE_SHIFT);
+               }
+                       axi_dma_iowrite64(chan->chip, DMAC_CHSUSPREG, val);
        } else {
-               val = axi_dma_ioread32(chan->chip, DMAC_CHSUSPREG);
-               val &= ~(BIT(chan->id) << DMAC_CHAN_SUSP2_SHIFT);
-               val |=  (BIT(chan->id) << DMAC_CHAN_SUSP2_WE_SHIFT);
-               axi_dma_iowrite32(chan->chip, DMAC_CHSUSPREG, val);
+               if (chan->chip->dw->hdata->reg_map_8_channels) {
+                       val = axi_dma_ioread32(chan->chip, DMAC_CHEN);
+                       val &= ~(BIT(chan->id) << DMAC_CHAN_SUSP_SHIFT);
+                       val |=  (BIT(chan->id) << DMAC_CHAN_SUSP_WE_SHIFT);
+                       axi_dma_iowrite32(chan->chip, DMAC_CHEN, (u32)val);
+               } else {
+                       val = axi_dma_ioread32(chan->chip, DMAC_CHSUSPREG);
+                       val &= ~(BIT(chan->id) << DMAC_CHAN_SUSP2_SHIFT);
+                       val |=  (BIT(chan->id) << DMAC_CHAN_SUSP2_WE_SHIFT);
+                       axi_dma_iowrite32(chan->chip, DMAC_CHSUSPREG, (u32)val);
+               }
        }
 
        chan->is_paused = false;
index eb267cb24f6702808f812da0b1a06c9188b3889b..454904d996540c4725c19b93b67f5d0ef8fb6f7c 100644 (file)
@@ -18,7 +18,7 @@
 
 #include "../virt-dma.h"
 
-#define DMAC_MAX_CHANNELS      16
+#define DMAC_MAX_CHANNELS      32
 #define DMAC_MAX_MASTERS       2
 #define DMAC_MAX_BLK_SIZE      0x200000
 
@@ -222,6 +222,10 @@ static inline struct axi_dma_chan *dchan_to_axi_dma_chan(struct dma_chan *dchan)
 /* DMAC_CHEN2 */
 #define DMAC_CHAN_EN2_WE_SHIFT         16
 
+/* DMAC CHAN BLOCKS */
+#define DMAC_CHAN_BLOCK_SHIFT          32
+#define DMAC_CHAN_16                   16
+
 /* DMAC_CHSUSP */
 #define DMAC_CHAN_SUSP2_SHIFT          0
 #define DMAC_CHAN_SUSP2_WE_SHIFT       16