Skip to content

Commit 21e1273

Browse files
Sheetalvinodkoul
authored andcommitted
dmaengine: tegra210-adma: Add Tegra264 support
Add Tegra264 ADMA support with following changes: - Add soc_data for Tegra264-specific variations. - Tegra264 supports 64 channels and 10 pages, hence update the global page configuration. - In Tegra264 FIFO and outstanding request configs are moved to global registers, hence add those registers offset in adma channel struct. Also, 'has_outstanding_reqs' is removed and configuration moved to the SoC data. - Update channel direction and mode bit positions as per Tegra264. - Register offsets are updated to align with Tegra264. Signed-off-by: Sheetal <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Vinod Koul <[email protected]>
1 parent b81cd16 commit 21e1273

File tree

1 file changed

+160
-25
lines changed

1 file changed

+160
-25
lines changed

drivers/dma/tegra210-adma.c

Lines changed: 160 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,10 @@
2727

2828
#define ADMA_CH_INT_CLEAR 0x1c
2929
#define ADMA_CH_CTRL 0x24
30-
#define ADMA_CH_CTRL_DIR(val) (((val) & 0xf) << 12)
30+
#define ADMA_CH_CTRL_DIR(val, mask, shift) (((val) & (mask)) << (shift))
3131
#define ADMA_CH_CTRL_DIR_AHUB2MEM 2
3232
#define ADMA_CH_CTRL_DIR_MEM2AHUB 4
33-
#define ADMA_CH_CTRL_MODE_CONTINUOUS (2 << 8)
33+
#define ADMA_CH_CTRL_MODE_CONTINUOUS(shift) (2 << (shift))
3434
#define ADMA_CH_CTRL_FLOWCTRL_EN BIT(1)
3535
#define ADMA_CH_CTRL_XFER_PAUSE_SHIFT 0
3636

@@ -41,15 +41,27 @@
4141
#define ADMA_CH_CONFIG_MAX_BURST_SIZE 16
4242
#define ADMA_CH_CONFIG_WEIGHT_FOR_WRR(val) ((val) & 0xf)
4343
#define ADMA_CH_CONFIG_MAX_BUFS 8
44-
#define TEGRA186_ADMA_CH_CONFIG_OUTSTANDING_REQS(reqs) (reqs << 4)
44+
#define TEGRA186_ADMA_CH_CONFIG_OUTSTANDING_REQS(reqs) ((reqs) << 4)
45+
46+
#define ADMA_GLOBAL_CH_CONFIG 0x400
47+
#define ADMA_GLOBAL_CH_CONFIG_WEIGHT_FOR_WRR(val) ((val) & 0x7)
48+
#define ADMA_GLOBAL_CH_CONFIG_OUTSTANDING_REQS(reqs) ((reqs) << 8)
4549

4650
#define TEGRA186_ADMA_GLOBAL_PAGE_CHGRP 0x30
4751
#define TEGRA186_ADMA_GLOBAL_PAGE_RX_REQ 0x70
4852
#define TEGRA186_ADMA_GLOBAL_PAGE_TX_REQ 0x84
53+
#define TEGRA264_ADMA_GLOBAL_PAGE_CHGRP_0 0x44
54+
#define TEGRA264_ADMA_GLOBAL_PAGE_CHGRP_1 0x48
55+
#define TEGRA264_ADMA_GLOBAL_PAGE_RX_REQ_0 0x100
56+
#define TEGRA264_ADMA_GLOBAL_PAGE_RX_REQ_1 0x104
57+
#define TEGRA264_ADMA_GLOBAL_PAGE_TX_REQ_0 0x180
58+
#define TEGRA264_ADMA_GLOBAL_PAGE_TX_REQ_1 0x184
59+
#define TEGRA264_ADMA_GLOBAL_PAGE_OFFSET 0x8
4960

5061
#define ADMA_CH_FIFO_CTRL 0x2c
5162
#define ADMA_CH_TX_FIFO_SIZE_SHIFT 8
5263
#define ADMA_CH_RX_FIFO_SIZE_SHIFT 0
64+
#define ADMA_GLOBAL_CH_FIFO_CTRL 0x300
5365

5466
#define ADMA_CH_LOWER_SRC_ADDR 0x34
5567
#define ADMA_CH_LOWER_TRG_ADDR 0x3c
@@ -73,36 +85,48 @@ struct tegra_adma;
7385
* @adma_get_burst_config: Function callback used to set DMA burst size.
7486
* @global_reg_offset: Register offset of DMA global register.
7587
* @global_int_clear: Register offset of DMA global interrupt clear.
88+
* @global_ch_fifo_base: Global channel fifo ctrl base offset
89+
* @global_ch_config_base: Global channel config base offset
7690
* @ch_req_tx_shift: Register offset for AHUB transmit channel select.
7791
* @ch_req_rx_shift: Register offset for AHUB receive channel select.
92+
* @ch_dir_shift: Channel direction bit position.
93+
* @ch_mode_shift: Channel mode bit position.
7894
* @ch_base_offset: Register offset of DMA channel registers.
95+
* @ch_tc_offset_diff: From TC register onwards offset differs for Tegra264
7996
* @ch_fifo_ctrl: Default value for channel FIFO CTRL register.
97+
* @ch_config: Outstanding and WRR config values
8098
* @ch_req_mask: Mask for Tx or Rx channel select.
99+
* @ch_dir_mask: Mask for channel direction.
81100
* @ch_req_max: Maximum number of Tx or Rx channels available.
82101
* @ch_reg_size: Size of DMA channel register space.
83102
* @nr_channels: Number of DMA channels available.
84103
* @ch_fifo_size_mask: Mask for FIFO size field.
85104
* @sreq_index_offset: Slave channel index offset.
86105
* @max_page: Maximum ADMA Channel Page.
87-
* @has_outstanding_reqs: If DMA channel can have outstanding requests.
88106
* @set_global_pg_config: Global page programming.
89107
*/
90108
struct tegra_adma_chip_data {
91109
unsigned int (*adma_get_burst_config)(unsigned int burst_size);
92110
unsigned int global_reg_offset;
93111
unsigned int global_int_clear;
112+
unsigned int global_ch_fifo_base;
113+
unsigned int global_ch_config_base;
94114
unsigned int ch_req_tx_shift;
95115
unsigned int ch_req_rx_shift;
116+
unsigned int ch_dir_shift;
117+
unsigned int ch_mode_shift;
96118
unsigned int ch_base_offset;
119+
unsigned int ch_tc_offset_diff;
97120
unsigned int ch_fifo_ctrl;
121+
unsigned int ch_config;
98122
unsigned int ch_req_mask;
123+
unsigned int ch_dir_mask;
99124
unsigned int ch_req_max;
100125
unsigned int ch_reg_size;
101126
unsigned int nr_channels;
102127
unsigned int ch_fifo_size_mask;
103128
unsigned int sreq_index_offset;
104129
unsigned int max_page;
105-
bool has_outstanding_reqs;
106130
void (*set_global_pg_config)(struct tegra_adma *tdma);
107131
};
108132

@@ -112,6 +136,7 @@ struct tegra_adma_chip_data {
112136
struct tegra_adma_chan_regs {
113137
unsigned int ctrl;
114138
unsigned int config;
139+
unsigned int global_config;
115140
unsigned int src_addr;
116141
unsigned int trg_addr;
117142
unsigned int fifo_ctrl;
@@ -150,6 +175,9 @@ struct tegra_adma_chan {
150175
/* Transfer count and position info */
151176
unsigned int tx_buf_count;
152177
unsigned int tx_buf_pos;
178+
179+
unsigned int global_ch_fifo_offset;
180+
unsigned int global_ch_config_offset;
153181
};
154182

155183
/*
@@ -246,6 +274,29 @@ static void tegra186_adma_global_page_config(struct tegra_adma *tdma)
246274
tdma_write(tdma, TEGRA186_ADMA_GLOBAL_PAGE_TX_REQ + (tdma->ch_page_no * 0x4), 0xffffff);
247275
}
248276

277+
static void tegra264_adma_global_page_config(struct tegra_adma *tdma)
278+
{
279+
u32 global_page_offset = tdma->ch_page_no * TEGRA264_ADMA_GLOBAL_PAGE_OFFSET;
280+
281+
/* If the default page (page1) is not used, then clear page1 registers */
282+
if (tdma->ch_page_no) {
283+
tdma_write(tdma, TEGRA264_ADMA_GLOBAL_PAGE_CHGRP_0, 0);
284+
tdma_write(tdma, TEGRA264_ADMA_GLOBAL_PAGE_CHGRP_1, 0);
285+
tdma_write(tdma, TEGRA264_ADMA_GLOBAL_PAGE_RX_REQ_0, 0);
286+
tdma_write(tdma, TEGRA264_ADMA_GLOBAL_PAGE_RX_REQ_1, 0);
287+
tdma_write(tdma, TEGRA264_ADMA_GLOBAL_PAGE_TX_REQ_0, 0);
288+
tdma_write(tdma, TEGRA264_ADMA_GLOBAL_PAGE_TX_REQ_1, 0);
289+
}
290+
291+
/* Program global registers for selected page */
292+
tdma_write(tdma, TEGRA264_ADMA_GLOBAL_PAGE_CHGRP_0 + global_page_offset, 0xffffffff);
293+
tdma_write(tdma, TEGRA264_ADMA_GLOBAL_PAGE_CHGRP_1 + global_page_offset, 0xffffffff);
294+
tdma_write(tdma, TEGRA264_ADMA_GLOBAL_PAGE_RX_REQ_0 + global_page_offset, 0xffffffff);
295+
tdma_write(tdma, TEGRA264_ADMA_GLOBAL_PAGE_RX_REQ_1 + global_page_offset, 0x1);
296+
tdma_write(tdma, TEGRA264_ADMA_GLOBAL_PAGE_TX_REQ_0 + global_page_offset, 0xffffffff);
297+
tdma_write(tdma, TEGRA264_ADMA_GLOBAL_PAGE_TX_REQ_1 + global_page_offset, 0x1);
298+
}
299+
249300
static int tegra_adma_init(struct tegra_adma *tdma)
250301
{
251302
u32 status;
@@ -404,11 +455,21 @@ static void tegra_adma_start(struct tegra_adma_chan *tdc)
404455

405456
tdc->tx_buf_pos = 0;
406457
tdc->tx_buf_count = 0;
407-
tdma_ch_write(tdc, ADMA_CH_TC, ch_regs->tc);
458+
tdma_ch_write(tdc, ADMA_CH_TC - tdc->tdma->cdata->ch_tc_offset_diff, ch_regs->tc);
408459
tdma_ch_write(tdc, ADMA_CH_CTRL, ch_regs->ctrl);
409-
tdma_ch_write(tdc, ADMA_CH_LOWER_SRC_ADDR, ch_regs->src_addr);
410-
tdma_ch_write(tdc, ADMA_CH_LOWER_TRG_ADDR, ch_regs->trg_addr);
411-
tdma_ch_write(tdc, ADMA_CH_FIFO_CTRL, ch_regs->fifo_ctrl);
460+
tdma_ch_write(tdc, ADMA_CH_LOWER_SRC_ADDR - tdc->tdma->cdata->ch_tc_offset_diff,
461+
ch_regs->src_addr);
462+
tdma_ch_write(tdc, ADMA_CH_LOWER_TRG_ADDR - tdc->tdma->cdata->ch_tc_offset_diff,
463+
ch_regs->trg_addr);
464+
465+
if (!tdc->tdma->cdata->global_ch_fifo_base)
466+
tdma_ch_write(tdc, ADMA_CH_FIFO_CTRL, ch_regs->fifo_ctrl);
467+
else if (tdc->global_ch_fifo_offset)
468+
tdma_write(tdc->tdma, tdc->global_ch_fifo_offset, ch_regs->fifo_ctrl);
469+
470+
if (tdc->global_ch_config_offset)
471+
tdma_write(tdc->tdma, tdc->global_ch_config_offset, ch_regs->global_config);
472+
412473
tdma_ch_write(tdc, ADMA_CH_CONFIG, ch_regs->config);
413474

414475
/* Start ADMA */
@@ -421,7 +482,8 @@ static unsigned int tegra_adma_get_residue(struct tegra_adma_chan *tdc)
421482
{
422483
struct tegra_adma_desc *desc = tdc->desc;
423484
unsigned int max = ADMA_CH_XFER_STATUS_COUNT_MASK + 1;
424-
unsigned int pos = tdma_ch_read(tdc, ADMA_CH_XFER_STATUS);
485+
unsigned int pos = tdma_ch_read(tdc, ADMA_CH_XFER_STATUS -
486+
tdc->tdma->cdata->ch_tc_offset_diff);
425487
unsigned int periods_remaining;
426488

427489
/*
@@ -627,13 +689,16 @@ static int tegra_adma_set_xfer_params(struct tegra_adma_chan *tdc,
627689
return -EINVAL;
628690
}
629691

630-
ch_regs->ctrl |= ADMA_CH_CTRL_DIR(adma_dir) |
631-
ADMA_CH_CTRL_MODE_CONTINUOUS |
692+
ch_regs->ctrl |= ADMA_CH_CTRL_DIR(adma_dir, cdata->ch_dir_mask,
693+
cdata->ch_dir_shift) |
694+
ADMA_CH_CTRL_MODE_CONTINUOUS(cdata->ch_mode_shift) |
632695
ADMA_CH_CTRL_FLOWCTRL_EN;
633696
ch_regs->config |= cdata->adma_get_burst_config(burst_size);
634-
ch_regs->config |= ADMA_CH_CONFIG_WEIGHT_FOR_WRR(1);
635-
if (cdata->has_outstanding_reqs)
636-
ch_regs->config |= TEGRA186_ADMA_CH_CONFIG_OUTSTANDING_REQS(8);
697+
698+
if (cdata->global_ch_config_base)
699+
ch_regs->global_config |= cdata->ch_config;
700+
else
701+
ch_regs->config |= cdata->ch_config;
637702

638703
/*
639704
* 'sreq_index' represents the current ADMAIF channel number and as per
@@ -788,12 +853,23 @@ static int __maybe_unused tegra_adma_runtime_suspend(struct device *dev)
788853
/* skip if channel is not active */
789854
if (!ch_reg->cmd)
790855
continue;
791-
ch_reg->tc = tdma_ch_read(tdc, ADMA_CH_TC);
792-
ch_reg->src_addr = tdma_ch_read(tdc, ADMA_CH_LOWER_SRC_ADDR);
793-
ch_reg->trg_addr = tdma_ch_read(tdc, ADMA_CH_LOWER_TRG_ADDR);
856+
ch_reg->tc = tdma_ch_read(tdc, ADMA_CH_TC - tdma->cdata->ch_tc_offset_diff);
857+
ch_reg->src_addr = tdma_ch_read(tdc, ADMA_CH_LOWER_SRC_ADDR -
858+
tdma->cdata->ch_tc_offset_diff);
859+
ch_reg->trg_addr = tdma_ch_read(tdc, ADMA_CH_LOWER_TRG_ADDR -
860+
tdma->cdata->ch_tc_offset_diff);
794861
ch_reg->ctrl = tdma_ch_read(tdc, ADMA_CH_CTRL);
795-
ch_reg->fifo_ctrl = tdma_ch_read(tdc, ADMA_CH_FIFO_CTRL);
862+
863+
if (tdc->global_ch_config_offset)
864+
ch_reg->global_config = tdma_read(tdc->tdma, tdc->global_ch_config_offset);
865+
866+
if (!tdc->tdma->cdata->global_ch_fifo_base)
867+
ch_reg->fifo_ctrl = tdma_ch_read(tdc, ADMA_CH_FIFO_CTRL);
868+
else if (tdc->global_ch_fifo_offset)
869+
ch_reg->fifo_ctrl = tdma_read(tdc->tdma, tdc->global_ch_fifo_offset);
870+
796871
ch_reg->config = tdma_ch_read(tdc, ADMA_CH_CONFIG);
872+
797873
}
798874

799875
clk_disable:
@@ -832,12 +908,23 @@ static int __maybe_unused tegra_adma_runtime_resume(struct device *dev)
832908
/* skip if channel was not active earlier */
833909
if (!ch_reg->cmd)
834910
continue;
835-
tdma_ch_write(tdc, ADMA_CH_TC, ch_reg->tc);
836-
tdma_ch_write(tdc, ADMA_CH_LOWER_SRC_ADDR, ch_reg->src_addr);
837-
tdma_ch_write(tdc, ADMA_CH_LOWER_TRG_ADDR, ch_reg->trg_addr);
911+
tdma_ch_write(tdc, ADMA_CH_TC - tdma->cdata->ch_tc_offset_diff, ch_reg->tc);
912+
tdma_ch_write(tdc, ADMA_CH_LOWER_SRC_ADDR - tdma->cdata->ch_tc_offset_diff,
913+
ch_reg->src_addr);
914+
tdma_ch_write(tdc, ADMA_CH_LOWER_TRG_ADDR - tdma->cdata->ch_tc_offset_diff,
915+
ch_reg->trg_addr);
838916
tdma_ch_write(tdc, ADMA_CH_CTRL, ch_reg->ctrl);
839-
tdma_ch_write(tdc, ADMA_CH_FIFO_CTRL, ch_reg->fifo_ctrl);
917+
918+
if (!tdc->tdma->cdata->global_ch_fifo_base)
919+
tdma_ch_write(tdc, ADMA_CH_FIFO_CTRL, ch_reg->fifo_ctrl);
920+
else if (tdc->global_ch_fifo_offset)
921+
tdma_write(tdc->tdma, tdc->global_ch_fifo_offset, ch_reg->fifo_ctrl);
922+
923+
if (tdc->global_ch_config_offset)
924+
tdma_write(tdc->tdma, tdc->global_ch_config_offset, ch_reg->global_config);
925+
840926
tdma_ch_write(tdc, ADMA_CH_CONFIG, ch_reg->config);
927+
841928
tdma_ch_write(tdc, ADMA_CH_CMD, ch_reg->cmd);
842929
}
843930

@@ -848,41 +935,80 @@ static const struct tegra_adma_chip_data tegra210_chip_data = {
848935
.adma_get_burst_config = tegra210_adma_get_burst_config,
849936
.global_reg_offset = 0xc00,
850937
.global_int_clear = 0x20,
938+
.global_ch_fifo_base = 0,
939+
.global_ch_config_base = 0,
851940
.ch_req_tx_shift = 28,
852941
.ch_req_rx_shift = 24,
942+
.ch_dir_shift = 12,
943+
.ch_mode_shift = 8,
853944
.ch_base_offset = 0,
945+
.ch_tc_offset_diff = 0,
946+
.ch_config = ADMA_CH_CONFIG_WEIGHT_FOR_WRR(1),
854947
.ch_req_mask = 0xf,
948+
.ch_dir_mask = 0xf,
855949
.ch_req_max = 10,
856950
.ch_reg_size = 0x80,
857951
.nr_channels = 22,
858952
.ch_fifo_size_mask = 0xf,
859953
.sreq_index_offset = 2,
860954
.max_page = 0,
861-
.has_outstanding_reqs = false,
862955
.set_global_pg_config = NULL,
863956
};
864957

865958
static const struct tegra_adma_chip_data tegra186_chip_data = {
866959
.adma_get_burst_config = tegra186_adma_get_burst_config,
867960
.global_reg_offset = 0,
868961
.global_int_clear = 0x402c,
962+
.global_ch_fifo_base = 0,
963+
.global_ch_config_base = 0,
869964
.ch_req_tx_shift = 27,
870965
.ch_req_rx_shift = 22,
966+
.ch_dir_shift = 12,
967+
.ch_mode_shift = 8,
871968
.ch_base_offset = 0x10000,
969+
.ch_tc_offset_diff = 0,
970+
.ch_config = ADMA_CH_CONFIG_WEIGHT_FOR_WRR(1) |
971+
TEGRA186_ADMA_CH_CONFIG_OUTSTANDING_REQS(8),
872972
.ch_req_mask = 0x1f,
973+
.ch_dir_mask = 0xf,
873974
.ch_req_max = 20,
874975
.ch_reg_size = 0x100,
875976
.nr_channels = 32,
876977
.ch_fifo_size_mask = 0x1f,
877978
.sreq_index_offset = 4,
878979
.max_page = 4,
879-
.has_outstanding_reqs = true,
880980
.set_global_pg_config = tegra186_adma_global_page_config,
881981
};
882982

983+
static const struct tegra_adma_chip_data tegra264_chip_data = {
984+
.adma_get_burst_config = tegra186_adma_get_burst_config,
985+
.global_reg_offset = 0,
986+
.global_int_clear = 0x800c,
987+
.global_ch_fifo_base = ADMA_GLOBAL_CH_FIFO_CTRL,
988+
.global_ch_config_base = ADMA_GLOBAL_CH_CONFIG,
989+
.ch_req_tx_shift = 26,
990+
.ch_req_rx_shift = 20,
991+
.ch_dir_shift = 10,
992+
.ch_mode_shift = 7,
993+
.ch_base_offset = 0x10000,
994+
.ch_tc_offset_diff = 4,
995+
.ch_config = ADMA_GLOBAL_CH_CONFIG_WEIGHT_FOR_WRR(1) |
996+
ADMA_GLOBAL_CH_CONFIG_OUTSTANDING_REQS(8),
997+
.ch_req_mask = 0x3f,
998+
.ch_dir_mask = 7,
999+
.ch_req_max = 32,
1000+
.ch_reg_size = 0x100,
1001+
.nr_channels = 64,
1002+
.ch_fifo_size_mask = 0x7f,
1003+
.sreq_index_offset = 0,
1004+
.max_page = 10,
1005+
.set_global_pg_config = tegra264_adma_global_page_config,
1006+
};
1007+
8831008
static const struct of_device_id tegra_adma_of_match[] = {
8841009
{ .compatible = "nvidia,tegra210-adma", .data = &tegra210_chip_data },
8851010
{ .compatible = "nvidia,tegra186-adma", .data = &tegra186_chip_data },
1011+
{ .compatible = "nvidia,tegra264-adma", .data = &tegra264_chip_data },
8861012
{ },
8871013
};
8881014
MODULE_DEVICE_TABLE(of, tegra_adma_of_match);
@@ -985,6 +1111,15 @@ static int tegra_adma_probe(struct platform_device *pdev)
9851111

9861112
tdc->chan_addr = tdma->ch_base_addr + (cdata->ch_reg_size * i);
9871113

1114+
if (tdma->base_addr) {
1115+
if (cdata->global_ch_fifo_base)
1116+
tdc->global_ch_fifo_offset = cdata->global_ch_fifo_base + (4 * i);
1117+
1118+
if (cdata->global_ch_config_base)
1119+
tdc->global_ch_config_offset =
1120+
cdata->global_ch_config_base + (4 * i);
1121+
}
1122+
9881123
tdc->irq = of_irq_get(pdev->dev.of_node, i);
9891124
if (tdc->irq <= 0) {
9901125
ret = tdc->irq ?: -ENXIO;

0 commit comments

Comments
 (0)