Commit 495e18b1 authored by Sergey Khimich's avatar Sergey Khimich Committed by Vinod Koul
Browse files

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



Added support for DMA controller with more than 16 channels.

Signed-off-by: default avatarSergey Khimich <serghox@gmail.com>
Link: https://lore.kernel.org/r/20231010101450.2949126-2-serghox@gmail.com


Signed-off-by: default avatarVinod Koul <vkoul@kernel.org>
parent c1939c2f
Loading
Loading
Loading
Loading
+115 −41
Original line number Diff line number Diff line
@@ -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,37 +193,72 @@ 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;

	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, val);
		axi_dma_iowrite32(chan->chip, DMAC_CHEN, (u32)val);
	}
}

static inline void axi_chan_enable(struct axi_dma_chan *chan)
{
	u32 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) |
				(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_iowrite64(chan->chip, DMAC_CHEN, val);
	} else {
		val = axi_dma_ioread32(chan->chip, DMAC_CHEN);
	if (chan->chip->dw->hdata->reg_map_8_channels)
		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
		} 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_iowrite32(chan->chip, DMAC_CHEN, (u32)val);
	}
}

static inline bool axi_chan_is_hw_enable(struct axi_dma_chan *chan)
{
	u32 val;
	u64 val;

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

	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));
}

@@ -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->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 {
		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);
			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->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 {
		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);
			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, val);
			axi_dma_iowrite32(chan->chip, DMAC_CHSUSPREG, (u32)val);
		}
	}

	chan->is_paused = false;
+5 −1
Original line number Diff line number Diff line
@@ -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