Skip to content

Commit 68811c9

Browse files
mkumardvinodkoul
authored andcommitted
dmaengine: tegra210-adma: Support channel page
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 <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Vinod Koul <[email protected]>
1 parent 762b37f commit 68811c9

File tree

1 file changed

+76
-10
lines changed

1 file changed

+76
-10
lines changed

drivers/dma/tegra210-adma.c

Lines changed: 76 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@
4343
#define ADMA_CH_CONFIG_MAX_BUFS 8
4444
#define TEGRA186_ADMA_CH_CONFIG_OUTSTANDING_REQS(reqs) (reqs << 4)
4545

46+
#define TEGRA186_ADMA_GLOBAL_PAGE_CHGRP 0x30
47+
#define TEGRA186_ADMA_GLOBAL_PAGE_RX_REQ 0x70
48+
#define TEGRA186_ADMA_GLOBAL_PAGE_TX_REQ 0x84
49+
4650
#define ADMA_CH_FIFO_CTRL 0x2c
4751
#define ADMA_CH_TX_FIFO_SIZE_SHIFT 8
4852
#define ADMA_CH_RX_FIFO_SIZE_SHIFT 0
@@ -96,6 +100,7 @@ struct tegra_adma_chip_data {
96100
unsigned int ch_fifo_size_mask;
97101
unsigned int sreq_index_offset;
98102
bool has_outstanding_reqs;
103+
void (*set_global_pg_config)(struct tegra_adma *tdma);
99104
};
100105

101106
/*
@@ -151,6 +156,7 @@ struct tegra_adma {
151156
struct dma_device dma_dev;
152157
struct device *dev;
153158
void __iomem *base_addr;
159+
void __iomem *ch_base_addr;
154160
struct clk *ahub_clk;
155161
unsigned int nr_channels;
156162
unsigned long *dma_chan_mask;
@@ -159,6 +165,7 @@ struct tegra_adma {
159165

160166
/* Used to store global command register state when suspending */
161167
unsigned int global_cmd;
168+
unsigned int ch_page_no;
162169

163170
const struct tegra_adma_chip_data *cdata;
164171

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

186+
static inline void tdma_ch_global_write(struct tegra_adma *tdma, u32 reg, u32 val)
187+
{
188+
writel(val, tdma->ch_base_addr + tdma->cdata->global_reg_offset + reg);
189+
}
190+
179191
static inline void tdma_ch_write(struct tegra_adma_chan *tdc, u32 reg, u32 val)
180192
{
181193
writel(val, tdc->chan_addr + reg);
@@ -217,13 +229,30 @@ static int tegra_adma_slave_config(struct dma_chan *dc,
217229
return 0;
218230
}
219231

232+
static void tegra186_adma_global_page_config(struct tegra_adma *tdma)
233+
{
234+
/*
235+
* Clear the default page1 channel group configs and program
236+
* the global registers based on the actual page usage
237+
*/
238+
tdma_write(tdma, TEGRA186_ADMA_GLOBAL_PAGE_CHGRP, 0);
239+
tdma_write(tdma, TEGRA186_ADMA_GLOBAL_PAGE_RX_REQ, 0);
240+
tdma_write(tdma, TEGRA186_ADMA_GLOBAL_PAGE_TX_REQ, 0);
241+
tdma_write(tdma, TEGRA186_ADMA_GLOBAL_PAGE_CHGRP + (tdma->ch_page_no * 0x4), 0xff);
242+
tdma_write(tdma, TEGRA186_ADMA_GLOBAL_PAGE_RX_REQ + (tdma->ch_page_no * 0x4), 0x1ffffff);
243+
tdma_write(tdma, TEGRA186_ADMA_GLOBAL_PAGE_TX_REQ + (tdma->ch_page_no * 0x4), 0xffffff);
244+
}
245+
220246
static int tegra_adma_init(struct tegra_adma *tdma)
221247
{
222248
u32 status;
223249
int ret;
224250

225-
/* Clear any interrupts */
226-
tdma_write(tdma, tdma->cdata->ch_base_offset + tdma->cdata->global_int_clear, 0x1);
251+
/* Clear any channels group global interrupts */
252+
tdma_ch_global_write(tdma, tdma->cdata->global_int_clear, 0x1);
253+
254+
if (!tdma->base_addr)
255+
return 0;
227256

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

269+
if (tdma->cdata->set_global_pg_config)
270+
tdma->cdata->set_global_pg_config(tdma);
271+
240272
/* Enable global ADMA registers */
241273
tdma_write(tdma, ADMA_GLOBAL_CMD, 1);
242274

@@ -736,7 +768,9 @@ static int __maybe_unused tegra_adma_runtime_suspend(struct device *dev)
736768
struct tegra_adma_chan *tdc;
737769
int i;
738770

739-
tdma->global_cmd = tdma_read(tdma, ADMA_GLOBAL_CMD);
771+
if (tdma->base_addr)
772+
tdma->global_cmd = tdma_read(tdma, ADMA_GLOBAL_CMD);
773+
740774
if (!tdma->global_cmd)
741775
goto clk_disable;
742776

@@ -777,7 +811,11 @@ static int __maybe_unused tegra_adma_runtime_resume(struct device *dev)
777811
dev_err(dev, "ahub clk_enable failed: %d\n", ret);
778812
return ret;
779813
}
780-
tdma_write(tdma, ADMA_GLOBAL_CMD, tdma->global_cmd);
814+
if (tdma->base_addr) {
815+
tdma_write(tdma, ADMA_GLOBAL_CMD, tdma->global_cmd);
816+
if (tdma->cdata->set_global_pg_config)
817+
tdma->cdata->set_global_pg_config(tdma);
818+
}
781819

782820
if (!tdma->global_cmd)
783821
return 0;
@@ -817,6 +855,7 @@ static const struct tegra_adma_chip_data tegra210_chip_data = {
817855
.ch_fifo_size_mask = 0xf,
818856
.sreq_index_offset = 2,
819857
.has_outstanding_reqs = false,
858+
.set_global_pg_config = NULL,
820859
};
821860

822861
static const struct tegra_adma_chip_data tegra186_chip_data = {
@@ -833,6 +872,7 @@ static const struct tegra_adma_chip_data tegra186_chip_data = {
833872
.ch_fifo_size_mask = 0x1f,
834873
.sreq_index_offset = 4,
835874
.has_outstanding_reqs = true,
875+
.set_global_pg_config = tegra186_adma_global_page_config,
836876
};
837877

838878
static const struct of_device_id tegra_adma_of_match[] = {
@@ -846,7 +886,8 @@ static int tegra_adma_probe(struct platform_device *pdev)
846886
{
847887
const struct tegra_adma_chip_data *cdata;
848888
struct tegra_adma *tdma;
849-
int ret, i;
889+
struct resource *res_page, *res_base;
890+
int ret, i, page_no;
850891

851892
cdata = of_device_get_match_data(&pdev->dev);
852893
if (!cdata) {
@@ -865,9 +906,35 @@ static int tegra_adma_probe(struct platform_device *pdev)
865906
tdma->nr_channels = cdata->nr_channels;
866907
platform_set_drvdata(pdev, tdma);
867908

868-
tdma->base_addr = devm_platform_ioremap_resource(pdev, 0);
869-
if (IS_ERR(tdma->base_addr))
870-
return PTR_ERR(tdma->base_addr);
909+
res_page = platform_get_resource_byname(pdev, IORESOURCE_MEM, "page");
910+
if (res_page) {
911+
tdma->ch_base_addr = devm_ioremap_resource(&pdev->dev, res_page);
912+
if (IS_ERR(tdma->ch_base_addr))
913+
return PTR_ERR(tdma->ch_base_addr);
914+
915+
res_base = platform_get_resource_byname(pdev, IORESOURCE_MEM, "global");
916+
if (res_base) {
917+
page_no = (res_page->start - res_base->start) / cdata->ch_base_offset;
918+
if (page_no <= 0)
919+
return -EINVAL;
920+
tdma->ch_page_no = page_no - 1;
921+
tdma->base_addr = devm_ioremap_resource(&pdev->dev, res_base);
922+
if (IS_ERR(tdma->base_addr))
923+
return PTR_ERR(tdma->base_addr);
924+
}
925+
} else {
926+
/* If no 'page' property found, then reg DT binding would be legacy */
927+
res_base = platform_get_resource(pdev, IORESOURCE_MEM, 0);
928+
if (res_base) {
929+
tdma->base_addr = devm_ioremap_resource(&pdev->dev, res_base);
930+
if (IS_ERR(tdma->base_addr))
931+
return PTR_ERR(tdma->base_addr);
932+
} else {
933+
return -ENODEV;
934+
}
935+
936+
tdma->ch_base_addr = tdma->base_addr + cdata->ch_base_offset;
937+
}
871938

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

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

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

0 commit comments

Comments
 (0)