diff mbox series

[3/3] dmaengine: tegra: Add support for dma-channel-mask

Message ID 20220913155251.59375-4-akhilrajeev@nvidia.com (mailing list archive)
State Superseded
Headers show
Series Tegra GCPDMA: Add dma-channel-mask support | expand

Commit Message

Akhil R Sept. 13, 2022, 3:52 p.m. UTC
Add support for dma-channel-mask so that only the specified channels
are used. This helps to reserve some channels for the firmware.

This was initially achieved by limiting the channel number to 31 in
the driver and adjusting the register address to skip channel0 which
was reserved for a firmware. Now, with this change, the driver can
align more to the actual hardware which has 32 channels.

Signed-off-by: Akhil R <akhilrajeev@nvidia.com>
---
 drivers/dma/tegra186-gpc-dma.c | 35 ++++++++++++++++++++++++++++------
 1 file changed, 29 insertions(+), 6 deletions(-)

Comments

kernel test robot Sept. 14, 2022, 1:25 a.m. UTC | #1
Hi Akhil,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on robh/for-next]
[also build test WARNING on vkoul-dmaengine/next linus/master v6.0-rc5 next-20220913]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Akhil-R/Tegra-GCPDMA-Add-dma-channel-mask-support/20220914-010611
base:   https://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git for-next
config: loongarch-allyesconfig (https://download.01.org/0day-ci/archive/20220914/202209140942.NsWTm6xM-lkp@intel.com/config)
compiler: loongarch64-linux-gcc (GCC) 12.1.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/intel-lab-lkp/linux/commit/b760183e9631ceaf2f36072fc4a7438c3d62887b
        git remote add linux-review https://github.com/intel-lab-lkp/linux
        git fetch --no-tags linux-review Akhil-R/Tegra-GCPDMA-Add-dma-channel-mask-support/20220914-010611
        git checkout b760183e9631ceaf2f36072fc4a7438c3d62887b
        # save the config file
        mkdir build_dir && cp config build_dir/.config
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross W=1 O=build_dir ARCH=loongarch SHELL=/bin/bash drivers/

If you fix the issue, kindly add following tag where applicable
Reported-by: kernel test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

   In file included from include/linux/device.h:15,
                    from include/linux/dmaengine.h:8,
                    from drivers/dma/tegra186-gpc-dma.c:9:
   drivers/dma/tegra186-gpc-dma.c: In function 'tegra_dma_probe':
>> drivers/dma/tegra186-gpc-dma.c:1469:30: warning: format '%d' expects argument of type 'int', but argument 3 has type 'long unsigned int' [-Wformat=]
    1469 |         dev_info(&pdev->dev, "GPC DMA driver register %d channels\n",
         |                              ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/dev_printk.h:110:30: note: in definition of macro 'dev_printk_index_wrap'
     110 |                 _p_func(dev, fmt, ##__VA_ARGS__);                       \
         |                              ^~~
   include/linux/dev_printk.h:150:58: note: in expansion of macro 'dev_fmt'
     150 |         dev_printk_index_wrap(_dev_info, KERN_INFO, dev, dev_fmt(fmt), ##__VA_ARGS__)
         |                                                          ^~~~~~~
   drivers/dma/tegra186-gpc-dma.c:1469:9: note: in expansion of macro 'dev_info'
    1469 |         dev_info(&pdev->dev, "GPC DMA driver register %d channels\n",
         |         ^~~~~~~~
   drivers/dma/tegra186-gpc-dma.c:1469:56: note: format string is defined here
    1469 |         dev_info(&pdev->dev, "GPC DMA driver register %d channels\n",
         |                                                       ~^
         |                                                        |
         |                                                        int
         |                                                       %ld


vim +1469 drivers/dma/tegra186-gpc-dma.c

ee17028009d49f Akhil R 2022-02-25  1346  
ee17028009d49f Akhil R 2022-02-25  1347  static int tegra_dma_probe(struct platform_device *pdev)
ee17028009d49f Akhil R 2022-02-25  1348  {
ee17028009d49f Akhil R 2022-02-25  1349  	const struct tegra_dma_chip_data *cdata = NULL;
ee17028009d49f Akhil R 2022-02-25  1350  	struct iommu_fwspec *iommu_spec;
ee17028009d49f Akhil R 2022-02-25  1351  	unsigned int stream_id, i;
ee17028009d49f Akhil R 2022-02-25  1352  	struct tegra_dma *tdma;
ee17028009d49f Akhil R 2022-02-25  1353  	int ret;
ee17028009d49f Akhil R 2022-02-25  1354  
ee17028009d49f Akhil R 2022-02-25  1355  	cdata = of_device_get_match_data(&pdev->dev);
ee17028009d49f Akhil R 2022-02-25  1356  
ee17028009d49f Akhil R 2022-02-25  1357  	tdma = devm_kzalloc(&pdev->dev,
ee17028009d49f Akhil R 2022-02-25  1358  			    struct_size(tdma, channels, cdata->nr_channels),
ee17028009d49f Akhil R 2022-02-25  1359  			    GFP_KERNEL);
ee17028009d49f Akhil R 2022-02-25  1360  	if (!tdma)
ee17028009d49f Akhil R 2022-02-25  1361  		return -ENOMEM;
ee17028009d49f Akhil R 2022-02-25  1362  
ee17028009d49f Akhil R 2022-02-25  1363  	tdma->dev = &pdev->dev;
ee17028009d49f Akhil R 2022-02-25  1364  	tdma->chip_data = cdata;
ee17028009d49f Akhil R 2022-02-25  1365  	platform_set_drvdata(pdev, tdma);
ee17028009d49f Akhil R 2022-02-25  1366  
ee17028009d49f Akhil R 2022-02-25  1367  	tdma->base_addr = devm_platform_ioremap_resource(pdev, 0);
ee17028009d49f Akhil R 2022-02-25  1368  	if (IS_ERR(tdma->base_addr))
ee17028009d49f Akhil R 2022-02-25  1369  		return PTR_ERR(tdma->base_addr);
ee17028009d49f Akhil R 2022-02-25  1370  
ee17028009d49f Akhil R 2022-02-25  1371  	tdma->rst = devm_reset_control_get_exclusive(&pdev->dev, "gpcdma");
ee17028009d49f Akhil R 2022-02-25  1372  	if (IS_ERR(tdma->rst)) {
ee17028009d49f Akhil R 2022-02-25  1373  		return dev_err_probe(&pdev->dev, PTR_ERR(tdma->rst),
ee17028009d49f Akhil R 2022-02-25  1374  			      "Missing controller reset\n");
ee17028009d49f Akhil R 2022-02-25  1375  	}
ee17028009d49f Akhil R 2022-02-25  1376  	reset_control_reset(tdma->rst);
ee17028009d49f Akhil R 2022-02-25  1377  
ee17028009d49f Akhil R 2022-02-25  1378  	tdma->dma_dev.dev = &pdev->dev;
ee17028009d49f Akhil R 2022-02-25  1379  
ee17028009d49f Akhil R 2022-02-25  1380  	iommu_spec = dev_iommu_fwspec_get(&pdev->dev);
ee17028009d49f Akhil R 2022-02-25  1381  	if (!iommu_spec) {
ee17028009d49f Akhil R 2022-02-25  1382  		dev_err(&pdev->dev, "Missing iommu stream-id\n");
ee17028009d49f Akhil R 2022-02-25  1383  		return -EINVAL;
ee17028009d49f Akhil R 2022-02-25  1384  	}
ee17028009d49f Akhil R 2022-02-25  1385  	stream_id = iommu_spec->ids[0] & 0xffff;
ee17028009d49f Akhil R 2022-02-25  1386  
b760183e9631ce Akhil R 2022-09-13  1387  	ret = device_property_read_u32(&pdev->dev, "dma-channel-mask",
b760183e9631ce Akhil R 2022-09-13  1388  				       &tdma->chan_mask);
b760183e9631ce Akhil R 2022-09-13  1389  	if (ret) {
b760183e9631ce Akhil R 2022-09-13  1390  		dev_warn(&pdev->dev,
b760183e9631ce Akhil R 2022-09-13  1391  			 "Missing dma-channel-mask property, using default channel mask %#x\n",
b760183e9631ce Akhil R 2022-09-13  1392  			 TEGRA_GPCDMA_DEFAULT_CHANNEL_MASK);
b760183e9631ce Akhil R 2022-09-13  1393  		tdma->chan_mask = TEGRA_GPCDMA_DEFAULT_CHANNEL_MASK;
b760183e9631ce Akhil R 2022-09-13  1394  	}
b760183e9631ce Akhil R 2022-09-13  1395  
ee17028009d49f Akhil R 2022-02-25  1396  	INIT_LIST_HEAD(&tdma->dma_dev.channels);
ee17028009d49f Akhil R 2022-02-25  1397  	for (i = 0; i < cdata->nr_channels; i++) {
ee17028009d49f Akhil R 2022-02-25  1398  		struct tegra_dma_channel *tdc = &tdma->channels[i];
ee17028009d49f Akhil R 2022-02-25  1399  
b760183e9631ce Akhil R 2022-09-13  1400  		/* Check for channel mask */
b760183e9631ce Akhil R 2022-09-13  1401  		if (!((1 << i) & tdma->chan_mask))
b760183e9631ce Akhil R 2022-09-13  1402  			continue;
b760183e9631ce Akhil R 2022-09-13  1403  
461cd3709f266d Akhil R 2022-05-05  1404  		tdc->irq = platform_get_irq(pdev, i);
461cd3709f266d Akhil R 2022-05-05  1405  		if (tdc->irq < 0)
461cd3709f266d Akhil R 2022-05-05  1406  			return tdc->irq;
461cd3709f266d Akhil R 2022-05-05  1407  
b760183e9631ce Akhil R 2022-09-13  1408  		tdc->chan_base_offset = TEGRA_GPCDMA_CHANNEL_BASE_ADDR_OFFSET +
ee17028009d49f Akhil R 2022-02-25  1409  					i * cdata->channel_reg_size;
ee17028009d49f Akhil R 2022-02-25  1410  		snprintf(tdc->name, sizeof(tdc->name), "gpcdma.%d", i);
ee17028009d49f Akhil R 2022-02-25  1411  		tdc->tdma = tdma;
ee17028009d49f Akhil R 2022-02-25  1412  		tdc->id = i;
ee17028009d49f Akhil R 2022-02-25  1413  		tdc->slave_id = -1;
ee17028009d49f Akhil R 2022-02-25  1414  
ee17028009d49f Akhil R 2022-02-25  1415  		vchan_init(&tdc->vc, &tdma->dma_dev);
ee17028009d49f Akhil R 2022-02-25  1416  		tdc->vc.desc_free = tegra_dma_desc_free;
ee17028009d49f Akhil R 2022-02-25  1417  
ee17028009d49f Akhil R 2022-02-25  1418  		/* program stream-id for this channel */
ee17028009d49f Akhil R 2022-02-25  1419  		tegra_dma_program_sid(tdc, stream_id);
ee17028009d49f Akhil R 2022-02-25  1420  		tdc->stream_id = stream_id;
ee17028009d49f Akhil R 2022-02-25  1421  	}
ee17028009d49f Akhil R 2022-02-25  1422  
ee17028009d49f Akhil R 2022-02-25  1423  	dma_cap_set(DMA_SLAVE, tdma->dma_dev.cap_mask);
ee17028009d49f Akhil R 2022-02-25  1424  	dma_cap_set(DMA_PRIVATE, tdma->dma_dev.cap_mask);
ee17028009d49f Akhil R 2022-02-25  1425  	dma_cap_set(DMA_MEMCPY, tdma->dma_dev.cap_mask);
ee17028009d49f Akhil R 2022-02-25  1426  	dma_cap_set(DMA_MEMSET, tdma->dma_dev.cap_mask);
ee17028009d49f Akhil R 2022-02-25  1427  	dma_cap_set(DMA_CYCLIC, tdma->dma_dev.cap_mask);
ee17028009d49f Akhil R 2022-02-25  1428  
ee17028009d49f Akhil R 2022-02-25  1429  	/*
ee17028009d49f Akhil R 2022-02-25  1430  	 * Only word aligned transfers are supported. Set the copy
ee17028009d49f Akhil R 2022-02-25  1431  	 * alignment shift.
ee17028009d49f Akhil R 2022-02-25  1432  	 */
ee17028009d49f Akhil R 2022-02-25  1433  	tdma->dma_dev.copy_align = 2;
ee17028009d49f Akhil R 2022-02-25  1434  	tdma->dma_dev.fill_align = 2;
ee17028009d49f Akhil R 2022-02-25  1435  	tdma->dma_dev.device_alloc_chan_resources =
ee17028009d49f Akhil R 2022-02-25  1436  					tegra_dma_alloc_chan_resources;
ee17028009d49f Akhil R 2022-02-25  1437  	tdma->dma_dev.device_free_chan_resources =
ee17028009d49f Akhil R 2022-02-25  1438  					tegra_dma_free_chan_resources;
ee17028009d49f Akhil R 2022-02-25  1439  	tdma->dma_dev.device_prep_slave_sg = tegra_dma_prep_slave_sg;
ee17028009d49f Akhil R 2022-02-25  1440  	tdma->dma_dev.device_prep_dma_memcpy = tegra_dma_prep_dma_memcpy;
ee17028009d49f Akhil R 2022-02-25  1441  	tdma->dma_dev.device_prep_dma_memset = tegra_dma_prep_dma_memset;
ee17028009d49f Akhil R 2022-02-25  1442  	tdma->dma_dev.device_prep_dma_cyclic = tegra_dma_prep_dma_cyclic;
ee17028009d49f Akhil R 2022-02-25  1443  	tdma->dma_dev.device_config = tegra_dma_slave_config;
ee17028009d49f Akhil R 2022-02-25  1444  	tdma->dma_dev.device_terminate_all = tegra_dma_terminate_all;
ee17028009d49f Akhil R 2022-02-25  1445  	tdma->dma_dev.device_tx_status = tegra_dma_tx_status;
ee17028009d49f Akhil R 2022-02-25  1446  	tdma->dma_dev.device_issue_pending = tegra_dma_issue_pending;
ee17028009d49f Akhil R 2022-02-25  1447  	tdma->dma_dev.device_pause = tegra_dma_device_pause;
ee17028009d49f Akhil R 2022-02-25  1448  	tdma->dma_dev.device_resume = tegra_dma_device_resume;
ee17028009d49f Akhil R 2022-02-25  1449  	tdma->dma_dev.device_synchronize = tegra_dma_chan_synchronize;
ee17028009d49f Akhil R 2022-02-25  1450  	tdma->dma_dev.residue_granularity = DMA_RESIDUE_GRANULARITY_BURST;
ee17028009d49f Akhil R 2022-02-25  1451  
ee17028009d49f Akhil R 2022-02-25  1452  	ret = dma_async_device_register(&tdma->dma_dev);
ee17028009d49f Akhil R 2022-02-25  1453  	if (ret < 0) {
ee17028009d49f Akhil R 2022-02-25  1454  		dev_err_probe(&pdev->dev, ret,
ee17028009d49f Akhil R 2022-02-25  1455  			      "GPC DMA driver registration failed\n");
ee17028009d49f Akhil R 2022-02-25  1456  		return ret;
ee17028009d49f Akhil R 2022-02-25  1457  	}
ee17028009d49f Akhil R 2022-02-25  1458  
ee17028009d49f Akhil R 2022-02-25  1459  	ret = of_dma_controller_register(pdev->dev.of_node,
ee17028009d49f Akhil R 2022-02-25  1460  					 tegra_dma_of_xlate, tdma);
ee17028009d49f Akhil R 2022-02-25  1461  	if (ret < 0) {
ee17028009d49f Akhil R 2022-02-25  1462  		dev_err_probe(&pdev->dev, ret,
ee17028009d49f Akhil R 2022-02-25  1463  			      "GPC DMA OF registration failed\n");
ee17028009d49f Akhil R 2022-02-25  1464  
ee17028009d49f Akhil R 2022-02-25  1465  		dma_async_device_unregister(&tdma->dma_dev);
ee17028009d49f Akhil R 2022-02-25  1466  		return ret;
ee17028009d49f Akhil R 2022-02-25  1467  	}
ee17028009d49f Akhil R 2022-02-25  1468  
ee17028009d49f Akhil R 2022-02-25 @1469  	dev_info(&pdev->dev, "GPC DMA driver register %d channels\n",
b760183e9631ce Akhil R 2022-09-13  1470  		 hweight_long(tdma->chan_mask));
ee17028009d49f Akhil R 2022-02-25  1471  
ee17028009d49f Akhil R 2022-02-25  1472  	return 0;
ee17028009d49f Akhil R 2022-02-25  1473  }
ee17028009d49f Akhil R 2022-02-25  1474
Thierry Reding Sept. 14, 2022, 2:23 p.m. UTC | #2
On Tue, Sep 13, 2022 at 09:22:51PM +0530, Akhil R wrote:
> Add support for dma-channel-mask so that only the specified channels
> are used. This helps to reserve some channels for the firmware.
> 
> This was initially achieved by limiting the channel number to 31 in
> the driver and adjusting the register address to skip channel0 which
> was reserved for a firmware. Now, with this change, the driver can
> align more to the actual hardware which has 32 channels.
> 
> Signed-off-by: Akhil R <akhilrajeev@nvidia.com>
> ---
>  drivers/dma/tegra186-gpc-dma.c | 35 ++++++++++++++++++++++++++++------
>  1 file changed, 29 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/dma/tegra186-gpc-dma.c b/drivers/dma/tegra186-gpc-dma.c
> index fa9bda4a2bc6..f69a800c4f80 100644
> --- a/drivers/dma/tegra186-gpc-dma.c
> +++ b/drivers/dma/tegra186-gpc-dma.c
> @@ -161,7 +161,10 @@
>  #define TEGRA_GPCDMA_BURST_COMPLETION_TIMEOUT	5000 /* 5 msec */
>  
>  /* Channel base address offset from GPCDMA base address */
> -#define TEGRA_GPCDMA_CHANNEL_BASE_ADD_OFFSET	0x20000
> +#define TEGRA_GPCDMA_CHANNEL_BASE_ADDR_OFFSET	0x10000
> +
> +/* Default channel mask reserving channel0 */
> +#define TEGRA_GPCDMA_DEFAULT_CHANNEL_MASK	0xfffffffe
>  
>  struct tegra_dma;
>  struct tegra_dma_channel;
> @@ -246,6 +249,7 @@ struct tegra_dma {
>  	const struct tegra_dma_chip_data *chip_data;
>  	unsigned long sid_m2d_reserved;
>  	unsigned long sid_d2m_reserved;
> +	u32 chan_mask;
>  	void __iomem *base_addr;
>  	struct device *dev;
>  	struct dma_device dma_dev;
> @@ -1288,7 +1292,7 @@ static struct dma_chan *tegra_dma_of_xlate(struct of_phandle_args *dma_spec,
>  }
>  
>  static const struct tegra_dma_chip_data tegra186_dma_chip_data = {
> -	.nr_channels = 31,
> +	.nr_channels = 32,
>  	.channel_reg_size = SZ_64K,
>  	.max_dma_count = SZ_1G,
>  	.hw_support_pause = false,
> @@ -1296,7 +1300,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 = 31,
> +	.nr_channels = 32,
>  	.channel_reg_size = SZ_64K,
>  	.max_dma_count = SZ_1G,
>  	.hw_support_pause = true,
> @@ -1304,7 +1308,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 = 31,
> +	.nr_channels = 32,
>  	.channel_reg_size = SZ_64K,
>  	.max_dma_count = SZ_1G,
>  	.hw_support_pause = true,
> @@ -1380,15 +1384,28 @@ static int tegra_dma_probe(struct platform_device *pdev)
>  	}
>  	stream_id = iommu_spec->ids[0] & 0xffff;
>  
> +	ret = device_property_read_u32(&pdev->dev, "dma-channel-mask",
> +				       &tdma->chan_mask);
> +	if (ret) {
> +		dev_warn(&pdev->dev,
> +			 "Missing dma-channel-mask property, using default channel mask %#x\n",
> +			 TEGRA_GPCDMA_DEFAULT_CHANNEL_MASK);
> +		tdma->chan_mask = TEGRA_GPCDMA_DEFAULT_CHANNEL_MASK;
> +	}
> +
>  	INIT_LIST_HEAD(&tdma->dma_dev.channels);
>  	for (i = 0; i < cdata->nr_channels; i++) {
>  		struct tegra_dma_channel *tdc = &tdma->channels[i];
>  
> +		/* Check for channel mask */
> +		if (!((1 << i) & tdma->chan_mask))

It's more idiomatic to reverse the operands and use the BIT macro, which
checkpatch should've warned about:

	if (!(tdma->chan_mask & BIT(i)))

There's a few other occurrences of that below.

Thierry

> +			continue;
> +
>  		tdc->irq = platform_get_irq(pdev, i);
>  		if (tdc->irq < 0)
>  			return tdc->irq;
>  
> -		tdc->chan_base_offset = TEGRA_GPCDMA_CHANNEL_BASE_ADD_OFFSET +
> +		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->tdma = tdma;
> @@ -1450,7 +1467,7 @@ static int tegra_dma_probe(struct platform_device *pdev)
>  	}
>  
>  	dev_info(&pdev->dev, "GPC DMA driver register %d channels\n",
> -		 cdata->nr_channels);
> +		 hweight_long(tdma->chan_mask));
>  
>  	return 0;
>  }
> @@ -1473,6 +1490,9 @@ static int __maybe_unused tegra_dma_pm_suspend(struct device *dev)
>  	for (i = 0; i < tdma->chip_data->nr_channels; i++) {
>  		struct tegra_dma_channel *tdc = &tdma->channels[i];
>  
> +		if (!((1 << i) & tdma->chan_mask))
> +			continue;
> +
>  		if (tdc->dma_desc) {
>  			dev_err(tdma->dev, "channel %u busy\n", i);
>  			return -EBUSY;
> @@ -1492,6 +1512,9 @@ static int __maybe_unused tegra_dma_pm_resume(struct device *dev)
>  	for (i = 0; i < tdma->chip_data->nr_channels; i++) {
>  		struct tegra_dma_channel *tdc = &tdma->channels[i];
>  
> +		if (!((1 << i) & tdma->chan_mask))
> +			continue;
> +
>  		tegra_dma_program_sid(tdc, tdc->stream_id);
>  	}
>  
> -- 
> 2.17.1
>
diff mbox series

Patch

diff --git a/drivers/dma/tegra186-gpc-dma.c b/drivers/dma/tegra186-gpc-dma.c
index fa9bda4a2bc6..f69a800c4f80 100644
--- a/drivers/dma/tegra186-gpc-dma.c
+++ b/drivers/dma/tegra186-gpc-dma.c
@@ -161,7 +161,10 @@ 
 #define TEGRA_GPCDMA_BURST_COMPLETION_TIMEOUT	5000 /* 5 msec */
 
 /* Channel base address offset from GPCDMA base address */
-#define TEGRA_GPCDMA_CHANNEL_BASE_ADD_OFFSET	0x20000
+#define TEGRA_GPCDMA_CHANNEL_BASE_ADDR_OFFSET	0x10000
+
+/* Default channel mask reserving channel0 */
+#define TEGRA_GPCDMA_DEFAULT_CHANNEL_MASK	0xfffffffe
 
 struct tegra_dma;
 struct tegra_dma_channel;
@@ -246,6 +249,7 @@  struct tegra_dma {
 	const struct tegra_dma_chip_data *chip_data;
 	unsigned long sid_m2d_reserved;
 	unsigned long sid_d2m_reserved;
+	u32 chan_mask;
 	void __iomem *base_addr;
 	struct device *dev;
 	struct dma_device dma_dev;
@@ -1288,7 +1292,7 @@  static struct dma_chan *tegra_dma_of_xlate(struct of_phandle_args *dma_spec,
 }
 
 static const struct tegra_dma_chip_data tegra186_dma_chip_data = {
-	.nr_channels = 31,
+	.nr_channels = 32,
 	.channel_reg_size = SZ_64K,
 	.max_dma_count = SZ_1G,
 	.hw_support_pause = false,
@@ -1296,7 +1300,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 = 31,
+	.nr_channels = 32,
 	.channel_reg_size = SZ_64K,
 	.max_dma_count = SZ_1G,
 	.hw_support_pause = true,
@@ -1304,7 +1308,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 = 31,
+	.nr_channels = 32,
 	.channel_reg_size = SZ_64K,
 	.max_dma_count = SZ_1G,
 	.hw_support_pause = true,
@@ -1380,15 +1384,28 @@  static int tegra_dma_probe(struct platform_device *pdev)
 	}
 	stream_id = iommu_spec->ids[0] & 0xffff;
 
+	ret = device_property_read_u32(&pdev->dev, "dma-channel-mask",
+				       &tdma->chan_mask);
+	if (ret) {
+		dev_warn(&pdev->dev,
+			 "Missing dma-channel-mask property, using default channel mask %#x\n",
+			 TEGRA_GPCDMA_DEFAULT_CHANNEL_MASK);
+		tdma->chan_mask = TEGRA_GPCDMA_DEFAULT_CHANNEL_MASK;
+	}
+
 	INIT_LIST_HEAD(&tdma->dma_dev.channels);
 	for (i = 0; i < cdata->nr_channels; i++) {
 		struct tegra_dma_channel *tdc = &tdma->channels[i];
 
+		/* Check for channel mask */
+		if (!((1 << i) & tdma->chan_mask))
+			continue;
+
 		tdc->irq = platform_get_irq(pdev, i);
 		if (tdc->irq < 0)
 			return tdc->irq;
 
-		tdc->chan_base_offset = TEGRA_GPCDMA_CHANNEL_BASE_ADD_OFFSET +
+		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->tdma = tdma;
@@ -1450,7 +1467,7 @@  static int tegra_dma_probe(struct platform_device *pdev)
 	}
 
 	dev_info(&pdev->dev, "GPC DMA driver register %d channels\n",
-		 cdata->nr_channels);
+		 hweight_long(tdma->chan_mask));
 
 	return 0;
 }
@@ -1473,6 +1490,9 @@  static int __maybe_unused tegra_dma_pm_suspend(struct device *dev)
 	for (i = 0; i < tdma->chip_data->nr_channels; i++) {
 		struct tegra_dma_channel *tdc = &tdma->channels[i];
 
+		if (!((1 << i) & tdma->chan_mask))
+			continue;
+
 		if (tdc->dma_desc) {
 			dev_err(tdma->dev, "channel %u busy\n", i);
 			return -EBUSY;
@@ -1492,6 +1512,9 @@  static int __maybe_unused tegra_dma_pm_resume(struct device *dev)
 	for (i = 0; i < tdma->chip_data->nr_channels; i++) {
 		struct tegra_dma_channel *tdc = &tdma->channels[i];
 
+		if (!((1 << i) & tdma->chan_mask))
+			continue;
+
 		tegra_dma_program_sid(tdc, tdc->stream_id);
 	}