mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-07-22 02:17:36 -04:00
dmaengine: tegra: Support address width > 39 bits
Tegra264 supports address width of 41 bits. Unlike older SoCs which use a common high_addr register for upper address bits, Tegra264 has separate src_high and dst_high registers to accommodate this wider address space. Add an addr_bits property to the device data structure to specify the number of address bits supported on each device and use that to program the appropriate registers. Update the sg_req struct to remove the high_addr field and use dma_addr_t for src and dst to store the complete addresses. Extract the high address bits only when programming the registers. Signed-off-by: Akhil R <akhilrajeev@nvidia.com> Reviewed-by: Frank Li <Frank.Li@nxp.com> Reviewed-by: Jon Hunter <jonathanh@nvidia.com> Link: https://patch.msgid.link/20260331102303.33181-7-akhilrajeev@nvidia.com Signed-off-by: Vinod Koul <vkoul@kernel.org>
This commit is contained in:
@@ -146,6 +146,7 @@ struct tegra_dma_channel;
|
||||
*/
|
||||
struct tegra_dma_chip_data {
|
||||
bool hw_support_pause;
|
||||
unsigned int addr_bits;
|
||||
unsigned int nr_channels;
|
||||
unsigned int channel_reg_size;
|
||||
unsigned int max_dma_count;
|
||||
@@ -161,6 +162,8 @@ struct tegra_dma_channel_regs {
|
||||
u32 src;
|
||||
u32 dst;
|
||||
u32 high_addr;
|
||||
u32 src_high;
|
||||
u32 dst_high;
|
||||
u32 mc_seq;
|
||||
u32 mmio_seq;
|
||||
u32 wcount;
|
||||
@@ -179,10 +182,9 @@ struct tegra_dma_channel_regs {
|
||||
*/
|
||||
struct tegra_dma_sg_req {
|
||||
unsigned int len;
|
||||
dma_addr_t src;
|
||||
dma_addr_t dst;
|
||||
u32 csr;
|
||||
u32 src;
|
||||
u32 dst;
|
||||
u32 high_addr;
|
||||
u32 mc_seq;
|
||||
u32 mmio_seq;
|
||||
u32 wcount;
|
||||
@@ -266,6 +268,25 @@ static inline struct device *tdc2dev(struct tegra_dma_channel *tdc)
|
||||
return tdc->vc.chan.device->dev;
|
||||
}
|
||||
|
||||
static void tegra_dma_program_addr(struct tegra_dma_channel *tdc,
|
||||
struct tegra_dma_sg_req *sg_req)
|
||||
{
|
||||
tdc_write(tdc, tdc->regs->src, lower_32_bits(sg_req->src));
|
||||
tdc_write(tdc, tdc->regs->dst, lower_32_bits(sg_req->dst));
|
||||
|
||||
if (tdc->tdma->chip_data->addr_bits > 39) {
|
||||
tdc_write(tdc, tdc->regs->src_high, upper_32_bits(sg_req->src));
|
||||
tdc_write(tdc, tdc->regs->dst_high, upper_32_bits(sg_req->dst));
|
||||
} else {
|
||||
u32 src_high = FIELD_PREP(TEGRA_GPCDMA_HIGH_ADDR_SRC_PTR,
|
||||
upper_32_bits(sg_req->src));
|
||||
u32 dst_high = FIELD_PREP(TEGRA_GPCDMA_HIGH_ADDR_DST_PTR,
|
||||
upper_32_bits(sg_req->dst));
|
||||
|
||||
tdc_write(tdc, tdc->regs->high_addr, src_high | dst_high);
|
||||
}
|
||||
}
|
||||
|
||||
static void tegra_dma_dump_chan_regs(struct tegra_dma_channel *tdc)
|
||||
{
|
||||
dev_dbg(tdc2dev(tdc), "DMA Channel %d name %s register dump:\n",
|
||||
@@ -274,10 +295,20 @@ static void tegra_dma_dump_chan_regs(struct tegra_dma_channel *tdc)
|
||||
tdc_read(tdc, tdc->regs->csr),
|
||||
tdc_read(tdc, tdc->regs->status),
|
||||
tdc_read(tdc, tdc->regs->csre));
|
||||
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));
|
||||
|
||||
if (tdc->tdma->chip_data->addr_bits > 39) {
|
||||
dev_dbg(tdc2dev(tdc), "SRC %x SRC HI %x DST %x DST HI %x\n",
|
||||
tdc_read(tdc, tdc->regs->src),
|
||||
tdc_read(tdc, tdc->regs->src_high),
|
||||
tdc_read(tdc, tdc->regs->dst),
|
||||
tdc_read(tdc, tdc->regs->dst_high));
|
||||
} else {
|
||||
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),
|
||||
@@ -480,9 +511,7 @@ static void tegra_dma_configure_next_sg(struct tegra_dma_channel *tdc)
|
||||
sg_req = &dma_desc->sg_req[dma_desc->sg_idx];
|
||||
|
||||
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);
|
||||
tegra_dma_program_addr(tdc, sg_req);
|
||||
|
||||
/* Start DMA */
|
||||
tdc_write(tdc, tdc->regs->csr,
|
||||
@@ -510,11 +539,9 @@ static void tegra_dma_start(struct tegra_dma_channel *tdc)
|
||||
|
||||
sg_req = &dma_desc->sg_req[dma_desc->sg_idx];
|
||||
|
||||
tegra_dma_program_addr(tdc, sg_req);
|
||||
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);
|
||||
@@ -819,7 +846,7 @@ static unsigned int get_burst_size(struct tegra_dma_channel *tdc,
|
||||
|
||||
static int get_transfer_param(struct tegra_dma_channel *tdc,
|
||||
enum dma_transfer_direction direction,
|
||||
u32 *apb_addr,
|
||||
dma_addr_t *apb_addr,
|
||||
u32 *mmio_seq,
|
||||
u32 *csr,
|
||||
unsigned int *burst_size,
|
||||
@@ -897,11 +924,9 @@ tegra_dma_prep_dma_memset(struct dma_chan *dc, dma_addr_t dest, int value,
|
||||
dma_desc->bytes_req = len;
|
||||
dma_desc->sg_count = 1;
|
||||
sg_req = dma_desc->sg_req;
|
||||
|
||||
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].fixed_pattern = value;
|
||||
/* Word count reg takes value as (N +1) words */
|
||||
sg_req[0].wcount = ((len - 4) >> 2);
|
||||
@@ -969,10 +994,7 @@ tegra_dma_prep_dma_memcpy(struct dma_chan *dc, dma_addr_t dest,
|
||||
|
||||
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].high_addr |=
|
||||
FIELD_PREP(TEGRA_GPCDMA_HIGH_ADDR_DST_PTR, (dest >> 32));
|
||||
|
||||
/* Word count reg takes value as (N +1) words */
|
||||
sg_req[0].wcount = ((len - 4) >> 2);
|
||||
sg_req[0].csr = csr;
|
||||
@@ -992,7 +1014,8 @@ tegra_dma_prep_slave_sg(struct dma_chan *dc, struct scatterlist *sgl,
|
||||
struct tegra_dma_channel *tdc = to_tegra_dma_chan(dc);
|
||||
unsigned int max_dma_count = tdc->tdma->chip_data->max_dma_count;
|
||||
enum dma_slave_buswidth slave_bw = DMA_SLAVE_BUSWIDTH_UNDEFINED;
|
||||
u32 csr, mc_seq, apb_ptr = 0, mmio_seq = 0;
|
||||
u32 csr, mc_seq, mmio_seq = 0;
|
||||
dma_addr_t apb_ptr = 0;
|
||||
struct tegra_dma_sg_req *sg_req;
|
||||
struct tegra_dma_desc *dma_desc;
|
||||
struct scatterlist *sg;
|
||||
@@ -1080,13 +1103,9 @@ tegra_dma_prep_slave_sg(struct dma_chan *dc, struct scatterlist *sgl,
|
||||
if (direction == DMA_MEM_TO_DEV) {
|
||||
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].src = apb_ptr;
|
||||
sg_req[i].dst = mem;
|
||||
sg_req[i].high_addr =
|
||||
FIELD_PREP(TEGRA_GPCDMA_HIGH_ADDR_DST_PTR, (mem >> 32));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1110,7 +1129,8 @@ tegra_dma_prep_dma_cyclic(struct dma_chan *dc, dma_addr_t buf_addr, size_t buf_l
|
||||
unsigned long flags)
|
||||
{
|
||||
enum dma_slave_buswidth slave_bw = DMA_SLAVE_BUSWIDTH_UNDEFINED;
|
||||
u32 csr, mc_seq, apb_ptr = 0, mmio_seq = 0, burst_size;
|
||||
u32 csr, mc_seq, mmio_seq = 0, burst_size;
|
||||
dma_addr_t apb_ptr = 0;
|
||||
unsigned int max_dma_count, len, period_count, i;
|
||||
struct tegra_dma_channel *tdc = to_tegra_dma_chan(dc);
|
||||
struct tegra_dma_desc *dma_desc;
|
||||
@@ -1201,13 +1221,9 @@ tegra_dma_prep_dma_cyclic(struct dma_chan *dc, dma_addr_t buf_addr, size_t buf_l
|
||||
if (direction == DMA_MEM_TO_DEV) {
|
||||
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].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
|
||||
@@ -1304,6 +1320,7 @@ static const struct tegra_dma_channel_regs tegra186_reg_offsets = {
|
||||
|
||||
static const struct tegra_dma_chip_data tegra186_dma_chip_data = {
|
||||
.nr_channels = 32,
|
||||
.addr_bits = 39,
|
||||
.channel_reg_size = SZ_64K,
|
||||
.max_dma_count = SZ_1G,
|
||||
.hw_support_pause = false,
|
||||
@@ -1313,6 +1330,7 @@ static const struct tegra_dma_chip_data tegra186_dma_chip_data = {
|
||||
|
||||
static const struct tegra_dma_chip_data tegra194_dma_chip_data = {
|
||||
.nr_channels = 32,
|
||||
.addr_bits = 39,
|
||||
.channel_reg_size = SZ_64K,
|
||||
.max_dma_count = SZ_1G,
|
||||
.hw_support_pause = true,
|
||||
@@ -1322,6 +1340,7 @@ static const struct tegra_dma_chip_data tegra194_dma_chip_data = {
|
||||
|
||||
static const struct tegra_dma_chip_data tegra234_dma_chip_data = {
|
||||
.nr_channels = 32,
|
||||
.addr_bits = 39,
|
||||
.channel_reg_size = SZ_64K,
|
||||
.max_dma_count = SZ_1G,
|
||||
.hw_support_pause = true,
|
||||
@@ -1433,6 +1452,8 @@ static int tegra_dma_probe(struct platform_device *pdev)
|
||||
tdc->stream_id = stream_id;
|
||||
}
|
||||
|
||||
dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(cdata->addr_bits));
|
||||
|
||||
dma_cap_set(DMA_SLAVE, tdma->dma_dev.cap_mask);
|
||||
dma_cap_set(DMA_PRIVATE, tdma->dma_dev.cap_mask);
|
||||
dma_cap_set(DMA_MEMCPY, tdma->dma_dev.cap_mask);
|
||||
|
||||
Reference in New Issue
Block a user