1 /*****************************************************************************
2 * Copyright 2003 - 2008 Broadcom Corporation. All rights reserved.
4 * Unless you and Broadcom execute a separate written software license
5 * agreement governing use of this software, this software is licensed to you
6 * under the terms of the GNU General Public License version 2, available at
7 * http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
9 * Notwithstanding the above, under no circumstances may you combine this
10 * software in any way with any other Broadcom software provided under a
11 * license other than the GPL, without Broadcom's express prior written
13 *****************************************************************************/
15 /****************************************************************************/
17 * @file dmacHw_extra.c
19 * @brief Extra Low level DMA controller driver routines
23 * These routines provide basic DMA functionality only.
25 /****************************************************************************/
27 /* ---- Include Files ---------------------------------------------------- */
29 #include <csp/stdint.h>
32 #include <csp/dmacHw.h>
33 #include <mach/csp/dmacHw_reg.h>
34 #include <mach/csp/dmacHw_priv.h>
36 extern dmacHw_CBLK_t dmacHw_gCblk[dmacHw_MAX_CHANNEL_COUNT]; /* Declared in dmacHw.c */
38 /* ---- External Function Prototypes ------------------------------------- */
40 /* ---- Internal Use Function Prototypes --------------------------------- */
41 /****************************************************************************/
43 * @brief Overwrites data length in the descriptor
45 * This function overwrites data length in the descriptor
51 * This is only used for PCM channel
53 /****************************************************************************/
54 void dmacHw_setDataLength(dmacHw_CONFIG_t *pConfig, /* [ IN ] Configuration settings */
55 void *pDescriptor, /* [ IN ] Descriptor buffer */
56 size_t dataLen /* [ IN ] Data length in bytes */
59 /****************************************************************************/
61 * @brief Helper function to display DMA registers
69 /****************************************************************************/
70 static void DisplayRegisterContents(int module, /* [ IN ] DMA Controller unit (0-1) */
71 int channel, /* [ IN ] DMA Channel (0-7) / -1(all) */
72 int (*fpPrint) (const char *, ...) /* [ IN ] Callback to the print function */
76 (*fpPrint) ("Displaying register content \n\n");
77 (*fpPrint) ("Module %d: Interrupt raw transfer 0x%X\n",
78 module, (uint32_t) (dmacHw_REG_INT_RAW_TRAN(module)));
79 (*fpPrint) ("Module %d: Interrupt raw block 0x%X\n",
80 module, (uint32_t) (dmacHw_REG_INT_RAW_BLOCK(module)));
81 (*fpPrint) ("Module %d: Interrupt raw src transfer 0x%X\n",
82 module, (uint32_t) (dmacHw_REG_INT_RAW_STRAN(module)));
83 (*fpPrint) ("Module %d: Interrupt raw dst transfer 0x%X\n",
84 module, (uint32_t) (dmacHw_REG_INT_RAW_DTRAN(module)));
85 (*fpPrint) ("Module %d: Interrupt raw error 0x%X\n",
86 module, (uint32_t) (dmacHw_REG_INT_RAW_ERROR(module)));
87 (*fpPrint) ("--------------------------------------------------\n");
88 (*fpPrint) ("Module %d: Interrupt stat transfer 0x%X\n",
89 module, (uint32_t) (dmacHw_REG_INT_STAT_TRAN(module)));
90 (*fpPrint) ("Module %d: Interrupt stat block 0x%X\n",
91 module, (uint32_t) (dmacHw_REG_INT_STAT_BLOCK(module)));
92 (*fpPrint) ("Module %d: Interrupt stat src transfer 0x%X\n",
93 module, (uint32_t) (dmacHw_REG_INT_STAT_STRAN(module)));
94 (*fpPrint) ("Module %d: Interrupt stat dst transfer 0x%X\n",
95 module, (uint32_t) (dmacHw_REG_INT_STAT_DTRAN(module)));
96 (*fpPrint) ("Module %d: Interrupt stat error 0x%X\n",
97 module, (uint32_t) (dmacHw_REG_INT_STAT_ERROR(module)));
98 (*fpPrint) ("--------------------------------------------------\n");
99 (*fpPrint) ("Module %d: Interrupt mask transfer 0x%X\n",
100 module, (uint32_t) (dmacHw_REG_INT_MASK_TRAN(module)));
101 (*fpPrint) ("Module %d: Interrupt mask block 0x%X\n",
102 module, (uint32_t) (dmacHw_REG_INT_MASK_BLOCK(module)));
103 (*fpPrint) ("Module %d: Interrupt mask src transfer 0x%X\n",
104 module, (uint32_t) (dmacHw_REG_INT_MASK_STRAN(module)));
105 (*fpPrint) ("Module %d: Interrupt mask dst transfer 0x%X\n",
106 module, (uint32_t) (dmacHw_REG_INT_MASK_DTRAN(module)));
107 (*fpPrint) ("Module %d: Interrupt mask error 0x%X\n",
108 module, (uint32_t) (dmacHw_REG_INT_MASK_ERROR(module)));
109 (*fpPrint) ("--------------------------------------------------\n");
110 (*fpPrint) ("Module %d: Interrupt clear transfer 0x%X\n",
111 module, (uint32_t) (dmacHw_REG_INT_CLEAR_TRAN(module)));
112 (*fpPrint) ("Module %d: Interrupt clear block 0x%X\n",
113 module, (uint32_t) (dmacHw_REG_INT_CLEAR_BLOCK(module)));
114 (*fpPrint) ("Module %d: Interrupt clear src transfer 0x%X\n",
115 module, (uint32_t) (dmacHw_REG_INT_CLEAR_STRAN(module)));
116 (*fpPrint) ("Module %d: Interrupt clear dst transfer 0x%X\n",
117 module, (uint32_t) (dmacHw_REG_INT_CLEAR_DTRAN(module)));
118 (*fpPrint) ("Module %d: Interrupt clear error 0x%X\n",
119 module, (uint32_t) (dmacHw_REG_INT_CLEAR_ERROR(module)));
120 (*fpPrint) ("--------------------------------------------------\n");
121 (*fpPrint) ("Module %d: SW source req 0x%X\n",
122 module, (uint32_t) (dmacHw_REG_SW_HS_SRC_REQ(module)));
123 (*fpPrint) ("Module %d: SW dest req 0x%X\n",
124 module, (uint32_t) (dmacHw_REG_SW_HS_DST_REQ(module)));
125 (*fpPrint) ("Module %d: SW source signal 0x%X\n",
126 module, (uint32_t) (dmacHw_REG_SW_HS_SRC_SGL_REQ(module)));
127 (*fpPrint) ("Module %d: SW dest signal 0x%X\n",
128 module, (uint32_t) (dmacHw_REG_SW_HS_DST_SGL_REQ(module)));
129 (*fpPrint) ("Module %d: SW source last 0x%X\n",
130 module, (uint32_t) (dmacHw_REG_SW_HS_SRC_LST_REQ(module)));
131 (*fpPrint) ("Module %d: SW dest last 0x%X\n",
132 module, (uint32_t) (dmacHw_REG_SW_HS_DST_LST_REQ(module)));
133 (*fpPrint) ("--------------------------------------------------\n");
134 (*fpPrint) ("Module %d: misc config 0x%X\n",
135 module, (uint32_t) (dmacHw_REG_MISC_CFG(module)));
136 (*fpPrint) ("Module %d: misc channel enable 0x%X\n",
137 module, (uint32_t) (dmacHw_REG_MISC_CH_ENABLE(module)));
138 (*fpPrint) ("Module %d: misc ID 0x%X\n",
139 module, (uint32_t) (dmacHw_REG_MISC_ID(module)));
140 (*fpPrint) ("Module %d: misc test 0x%X\n",
141 module, (uint32_t) (dmacHw_REG_MISC_TEST(module)));
144 for (chan = 0; chan < 8; chan++) {
146 ("--------------------------------------------------\n");
148 ("Module %d: Channel %d Source 0x%X\n",
150 (uint32_t) (dmacHw_REG_SAR(module, chan)));
152 ("Module %d: Channel %d Destination 0x%X\n",
154 (uint32_t) (dmacHw_REG_DAR(module, chan)));
156 ("Module %d: Channel %d LLP 0x%X\n",
158 (uint32_t) (dmacHw_REG_LLP(module, chan)));
160 ("Module %d: Channel %d Control (LO) 0x%X\n",
162 (uint32_t) (dmacHw_REG_CTL_LO(module, chan)));
164 ("Module %d: Channel %d Control (HI) 0x%X\n",
166 (uint32_t) (dmacHw_REG_CTL_HI(module, chan)));
168 ("Module %d: Channel %d Source Stats 0x%X\n",
170 (uint32_t) (dmacHw_REG_SSTAT(module, chan)));
172 ("Module %d: Channel %d Dest Stats 0x%X\n",
174 (uint32_t) (dmacHw_REG_DSTAT(module, chan)));
176 ("Module %d: Channel %d Source Stats Addr 0x%X\n",
178 (uint32_t) (dmacHw_REG_SSTATAR(module, chan)));
180 ("Module %d: Channel %d Dest Stats Addr 0x%X\n",
182 (uint32_t) (dmacHw_REG_DSTATAR(module, chan)));
184 ("Module %d: Channel %d Config (LO) 0x%X\n",
186 (uint32_t) (dmacHw_REG_CFG_LO(module, chan)));
188 ("Module %d: Channel %d Config (HI) 0x%X\n",
190 (uint32_t) (dmacHw_REG_CFG_HI(module, chan)));
195 ("--------------------------------------------------\n");
197 ("Module %d: Channel %d Source 0x%X\n",
198 module, chan, (uint32_t) (dmacHw_REG_SAR(module, chan)));
200 ("Module %d: Channel %d Destination 0x%X\n",
201 module, chan, (uint32_t) (dmacHw_REG_DAR(module, chan)));
203 ("Module %d: Channel %d LLP 0x%X\n",
204 module, chan, (uint32_t) (dmacHw_REG_LLP(module, chan)));
206 ("Module %d: Channel %d Control (LO) 0x%X\n",
208 (uint32_t) (dmacHw_REG_CTL_LO(module, chan)));
210 ("Module %d: Channel %d Control (HI) 0x%X\n",
212 (uint32_t) (dmacHw_REG_CTL_HI(module, chan)));
214 ("Module %d: Channel %d Source Stats 0x%X\n",
215 module, chan, (uint32_t) (dmacHw_REG_SSTAT(module, chan)));
217 ("Module %d: Channel %d Dest Stats 0x%X\n",
218 module, chan, (uint32_t) (dmacHw_REG_DSTAT(module, chan)));
220 ("Module %d: Channel %d Source Stats Addr 0x%X\n",
222 (uint32_t) (dmacHw_REG_SSTATAR(module, chan)));
224 ("Module %d: Channel %d Dest Stats Addr 0x%X\n",
226 (uint32_t) (dmacHw_REG_DSTATAR(module, chan)));
228 ("Module %d: Channel %d Config (LO) 0x%X\n",
230 (uint32_t) (dmacHw_REG_CFG_LO(module, chan)));
232 ("Module %d: Channel %d Config (HI) 0x%X\n",
234 (uint32_t) (dmacHw_REG_CFG_HI(module, chan)));
238 /****************************************************************************/
240 * @brief Helper function to display descriptor ring
248 /****************************************************************************/
249 static void DisplayDescRing(void *pDescriptor, /* [ IN ] Descriptor buffer */
250 int (*fpPrint) (const char *, ...) /* [ IN ] Callback to the print function */
252 dmacHw_DESC_RING_t *pRing = dmacHw_GET_DESC_RING(pDescriptor);
253 dmacHw_DESC_t *pStart;
255 if (pRing->pHead == NULL) {
259 pStart = pRing->pHead;
261 while ((dmacHw_DESC_t *) pStart->llp != pRing->pHead) {
262 if (pStart == pRing->pHead) {
263 (*fpPrint) ("Head\n");
265 if (pStart == pRing->pTail) {
266 (*fpPrint) ("Tail\n");
268 if (pStart == pRing->pProg) {
269 (*fpPrint) ("Prog\n");
271 if (pStart == pRing->pEnd) {
272 (*fpPrint) ("End\n");
274 if (pStart == pRing->pFree) {
275 (*fpPrint) ("Free\n");
277 (*fpPrint) ("0x%X:\n", (uint32_t) pStart);
278 (*fpPrint) ("sar 0x%0X\n", pStart->sar);
279 (*fpPrint) ("dar 0x%0X\n", pStart->dar);
280 (*fpPrint) ("llp 0x%0X\n", pStart->llp);
281 (*fpPrint) ("ctl.lo 0x%0X\n", pStart->ctl.lo);
282 (*fpPrint) ("ctl.hi 0x%0X\n", pStart->ctl.hi);
283 (*fpPrint) ("sstat 0x%0X\n", pStart->sstat);
284 (*fpPrint) ("dstat 0x%0X\n", pStart->dstat);
285 (*fpPrint) ("devCtl 0x%0X\n", pStart->devCtl);
287 pStart = (dmacHw_DESC_t *) pStart->llp;
289 if (pStart == pRing->pHead) {
290 (*fpPrint) ("Head\n");
292 if (pStart == pRing->pTail) {
293 (*fpPrint) ("Tail\n");
295 if (pStart == pRing->pProg) {
296 (*fpPrint) ("Prog\n");
298 if (pStart == pRing->pEnd) {
299 (*fpPrint) ("End\n");
301 if (pStart == pRing->pFree) {
302 (*fpPrint) ("Free\n");
304 (*fpPrint) ("0x%X:\n", (uint32_t) pStart);
305 (*fpPrint) ("sar 0x%0X\n", pStart->sar);
306 (*fpPrint) ("dar 0x%0X\n", pStart->dar);
307 (*fpPrint) ("llp 0x%0X\n", pStart->llp);
308 (*fpPrint) ("ctl.lo 0x%0X\n", pStart->ctl.lo);
309 (*fpPrint) ("ctl.hi 0x%0X\n", pStart->ctl.hi);
310 (*fpPrint) ("sstat 0x%0X\n", pStart->sstat);
311 (*fpPrint) ("dstat 0x%0X\n", pStart->dstat);
312 (*fpPrint) ("devCtl 0x%0X\n", pStart->devCtl);
315 /****************************************************************************/
317 * @brief Check if DMA channel is the flow controller
319 * @return 1 : If DMA is a flow controller
320 * 0 : Peripheral is the flow controller
325 /****************************************************************************/
326 static inline int DmaIsFlowController(void *pDescriptor /* [ IN ] Descriptor buffer */
329 (dmacHw_GET_DESC_RING(pDescriptor))->pTail->ctl.
330 lo & dmacHw_REG_CTL_TTFC_MASK;
333 case dmacHw_REG_CTL_TTFC_MM_DMAC:
334 case dmacHw_REG_CTL_TTFC_MP_DMAC:
335 case dmacHw_REG_CTL_TTFC_PM_DMAC:
336 case dmacHw_REG_CTL_TTFC_PP_DMAC:
343 /****************************************************************************/
345 * @brief Overwrites data length in the descriptor
347 * This function overwrites data length in the descriptor
353 * This is only used for PCM channel
355 /****************************************************************************/
356 void dmacHw_setDataLength(dmacHw_CONFIG_t *pConfig, /* [ IN ] Configuration settings */
357 void *pDescriptor, /* [ IN ] Descriptor buffer */
358 size_t dataLen /* [ IN ] Data length in bytes */
360 dmacHw_DESC_t *pProg;
361 dmacHw_DESC_t *pHead;
365 pHead = (dmacHw_GET_DESC_RING(pDescriptor))->pHead;
368 srcTrSize = dmacHw_GetTrWidthInBytes(pConfig->srcMaxTransactionWidth);
369 srcTs = dataLen / srcTrSize;
371 pProg->ctl.hi = srcTs & dmacHw_REG_CTL_BLOCK_TS_MASK;
372 pProg = (dmacHw_DESC_t *) pProg->llp;
373 } while (pProg != pHead);
376 /****************************************************************************/
378 * @brief Clears the interrupt
380 * This function clears the DMA channel specific interrupt
386 * Must be called under the context of ISR
388 /****************************************************************************/
389 void dmacHw_clearInterrupt(dmacHw_HANDLE_t handle /* [ IN ] DMA Channel handle */
391 dmacHw_CBLK_t *pCblk = dmacHw_HANDLE_TO_CBLK(handle);
393 dmacHw_TRAN_INT_CLEAR(pCblk->module, pCblk->channel);
394 dmacHw_BLOCK_INT_CLEAR(pCblk->module, pCblk->channel);
395 dmacHw_ERROR_INT_CLEAR(pCblk->module, pCblk->channel);
398 /****************************************************************************/
400 * @brief Returns the cause of channel specific DMA interrupt
402 * This function returns the cause of interrupt
404 * @return Interrupt status, each bit representing a specific type of interrupt
407 * Should be called under the context of ISR
409 /****************************************************************************/
410 dmacHw_INTERRUPT_STATUS_e dmacHw_getInterruptStatus(dmacHw_HANDLE_t handle /* [ IN ] DMA Channel handle */
412 dmacHw_CBLK_t *pCblk = dmacHw_HANDLE_TO_CBLK(handle);
413 dmacHw_INTERRUPT_STATUS_e status = dmacHw_INTERRUPT_STATUS_NONE;
415 if (dmacHw_REG_INT_STAT_TRAN(pCblk->module) &
416 ((0x00000001 << pCblk->channel))) {
417 status |= dmacHw_INTERRUPT_STATUS_TRANS;
419 if (dmacHw_REG_INT_STAT_BLOCK(pCblk->module) &
420 ((0x00000001 << pCblk->channel))) {
421 status |= dmacHw_INTERRUPT_STATUS_BLOCK;
423 if (dmacHw_REG_INT_STAT_ERROR(pCblk->module) &
424 ((0x00000001 << pCblk->channel))) {
425 status |= dmacHw_INTERRUPT_STATUS_ERROR;
431 /****************************************************************************/
433 * @brief Indentifies a DMA channel causing interrupt
435 * This functions returns a channel causing interrupt of type dmacHw_INTERRUPT_STATUS_e
437 * @return NULL : No channel causing DMA interrupt
438 * ! NULL : Handle to a channel causing DMA interrupt
440 * dmacHw_clearInterrupt() must be called with a valid handle after calling this function
442 /****************************************************************************/
443 dmacHw_HANDLE_t dmacHw_getInterruptSource(void)
447 for (i = 0; i < dmaChannelCount_0 + dmaChannelCount_1; i++) {
448 if ((dmacHw_REG_INT_STAT_TRAN(dmacHw_gCblk[i].module) &
449 ((0x00000001 << dmacHw_gCblk[i].channel)))
450 || (dmacHw_REG_INT_STAT_BLOCK(dmacHw_gCblk[i].module) &
451 ((0x00000001 << dmacHw_gCblk[i].channel)))
452 || (dmacHw_REG_INT_STAT_ERROR(dmacHw_gCblk[i].module) &
453 ((0x00000001 << dmacHw_gCblk[i].channel)))
455 return dmacHw_CBLK_TO_HANDLE(&dmacHw_gCblk[i]);
458 return dmacHw_CBLK_TO_HANDLE(NULL);
461 /****************************************************************************/
463 * @brief Estimates number of descriptor needed to perform certain DMA transfer
466 * @return On failure : -1
467 * On success : Number of descriptor count
471 /****************************************************************************/
472 int dmacHw_calculateDescriptorCount(dmacHw_CONFIG_t *pConfig, /* [ IN ] Configuration settings */
473 void *pSrcAddr, /* [ IN ] Source (Peripheral/Memory) address */
474 void *pDstAddr, /* [ IN ] Destination (Peripheral/Memory) address */
475 size_t dataLen /* [ IN ] Data length in bytes */
482 uint32_t maxBlockSize = dmacHw_MAX_BLOCKSIZE;
483 dmacHw_TRANSACTION_WIDTH_e dstTrWidth;
484 dmacHw_TRANSACTION_WIDTH_e srcTrWidth;
486 dstTrSize = dmacHw_GetTrWidthInBytes(pConfig->dstMaxTransactionWidth);
487 srcTrSize = dmacHw_GetTrWidthInBytes(pConfig->srcMaxTransactionWidth);
489 /* Skip Tx if buffer is NULL or length is unknown */
490 if ((pSrcAddr == NULL) || (pDstAddr == NULL) || (dataLen == 0)) {
491 /* Do not initiate transfer */
495 /* Ensure scatter and gather are transaction aligned */
496 if (pConfig->srcGatherWidth % srcTrSize
497 || pConfig->dstScatterWidth % dstTrSize) {
502 Background 1: DMAC can not perform DMA if source and destination addresses are
503 not properly aligned with the channel's transaction width. So, for successful
504 DMA transfer, transaction width must be set according to the alignment of the
505 source and destination address.
508 /* Adjust destination transaction width if destination address is not aligned properly */
509 dstTrWidth = pConfig->dstMaxTransactionWidth;
510 while (dmacHw_ADDRESS_MASK(dstTrSize) & (uint32_t) pDstAddr) {
511 dstTrWidth = dmacHw_GetNextTrWidth(dstTrWidth);
512 dstTrSize = dmacHw_GetTrWidthInBytes(dstTrWidth);
515 /* Adjust source transaction width if source address is not aligned properly */
516 srcTrWidth = pConfig->srcMaxTransactionWidth;
517 while (dmacHw_ADDRESS_MASK(srcTrSize) & (uint32_t) pSrcAddr) {
518 srcTrWidth = dmacHw_GetNextTrWidth(srcTrWidth);
519 srcTrSize = dmacHw_GetTrWidthInBytes(srcTrWidth);
522 /* Find the maximum transaction per descriptor */
523 if (pConfig->maxDataPerBlock
524 && ((pConfig->maxDataPerBlock / srcTrSize) <
525 dmacHw_MAX_BLOCKSIZE)) {
526 maxBlockSize = pConfig->maxDataPerBlock / srcTrSize;
529 /* Find number of source transactions needed to complete the DMA transfer */
530 srcTs = dataLen / srcTrSize;
531 /* Find the odd number of bytes that need to be transferred as single byte transaction width */
532 if (srcTs && (dstTrSize > srcTrSize)) {
533 oddSize = dataLen % dstTrSize;
534 /* Adjust source transaction count due to "oddSize" */
535 srcTs = srcTs - (oddSize / srcTrSize);
537 oddSize = dataLen % srcTrSize;
539 /* Adjust "descCount" due to "oddSize" */
544 /* Find the number of descriptor needed for total "srcTs" */
546 descCount += ((srcTs - 1) / maxBlockSize) + 1;
552 /****************************************************************************/
554 * @brief Check the existance of pending descriptor
556 * This function confirmes if there is any pending descriptor in the chain
557 * to program the channel
559 * @return 1 : Channel need to be programmed with pending descriptor
560 * 0 : No more pending descriptor to programe the channel
563 * - This function should be called from ISR in case there are pending
564 * descriptor to program the channel.
571 * if (dmacHw_descriptorPending (handle))
573 * dmacHw_initiateTransfer (handle);
578 /****************************************************************************/
579 uint32_t dmacHw_descriptorPending(dmacHw_HANDLE_t handle, /* [ IN ] DMA Channel handle */
580 void *pDescriptor /* [ IN ] Descriptor buffer */
582 dmacHw_CBLK_t *pCblk = dmacHw_HANDLE_TO_CBLK(handle);
583 dmacHw_DESC_RING_t *pRing = dmacHw_GET_DESC_RING(pDescriptor);
585 /* Make sure channel is not busy */
586 if (!CHANNEL_BUSY(pCblk->module, pCblk->channel)) {
587 /* Check if pEnd is not processed */
589 /* Something left for processing */
596 /****************************************************************************/
598 * @brief Program channel register to stop transfer
600 * Ensures the channel is not doing any transfer after calling this function
605 /****************************************************************************/
606 void dmacHw_stopTransfer(dmacHw_HANDLE_t handle /* [ IN ] DMA Channel handle */
608 dmacHw_CBLK_t *pCblk;
610 pCblk = dmacHw_HANDLE_TO_CBLK(handle);
612 /* Stop the channel */
613 dmacHw_DMA_STOP(pCblk->module, pCblk->channel);
616 /****************************************************************************/
618 * @brief Deallocates source or destination memory, allocated
620 * This function can be called to deallocate data memory that was DMAed successfully
622 * @return On failure : -1
623 * On success : Number of buffer freed
626 * This function will be called ONLY, when source OR destination address is pointing
629 /****************************************************************************/
630 int dmacHw_freeMem(dmacHw_CONFIG_t *pConfig, /* [ IN ] Configuration settings */
631 void *pDescriptor, /* [ IN ] Descriptor buffer */
632 void (*fpFree) (void *) /* [ IN ] Function pointer to free data memory */
634 dmacHw_DESC_RING_t *pRing = dmacHw_GET_DESC_RING(pDescriptor);
637 if (fpFree == NULL) {
641 while ((pRing->pFree != pRing->pTail)
642 && (pRing->pFree->ctl.lo & dmacHw_DESC_FREE)) {
643 if (pRing->pFree->devCtl == dmacHw_FREE_USER_MEMORY) {
644 /* Identify, which memory to free */
645 if (dmacHw_DST_IS_MEMORY(pConfig->transferType)) {
646 (*fpFree) ((void *)pRing->pFree->dar);
648 /* Destination was a peripheral */
649 (*fpFree) ((void *)pRing->pFree->sar);
651 /* Unmark user memory to indicate it is freed */
652 pRing->pFree->devCtl = ~dmacHw_FREE_USER_MEMORY;
654 dmacHw_NEXT_DESC(pRing, pFree);
662 /****************************************************************************/
664 * @brief Prepares descriptor ring, when source peripheral working as a flow controller
666 * This function will update the discriptor ring by allocating buffers, when source peripheral
667 * has to work as a flow controller to transfer data from:
668 * - Peripheral to memory.
670 * @return On failure : -1
671 * On success : Number of descriptor updated
675 * Channel must be configured for peripheral to memory transfer
678 /****************************************************************************/
679 int dmacHw_setVariableDataDescriptor(dmacHw_HANDLE_t handle, /* [ IN ] DMA Channel handle */
680 dmacHw_CONFIG_t *pConfig, /* [ IN ] Configuration settings */
681 void *pDescriptor, /* [ IN ] Descriptor buffer */
682 uint32_t srcAddr, /* [ IN ] Source peripheral address */
683 void *(*fpAlloc) (int len), /* [ IN ] Function pointer that provides destination memory */
684 int len, /* [ IN ] Number of bytes "fpAlloc" will allocate for destination */
685 int num /* [ IN ] Number of descriptor to set */
687 dmacHw_CBLK_t *pCblk = dmacHw_HANDLE_TO_CBLK(handle);
688 dmacHw_DESC_t *pProg = NULL;
689 dmacHw_DESC_t *pLast = NULL;
690 dmacHw_DESC_RING_t *pRing = dmacHw_GET_DESC_RING(pDescriptor);
692 uint32_t controlParam;
695 dmacHw_ASSERT(pConfig->transferType ==
696 dmacHw_TRANSFER_TYPE_PERIPHERAL_TO_MEM);
698 if (num > pRing->num) {
702 pLast = pRing->pEnd; /* Last descriptor updated */
703 pProg = pRing->pHead; /* First descriptor in the new list */
705 controlParam = pConfig->srcUpdate |
707 pConfig->srcMaxTransactionWidth |
708 pConfig->dstMaxTransactionWidth |
709 pConfig->srcMasterInterface |
710 pConfig->dstMasterInterface |
711 pConfig->srcMaxBurstWidth |
712 pConfig->dstMaxBurstWidth |
713 dmacHw_REG_CTL_TTFC_PM_PERI |
714 dmacHw_REG_CTL_LLP_DST_EN |
715 dmacHw_REG_CTL_LLP_SRC_EN | dmacHw_REG_CTL_INT_EN;
717 for (i = 0; i < num; i++) {
718 /* Allocate Rx buffer only for idle descriptor */
719 if (((pRing->pHead->ctl.hi & dmacHw_DESC_FREE) == 0) ||
720 ((dmacHw_DESC_t *) pRing->pHead->llp == pRing->pTail)
722 /* Rx descriptor is not idle */
725 /* Set source address */
726 pRing->pHead->sar = srcAddr;
728 /* Allocate memory for buffer in descriptor */
729 dstAddr = (uint32_t) (*fpAlloc) (len);
730 /* Check the destination address */
733 /* Not a single descriptor is available */
738 /* Set destination address */
739 pRing->pHead->dar = dstAddr;
741 /* Set control information */
742 pRing->pHead->ctl.lo = controlParam;
743 /* Use "devCtl" to mark the memory that need to be freed later */
744 pRing->pHead->devCtl = dmacHw_FREE_USER_MEMORY;
745 /* Descriptor is now owned by the channel */
746 pRing->pHead->ctl.hi = 0;
747 /* Remember the descriptor last updated */
748 pRing->pEnd = pRing->pHead;
749 /* Update next descriptor */
750 dmacHw_NEXT_DESC(pRing, pHead);
753 /* Mark the end of the list */
754 pRing->pEnd->ctl.lo &=
755 ~(dmacHw_REG_CTL_LLP_DST_EN | dmacHw_REG_CTL_LLP_SRC_EN);
756 /* Connect the list */
757 if (pLast != pProg) {
759 dmacHw_REG_CTL_LLP_DST_EN | dmacHw_REG_CTL_LLP_SRC_EN;
761 /* Mark the descriptors are updated */
762 pCblk->descUpdated = 1;
763 if (!pCblk->varDataStarted) {
764 /* LLP must be pointing to the first descriptor */
765 dmacHw_SET_LLP(pCblk->module, pCblk->channel,
766 (uint32_t) pProg - pRing->virt2PhyOffset);
767 /* Channel, handling variable data started */
768 pCblk->varDataStarted = 1;
774 /****************************************************************************/
776 * @brief Read data DMAed to memory
778 * This function will read data that has been DMAed to memory while transfering from:
780 * - Peripheral to memory
786 * @return 0 - No more data is available to read
787 * 1 - More data might be available to read
790 /****************************************************************************/
791 int dmacHw_readTransferredData(dmacHw_HANDLE_t handle, /* [ IN ] DMA Channel handle */
792 dmacHw_CONFIG_t *pConfig, /* [ IN ] Configuration settings */
793 void *pDescriptor, /* [ IN ] Descriptor buffer */
794 void **ppBbuf, /* [ OUT ] Data received */
795 size_t *pLlen /* [ OUT ] Length of the data received */
797 dmacHw_DESC_RING_t *pRing = dmacHw_GET_DESC_RING(pDescriptor);
801 if (pConfig->transferMode != dmacHw_TRANSFER_MODE_CONTINUOUS) {
802 if (((pRing->pTail->ctl.hi & dmacHw_DESC_FREE) == 0) ||
803 (pRing->pTail == pRing->pHead)
805 /* No receive data available */
806 *ppBbuf = (char *)NULL;
813 /* Return read buffer and length */
814 *ppBbuf = (char *)pRing->pTail->dar;
816 /* Extract length of the received data */
817 if (DmaIsFlowController(pDescriptor)) {
818 uint32_t srcTrSize = 0;
820 switch (pRing->pTail->ctl.lo & dmacHw_REG_CTL_SRC_TR_WIDTH_MASK) {
821 case dmacHw_REG_CTL_SRC_TR_WIDTH_8:
824 case dmacHw_REG_CTL_SRC_TR_WIDTH_16:
827 case dmacHw_REG_CTL_SRC_TR_WIDTH_32:
830 case dmacHw_REG_CTL_SRC_TR_WIDTH_64:
836 /* Calculate length from the block size */
838 (pRing->pTail->ctl.hi & dmacHw_REG_CTL_BLOCK_TS_MASK) *
841 /* Extract length from the source peripheral */
842 *pLlen = pRing->pTail->sstat;
845 /* Advance tail to next descriptor */
846 dmacHw_NEXT_DESC(pRing, pTail);
851 /****************************************************************************/
853 * @brief Set descriptor carrying control information
855 * This function will be used to send specific control information to the device
856 * using the DMA channel
859 * @return -1 - On failure
865 /****************************************************************************/
866 int dmacHw_setControlDescriptor(dmacHw_CONFIG_t *pConfig, /* [ IN ] Configuration settings */
867 void *pDescriptor, /* [ IN ] Descriptor buffer */
868 uint32_t ctlAddress, /* [ IN ] Address of the device control register */
869 uint32_t control /* [ IN ] Device control information */
871 dmacHw_DESC_RING_t *pRing = dmacHw_GET_DESC_RING(pDescriptor);
873 if (ctlAddress == 0) {
877 /* Check the availability of descriptors in the ring */
878 if ((pRing->pHead->ctl.hi & dmacHw_DESC_FREE) == 0) {
881 /* Set control information */
882 pRing->pHead->devCtl = control;
883 /* Set source and destination address */
884 pRing->pHead->sar = (uint32_t) &pRing->pHead->devCtl;
885 pRing->pHead->dar = ctlAddress;
886 /* Set control parameters */
887 if (pConfig->flowControler == dmacHw_FLOW_CONTROL_DMA) {
888 pRing->pHead->ctl.lo = pConfig->transferType |
889 dmacHw_SRC_ADDRESS_UPDATE_MODE_INC |
890 dmacHw_DST_ADDRESS_UPDATE_MODE_INC |
891 dmacHw_SRC_TRANSACTION_WIDTH_32 |
892 pConfig->dstMaxTransactionWidth |
893 dmacHw_SRC_BURST_WIDTH_0 |
894 dmacHw_DST_BURST_WIDTH_0 |
895 pConfig->srcMasterInterface |
896 pConfig->dstMasterInterface | dmacHw_REG_CTL_INT_EN;
898 uint32_t transferType = 0;
899 switch (pConfig->transferType) {
900 case dmacHw_TRANSFER_TYPE_PERIPHERAL_TO_MEM:
901 transferType = dmacHw_REG_CTL_TTFC_PM_PERI;
903 case dmacHw_TRANSFER_TYPE_MEM_TO_PERIPHERAL:
904 transferType = dmacHw_REG_CTL_TTFC_MP_PERI;
909 pRing->pHead->ctl.lo = transferType |
910 dmacHw_SRC_ADDRESS_UPDATE_MODE_INC |
911 dmacHw_DST_ADDRESS_UPDATE_MODE_INC |
912 dmacHw_SRC_TRANSACTION_WIDTH_32 |
913 pConfig->dstMaxTransactionWidth |
914 dmacHw_SRC_BURST_WIDTH_0 |
915 dmacHw_DST_BURST_WIDTH_0 |
916 pConfig->srcMasterInterface |
917 pConfig->dstMasterInterface |
918 pConfig->flowControler | dmacHw_REG_CTL_INT_EN;
921 /* Set block transaction size to one 32 bit transaction */
922 pRing->pHead->ctl.hi = dmacHw_REG_CTL_BLOCK_TS_MASK & 1;
924 /* Remember the descriptor to initialize the registers */
925 if (pRing->pProg == dmacHw_DESC_INIT) {
926 pRing->pProg = pRing->pHead;
928 pRing->pEnd = pRing->pHead;
930 /* Advance the descriptor */
931 dmacHw_NEXT_DESC(pRing, pHead);
933 /* Update Tail pointer if destination is a peripheral */
934 if (!dmacHw_DST_IS_MEMORY(pConfig->transferType)) {
935 pRing->pTail = pRing->pHead;
940 /****************************************************************************/
942 * @brief Sets channel specific user data
944 * This function associates user data to a specif DMA channel
947 /****************************************************************************/
948 void dmacHw_setChannelUserData(dmacHw_HANDLE_t handle, /* [ IN ] DMA Channel handle */
949 void *userData /* [ IN ] User data */
951 dmacHw_CBLK_t *pCblk = dmacHw_HANDLE_TO_CBLK(handle);
953 pCblk->userData = userData;
956 /****************************************************************************/
958 * @brief Gets channel specific user data
960 * This function returns user data specific to a DMA channel
964 /****************************************************************************/
965 void *dmacHw_getChannelUserData(dmacHw_HANDLE_t handle /* [ IN ] DMA Channel handle */
967 dmacHw_CBLK_t *pCblk = dmacHw_HANDLE_TO_CBLK(handle);
969 return pCblk->userData;
972 /****************************************************************************/
974 * @brief Resets descriptor control information
978 /****************************************************************************/
979 void dmacHw_resetDescriptorControl(void *pDescriptor /* [ IN ] Descriptor buffer */
982 dmacHw_DESC_RING_t *pRing;
983 dmacHw_DESC_t *pDesc;
985 pRing = dmacHw_GET_DESC_RING(pDescriptor);
986 pDesc = pRing->pHead;
988 for (i = 0; i < pRing->num; i++) {
989 /* Mark descriptor is ready to use */
990 pDesc->ctl.hi = dmacHw_DESC_FREE;
991 /* Look into next link list item */
994 pRing->pFree = pRing->pTail = pRing->pEnd = pRing->pHead;
995 pRing->pProg = dmacHw_DESC_INIT;
998 /****************************************************************************/
1000 * @brief Displays channel specific registers and other control parameters
1008 /****************************************************************************/
1009 void dmacHw_printDebugInfo(dmacHw_HANDLE_t handle, /* [ IN ] DMA Channel handle */
1010 void *pDescriptor, /* [ IN ] Descriptor buffer */
1011 int (*fpPrint) (const char *, ...) /* [ IN ] Print callback function */
1013 dmacHw_CBLK_t *pCblk = dmacHw_HANDLE_TO_CBLK(handle);
1015 DisplayRegisterContents(pCblk->module, pCblk->channel, fpPrint);
1016 DisplayDescRing(pDescriptor, fpPrint);