Skip to content

Commit

Permalink
dmaengine: tegra210-adma: Support channel page
Browse files Browse the repository at this point in the history
Multiple ADMA Channel page hardware support has been
added from TEGRA186 and onwards.

- Add support in the tegra adma driver to handle selective
  channel page usage
- Make global register programming optional

Signed-off-by: Mohan Kumar D <mkumard@nvidia.com>
Link: https://lore.kernel.org/r/20241217074358.340180-3-mkumard@nvidia.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>
  • Loading branch information
Mohan Kumar D authored and Vinod Koul committed Dec 24, 2024
1 parent 762b37f commit 68811c9
Showing 1 changed file with 76 additions and 10 deletions.
86 changes: 76 additions & 10 deletions drivers/dma/tegra210-adma.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@
#define ADMA_CH_CONFIG_MAX_BUFS 8
#define TEGRA186_ADMA_CH_CONFIG_OUTSTANDING_REQS(reqs) (reqs << 4)

#define TEGRA186_ADMA_GLOBAL_PAGE_CHGRP 0x30
#define TEGRA186_ADMA_GLOBAL_PAGE_RX_REQ 0x70
#define TEGRA186_ADMA_GLOBAL_PAGE_TX_REQ 0x84

#define ADMA_CH_FIFO_CTRL 0x2c
#define ADMA_CH_TX_FIFO_SIZE_SHIFT 8
#define ADMA_CH_RX_FIFO_SIZE_SHIFT 0
Expand Down Expand Up @@ -96,6 +100,7 @@ struct tegra_adma_chip_data {
unsigned int ch_fifo_size_mask;
unsigned int sreq_index_offset;
bool has_outstanding_reqs;
void (*set_global_pg_config)(struct tegra_adma *tdma);
};

/*
Expand Down Expand Up @@ -151,6 +156,7 @@ struct tegra_adma {
struct dma_device dma_dev;
struct device *dev;
void __iomem *base_addr;
void __iomem *ch_base_addr;
struct clk *ahub_clk;
unsigned int nr_channels;
unsigned long *dma_chan_mask;
Expand All @@ -159,6 +165,7 @@ struct tegra_adma {

/* Used to store global command register state when suspending */
unsigned int global_cmd;
unsigned int ch_page_no;

const struct tegra_adma_chip_data *cdata;

Expand All @@ -176,6 +183,11 @@ static inline u32 tdma_read(struct tegra_adma *tdma, u32 reg)
return readl(tdma->base_addr + tdma->cdata->global_reg_offset + reg);
}

static inline void tdma_ch_global_write(struct tegra_adma *tdma, u32 reg, u32 val)
{
writel(val, tdma->ch_base_addr + tdma->cdata->global_reg_offset + reg);
}

static inline void tdma_ch_write(struct tegra_adma_chan *tdc, u32 reg, u32 val)
{
writel(val, tdc->chan_addr + reg);
Expand Down Expand Up @@ -217,13 +229,30 @@ static int tegra_adma_slave_config(struct dma_chan *dc,
return 0;
}

static void tegra186_adma_global_page_config(struct tegra_adma *tdma)
{
/*
* Clear the default page1 channel group configs and program
* the global registers based on the actual page usage
*/
tdma_write(tdma, TEGRA186_ADMA_GLOBAL_PAGE_CHGRP, 0);
tdma_write(tdma, TEGRA186_ADMA_GLOBAL_PAGE_RX_REQ, 0);
tdma_write(tdma, TEGRA186_ADMA_GLOBAL_PAGE_TX_REQ, 0);
tdma_write(tdma, TEGRA186_ADMA_GLOBAL_PAGE_CHGRP + (tdma->ch_page_no * 0x4), 0xff);
tdma_write(tdma, TEGRA186_ADMA_GLOBAL_PAGE_RX_REQ + (tdma->ch_page_no * 0x4), 0x1ffffff);
tdma_write(tdma, TEGRA186_ADMA_GLOBAL_PAGE_TX_REQ + (tdma->ch_page_no * 0x4), 0xffffff);
}

static int tegra_adma_init(struct tegra_adma *tdma)
{
u32 status;
int ret;

/* Clear any interrupts */
tdma_write(tdma, tdma->cdata->ch_base_offset + tdma->cdata->global_int_clear, 0x1);
/* Clear any channels group global interrupts */
tdma_ch_global_write(tdma, tdma->cdata->global_int_clear, 0x1);

if (!tdma->base_addr)
return 0;

/* Assert soft reset */
tdma_write(tdma, ADMA_GLOBAL_SOFT_RESET, 0x1);
Expand All @@ -237,6 +266,9 @@ static int tegra_adma_init(struct tegra_adma *tdma)
if (ret)
return ret;

if (tdma->cdata->set_global_pg_config)
tdma->cdata->set_global_pg_config(tdma);

/* Enable global ADMA registers */
tdma_write(tdma, ADMA_GLOBAL_CMD, 1);

Expand Down Expand Up @@ -736,7 +768,9 @@ 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->base_addr)
tdma->global_cmd = tdma_read(tdma, ADMA_GLOBAL_CMD);

if (!tdma->global_cmd)
goto clk_disable;

Expand Down Expand Up @@ -777,7 +811,11 @@ 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->base_addr) {
tdma_write(tdma, ADMA_GLOBAL_CMD, tdma->global_cmd);
if (tdma->cdata->set_global_pg_config)
tdma->cdata->set_global_pg_config(tdma);
}

if (!tdma->global_cmd)
return 0;
Expand Down Expand Up @@ -817,6 +855,7 @@ static const struct tegra_adma_chip_data tegra210_chip_data = {
.ch_fifo_size_mask = 0xf,
.sreq_index_offset = 2,
.has_outstanding_reqs = false,
.set_global_pg_config = NULL,
};

static const struct tegra_adma_chip_data tegra186_chip_data = {
Expand All @@ -833,6 +872,7 @@ static const struct tegra_adma_chip_data tegra186_chip_data = {
.ch_fifo_size_mask = 0x1f,
.sreq_index_offset = 4,
.has_outstanding_reqs = true,
.set_global_pg_config = tegra186_adma_global_page_config,
};

static const struct of_device_id tegra_adma_of_match[] = {
Expand All @@ -846,7 +886,8 @@ static int tegra_adma_probe(struct platform_device *pdev)
{
const struct tegra_adma_chip_data *cdata;
struct tegra_adma *tdma;
int ret, i;
struct resource *res_page, *res_base;
int ret, i, page_no;

cdata = of_device_get_match_data(&pdev->dev);
if (!cdata) {
Expand All @@ -865,9 +906,35 @@ 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);
if (IS_ERR(tdma->base_addr))
return PTR_ERR(tdma->base_addr);
res_page = platform_get_resource_byname(pdev, IORESOURCE_MEM, "page");
if (res_page) {
tdma->ch_base_addr = devm_ioremap_resource(&pdev->dev, res_page);
if (IS_ERR(tdma->ch_base_addr))
return PTR_ERR(tdma->ch_base_addr);

res_base = platform_get_resource_byname(pdev, IORESOURCE_MEM, "global");
if (res_base) {
page_no = (res_page->start - res_base->start) / cdata->ch_base_offset;
if (page_no <= 0)
return -EINVAL;
tdma->ch_page_no = page_no - 1;
tdma->base_addr = devm_ioremap_resource(&pdev->dev, res_base);
if (IS_ERR(tdma->base_addr))
return PTR_ERR(tdma->base_addr);
}
} else {
/* If no 'page' property found, then reg DT binding would be legacy */
res_base = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (res_base) {
tdma->base_addr = devm_ioremap_resource(&pdev->dev, res_base);
if (IS_ERR(tdma->base_addr))
return PTR_ERR(tdma->base_addr);
} else {
return -ENODEV;
}

tdma->ch_base_addr = tdma->base_addr + cdata->ch_base_offset;
}

tdma->ahub_clk = devm_clk_get(&pdev->dev, "d_audio");
if (IS_ERR(tdma->ahub_clk)) {
Expand Down Expand Up @@ -900,8 +967,7 @@ static int tegra_adma_probe(struct platform_device *pdev)
if (!test_bit(i, tdma->dma_chan_mask))
continue;

tdc->chan_addr = tdma->base_addr + cdata->ch_base_offset
+ (cdata->ch_reg_size * i);
tdc->chan_addr = tdma->ch_base_addr + (cdata->ch_reg_size * i);

tdc->irq = of_irq_get(pdev->dev.of_node, i);
if (tdc->irq <= 0) {
Expand Down

0 comments on commit 68811c9

Please sign in to comment.