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