.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * Ingenic JZ4780 DMA controller |
---|
3 | 4 | * |
---|
4 | 5 | * Copyright (c) 2015 Imagination Technologies |
---|
5 | 6 | * Author: Alex Smith <alex@alex-smith.me.uk> |
---|
6 | | - * |
---|
7 | | - * This program is free software; you can redistribute it and/or modify it |
---|
8 | | - * under the terms of the GNU General Public License as published by the |
---|
9 | | - * Free Software Foundation; either version 2 of the License, or (at your |
---|
10 | | - * option) any later version. |
---|
11 | 7 | */ |
---|
12 | 8 | |
---|
13 | 9 | #include <linux/clk.h> |
---|
.. | .. |
---|
16 | 12 | #include <linux/interrupt.h> |
---|
17 | 13 | #include <linux/module.h> |
---|
18 | 14 | #include <linux/of.h> |
---|
| 15 | +#include <linux/of_device.h> |
---|
19 | 16 | #include <linux/of_dma.h> |
---|
20 | 17 | #include <linux/platform_device.h> |
---|
21 | 18 | #include <linux/slab.h> |
---|
.. | .. |
---|
23 | 20 | #include "dmaengine.h" |
---|
24 | 21 | #include "virt-dma.h" |
---|
25 | 22 | |
---|
26 | | -#define JZ_DMA_NR_CHANNELS 32 |
---|
27 | | - |
---|
28 | 23 | /* Global registers. */ |
---|
29 | | -#define JZ_DMA_REG_DMAC 0x1000 |
---|
30 | | -#define JZ_DMA_REG_DIRQP 0x1004 |
---|
31 | | -#define JZ_DMA_REG_DDR 0x1008 |
---|
32 | | -#define JZ_DMA_REG_DDRS 0x100c |
---|
33 | | -#define JZ_DMA_REG_DMACP 0x101c |
---|
34 | | -#define JZ_DMA_REG_DSIRQP 0x1020 |
---|
35 | | -#define JZ_DMA_REG_DSIRQM 0x1024 |
---|
36 | | -#define JZ_DMA_REG_DCIRQP 0x1028 |
---|
37 | | -#define JZ_DMA_REG_DCIRQM 0x102c |
---|
| 24 | +#define JZ_DMA_REG_DMAC 0x00 |
---|
| 25 | +#define JZ_DMA_REG_DIRQP 0x04 |
---|
| 26 | +#define JZ_DMA_REG_DDR 0x08 |
---|
| 27 | +#define JZ_DMA_REG_DDRS 0x0c |
---|
| 28 | +#define JZ_DMA_REG_DCKE 0x10 |
---|
| 29 | +#define JZ_DMA_REG_DCKES 0x14 |
---|
| 30 | +#define JZ_DMA_REG_DCKEC 0x18 |
---|
| 31 | +#define JZ_DMA_REG_DMACP 0x1c |
---|
| 32 | +#define JZ_DMA_REG_DSIRQP 0x20 |
---|
| 33 | +#define JZ_DMA_REG_DSIRQM 0x24 |
---|
| 34 | +#define JZ_DMA_REG_DCIRQP 0x28 |
---|
| 35 | +#define JZ_DMA_REG_DCIRQM 0x2c |
---|
38 | 36 | |
---|
39 | 37 | /* Per-channel registers. */ |
---|
40 | 38 | #define JZ_DMA_REG_CHAN(n) (n * 0x20) |
---|
41 | | -#define JZ_DMA_REG_DSA(n) (0x00 + JZ_DMA_REG_CHAN(n)) |
---|
42 | | -#define JZ_DMA_REG_DTA(n) (0x04 + JZ_DMA_REG_CHAN(n)) |
---|
43 | | -#define JZ_DMA_REG_DTC(n) (0x08 + JZ_DMA_REG_CHAN(n)) |
---|
44 | | -#define JZ_DMA_REG_DRT(n) (0x0c + JZ_DMA_REG_CHAN(n)) |
---|
45 | | -#define JZ_DMA_REG_DCS(n) (0x10 + JZ_DMA_REG_CHAN(n)) |
---|
46 | | -#define JZ_DMA_REG_DCM(n) (0x14 + JZ_DMA_REG_CHAN(n)) |
---|
47 | | -#define JZ_DMA_REG_DDA(n) (0x18 + JZ_DMA_REG_CHAN(n)) |
---|
48 | | -#define JZ_DMA_REG_DSD(n) (0x1c + JZ_DMA_REG_CHAN(n)) |
---|
| 39 | +#define JZ_DMA_REG_DSA 0x00 |
---|
| 40 | +#define JZ_DMA_REG_DTA 0x04 |
---|
| 41 | +#define JZ_DMA_REG_DTC 0x08 |
---|
| 42 | +#define JZ_DMA_REG_DRT 0x0c |
---|
| 43 | +#define JZ_DMA_REG_DCS 0x10 |
---|
| 44 | +#define JZ_DMA_REG_DCM 0x14 |
---|
| 45 | +#define JZ_DMA_REG_DDA 0x18 |
---|
| 46 | +#define JZ_DMA_REG_DSD 0x1c |
---|
49 | 47 | |
---|
50 | 48 | #define JZ_DMA_DMAC_DMAE BIT(0) |
---|
51 | 49 | #define JZ_DMA_DMAC_AR BIT(2) |
---|
52 | 50 | #define JZ_DMA_DMAC_HLT BIT(3) |
---|
| 51 | +#define JZ_DMA_DMAC_FAIC BIT(27) |
---|
53 | 52 | #define JZ_DMA_DMAC_FMSC BIT(31) |
---|
54 | 53 | |
---|
55 | 54 | #define JZ_DMA_DRT_AUTO 0x8 |
---|
.. | .. |
---|
86 | 85 | BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | \ |
---|
87 | 86 | BIT(DMA_SLAVE_BUSWIDTH_4_BYTES)) |
---|
88 | 87 | |
---|
| 88 | +#define JZ4780_DMA_CTRL_OFFSET 0x1000 |
---|
| 89 | + |
---|
| 90 | +/* macros for use with jz4780_dma_soc_data.flags */ |
---|
| 91 | +#define JZ_SOC_DATA_ALLOW_LEGACY_DT BIT(0) |
---|
| 92 | +#define JZ_SOC_DATA_PROGRAMMABLE_DMA BIT(1) |
---|
| 93 | +#define JZ_SOC_DATA_PER_CHAN_PM BIT(2) |
---|
| 94 | +#define JZ_SOC_DATA_NO_DCKES_DCKEC BIT(3) |
---|
| 95 | +#define JZ_SOC_DATA_BREAK_LINKS BIT(4) |
---|
| 96 | + |
---|
89 | 97 | /** |
---|
90 | 98 | * struct jz4780_dma_hwdesc - descriptor structure read by the DMA controller. |
---|
91 | 99 | * @dcm: value for the DCM (channel command) register |
---|
.. | .. |
---|
94 | 102 | * @dtc: transfer count (number of blocks of the transfer size specified in DCM |
---|
95 | 103 | * to transfer) in the low 24 bits, offset of the next descriptor from the |
---|
96 | 104 | * descriptor base address in the upper 8 bits. |
---|
97 | | - * @sd: target/source stride difference (in stride transfer mode). |
---|
98 | | - * @drt: request type |
---|
99 | 105 | */ |
---|
100 | 106 | struct jz4780_dma_hwdesc { |
---|
101 | 107 | uint32_t dcm; |
---|
102 | 108 | uint32_t dsa; |
---|
103 | 109 | uint32_t dta; |
---|
104 | 110 | uint32_t dtc; |
---|
105 | | - uint32_t sd; |
---|
106 | | - uint32_t drt; |
---|
107 | | - uint32_t reserved[2]; |
---|
108 | 111 | }; |
---|
109 | 112 | |
---|
110 | 113 | /* Size of allocations for hardware descriptor blocks. */ |
---|
.. | .. |
---|
135 | 138 | unsigned int curr_hwdesc; |
---|
136 | 139 | }; |
---|
137 | 140 | |
---|
| 141 | +struct jz4780_dma_soc_data { |
---|
| 142 | + unsigned int nb_channels; |
---|
| 143 | + unsigned int transfer_ord_max; |
---|
| 144 | + unsigned long flags; |
---|
| 145 | +}; |
---|
| 146 | + |
---|
138 | 147 | struct jz4780_dma_dev { |
---|
139 | 148 | struct dma_device dma_device; |
---|
140 | | - void __iomem *base; |
---|
| 149 | + void __iomem *chn_base; |
---|
| 150 | + void __iomem *ctrl_base; |
---|
141 | 151 | struct clk *clk; |
---|
142 | 152 | unsigned int irq; |
---|
| 153 | + const struct jz4780_dma_soc_data *soc_data; |
---|
143 | 154 | |
---|
144 | 155 | uint32_t chan_reserved; |
---|
145 | | - struct jz4780_dma_chan chan[JZ_DMA_NR_CHANNELS]; |
---|
| 156 | + struct jz4780_dma_chan chan[]; |
---|
146 | 157 | }; |
---|
147 | 158 | |
---|
148 | 159 | struct jz4780_dma_filter_data { |
---|
149 | | - struct device_node *of_node; |
---|
150 | 160 | uint32_t transfer_type; |
---|
151 | 161 | int channel; |
---|
152 | 162 | }; |
---|
.. | .. |
---|
169 | 179 | dma_device); |
---|
170 | 180 | } |
---|
171 | 181 | |
---|
172 | | -static inline uint32_t jz4780_dma_readl(struct jz4780_dma_dev *jzdma, |
---|
173 | | - unsigned int reg) |
---|
| 182 | +static inline uint32_t jz4780_dma_chn_readl(struct jz4780_dma_dev *jzdma, |
---|
| 183 | + unsigned int chn, unsigned int reg) |
---|
174 | 184 | { |
---|
175 | | - return readl(jzdma->base + reg); |
---|
| 185 | + return readl(jzdma->chn_base + reg + JZ_DMA_REG_CHAN(chn)); |
---|
176 | 186 | } |
---|
177 | 187 | |
---|
178 | | -static inline void jz4780_dma_writel(struct jz4780_dma_dev *jzdma, |
---|
| 188 | +static inline void jz4780_dma_chn_writel(struct jz4780_dma_dev *jzdma, |
---|
| 189 | + unsigned int chn, unsigned int reg, uint32_t val) |
---|
| 190 | +{ |
---|
| 191 | + writel(val, jzdma->chn_base + reg + JZ_DMA_REG_CHAN(chn)); |
---|
| 192 | +} |
---|
| 193 | + |
---|
| 194 | +static inline uint32_t jz4780_dma_ctrl_readl(struct jz4780_dma_dev *jzdma, |
---|
| 195 | + unsigned int reg) |
---|
| 196 | +{ |
---|
| 197 | + return readl(jzdma->ctrl_base + reg); |
---|
| 198 | +} |
---|
| 199 | + |
---|
| 200 | +static inline void jz4780_dma_ctrl_writel(struct jz4780_dma_dev *jzdma, |
---|
179 | 201 | unsigned int reg, uint32_t val) |
---|
180 | 202 | { |
---|
181 | | - writel(val, jzdma->base + reg); |
---|
| 203 | + writel(val, jzdma->ctrl_base + reg); |
---|
| 204 | +} |
---|
| 205 | + |
---|
| 206 | +static inline void jz4780_dma_chan_enable(struct jz4780_dma_dev *jzdma, |
---|
| 207 | + unsigned int chn) |
---|
| 208 | +{ |
---|
| 209 | + if (jzdma->soc_data->flags & JZ_SOC_DATA_PER_CHAN_PM) { |
---|
| 210 | + unsigned int reg; |
---|
| 211 | + |
---|
| 212 | + if (jzdma->soc_data->flags & JZ_SOC_DATA_NO_DCKES_DCKEC) |
---|
| 213 | + reg = JZ_DMA_REG_DCKE; |
---|
| 214 | + else |
---|
| 215 | + reg = JZ_DMA_REG_DCKES; |
---|
| 216 | + |
---|
| 217 | + jz4780_dma_ctrl_writel(jzdma, reg, BIT(chn)); |
---|
| 218 | + } |
---|
| 219 | +} |
---|
| 220 | + |
---|
| 221 | +static inline void jz4780_dma_chan_disable(struct jz4780_dma_dev *jzdma, |
---|
| 222 | + unsigned int chn) |
---|
| 223 | +{ |
---|
| 224 | + if ((jzdma->soc_data->flags & JZ_SOC_DATA_PER_CHAN_PM) && |
---|
| 225 | + !(jzdma->soc_data->flags & JZ_SOC_DATA_NO_DCKES_DCKEC)) |
---|
| 226 | + jz4780_dma_ctrl_writel(jzdma, JZ_DMA_REG_DCKEC, BIT(chn)); |
---|
182 | 227 | } |
---|
183 | 228 | |
---|
184 | 229 | static struct jz4780_dma_desc *jz4780_dma_desc_alloc( |
---|
.. | .. |
---|
215 | 260 | kfree(desc); |
---|
216 | 261 | } |
---|
217 | 262 | |
---|
218 | | -static uint32_t jz4780_dma_transfer_size(unsigned long val, uint32_t *shift) |
---|
| 263 | +static uint32_t jz4780_dma_transfer_size(struct jz4780_dma_chan *jzchan, |
---|
| 264 | + unsigned long val, uint32_t *shift) |
---|
219 | 265 | { |
---|
| 266 | + struct jz4780_dma_dev *jzdma = jz4780_dma_chan_parent(jzchan); |
---|
220 | 267 | int ord = ffs(val) - 1; |
---|
221 | 268 | |
---|
222 | 269 | /* |
---|
.. | .. |
---|
228 | 275 | */ |
---|
229 | 276 | if (ord == 3) |
---|
230 | 277 | ord = 2; |
---|
231 | | - else if (ord > 7) |
---|
232 | | - ord = 7; |
---|
| 278 | + else if (ord > jzdma->soc_data->transfer_ord_max) |
---|
| 279 | + ord = jzdma->soc_data->transfer_ord_max; |
---|
233 | 280 | |
---|
234 | 281 | *shift = ord; |
---|
235 | 282 | |
---|
.. | .. |
---|
262 | 309 | desc->dcm = JZ_DMA_DCM_SAI; |
---|
263 | 310 | desc->dsa = addr; |
---|
264 | 311 | desc->dta = config->dst_addr; |
---|
265 | | - desc->drt = jzchan->transfer_type; |
---|
266 | 312 | |
---|
267 | 313 | width = config->dst_addr_width; |
---|
268 | 314 | maxburst = config->dst_maxburst; |
---|
.. | .. |
---|
270 | 316 | desc->dcm = JZ_DMA_DCM_DAI; |
---|
271 | 317 | desc->dsa = config->src_addr; |
---|
272 | 318 | desc->dta = addr; |
---|
273 | | - desc->drt = jzchan->transfer_type; |
---|
274 | 319 | |
---|
275 | 320 | width = config->src_addr_width; |
---|
276 | 321 | maxburst = config->src_maxburst; |
---|
.. | .. |
---|
283 | 328 | * divisible by the transfer size, and we must not use more than the |
---|
284 | 329 | * maximum burst specified by the user. |
---|
285 | 330 | */ |
---|
286 | | - tsz = jz4780_dma_transfer_size(addr | len | (width * maxburst), |
---|
| 331 | + tsz = jz4780_dma_transfer_size(jzchan, addr | len | (width * maxburst), |
---|
287 | 332 | &jzchan->transfer_shift); |
---|
288 | 333 | |
---|
289 | 334 | switch (width) { |
---|
.. | .. |
---|
311 | 356 | void *context) |
---|
312 | 357 | { |
---|
313 | 358 | struct jz4780_dma_chan *jzchan = to_jz4780_dma_chan(chan); |
---|
| 359 | + struct jz4780_dma_dev *jzdma = jz4780_dma_chan_parent(jzchan); |
---|
314 | 360 | struct jz4780_dma_desc *desc; |
---|
315 | 361 | unsigned int i; |
---|
316 | 362 | int err; |
---|
.. | .. |
---|
331 | 377 | |
---|
332 | 378 | desc->desc[i].dcm |= JZ_DMA_DCM_TIE; |
---|
333 | 379 | |
---|
334 | | - if (i != (sg_len - 1)) { |
---|
| 380 | + if (i != (sg_len - 1) && |
---|
| 381 | + !(jzdma->soc_data->flags & JZ_SOC_DATA_BREAK_LINKS)) { |
---|
335 | 382 | /* Automatically proceeed to the next descriptor. */ |
---|
336 | 383 | desc->desc[i].dcm |= JZ_DMA_DCM_LINK; |
---|
337 | 384 | |
---|
.. | .. |
---|
412 | 459 | if (!desc) |
---|
413 | 460 | return NULL; |
---|
414 | 461 | |
---|
415 | | - tsz = jz4780_dma_transfer_size(dest | src | len, |
---|
| 462 | + tsz = jz4780_dma_transfer_size(jzchan, dest | src | len, |
---|
416 | 463 | &jzchan->transfer_shift); |
---|
| 464 | + |
---|
| 465 | + jzchan->transfer_type = JZ_DMA_DRT_AUTO; |
---|
417 | 466 | |
---|
418 | 467 | desc->desc[0].dsa = src; |
---|
419 | 468 | desc->desc[0].dta = dest; |
---|
420 | | - desc->desc[0].drt = JZ_DMA_DRT_AUTO; |
---|
421 | 469 | desc->desc[0].dcm = JZ_DMA_DCM_TIE | JZ_DMA_DCM_SAI | JZ_DMA_DCM_DAI | |
---|
422 | 470 | tsz << JZ_DMA_DCM_TSZ_SHIFT | |
---|
423 | 471 | JZ_DMA_WIDTH_32_BIT << JZ_DMA_DCM_SP_SHIFT | |
---|
.. | .. |
---|
472 | 520 | (jzchan->curr_hwdesc + 1) % jzchan->desc->count; |
---|
473 | 521 | } |
---|
474 | 522 | |
---|
475 | | - /* Use 8-word descriptors. */ |
---|
476 | | - jz4780_dma_writel(jzdma, JZ_DMA_REG_DCS(jzchan->id), JZ_DMA_DCS_DES8); |
---|
| 523 | + /* Enable the channel's clock. */ |
---|
| 524 | + jz4780_dma_chan_enable(jzdma, jzchan->id); |
---|
| 525 | + |
---|
| 526 | + /* Use 4-word descriptors. */ |
---|
| 527 | + jz4780_dma_chn_writel(jzdma, jzchan->id, JZ_DMA_REG_DCS, 0); |
---|
| 528 | + |
---|
| 529 | + /* Set transfer type. */ |
---|
| 530 | + jz4780_dma_chn_writel(jzdma, jzchan->id, JZ_DMA_REG_DRT, |
---|
| 531 | + jzchan->transfer_type); |
---|
| 532 | + |
---|
| 533 | + /* |
---|
| 534 | + * Set the transfer count. This is redundant for a descriptor-driven |
---|
| 535 | + * transfer. However, there can be a delay between the transfer start |
---|
| 536 | + * time and when DTCn reg contains the new transfer count. Setting |
---|
| 537 | + * it explicitly ensures residue is computed correctly at all times. |
---|
| 538 | + */ |
---|
| 539 | + jz4780_dma_chn_writel(jzdma, jzchan->id, JZ_DMA_REG_DTC, |
---|
| 540 | + jzchan->desc->desc[jzchan->curr_hwdesc].dtc); |
---|
477 | 541 | |
---|
478 | 542 | /* Write descriptor address and initiate descriptor fetch. */ |
---|
479 | 543 | desc_phys = jzchan->desc->desc_phys + |
---|
480 | 544 | (jzchan->curr_hwdesc * sizeof(*jzchan->desc->desc)); |
---|
481 | | - jz4780_dma_writel(jzdma, JZ_DMA_REG_DDA(jzchan->id), desc_phys); |
---|
482 | | - jz4780_dma_writel(jzdma, JZ_DMA_REG_DDRS, BIT(jzchan->id)); |
---|
| 545 | + jz4780_dma_chn_writel(jzdma, jzchan->id, JZ_DMA_REG_DDA, desc_phys); |
---|
| 546 | + jz4780_dma_ctrl_writel(jzdma, JZ_DMA_REG_DDRS, BIT(jzchan->id)); |
---|
483 | 547 | |
---|
484 | 548 | /* Enable the channel. */ |
---|
485 | | - jz4780_dma_writel(jzdma, JZ_DMA_REG_DCS(jzchan->id), |
---|
486 | | - JZ_DMA_DCS_DES8 | JZ_DMA_DCS_CTE); |
---|
| 549 | + jz4780_dma_chn_writel(jzdma, jzchan->id, JZ_DMA_REG_DCS, |
---|
| 550 | + JZ_DMA_DCS_CTE); |
---|
487 | 551 | } |
---|
488 | 552 | |
---|
489 | 553 | static void jz4780_dma_issue_pending(struct dma_chan *chan) |
---|
.. | .. |
---|
509 | 573 | spin_lock_irqsave(&jzchan->vchan.lock, flags); |
---|
510 | 574 | |
---|
511 | 575 | /* Clear the DMA status and stop the transfer. */ |
---|
512 | | - jz4780_dma_writel(jzdma, JZ_DMA_REG_DCS(jzchan->id), 0); |
---|
| 576 | + jz4780_dma_chn_writel(jzdma, jzchan->id, JZ_DMA_REG_DCS, 0); |
---|
513 | 577 | if (jzchan->desc) { |
---|
514 | 578 | vchan_terminate_vdesc(&jzchan->desc->vdesc); |
---|
515 | 579 | jzchan->desc = NULL; |
---|
516 | 580 | } |
---|
| 581 | + |
---|
| 582 | + jz4780_dma_chan_disable(jzdma, jzchan->id); |
---|
517 | 583 | |
---|
518 | 584 | vchan_get_all_descriptors(&jzchan->vchan, &head); |
---|
519 | 585 | |
---|
.. | .. |
---|
526 | 592 | static void jz4780_dma_synchronize(struct dma_chan *chan) |
---|
527 | 593 | { |
---|
528 | 594 | struct jz4780_dma_chan *jzchan = to_jz4780_dma_chan(chan); |
---|
| 595 | + struct jz4780_dma_dev *jzdma = jz4780_dma_chan_parent(jzchan); |
---|
529 | 596 | |
---|
530 | 597 | vchan_synchronize(&jzchan->vchan); |
---|
| 598 | + jz4780_dma_chan_disable(jzdma, jzchan->id); |
---|
531 | 599 | } |
---|
532 | 600 | |
---|
533 | 601 | static int jz4780_dma_config(struct dma_chan *chan, |
---|
.. | .. |
---|
549 | 617 | struct jz4780_dma_desc *desc, unsigned int next_sg) |
---|
550 | 618 | { |
---|
551 | 619 | struct jz4780_dma_dev *jzdma = jz4780_dma_chan_parent(jzchan); |
---|
552 | | - unsigned int residue, count; |
---|
| 620 | + unsigned int count = 0; |
---|
553 | 621 | unsigned int i; |
---|
554 | 622 | |
---|
555 | | - residue = 0; |
---|
556 | | - |
---|
557 | 623 | for (i = next_sg; i < desc->count; i++) |
---|
558 | | - residue += desc->desc[i].dtc << jzchan->transfer_shift; |
---|
| 624 | + count += desc->desc[i].dtc & GENMASK(23, 0); |
---|
559 | 625 | |
---|
560 | | - if (next_sg != 0) { |
---|
561 | | - count = jz4780_dma_readl(jzdma, |
---|
562 | | - JZ_DMA_REG_DTC(jzchan->id)); |
---|
563 | | - residue += count << jzchan->transfer_shift; |
---|
564 | | - } |
---|
| 626 | + if (next_sg != 0) |
---|
| 627 | + count += jz4780_dma_chn_readl(jzdma, jzchan->id, |
---|
| 628 | + JZ_DMA_REG_DTC); |
---|
565 | 629 | |
---|
566 | | - return residue; |
---|
| 630 | + return count << jzchan->transfer_shift; |
---|
567 | 631 | } |
---|
568 | 632 | |
---|
569 | 633 | static enum dma_status jz4780_dma_tx_status(struct dma_chan *chan, |
---|
.. | .. |
---|
573 | 637 | struct virt_dma_desc *vdesc; |
---|
574 | 638 | enum dma_status status; |
---|
575 | 639 | unsigned long flags; |
---|
| 640 | + unsigned long residue = 0; |
---|
576 | 641 | |
---|
577 | 642 | spin_lock_irqsave(&jzchan->vchan.lock, flags); |
---|
578 | 643 | |
---|
.. | .. |
---|
583 | 648 | vdesc = vchan_find_desc(&jzchan->vchan, cookie); |
---|
584 | 649 | if (vdesc) { |
---|
585 | 650 | /* On the issued list, so hasn't been processed yet */ |
---|
586 | | - txstate->residue = jz4780_dma_desc_residue(jzchan, |
---|
| 651 | + residue = jz4780_dma_desc_residue(jzchan, |
---|
587 | 652 | to_jz4780_dma_desc(vdesc), 0); |
---|
588 | 653 | } else if (cookie == jzchan->desc->vdesc.tx.cookie) { |
---|
589 | | - txstate->residue = jz4780_dma_desc_residue(jzchan, jzchan->desc, |
---|
| 654 | + residue = jz4780_dma_desc_residue(jzchan, jzchan->desc, |
---|
590 | 655 | jzchan->curr_hwdesc + 1); |
---|
591 | | - } else |
---|
592 | | - txstate->residue = 0; |
---|
| 656 | + } |
---|
| 657 | + dma_set_residue(txstate, residue); |
---|
593 | 658 | |
---|
594 | 659 | if (vdesc && jzchan->desc && vdesc == &jzchan->desc->vdesc |
---|
595 | 660 | && jzchan->desc->status & (JZ_DMA_DCS_AR | JZ_DMA_DCS_HLT)) |
---|
.. | .. |
---|
600 | 665 | return status; |
---|
601 | 666 | } |
---|
602 | 667 | |
---|
603 | | -static void jz4780_dma_chan_irq(struct jz4780_dma_dev *jzdma, |
---|
604 | | - struct jz4780_dma_chan *jzchan) |
---|
| 668 | +static bool jz4780_dma_chan_irq(struct jz4780_dma_dev *jzdma, |
---|
| 669 | + struct jz4780_dma_chan *jzchan) |
---|
605 | 670 | { |
---|
| 671 | + const unsigned int soc_flags = jzdma->soc_data->flags; |
---|
| 672 | + struct jz4780_dma_desc *desc = jzchan->desc; |
---|
606 | 673 | uint32_t dcs; |
---|
| 674 | + bool ack = true; |
---|
607 | 675 | |
---|
608 | 676 | spin_lock(&jzchan->vchan.lock); |
---|
609 | 677 | |
---|
610 | | - dcs = jz4780_dma_readl(jzdma, JZ_DMA_REG_DCS(jzchan->id)); |
---|
611 | | - jz4780_dma_writel(jzdma, JZ_DMA_REG_DCS(jzchan->id), 0); |
---|
| 678 | + dcs = jz4780_dma_chn_readl(jzdma, jzchan->id, JZ_DMA_REG_DCS); |
---|
| 679 | + jz4780_dma_chn_writel(jzdma, jzchan->id, JZ_DMA_REG_DCS, 0); |
---|
612 | 680 | |
---|
613 | 681 | if (dcs & JZ_DMA_DCS_AR) { |
---|
614 | 682 | dev_warn(&jzchan->vchan.chan.dev->device, |
---|
.. | .. |
---|
626 | 694 | if ((dcs & (JZ_DMA_DCS_AR | JZ_DMA_DCS_HLT)) == 0) { |
---|
627 | 695 | if (jzchan->desc->type == DMA_CYCLIC) { |
---|
628 | 696 | vchan_cyclic_callback(&jzchan->desc->vdesc); |
---|
629 | | - } else { |
---|
630 | | - vchan_cookie_complete(&jzchan->desc->vdesc); |
---|
631 | | - jzchan->desc = NULL; |
---|
632 | | - } |
---|
633 | 697 | |
---|
634 | | - jz4780_dma_begin(jzchan); |
---|
| 698 | + jz4780_dma_begin(jzchan); |
---|
| 699 | + } else if (dcs & JZ_DMA_DCS_TT) { |
---|
| 700 | + if (!(soc_flags & JZ_SOC_DATA_BREAK_LINKS) || |
---|
| 701 | + (jzchan->curr_hwdesc + 1 == desc->count)) { |
---|
| 702 | + vchan_cookie_complete(&desc->vdesc); |
---|
| 703 | + jzchan->desc = NULL; |
---|
| 704 | + } |
---|
| 705 | + |
---|
| 706 | + jz4780_dma_begin(jzchan); |
---|
| 707 | + } else { |
---|
| 708 | + /* False positive - continue the transfer */ |
---|
| 709 | + ack = false; |
---|
| 710 | + jz4780_dma_chn_writel(jzdma, jzchan->id, |
---|
| 711 | + JZ_DMA_REG_DCS, |
---|
| 712 | + JZ_DMA_DCS_CTE); |
---|
| 713 | + } |
---|
635 | 714 | } |
---|
636 | 715 | } else { |
---|
637 | 716 | dev_err(&jzchan->vchan.chan.dev->device, |
---|
.. | .. |
---|
639 | 718 | } |
---|
640 | 719 | |
---|
641 | 720 | spin_unlock(&jzchan->vchan.lock); |
---|
| 721 | + |
---|
| 722 | + return ack; |
---|
642 | 723 | } |
---|
643 | 724 | |
---|
644 | 725 | static irqreturn_t jz4780_dma_irq_handler(int irq, void *data) |
---|
645 | 726 | { |
---|
646 | 727 | struct jz4780_dma_dev *jzdma = data; |
---|
647 | | - uint32_t pending, dmac; |
---|
| 728 | + unsigned int nb_channels = jzdma->soc_data->nb_channels; |
---|
| 729 | + unsigned long pending; |
---|
| 730 | + uint32_t dmac; |
---|
648 | 731 | int i; |
---|
649 | 732 | |
---|
650 | | - pending = jz4780_dma_readl(jzdma, JZ_DMA_REG_DIRQP); |
---|
| 733 | + pending = jz4780_dma_ctrl_readl(jzdma, JZ_DMA_REG_DIRQP); |
---|
651 | 734 | |
---|
652 | | - for (i = 0; i < JZ_DMA_NR_CHANNELS; i++) { |
---|
653 | | - if (!(pending & (1<<i))) |
---|
654 | | - continue; |
---|
655 | | - |
---|
656 | | - jz4780_dma_chan_irq(jzdma, &jzdma->chan[i]); |
---|
| 735 | + for_each_set_bit(i, &pending, nb_channels) { |
---|
| 736 | + if (jz4780_dma_chan_irq(jzdma, &jzdma->chan[i])) |
---|
| 737 | + pending &= ~BIT(i); |
---|
657 | 738 | } |
---|
658 | 739 | |
---|
659 | 740 | /* Clear halt and address error status of all channels. */ |
---|
660 | | - dmac = jz4780_dma_readl(jzdma, JZ_DMA_REG_DMAC); |
---|
| 741 | + dmac = jz4780_dma_ctrl_readl(jzdma, JZ_DMA_REG_DMAC); |
---|
661 | 742 | dmac &= ~(JZ_DMA_DMAC_HLT | JZ_DMA_DMAC_AR); |
---|
662 | | - jz4780_dma_writel(jzdma, JZ_DMA_REG_DMAC, dmac); |
---|
| 743 | + jz4780_dma_ctrl_writel(jzdma, JZ_DMA_REG_DMAC, dmac); |
---|
663 | 744 | |
---|
664 | 745 | /* Clear interrupt pending status. */ |
---|
665 | | - jz4780_dma_writel(jzdma, JZ_DMA_REG_DIRQP, 0); |
---|
| 746 | + jz4780_dma_ctrl_writel(jzdma, JZ_DMA_REG_DIRQP, pending); |
---|
666 | 747 | |
---|
667 | 748 | return IRQ_HANDLED; |
---|
668 | 749 | } |
---|
.. | .. |
---|
699 | 780 | struct jz4780_dma_dev *jzdma = jz4780_dma_chan_parent(jzchan); |
---|
700 | 781 | struct jz4780_dma_filter_data *data = param; |
---|
701 | 782 | |
---|
702 | | - if (jzdma->dma_device.dev->of_node != data->of_node) |
---|
703 | | - return false; |
---|
704 | 783 | |
---|
705 | 784 | if (data->channel > -1) { |
---|
706 | 785 | if (data->channel != jzchan->id) |
---|
.. | .. |
---|
724 | 803 | if (dma_spec->args_count != 2) |
---|
725 | 804 | return NULL; |
---|
726 | 805 | |
---|
727 | | - data.of_node = ofdma->of_node; |
---|
728 | 806 | data.transfer_type = dma_spec->args[0]; |
---|
729 | 807 | data.channel = dma_spec->args[1]; |
---|
730 | 808 | |
---|
731 | 809 | if (data.channel > -1) { |
---|
732 | | - if (data.channel >= JZ_DMA_NR_CHANNELS) { |
---|
| 810 | + if (data.channel >= jzdma->soc_data->nb_channels) { |
---|
733 | 811 | dev_err(jzdma->dma_device.dev, |
---|
734 | 812 | "device requested non-existent channel %u\n", |
---|
735 | 813 | data.channel); |
---|
.. | .. |
---|
749 | 827 | return dma_get_slave_channel( |
---|
750 | 828 | &jzdma->chan[data.channel].vchan.chan); |
---|
751 | 829 | } else { |
---|
752 | | - return dma_request_channel(mask, jz4780_dma_filter_fn, &data); |
---|
| 830 | + return __dma_request_channel(&mask, jz4780_dma_filter_fn, &data, |
---|
| 831 | + ofdma->of_node); |
---|
753 | 832 | } |
---|
754 | 833 | } |
---|
755 | 834 | |
---|
756 | 835 | static int jz4780_dma_probe(struct platform_device *pdev) |
---|
757 | 836 | { |
---|
758 | 837 | struct device *dev = &pdev->dev; |
---|
| 838 | + const struct jz4780_dma_soc_data *soc_data; |
---|
759 | 839 | struct jz4780_dma_dev *jzdma; |
---|
760 | 840 | struct jz4780_dma_chan *jzchan; |
---|
761 | 841 | struct dma_device *dd; |
---|
.. | .. |
---|
767 | 847 | return -EINVAL; |
---|
768 | 848 | } |
---|
769 | 849 | |
---|
770 | | - jzdma = devm_kzalloc(dev, sizeof(*jzdma), GFP_KERNEL); |
---|
| 850 | + soc_data = device_get_match_data(dev); |
---|
| 851 | + if (!soc_data) |
---|
| 852 | + return -EINVAL; |
---|
| 853 | + |
---|
| 854 | + jzdma = devm_kzalloc(dev, struct_size(jzdma, chan, |
---|
| 855 | + soc_data->nb_channels), GFP_KERNEL); |
---|
771 | 856 | if (!jzdma) |
---|
772 | 857 | return -ENOMEM; |
---|
773 | 858 | |
---|
| 859 | + jzdma->soc_data = soc_data; |
---|
774 | 860 | platform_set_drvdata(pdev, jzdma); |
---|
775 | 861 | |
---|
776 | | - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
---|
777 | | - if (!res) { |
---|
| 862 | + jzdma->chn_base = devm_platform_ioremap_resource(pdev, 0); |
---|
| 863 | + if (IS_ERR(jzdma->chn_base)) |
---|
| 864 | + return PTR_ERR(jzdma->chn_base); |
---|
| 865 | + |
---|
| 866 | + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); |
---|
| 867 | + if (res) { |
---|
| 868 | + jzdma->ctrl_base = devm_ioremap_resource(dev, res); |
---|
| 869 | + if (IS_ERR(jzdma->ctrl_base)) |
---|
| 870 | + return PTR_ERR(jzdma->ctrl_base); |
---|
| 871 | + } else if (soc_data->flags & JZ_SOC_DATA_ALLOW_LEGACY_DT) { |
---|
| 872 | + /* |
---|
| 873 | + * On JZ4780, if the second memory resource was not supplied, |
---|
| 874 | + * assume we're using an old devicetree, and calculate the |
---|
| 875 | + * offset to the control registers. |
---|
| 876 | + */ |
---|
| 877 | + jzdma->ctrl_base = jzdma->chn_base + JZ4780_DMA_CTRL_OFFSET; |
---|
| 878 | + } else { |
---|
778 | 879 | dev_err(dev, "failed to get I/O memory\n"); |
---|
779 | 880 | return -EINVAL; |
---|
780 | | - } |
---|
781 | | - |
---|
782 | | - jzdma->base = devm_ioremap_resource(dev, res); |
---|
783 | | - if (IS_ERR(jzdma->base)) |
---|
784 | | - return PTR_ERR(jzdma->base); |
---|
785 | | - |
---|
786 | | - ret = platform_get_irq(pdev, 0); |
---|
787 | | - if (ret < 0) { |
---|
788 | | - dev_err(dev, "failed to get IRQ: %d\n", ret); |
---|
789 | | - return ret; |
---|
790 | | - } |
---|
791 | | - |
---|
792 | | - jzdma->irq = ret; |
---|
793 | | - |
---|
794 | | - ret = request_irq(jzdma->irq, jz4780_dma_irq_handler, 0, dev_name(dev), |
---|
795 | | - jzdma); |
---|
796 | | - if (ret) { |
---|
797 | | - dev_err(dev, "failed to request IRQ %u!\n", jzdma->irq); |
---|
798 | | - return ret; |
---|
799 | 881 | } |
---|
800 | 882 | |
---|
801 | 883 | jzdma->clk = devm_clk_get(dev, NULL); |
---|
802 | 884 | if (IS_ERR(jzdma->clk)) { |
---|
803 | 885 | dev_err(dev, "failed to get clock\n"); |
---|
804 | 886 | ret = PTR_ERR(jzdma->clk); |
---|
805 | | - goto err_free_irq; |
---|
| 887 | + return ret; |
---|
806 | 888 | } |
---|
807 | 889 | |
---|
808 | 890 | clk_prepare_enable(jzdma->clk); |
---|
.. | .. |
---|
839 | 921 | * Also set the FMSC bit - it increases MSC performance, so it makes |
---|
840 | 922 | * little sense not to enable it. |
---|
841 | 923 | */ |
---|
842 | | - jz4780_dma_writel(jzdma, JZ_DMA_REG_DMAC, |
---|
843 | | - JZ_DMA_DMAC_DMAE | JZ_DMA_DMAC_FMSC); |
---|
844 | | - jz4780_dma_writel(jzdma, JZ_DMA_REG_DMACP, 0); |
---|
| 924 | + jz4780_dma_ctrl_writel(jzdma, JZ_DMA_REG_DMAC, JZ_DMA_DMAC_DMAE | |
---|
| 925 | + JZ_DMA_DMAC_FAIC | JZ_DMA_DMAC_FMSC); |
---|
| 926 | + |
---|
| 927 | + if (soc_data->flags & JZ_SOC_DATA_PROGRAMMABLE_DMA) |
---|
| 928 | + jz4780_dma_ctrl_writel(jzdma, JZ_DMA_REG_DMACP, 0); |
---|
845 | 929 | |
---|
846 | 930 | INIT_LIST_HEAD(&dd->channels); |
---|
847 | 931 | |
---|
848 | | - for (i = 0; i < JZ_DMA_NR_CHANNELS; i++) { |
---|
| 932 | + for (i = 0; i < soc_data->nb_channels; i++) { |
---|
849 | 933 | jzchan = &jzdma->chan[i]; |
---|
850 | 934 | jzchan->id = i; |
---|
851 | 935 | |
---|
.. | .. |
---|
853 | 937 | jzchan->vchan.desc_free = jz4780_dma_desc_free; |
---|
854 | 938 | } |
---|
855 | 939 | |
---|
856 | | - ret = dma_async_device_register(dd); |
---|
| 940 | + ret = platform_get_irq(pdev, 0); |
---|
| 941 | + if (ret < 0) |
---|
| 942 | + goto err_disable_clk; |
---|
| 943 | + |
---|
| 944 | + jzdma->irq = ret; |
---|
| 945 | + |
---|
| 946 | + ret = request_irq(jzdma->irq, jz4780_dma_irq_handler, 0, dev_name(dev), |
---|
| 947 | + jzdma); |
---|
| 948 | + if (ret) { |
---|
| 949 | + dev_err(dev, "failed to request IRQ %u!\n", jzdma->irq); |
---|
| 950 | + goto err_disable_clk; |
---|
| 951 | + } |
---|
| 952 | + |
---|
| 953 | + ret = dmaenginem_async_device_register(dd); |
---|
857 | 954 | if (ret) { |
---|
858 | 955 | dev_err(dev, "failed to register device\n"); |
---|
859 | | - goto err_disable_clk; |
---|
| 956 | + goto err_free_irq; |
---|
860 | 957 | } |
---|
861 | 958 | |
---|
862 | 959 | /* Register with OF DMA helpers. */ |
---|
.. | .. |
---|
864 | 961 | jzdma); |
---|
865 | 962 | if (ret) { |
---|
866 | 963 | dev_err(dev, "failed to register OF DMA controller\n"); |
---|
867 | | - goto err_unregister_dev; |
---|
| 964 | + goto err_free_irq; |
---|
868 | 965 | } |
---|
869 | 966 | |
---|
870 | 967 | dev_info(dev, "JZ4780 DMA controller initialised\n"); |
---|
871 | 968 | return 0; |
---|
872 | 969 | |
---|
873 | | -err_unregister_dev: |
---|
874 | | - dma_async_device_unregister(dd); |
---|
| 970 | +err_free_irq: |
---|
| 971 | + free_irq(jzdma->irq, jzdma); |
---|
875 | 972 | |
---|
876 | 973 | err_disable_clk: |
---|
877 | 974 | clk_disable_unprepare(jzdma->clk); |
---|
878 | | - |
---|
879 | | -err_free_irq: |
---|
880 | | - free_irq(jzdma->irq, jzdma); |
---|
881 | 975 | return ret; |
---|
882 | 976 | } |
---|
883 | 977 | |
---|
.. | .. |
---|
888 | 982 | |
---|
889 | 983 | of_dma_controller_free(pdev->dev.of_node); |
---|
890 | 984 | |
---|
| 985 | + clk_disable_unprepare(jzdma->clk); |
---|
891 | 986 | free_irq(jzdma->irq, jzdma); |
---|
892 | 987 | |
---|
893 | | - for (i = 0; i < JZ_DMA_NR_CHANNELS; i++) |
---|
| 988 | + for (i = 0; i < jzdma->soc_data->nb_channels; i++) |
---|
894 | 989 | tasklet_kill(&jzdma->chan[i].vchan.task); |
---|
895 | 990 | |
---|
896 | | - dma_async_device_unregister(&jzdma->dma_device); |
---|
897 | 991 | return 0; |
---|
898 | 992 | } |
---|
899 | 993 | |
---|
| 994 | +static const struct jz4780_dma_soc_data jz4740_dma_soc_data = { |
---|
| 995 | + .nb_channels = 6, |
---|
| 996 | + .transfer_ord_max = 5, |
---|
| 997 | + .flags = JZ_SOC_DATA_BREAK_LINKS, |
---|
| 998 | +}; |
---|
| 999 | + |
---|
| 1000 | +static const struct jz4780_dma_soc_data jz4725b_dma_soc_data = { |
---|
| 1001 | + .nb_channels = 6, |
---|
| 1002 | + .transfer_ord_max = 5, |
---|
| 1003 | + .flags = JZ_SOC_DATA_PER_CHAN_PM | JZ_SOC_DATA_NO_DCKES_DCKEC | |
---|
| 1004 | + JZ_SOC_DATA_BREAK_LINKS, |
---|
| 1005 | +}; |
---|
| 1006 | + |
---|
| 1007 | +static const struct jz4780_dma_soc_data jz4770_dma_soc_data = { |
---|
| 1008 | + .nb_channels = 6, |
---|
| 1009 | + .transfer_ord_max = 6, |
---|
| 1010 | + .flags = JZ_SOC_DATA_PER_CHAN_PM, |
---|
| 1011 | +}; |
---|
| 1012 | + |
---|
| 1013 | +static const struct jz4780_dma_soc_data jz4780_dma_soc_data = { |
---|
| 1014 | + .nb_channels = 32, |
---|
| 1015 | + .transfer_ord_max = 7, |
---|
| 1016 | + .flags = JZ_SOC_DATA_ALLOW_LEGACY_DT | JZ_SOC_DATA_PROGRAMMABLE_DMA, |
---|
| 1017 | +}; |
---|
| 1018 | + |
---|
| 1019 | +static const struct jz4780_dma_soc_data x1000_dma_soc_data = { |
---|
| 1020 | + .nb_channels = 8, |
---|
| 1021 | + .transfer_ord_max = 7, |
---|
| 1022 | + .flags = JZ_SOC_DATA_PROGRAMMABLE_DMA, |
---|
| 1023 | +}; |
---|
| 1024 | + |
---|
| 1025 | +static const struct jz4780_dma_soc_data x1830_dma_soc_data = { |
---|
| 1026 | + .nb_channels = 32, |
---|
| 1027 | + .transfer_ord_max = 7, |
---|
| 1028 | + .flags = JZ_SOC_DATA_PROGRAMMABLE_DMA, |
---|
| 1029 | +}; |
---|
| 1030 | + |
---|
900 | 1031 | static const struct of_device_id jz4780_dma_dt_match[] = { |
---|
901 | | - { .compatible = "ingenic,jz4780-dma", .data = NULL }, |
---|
| 1032 | + { .compatible = "ingenic,jz4740-dma", .data = &jz4740_dma_soc_data }, |
---|
| 1033 | + { .compatible = "ingenic,jz4725b-dma", .data = &jz4725b_dma_soc_data }, |
---|
| 1034 | + { .compatible = "ingenic,jz4770-dma", .data = &jz4770_dma_soc_data }, |
---|
| 1035 | + { .compatible = "ingenic,jz4780-dma", .data = &jz4780_dma_soc_data }, |
---|
| 1036 | + { .compatible = "ingenic,x1000-dma", .data = &x1000_dma_soc_data }, |
---|
| 1037 | + { .compatible = "ingenic,x1830-dma", .data = &x1830_dma_soc_data }, |
---|
902 | 1038 | {}, |
---|
903 | 1039 | }; |
---|
904 | 1040 | MODULE_DEVICE_TABLE(of, jz4780_dma_dt_match); |
---|