public inbox for linux-tegra@vger.kernel.org
 help / color / mirror / Atom feed
From: Frank Li <Frank.li@nxp.com>
To: Akhil R <akhilrajeev@nvidia.com>
Cc: Vinod Koul <vkoul@kernel.org>, Frank Li <Frank.Li@kernel.org>,
	Rob Herring <robh@kernel.org>,
	Krzysztof Kozlowski <krzk+dt@kernel.org>,
	Conor Dooley <conor+dt@kernel.org>,
	Thierry Reding <thierry.reding@kernel.org>,
	Jonathan Hunter <jonathanh@nvidia.com>,
	Laxman Dewangan <ldewangan@nvidia.com>,
	Philipp Zabel <p.zabel@pengutronix.de>,
	dmaengine@vger.kernel.org, devicetree@vger.kernel.org,
	linux-tegra@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: Re: [PATCH v2 5/9] dmaengine: tegra: Support address width > 39 bits
Date: Mon, 2 Mar 2026 16:14:25 -0500	[thread overview]
Message-ID: <aaX9sfdDORWIqYos@lizhi-Precision-Tower-5810> (raw)
In-Reply-To: <20260302123239.68441-6-akhilrajeev@nvidia.com>

On Mon, Mar 02, 2026 at 06:02:35PM +0530, Akhil R wrote:
> 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>
> ---
>  drivers/dma/tegra186-gpc-dma.c | 87 ++++++++++++++++++++++------------
>  1 file changed, 56 insertions(+), 31 deletions(-)
>
> diff --git a/drivers/dma/tegra186-gpc-dma.c b/drivers/dma/tegra186-gpc-dma.c
> index 09ba2755c06d..753e86d05a02 100644
> --- a/drivers/dma/tegra186-gpc-dma.c
> +++ b/drivers/dma/tegra186-gpc-dma.c
> @@ -151,6 +151,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;
> @@ -166,6 +167,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;
> @@ -186,10 +189,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;
> @@ -273,6 +275,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",
> @@ -281,10 +302,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),
> @@ -487,9 +518,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,
> @@ -517,11 +546,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);
> @@ -826,7 +853,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,
> @@ -904,11 +931,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);
> @@ -976,10 +1001,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;
> @@ -999,7 +1021,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;
> @@ -1087,13 +1110,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));
>  		}
>
>  		/*
> @@ -1117,7 +1136,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;
> @@ -1209,13 +1229,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
> @@ -1314,6 +1330,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,
> @@ -1323,6 +1340,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,
> @@ -1332,6 +1350,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,
> @@ -1443,6 +1462,12 @@ static int tegra_dma_probe(struct platform_device *pdev)
>  		tdc->stream_id = stream_id;
>  	}
>
> +	ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(cdata->addr_bits));

when bit mask >= 32, dma_set_mask_and_coherent() never return failure. So
needn't check return value.

Reviewed-by: Frank Li <Frank.Li@nxp.com>
> +	if (ret) {
> +		dev_err(&pdev->dev, "Failed to set DMA mask: %d\n", ret);
> +		return ret;
> +	}
> +
>  	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);
> --
> 2.50.1
>

  reply	other threads:[~2026-03-02 21:14 UTC|newest]

Thread overview: 24+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-03-02 12:32 [PATCH v2 0/9] Add GPCDMA support in Tegra264 Akhil R
2026-03-02 12:32 ` [PATCH v2 1/9] dt-bindings: dma: nvidia,tegra186-gpc-dma: Add iommu-map property Akhil R
2026-03-03  6:39   ` Krzysztof Kozlowski
2026-03-03  8:40     ` Akhil R
2026-03-03  8:57       ` Krzysztof Kozlowski
2026-03-03 13:09       ` Jon Hunter
2026-03-03 17:14         ` Akhil R
2026-03-03 17:34           ` Jon Hunter
2026-03-04 10:37             ` Akhil R
2026-03-04 11:10               ` Jon Hunter
2026-03-10  4:44                 ` Akhil R
2026-03-10  9:47                   ` Jon Hunter
2026-03-02 12:32 ` [PATCH v2 2/9] dt-bindings: dma: nvidia,tegra186-gpc-dma: Make reset optional Akhil R
2026-03-02 20:31   ` Frank Li
2026-03-03 13:27     ` Jon Hunter
2026-03-02 12:32 ` [PATCH v2 3/9] dmaengine: tegra: Make reset control optional Akhil R
2026-03-02 20:31   ` Frank Li
2026-03-02 12:32 ` [PATCH v2 4/9] dmaengine: tegra: Use struct for register offsets Akhil R
2026-03-02 12:32 ` [PATCH v2 5/9] dmaengine: tegra: Support address width > 39 bits Akhil R
2026-03-02 21:14   ` Frank Li [this message]
2026-03-02 12:32 ` [PATCH v2 6/9] dmaengine: tegra: Use managed DMA controller registration Akhil R
2026-03-02 12:32 ` [PATCH v2 7/9] dmaengine: tegra: Use iommu-map for stream ID Akhil R
2026-03-02 12:32 ` [PATCH v2 8/9] dmaengine: tegra: Add Tegra264 support Akhil R
2026-03-02 12:32 ` [PATCH v2 9/9] arm64: tegra: Add iommu-map and enable GPCDMA in Tegra264 Akhil R

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=aaX9sfdDORWIqYos@lizhi-Precision-Tower-5810 \
    --to=frank.li@nxp.com \
    --cc=Frank.Li@kernel.org \
    --cc=akhilrajeev@nvidia.com \
    --cc=conor+dt@kernel.org \
    --cc=devicetree@vger.kernel.org \
    --cc=dmaengine@vger.kernel.org \
    --cc=jonathanh@nvidia.com \
    --cc=krzk+dt@kernel.org \
    --cc=ldewangan@nvidia.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-tegra@vger.kernel.org \
    --cc=p.zabel@pengutronix.de \
    --cc=robh@kernel.org \
    --cc=thierry.reding@kernel.org \
    --cc=vkoul@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox