diff options
author | Laxman Dewangan <ldewangan@nvidia.com> | 2014-01-06 13:16:45 -0500 |
---|---|---|
committer | Vinod Koul <vinod.koul@intel.com> | 2014-01-20 04:05:52 -0500 |
commit | 911daccc8b9672ec2206d3741127089dc2c695d4 (patch) | |
tree | c9ecf09f7c6700310e7ec5f0286a709095cd710e | |
parent | 5a87f0e618c709b982c1fa568a30346c38ea28de (diff) |
dma: tegra: add support for Tegra148/124
Tegra148 introduces a few changes to the APB DMA HW registers. Update the
driver to cope with them. Tegra124 inherits these changes.
* The register address stride between DMA channels increases.
* A new per-channel WCOUNT register is introduced.
Signed-off-by: Laxman Dewangan <ldewangan@nvidia.com>
Signed-off-by: Kunal Agrawal <kunala@nvidia.com>
[swarren, remove .dts file change, rewrote commit description, removed
some duplicate/unused code and register IO]
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Reviewed-by: Thierry Reding <treding@nvidia.com>
Tested-by: Thierry Reding <treding@nvidia.com>
Signed-off-by: Vinod Koul <vinod.koul@intel.com>
-rw-r--r-- | drivers/dma/tegra20-apb-dma.c | 62 |
1 files changed, 55 insertions, 7 deletions
diff --git a/drivers/dma/tegra20-apb-dma.c b/drivers/dma/tegra20-apb-dma.c index 73654e33f13b..25873bc10350 100644 --- a/drivers/dma/tegra20-apb-dma.c +++ b/drivers/dma/tegra20-apb-dma.c | |||
@@ -99,6 +99,11 @@ | |||
99 | #define TEGRA_APBDMA_APBSEQ_DATA_SWAP BIT(27) | 99 | #define TEGRA_APBDMA_APBSEQ_DATA_SWAP BIT(27) |
100 | #define TEGRA_APBDMA_APBSEQ_WRAP_WORD_1 (1 << 16) | 100 | #define TEGRA_APBDMA_APBSEQ_WRAP_WORD_1 (1 << 16) |
101 | 101 | ||
102 | /* Tegra148 specific registers */ | ||
103 | #define TEGRA_APBDMA_CHAN_WCOUNT 0x20 | ||
104 | |||
105 | #define TEGRA_APBDMA_CHAN_WORD_TRANSFER 0x24 | ||
106 | |||
102 | /* | 107 | /* |
103 | * If any burst is in flight and DMA paused then this is the time to complete | 108 | * If any burst is in flight and DMA paused then this is the time to complete |
104 | * on-flight burst and update DMA status register. | 109 | * on-flight burst and update DMA status register. |
@@ -108,21 +113,22 @@ | |||
108 | /* Channel base address offset from APBDMA base address */ | 113 | /* Channel base address offset from APBDMA base address */ |
109 | #define TEGRA_APBDMA_CHANNEL_BASE_ADD_OFFSET 0x1000 | 114 | #define TEGRA_APBDMA_CHANNEL_BASE_ADD_OFFSET 0x1000 |
110 | 115 | ||
111 | /* DMA channel register space size */ | ||
112 | #define TEGRA_APBDMA_CHANNEL_REGISTER_SIZE 0x20 | ||
113 | |||
114 | struct tegra_dma; | 116 | struct tegra_dma; |
115 | 117 | ||
116 | /* | 118 | /* |
117 | * tegra_dma_chip_data Tegra chip specific DMA data | 119 | * tegra_dma_chip_data Tegra chip specific DMA data |
118 | * @nr_channels: Number of channels available in the controller. | 120 | * @nr_channels: Number of channels available in the controller. |
121 | * @channel_reg_size: Channel register size/stride. | ||
119 | * @max_dma_count: Maximum DMA transfer count supported by DMA controller. | 122 | * @max_dma_count: Maximum DMA transfer count supported by DMA controller. |
120 | * @support_channel_pause: Support channel wise pause of dma. | 123 | * @support_channel_pause: Support channel wise pause of dma. |
124 | * @support_separate_wcount_reg: Support separate word count register. | ||
121 | */ | 125 | */ |
122 | struct tegra_dma_chip_data { | 126 | struct tegra_dma_chip_data { |
123 | int nr_channels; | 127 | int nr_channels; |
128 | int channel_reg_size; | ||
124 | int max_dma_count; | 129 | int max_dma_count; |
125 | bool support_channel_pause; | 130 | bool support_channel_pause; |
131 | bool support_separate_wcount_reg; | ||
126 | }; | 132 | }; |
127 | 133 | ||
128 | /* DMA channel registers */ | 134 | /* DMA channel registers */ |
@@ -132,6 +138,7 @@ struct tegra_dma_channel_regs { | |||
132 | unsigned long apb_ptr; | 138 | unsigned long apb_ptr; |
133 | unsigned long ahb_seq; | 139 | unsigned long ahb_seq; |
134 | unsigned long apb_seq; | 140 | unsigned long apb_seq; |
141 | unsigned long wcount; | ||
135 | }; | 142 | }; |
136 | 143 | ||
137 | /* | 144 | /* |
@@ -421,6 +428,8 @@ static void tegra_dma_start(struct tegra_dma_channel *tdc, | |||
421 | tdc_write(tdc, TEGRA_APBDMA_CHAN_APBPTR, ch_regs->apb_ptr); | 428 | tdc_write(tdc, TEGRA_APBDMA_CHAN_APBPTR, ch_regs->apb_ptr); |
422 | tdc_write(tdc, TEGRA_APBDMA_CHAN_AHBSEQ, ch_regs->ahb_seq); | 429 | tdc_write(tdc, TEGRA_APBDMA_CHAN_AHBSEQ, ch_regs->ahb_seq); |
423 | tdc_write(tdc, TEGRA_APBDMA_CHAN_AHBPTR, ch_regs->ahb_ptr); | 430 | tdc_write(tdc, TEGRA_APBDMA_CHAN_AHBPTR, ch_regs->ahb_ptr); |
431 | if (tdc->tdma->chip_data->support_separate_wcount_reg) | ||
432 | tdc_write(tdc, TEGRA_APBDMA_CHAN_WCOUNT, ch_regs->wcount); | ||
424 | 433 | ||
425 | /* Start DMA */ | 434 | /* Start DMA */ |
426 | tdc_write(tdc, TEGRA_APBDMA_CHAN_CSR, | 435 | tdc_write(tdc, TEGRA_APBDMA_CHAN_CSR, |
@@ -460,6 +469,9 @@ static void tegra_dma_configure_for_next(struct tegra_dma_channel *tdc, | |||
460 | /* Safe to program new configuration */ | 469 | /* Safe to program new configuration */ |
461 | tdc_write(tdc, TEGRA_APBDMA_CHAN_APBPTR, nsg_req->ch_regs.apb_ptr); | 470 | tdc_write(tdc, TEGRA_APBDMA_CHAN_APBPTR, nsg_req->ch_regs.apb_ptr); |
462 | tdc_write(tdc, TEGRA_APBDMA_CHAN_AHBPTR, nsg_req->ch_regs.ahb_ptr); | 471 | tdc_write(tdc, TEGRA_APBDMA_CHAN_AHBPTR, nsg_req->ch_regs.ahb_ptr); |
472 | if (tdc->tdma->chip_data->support_separate_wcount_reg) | ||
473 | tdc_write(tdc, TEGRA_APBDMA_CHAN_WCOUNT, | ||
474 | nsg_req->ch_regs.wcount); | ||
463 | tdc_write(tdc, TEGRA_APBDMA_CHAN_CSR, | 475 | tdc_write(tdc, TEGRA_APBDMA_CHAN_CSR, |
464 | nsg_req->ch_regs.csr | TEGRA_APBDMA_CSR_ENB); | 476 | nsg_req->ch_regs.csr | TEGRA_APBDMA_CSR_ENB); |
465 | nsg_req->configured = true; | 477 | nsg_req->configured = true; |
@@ -713,6 +725,7 @@ static void tegra_dma_terminate_all(struct dma_chan *dc) | |||
713 | struct tegra_dma_desc *dma_desc; | 725 | struct tegra_dma_desc *dma_desc; |
714 | unsigned long flags; | 726 | unsigned long flags; |
715 | unsigned long status; | 727 | unsigned long status; |
728 | unsigned long wcount; | ||
716 | bool was_busy; | 729 | bool was_busy; |
717 | 730 | ||
718 | spin_lock_irqsave(&tdc->lock, flags); | 731 | spin_lock_irqsave(&tdc->lock, flags); |
@@ -733,6 +746,10 @@ static void tegra_dma_terminate_all(struct dma_chan *dc) | |||
733 | tdc->isr_handler(tdc, true); | 746 | tdc->isr_handler(tdc, true); |
734 | status = tdc_read(tdc, TEGRA_APBDMA_CHAN_STATUS); | 747 | status = tdc_read(tdc, TEGRA_APBDMA_CHAN_STATUS); |
735 | } | 748 | } |
749 | if (tdc->tdma->chip_data->support_separate_wcount_reg) | ||
750 | wcount = tdc_read(tdc, TEGRA_APBDMA_CHAN_WORD_TRANSFER); | ||
751 | else | ||
752 | wcount = status; | ||
736 | 753 | ||
737 | was_busy = tdc->busy; | 754 | was_busy = tdc->busy; |
738 | tegra_dma_stop(tdc); | 755 | tegra_dma_stop(tdc); |
@@ -741,7 +758,7 @@ static void tegra_dma_terminate_all(struct dma_chan *dc) | |||
741 | sgreq = list_first_entry(&tdc->pending_sg_req, | 758 | sgreq = list_first_entry(&tdc->pending_sg_req, |
742 | typeof(*sgreq), node); | 759 | typeof(*sgreq), node); |
743 | sgreq->dma_desc->bytes_transferred += | 760 | sgreq->dma_desc->bytes_transferred += |
744 | get_current_xferred_count(tdc, sgreq, status); | 761 | get_current_xferred_count(tdc, sgreq, wcount); |
745 | } | 762 | } |
746 | tegra_dma_resume(tdc); | 763 | tegra_dma_resume(tdc); |
747 | 764 | ||
@@ -903,6 +920,17 @@ static int get_transfer_param(struct tegra_dma_channel *tdc, | |||
903 | return -EINVAL; | 920 | return -EINVAL; |
904 | } | 921 | } |
905 | 922 | ||
923 | static void tegra_dma_prep_wcount(struct tegra_dma_channel *tdc, | ||
924 | struct tegra_dma_channel_regs *ch_regs, u32 len) | ||
925 | { | ||
926 | u32 len_field = (len - 4) & 0xFFFC; | ||
927 | |||
928 | if (tdc->tdma->chip_data->support_separate_wcount_reg) | ||
929 | ch_regs->wcount = len_field; | ||
930 | else | ||
931 | ch_regs->csr |= len_field; | ||
932 | } | ||
933 | |||
906 | static struct dma_async_tx_descriptor *tegra_dma_prep_slave_sg( | 934 | static struct dma_async_tx_descriptor *tegra_dma_prep_slave_sg( |
907 | struct dma_chan *dc, struct scatterlist *sgl, unsigned int sg_len, | 935 | struct dma_chan *dc, struct scatterlist *sgl, unsigned int sg_len, |
908 | enum dma_transfer_direction direction, unsigned long flags, | 936 | enum dma_transfer_direction direction, unsigned long flags, |
@@ -986,7 +1014,8 @@ static struct dma_async_tx_descriptor *tegra_dma_prep_slave_sg( | |||
986 | 1014 | ||
987 | sg_req->ch_regs.apb_ptr = apb_ptr; | 1015 | sg_req->ch_regs.apb_ptr = apb_ptr; |
988 | sg_req->ch_regs.ahb_ptr = mem; | 1016 | sg_req->ch_regs.ahb_ptr = mem; |
989 | sg_req->ch_regs.csr = csr | ((len - 4) & 0xFFFC); | 1017 | sg_req->ch_regs.csr = csr; |
1018 | tegra_dma_prep_wcount(tdc, &sg_req->ch_regs, len); | ||
990 | sg_req->ch_regs.apb_seq = apb_seq; | 1019 | sg_req->ch_regs.apb_seq = apb_seq; |
991 | sg_req->ch_regs.ahb_seq = ahb_seq; | 1020 | sg_req->ch_regs.ahb_seq = ahb_seq; |
992 | sg_req->configured = false; | 1021 | sg_req->configured = false; |
@@ -1115,7 +1144,8 @@ static struct dma_async_tx_descriptor *tegra_dma_prep_dma_cyclic( | |||
1115 | ahb_seq |= get_burst_size(tdc, burst_size, slave_bw, len); | 1144 | ahb_seq |= get_burst_size(tdc, burst_size, slave_bw, len); |
1116 | sg_req->ch_regs.apb_ptr = apb_ptr; | 1145 | sg_req->ch_regs.apb_ptr = apb_ptr; |
1117 | sg_req->ch_regs.ahb_ptr = mem; | 1146 | sg_req->ch_regs.ahb_ptr = mem; |
1118 | sg_req->ch_regs.csr = csr | ((len - 4) & 0xFFFC); | 1147 | sg_req->ch_regs.csr = csr; |
1148 | tegra_dma_prep_wcount(tdc, &sg_req->ch_regs, len); | ||
1119 | sg_req->ch_regs.apb_seq = apb_seq; | 1149 | sg_req->ch_regs.apb_seq = apb_seq; |
1120 | sg_req->ch_regs.ahb_seq = ahb_seq; | 1150 | sg_req->ch_regs.ahb_seq = ahb_seq; |
1121 | sg_req->configured = false; | 1151 | sg_req->configured = false; |
@@ -1210,27 +1240,45 @@ static void tegra_dma_free_chan_resources(struct dma_chan *dc) | |||
1210 | /* Tegra20 specific DMA controller information */ | 1240 | /* Tegra20 specific DMA controller information */ |
1211 | static const struct tegra_dma_chip_data tegra20_dma_chip_data = { | 1241 | static const struct tegra_dma_chip_data tegra20_dma_chip_data = { |
1212 | .nr_channels = 16, | 1242 | .nr_channels = 16, |
1243 | .channel_reg_size = 0x20, | ||
1213 | .max_dma_count = 1024UL * 64, | 1244 | .max_dma_count = 1024UL * 64, |
1214 | .support_channel_pause = false, | 1245 | .support_channel_pause = false, |
1246 | .support_separate_wcount_reg = false, | ||
1215 | }; | 1247 | }; |
1216 | 1248 | ||
1217 | /* Tegra30 specific DMA controller information */ | 1249 | /* Tegra30 specific DMA controller information */ |
1218 | static const struct tegra_dma_chip_data tegra30_dma_chip_data = { | 1250 | static const struct tegra_dma_chip_data tegra30_dma_chip_data = { |
1219 | .nr_channels = 32, | 1251 | .nr_channels = 32, |
1252 | .channel_reg_size = 0x20, | ||
1220 | .max_dma_count = 1024UL * 64, | 1253 | .max_dma_count = 1024UL * 64, |
1221 | .support_channel_pause = false, | 1254 | .support_channel_pause = false, |
1255 | .support_separate_wcount_reg = false, | ||
1222 | }; | 1256 | }; |
1223 | 1257 | ||
1224 | /* Tegra114 specific DMA controller information */ | 1258 | /* Tegra114 specific DMA controller information */ |
1225 | static const struct tegra_dma_chip_data tegra114_dma_chip_data = { | 1259 | static const struct tegra_dma_chip_data tegra114_dma_chip_data = { |
1226 | .nr_channels = 32, | 1260 | .nr_channels = 32, |
1261 | .channel_reg_size = 0x20, | ||
1227 | .max_dma_count = 1024UL * 64, | 1262 | .max_dma_count = 1024UL * 64, |
1228 | .support_channel_pause = true, | 1263 | .support_channel_pause = true, |
1264 | .support_separate_wcount_reg = false, | ||
1265 | }; | ||
1266 | |||
1267 | /* Tegra148 specific DMA controller information */ | ||
1268 | static const struct tegra_dma_chip_data tegra148_dma_chip_data = { | ||
1269 | .nr_channels = 32, | ||
1270 | .channel_reg_size = 0x40, | ||
1271 | .max_dma_count = 1024UL * 64, | ||
1272 | .support_channel_pause = true, | ||
1273 | .support_separate_wcount_reg = true, | ||
1229 | }; | 1274 | }; |
1230 | 1275 | ||
1231 | 1276 | ||
1232 | static const struct of_device_id tegra_dma_of_match[] = { | 1277 | static const struct of_device_id tegra_dma_of_match[] = { |
1233 | { | 1278 | { |
1279 | .compatible = "nvidia,tegra148-apbdma", | ||
1280 | .data = &tegra148_dma_chip_data, | ||
1281 | }, { | ||
1234 | .compatible = "nvidia,tegra114-apbdma", | 1282 | .compatible = "nvidia,tegra114-apbdma", |
1235 | .data = &tegra114_dma_chip_data, | 1283 | .data = &tegra114_dma_chip_data, |
1236 | }, { | 1284 | }, { |
@@ -1318,7 +1366,7 @@ static int tegra_dma_probe(struct platform_device *pdev) | |||
1318 | struct tegra_dma_channel *tdc = &tdma->channels[i]; | 1366 | struct tegra_dma_channel *tdc = &tdma->channels[i]; |
1319 | 1367 | ||
1320 | tdc->chan_base_offset = TEGRA_APBDMA_CHANNEL_BASE_ADD_OFFSET + | 1368 | tdc->chan_base_offset = TEGRA_APBDMA_CHANNEL_BASE_ADD_OFFSET + |
1321 | i * TEGRA_APBDMA_CHANNEL_REGISTER_SIZE; | 1369 | i * cdata->channel_reg_size; |
1322 | 1370 | ||
1323 | res = platform_get_resource(pdev, IORESOURCE_IRQ, i); | 1371 | res = platform_get_resource(pdev, IORESOURCE_IRQ, i); |
1324 | if (!res) { | 1372 | if (!res) { |