1 /*
2 * Copyright 2024 Microchip Technology Inc. and its subsidiaries.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6 #include <stdbool.h>
7 #include <stddef.h>
8 #include <stdint.h>
9
10 #include <device_mec5.h>
11 #include "mec_pcfg.h"
12 #include "mec_defs.h"
13 #include "mec_dmac_api.h"
14 #include "mec_ecia_api.h"
15 #include "mec_pcr_api.h"
16 #include "mec_retval.h"
17
18 /* #define MEC_DMAC_DEBUG_REGS */
19
20 #define MEC_DMA_CHAN_ALL_STATUS (MEC_BIT(MEC_DMA_CHAN_ISTATUS_BERR_Pos) \
21 | MEC_BIT(MEC_DMA_CHAN_ISTATUS_HFCREQ_Pos) \
22 | MEC_BIT(MEC_DMA_CHAN_ISTATUS_DONE_Pos) \
23 | MEC_BIT(MEC_DMA_CHAN_ISTATUS_HFCTERM_Pos))
24
25 #define MEC_DMA_CHAN_STOP_WAIT 256u
26
27 #define MEC_DMAC_GIRQ 14
28 #define MEC_DMAC_GIRQ_IDX 6
29
30 #define MEC_DMAC_CHAN0_ECIA_INFO MEC5_ECIA_INFO(14, 0, 6, 24)
31 #define MEC_DMAC_CHAN1_ECIA_INFO MEC5_ECIA_INFO(14, 1, 6, 25)
32 #define MEC_DMAC_CHAN2_ECIA_INFO MEC5_ECIA_INFO(14, 2, 6, 26)
33 #define MEC_DMAC_CHAN3_ECIA_INFO MEC5_ECIA_INFO(14, 3, 6, 27)
34 #define MEC_DMAC_CHAN4_ECIA_INFO MEC5_ECIA_INFO(14, 4, 6, 28)
35 #define MEC_DMAC_CHAN5_ECIA_INFO MEC5_ECIA_INFO(14, 5, 6, 29)
36 #define MEC_DMAC_CHAN6_ECIA_INFO MEC5_ECIA_INFO(14, 6, 6, 30)
37 #define MEC_DMAC_CHAN7_ECIA_INFO MEC5_ECIA_INFO(14, 7, 6, 31)
38 #define MEC_DMAC_CHAN8_ECIA_INFO MEC5_ECIA_INFO(14, 8, 6, 32)
39 #define MEC_DMAC_CHAN9_ECIA_INFO MEC5_ECIA_INFO(14, 9, 6, 33)
40 #define MEC_DMAC_CHAN10_ECIA_INFO MEC5_ECIA_INFO(14, 10, 6, 34)
41 #define MEC_DMAC_CHAN11_ECIA_INFO MEC5_ECIA_INFO(14, 11, 6, 35)
42 #define MEC_DMAC_CHAN12_ECIA_INFO MEC5_ECIA_INFO(14, 12, 6, 36)
43 #define MEC_DMAC_CHAN13_ECIA_INFO MEC5_ECIA_INFO(14, 13, 6, 37)
44 #define MEC_DMAC_CHAN14_ECIA_INFO MEC5_ECIA_INFO(14, 14, 6, 38)
45 #define MEC_DMAC_CHAN15_ECIA_INFO MEC5_ECIA_INFO(14, 15, 6, 39)
46 #if MEC5_DMAC_NUM_CHANNELS == 20
47 #define MEC_DMAC_CHAN16_ECIA_INFO MEC5_ECIA_INFO(14, 16, 6, 194)
48 #define MEC_DMAC_CHAN17_ECIA_INFO MEC5_ECIA_INFO(14, 17, 6, 195)
49 #define MEC_DMAC_CHAN18_ECIA_INFO MEC5_ECIA_INFO(14, 18, 6, 196)
50 #define MEC_DMAC_CHAN19_ECIA_INFO MEC5_ECIA_INFO(14, 19, 6, 197)
51 #endif
52
53 // MEC_DMAC_BASE, MEC_PCR_DMA, MEC5_DMAC_NUM_CHANNELS
54 // MEC_PCR_DMA
55
56 const uint32_t dmac_ecia_info_table[MEC5_DMAC_NUM_CHANNELS] = {
57 MEC_DMAC_CHAN0_ECIA_INFO, MEC_DMAC_CHAN1_ECIA_INFO,
58 MEC_DMAC_CHAN2_ECIA_INFO, MEC_DMAC_CHAN3_ECIA_INFO,
59 MEC_DMAC_CHAN4_ECIA_INFO, MEC_DMAC_CHAN5_ECIA_INFO,
60 MEC_DMAC_CHAN6_ECIA_INFO, MEC_DMAC_CHAN7_ECIA_INFO,
61 MEC_DMAC_CHAN8_ECIA_INFO, MEC_DMAC_CHAN9_ECIA_INFO,
62 MEC_DMAC_CHAN10_ECIA_INFO, MEC_DMAC_CHAN11_ECIA_INFO,
63 MEC_DMAC_CHAN12_ECIA_INFO, MEC_DMAC_CHAN13_ECIA_INFO,
64 MEC_DMAC_CHAN14_ECIA_INFO, MEC_DMAC_CHAN15_ECIA_INFO,
65 #if MEC5_DMAC_NUM_CHANNELS == 20
66 MEC_DMAC_CHAN16_ECIA_INFO, MEC_DMAC_CHAN17_ECIA_INFO,
67 MEC_DMAC_CHAN18_ECIA_INFO, MEC_DMAC_CHAN19_ECIA_INFO,
68 #endif
69 };
70
71 #ifdef MEC_DMAC_DEBUG_REGS
72 struct mec_dma_chan_regs_save {
73 uint32_t actv;
74 uint32_t mstart;
75 uint32_t mend;
76 uint32_t dstart;
77 uint32_t ctrl;
78 uint32_t istatus;
79 uint32_t ien;
80 uint32_t fsm;
81 };
82
83 struct mec_dma_chan_regs_save dbg_mec_dma[MEC5_DMAC_NUM_CHANNELS];
84 #endif
85
dmac_get_ecia_info(uint32_t channel)86 static uint32_t dmac_get_ecia_info(uint32_t channel)
87 {
88 if (channel < MEC5_DMAC_NUM_CHANNELS) {
89 return dmac_ecia_info_table[channel];
90 }
91
92 return UINT32_MAX;
93 }
94
dma_chan_ia_enable(uint32_t channel)95 static void dma_chan_ia_enable(uint32_t channel)
96 {
97 uint32_t devi = dmac_get_ecia_info(channel);
98
99 mec_hal_girq_ctrl(devi, 1u);
100 }
101
dma_chan_ia_disable(uint32_t channel)102 static void dma_chan_ia_disable(uint32_t channel)
103 {
104 uint32_t devi = dmac_get_ecia_info(channel);
105
106 mec_hal_girq_ctrl(devi, 0);
107 }
108
dmac_clr_ia_status(uint32_t channel)109 static void dmac_clr_ia_status(uint32_t channel)
110 {
111 uint32_t devi = dmac_get_ecia_info(channel);
112
113 mec_hal_girq_clr_src(devi);
114 }
115
dma_clr_ia_all(void)116 static void dma_clr_ia_all(void)
117 {
118 for (uint8_t chan = 0; chan < MEC5_DMAC_NUM_CHANNELS; chan++) {
119 mec_hal_girq_clr_src(dmac_ecia_info_table[chan]);
120 }
121 }
122
mec_hal_dmac_girq_result(void)123 uint32_t mec_hal_dmac_girq_result(void)
124 {
125 return mec_hal_girq_result_get(MEC_DMAC_GIRQ);
126 }
127
mec_hal_dmac_girq_aggr(uint8_t enable)128 void mec_hal_dmac_girq_aggr(uint8_t enable)
129 {
130 mec_hal_ecia_girq_aggr_enable(MEC_DMAC_GIRQ, enable);
131 }
132
mec_hal_dmac_reset(void)133 int mec_hal_dmac_reset(void)
134 {
135 struct mec_dmac_regs *base = MEC_DMAC;
136
137 base->MCTRL |= MEC_BIT(MEC_DMAC_MCTRL_MRST_Pos);
138
139 return MEC_RET_OK;
140 }
141
mec_hal_dmac_enable(uint8_t enable)142 int mec_hal_dmac_enable(uint8_t enable)
143 {
144 struct mec_dmac_regs *base = MEC_DMAC;
145
146 if (enable) {
147 base->MCTRL |= MEC_BIT(MEC_DMAC_MCTRL_MACTV_Pos);
148 } else {
149 base->MCTRL &= (uint32_t)~MEC_BIT(MEC_DMAC_MCTRL_MACTV_Pos);
150 }
151
152 return MEC_RET_OK;
153 }
154
mec_hal_dmac_is_enabled(void)155 bool mec_hal_dmac_is_enabled(void)
156 {
157 struct mec_dmac_regs *base = MEC_DMAC;
158
159 if (base->MCTRL & MEC_BIT(MEC_DMAC_MCTRL_MACTV_Pos)) {
160 return true;
161 }
162
163 return false;
164 }
165
mec_hal_dma_chan_ia_status_clr(enum mec_dmac_channel channel)166 int mec_hal_dma_chan_ia_status_clr(enum mec_dmac_channel channel)
167 {
168 if (channel >= MEC5_DMAC_NUM_CHANNELS) {
169 return MEC_RET_ERR_INVAL;
170 }
171
172 dmac_clr_ia_status(channel);
173
174 return MEC_RET_OK;
175 }
176
mec_hal_dma_chan_ia_status_clr_mask(uint32_t chanmsk)177 int mec_hal_dma_chan_ia_status_clr_mask(uint32_t chanmsk)
178 {
179 chanmsk &= MEC_DMAC_ALL_CHAN_MASK;
180 if (!chanmsk) {
181 return MEC_RET_OK;
182 }
183
184 MEC_ECIA0->GIRQ[MEC_DMAC_GIRQ_IDX].SOURCE = chanmsk;
185
186 return MEC_RET_OK;
187 }
188
mec_hal_dma_chan_ia_enable(enum mec_dmac_channel channel)189 int mec_hal_dma_chan_ia_enable(enum mec_dmac_channel channel)
190 {
191 if (channel >= MEC5_DMAC_NUM_CHANNELS) {
192 return MEC_RET_ERR_INVAL;
193 }
194
195 dma_chan_ia_enable(channel);
196
197 return MEC_RET_OK;
198 }
199
mec_hal_dma_chan_ia_disable(enum mec_dmac_channel channel)200 int mec_hal_dma_chan_ia_disable(enum mec_dmac_channel channel)
201 {
202 if (channel >= MEC5_DMAC_NUM_CHANNELS) {
203 return MEC_RET_ERR_INVAL;
204 }
205
206 dma_chan_ia_disable(channel);
207
208 return MEC_RET_OK;
209 }
210
mec_hal_dma_chan_ia_enable_mask(uint32_t chan_mask)211 int mec_hal_dma_chan_ia_enable_mask(uint32_t chan_mask)
212 {
213 if (!chan_mask) {
214 return MEC_RET_OK;
215 }
216
217 for (uint32_t chan = 0; chan < MEC5_DMAC_NUM_CHANNELS; chan++) {
218 if (chan_mask & MEC_BIT(chan)) {
219 dma_chan_ia_enable(chan);
220 }
221 }
222
223 return MEC_RET_OK;
224 }
225
mec_hal_dma_chan_ia_disable_mask(uint32_t chan_mask)226 int mec_hal_dma_chan_ia_disable_mask(uint32_t chan_mask)
227 {
228 if (!chan_mask) {
229 return MEC_RET_OK;
230 }
231
232 for (uint32_t chan = 0; chan < MEC5_DMAC_NUM_CHANNELS; chan++) {
233 if (chan_mask & MEC_BIT(chan)) {
234 dma_chan_ia_disable(chan);
235 }
236 }
237
238 return MEC_RET_OK;
239 }
240
mec_hal_dmac_init(uint32_t chan_mask)241 int mec_hal_dmac_init(uint32_t chan_mask)
242 {
243 mec_hal_pcr_clr_blk_slp_en(MEC_PCR_DMA); /* clocks gated ON */
244 mec_hal_dmac_reset();
245 dma_clr_ia_all();
246 mec_hal_dmac_enable(1u);
247 mec_hal_dma_chan_ia_enable_mask(chan_mask);
248
249 return MEC_RET_OK;
250 }
251
mec_hal_dma_chan_init(enum mec_dmac_channel chan)252 int mec_hal_dma_chan_init(enum mec_dmac_channel chan)
253 {
254 struct mec_dmac_regs *base = MEC_DMAC;
255
256 if (chan >= MEC_DMAC_CHAN_MAX) {
257 return MEC_RET_ERR_INVAL;
258 }
259
260 struct mec_dma_chan_regs *regs = &base->CHAN[chan];
261
262 regs->MEND = 0;
263 regs->MSTART = 0;
264
265 regs->ACTV = 0;
266 regs->CTRL = 0;
267 regs->DSTART = 0;
268 regs->IEN = 0;
269 regs->ISTATUS = MEC_DMA_CHAN_ALL_STATUS;
270
271 return MEC_RET_OK;
272 }
273
mec_hal_dma_chan_intr_status(enum mec_dmac_channel chan,uint32_t * status)274 int mec_hal_dma_chan_intr_status(enum mec_dmac_channel chan, uint32_t *status)
275 {
276 struct mec_dmac_regs *base = MEC_DMAC;
277 uint32_t hwsts = 0u, logical_sts = 0u;
278
279 if (!status || (chan >= MEC_DMAC_CHAN_MAX)) {
280 return MEC_RET_ERR_INVAL;
281 }
282
283 hwsts = base->CHAN[chan].ISTATUS;
284 if (hwsts & MEC_BIT(MEC_DMA_CHAN_ISTATUS_BERR_Pos)) {
285 logical_sts |= MEC_BIT(MEC_DMA_CHAN_STS_BUS_ERR_POS);
286 }
287
288 if (hwsts & MEC_BIT(MEC_DMA_CHAN_ISTATUS_HFCREQ_Pos)) {
289 logical_sts |= MEC_BIT(MEC_DMA_CHAN_STS_HFC_OVF_POS);
290 }
291
292 if (hwsts & MEC_BIT(MEC_DMA_CHAN_ISTATUS_DONE_Pos)) {
293 logical_sts |= MEC_BIT(MEC_DMA_CHAN_STS_DONE_POS);
294 }
295
296 if (hwsts & MEC_BIT(MEC_DMA_CHAN_ISTATUS_HFCTERM_Pos)) {
297 logical_sts |= MEC_BIT(MEC_DMA_CHAN_STS_HFC_TERM_POS);
298 }
299
300 *status = logical_sts;
301
302 return MEC_RET_OK;
303 }
304
mec_hal_dma_chan_intr_status_clr(enum mec_dmac_channel chan)305 int mec_hal_dma_chan_intr_status_clr(enum mec_dmac_channel chan)
306 {
307 struct mec_dmac_regs *base = MEC_DMAC;
308
309 if (chan >= MEC_DMAC_CHAN_MAX) {
310 return MEC_RET_ERR_INVAL;
311 }
312
313 base->CHAN[chan].ISTATUS = MEC_DMA_CHAN_ALL_STATUS;
314 MEC_ECIA0->GIRQ[MEC_DMAC_GIRQ_IDX].SOURCE = MEC_BIT(chan);
315
316 return MEC_RET_OK;
317 }
318
mec_hal_dma_chan_intr_en(enum mec_dmac_channel chan,uint8_t ien)319 int mec_hal_dma_chan_intr_en(enum mec_dmac_channel chan, uint8_t ien)
320 {
321 struct mec_dmac_regs *base = MEC_DMAC;
322 uint32_t ien_val = 0u;
323
324 if (chan >= MEC_DMAC_CHAN_MAX) {
325 return MEC_RET_ERR_INVAL;
326 }
327
328 if (ien) {
329 ien_val = MEC_BIT(MEC_DMA_CHAN_IEN_DONE_Pos) | MEC_BIT(MEC_DMA_CHAN_IEN_BERR_Pos);
330 }
331
332 base->CHAN[chan].IEN = ien_val;
333
334 return MEC_RET_OK;
335 }
336
mec_hal_dma_chan_start(enum mec_dmac_channel chan)337 int mec_hal_dma_chan_start(enum mec_dmac_channel chan)
338 {
339 uint32_t ctrl = 0;
340 struct mec_dmac_regs *base = MEC_DMAC;
341 uint8_t start_pos = MEC_DMA_CHAN_CTRL_HFC_RUN_Pos;
342
343 if (chan >= MEC_DMAC_CHAN_MAX) {
344 return MEC_RET_ERR_INVAL;
345 }
346
347 struct mec_dma_chan_regs *regs = &base->CHAN[chan];
348
349 regs->ACTV = 0; /* clock gate */
350 ctrl = regs->CTRL;
351
352 if (ctrl & MEC_BIT(MEC_DMA_CHAN_CTRL_DHFC_Pos)) {
353 start_pos = MEC_DMA_CHAN_CTRL_SWFC_RUN_Pos;
354 }
355
356 ctrl &= (uint32_t)~(MEC_BIT(MEC_DMA_CHAN_CTRL_HFC_RUN_Pos)
357 | MEC_BIT(MEC_DMA_CHAN_CTRL_SWFC_RUN_Pos));
358
359 #ifdef MEC_DMAC_DEBUG_REGS
360 dbg_mec_dma[chan].actv = MEC_BIT(MEC_DMA_CHAN_ACTV_EN_Pos);
361 dbg_mec_dma[chan].mstart = regs->MSTART;
362 dbg_mec_dma[chan].mend = regs->MEND;
363 dbg_mec_dma[chan].dstart = regs->DSTART;
364 dbg_mec_dma[chan].ctrl = ctrl | MEC_BIT(start_pos);
365 dbg_mec_dma[chan].istatus = regs->ISTATUS;
366 dbg_mec_dma[chan].ien = regs->IEN;
367 dbg_mec_dma[chan].fsm = regs->FSM;
368 #endif
369
370 regs->CTRL = ctrl | MEC_BIT(start_pos);
371 regs->ACTV = MEC_BIT(MEC_DMA_CHAN_ACTV_EN_Pos);
372
373 return MEC_RET_OK;
374 }
375
mec_hal_dma_chan_is_busy(enum mec_dmac_channel chan)376 bool mec_hal_dma_chan_is_busy(enum mec_dmac_channel chan)
377 {
378 struct mec_dmac_regs *base = MEC_DMAC;
379
380 if (chan >= MEC_DMAC_CHAN_MAX) {
381 return false;
382 }
383
384 if (base->CHAN[chan].CTRL & MEC_BIT(MEC_DMA_CHAN_CTRL_BUSY_Pos)) {
385 return true;
386 }
387
388 return false;
389 }
390
mec_hal_dma_chan_halt(enum mec_dmac_channel chan)391 int mec_hal_dma_chan_halt(enum mec_dmac_channel chan)
392 {
393 struct mec_dmac_regs *base = MEC_DMAC;
394 uint32_t halt = (MEC_BIT(MEC_DMA_CHAN_CTRL_HFC_RUN_Pos)
395 | MEC_BIT(MEC_DMA_CHAN_CTRL_SWFC_RUN_Pos));
396
397 if (chan >= MEC_DMAC_CHAN_MAX) {
398 return MEC_RET_ERR_INVAL;
399 }
400
401 struct mec_dma_chan_regs *regs = &base->CHAN[chan];
402
403 regs->CTRL &= ~halt;
404 regs->ACTV = 0;
405
406 return MEC_RET_OK;
407 }
408
mec_hal_dma_chan_stop(enum mec_dmac_channel chan)409 int mec_hal_dma_chan_stop(enum mec_dmac_channel chan)
410 {
411 struct mec_dmac_regs *base = MEC_DMAC;
412 uint32_t wait_cnt = MEC_DMA_CHAN_STOP_WAIT;
413 int ret = MEC_RET_OK;
414
415 if (chan >= MEC_DMAC_CHAN_MAX) {
416 return MEC_RET_ERR_INVAL;
417 }
418
419 struct mec_dma_chan_regs *regs = &base->CHAN[chan];
420
421 if (regs->CTRL & MEC_BIT(MEC_DMA_CHAN_CTRL_BUSY_Pos)) {
422 regs->CTRL |= MEC_BIT(MEC_DMA_CHAN_CTRL_ABORT_Pos);
423 /* should stop on next byte boundary */
424 while (regs->CTRL & MEC_BIT(MEC_DMA_CHAN_CTRL_BUSY_Pos)) {
425 if (!wait_cnt) {
426 ret = MEC_RET_ERR_TIMEOUT;
427 break;
428 }
429 wait_cnt--;
430 }
431 }
432
433 regs->CTRL &= (uint32_t)~(MEC_BIT(MEC_DMA_CHAN_CTRL_HFC_RUN_Pos)
434 | MEC_BIT(MEC_DMA_CHAN_CTRL_SWFC_RUN_Pos));
435 regs->ACTV = 0;
436
437 return ret;
438 }
439
mec_hal_dma_chan_hwfc_set(enum mec_dmac_channel chan,enum mec_dmac_hwfc_dev_id hwfc_dev,uintptr_t dev_addr)440 int mec_hal_dma_chan_hwfc_set(enum mec_dmac_channel chan, enum mec_dmac_hwfc_dev_id hwfc_dev,
441 uintptr_t dev_addr)
442 {
443 struct mec_dmac_regs *base = MEC_DMAC;
444 uint32_t ctrl = 0;
445
446 if ((chan >= MEC_DMAC_CHAN_MAX) || (hwfc_dev >= MEC_DMAC_DEV_ID_MAX)) {
447 return MEC_RET_ERR_INVAL;
448 }
449
450 struct mec_dma_chan_regs *regs = &base->CHAN[chan];
451
452 ctrl = regs->CTRL & (uint32_t)~(MEC_DMA_CHAN_CTRL_HFC_DEV_Msk);
453 ctrl |= (((uint32_t)hwfc_dev << MEC_DMA_CHAN_CTRL_HFC_DEV_Pos)
454 & MEC_DMA_CHAN_CTRL_HFC_DEV_Msk);
455 regs->CTRL = ctrl;
456 regs->DSTART = dev_addr;
457
458 return MEC_RET_OK;
459 }
460
mec_hal_dma_chan_dir_set(enum mec_dmac_channel chan,enum mec_dmac_dir dir)461 int mec_hal_dma_chan_dir_set(enum mec_dmac_channel chan, enum mec_dmac_dir dir)
462 {
463 struct mec_dmac_regs *base = MEC_DMAC;
464
465 if ((chan >= MEC_DMAC_CHAN_MAX) || (dir >= MEC_DMAC_DIR_MAX)) {
466 return MEC_RET_ERR_INVAL;
467 }
468
469 struct mec_dma_chan_regs *regs = &base->CHAN[chan];
470
471 if (dir == MEC_DMAC_DIR_MEM_TO_DEV) {
472 regs->CTRL |= MEC_BIT(MEC_DMA_CHAN_CTRL_MEM2DEV_Pos);
473 } else {
474 regs->CTRL &= (uint32_t)~MEC_BIT(MEC_DMA_CHAN_CTRL_MEM2DEV_Pos);
475 }
476
477 return MEC_RET_OK;
478 }
479
mec_hal_dma_chan_dir_get(enum mec_dmac_channel chan,enum mec_dmac_dir * dir)480 int mec_hal_dma_chan_dir_get(enum mec_dmac_channel chan, enum mec_dmac_dir * dir)
481 {
482 struct mec_dmac_regs *base = MEC_DMAC;
483
484 if (!dir || (chan >= MEC_DMAC_CHAN_MAX)) {
485 return MEC_RET_ERR_INVAL;
486 }
487
488 *dir = MEC_DMAC_DIR_DEV_TO_MEM;
489 if (base->CHAN[chan].CTRL & MEC_BIT(MEC_DMA_CHAN_CTRL_MEM2DEV_Pos)) {
490 *dir = MEC_DMAC_DIR_MEM_TO_DEV;
491 }
492
493 return MEC_RET_OK;
494 }
495
mec_hal_dma_chan_mem_set(enum mec_dmac_channel chan,uintptr_t maddr,size_t nbytes)496 int mec_hal_dma_chan_mem_set(enum mec_dmac_channel chan, uintptr_t maddr, size_t nbytes)
497 {
498 struct mec_dmac_regs *base = MEC_DMAC;
499
500 if (chan >= MEC_DMAC_CHAN_MAX) {
501 return MEC_RET_ERR_INVAL;
502 }
503
504 struct mec_dma_chan_regs *regs = &base->CHAN[chan];
505
506 regs->MSTART = maddr;
507 regs->MEND = maddr + nbytes;
508
509 return MEC_RET_OK;
510 }
511
mec_hal_dma_chan_mem_units_set(enum mec_dmac_channel chan,enum mec_dmac_unit_size unitsz)512 int mec_hal_dma_chan_mem_units_set(enum mec_dmac_channel chan, enum mec_dmac_unit_size unitsz)
513 {
514 struct mec_dmac_regs *base = MEC_DMAC;
515 uint32_t ctrl = 0, v = 0;
516
517 if (chan >= MEC_DMAC_CHAN_MAX) {
518 return MEC_RET_ERR_INVAL;
519 }
520
521 struct mec_dma_chan_regs *regs = &base->CHAN[chan];
522
523 v = 1u;
524 if ((unitsz == 4u) || (unitsz == 2u)) {
525 v = unitsz;
526 }
527
528 v <<= MEC_DMA_CHAN_CTRL_UNITSZ_Pos;
529 ctrl = regs->CTRL & (uint32_t)~MEC_DMA_CHAN_CTRL_UNITSZ_Msk;
530 ctrl |= v;
531 regs->CTRL = ctrl;
532
533 return MEC_RET_OK;
534 }
535
mec_hal_dma_chan_rem_bytes(enum mec_dmac_channel chan,uint32_t * remsz)536 int mec_hal_dma_chan_rem_bytes(enum mec_dmac_channel chan, uint32_t *remsz)
537 {
538 struct mec_dmac_regs *base = MEC_DMAC;
539 uint32_t mstart = 0, mend = 0, nrem = 0;
540
541 if (!remsz || (chan >= MEC_DMAC_CHAN_MAX)) {
542 return MEC_RET_ERR_INVAL;
543 }
544
545 struct mec_dma_chan_regs *regs = &base->CHAN[chan];
546
547 nrem = 0u;
548 mend = regs->MEND;
549 mstart = regs->MSTART;
550 if (mend > mstart) {
551 nrem = mend - mstart;
552 }
553
554 *remsz = nrem;
555
556 return 0;
557 }
558
mec_hal_dma_chan_reload(enum mec_dmac_channel chan,uintptr_t src,uintptr_t dest,size_t nbytes)559 int mec_hal_dma_chan_reload(enum mec_dmac_channel chan, uintptr_t src, uintptr_t dest,
560 size_t nbytes)
561 {
562 struct mec_dmac_regs *base = MEC_DMAC;
563
564 if (chan >= MEC_DMAC_CHAN_MAX) {
565 return MEC_RET_ERR_INVAL;
566 }
567
568 struct mec_dma_chan_regs *regs = &base->CHAN[chan];
569
570 /* ensure HW is "done" by mstart == mend */
571 regs->MSTART = base->CHAN[chan].MEND;
572 regs->MEND = 0; /* keep mend <= mstart */
573
574 if (regs->CTRL & MEC_BIT(MEC_DMA_CHAN_CTRL_MEM2DEV_Pos)) {
575 regs->MSTART = src;
576 regs->MEND = src + nbytes;
577 regs->DSTART = dest;
578 } else { /* device to memory */
579 regs->MSTART = dest;
580 regs->MEND = dest + nbytes;
581 regs->DSTART = src;
582 }
583
584 return MEC_RET_OK;
585 }
586
587 /* Configure a DMA channel for transfer.
588 * DMA termination is based on channel memory start address incrementing until it matches
589 * the memory end address. Device has start address register but no end address.
590 * Control register has a bit to select the direction Memory to Device or Device to Memory.
591 * Memory to Device: source is memory, destination is device.
592 * Control direction bit = 1 (Mem2Dev)
593 * Control Increment Mem = 1
594 * Control Increment Dev is optional. Current MCHP peripherals which can use central DMA
595 * expose their data as a single data register.
596 * Memory Start address reg = source address
597 * Memory End addresss reg = source address + transfer size in bytes
598 * Device Start address reg = destination address
599 *
600 * Device to Memory: source is device HW register, destination is memory
601 * Control direction bit = 0 (Dev2Mem)
602 * Control Increment Mem = 1 may be 0 if writing same value to device.
603 * Control Increment Dev is optional.
604 * Memory Start address reg = destination address (memory)
605 * Memory End address regs = destination address + transfer size in bytes
606 * Device Start address reg = source address (device register address)
607 */
mec_hal_dma_chan_cfg(enum mec_dmac_channel chan,struct mec_dma_cfg * cfg)608 int mec_hal_dma_chan_cfg(enum mec_dmac_channel chan, struct mec_dma_cfg *cfg)
609 {
610 struct mec_dmac_regs *base = MEC_DMAC;
611 uint32_t ctrl = 0u; /* dir = Dev2Mem, IncrMem=0, IncrDev=0 */
612 uint32_t usz = 1u;
613
614 if (!cfg || (chan >= MEC_DMAC_CHAN_MAX)) {
615 return MEC_RET_ERR_INVAL;
616 }
617
618 mec_hal_dma_chan_init(chan);
619
620 if ((cfg->unitsz == 4u) || (cfg->unitsz == 2u)) {
621 usz = cfg->unitsz;
622 }
623
624 struct mec_dma_chan_regs *regs = &base->CHAN[chan];
625
626 ctrl = usz << MEC_DMA_CHAN_CTRL_UNITSZ_Pos;
627 if (cfg->dir == MEC_DMAC_DIR_MEM_TO_DEV) {
628 ctrl |= MEC_BIT(MEC_DMA_CHAN_CTRL_MEM2DEV_Pos);
629 regs->MSTART = cfg->src_addr;
630 regs->MEND = cfg->src_addr + cfg->nbytes;
631 regs->DSTART = cfg->dst_addr;
632 if (cfg->flags & MEC_DMA_CFG_FLAG_INCR_SRC_ADDR) {
633 ctrl |= MEC_BIT(MEC_DMA_CHAN_CTRL_INCRM_Pos);
634 }
635 if (cfg->flags & MEC_DMA_CFG_FLAG_INCR_DST_ADDR) {
636 ctrl |= MEC_BIT(MEC_DMA_CHAN_CTRL_INCRD_Pos);
637 }
638 } else { /* device(source address) to memory(destination address) */
639 regs->MSTART = cfg->dst_addr;
640 regs->MEND = cfg->dst_addr + cfg->nbytes;
641 regs->DSTART = cfg->src_addr;
642 if (cfg->flags & MEC_DMA_CFG_FLAG_INCR_SRC_ADDR) {
643 ctrl |= MEC_BIT(MEC_DMA_CHAN_CTRL_INCRD_Pos);
644 }
645 if (cfg->flags & MEC_DMA_CFG_FLAG_INCR_DST_ADDR) {
646 ctrl |= MEC_BIT(MEC_DMA_CHAN_CTRL_INCRM_Pos);
647 }
648 }
649
650 if (cfg->hwfc_dev < MEC_DMAC_DEV_ID_NONE) {
651 ctrl |= (((uint32_t)cfg->hwfc_dev << MEC_DMA_CHAN_CTRL_HFC_DEV_Pos)
652 & MEC_DMA_CHAN_CTRL_HFC_DEV_Msk);
653 } else {
654 ctrl |= MEC_BIT(MEC_DMA_CHAN_CTRL_DHFC_Pos);
655 }
656
657 regs->CTRL = ctrl;
658 regs->ACTV |= MEC_BIT(MEC_DMA_CHAN_ACTV_EN_Pos);
659
660 return MEC_RET_OK;
661 }
662
mec_hal_dma_chan_cfg_get(enum mec_dmac_channel chan,struct mec_dma_cfg * cfg)663 int mec_hal_dma_chan_cfg_get(enum mec_dmac_channel chan, struct mec_dma_cfg *cfg)
664 {
665 struct mec_dmac_regs *base = MEC_DMAC;
666 uint32_t ctrl = 0u, dstart = 0u, mstart = 0u, mend = 0u;
667
668 if (!cfg || (chan >= MEC_DMAC_CHAN_MAX)) {
669 return MEC_RET_ERR_INVAL;
670 }
671
672 struct mec_dma_chan_regs *regs = &base->CHAN[chan];
673
674 cfg->flags = 0u;
675
676 ctrl = regs->CTRL;
677 if (ctrl & MEC_BIT(MEC_DMA_CHAN_CTRL_DHFC_Pos)) {
678 cfg->hwfc_dev = MEC_DMAC_DEV_ID_NONE;
679 } else {
680 cfg->hwfc_dev = (ctrl & MEC_DMA_CHAN_CTRL_HFC_DEV_Msk) >> MEC_DMA_CHAN_CTRL_HFC_DEV_Pos;
681 }
682
683 if (ctrl & MEC_BIT(MEC_DMA_CHAN_CTRL_MEM2DEV_Pos)) {
684 cfg->dir = MEC_DMAC_DIR_MEM_TO_DEV;
685 if (ctrl & MEC_BIT(MEC_DMA_CHAN_CTRL_INCRM_Pos)) {
686 cfg->flags |= MEC_DMA_CFG_FLAG_INCR_SRC_ADDR;
687 }
688 if (ctrl & MEC_BIT(MEC_DMA_CHAN_CTRL_INCRD_Pos)) {
689 cfg->flags |= MEC_DMA_CFG_FLAG_INCR_DST_ADDR;
690 }
691 } else {
692 cfg->dir = MEC_DMAC_DIR_DEV_TO_MEM;
693 if (ctrl & MEC_BIT(MEC_DMA_CHAN_CTRL_INCRM_Pos)) {
694 cfg->flags |= MEC_DMA_CFG_FLAG_INCR_DST_ADDR;
695 }
696 if (ctrl & MEC_BIT(MEC_DMA_CHAN_CTRL_INCRD_Pos)) {
697 cfg->flags |= MEC_DMA_CFG_FLAG_INCR_SRC_ADDR;
698 }
699 }
700
701 cfg->nbytes = 0u;
702 mstart = regs->MSTART;
703 mend = regs->MEND;
704 dstart = regs->DSTART;
705 if (mend > mstart) {
706 cfg->nbytes = mend - mstart;
707 }
708
709 if (ctrl & MEC_BIT(MEC_DMA_CHAN_CTRL_MEM2DEV_Pos)) {
710 cfg->src_addr = mstart;
711 cfg->dst_addr = dstart;
712 } else {
713 cfg->src_addr = dstart;
714 cfg->dst_addr = mstart;
715 }
716
717 return MEC_RET_OK;
718 }
719 /* end mec_dmac.c */
720