1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (c) 2018-2019 Synopsys, Inc. and/or its affiliates.
4 * Synopsys DesignWare eDMA v0 core
6 * Author: Gustavo Pimentel <gustavo.pimentel@synopsys.com>
9 #include <linux/bitfield.h>
11 #include "dw-edma-core.h"
12 #include "dw-edma-v0-core.h"
13 #include "dw-edma-v0-regs.h"
14 #include "dw-edma-v0-debugfs.h"
16 enum dw_edma_control
{
17 DW_EDMA_V0_CB
= BIT(0),
18 DW_EDMA_V0_TCB
= BIT(1),
19 DW_EDMA_V0_LLP
= BIT(2),
20 DW_EDMA_V0_LIE
= BIT(3),
21 DW_EDMA_V0_RIE
= BIT(4),
22 DW_EDMA_V0_CCS
= BIT(8),
23 DW_EDMA_V0_LLE
= BIT(9),
26 static inline struct dw_edma_v0_regs __iomem
*__dw_regs(struct dw_edma
*dw
)
28 return dw
->rg_region
.vaddr
;
31 #define SET(dw, name, value) \
32 writel(value, &(__dw_regs(dw)->name))
34 #define GET(dw, name) \
35 readl(&(__dw_regs(dw)->name))
37 #define SET_RW(dw, dir, name, value) \
39 if ((dir) == EDMA_DIR_WRITE) \
40 SET(dw, wr_##name, value); \
42 SET(dw, rd_##name, value); \
45 #define GET_RW(dw, dir, name) \
46 ((dir) == EDMA_DIR_WRITE \
47 ? GET(dw, wr_##name) \
50 #define SET_BOTH(dw, name, value) \
52 SET(dw, wr_##name, value); \
53 SET(dw, rd_##name, value); \
56 static inline struct dw_edma_v0_ch_regs __iomem
*
57 __dw_ch_regs(struct dw_edma
*dw
, enum dw_edma_dir dir
, u16 ch
)
59 if (dw
->mode
== EDMA_MODE_LEGACY
)
60 return &(__dw_regs(dw
)->type
.legacy
.ch
);
62 if (dir
== EDMA_DIR_WRITE
)
63 return &__dw_regs(dw
)->type
.unroll
.ch
[ch
].wr
;
65 return &__dw_regs(dw
)->type
.unroll
.ch
[ch
].rd
;
68 static inline void writel_ch(struct dw_edma
*dw
, enum dw_edma_dir dir
, u16 ch
,
69 u32 value
, void __iomem
*addr
)
71 if (dw
->mode
== EDMA_MODE_LEGACY
) {
75 raw_spin_lock_irqsave(&dw
->lock
, flags
);
77 viewport_sel
= FIELD_PREP(EDMA_V0_VIEWPORT_MASK
, ch
);
78 if (dir
== EDMA_DIR_READ
)
79 viewport_sel
|= BIT(31);
82 &(__dw_regs(dw
)->type
.legacy
.viewport_sel
));
85 raw_spin_unlock_irqrestore(&dw
->lock
, flags
);
91 static inline u32
readl_ch(struct dw_edma
*dw
, enum dw_edma_dir dir
, u16 ch
,
92 const void __iomem
*addr
)
96 if (dw
->mode
== EDMA_MODE_LEGACY
) {
100 raw_spin_lock_irqsave(&dw
->lock
, flags
);
102 viewport_sel
= FIELD_PREP(EDMA_V0_VIEWPORT_MASK
, ch
);
103 if (dir
== EDMA_DIR_READ
)
104 viewport_sel
|= BIT(31);
107 &(__dw_regs(dw
)->type
.legacy
.viewport_sel
));
110 raw_spin_unlock_irqrestore(&dw
->lock
, flags
);
118 #define SET_CH(dw, dir, ch, name, value) \
119 writel_ch(dw, dir, ch, value, &(__dw_ch_regs(dw, dir, ch)->name))
121 #define GET_CH(dw, dir, ch, name) \
122 readl_ch(dw, dir, ch, &(__dw_ch_regs(dw, dir, ch)->name))
124 #define SET_LL(ll, value) \
127 /* eDMA management callbacks */
128 void dw_edma_v0_core_off(struct dw_edma
*dw
)
130 SET_BOTH(dw
, int_mask
, EDMA_V0_DONE_INT_MASK
| EDMA_V0_ABORT_INT_MASK
);
131 SET_BOTH(dw
, int_clear
, EDMA_V0_DONE_INT_MASK
| EDMA_V0_ABORT_INT_MASK
);
132 SET_BOTH(dw
, engine_en
, 0);
135 u16
dw_edma_v0_core_ch_count(struct dw_edma
*dw
, enum dw_edma_dir dir
)
139 if (dir
== EDMA_DIR_WRITE
)
140 num_ch
= FIELD_GET(EDMA_V0_WRITE_CH_COUNT_MASK
, GET(dw
, ctrl
));
142 num_ch
= FIELD_GET(EDMA_V0_READ_CH_COUNT_MASK
, GET(dw
, ctrl
));
144 if (num_ch
> EDMA_V0_MAX_NR_CH
)
145 num_ch
= EDMA_V0_MAX_NR_CH
;
150 enum dma_status
dw_edma_v0_core_ch_status(struct dw_edma_chan
*chan
)
152 struct dw_edma
*dw
= chan
->chip
->dw
;
155 tmp
= FIELD_GET(EDMA_V0_CH_STATUS_MASK
,
156 GET_CH(dw
, chan
->dir
, chan
->id
, ch_control1
));
159 return DMA_IN_PROGRESS
;
166 void dw_edma_v0_core_clear_done_int(struct dw_edma_chan
*chan
)
168 struct dw_edma
*dw
= chan
->chip
->dw
;
170 SET_RW(dw
, chan
->dir
, int_clear
,
171 FIELD_PREP(EDMA_V0_DONE_INT_MASK
, BIT(chan
->id
)));
174 void dw_edma_v0_core_clear_abort_int(struct dw_edma_chan
*chan
)
176 struct dw_edma
*dw
= chan
->chip
->dw
;
178 SET_RW(dw
, chan
->dir
, int_clear
,
179 FIELD_PREP(EDMA_V0_ABORT_INT_MASK
, BIT(chan
->id
)));
182 u32
dw_edma_v0_core_status_done_int(struct dw_edma
*dw
, enum dw_edma_dir dir
)
184 return FIELD_GET(EDMA_V0_DONE_INT_MASK
, GET_RW(dw
, dir
, int_status
));
187 u32
dw_edma_v0_core_status_abort_int(struct dw_edma
*dw
, enum dw_edma_dir dir
)
189 return FIELD_GET(EDMA_V0_ABORT_INT_MASK
, GET_RW(dw
, dir
, int_status
));
192 static void dw_edma_v0_core_write_chunk(struct dw_edma_chunk
*chunk
)
194 struct dw_edma_burst
*child
;
195 struct dw_edma_v0_lli __iomem
*lli
;
196 struct dw_edma_v0_llp __iomem
*llp
;
197 u32 control
= 0, i
= 0;
200 lli
= chunk
->ll_region
.vaddr
;
203 control
= DW_EDMA_V0_CB
;
205 j
= chunk
->bursts_alloc
;
206 list_for_each_entry(child
, &chunk
->burst
->list
, list
) {
209 control
|= (DW_EDMA_V0_LIE
| DW_EDMA_V0_RIE
);
211 /* Channel control */
212 SET_LL(&lli
[i
].control
, control
);
214 SET_LL(&lli
[i
].transfer_size
, child
->sz
);
215 /* SAR - low, high */
216 SET_LL(&lli
[i
].sar_low
, lower_32_bits(child
->sar
));
217 SET_LL(&lli
[i
].sar_high
, upper_32_bits(child
->sar
));
218 /* DAR - low, high */
219 SET_LL(&lli
[i
].dar_low
, lower_32_bits(child
->dar
));
220 SET_LL(&lli
[i
].dar_high
, upper_32_bits(child
->dar
));
224 llp
= (void __iomem
*)&lli
[i
];
225 control
= DW_EDMA_V0_LLP
| DW_EDMA_V0_TCB
;
227 control
|= DW_EDMA_V0_CB
;
229 /* Channel control */
230 SET_LL(&llp
->control
, control
);
231 /* Linked list - low, high */
232 SET_LL(&llp
->llp_low
, lower_32_bits(chunk
->ll_region
.paddr
));
233 SET_LL(&llp
->llp_high
, upper_32_bits(chunk
->ll_region
.paddr
));
236 void dw_edma_v0_core_start(struct dw_edma_chunk
*chunk
, bool first
)
238 struct dw_edma_chan
*chan
= chunk
->chan
;
239 struct dw_edma
*dw
= chan
->chip
->dw
;
242 dw_edma_v0_core_write_chunk(chunk
);
246 SET_RW(dw
, chan
->dir
, engine_en
, BIT(0));
247 /* Interrupt unmask - done, abort */
248 tmp
= GET_RW(dw
, chan
->dir
, int_mask
);
249 tmp
&= ~FIELD_PREP(EDMA_V0_DONE_INT_MASK
, BIT(chan
->id
));
250 tmp
&= ~FIELD_PREP(EDMA_V0_ABORT_INT_MASK
, BIT(chan
->id
));
251 SET_RW(dw
, chan
->dir
, int_mask
, tmp
);
252 /* Linked list error */
253 tmp
= GET_RW(dw
, chan
->dir
, linked_list_err_en
);
254 tmp
|= FIELD_PREP(EDMA_V0_LINKED_LIST_ERR_MASK
, BIT(chan
->id
));
255 SET_RW(dw
, chan
->dir
, linked_list_err_en
, tmp
);
256 /* Channel control */
257 SET_CH(dw
, chan
->dir
, chan
->id
, ch_control1
,
258 (DW_EDMA_V0_CCS
| DW_EDMA_V0_LLE
));
259 /* Linked list - low, high */
260 SET_CH(dw
, chan
->dir
, chan
->id
, llp_low
,
261 lower_32_bits(chunk
->ll_region
.paddr
));
262 SET_CH(dw
, chan
->dir
, chan
->id
, llp_high
,
263 upper_32_bits(chunk
->ll_region
.paddr
));
266 SET_RW(dw
, chan
->dir
, doorbell
,
267 FIELD_PREP(EDMA_V0_DOORBELL_CH_MASK
, chan
->id
));
270 int dw_edma_v0_core_device_config(struct dw_edma_chan
*chan
)
272 struct dw_edma
*dw
= chan
->chip
->dw
;
275 /* MSI done addr - low, high */
276 SET_RW(dw
, chan
->dir
, done_imwr_low
, chan
->msi
.address_lo
);
277 SET_RW(dw
, chan
->dir
, done_imwr_high
, chan
->msi
.address_hi
);
278 /* MSI abort addr - low, high */
279 SET_RW(dw
, chan
->dir
, abort_imwr_low
, chan
->msi
.address_lo
);
280 SET_RW(dw
, chan
->dir
, abort_imwr_high
, chan
->msi
.address_hi
);
281 /* MSI data - low, high */
285 tmp
= GET_RW(dw
, chan
->dir
, ch01_imwr_data
);
290 tmp
= GET_RW(dw
, chan
->dir
, ch23_imwr_data
);
295 tmp
= GET_RW(dw
, chan
->dir
, ch45_imwr_data
);
300 tmp
= GET_RW(dw
, chan
->dir
, ch67_imwr_data
);
304 if (chan
->id
& BIT(0)) {
305 /* Channel odd {1, 3, 5, 7} */
306 tmp
&= EDMA_V0_CH_EVEN_MSI_DATA_MASK
;
307 tmp
|= FIELD_PREP(EDMA_V0_CH_ODD_MSI_DATA_MASK
,
310 /* Channel even {0, 2, 4, 6} */
311 tmp
&= EDMA_V0_CH_ODD_MSI_DATA_MASK
;
312 tmp
|= FIELD_PREP(EDMA_V0_CH_EVEN_MSI_DATA_MASK
,
319 SET_RW(dw
, chan
->dir
, ch01_imwr_data
, tmp
);
324 SET_RW(dw
, chan
->dir
, ch23_imwr_data
, tmp
);
329 SET_RW(dw
, chan
->dir
, ch45_imwr_data
, tmp
);
334 SET_RW(dw
, chan
->dir
, ch67_imwr_data
, tmp
);
341 /* eDMA debugfs callbacks */
342 void dw_edma_v0_core_debugfs_on(struct dw_edma_chip
*chip
)
344 dw_edma_v0_debugfs_on(chip
);
347 void dw_edma_v0_core_debugfs_off(void)
349 dw_edma_v0_debugfs_off();