mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-25 11:55:37 +00:00
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:
parent
c1939c2f76
commit
495e18b16e
2 changed files with 117 additions and 39 deletions
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue