From 2e13357c8178b8a2a4645236b1321953f81a0780 Mon Sep 17 00:00:00 2001 From: pmedawala Date: Mon, 7 Nov 2022 14:24:59 +0000 Subject: [PATCH] NVIDIA: SAUCE: dmaengine: tegra210-adma: Add support for virtualisation BugLink: https://bugs.launchpad.net/bugs/2072591 Provide support to parse dma-channels and dma-channel-mask DT properties for ADMA virtualisation. http://nvbugs/3735757 Signed-off-by: pmedawala Reviewed-by: Uday Gupta Reviewed-by: Sameer Pujar Reviewed-by: Niranjan Dighe Tested-by: Abhilash G Reviewed-by: Abhilash G Signed-off-by: Laxman Dewangan Acked-by: Jacob Martin Acked-by: Noah Wager Signed-off-by: Noah Wager --- drivers/dma/tegra210-adma.c | 65 +++++++++++++++++++++++++++++++------ 1 file changed, 55 insertions(+), 10 deletions(-) diff --git a/drivers/dma/tegra210-adma.c b/drivers/dma/tegra210-adma.c index 24ad7077c53b..7b98719fda06 100644 --- a/drivers/dma/tegra210-adma.c +++ b/drivers/dma/tegra210-adma.c @@ -2,7 +2,7 @@ /* * ADMA driver for Nvidia's Tegra210 ADMA controller. * - * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved. */ #include @@ -80,6 +80,7 @@ struct tegra_adma; * @ch_fifo_size_mask: Mask for FIFO size field. * @sreq_index_offset: Slave channel index offset. * @has_outstanding_reqs: If DMA channel can have outstanding requests. + * @is_virtualized: Is DMA virtualized, if yes, it does not write to global PAGE */ struct tegra_adma_chip_data { unsigned int (*adma_get_burst_config)(unsigned int burst_size); @@ -96,6 +97,7 @@ struct tegra_adma_chip_data { unsigned int ch_fifo_size_mask; unsigned int sreq_index_offset; bool has_outstanding_reqs; + bool is_virtualized; }; /* @@ -225,6 +227,11 @@ static int tegra_adma_init(struct tegra_adma *tdma) /* Clear any interrupts */ tdma_write(tdma, tdma->cdata->ch_base_offset + tdma->cdata->global_int_clear, 0x1); + if (tdma->cdata->is_virtualized) { + tdma->global_cmd = 1; + return 0; + } + /* Assert soft reset */ tdma_write(tdma, ADMA_GLOBAL_SOFT_RESET, 0x1); @@ -667,9 +674,12 @@ static struct dma_async_tx_descriptor *tegra_adma_prep_dma_cyclic( static int tegra_adma_alloc_chan_resources(struct dma_chan *dc) { struct tegra_adma_chan *tdc = to_tegra_adma_chan(dc); - int ret; + int ret, flags; - ret = request_irq(tdc->irq, tegra_adma_isr, 0, dma_chan_name(dc), tdc); + flags = (tdc->tdma->cdata->is_virtualized) ? IRQF_NO_THREAD : 0; + + ret = request_irq(tdc->irq, tegra_adma_isr, flags, + dma_chan_name(dc), tdc); if (ret) { dev_err(tdc2dev(tdc), "failed to get interrupt for %s\n", dma_chan_name(dc)); @@ -736,9 +746,11 @@ static int __maybe_unused tegra_adma_runtime_suspend(struct device *dev) struct tegra_adma_chan *tdc; int i; - tdma->global_cmd = tdma_read(tdma, ADMA_GLOBAL_CMD); - if (!tdma->global_cmd) - goto clk_disable; + if (!tdma->cdata->is_virtualized) { + tdma->global_cmd = tdma_read(tdma, ADMA_GLOBAL_CMD); + if (!tdma->global_cmd) + goto clk_disable; + } for (i = 0; i < tdma->nr_channels; i++) { tdc = &tdma->channels[i]; @@ -777,7 +789,8 @@ static int __maybe_unused tegra_adma_runtime_resume(struct device *dev) dev_err(dev, "ahub clk_enable failed: %d\n", ret); return ret; } - tdma_write(tdma, ADMA_GLOBAL_CMD, tdma->global_cmd); + if (!tdma->cdata->is_virtualized) + tdma_write(tdma, ADMA_GLOBAL_CMD, tdma->global_cmd); if (!tdma->global_cmd) return 0; @@ -835,9 +848,28 @@ static const struct tegra_adma_chip_data tegra186_chip_data = { .has_outstanding_reqs = true, }; +static const struct tegra_adma_chip_data tegra234_virt_chip_data = { + .adma_get_burst_config = tegra186_adma_get_burst_config, + .global_reg_offset = 0, + .global_int_clear = 0x402c, + .ch_req_tx_shift = 27, + .ch_req_rx_shift = 22, + .ch_base_offset = 0x10000, + .ch_req_mask = 0x1f, + .ch_req_max = 20, + .ch_reg_size = 0x100, + .nr_channels = 32, + .ch_fifo_size_mask = 0x1f, + .sreq_index_offset = 4, + .has_outstanding_reqs = true, + .is_virtualized = true, +}; + static const struct of_device_id tegra_adma_of_match[] = { { .compatible = "nvidia,tegra210-adma", .data = &tegra210_chip_data }, { .compatible = "nvidia,tegra186-adma", .data = &tegra186_chip_data }, + { .compatible = "nvidia,tegra234-adma-virt", + .data = &tegra234_virt_chip_data }, { }, }; MODULE_DEVICE_TABLE(of, tegra_adma_of_match); @@ -845,8 +877,11 @@ MODULE_DEVICE_TABLE(of, tegra_adma_of_match); static int tegra_adma_probe(struct platform_device *pdev) { const struct tegra_adma_chip_data *cdata; + struct resource *global_base, *page_base; struct tegra_adma *tdma; int ret, i; + unsigned int dma_chan_mask = 0xFFFFFFFF; + unsigned int chan_page_offset = 0; cdata = of_device_get_match_data(&pdev->dev); if (!cdata) { @@ -865,7 +900,8 @@ static int tegra_adma_probe(struct platform_device *pdev) tdma->nr_channels = cdata->nr_channels; platform_set_drvdata(pdev, tdma); - tdma->base_addr = devm_platform_ioremap_resource(pdev, 0); + global_base = platform_get_resource(pdev, IORESOURCE_MEM, 0); + tdma->base_addr = devm_ioremap_resource(&pdev->dev, global_base); if (IS_ERR(tdma->base_addr)) return PTR_ERR(tdma->base_addr); @@ -875,6 +911,11 @@ static int tegra_adma_probe(struct platform_device *pdev) return PTR_ERR(tdma->ahub_clk); } + page_base = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (page_base) + chan_page_offset = (unsigned int) (page_base->start - + global_base->start - cdata->ch_base_offset); + tdma->dma_chan_mask = devm_kzalloc(&pdev->dev, BITS_TO_LONGS(tdma->nr_channels) * sizeof(unsigned long), GFP_KERNEL); @@ -895,15 +936,19 @@ static int tegra_adma_probe(struct platform_device *pdev) INIT_LIST_HEAD(&tdma->dma_dev.channels); for (i = 0; i < tdma->nr_channels; i++) { struct tegra_adma_chan *tdc = &tdma->channels[i]; + int bit_pos = ffs(dma_chan_mask) - 1; /* skip for reserved channels */ if (!test_bit(i, tdma->dma_chan_mask)) continue; tdc->chan_addr = tdma->base_addr + cdata->ch_base_offset - + (cdata->ch_reg_size * i); + + chan_page_offset + + (cdata->ch_reg_size * bit_pos); - tdc->irq = of_irq_get(pdev->dev.of_node, i); + dma_chan_mask &= ~(1 << bit_pos); + + tdc->irq = of_irq_get(pdev->dev.of_node, bit_pos); if (tdc->irq <= 0) { ret = tdc->irq ?: -ENXIO; goto irq_dispose;