Repurpose tegra_dma_channel_regs struct to define offsets for all the
channel registers. Previously, the struct only held the register values
for each transfer and was wrapped within tegra_dma_sg_req. Now, let
struct tegra_dma_sg_req hold the values directly and use channel_regs
for storing the register offsets. Update all register read/write to use
channel_regs struct. This is to accommodate the register offset change
in Tegra264.
Signed-off-by: Akhil R <akhilrajeev@nvidia.com>
---
drivers/dma/tegra186-gpc-dma.c | 280 +++++++++++++++++----------------
1 file changed, 147 insertions(+), 133 deletions(-)
diff --git a/drivers/dma/tegra186-gpc-dma.c b/drivers/dma/tegra186-gpc-dma.c
index 236a298c26a1..72701b543ceb 100644
--- a/drivers/dma/tegra186-gpc-dma.c
+++ b/drivers/dma/tegra186-gpc-dma.c
@@ -22,7 +22,6 @@
#include "virt-dma.h"
/* CSR register */
-#define TEGRA_GPCDMA_CHAN_CSR 0x00
#define TEGRA_GPCDMA_CSR_ENB BIT(31)
#define TEGRA_GPCDMA_CSR_IE_EOC BIT(30)
#define TEGRA_GPCDMA_CSR_ONCE BIT(27)
@@ -58,7 +57,6 @@
#define TEGRA_GPCDMA_CSR_WEIGHT GENMASK(13, 10)
/* STATUS register */
-#define TEGRA_GPCDMA_CHAN_STATUS 0x004
#define TEGRA_GPCDMA_STATUS_BUSY BIT(31)
#define TEGRA_GPCDMA_STATUS_ISE_EOC BIT(30)
#define TEGRA_GPCDMA_STATUS_PING_PONG BIT(28)
@@ -70,22 +68,13 @@
#define TEGRA_GPCDMA_STATUS_IRQ_STA BIT(21)
#define TEGRA_GPCDMA_STATUS_IRQ_TRIG_STA BIT(20)
-#define TEGRA_GPCDMA_CHAN_CSRE 0x008
#define TEGRA_GPCDMA_CHAN_CSRE_PAUSE BIT(31)
-/* Source address */
-#define TEGRA_GPCDMA_CHAN_SRC_PTR 0x00C
-
-/* Destination address */
-#define TEGRA_GPCDMA_CHAN_DST_PTR 0x010
-
/* High address pointer */
-#define TEGRA_GPCDMA_CHAN_HIGH_ADDR_PTR 0x014
#define TEGRA_GPCDMA_HIGH_ADDR_SRC_PTR GENMASK(7, 0)
#define TEGRA_GPCDMA_HIGH_ADDR_DST_PTR GENMASK(23, 16)
/* MC sequence register */
-#define TEGRA_GPCDMA_CHAN_MCSEQ 0x18
#define TEGRA_GPCDMA_MCSEQ_DATA_SWAP BIT(31)
#define TEGRA_GPCDMA_MCSEQ_REQ_COUNT GENMASK(30, 25)
#define TEGRA_GPCDMA_MCSEQ_BURST GENMASK(24, 23)
@@ -101,7 +90,6 @@
#define TEGRA_GPCDMA_MCSEQ_STREAM_ID0_MASK GENMASK(6, 0)
/* MMIO sequence register */
-#define TEGRA_GPCDMA_CHAN_MMIOSEQ 0x01c
#define TEGRA_GPCDMA_MMIOSEQ_DBL_BUF BIT(31)
#define TEGRA_GPCDMA_MMIOSEQ_BUS_WIDTH GENMASK(30, 28)
#define TEGRA_GPCDMA_MMIOSEQ_BUS_WIDTH_8 \
@@ -120,17 +108,7 @@
#define TEGRA_GPCDMA_MMIOSEQ_WRAP_WORD GENMASK(18, 16)
#define TEGRA_GPCDMA_MMIOSEQ_MMIO_PROT GENMASK(8, 7)
-/* Channel WCOUNT */
-#define TEGRA_GPCDMA_CHAN_WCOUNT 0x20
-
-/* Transfer count */
-#define TEGRA_GPCDMA_CHAN_XFER_COUNT 0x24
-
-/* DMA byte count status */
-#define TEGRA_GPCDMA_CHAN_DMA_BYTE_STATUS 0x28
-
/* Error Status Register */
-#define TEGRA_GPCDMA_CHAN_ERR_STATUS 0x30
#define TEGRA_GPCDMA_CHAN_ERR_TYPE_SHIFT 8
#define TEGRA_GPCDMA_CHAN_ERR_TYPE_MASK 0xF
#define TEGRA_GPCDMA_CHAN_ERR_TYPE(err) ( \
@@ -143,14 +121,9 @@
#define TEGRA_DMA_MC_SLAVE_ERR 0xB
#define TEGRA_DMA_MMIO_SLAVE_ERR 0xA
-/* Fixed Pattern */
-#define TEGRA_GPCDMA_CHAN_FIXED_PATTERN 0x34
-
-#define TEGRA_GPCDMA_CHAN_TZ 0x38
#define TEGRA_GPCDMA_CHAN_TZ_MMIO_PROT_1 BIT(0)
#define TEGRA_GPCDMA_CHAN_TZ_MC_PROT_1 BIT(1)
-#define TEGRA_GPCDMA_CHAN_SPARE 0x3c
#define TEGRA_GPCDMA_CHAN_SPARE_EN_LEGACY_FC BIT(16)
/*
@@ -181,19 +154,27 @@ struct tegra_dma_chip_data {
unsigned int nr_channels;
unsigned int channel_reg_size;
unsigned int max_dma_count;
+ const struct tegra_dma_channel_regs *channel_regs;
int (*terminate)(struct tegra_dma_channel *tdc);
};
/* DMA channel registers */
struct tegra_dma_channel_regs {
u32 csr;
- u32 src_ptr;
- u32 dst_ptr;
- u32 high_addr_ptr;
+ u32 status;
+ u32 csre;
+ u32 src;
+ u32 dst;
+ u32 high_addr;
u32 mc_seq;
u32 mmio_seq;
u32 wcount;
+ u32 wxfer;
+ u32 wstatus;
+ u32 err_status;
u32 fixed_pattern;
+ u32 tz;
+ u32 spare;
};
/*
@@ -205,7 +186,14 @@ struct tegra_dma_channel_regs {
*/
struct tegra_dma_sg_req {
unsigned int len;
- struct tegra_dma_channel_regs ch_regs;
+ u32 csr;
+ u32 src;
+ u32 dst;
+ u32 high_addr;
+ u32 mc_seq;
+ u32 mmio_seq;
+ u32 wcount;
+ u32 fixed_pattern;
};
/*
@@ -228,19 +216,20 @@ struct tegra_dma_desc {
* tegra_dma_channel: Channel specific information
*/
struct tegra_dma_channel {
- bool config_init;
- char name[30];
- enum dma_transfer_direction sid_dir;
- enum dma_status status;
- int id;
- int irq;
- int slave_id;
+ const struct tegra_dma_channel_regs *regs;
struct tegra_dma *tdma;
struct virt_dma_chan vc;
struct tegra_dma_desc *dma_desc;
struct dma_slave_config dma_sconfig;
+ enum dma_transfer_direction sid_dir;
+ enum dma_status status;
unsigned int stream_id;
unsigned long chan_base_offset;
+ bool config_init;
+ char name[30];
+ int id;
+ int irq;
+ int slave_id;
};
/*
@@ -288,22 +277,25 @@ static void tegra_dma_dump_chan_regs(struct tegra_dma_channel *tdc)
{
dev_dbg(tdc2dev(tdc), "DMA Channel %d name %s register dump:\n",
tdc->id, tdc->name);
- dev_dbg(tdc2dev(tdc), "CSR %x STA %x CSRE %x SRC %x DST %x\n",
- tdc_read(tdc, TEGRA_GPCDMA_CHAN_CSR),
- tdc_read(tdc, TEGRA_GPCDMA_CHAN_STATUS),
- tdc_read(tdc, TEGRA_GPCDMA_CHAN_CSRE),
- tdc_read(tdc, TEGRA_GPCDMA_CHAN_SRC_PTR),
- tdc_read(tdc, TEGRA_GPCDMA_CHAN_DST_PTR)
+ dev_dbg(tdc2dev(tdc), "CSR %x STA %x CSRE %x\n",
+ tdc_read(tdc, tdc->regs->csr),
+ tdc_read(tdc, tdc->regs->status),
+ tdc_read(tdc, tdc->regs->csre)
);
- dev_dbg(tdc2dev(tdc), "MCSEQ %x IOSEQ %x WCNT %x XFER %x BSTA %x\n",
- tdc_read(tdc, TEGRA_GPCDMA_CHAN_MCSEQ),
- tdc_read(tdc, TEGRA_GPCDMA_CHAN_MMIOSEQ),
- tdc_read(tdc, TEGRA_GPCDMA_CHAN_WCOUNT),
- tdc_read(tdc, TEGRA_GPCDMA_CHAN_XFER_COUNT),
- tdc_read(tdc, TEGRA_GPCDMA_CHAN_DMA_BYTE_STATUS)
+ dev_dbg(tdc2dev(tdc), "SRC %x DST %x HI ADDR %x\n",
+ tdc_read(tdc, tdc->regs->src),
+ tdc_read(tdc, tdc->regs->dst),
+ tdc_read(tdc, tdc->regs->high_addr)
+ );
+ dev_dbg(tdc2dev(tdc), "MCSEQ %x IOSEQ %x WCNT %x XFER %x WSTA %x\n",
+ tdc_read(tdc, tdc->regs->mc_seq),
+ tdc_read(tdc, tdc->regs->mmio_seq),
+ tdc_read(tdc, tdc->regs->wcount),
+ tdc_read(tdc, tdc->regs->wxfer),
+ tdc_read(tdc, tdc->regs->wstatus)
);
dev_dbg(tdc2dev(tdc), "DMA ERR_STA %x\n",
- tdc_read(tdc, TEGRA_GPCDMA_CHAN_ERR_STATUS));
+ tdc_read(tdc, tdc->regs->err_status));
}
static int tegra_dma_sid_reserve(struct tegra_dma_channel *tdc,
@@ -377,13 +369,13 @@ static int tegra_dma_pause(struct tegra_dma_channel *tdc)
int ret;
u32 val;
- val = tdc_read(tdc, TEGRA_GPCDMA_CHAN_CSRE);
+ val = tdc_read(tdc, tdc->regs->csre);
val |= TEGRA_GPCDMA_CHAN_CSRE_PAUSE;
- tdc_write(tdc, TEGRA_GPCDMA_CHAN_CSRE, val);
+ tdc_write(tdc, tdc->regs->csre, val);
/* Wait until busy bit is de-asserted */
ret = readl_relaxed_poll_timeout_atomic(tdc->tdma->base_addr +
- tdc->chan_base_offset + TEGRA_GPCDMA_CHAN_STATUS,
+ tdc->chan_base_offset + tdc->regs->status,
val,
!(val & TEGRA_GPCDMA_STATUS_BUSY),
TEGRA_GPCDMA_BURST_COMPLETE_TIME,
@@ -419,9 +411,9 @@ static void tegra_dma_resume(struct tegra_dma_channel *tdc)
{
u32 val;
- val = tdc_read(tdc, TEGRA_GPCDMA_CHAN_CSRE);
+ val = tdc_read(tdc, tdc->regs->csre);
val &= ~TEGRA_GPCDMA_CHAN_CSRE_PAUSE;
- tdc_write(tdc, TEGRA_GPCDMA_CHAN_CSRE, val);
+ tdc_write(tdc, tdc->regs->csre, val);
tdc->status = DMA_IN_PROGRESS;
}
@@ -456,27 +448,27 @@ static void tegra_dma_disable(struct tegra_dma_channel *tdc)
{
u32 csr, status;
- csr = tdc_read(tdc, TEGRA_GPCDMA_CHAN_CSR);
+ csr = tdc_read(tdc, tdc->regs->csr);
/* Disable interrupts */
csr &= ~TEGRA_GPCDMA_CSR_IE_EOC;
/* Disable DMA */
csr &= ~TEGRA_GPCDMA_CSR_ENB;
- tdc_write(tdc, TEGRA_GPCDMA_CHAN_CSR, csr);
+ tdc_write(tdc, tdc->regs->csr, csr);
/* Clear interrupt status if it is there */
- status = tdc_read(tdc, TEGRA_GPCDMA_CHAN_STATUS);
+ status = tdc_read(tdc, tdc->regs->status);
if (status & TEGRA_GPCDMA_STATUS_ISE_EOC) {
dev_dbg(tdc2dev(tdc), "%s():clearing interrupt\n", __func__);
- tdc_write(tdc, TEGRA_GPCDMA_CHAN_STATUS, status);
+ tdc_write(tdc, tdc->regs->status, status);
}
}
static void tegra_dma_configure_next_sg(struct tegra_dma_channel *tdc)
{
struct tegra_dma_desc *dma_desc = tdc->dma_desc;
- struct tegra_dma_channel_regs *ch_regs;
+ struct tegra_dma_sg_req *sg_req;
int ret;
u32 val;
@@ -488,29 +480,29 @@ static void tegra_dma_configure_next_sg(struct tegra_dma_channel *tdc)
/* Configure next transfer immediately after DMA is busy */
ret = readl_relaxed_poll_timeout_atomic(tdc->tdma->base_addr +
- tdc->chan_base_offset + TEGRA_GPCDMA_CHAN_STATUS,
+ tdc->chan_base_offset + tdc->regs->status,
val,
(val & TEGRA_GPCDMA_STATUS_BUSY), 0,
TEGRA_GPCDMA_BURST_COMPLETION_TIMEOUT);
if (ret)
return;
- ch_regs = &dma_desc->sg_req[dma_desc->sg_idx].ch_regs;
+ sg_req = &dma_desc->sg_req[dma_desc->sg_idx];
- tdc_write(tdc, TEGRA_GPCDMA_CHAN_WCOUNT, ch_regs->wcount);
- tdc_write(tdc, TEGRA_GPCDMA_CHAN_SRC_PTR, ch_regs->src_ptr);
- tdc_write(tdc, TEGRA_GPCDMA_CHAN_DST_PTR, ch_regs->dst_ptr);
- tdc_write(tdc, TEGRA_GPCDMA_CHAN_HIGH_ADDR_PTR, ch_regs->high_addr_ptr);
+ tdc_write(tdc, tdc->regs->wcount, sg_req->wcount);
+ tdc_write(tdc, tdc->regs->src, sg_req->src);
+ tdc_write(tdc, tdc->regs->dst, sg_req->dst);
+ tdc_write(tdc, tdc->regs->high_addr, sg_req->high_addr);
/* Start DMA */
- tdc_write(tdc, TEGRA_GPCDMA_CHAN_CSR,
- ch_regs->csr | TEGRA_GPCDMA_CSR_ENB);
+ tdc_write(tdc, tdc->regs->csr,
+ sg_req->csr | TEGRA_GPCDMA_CSR_ENB);
}
static void tegra_dma_start(struct tegra_dma_channel *tdc)
{
struct tegra_dma_desc *dma_desc = tdc->dma_desc;
- struct tegra_dma_channel_regs *ch_regs;
+ struct tegra_dma_sg_req *sg_req;
struct virt_dma_desc *vdesc;
if (!dma_desc) {
@@ -526,21 +518,21 @@ static void tegra_dma_start(struct tegra_dma_channel *tdc)
tegra_dma_resume(tdc);
}
- ch_regs = &dma_desc->sg_req[dma_desc->sg_idx].ch_regs;
+ sg_req = &dma_desc->sg_req[dma_desc->sg_idx];
- tdc_write(tdc, TEGRA_GPCDMA_CHAN_WCOUNT, ch_regs->wcount);
- tdc_write(tdc, TEGRA_GPCDMA_CHAN_CSR, 0);
- tdc_write(tdc, TEGRA_GPCDMA_CHAN_SRC_PTR, ch_regs->src_ptr);
- tdc_write(tdc, TEGRA_GPCDMA_CHAN_DST_PTR, ch_regs->dst_ptr);
- tdc_write(tdc, TEGRA_GPCDMA_CHAN_HIGH_ADDR_PTR, ch_regs->high_addr_ptr);
- tdc_write(tdc, TEGRA_GPCDMA_CHAN_FIXED_PATTERN, ch_regs->fixed_pattern);
- tdc_write(tdc, TEGRA_GPCDMA_CHAN_MMIOSEQ, ch_regs->mmio_seq);
- tdc_write(tdc, TEGRA_GPCDMA_CHAN_MCSEQ, ch_regs->mc_seq);
- tdc_write(tdc, TEGRA_GPCDMA_CHAN_CSR, ch_regs->csr);
+ tdc_write(tdc, tdc->regs->wcount, sg_req->wcount);
+ tdc_write(tdc, tdc->regs->csr, 0);
+ tdc_write(tdc, tdc->regs->src, sg_req->src);
+ tdc_write(tdc, tdc->regs->dst, sg_req->dst);
+ tdc_write(tdc, tdc->regs->high_addr, sg_req->high_addr);
+ tdc_write(tdc, tdc->regs->fixed_pattern, sg_req->fixed_pattern);
+ tdc_write(tdc, tdc->regs->mmio_seq, sg_req->mmio_seq);
+ tdc_write(tdc, tdc->regs->mc_seq, sg_req->mc_seq);
+ tdc_write(tdc, tdc->regs->csr, sg_req->csr);
/* Start DMA */
- tdc_write(tdc, TEGRA_GPCDMA_CHAN_CSR,
- ch_regs->csr | TEGRA_GPCDMA_CSR_ENB);
+ tdc_write(tdc, tdc->regs->csr,
+ sg_req->csr | TEGRA_GPCDMA_CSR_ENB);
}
static void tegra_dma_xfer_complete(struct tegra_dma_channel *tdc)
@@ -601,19 +593,19 @@ static irqreturn_t tegra_dma_isr(int irq, void *dev_id)
u32 status;
/* Check channel error status register */
- status = tdc_read(tdc, TEGRA_GPCDMA_CHAN_ERR_STATUS);
+ status = tdc_read(tdc, tdc->regs->err_status);
if (status) {
tegra_dma_chan_decode_error(tdc, status);
tegra_dma_dump_chan_regs(tdc);
- tdc_write(tdc, TEGRA_GPCDMA_CHAN_ERR_STATUS, 0xFFFFFFFF);
+ tdc_write(tdc, tdc->regs->err_status, 0xFFFFFFFF);
}
spin_lock(&tdc->vc.lock);
- status = tdc_read(tdc, TEGRA_GPCDMA_CHAN_STATUS);
+ status = tdc_read(tdc, tdc->regs->status);
if (!(status & TEGRA_GPCDMA_STATUS_ISE_EOC))
goto irq_done;
- tdc_write(tdc, TEGRA_GPCDMA_CHAN_STATUS,
+ tdc_write(tdc, tdc->regs->status,
TEGRA_GPCDMA_STATUS_ISE_EOC);
if (!dma_desc)
@@ -673,10 +665,10 @@ static int tegra_dma_stop_client(struct tegra_dma_channel *tdc)
* to stop DMA engine from starting any more bursts for
* the given client and wait for in flight bursts to complete
*/
- csr = tdc_read(tdc, TEGRA_GPCDMA_CHAN_CSR);
+ csr = tdc_read(tdc, tdc->regs->csr);
csr &= ~(TEGRA_GPCDMA_CSR_REQ_SEL_MASK);
csr |= TEGRA_GPCDMA_CSR_REQ_SEL_UNUSED;
- tdc_write(tdc, TEGRA_GPCDMA_CHAN_CSR, csr);
+ tdc_write(tdc, tdc->regs->csr, csr);
/* Wait for in flight data transfer to finish */
udelay(TEGRA_GPCDMA_BURST_COMPLETE_TIME);
@@ -687,7 +679,7 @@ static int tegra_dma_stop_client(struct tegra_dma_channel *tdc)
ret = readl_relaxed_poll_timeout_atomic(tdc->tdma->base_addr +
tdc->chan_base_offset +
- TEGRA_GPCDMA_CHAN_STATUS,
+ tdc->regs->status,
status,
!(status & (TEGRA_GPCDMA_STATUS_CHANNEL_TX |
TEGRA_GPCDMA_STATUS_CHANNEL_RX)),
@@ -739,14 +731,14 @@ static int tegra_dma_get_residual(struct tegra_dma_channel *tdc)
unsigned int bytes_xfer, residual;
u32 wcount = 0, status;
- wcount = tdc_read(tdc, TEGRA_GPCDMA_CHAN_XFER_COUNT);
+ wcount = tdc_read(tdc, tdc->regs->wxfer);
/*
* Set wcount = 0 if EOC bit is set. The transfer would have
* already completed and the CHAN_XFER_COUNT could have updated
* for the next transfer, specifically in case of cyclic transfers.
*/
- status = tdc_read(tdc, TEGRA_GPCDMA_CHAN_STATUS);
+ status = tdc_read(tdc, tdc->regs->status);
if (status & TEGRA_GPCDMA_STATUS_ISE_EOC)
wcount = 0;
@@ -893,7 +885,7 @@ tegra_dma_prep_dma_memset(struct dma_chan *dc, dma_addr_t dest, int value,
/* Configure default priority weight for the channel */
csr |= FIELD_PREP(TEGRA_GPCDMA_CSR_WEIGHT, 1);
- mc_seq = tdc_read(tdc, TEGRA_GPCDMA_CHAN_MCSEQ);
+ mc_seq = tdc_read(tdc, tdc->regs->mc_seq);
/* retain stream-id and clean rest */
mc_seq &= TEGRA_GPCDMA_MCSEQ_STREAM_ID0_MASK;
@@ -916,16 +908,16 @@ tegra_dma_prep_dma_memset(struct dma_chan *dc, dma_addr_t dest, int value,
dma_desc->sg_count = 1;
sg_req = dma_desc->sg_req;
- sg_req[0].ch_regs.src_ptr = 0;
- sg_req[0].ch_regs.dst_ptr = dest;
- sg_req[0].ch_regs.high_addr_ptr =
+ sg_req[0].src = 0;
+ sg_req[0].dst = dest;
+ sg_req[0].high_addr =
FIELD_PREP(TEGRA_GPCDMA_HIGH_ADDR_DST_PTR, (dest >> 32));
- sg_req[0].ch_regs.fixed_pattern = value;
+ sg_req[0].fixed_pattern = value;
/* Word count reg takes value as (N +1) words */
- sg_req[0].ch_regs.wcount = ((len - 4) >> 2);
- sg_req[0].ch_regs.csr = csr;
- sg_req[0].ch_regs.mmio_seq = 0;
- sg_req[0].ch_regs.mc_seq = mc_seq;
+ sg_req[0].wcount = ((len - 4) >> 2);
+ sg_req[0].csr = csr;
+ sg_req[0].mmio_seq = 0;
+ sg_req[0].mc_seq = mc_seq;
sg_req[0].len = len;
dma_desc->cyclic = false;
@@ -961,7 +953,7 @@ tegra_dma_prep_dma_memcpy(struct dma_chan *dc, dma_addr_t dest,
/* Configure default priority weight for the channel */
csr |= FIELD_PREP(TEGRA_GPCDMA_CSR_WEIGHT, 1);
- mc_seq = tdc_read(tdc, TEGRA_GPCDMA_CHAN_MCSEQ);
+ mc_seq = tdc_read(tdc, tdc->regs->mc_seq);
/* retain stream-id and clean rest */
mc_seq &= (TEGRA_GPCDMA_MCSEQ_STREAM_ID0_MASK) |
(TEGRA_GPCDMA_MCSEQ_STREAM_ID1_MASK);
@@ -985,17 +977,17 @@ tegra_dma_prep_dma_memcpy(struct dma_chan *dc, dma_addr_t dest,
dma_desc->sg_count = 1;
sg_req = dma_desc->sg_req;
- sg_req[0].ch_regs.src_ptr = src;
- sg_req[0].ch_regs.dst_ptr = dest;
- sg_req[0].ch_regs.high_addr_ptr =
+ sg_req[0].src = src;
+ sg_req[0].dst = dest;
+ sg_req[0].high_addr =
FIELD_PREP(TEGRA_GPCDMA_HIGH_ADDR_SRC_PTR, (src >> 32));
- sg_req[0].ch_regs.high_addr_ptr |=
+ sg_req[0].high_addr |=
FIELD_PREP(TEGRA_GPCDMA_HIGH_ADDR_DST_PTR, (dest >> 32));
/* Word count reg takes value as (N +1) words */
- sg_req[0].ch_regs.wcount = ((len - 4) >> 2);
- sg_req[0].ch_regs.csr = csr;
- sg_req[0].ch_regs.mmio_seq = 0;
- sg_req[0].ch_regs.mc_seq = mc_seq;
+ sg_req[0].wcount = ((len - 4) >> 2);
+ sg_req[0].csr = csr;
+ sg_req[0].mmio_seq = 0;
+ sg_req[0].mc_seq = mc_seq;
sg_req[0].len = len;
dma_desc->cyclic = false;
@@ -1049,7 +1041,7 @@ tegra_dma_prep_slave_sg(struct dma_chan *dc, struct scatterlist *sgl,
if (flags & DMA_PREP_INTERRUPT)
csr |= TEGRA_GPCDMA_CSR_IE_EOC;
- mc_seq = tdc_read(tdc, TEGRA_GPCDMA_CHAN_MCSEQ);
+ mc_seq = tdc_read(tdc, tdc->regs->mc_seq);
/* retain stream-id and clean rest */
mc_seq &= TEGRA_GPCDMA_MCSEQ_STREAM_ID0_MASK;
@@ -1096,14 +1088,14 @@ tegra_dma_prep_slave_sg(struct dma_chan *dc, struct scatterlist *sgl,
dma_desc->bytes_req += len;
if (direction == DMA_MEM_TO_DEV) {
- sg_req[i].ch_regs.src_ptr = mem;
- sg_req[i].ch_regs.dst_ptr = apb_ptr;
- sg_req[i].ch_regs.high_addr_ptr =
+ sg_req[i].src = mem;
+ sg_req[i].dst = apb_ptr;
+ sg_req[i].high_addr =
FIELD_PREP(TEGRA_GPCDMA_HIGH_ADDR_SRC_PTR, (mem >> 32));
} else if (direction == DMA_DEV_TO_MEM) {
- sg_req[i].ch_regs.src_ptr = apb_ptr;
- sg_req[i].ch_regs.dst_ptr = mem;
- sg_req[i].ch_regs.high_addr_ptr =
+ sg_req[i].src = apb_ptr;
+ sg_req[i].dst = mem;
+ sg_req[i].high_addr =
FIELD_PREP(TEGRA_GPCDMA_HIGH_ADDR_DST_PTR, (mem >> 32));
}
@@ -1111,10 +1103,10 @@ tegra_dma_prep_slave_sg(struct dma_chan *dc, struct scatterlist *sgl,
* Word count register takes input in words. Writing a value
* of N into word count register means a req of (N+1) words.
*/
- sg_req[i].ch_regs.wcount = ((len - 4) >> 2);
- sg_req[i].ch_regs.csr = csr;
- sg_req[i].ch_regs.mmio_seq = mmio_seq;
- sg_req[i].ch_regs.mc_seq = mc_seq;
+ sg_req[i].wcount = ((len - 4) >> 2);
+ sg_req[i].csr = csr;
+ sg_req[i].mmio_seq = mmio_seq;
+ sg_req[i].mc_seq = mc_seq;
sg_req[i].len = len;
}
@@ -1186,7 +1178,7 @@ tegra_dma_prep_dma_cyclic(struct dma_chan *dc, dma_addr_t buf_addr, size_t buf_l
mmio_seq |= FIELD_PREP(TEGRA_GPCDMA_MMIOSEQ_WRAP_WORD, 1);
- mc_seq = tdc_read(tdc, TEGRA_GPCDMA_CHAN_MCSEQ);
+ mc_seq = tdc_read(tdc, tdc->regs->mc_seq);
/* retain stream-id and clean rest */
mc_seq &= TEGRA_GPCDMA_MCSEQ_STREAM_ID0_MASK;
@@ -1218,24 +1210,24 @@ tegra_dma_prep_dma_cyclic(struct dma_chan *dc, dma_addr_t buf_addr, size_t buf_l
for (i = 0; i < period_count; i++) {
mmio_seq |= get_burst_size(tdc, burst_size, slave_bw, len);
if (direction == DMA_MEM_TO_DEV) {
- sg_req[i].ch_regs.src_ptr = mem;
- sg_req[i].ch_regs.dst_ptr = apb_ptr;
- sg_req[i].ch_regs.high_addr_ptr =
+ sg_req[i].src = mem;
+ sg_req[i].dst = apb_ptr;
+ sg_req[i].high_addr =
FIELD_PREP(TEGRA_GPCDMA_HIGH_ADDR_SRC_PTR, (mem >> 32));
} else if (direction == DMA_DEV_TO_MEM) {
- sg_req[i].ch_regs.src_ptr = apb_ptr;
- sg_req[i].ch_regs.dst_ptr = mem;
- sg_req[i].ch_regs.high_addr_ptr =
+ sg_req[i].src = apb_ptr;
+ sg_req[i].dst = mem;
+ sg_req[i].high_addr =
FIELD_PREP(TEGRA_GPCDMA_HIGH_ADDR_DST_PTR, (mem >> 32));
}
/*
* Word count register takes input in words. Writing a value
* of N into word count register means a req of (N+1) words.
*/
- sg_req[i].ch_regs.wcount = ((len - 4) >> 2);
- sg_req[i].ch_regs.csr = csr;
- sg_req[i].ch_regs.mmio_seq = mmio_seq;
- sg_req[i].ch_regs.mc_seq = mc_seq;
+ sg_req[i].wcount = ((len - 4) >> 2);
+ sg_req[i].csr = csr;
+ sg_req[i].mmio_seq = mmio_seq;
+ sg_req[i].mc_seq = mc_seq;
sg_req[i].len = len;
mem += len;
@@ -1305,11 +1297,30 @@ static struct dma_chan *tegra_dma_of_xlate(struct of_phandle_args *dma_spec,
return chan;
}
+static const struct tegra_dma_channel_regs tegra186_reg_offsets = {
+ .csr = 0x0,
+ .status = 0x4,
+ .csre = 0x8,
+ .src = 0xc,
+ .dst = 0x10,
+ .high_addr = 0x14,
+ .mc_seq = 0x18,
+ .mmio_seq = 0x1c,
+ .wcount = 0x20,
+ .wxfer = 0x24,
+ .wstatus = 0x28,
+ .err_status = 0x30,
+ .fixed_pattern = 0x34,
+ .tz = 0x38,
+ .spare = 0x40,
+};
+
static const struct tegra_dma_chip_data tegra186_dma_chip_data = {
.nr_channels = 32,
.channel_reg_size = SZ_64K,
.max_dma_count = SZ_1G,
.hw_support_pause = false,
+ .channel_regs = &tegra186_reg_offsets,
.terminate = tegra_dma_stop_client,
};
@@ -1318,6 +1329,7 @@ static const struct tegra_dma_chip_data tegra194_dma_chip_data = {
.channel_reg_size = SZ_64K,
.max_dma_count = SZ_1G,
.hw_support_pause = true,
+ .channel_regs = &tegra186_reg_offsets,
.terminate = tegra_dma_pause,
};
@@ -1326,6 +1338,7 @@ static const struct tegra_dma_chip_data tegra234_dma_chip_data = {
.channel_reg_size = SZ_64K,
.max_dma_count = SZ_1G,
.hw_support_pause = true,
+ .channel_regs = &tegra186_reg_offsets,
.terminate = tegra_dma_pause_noerr,
};
@@ -1346,7 +1359,7 @@ MODULE_DEVICE_TABLE(of, tegra_dma_of_match);
static int tegra_dma_program_sid(struct tegra_dma_channel *tdc, int stream_id)
{
- unsigned int reg_val = tdc_read(tdc, TEGRA_GPCDMA_CHAN_MCSEQ);
+ unsigned int reg_val = tdc_read(tdc, tdc->regs->mc_seq);
reg_val &= ~(TEGRA_GPCDMA_MCSEQ_STREAM_ID0_MASK);
reg_val &= ~(TEGRA_GPCDMA_MCSEQ_STREAM_ID1_MASK);
@@ -1354,7 +1367,7 @@ static int tegra_dma_program_sid(struct tegra_dma_channel *tdc, int stream_id)
reg_val |= FIELD_PREP(TEGRA_GPCDMA_MCSEQ_STREAM_ID0_MASK, stream_id);
reg_val |= FIELD_PREP(TEGRA_GPCDMA_MCSEQ_STREAM_ID1_MASK, stream_id);
- tdc_write(tdc, TEGRA_GPCDMA_CHAN_MCSEQ, reg_val);
+ tdc_write(tdc, tdc->regs->mc_seq, reg_val);
return 0;
}
@@ -1420,6 +1433,7 @@ static int tegra_dma_probe(struct platform_device *pdev)
tdc->chan_base_offset = TEGRA_GPCDMA_CHANNEL_BASE_ADDR_OFFSET +
i * cdata->channel_reg_size;
snprintf(tdc->name, sizeof(tdc->name), "gpcdma.%d", i);
+ tdc->regs = cdata->channel_regs;
tdc->tdma = tdma;
tdc->id = i;
tdc->slave_id = -1;
--
2.50.1
On Tue, Feb 17, 2026 at 11:04:53PM +0530, Akhil R wrote:
> Repurpose tegra_dma_channel_regs struct to define offsets for all the
> channel registers. Previously, the struct only held the register values
> for each transfer and was wrapped within tegra_dma_sg_req. Now, let
> struct tegra_dma_sg_req hold the values directly and use channel_regs
> for storing the register offsets. Update all register read/write to use
> channel_regs struct. This is to accommodate the register offset change
> in Tegra264.
>
> Signed-off-by: Akhil R <akhilrajeev@nvidia.com>
> ---
Reviewed-by: Frank Li <Frank.Li@nxp.com>
> drivers/dma/tegra186-gpc-dma.c | 280 +++++++++++++++++----------------
> 1 file changed, 147 insertions(+), 133 deletions(-)
>
> diff --git a/drivers/dma/tegra186-gpc-dma.c b/drivers/dma/tegra186-gpc-dma.c
> index 236a298c26a1..72701b543ceb 100644
> --- a/drivers/dma/tegra186-gpc-dma.c
> +++ b/drivers/dma/tegra186-gpc-dma.c
> @@ -22,7 +22,6 @@
> #include "virt-dma.h"
>
> /* CSR register */
> -#define TEGRA_GPCDMA_CHAN_CSR 0x00
> #define TEGRA_GPCDMA_CSR_ENB BIT(31)
> #define TEGRA_GPCDMA_CSR_IE_EOC BIT(30)
> #define TEGRA_GPCDMA_CSR_ONCE BIT(27)
> @@ -58,7 +57,6 @@
> #define TEGRA_GPCDMA_CSR_WEIGHT GENMASK(13, 10)
>
> /* STATUS register */
> -#define TEGRA_GPCDMA_CHAN_STATUS 0x004
> #define TEGRA_GPCDMA_STATUS_BUSY BIT(31)
> #define TEGRA_GPCDMA_STATUS_ISE_EOC BIT(30)
> #define TEGRA_GPCDMA_STATUS_PING_PONG BIT(28)
> @@ -70,22 +68,13 @@
> #define TEGRA_GPCDMA_STATUS_IRQ_STA BIT(21)
> #define TEGRA_GPCDMA_STATUS_IRQ_TRIG_STA BIT(20)
>
> -#define TEGRA_GPCDMA_CHAN_CSRE 0x008
> #define TEGRA_GPCDMA_CHAN_CSRE_PAUSE BIT(31)
>
> -/* Source address */
> -#define TEGRA_GPCDMA_CHAN_SRC_PTR 0x00C
> -
> -/* Destination address */
> -#define TEGRA_GPCDMA_CHAN_DST_PTR 0x010
> -
> /* High address pointer */
> -#define TEGRA_GPCDMA_CHAN_HIGH_ADDR_PTR 0x014
> #define TEGRA_GPCDMA_HIGH_ADDR_SRC_PTR GENMASK(7, 0)
> #define TEGRA_GPCDMA_HIGH_ADDR_DST_PTR GENMASK(23, 16)
>
> /* MC sequence register */
> -#define TEGRA_GPCDMA_CHAN_MCSEQ 0x18
> #define TEGRA_GPCDMA_MCSEQ_DATA_SWAP BIT(31)
> #define TEGRA_GPCDMA_MCSEQ_REQ_COUNT GENMASK(30, 25)
> #define TEGRA_GPCDMA_MCSEQ_BURST GENMASK(24, 23)
> @@ -101,7 +90,6 @@
> #define TEGRA_GPCDMA_MCSEQ_STREAM_ID0_MASK GENMASK(6, 0)
>
> /* MMIO sequence register */
> -#define TEGRA_GPCDMA_CHAN_MMIOSEQ 0x01c
> #define TEGRA_GPCDMA_MMIOSEQ_DBL_BUF BIT(31)
> #define TEGRA_GPCDMA_MMIOSEQ_BUS_WIDTH GENMASK(30, 28)
> #define TEGRA_GPCDMA_MMIOSEQ_BUS_WIDTH_8 \
> @@ -120,17 +108,7 @@
> #define TEGRA_GPCDMA_MMIOSEQ_WRAP_WORD GENMASK(18, 16)
> #define TEGRA_GPCDMA_MMIOSEQ_MMIO_PROT GENMASK(8, 7)
>
> -/* Channel WCOUNT */
> -#define TEGRA_GPCDMA_CHAN_WCOUNT 0x20
> -
> -/* Transfer count */
> -#define TEGRA_GPCDMA_CHAN_XFER_COUNT 0x24
> -
> -/* DMA byte count status */
> -#define TEGRA_GPCDMA_CHAN_DMA_BYTE_STATUS 0x28
> -
> /* Error Status Register */
> -#define TEGRA_GPCDMA_CHAN_ERR_STATUS 0x30
> #define TEGRA_GPCDMA_CHAN_ERR_TYPE_SHIFT 8
> #define TEGRA_GPCDMA_CHAN_ERR_TYPE_MASK 0xF
> #define TEGRA_GPCDMA_CHAN_ERR_TYPE(err) ( \
> @@ -143,14 +121,9 @@
> #define TEGRA_DMA_MC_SLAVE_ERR 0xB
> #define TEGRA_DMA_MMIO_SLAVE_ERR 0xA
>
> -/* Fixed Pattern */
> -#define TEGRA_GPCDMA_CHAN_FIXED_PATTERN 0x34
> -
> -#define TEGRA_GPCDMA_CHAN_TZ 0x38
> #define TEGRA_GPCDMA_CHAN_TZ_MMIO_PROT_1 BIT(0)
> #define TEGRA_GPCDMA_CHAN_TZ_MC_PROT_1 BIT(1)
>
> -#define TEGRA_GPCDMA_CHAN_SPARE 0x3c
> #define TEGRA_GPCDMA_CHAN_SPARE_EN_LEGACY_FC BIT(16)
>
> /*
> @@ -181,19 +154,27 @@ struct tegra_dma_chip_data {
> unsigned int nr_channels;
> unsigned int channel_reg_size;
> unsigned int max_dma_count;
> + const struct tegra_dma_channel_regs *channel_regs;
> int (*terminate)(struct tegra_dma_channel *tdc);
> };
>
> /* DMA channel registers */
> struct tegra_dma_channel_regs {
> u32 csr;
> - u32 src_ptr;
> - u32 dst_ptr;
> - u32 high_addr_ptr;
> + u32 status;
> + u32 csre;
> + u32 src;
> + u32 dst;
> + u32 high_addr;
> u32 mc_seq;
> u32 mmio_seq;
> u32 wcount;
> + u32 wxfer;
> + u32 wstatus;
> + u32 err_status;
> u32 fixed_pattern;
> + u32 tz;
> + u32 spare;
> };
>
> /*
> @@ -205,7 +186,14 @@ struct tegra_dma_channel_regs {
> */
> struct tegra_dma_sg_req {
> unsigned int len;
> - struct tegra_dma_channel_regs ch_regs;
> + u32 csr;
> + u32 src;
> + u32 dst;
> + u32 high_addr;
> + u32 mc_seq;
> + u32 mmio_seq;
> + u32 wcount;
> + u32 fixed_pattern;
> };
>
> /*
> @@ -228,19 +216,20 @@ struct tegra_dma_desc {
> * tegra_dma_channel: Channel specific information
> */
> struct tegra_dma_channel {
> - bool config_init;
> - char name[30];
> - enum dma_transfer_direction sid_dir;
> - enum dma_status status;
> - int id;
> - int irq;
> - int slave_id;
> + const struct tegra_dma_channel_regs *regs;
> struct tegra_dma *tdma;
> struct virt_dma_chan vc;
> struct tegra_dma_desc *dma_desc;
> struct dma_slave_config dma_sconfig;
> + enum dma_transfer_direction sid_dir;
> + enum dma_status status;
> unsigned int stream_id;
> unsigned long chan_base_offset;
> + bool config_init;
> + char name[30];
> + int id;
> + int irq;
> + int slave_id;
> };
>
> /*
> @@ -288,22 +277,25 @@ static void tegra_dma_dump_chan_regs(struct tegra_dma_channel *tdc)
> {
> dev_dbg(tdc2dev(tdc), "DMA Channel %d name %s register dump:\n",
> tdc->id, tdc->name);
> - dev_dbg(tdc2dev(tdc), "CSR %x STA %x CSRE %x SRC %x DST %x\n",
> - tdc_read(tdc, TEGRA_GPCDMA_CHAN_CSR),
> - tdc_read(tdc, TEGRA_GPCDMA_CHAN_STATUS),
> - tdc_read(tdc, TEGRA_GPCDMA_CHAN_CSRE),
> - tdc_read(tdc, TEGRA_GPCDMA_CHAN_SRC_PTR),
> - tdc_read(tdc, TEGRA_GPCDMA_CHAN_DST_PTR)
> + dev_dbg(tdc2dev(tdc), "CSR %x STA %x CSRE %x\n",
> + tdc_read(tdc, tdc->regs->csr),
> + tdc_read(tdc, tdc->regs->status),
> + tdc_read(tdc, tdc->regs->csre)
> );
> - dev_dbg(tdc2dev(tdc), "MCSEQ %x IOSEQ %x WCNT %x XFER %x BSTA %x\n",
> - tdc_read(tdc, TEGRA_GPCDMA_CHAN_MCSEQ),
> - tdc_read(tdc, TEGRA_GPCDMA_CHAN_MMIOSEQ),
> - tdc_read(tdc, TEGRA_GPCDMA_CHAN_WCOUNT),
> - tdc_read(tdc, TEGRA_GPCDMA_CHAN_XFER_COUNT),
> - tdc_read(tdc, TEGRA_GPCDMA_CHAN_DMA_BYTE_STATUS)
> + dev_dbg(tdc2dev(tdc), "SRC %x DST %x HI ADDR %x\n",
> + tdc_read(tdc, tdc->regs->src),
> + tdc_read(tdc, tdc->regs->dst),
> + tdc_read(tdc, tdc->regs->high_addr)
> + );
> + dev_dbg(tdc2dev(tdc), "MCSEQ %x IOSEQ %x WCNT %x XFER %x WSTA %x\n",
> + tdc_read(tdc, tdc->regs->mc_seq),
> + tdc_read(tdc, tdc->regs->mmio_seq),
> + tdc_read(tdc, tdc->regs->wcount),
> + tdc_read(tdc, tdc->regs->wxfer),
> + tdc_read(tdc, tdc->regs->wstatus)
> );
> dev_dbg(tdc2dev(tdc), "DMA ERR_STA %x\n",
> - tdc_read(tdc, TEGRA_GPCDMA_CHAN_ERR_STATUS));
> + tdc_read(tdc, tdc->regs->err_status));
> }
>
> static int tegra_dma_sid_reserve(struct tegra_dma_channel *tdc,
> @@ -377,13 +369,13 @@ static int tegra_dma_pause(struct tegra_dma_channel *tdc)
> int ret;
> u32 val;
>
> - val = tdc_read(tdc, TEGRA_GPCDMA_CHAN_CSRE);
> + val = tdc_read(tdc, tdc->regs->csre);
> val |= TEGRA_GPCDMA_CHAN_CSRE_PAUSE;
> - tdc_write(tdc, TEGRA_GPCDMA_CHAN_CSRE, val);
> + tdc_write(tdc, tdc->regs->csre, val);
>
> /* Wait until busy bit is de-asserted */
> ret = readl_relaxed_poll_timeout_atomic(tdc->tdma->base_addr +
> - tdc->chan_base_offset + TEGRA_GPCDMA_CHAN_STATUS,
> + tdc->chan_base_offset + tdc->regs->status,
> val,
> !(val & TEGRA_GPCDMA_STATUS_BUSY),
> TEGRA_GPCDMA_BURST_COMPLETE_TIME,
> @@ -419,9 +411,9 @@ static void tegra_dma_resume(struct tegra_dma_channel *tdc)
> {
> u32 val;
>
> - val = tdc_read(tdc, TEGRA_GPCDMA_CHAN_CSRE);
> + val = tdc_read(tdc, tdc->regs->csre);
> val &= ~TEGRA_GPCDMA_CHAN_CSRE_PAUSE;
> - tdc_write(tdc, TEGRA_GPCDMA_CHAN_CSRE, val);
> + tdc_write(tdc, tdc->regs->csre, val);
>
> tdc->status = DMA_IN_PROGRESS;
> }
> @@ -456,27 +448,27 @@ static void tegra_dma_disable(struct tegra_dma_channel *tdc)
> {
> u32 csr, status;
>
> - csr = tdc_read(tdc, TEGRA_GPCDMA_CHAN_CSR);
> + csr = tdc_read(tdc, tdc->regs->csr);
>
> /* Disable interrupts */
> csr &= ~TEGRA_GPCDMA_CSR_IE_EOC;
>
> /* Disable DMA */
> csr &= ~TEGRA_GPCDMA_CSR_ENB;
> - tdc_write(tdc, TEGRA_GPCDMA_CHAN_CSR, csr);
> + tdc_write(tdc, tdc->regs->csr, csr);
>
> /* Clear interrupt status if it is there */
> - status = tdc_read(tdc, TEGRA_GPCDMA_CHAN_STATUS);
> + status = tdc_read(tdc, tdc->regs->status);
> if (status & TEGRA_GPCDMA_STATUS_ISE_EOC) {
> dev_dbg(tdc2dev(tdc), "%s():clearing interrupt\n", __func__);
> - tdc_write(tdc, TEGRA_GPCDMA_CHAN_STATUS, status);
> + tdc_write(tdc, tdc->regs->status, status);
> }
> }
>
> static void tegra_dma_configure_next_sg(struct tegra_dma_channel *tdc)
> {
> struct tegra_dma_desc *dma_desc = tdc->dma_desc;
> - struct tegra_dma_channel_regs *ch_regs;
> + struct tegra_dma_sg_req *sg_req;
> int ret;
> u32 val;
>
> @@ -488,29 +480,29 @@ static void tegra_dma_configure_next_sg(struct tegra_dma_channel *tdc)
>
> /* Configure next transfer immediately after DMA is busy */
> ret = readl_relaxed_poll_timeout_atomic(tdc->tdma->base_addr +
> - tdc->chan_base_offset + TEGRA_GPCDMA_CHAN_STATUS,
> + tdc->chan_base_offset + tdc->regs->status,
> val,
> (val & TEGRA_GPCDMA_STATUS_BUSY), 0,
> TEGRA_GPCDMA_BURST_COMPLETION_TIMEOUT);
> if (ret)
> return;
>
> - ch_regs = &dma_desc->sg_req[dma_desc->sg_idx].ch_regs;
> + sg_req = &dma_desc->sg_req[dma_desc->sg_idx];
>
> - tdc_write(tdc, TEGRA_GPCDMA_CHAN_WCOUNT, ch_regs->wcount);
> - tdc_write(tdc, TEGRA_GPCDMA_CHAN_SRC_PTR, ch_regs->src_ptr);
> - tdc_write(tdc, TEGRA_GPCDMA_CHAN_DST_PTR, ch_regs->dst_ptr);
> - tdc_write(tdc, TEGRA_GPCDMA_CHAN_HIGH_ADDR_PTR, ch_regs->high_addr_ptr);
> + tdc_write(tdc, tdc->regs->wcount, sg_req->wcount);
> + tdc_write(tdc, tdc->regs->src, sg_req->src);
> + tdc_write(tdc, tdc->regs->dst, sg_req->dst);
> + tdc_write(tdc, tdc->regs->high_addr, sg_req->high_addr);
>
> /* Start DMA */
> - tdc_write(tdc, TEGRA_GPCDMA_CHAN_CSR,
> - ch_regs->csr | TEGRA_GPCDMA_CSR_ENB);
> + tdc_write(tdc, tdc->regs->csr,
> + sg_req->csr | TEGRA_GPCDMA_CSR_ENB);
> }
>
> static void tegra_dma_start(struct tegra_dma_channel *tdc)
> {
> struct tegra_dma_desc *dma_desc = tdc->dma_desc;
> - struct tegra_dma_channel_regs *ch_regs;
> + struct tegra_dma_sg_req *sg_req;
> struct virt_dma_desc *vdesc;
>
> if (!dma_desc) {
> @@ -526,21 +518,21 @@ static void tegra_dma_start(struct tegra_dma_channel *tdc)
> tegra_dma_resume(tdc);
> }
>
> - ch_regs = &dma_desc->sg_req[dma_desc->sg_idx].ch_regs;
> + sg_req = &dma_desc->sg_req[dma_desc->sg_idx];
>
> - tdc_write(tdc, TEGRA_GPCDMA_CHAN_WCOUNT, ch_regs->wcount);
> - tdc_write(tdc, TEGRA_GPCDMA_CHAN_CSR, 0);
> - tdc_write(tdc, TEGRA_GPCDMA_CHAN_SRC_PTR, ch_regs->src_ptr);
> - tdc_write(tdc, TEGRA_GPCDMA_CHAN_DST_PTR, ch_regs->dst_ptr);
> - tdc_write(tdc, TEGRA_GPCDMA_CHAN_HIGH_ADDR_PTR, ch_regs->high_addr_ptr);
> - tdc_write(tdc, TEGRA_GPCDMA_CHAN_FIXED_PATTERN, ch_regs->fixed_pattern);
> - tdc_write(tdc, TEGRA_GPCDMA_CHAN_MMIOSEQ, ch_regs->mmio_seq);
> - tdc_write(tdc, TEGRA_GPCDMA_CHAN_MCSEQ, ch_regs->mc_seq);
> - tdc_write(tdc, TEGRA_GPCDMA_CHAN_CSR, ch_regs->csr);
> + tdc_write(tdc, tdc->regs->wcount, sg_req->wcount);
> + tdc_write(tdc, tdc->regs->csr, 0);
> + tdc_write(tdc, tdc->regs->src, sg_req->src);
> + tdc_write(tdc, tdc->regs->dst, sg_req->dst);
> + tdc_write(tdc, tdc->regs->high_addr, sg_req->high_addr);
> + tdc_write(tdc, tdc->regs->fixed_pattern, sg_req->fixed_pattern);
> + tdc_write(tdc, tdc->regs->mmio_seq, sg_req->mmio_seq);
> + tdc_write(tdc, tdc->regs->mc_seq, sg_req->mc_seq);
> + tdc_write(tdc, tdc->regs->csr, sg_req->csr);
>
> /* Start DMA */
> - tdc_write(tdc, TEGRA_GPCDMA_CHAN_CSR,
> - ch_regs->csr | TEGRA_GPCDMA_CSR_ENB);
> + tdc_write(tdc, tdc->regs->csr,
> + sg_req->csr | TEGRA_GPCDMA_CSR_ENB);
> }
>
> static void tegra_dma_xfer_complete(struct tegra_dma_channel *tdc)
> @@ -601,19 +593,19 @@ static irqreturn_t tegra_dma_isr(int irq, void *dev_id)
> u32 status;
>
> /* Check channel error status register */
> - status = tdc_read(tdc, TEGRA_GPCDMA_CHAN_ERR_STATUS);
> + status = tdc_read(tdc, tdc->regs->err_status);
> if (status) {
> tegra_dma_chan_decode_error(tdc, status);
> tegra_dma_dump_chan_regs(tdc);
> - tdc_write(tdc, TEGRA_GPCDMA_CHAN_ERR_STATUS, 0xFFFFFFFF);
> + tdc_write(tdc, tdc->regs->err_status, 0xFFFFFFFF);
> }
>
> spin_lock(&tdc->vc.lock);
> - status = tdc_read(tdc, TEGRA_GPCDMA_CHAN_STATUS);
> + status = tdc_read(tdc, tdc->regs->status);
> if (!(status & TEGRA_GPCDMA_STATUS_ISE_EOC))
> goto irq_done;
>
> - tdc_write(tdc, TEGRA_GPCDMA_CHAN_STATUS,
> + tdc_write(tdc, tdc->regs->status,
> TEGRA_GPCDMA_STATUS_ISE_EOC);
>
> if (!dma_desc)
> @@ -673,10 +665,10 @@ static int tegra_dma_stop_client(struct tegra_dma_channel *tdc)
> * to stop DMA engine from starting any more bursts for
> * the given client and wait for in flight bursts to complete
> */
> - csr = tdc_read(tdc, TEGRA_GPCDMA_CHAN_CSR);
> + csr = tdc_read(tdc, tdc->regs->csr);
> csr &= ~(TEGRA_GPCDMA_CSR_REQ_SEL_MASK);
> csr |= TEGRA_GPCDMA_CSR_REQ_SEL_UNUSED;
> - tdc_write(tdc, TEGRA_GPCDMA_CHAN_CSR, csr);
> + tdc_write(tdc, tdc->regs->csr, csr);
>
> /* Wait for in flight data transfer to finish */
> udelay(TEGRA_GPCDMA_BURST_COMPLETE_TIME);
> @@ -687,7 +679,7 @@ static int tegra_dma_stop_client(struct tegra_dma_channel *tdc)
>
> ret = readl_relaxed_poll_timeout_atomic(tdc->tdma->base_addr +
> tdc->chan_base_offset +
> - TEGRA_GPCDMA_CHAN_STATUS,
> + tdc->regs->status,
> status,
> !(status & (TEGRA_GPCDMA_STATUS_CHANNEL_TX |
> TEGRA_GPCDMA_STATUS_CHANNEL_RX)),
> @@ -739,14 +731,14 @@ static int tegra_dma_get_residual(struct tegra_dma_channel *tdc)
> unsigned int bytes_xfer, residual;
> u32 wcount = 0, status;
>
> - wcount = tdc_read(tdc, TEGRA_GPCDMA_CHAN_XFER_COUNT);
> + wcount = tdc_read(tdc, tdc->regs->wxfer);
>
> /*
> * Set wcount = 0 if EOC bit is set. The transfer would have
> * already completed and the CHAN_XFER_COUNT could have updated
> * for the next transfer, specifically in case of cyclic transfers.
> */
> - status = tdc_read(tdc, TEGRA_GPCDMA_CHAN_STATUS);
> + status = tdc_read(tdc, tdc->regs->status);
> if (status & TEGRA_GPCDMA_STATUS_ISE_EOC)
> wcount = 0;
>
> @@ -893,7 +885,7 @@ tegra_dma_prep_dma_memset(struct dma_chan *dc, dma_addr_t dest, int value,
> /* Configure default priority weight for the channel */
> csr |= FIELD_PREP(TEGRA_GPCDMA_CSR_WEIGHT, 1);
>
> - mc_seq = tdc_read(tdc, TEGRA_GPCDMA_CHAN_MCSEQ);
> + mc_seq = tdc_read(tdc, tdc->regs->mc_seq);
> /* retain stream-id and clean rest */
> mc_seq &= TEGRA_GPCDMA_MCSEQ_STREAM_ID0_MASK;
>
> @@ -916,16 +908,16 @@ tegra_dma_prep_dma_memset(struct dma_chan *dc, dma_addr_t dest, int value,
> dma_desc->sg_count = 1;
> sg_req = dma_desc->sg_req;
>
> - sg_req[0].ch_regs.src_ptr = 0;
> - sg_req[0].ch_regs.dst_ptr = dest;
> - sg_req[0].ch_regs.high_addr_ptr =
> + sg_req[0].src = 0;
> + sg_req[0].dst = dest;
> + sg_req[0].high_addr =
> FIELD_PREP(TEGRA_GPCDMA_HIGH_ADDR_DST_PTR, (dest >> 32));
> - sg_req[0].ch_regs.fixed_pattern = value;
> + sg_req[0].fixed_pattern = value;
> /* Word count reg takes value as (N +1) words */
> - sg_req[0].ch_regs.wcount = ((len - 4) >> 2);
> - sg_req[0].ch_regs.csr = csr;
> - sg_req[0].ch_regs.mmio_seq = 0;
> - sg_req[0].ch_regs.mc_seq = mc_seq;
> + sg_req[0].wcount = ((len - 4) >> 2);
> + sg_req[0].csr = csr;
> + sg_req[0].mmio_seq = 0;
> + sg_req[0].mc_seq = mc_seq;
> sg_req[0].len = len;
>
> dma_desc->cyclic = false;
> @@ -961,7 +953,7 @@ tegra_dma_prep_dma_memcpy(struct dma_chan *dc, dma_addr_t dest,
> /* Configure default priority weight for the channel */
> csr |= FIELD_PREP(TEGRA_GPCDMA_CSR_WEIGHT, 1);
>
> - mc_seq = tdc_read(tdc, TEGRA_GPCDMA_CHAN_MCSEQ);
> + mc_seq = tdc_read(tdc, tdc->regs->mc_seq);
> /* retain stream-id and clean rest */
> mc_seq &= (TEGRA_GPCDMA_MCSEQ_STREAM_ID0_MASK) |
> (TEGRA_GPCDMA_MCSEQ_STREAM_ID1_MASK);
> @@ -985,17 +977,17 @@ tegra_dma_prep_dma_memcpy(struct dma_chan *dc, dma_addr_t dest,
> dma_desc->sg_count = 1;
> sg_req = dma_desc->sg_req;
>
> - sg_req[0].ch_regs.src_ptr = src;
> - sg_req[0].ch_regs.dst_ptr = dest;
> - sg_req[0].ch_regs.high_addr_ptr =
> + sg_req[0].src = src;
> + sg_req[0].dst = dest;
> + sg_req[0].high_addr =
> FIELD_PREP(TEGRA_GPCDMA_HIGH_ADDR_SRC_PTR, (src >> 32));
> - sg_req[0].ch_regs.high_addr_ptr |=
> + sg_req[0].high_addr |=
> FIELD_PREP(TEGRA_GPCDMA_HIGH_ADDR_DST_PTR, (dest >> 32));
> /* Word count reg takes value as (N +1) words */
> - sg_req[0].ch_regs.wcount = ((len - 4) >> 2);
> - sg_req[0].ch_regs.csr = csr;
> - sg_req[0].ch_regs.mmio_seq = 0;
> - sg_req[0].ch_regs.mc_seq = mc_seq;
> + sg_req[0].wcount = ((len - 4) >> 2);
> + sg_req[0].csr = csr;
> + sg_req[0].mmio_seq = 0;
> + sg_req[0].mc_seq = mc_seq;
> sg_req[0].len = len;
>
> dma_desc->cyclic = false;
> @@ -1049,7 +1041,7 @@ tegra_dma_prep_slave_sg(struct dma_chan *dc, struct scatterlist *sgl,
> if (flags & DMA_PREP_INTERRUPT)
> csr |= TEGRA_GPCDMA_CSR_IE_EOC;
>
> - mc_seq = tdc_read(tdc, TEGRA_GPCDMA_CHAN_MCSEQ);
> + mc_seq = tdc_read(tdc, tdc->regs->mc_seq);
> /* retain stream-id and clean rest */
> mc_seq &= TEGRA_GPCDMA_MCSEQ_STREAM_ID0_MASK;
>
> @@ -1096,14 +1088,14 @@ tegra_dma_prep_slave_sg(struct dma_chan *dc, struct scatterlist *sgl,
> dma_desc->bytes_req += len;
>
> if (direction == DMA_MEM_TO_DEV) {
> - sg_req[i].ch_regs.src_ptr = mem;
> - sg_req[i].ch_regs.dst_ptr = apb_ptr;
> - sg_req[i].ch_regs.high_addr_ptr =
> + sg_req[i].src = mem;
> + sg_req[i].dst = apb_ptr;
> + sg_req[i].high_addr =
> FIELD_PREP(TEGRA_GPCDMA_HIGH_ADDR_SRC_PTR, (mem >> 32));
> } else if (direction == DMA_DEV_TO_MEM) {
> - sg_req[i].ch_regs.src_ptr = apb_ptr;
> - sg_req[i].ch_regs.dst_ptr = mem;
> - sg_req[i].ch_regs.high_addr_ptr =
> + sg_req[i].src = apb_ptr;
> + sg_req[i].dst = mem;
> + sg_req[i].high_addr =
> FIELD_PREP(TEGRA_GPCDMA_HIGH_ADDR_DST_PTR, (mem >> 32));
> }
>
> @@ -1111,10 +1103,10 @@ tegra_dma_prep_slave_sg(struct dma_chan *dc, struct scatterlist *sgl,
> * Word count register takes input in words. Writing a value
> * of N into word count register means a req of (N+1) words.
> */
> - sg_req[i].ch_regs.wcount = ((len - 4) >> 2);
> - sg_req[i].ch_regs.csr = csr;
> - sg_req[i].ch_regs.mmio_seq = mmio_seq;
> - sg_req[i].ch_regs.mc_seq = mc_seq;
> + sg_req[i].wcount = ((len - 4) >> 2);
> + sg_req[i].csr = csr;
> + sg_req[i].mmio_seq = mmio_seq;
> + sg_req[i].mc_seq = mc_seq;
> sg_req[i].len = len;
> }
>
> @@ -1186,7 +1178,7 @@ tegra_dma_prep_dma_cyclic(struct dma_chan *dc, dma_addr_t buf_addr, size_t buf_l
>
> mmio_seq |= FIELD_PREP(TEGRA_GPCDMA_MMIOSEQ_WRAP_WORD, 1);
>
> - mc_seq = tdc_read(tdc, TEGRA_GPCDMA_CHAN_MCSEQ);
> + mc_seq = tdc_read(tdc, tdc->regs->mc_seq);
> /* retain stream-id and clean rest */
> mc_seq &= TEGRA_GPCDMA_MCSEQ_STREAM_ID0_MASK;
>
> @@ -1218,24 +1210,24 @@ tegra_dma_prep_dma_cyclic(struct dma_chan *dc, dma_addr_t buf_addr, size_t buf_l
> for (i = 0; i < period_count; i++) {
> mmio_seq |= get_burst_size(tdc, burst_size, slave_bw, len);
> if (direction == DMA_MEM_TO_DEV) {
> - sg_req[i].ch_regs.src_ptr = mem;
> - sg_req[i].ch_regs.dst_ptr = apb_ptr;
> - sg_req[i].ch_regs.high_addr_ptr =
> + sg_req[i].src = mem;
> + sg_req[i].dst = apb_ptr;
> + sg_req[i].high_addr =
> FIELD_PREP(TEGRA_GPCDMA_HIGH_ADDR_SRC_PTR, (mem >> 32));
> } else if (direction == DMA_DEV_TO_MEM) {
> - sg_req[i].ch_regs.src_ptr = apb_ptr;
> - sg_req[i].ch_regs.dst_ptr = mem;
> - sg_req[i].ch_regs.high_addr_ptr =
> + sg_req[i].src = apb_ptr;
> + sg_req[i].dst = mem;
> + sg_req[i].high_addr =
> FIELD_PREP(TEGRA_GPCDMA_HIGH_ADDR_DST_PTR, (mem >> 32));
> }
> /*
> * Word count register takes input in words. Writing a value
> * of N into word count register means a req of (N+1) words.
> */
> - sg_req[i].ch_regs.wcount = ((len - 4) >> 2);
> - sg_req[i].ch_regs.csr = csr;
> - sg_req[i].ch_regs.mmio_seq = mmio_seq;
> - sg_req[i].ch_regs.mc_seq = mc_seq;
> + sg_req[i].wcount = ((len - 4) >> 2);
> + sg_req[i].csr = csr;
> + sg_req[i].mmio_seq = mmio_seq;
> + sg_req[i].mc_seq = mc_seq;
> sg_req[i].len = len;
>
> mem += len;
> @@ -1305,11 +1297,30 @@ static struct dma_chan *tegra_dma_of_xlate(struct of_phandle_args *dma_spec,
> return chan;
> }
>
> +static const struct tegra_dma_channel_regs tegra186_reg_offsets = {
> + .csr = 0x0,
> + .status = 0x4,
> + .csre = 0x8,
> + .src = 0xc,
> + .dst = 0x10,
> + .high_addr = 0x14,
> + .mc_seq = 0x18,
> + .mmio_seq = 0x1c,
> + .wcount = 0x20,
> + .wxfer = 0x24,
> + .wstatus = 0x28,
> + .err_status = 0x30,
> + .fixed_pattern = 0x34,
> + .tz = 0x38,
> + .spare = 0x40,
> +};
> +
> static const struct tegra_dma_chip_data tegra186_dma_chip_data = {
> .nr_channels = 32,
> .channel_reg_size = SZ_64K,
> .max_dma_count = SZ_1G,
> .hw_support_pause = false,
> + .channel_regs = &tegra186_reg_offsets,
> .terminate = tegra_dma_stop_client,
> };
>
> @@ -1318,6 +1329,7 @@ static const struct tegra_dma_chip_data tegra194_dma_chip_data = {
> .channel_reg_size = SZ_64K,
> .max_dma_count = SZ_1G,
> .hw_support_pause = true,
> + .channel_regs = &tegra186_reg_offsets,
> .terminate = tegra_dma_pause,
> };
>
> @@ -1326,6 +1338,7 @@ static const struct tegra_dma_chip_data tegra234_dma_chip_data = {
> .channel_reg_size = SZ_64K,
> .max_dma_count = SZ_1G,
> .hw_support_pause = true,
> + .channel_regs = &tegra186_reg_offsets,
> .terminate = tegra_dma_pause_noerr,
> };
>
> @@ -1346,7 +1359,7 @@ MODULE_DEVICE_TABLE(of, tegra_dma_of_match);
>
> static int tegra_dma_program_sid(struct tegra_dma_channel *tdc, int stream_id)
> {
> - unsigned int reg_val = tdc_read(tdc, TEGRA_GPCDMA_CHAN_MCSEQ);
> + unsigned int reg_val = tdc_read(tdc, tdc->regs->mc_seq);
>
> reg_val &= ~(TEGRA_GPCDMA_MCSEQ_STREAM_ID0_MASK);
> reg_val &= ~(TEGRA_GPCDMA_MCSEQ_STREAM_ID1_MASK);
> @@ -1354,7 +1367,7 @@ static int tegra_dma_program_sid(struct tegra_dma_channel *tdc, int stream_id)
> reg_val |= FIELD_PREP(TEGRA_GPCDMA_MCSEQ_STREAM_ID0_MASK, stream_id);
> reg_val |= FIELD_PREP(TEGRA_GPCDMA_MCSEQ_STREAM_ID1_MASK, stream_id);
>
> - tdc_write(tdc, TEGRA_GPCDMA_CHAN_MCSEQ, reg_val);
> + tdc_write(tdc, tdc->regs->mc_seq, reg_val);
> return 0;
> }
>
> @@ -1420,6 +1433,7 @@ static int tegra_dma_probe(struct platform_device *pdev)
> tdc->chan_base_offset = TEGRA_GPCDMA_CHANNEL_BASE_ADDR_OFFSET +
> i * cdata->channel_reg_size;
> snprintf(tdc->name, sizeof(tdc->name), "gpcdma.%d", i);
> + tdc->regs = cdata->channel_regs;
> tdc->tdma = tdma;
> tdc->id = i;
> tdc->slave_id = -1;
> --
> 2.50.1
>
© 2016 - 2026 Red Hat, Inc.