5ddc90c0445f26e57462ba29339dbb6e8e92f116
[openwrt/staging/jow.git] / target / linux / at91 / patches-5.10 / 133-dmaengine-at_xdmac-add-support-for-sama7g5-based-at_.patch
1 From 613af756b93fe005d9db11ea26fd0318f239d5a2 Mon Sep 17 00:00:00 2001
2 From: Eugen Hristev <eugen.hristev@microchip.com>
3 Date: Fri, 16 Oct 2020 12:38:50 +0300
4 Subject: [PATCH 133/247] dmaengine: at_xdmac: add support for sama7g5 based
5 at_xdmac
6
7 SAMA7G5 SoC uses a slightly different variant of the AT_XDMAC.
8 Added support by a new compatible and a layout struct that copes
9 to the specific version considering the compatible string.
10 Only the differences in register map are present in the layout struct.
11 I reworked the register access for this part that has the differences.
12 Also the Source/Destination Interface bits are no longer valid for this
13 variant of the XDMAC. Thus, the layout also has a bool for specifying
14 whether these bits are required or not.
15
16 Signed-off-by: Eugen Hristev <eugen.hristev@microchip.com>
17 Link: https://lore.kernel.org/r/20201016093850.290053-1-eugen.hristev@microchip.com
18 Signed-off-by: Vinod Koul <vkoul@kernel.org>
19 ---
20 drivers/dma/at_xdmac.c | 110 +++++++++++++++++++++++++++++++----------
21 1 file changed, 84 insertions(+), 26 deletions(-)
22
23 diff --git a/drivers/dma/at_xdmac.c b/drivers/dma/at_xdmac.c
24 index 85fe260ccd07..2b096ea04018 100644
25 --- a/drivers/dma/at_xdmac.c
26 +++ b/drivers/dma/at_xdmac.c
27 @@ -38,13 +38,6 @@
28 #define AT_XDMAC_GE 0x1C /* Global Channel Enable Register */
29 #define AT_XDMAC_GD 0x20 /* Global Channel Disable Register */
30 #define AT_XDMAC_GS 0x24 /* Global Channel Status Register */
31 -#define AT_XDMAC_GRS 0x28 /* Global Channel Read Suspend Register */
32 -#define AT_XDMAC_GWS 0x2C /* Global Write Suspend Register */
33 -#define AT_XDMAC_GRWS 0x30 /* Global Channel Read Write Suspend Register */
34 -#define AT_XDMAC_GRWR 0x34 /* Global Channel Read Write Resume Register */
35 -#define AT_XDMAC_GSWR 0x38 /* Global Channel Software Request Register */
36 -#define AT_XDMAC_GSWS 0x3C /* Global channel Software Request Status Register */
37 -#define AT_XDMAC_GSWF 0x40 /* Global Channel Software Flush Request Register */
38 #define AT_XDMAC_VERSION 0xFFC /* XDMAC Version Register */
39
40 /* Channel relative registers offsets */
41 @@ -151,8 +144,6 @@
42 #define AT_XDMAC_CSUS 0x30 /* Channel Source Microblock Stride */
43 #define AT_XDMAC_CDUS 0x34 /* Channel Destination Microblock Stride */
44
45 -#define AT_XDMAC_CHAN_REG_BASE 0x50 /* Channel registers base address */
46 -
47 /* Microblock control members */
48 #define AT_XDMAC_MBR_UBC_UBLEN_MAX 0xFFFFFFUL /* Maximum Microblock Length */
49 #define AT_XDMAC_MBR_UBC_NDE (0x1 << 24) /* Next Descriptor Enable */
50 @@ -180,6 +171,27 @@ enum atc_status {
51 AT_XDMAC_CHAN_IS_PAUSED,
52 };
53
54 +struct at_xdmac_layout {
55 + /* Global Channel Read Suspend Register */
56 + u8 grs;
57 + /* Global Write Suspend Register */
58 + u8 gws;
59 + /* Global Channel Read Write Suspend Register */
60 + u8 grws;
61 + /* Global Channel Read Write Resume Register */
62 + u8 grwr;
63 + /* Global Channel Software Request Register */
64 + u8 gswr;
65 + /* Global channel Software Request Status Register */
66 + u8 gsws;
67 + /* Global Channel Software Flush Request Register */
68 + u8 gswf;
69 + /* Channel reg base */
70 + u8 chan_cc_reg_base;
71 + /* Source/Destination Interface must be specified or not */
72 + bool sdif;
73 +};
74 +
75 /* ----- Channels ----- */
76 struct at_xdmac_chan {
77 struct dma_chan chan;
78 @@ -213,6 +225,7 @@ struct at_xdmac {
79 struct clk *clk;
80 u32 save_gim;
81 struct dma_pool *at_xdmac_desc_pool;
82 + const struct at_xdmac_layout *layout;
83 struct at_xdmac_chan chan[];
84 };
85
86 @@ -245,9 +258,33 @@ struct at_xdmac_desc {
87 struct list_head xfer_node;
88 } __aligned(sizeof(u64));
89
90 +static const struct at_xdmac_layout at_xdmac_sama5d4_layout = {
91 + .grs = 0x28,
92 + .gws = 0x2C,
93 + .grws = 0x30,
94 + .grwr = 0x34,
95 + .gswr = 0x38,
96 + .gsws = 0x3C,
97 + .gswf = 0x40,
98 + .chan_cc_reg_base = 0x50,
99 + .sdif = true,
100 +};
101 +
102 +static const struct at_xdmac_layout at_xdmac_sama7g5_layout = {
103 + .grs = 0x30,
104 + .gws = 0x38,
105 + .grws = 0x40,
106 + .grwr = 0x44,
107 + .gswr = 0x48,
108 + .gsws = 0x4C,
109 + .gswf = 0x50,
110 + .chan_cc_reg_base = 0x60,
111 + .sdif = false,
112 +};
113 +
114 static inline void __iomem *at_xdmac_chan_reg_base(struct at_xdmac *atxdmac, unsigned int chan_nb)
115 {
116 - return atxdmac->regs + (AT_XDMAC_CHAN_REG_BASE + chan_nb * 0x40);
117 + return atxdmac->regs + (atxdmac->layout->chan_cc_reg_base + chan_nb * 0x40);
118 }
119
120 #define at_xdmac_read(atxdmac, reg) readl_relaxed((atxdmac)->regs + (reg))
121 @@ -343,8 +380,10 @@ static void at_xdmac_start_xfer(struct at_xdmac_chan *atchan,
122 first->active_xfer = true;
123
124 /* Tell xdmac where to get the first descriptor. */
125 - reg = AT_XDMAC_CNDA_NDA(first->tx_dma_desc.phys)
126 - | AT_XDMAC_CNDA_NDAIF(atchan->memif);
127 + reg = AT_XDMAC_CNDA_NDA(first->tx_dma_desc.phys);
128 + if (atxdmac->layout->sdif)
129 + reg |= AT_XDMAC_CNDA_NDAIF(atchan->memif);
130 +
131 at_xdmac_chan_write(atchan, AT_XDMAC_CNDA, reg);
132
133 /*
134 @@ -539,6 +578,7 @@ static int at_xdmac_compute_chan_conf(struct dma_chan *chan,
135 enum dma_transfer_direction direction)
136 {
137 struct at_xdmac_chan *atchan = to_at_xdmac_chan(chan);
138 + struct at_xdmac *atxdmac = to_at_xdmac(atchan->chan.device);
139 int csize, dwidth;
140
141 if (direction == DMA_DEV_TO_MEM) {
142 @@ -546,12 +586,14 @@ static int at_xdmac_compute_chan_conf(struct dma_chan *chan,
143 AT91_XDMAC_DT_PERID(atchan->perid)
144 | AT_XDMAC_CC_DAM_INCREMENTED_AM
145 | AT_XDMAC_CC_SAM_FIXED_AM
146 - | AT_XDMAC_CC_DIF(atchan->memif)
147 - | AT_XDMAC_CC_SIF(atchan->perif)
148 | AT_XDMAC_CC_SWREQ_HWR_CONNECTED
149 | AT_XDMAC_CC_DSYNC_PER2MEM
150 | AT_XDMAC_CC_MBSIZE_SIXTEEN
151 | AT_XDMAC_CC_TYPE_PER_TRAN;
152 + if (atxdmac->layout->sdif)
153 + atchan->cfg |= AT_XDMAC_CC_DIF(atchan->memif) |
154 + AT_XDMAC_CC_SIF(atchan->perif);
155 +
156 csize = ffs(atchan->sconfig.src_maxburst) - 1;
157 if (csize < 0) {
158 dev_err(chan2dev(chan), "invalid src maxburst value\n");
159 @@ -569,12 +611,14 @@ static int at_xdmac_compute_chan_conf(struct dma_chan *chan,
160 AT91_XDMAC_DT_PERID(atchan->perid)
161 | AT_XDMAC_CC_DAM_FIXED_AM
162 | AT_XDMAC_CC_SAM_INCREMENTED_AM
163 - | AT_XDMAC_CC_DIF(atchan->perif)
164 - | AT_XDMAC_CC_SIF(atchan->memif)
165 | AT_XDMAC_CC_SWREQ_HWR_CONNECTED
166 | AT_XDMAC_CC_DSYNC_MEM2PER
167 | AT_XDMAC_CC_MBSIZE_SIXTEEN
168 | AT_XDMAC_CC_TYPE_PER_TRAN;
169 + if (atxdmac->layout->sdif)
170 + atchan->cfg |= AT_XDMAC_CC_DIF(atchan->perif) |
171 + AT_XDMAC_CC_SIF(atchan->memif);
172 +
173 csize = ffs(atchan->sconfig.dst_maxburst) - 1;
174 if (csize < 0) {
175 dev_err(chan2dev(chan), "invalid src maxburst value\n");
176 @@ -864,10 +908,12 @@ at_xdmac_interleaved_queue_desc(struct dma_chan *chan,
177 * ERRATA: Even if useless for memory transfers, the PERID has to not
178 * match the one of another channel. If not, it could lead to spurious
179 * flag status.
180 + * For SAMA7G5x case, the SIF and DIF fields are no longer used.
181 + * Thus, no need to have the SIF/DIF interfaces here.
182 + * For SAMA5D4x and SAMA5D2x the SIF and DIF are already configured as
183 + * zero.
184 */
185 u32 chan_cc = AT_XDMAC_CC_PERID(0x7f)
186 - | AT_XDMAC_CC_DIF(0)
187 - | AT_XDMAC_CC_SIF(0)
188 | AT_XDMAC_CC_MBSIZE_SIXTEEN
189 | AT_XDMAC_CC_TYPE_MEM_TRAN;
190
191 @@ -1046,12 +1092,14 @@ at_xdmac_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
192 * ERRATA: Even if useless for memory transfers, the PERID has to not
193 * match the one of another channel. If not, it could lead to spurious
194 * flag status.
195 + * For SAMA7G5x case, the SIF and DIF fields are no longer used.
196 + * Thus, no need to have the SIF/DIF interfaces here.
197 + * For SAMA5D4x and SAMA5D2x the SIF and DIF are already configured as
198 + * zero.
199 */
200 u32 chan_cc = AT_XDMAC_CC_PERID(0x7f)
201 | AT_XDMAC_CC_DAM_INCREMENTED_AM
202 | AT_XDMAC_CC_SAM_INCREMENTED_AM
203 - | AT_XDMAC_CC_DIF(0)
204 - | AT_XDMAC_CC_SIF(0)
205 | AT_XDMAC_CC_MBSIZE_SIXTEEN
206 | AT_XDMAC_CC_TYPE_MEM_TRAN;
207 unsigned long irqflags;
208 @@ -1152,12 +1200,14 @@ static struct at_xdmac_desc *at_xdmac_memset_create_desc(struct dma_chan *chan,
209 * ERRATA: Even if useless for memory transfers, the PERID has to not
210 * match the one of another channel. If not, it could lead to spurious
211 * flag status.
212 + * For SAMA7G5x case, the SIF and DIF fields are no longer used.
213 + * Thus, no need to have the SIF/DIF interfaces here.
214 + * For SAMA5D4x and SAMA5D2x the SIF and DIF are already configured as
215 + * zero.
216 */
217 u32 chan_cc = AT_XDMAC_CC_PERID(0x7f)
218 | AT_XDMAC_CC_DAM_UBS_AM
219 | AT_XDMAC_CC_SAM_INCREMENTED_AM
220 - | AT_XDMAC_CC_DIF(0)
221 - | AT_XDMAC_CC_SIF(0)
222 | AT_XDMAC_CC_MBSIZE_SIXTEEN
223 | AT_XDMAC_CC_MEMSET_HW_MODE
224 | AT_XDMAC_CC_TYPE_MEM_TRAN;
225 @@ -1436,7 +1486,7 @@ at_xdmac_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
226 mask = AT_XDMAC_CC_TYPE | AT_XDMAC_CC_DSYNC;
227 value = AT_XDMAC_CC_TYPE_PER_TRAN | AT_XDMAC_CC_DSYNC_PER2MEM;
228 if ((desc->lld.mbr_cfg & mask) == value) {
229 - at_xdmac_write(atxdmac, AT_XDMAC_GSWF, atchan->mask);
230 + at_xdmac_write(atxdmac, atxdmac->layout->gswf, atchan->mask);
231 while (!(at_xdmac_chan_read(atchan, AT_XDMAC_CIS) & AT_XDMAC_CIS_FIS))
232 cpu_relax();
233 }
234 @@ -1494,7 +1544,7 @@ at_xdmac_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
235 * FIFO flush ensures that data are really written.
236 */
237 if ((desc->lld.mbr_cfg & mask) == value) {
238 - at_xdmac_write(atxdmac, AT_XDMAC_GSWF, atchan->mask);
239 + at_xdmac_write(atxdmac, atxdmac->layout->gswf, atchan->mask);
240 while (!(at_xdmac_chan_read(atchan, AT_XDMAC_CIS) & AT_XDMAC_CIS_FIS))
241 cpu_relax();
242 }
243 @@ -1760,7 +1810,7 @@ static int at_xdmac_device_pause(struct dma_chan *chan)
244 return 0;
245
246 spin_lock_irqsave(&atchan->lock, flags);
247 - at_xdmac_write(atxdmac, AT_XDMAC_GRWS, atchan->mask);
248 + at_xdmac_write(atxdmac, atxdmac->layout->grws, atchan->mask);
249 while (at_xdmac_chan_read(atchan, AT_XDMAC_CC)
250 & (AT_XDMAC_CC_WRIP | AT_XDMAC_CC_RDIP))
251 cpu_relax();
252 @@ -1783,7 +1833,7 @@ static int at_xdmac_device_resume(struct dma_chan *chan)
253 return 0;
254 }
255
256 - at_xdmac_write(atxdmac, AT_XDMAC_GRWR, atchan->mask);
257 + at_xdmac_write(atxdmac, atxdmac->layout->grwr, atchan->mask);
258 clear_bit(AT_XDMAC_CHAN_IS_PAUSED, &atchan->status);
259 spin_unlock_irqrestore(&atchan->lock, flags);
260
261 @@ -1985,6 +2035,10 @@ static int at_xdmac_probe(struct platform_device *pdev)
262 atxdmac->regs = base;
263 atxdmac->irq = irq;
264
265 + atxdmac->layout = of_device_get_match_data(&pdev->dev);
266 + if (!atxdmac->layout)
267 + return -ENODEV;
268 +
269 atxdmac->clk = devm_clk_get(&pdev->dev, "dma_clk");
270 if (IS_ERR(atxdmac->clk)) {
271 dev_err(&pdev->dev, "can't get dma_clk\n");
272 @@ -2127,6 +2181,10 @@ static const struct dev_pm_ops atmel_xdmac_dev_pm_ops = {
273 static const struct of_device_id atmel_xdmac_dt_ids[] = {
274 {
275 .compatible = "atmel,sama5d4-dma",
276 + .data = &at_xdmac_sama5d4_layout,
277 + }, {
278 + .compatible = "microchip,sama7g5-dma",
279 + .data = &at_xdmac_sama7g5_layout,
280 }, {
281 /* sentinel */
282 }
283 --
284 2.32.0
285