1 /* SPDX-License-Identifier: BSD-3-Clause */
2 /*
3 * Copyright (c) 2020-2021 Rockchip Electronics Co., Ltd.
4 */
5
6 #include "hal_base.h"
7
8 #ifdef HAL_DWDMA_MODULE_ENABLED
9
10 /** @addtogroup RK_HAL_Driver
11 * @{
12 */
13
14 /** @addtogroup DWDMA
15 * @{
16 */
17
18 /** @defgroup DWDMA_How_To_Use How To Use
19 * @{
20
21 The DWDMA driver can be used as follows:
22
23 - Invoke HAL_DWDMA_Init() to initialize dma.
24 - Invoke HAL_DWDMA_RequestChannel() to request a available dma channel.
25 - Invoke HAL_DWDMA_Config() to config dma transfer config.
26 - Invoke HAL_DWDMA_PrepDmaSingle()/HAL_DWDMA_PrepDmaCyclic() for single/cyclic transfer.
27 - Invoke HAL_DWDMA_Start() to start a ready dma transfer.
28 - Invoke HAL_DWDMA_Stop() to stop the dma channel.
29 - Invoke HAL_DWDMA_ReleaseChannel() to release the dma channel.
30 - Invoke HAL_DWDMA_DeInit() to deinitialize dma.
31 - More details refer to APIs' descriptions as below.
32
33 @} */
34
35 /** @defgroup DWDMA_Private_Definition Private Definition
36 * @{
37 */
38 /********************* Private MACRO Definition ******************************/
39
40 #define DW_CHAN_SET_BIT(reg, mask) \
41 WRITE_REG(reg, ((mask) << 8) | (mask))
42 #define DW_CHAN_CLEAR_BIT(reg, mask) \
43 WRITE_REG(reg, ((mask) << 8) | 0)
44
45 #define DWC_DEFAULT_CTLLO(_dwc) ({ \
46 struct DMA_SLAVE_CONFIG *_config = &(_dwc)->config; \
47 bool _islave = HAL_DMA_IsSlaveDirection((_dwc)->direction); \
48 uint8_t _smSize = _islave ? _config->srcMaxBurst : \
49 DWDMA_MSIZE_256; \
50 uint8_t _dmSize = _islave ? _config->dstMaxBurst : \
51 DWDMA_MSIZE_256; \
52 \
53 (DWC_CTLL_DST_MSIZE(_dmSize) \
54 | DWC_CTLL_SRC_MSIZE(_smSize) \
55 | DWC_CTLL_LLP_D_EN \
56 | DWC_CTLL_LLP_S_EN \
57 | DWC_CTLL_DMS((_dwc)->dstMaster) \
58 | DWC_CTLL_SMS((_dwc)->srcMaster)); \
59 })
60
61 /********************* Private Structure Definition **************************/
62
63 /********************* Private Variable Definition ***************************/
64
65 /********************* Private Function Definition ***************************/
66
DWC_DumpRegs(struct DWDMA_CHAN * dwc)67 __STATIC_INLINE void DWC_DumpRegs(struct DWDMA_CHAN *dwc)
68 {
69 HAL_DBG("SAR: 0x%08lx DAR: 0x%08lx LLP: 0x%08lx CTL: 0x%08lx:%08lx\n",
70 READ_REG(dwc->creg->SAR), READ_REG(dwc->creg->DAR),
71 READ_REG(dwc->creg->LLP), READ_REG(dwc->creg->CTL_HI),
72 READ_REG(dwc->creg->CTL_LO));
73 }
74
75 /**
76 * Fix config's burst len to bit.
77 */
DW_ConvertBurst(uint16_t * maxburst)78 __STATIC_INLINE void DW_ConvertBurst(uint16_t *maxburst)
79 {
80 uint32_t val;
81
82 switch (*maxburst) {
83 case 1:
84 val = 0;
85 break;
86 case 4:
87 val = 1;
88 break;
89 case 8:
90 val = 2;
91 break;
92 case 16:
93 val = 3;
94 break;
95 case 32:
96 val = 4;
97 break;
98 case 64:
99 val = 5;
100 break;
101 case 128:
102 val = 6;
103 break;
104 case 256:
105 val = 7;
106 break;
107 default:
108 val = 0;
109 break;
110 }
111
112 *maxburst = val;
113 }
114
115 /**
116 * Get burst len from bit.
117 * refer to MSIZE of register CTLx[13:11].
118 */
DW_GetBurstLength(uint32_t val)119 __STATIC_INLINE uint32_t DW_GetBurstLength(uint32_t val)
120 {
121 uint32_t len = 1;
122
123 if (val >= 1 && val <= 7) {
124 len = 1 << (val + 1);
125 }
126
127 return len;
128 }
129
DW_FFS(uint32_t word)130 __STATIC_INLINE uint32_t DW_FFS(uint32_t word)
131 {
132 #ifdef __GNUC__
133 HAL_ASSERT(word);
134
135 return (__builtin_ffs(word) - 1);
136 #else
137 int num = 0;
138
139 HAL_ASSERT(word);
140 if ((word & 0xffff) == 0) {
141 num += 16;
142 word >>= 16;
143 }
144 if ((word & 0xff) == 0) {
145 num += 8;
146 word >>= 8;
147 }
148 if ((word & 0xf) == 0) {
149 num += 4;
150 word >>= 4;
151 }
152 if ((word & 0x3) == 0) {
153 num += 2;
154 word >>= 2;
155 }
156 if ((word & 0x1) == 0) {
157 num += 1;
158 }
159
160 return num;
161 #endif
162 }
163
DWDMA_off(struct HAL_DWDMA_DEV * dw)164 static void DWDMA_off(struct HAL_DWDMA_DEV *dw)
165 {
166 struct DMA_REG *reg = dw->pReg;
167
168 WRITE_REG(reg->DMACFGREG, 0);
169
170 DW_CHAN_CLEAR_BIT(reg->MASK.TFR, dw->allChanMask);
171 DW_CHAN_CLEAR_BIT(reg->MASK.BLOCK, dw->allChanMask);
172 DW_CHAN_CLEAR_BIT(reg->MASK.SRCTRAN, dw->allChanMask);
173 DW_CHAN_CLEAR_BIT(reg->MASK.DSTTRAN, dw->allChanMask);
174 DW_CHAN_CLEAR_BIT(reg->MASK.ERR, dw->allChanMask);
175
176 while (READ_REG(reg->DMACFGREG) & DW_CFG_DMA_EN) {
177 ;
178 }
179 }
180
DWDMA_on(struct HAL_DWDMA_DEV * dw)181 static void DWDMA_on(struct HAL_DWDMA_DEV *dw)
182 {
183 struct DMA_REG *reg = dw->pReg;
184
185 WRITE_REG(reg->DMACFGREG, DW_CFG_DMA_EN);
186 }
187
DWC_initialize(struct DWDMA_CHAN * dwc)188 static void DWC_initialize(struct DWDMA_CHAN *dwc)
189 {
190 struct HAL_DWDMA_DEV *dw = dwc->dw;
191 uint32_t cfghi = DWC_CFGH_FIFO_MODE;
192 uint32_t cfglo = 0;
193
194 switch (dwc->direction) {
195 case DMA_MEM_TO_DEV:
196 cfglo |= dwc->cyclic ? DWC_CFGL_RELOAD_DAR : 0;
197 cfghi |= DWC_CFGH_DST_PER(dwc->periId);
198 break;
199 case DMA_DEV_TO_MEM:
200 cfglo |= dwc->cyclic ? DWC_CFGL_RELOAD_SAR : 0;
201 cfghi |= DWC_CFGH_SRC_PER(dwc->periId);
202 break;
203 default:
204 break;
205 }
206
207 WRITE_REG(dwc->creg->CFG_LO, cfglo);
208 WRITE_REG(dwc->creg->CFG_HI, cfghi);
209
210 /* Enable interrupts */
211 DW_CHAN_SET_BIT(dw->pReg->MASK.TFR, dwc->mask);
212 DW_CHAN_SET_BIT(dw->pReg->MASK.ERR, dwc->mask);
213 if (dwc->cyclic) {
214 DW_CHAN_SET_BIT(dw->pReg->MASK.BLOCK, dwc->mask);
215 }
216 }
217
DWC_deinitialize(struct DWDMA_CHAN * dwc)218 static void DWC_deinitialize(struct DWDMA_CHAN *dwc)
219 {
220 struct HAL_DWDMA_DEV *dw = dwc->dw;
221
222 /* Disable interrupts */
223 DW_CHAN_CLEAR_BIT(dw->pReg->MASK.TFR, dwc->mask);
224 DW_CHAN_CLEAR_BIT(dw->pReg->MASK.ERR, dwc->mask);
225 DW_CHAN_CLEAR_BIT(dw->pReg->MASK.BLOCK, dwc->mask);
226
227 /* Clear interrupts. */
228 WRITE_REG(dw->pReg->CLEAR.TFR, dwc->mask);
229 WRITE_REG(dw->pReg->CLEAR.SRCTRAN, dwc->mask);
230 WRITE_REG(dw->pReg->CLEAR.DSTTRAN, dwc->mask);
231 WRITE_REG(dw->pReg->CLEAR.ERR, dwc->mask);
232 WRITE_REG(dw->pReg->CLEAR.BLOCK, dwc->mask);
233 }
234
DWC_HandleCyclic(struct HAL_DWDMA_DEV * dw,struct DWDMA_CHAN * dwc,uint32_t statusBlock,uint32_t statusErr,uint32_t statusXfer)235 static void DWC_HandleCyclic(struct HAL_DWDMA_DEV *dw, struct DWDMA_CHAN *dwc,
236 uint32_t statusBlock, uint32_t statusErr, uint32_t statusXfer)
237 {
238 if (statusBlock & dwc->mask) {
239 if (!dwc->paused) {
240 WRITE_REG(dw->pReg->CLEAR.BLOCK, dwc->mask);
241 }
242 }
243
244 /* TODO: execption handler */
245 HAL_ASSERT(!statusErr && !statusXfer);
246
247 if (!dwc->paused) {
248 DW_CHAN_SET_BIT(dw->pReg->MASK.BLOCK, dwc->mask);
249 }
250 }
251
DWC_HandleError(struct HAL_DWDMA_DEV * dw,struct DWDMA_CHAN * dwc)252 static void DWC_HandleError(struct HAL_DWDMA_DEV *dw, struct DWDMA_CHAN *dwc)
253 {
254 HAL_DBG("%s: %d\n", __func__, __LINE__);
255
256 /* TODO: error handler */
257 DWC_DumpRegs(dwc);
258 WRITE_REG(dw->pReg->CLEAR.ERR, dwc->mask);
259 }
260
DWC_HandleXfer(struct HAL_DWDMA_DEV * dw,struct DWDMA_CHAN * dwc)261 static void DWC_HandleXfer(struct HAL_DWDMA_DEV *dw, struct DWDMA_CHAN *dwc)
262 {
263 HAL_DBG("%s: %d\n", __func__, __LINE__);
264
265 WRITE_REG(dw->pReg->CLEAR.TFR, dwc->mask);
266 }
267
268 /** @} */
269 /********************* Public Function Definition ****************************/
270
271 /** @defgroup DWDMA_Exported_Functions_Group2 State and Errors Functions
272
273 This section provides functions allowing to get the status of the module:
274
275 * @{
276 */
277
278 /** @} */
279
280 /** @defgroup DWDMA_Exported_Functions_Group4 Init and DeInit Functions
281
282 This section provides functions allowing to init and deinit the module:
283
284 * @{
285 */
286
287 /**
288 * @brief DW DMA Get Raw Block Status
289 *
290 * @param dw: the handle of dw dma.
291 *
292 * @return raw block status
293 */
HAL_DWDMA_GetRawBlockStatus(struct HAL_DWDMA_DEV * dw)294 uint32_t HAL_DWDMA_GetRawBlockStatus(struct HAL_DWDMA_DEV *dw)
295 {
296 return READ_REG(dw->pReg->RAW.BLOCK);
297 }
298
299 /**
300 * @brief DW DMA Get Raw Err Status
301 *
302 * @param dw: the handle of dw dma.
303 *
304 * @return raw err status
305 */
HAL_DWDMA_GetRawErrStatus(struct HAL_DWDMA_DEV * dw)306 uint32_t HAL_DWDMA_GetRawErrStatus(struct HAL_DWDMA_DEV *dw)
307 {
308 return READ_REG(dw->pReg->RAW.ERR);
309 }
310
311 /**
312 * @brief DW DMA Get Raw Xfer Status
313 *
314 * @param dw: the handle of dw dma.
315 *
316 * @return raw xfer status
317 */
HAL_DWDMA_GetRawXferStatus(struct HAL_DWDMA_DEV * dw)318 uint32_t HAL_DWDMA_GetRawXferStatus(struct HAL_DWDMA_DEV *dw)
319 {
320 return READ_REG(dw->pReg->RAW.TFR);
321 }
322
323 /**
324 * @brief Initializes a specific dw dma.
325 *
326 * @param dw: the handle of dw dma.
327 *
328 * @return
329 * - HAL_OK on success.
330 * - HAL_ERROR on fail.
331 */
HAL_DWDMA_Init(struct HAL_DWDMA_DEV * dw)332 HAL_Status HAL_DWDMA_Init(struct HAL_DWDMA_DEV *dw)
333 {
334 int i;
335 struct DMA_REG *reg = dw->pReg;
336 struct DWDMA_CHAN *dwc;
337
338 HAL_ASSERT(dw);
339
340 #ifdef HAL_DWDMA_BLOCK_ALIGN_SZ
341 HAL_ASSERT(HAL_DWDMA_BLOCK_ALIGN_SZ);
342 dw->blockSize &= ~(HAL_DWDMA_BLOCK_ALIGN_SZ - 1);
343 #endif
344 /* Calculate all channel mask before DMA setup */
345 dw->allChanMask = (1 << dw->maxChans) - 1;
346 /* Force dma off, just in case */
347 DWDMA_off(dw);
348
349 for (i = 0; i < dw->maxChans; i++) {
350 dwc = &dw->chan[i];
351
352 dwc->dw = dw;
353 dwc->creg = &(dw->pReg->CHAN[i]);
354 dwc->mask = 1 << i;
355 /* clear bit */
356 DW_CHAN_CLEAR_BIT(reg->CHENREG, dwc->mask);
357
358 dwc->direction = DMA_TRANS_NONE;
359 }
360
361 /* Clear all interrupts on all channels. */
362 WRITE_REG(reg->CLEAR.TFR, dw->allChanMask);
363 WRITE_REG(reg->CLEAR.BLOCK, dw->allChanMask);
364 WRITE_REG(reg->CLEAR.SRCTRAN, dw->allChanMask);
365 WRITE_REG(reg->CLEAR.DSTTRAN, dw->allChanMask);
366 WRITE_REG(reg->CLEAR.ERR, dw->allChanMask);
367
368 return HAL_OK;
369 }
370
371 /**
372 * @brief DeInitializes a specific dw dma.
373 *
374 * @param dw: the handle of dw dma.
375 *
376 * @return
377 * - HAL_OK on success.
378 * - HAL_ERROR on fail.
379 */
HAL_DWDMA_DeInit(struct HAL_DWDMA_DEV * dw)380 HAL_Status HAL_DWDMA_DeInit(struct HAL_DWDMA_DEV *dw)
381 {
382 HAL_ASSERT(dw);
383
384 DWDMA_off(dw);
385
386 DW_CHAN_CLEAR_BIT(dw->pReg->CHENREG, dw->allChanMask);
387
388 return HAL_OK;
389 }
390
391 /** @} */
392
393 /** @defgroup DWDMA_Exported_Functions_Group3 IO Functions
394
395 This section provides functions allowing to IO controlling:
396
397 * @{
398 */
399
400 /**
401 * @brief Pause the dma chan.
402 *
403 * @param dwc: the handle of dma chan.
404 *
405 * @return
406 * - HAL_OK on success
407 * - HAL_ERROR on other failures
408 */
HAL_DWDMA_Pause(struct DWDMA_CHAN * dwc)409 HAL_Status HAL_DWDMA_Pause(struct DWDMA_CHAN *dwc)
410 {
411 dwc->paused = true;
412
413 return HAL_OK;
414 }
415
416 /**
417 * @brief Resume the dma chan.
418 *
419 * @param dwc: the handle of dma chan.
420 *
421 * @return
422 * - HAL_OK on success
423 * - HAL_ERROR on other failures
424 */
HAL_DWDMA_Resume(struct DWDMA_CHAN * dwc)425 HAL_Status HAL_DWDMA_Resume(struct DWDMA_CHAN *dwc)
426 {
427 if (!dwc->paused) {
428 return HAL_OK;
429 }
430
431 dwc->paused = false;
432
433 WRITE_REG(dwc->dw->pReg->CLEAR.BLOCK, dwc->mask);
434 DW_CHAN_SET_BIT(dwc->dw->pReg->MASK.BLOCK, dwc->mask);
435
436 return HAL_OK;
437 }
438
439 /**
440 * @brief Start to run the dma chan.
441 *
442 * @param dwc: the handle of dma chan.
443 *
444 * @return
445 * - HAL_OK on success
446 * - HAL_BUSY if chan is busy
447 * - HAL_ERROR on other failures
448 */
HAL_DWDMA_Start(struct DWDMA_CHAN * dwc)449 HAL_Status HAL_DWDMA_Start(struct DWDMA_CHAN *dwc)
450 {
451 struct HAL_DWDMA_DEV *dw;
452 struct DMA_REG *reg;
453 struct DW_DESC *desc = &dwc->desc[0];
454 uint32_t ctllo = desc->lli.ctllo;
455
456 HAL_ASSERT(dwc);
457
458 dw = dwc->dw;
459 reg = dw->pReg;
460
461 if (READ_REG(reg->CHENREG) & dwc->mask) {
462 HAL_DBG("%s: chan is not idle\n", __func__);
463 DWC_DumpRegs(dwc);
464
465 return HAL_ERROR;
466 }
467
468 DWC_initialize(dwc);
469
470 desc = &dwc->desc[0];
471 WRITE_REG(dwc->creg->LLP, (uint32_t)desc);
472
473 ctllo = desc->lli.ctllo;
474 switch (dwc->direction) {
475 case DMA_MEM_TO_DEV:
476 ctllo |= DWC_CTLL_LLP_S_EN;
477 break;
478 case DMA_DEV_TO_MEM:
479 ctllo |= DWC_CTLL_LLP_D_EN;
480 break;
481 case DMA_MEM_TO_MEM:
482 ctllo |= DWC_CTLL_LLP_D_EN | DWC_CTLL_LLP_S_EN;
483 break;
484 default:
485 break;
486 }
487
488 WRITE_REG(dwc->creg->CTL_LO, ctllo);
489 WRITE_REG(dwc->creg->CTL_HI, 0);
490
491 DW_CHAN_SET_BIT(dw->pReg->CHENREG, dwc->mask);
492
493 return HAL_OK;
494 }
495
496 /**
497 * @brief Stop the dma chan.
498 *
499 * @param dwc: the handle of dma chan.
500 *
501 * @return
502 * - HAL_OK on success
503 * - HAL_BUSY if dma is busy
504 * - HAL_ERROR on other failures
505 */
HAL_DWDMA_Stop(struct DWDMA_CHAN * dwc)506 HAL_Status HAL_DWDMA_Stop(struct DWDMA_CHAN *dwc)
507 {
508 struct HAL_DWDMA_DEV *dw;
509
510 HAL_ASSERT(dwc);
511
512 dw = dwc->dw;
513
514 DW_CHAN_CLEAR_BIT(dw->pReg->CHENREG, dwc->mask);
515 while (READ_REG(dw->pReg->CHENREG) & dwc->mask) {
516 ;
517 }
518
519 DWC_deinitialize(dwc);
520
521 return HAL_OK;
522 }
523
524 /**
525 * @brief Handle dma chan
526 *
527 * @param dw: the handle of dw dma.
528 * @param chanId: the chan num.
529 *
530 * @return raw irq status
531 */
HAL_DWDMA_HandleChan(struct HAL_DWDMA_DEV * dw,uint32_t chanId)532 uint32_t HAL_DWDMA_HandleChan(struct HAL_DWDMA_DEV *dw, uint32_t chanId)
533 {
534 struct DWDMA_CHAN *dwc = &dw->chan[chanId];
535 uint32_t statusBlock;
536 uint32_t statusXfer;
537 uint32_t statusErr;
538
539 statusBlock = READ_REG(dw->pReg->RAW.BLOCK);
540 statusXfer = READ_REG(dw->pReg->RAW.TFR);
541 statusErr = READ_REG(dw->pReg->RAW.ERR);
542
543 if (dwc->cyclic) {
544 DWC_HandleCyclic(dw, dwc, statusBlock, statusXfer, statusXfer);
545 } else if (statusErr & dwc->mask) {
546 DWC_HandleError(dw, dwc);
547 } else if (statusXfer & dwc->mask) {
548 DWC_HandleXfer(dw, dwc);
549 }
550
551 return (statusBlock & dwc->mask) | (statusXfer & dwc->mask);
552 }
553
554 /**
555 * @brief dw dma IrqHandler
556 *
557 * @param dw: the handle of dw dma.
558 * @param chanId: the chan num.
559 *
560 * @return raw irq status
561 */
HAL_DWDMA_IrqHandler(struct HAL_DWDMA_DEV * dw,uint32_t chanId)562 uint32_t HAL_DWDMA_IrqHandler(struct HAL_DWDMA_DEV *dw, uint32_t chanId)
563 {
564 struct DWDMA_CHAN *dwc = &dw->chan[chanId];
565 uint32_t status = 0;
566
567 DW_CHAN_CLEAR_BIT(dw->pReg->MASK.TFR, dwc->mask);
568 DW_CHAN_CLEAR_BIT(dw->pReg->MASK.BLOCK, dwc->mask);
569 DW_CHAN_CLEAR_BIT(dw->pReg->MASK.ERR, dwc->mask);
570
571 status = HAL_DWDMA_HandleChan(dw, chanId);
572
573 /* Re-enable interrupts */
574 DW_CHAN_SET_BIT(dw->pReg->MASK.TFR, dwc->mask);
575 DW_CHAN_SET_BIT(dw->pReg->MASK.ERR, dwc->mask);
576
577 return status;
578 }
579
580 /**
581 * @brief Get the dma channel
582 *
583 * @param dw: the handle of dw dma.
584 * @param chanId: the chan id.
585 *
586 * @return the dma channel by chan id or NULL on error.
587 */
HAL_DWDMA_GetChannel(struct HAL_DWDMA_DEV * dw,uint32_t chanId)588 struct DWDMA_CHAN *HAL_DWDMA_GetChannel(struct HAL_DWDMA_DEV *dw, uint32_t chanId)
589 {
590 HAL_ASSERT(dw);
591
592 if (chanId > dw->maxChans) {
593 return NULL;
594 }
595
596 return &dw->chan[chanId];
597 }
598
599 /**
600 * @brief Request a dma channel
601 *
602 * @param dw: the handle of dw dma.
603 * @param id: the peri id.
604 *
605 * @return a idle dma channel.
606 * @note must hold lock.
607 */
HAL_DWDMA_RequestChannel(struct HAL_DWDMA_DEV * dw,DMA_REQ_Type id)608 struct DWDMA_CHAN *HAL_DWDMA_RequestChannel(struct HAL_DWDMA_DEV *dw, DMA_REQ_Type id)
609 {
610 struct DWDMA_CHAN *dwc = NULL;
611 int i;
612
613 HAL_ASSERT(dw);
614
615 if (!dw->used) {
616 DWDMA_on(dw);
617 }
618
619 for (i = 0; i < dw->maxChans; i++) {
620 dwc = &dw->chan[i];
621
622 if (dw->used & dwc->mask) {
623 continue;
624 }
625
626 dwc->periId = id;
627 dwc->chanId = i;
628 dw->used |= dwc->mask;
629 break;
630 }
631
632 if (i >= dw->maxChans || !dwc) {
633 return NULL;
634 }
635
636 return dwc;
637 }
638
639 /**
640 * @brief Release a dma channel
641 *
642 * @param dwc: the handle of dma chan.
643 *
644 * @return
645 * - HAL_OK on success.
646 * - HAL_ERROR on fail.
647 * @note must hold lock.
648 */
HAL_DWDMA_ReleaseChannel(struct DWDMA_CHAN * dwc)649 HAL_Status HAL_DWDMA_ReleaseChannel(struct DWDMA_CHAN *dwc)
650 {
651 struct HAL_DWDMA_DEV *dw;
652
653 HAL_ASSERT(dwc);
654
655 dw = dwc->dw;
656
657 dwc->periId = 0xff;
658
659 dwc->srcMaster = 0;
660 dwc->dstMaster = 0;
661
662 dwc->cyclic = false;
663
664 /* Disable interrupts */
665 DW_CHAN_CLEAR_BIT(dw->pReg->MASK.TFR, dwc->mask);
666 DW_CHAN_CLEAR_BIT(dw->pReg->MASK.BLOCK, dwc->mask);
667 DW_CHAN_CLEAR_BIT(dw->pReg->MASK.ERR, dwc->mask);
668
669 dw->used &= ~dwc->mask;
670 if (!dw->used) {
671 DWDMA_off(dw);
672 }
673
674 return HAL_OK;
675 }
676
677 /**
678 * @brief Config a dma channel
679 *
680 * @param dwc: the handle of dma chan.
681 * @param config: the peri req config.
682 *
683 * @return
684 * - HAL_OK on success.
685 * - HAL_ERROR on fail.
686 */
HAL_DWDMA_Config(struct DWDMA_CHAN * dwc,struct DMA_SLAVE_CONFIG * config)687 HAL_Status HAL_DWDMA_Config(struct DWDMA_CHAN *dwc, struct DMA_SLAVE_CONFIG *config)
688 {
689 memcpy(&dwc->config, config, sizeof(*config));
690 dwc->direction = config->direction;
691
692 DW_ConvertBurst(&dwc->config.srcMaxBurst);
693 DW_ConvertBurst(&dwc->config.dstMaxBurst);
694
695 return HAL_OK;
696 }
697
698 /**
699 * @brief Prepare a cyclic dma transfer for the channel
700 *
701 * @param dwc: the handle of dma chan.
702 * @param dmaAddr: the memory addr.
703 * @param len: data len.
704 * @param periodLen: periodic len.
705 * @param direction: transfer direction.
706 * @param callback: callback function.
707 * @param cparam: callback param.
708 *
709 * @return
710 * - HAL_OK on success.
711 * - HAL_ERROR on fail.
712 */
HAL_DWDMA_PrepDmaCyclic(struct DWDMA_CHAN * dwc,uint32_t dmaAddr,uint32_t len,uint32_t periodLen,eDMA_TRANSFER_DIRECTION direction,DMA_Callback callback,void * cparam)713 HAL_Status HAL_DWDMA_PrepDmaCyclic(struct DWDMA_CHAN *dwc, uint32_t dmaAddr,
714 uint32_t len, uint32_t periodLen,
715 eDMA_TRANSFER_DIRECTION direction,
716 DMA_Callback callback, void *cparam)
717 {
718 HAL_UNUSED struct HAL_DWDMA_DEV *dw;
719 struct DMA_SLAVE_CONFIG *config;
720 struct DW_DESC *desc, *last = NULL;
721 uint32_t regWidth;
722 uint32_t periods;
723 uint32_t i;
724
725 HAL_ASSERT(dwc);
726
727 dw = dwc->dw;
728 config = &dwc->config;
729
730 HAL_ASSERT(HAL_DMA_IsSlaveDirection(direction));
731
732 dwc->direction = direction;
733
734 if (direction == DMA_MEM_TO_DEV) {
735 regWidth = DW_FFS(config->dstAddrWidth);
736 WRITE_REG(dwc->creg->DAR, config->dstAddr);
737 } else {
738 regWidth = DW_FFS(config->srcAddrWidth);
739 WRITE_REG(dwc->creg->SAR, config->srcAddr);
740 }
741
742 periods = len / periodLen;
743
744 /* Check for too big/unaligned periods and unaligned DMA buffer. */
745 #ifdef HAL_DWDMA_BLOCK_ALIGN_SZ
746 HAL_ASSERT(HAL_IS_ALIGNED(periodLen, HAL_DWDMA_BLOCK_ALIGN_SZ));
747 #endif
748 HAL_ASSERT(periodLen <= (dw->blockSize << regWidth));
749 HAL_ASSERT(!(periodLen & ((1 << regWidth) - 1)));
750 HAL_ASSERT(!(dmaAddr & ((1 << regWidth) - 1)));
751
752 for (i = 0; i < periods; i++) {
753 desc = &dwc->desc[i];
754
755 HAL_ASSERT(desc);
756
757 switch (direction) {
758 case DMA_MEM_TO_DEV:
759 desc->lli.dar = config->dstAddr;
760 desc->lli.sar = dmaAddr + (periodLen * i);
761 desc->lli.ctllo = (DWC_DEFAULT_CTLLO(dwc)
762 | DWC_CTLL_DST_WIDTH(regWidth)
763 | DWC_CTLL_SRC_WIDTH(regWidth)
764 | DWC_CTLL_DST_FIX
765 | DWC_CTLL_SRC_INC
766 | DWC_CTLL_INT_EN
767 | DWC_CTLL_FC_M2P);
768
769 desc->lli.ctllo &= ~DWC_CTLL_LLP_D_EN;
770
771 break;
772 case DMA_DEV_TO_MEM:
773 desc->lli.dar = dmaAddr + (periodLen * i);
774 desc->lli.sar = config->srcAddr;
775 desc->lli.ctllo = (DWC_DEFAULT_CTLLO(dwc)
776 | DWC_CTLL_SRC_WIDTH(regWidth)
777 | DWC_CTLL_DST_WIDTH(regWidth)
778 | DWC_CTLL_DST_INC
779 | DWC_CTLL_SRC_FIX
780 | DWC_CTLL_INT_EN
781 | DWC_CTLL_FC_P2M);
782
783 desc->lli.ctllo &= ~DWC_CTLL_LLP_S_EN;
784
785 break;
786 default:
787 break;
788 }
789
790 desc->lli.ctlhi = (periodLen >> regWidth);
791 if (last) {
792 last->lli.llp = (uint32_t)desc;
793 }
794
795 last = desc;
796 }
797
798 /* cyclic */
799 last->lli.llp = (uint32_t)&dwc->desc[0];
800 dwc->cyclic = true;
801 dwc->callback = callback;
802 dwc->cparam = cparam;
803
804 HAL_DCACHE_CleanByRange((uint32_t)dwc->desc,
805 NR_DESCS_PER_CHANNEL * sizeof(*(dwc->desc)));
806
807 return HAL_OK;
808 }
809
810 /**
811 * @brief Prepare a single dma transfer for the channel
812 *
813 * @param dwc: the handle of dma chan.
814 * @param dmaAddr: the memory addr.
815 * @param len: data len.
816 * @param direction: transfer direction.
817 * @param callback: callback function.
818 * @param cparam: callback param.
819 *
820 * @return
821 * - HAL_OK on success.
822 * - HAL_ERROR on fail.
823 */
HAL_DWDMA_PrepDmaSingle(struct DWDMA_CHAN * dwc,uint32_t dmaAddr,uint32_t len,eDMA_TRANSFER_DIRECTION direction,DMA_Callback callback,void * cparam)824 HAL_Status HAL_DWDMA_PrepDmaSingle(struct DWDMA_CHAN *dwc, uint32_t dmaAddr,
825 uint32_t len,
826 eDMA_TRANSFER_DIRECTION direction,
827 DMA_Callback callback, void *cparam)
828 {
829 struct HAL_DWDMA_DEV *dw;
830 struct DMA_SLAVE_CONFIG *config;
831 struct DW_DESC *desc, *last = NULL;
832 uint32_t regWidth;
833 uint32_t xferCount;
834 uint32_t offset;
835 uint32_t src, dst;
836 uint32_t ctllo;
837 uint32_t burstLen;
838 uint32_t i = 0;
839
840 HAL_ASSERT(dwc);
841
842 dw = dwc->dw;
843 config = &dwc->config;
844
845 HAL_ASSERT(HAL_DMA_IsSlaveDirection(direction));
846
847 dwc->direction = direction;
848
849 if (direction == DMA_MEM_TO_DEV) {
850 burstLen = config->dstMaxBurst;
851 regWidth = DW_FFS(config->dstAddrWidth);
852 src = dmaAddr;
853 dst = config->dstAddr;
854 ctllo = (DWC_DEFAULT_CTLLO(dwc)
855 | DWC_CTLL_SRC_WIDTH(regWidth)
856 | DWC_CTLL_DST_WIDTH(regWidth)
857 | DWC_CTLL_DST_FIX
858 | DWC_CTLL_SRC_INC
859 | DWC_CTLL_FC_M2P);
860 } else {
861 burstLen = config->srcMaxBurst;
862 regWidth = DW_FFS(config->srcAddrWidth);
863 src = config->srcAddr;
864 dst = dmaAddr;
865 ctllo = (DWC_DEFAULT_CTLLO(dwc)
866 | DWC_CTLL_SRC_WIDTH(regWidth)
867 | DWC_CTLL_DST_WIDTH(regWidth)
868 | DWC_CTLL_DST_INC
869 | DWC_CTLL_SRC_FIX
870 | DWC_CTLL_FC_P2M);
871 }
872
873 burstLen = DW_GetBurstLength(burstLen);
874
875 for (offset = 0; offset < len; offset += xferCount << regWidth) {
876 xferCount = HAL_MIN((len - offset) >> regWidth, dw->blockSize);
877 xferCount &= ~(burstLen - 1);
878 desc = &dwc->desc[i];
879 desc->lli.sar = (ctllo & DWC_CTLL_SRC_FIX) ? src : src + offset;
880 desc->lli.dar = (ctllo & DWC_CTLL_DST_FIX) ? dst : dst + offset;
881 desc->lli.ctllo = ctllo;
882 desc->lli.ctlhi = xferCount;
883 desc->len = xferCount << regWidth;
884
885 if (last) {
886 last->lli.llp = (uint32_t)desc;
887 }
888
889 last = desc;
890
891 i++;
892 }
893
894 last->lli.ctllo |= DWC_CTLL_INT_EN;
895 last->lli.llp = 0;
896
897 dwc->callback = callback;
898 dwc->cparam = cparam;
899
900 HAL_DCACHE_CleanByRange((uint32_t)dwc->desc,
901 NR_DESCS_PER_CHANNEL * sizeof(*(dwc->desc)));
902
903 return HAL_OK;
904 }
905
906 /**
907 * @brief Prepare a dma memcpy
908 *
909 * @param dwc: the handle of dma chan.
910 * @param dst: the memory dst addr.
911 * @param src: the memory src addr.
912 * @param len: data len.
913 * @param callback: callback function.
914 * @param cparam: callback param.
915 *
916 * @return
917 * - HAL_OK on success.
918 * - HAL_ERROR on fail.
919 */
HAL_DWDMA_PrepDmaMemcpy(struct DWDMA_CHAN * dwc,uint32_t dst,uint32_t src,uint32_t len,DMA_Callback callback,void * cparam)920 HAL_Status HAL_DWDMA_PrepDmaMemcpy(struct DWDMA_CHAN *dwc, uint32_t dst,
921 uint32_t src, uint32_t len,
922 DMA_Callback callback, void *cparam)
923 {
924 struct HAL_DWDMA_DEV *dw;
925 struct DW_DESC *desc, *last = NULL;
926 uint32_t xferCount;
927 uint32_t offset;
928 uint32_t srcWidth;
929 uint32_t dstWidth;
930 uint32_t dataWidth;
931 uint32_t ctllo;
932 int i = 0;
933
934 HAL_ASSERT(dwc);
935 HAL_ASSERT(len);
936
937 dw = dwc->dw;
938
939 dwc->direction = DMA_MEM_TO_MEM;
940
941 dataWidth = dw->dataWidth;
942
943 srcWidth = dstWidth = DW_FFS(dataWidth | src | dst | len);
944
945 ctllo = DWC_DEFAULT_CTLLO(dwc)
946 | DWC_CTLL_DST_WIDTH(dstWidth)
947 | DWC_CTLL_SRC_WIDTH(srcWidth)
948 | DWC_CTLL_DST_INC
949 | DWC_CTLL_SRC_INC
950 | DWC_CTLL_FC_M2M;
951
952 for (offset = 0; offset < len; offset += xferCount << srcWidth) {
953 xferCount = HAL_MIN((len - offset) >> srcWidth, dw->blockSize);
954
955 desc = &dwc->desc[i];
956
957 desc->lli.sar = src + offset;
958 desc->lli.dar = dst + offset;
959 desc->lli.ctllo = ctllo;
960 desc->lli.ctlhi = xferCount;
961 desc->len = xferCount << srcWidth;
962
963 if (last) {
964 last->lli.llp = (uint32_t)desc;
965 }
966
967 last = desc;
968
969 i++;
970 }
971
972 last->lli.ctllo |= DWC_CTLL_INT_EN;
973 last->lli.llp = 0;
974
975 dwc->callback = callback;
976 dwc->cparam = cparam;
977
978 HAL_DCACHE_CleanByRange((uint32_t)dwc->desc,
979 NR_DESCS_PER_CHANNEL * sizeof(*(dwc->desc)));
980
981 return HAL_OK;
982 }
983
984 /** @} */
985
986 /** @} */
987
988 /** @} */
989
990 #endif /* HAL_DWDMA_MODULE_ENABLED */
991