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 <pmedawala@nvidia.com> Reviewed-by: Uday Gupta <udayg@nvidia.com> Reviewed-by: Sameer Pujar <spujar@nvidia.com> Reviewed-by: Niranjan Dighe <ndighe@nvidia.com> Tested-by: Abhilash G <abhilashg@nvidia.com> Reviewed-by: Abhilash G <abhilashg@nvidia.com> Signed-off-by: Laxman Dewangan <ldewangan@nvidia.com> Acked-by: Jacob Martin <jacob.martin@canonical.com> Acked-by: Noah Wager <noah.wager@canonical.com> Signed-off-by: Noah Wager <noah.wager@canonical.com>
This commit is contained in:
+55
-10
@@ -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 <linux/clk.h>
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user