dmaengine: dw-axi-dmac: Add support DMAX_NUM_CHANNELS > 16

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>
This commit is contained in:
Sergey Khimich 2023-10-10 13:14:50 +03:00 committed by Vinod Koul
parent c1939c2f76
commit 495e18b16e
2 changed files with 117 additions and 39 deletions

View 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;
u64 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);
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;
u64 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 |
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;
u64 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);
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;

View 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