1 /*****************************************************************************
2 * Copyright 2003 - 2008 Broadcom Corporation. All rights reserved.
3 *
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").
8 *
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
12 * consent.
13 *****************************************************************************/
14
15 /****************************************************************************/
16 /**
17 * @file dmacHw_extra.c
18 *
19 * @brief Extra Low level DMA controller driver routines
20 *
21 * @note
22 *
23 * These routines provide basic DMA functionality only.
24 */
25 /****************************************************************************/
26
27 /* ---- Include Files ---------------------------------------------------- */
28
29 #include <csp/stdint.h>
30 #include <stddef.h>
31
32 #include <csp/dmacHw.h>
33 #include <mach/csp/dmacHw_reg.h>
34 #include <mach/csp/dmacHw_priv.h>
35
36 extern dmacHw_CBLK_t dmacHw_gCblk[dmacHw_MAX_CHANNEL_COUNT]; /* Declared in dmacHw.c */
37
38 /* ---- External Function Prototypes ------------------------------------- */
39
40 /* ---- Internal Use Function Prototypes --------------------------------- */
41 /****************************************************************************/
42 /**
43 * @brief Overwrites data length in the descriptor
44 *
45 * This function overwrites data length in the descriptor
46 *
47 *
48 * @return void
49 *
50 * @note
51 * This is only used for PCM channel
52 */
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 */
57 );
58
59 /****************************************************************************/
60 /**
61 * @brief Helper function to display DMA registers
62 *
63 * @return void
64 *
65 *
66 * @note
67 * None
68 */
69 /****************************************************************************/
DisplayRegisterContents(int module,int channel,int (* fpPrint)(const char *,...))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 */
73 ) {
74 int chan;
75
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)));
142
143 if (channel == -1) {
144 for (chan = 0; chan < 8; chan++) {
145 (*fpPrint)
146 ("--------------------------------------------------\n");
147 (*fpPrint)
148 ("Module %d: Channel %d Source 0x%X\n",
149 module, chan,
150 (uint32_t) (dmacHw_REG_SAR(module, chan)));
151 (*fpPrint)
152 ("Module %d: Channel %d Destination 0x%X\n",
153 module, chan,
154 (uint32_t) (dmacHw_REG_DAR(module, chan)));
155 (*fpPrint)
156 ("Module %d: Channel %d LLP 0x%X\n",
157 module, chan,
158 (uint32_t) (dmacHw_REG_LLP(module, chan)));
159 (*fpPrint)
160 ("Module %d: Channel %d Control (LO) 0x%X\n",
161 module, chan,
162 (uint32_t) (dmacHw_REG_CTL_LO(module, chan)));
163 (*fpPrint)
164 ("Module %d: Channel %d Control (HI) 0x%X\n",
165 module, chan,
166 (uint32_t) (dmacHw_REG_CTL_HI(module, chan)));
167 (*fpPrint)
168 ("Module %d: Channel %d Source Stats 0x%X\n",
169 module, chan,
170 (uint32_t) (dmacHw_REG_SSTAT(module, chan)));
171 (*fpPrint)
172 ("Module %d: Channel %d Dest Stats 0x%X\n",
173 module, chan,
174 (uint32_t) (dmacHw_REG_DSTAT(module, chan)));
175 (*fpPrint)
176 ("Module %d: Channel %d Source Stats Addr 0x%X\n",
177 module, chan,
178 (uint32_t) (dmacHw_REG_SSTATAR(module, chan)));
179 (*fpPrint)
180 ("Module %d: Channel %d Dest Stats Addr 0x%X\n",
181 module, chan,
182 (uint32_t) (dmacHw_REG_DSTATAR(module, chan)));
183 (*fpPrint)
184 ("Module %d: Channel %d Config (LO) 0x%X\n",
185 module, chan,
186 (uint32_t) (dmacHw_REG_CFG_LO(module, chan)));
187 (*fpPrint)
188 ("Module %d: Channel %d Config (HI) 0x%X\n",
189 module, chan,
190 (uint32_t) (dmacHw_REG_CFG_HI(module, chan)));
191 }
192 } else {
193 chan = channel;
194 (*fpPrint)
195 ("--------------------------------------------------\n");
196 (*fpPrint)
197 ("Module %d: Channel %d Source 0x%X\n",
198 module, chan, (uint32_t) (dmacHw_REG_SAR(module, chan)));
199 (*fpPrint)
200 ("Module %d: Channel %d Destination 0x%X\n",
201 module, chan, (uint32_t) (dmacHw_REG_DAR(module, chan)));
202 (*fpPrint)
203 ("Module %d: Channel %d LLP 0x%X\n",
204 module, chan, (uint32_t) (dmacHw_REG_LLP(module, chan)));
205 (*fpPrint)
206 ("Module %d: Channel %d Control (LO) 0x%X\n",
207 module, chan,
208 (uint32_t) (dmacHw_REG_CTL_LO(module, chan)));
209 (*fpPrint)
210 ("Module %d: Channel %d Control (HI) 0x%X\n",
211 module, chan,
212 (uint32_t) (dmacHw_REG_CTL_HI(module, chan)));
213 (*fpPrint)
214 ("Module %d: Channel %d Source Stats 0x%X\n",
215 module, chan, (uint32_t) (dmacHw_REG_SSTAT(module, chan)));
216 (*fpPrint)
217 ("Module %d: Channel %d Dest Stats 0x%X\n",
218 module, chan, (uint32_t) (dmacHw_REG_DSTAT(module, chan)));
219 (*fpPrint)
220 ("Module %d: Channel %d Source Stats Addr 0x%X\n",
221 module, chan,
222 (uint32_t) (dmacHw_REG_SSTATAR(module, chan)));
223 (*fpPrint)
224 ("Module %d: Channel %d Dest Stats Addr 0x%X\n",
225 module, chan,
226 (uint32_t) (dmacHw_REG_DSTATAR(module, chan)));
227 (*fpPrint)
228 ("Module %d: Channel %d Config (LO) 0x%X\n",
229 module, chan,
230 (uint32_t) (dmacHw_REG_CFG_LO(module, chan)));
231 (*fpPrint)
232 ("Module %d: Channel %d Config (HI) 0x%X\n",
233 module, chan,
234 (uint32_t) (dmacHw_REG_CFG_HI(module, chan)));
235 }
236 }
237
238 /****************************************************************************/
239 /**
240 * @brief Helper function to display descriptor ring
241 *
242 * @return void
243 *
244 *
245 * @note
246 * None
247 */
248 /****************************************************************************/
DisplayDescRing(void * pDescriptor,int (* fpPrint)(const char *,...))249 static void DisplayDescRing(void *pDescriptor, /* [ IN ] Descriptor buffer */
250 int (*fpPrint) (const char *, ...) /* [ IN ] Callback to the print function */
251 ) {
252 dmacHw_DESC_RING_t *pRing = dmacHw_GET_DESC_RING(pDescriptor);
253 dmacHw_DESC_t *pStart;
254
255 if (pRing->pHead == NULL) {
256 return;
257 }
258
259 pStart = pRing->pHead;
260
261 while ((dmacHw_DESC_t *) pStart->llp != pRing->pHead) {
262 if (pStart == pRing->pHead) {
263 (*fpPrint) ("Head\n");
264 }
265 if (pStart == pRing->pTail) {
266 (*fpPrint) ("Tail\n");
267 }
268 if (pStart == pRing->pProg) {
269 (*fpPrint) ("Prog\n");
270 }
271 if (pStart == pRing->pEnd) {
272 (*fpPrint) ("End\n");
273 }
274 if (pStart == pRing->pFree) {
275 (*fpPrint) ("Free\n");
276 }
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);
286
287 pStart = (dmacHw_DESC_t *) pStart->llp;
288 }
289 if (pStart == pRing->pHead) {
290 (*fpPrint) ("Head\n");
291 }
292 if (pStart == pRing->pTail) {
293 (*fpPrint) ("Tail\n");
294 }
295 if (pStart == pRing->pProg) {
296 (*fpPrint) ("Prog\n");
297 }
298 if (pStart == pRing->pEnd) {
299 (*fpPrint) ("End\n");
300 }
301 if (pStart == pRing->pFree) {
302 (*fpPrint) ("Free\n");
303 }
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);
313 }
314
315 /****************************************************************************/
316 /**
317 * @brief Check if DMA channel is the flow controller
318 *
319 * @return 1 : If DMA is a flow controller
320 * 0 : Peripheral is the flow controller
321 *
322 * @note
323 * None
324 */
325 /****************************************************************************/
DmaIsFlowController(void * pDescriptor)326 static inline int DmaIsFlowController(void *pDescriptor /* [ IN ] Descriptor buffer */
327 ) {
328 uint32_t ttfc =
329 (dmacHw_GET_DESC_RING(pDescriptor))->pTail->ctl.
330 lo & dmacHw_REG_CTL_TTFC_MASK;
331
332 switch (ttfc) {
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:
337 return 1;
338 }
339
340 return 0;
341 }
342
343 /****************************************************************************/
344 /**
345 * @brief Overwrites data length in the descriptor
346 *
347 * This function overwrites data length in the descriptor
348 *
349 *
350 * @return void
351 *
352 * @note
353 * This is only used for PCM channel
354 */
355 /****************************************************************************/
dmacHw_setDataLength(dmacHw_CONFIG_t * pConfig,void * pDescriptor,size_t dataLen)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 */
359 ) {
360 dmacHw_DESC_t *pProg;
361 dmacHw_DESC_t *pHead;
362 int srcTs = 0;
363 int srcTrSize = 0;
364
365 pHead = (dmacHw_GET_DESC_RING(pDescriptor))->pHead;
366 pProg = pHead;
367
368 srcTrSize = dmacHw_GetTrWidthInBytes(pConfig->srcMaxTransactionWidth);
369 srcTs = dataLen / srcTrSize;
370 do {
371 pProg->ctl.hi = srcTs & dmacHw_REG_CTL_BLOCK_TS_MASK;
372 pProg = (dmacHw_DESC_t *) pProg->llp;
373 } while (pProg != pHead);
374 }
375
376 /****************************************************************************/
377 /**
378 * @brief Clears the interrupt
379 *
380 * This function clears the DMA channel specific interrupt
381 *
382 *
383 * @return void
384 *
385 * @note
386 * Must be called under the context of ISR
387 */
388 /****************************************************************************/
dmacHw_clearInterrupt(dmacHw_HANDLE_t handle)389 void dmacHw_clearInterrupt(dmacHw_HANDLE_t handle /* [ IN ] DMA Channel handle */
390 ) {
391 dmacHw_CBLK_t *pCblk = dmacHw_HANDLE_TO_CBLK(handle);
392
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);
396 }
397
398 /****************************************************************************/
399 /**
400 * @brief Returns the cause of channel specific DMA interrupt
401 *
402 * This function returns the cause of interrupt
403 *
404 * @return Interrupt status, each bit representing a specific type of interrupt
405 *
406 * @note
407 * Should be called under the context of ISR
408 */
409 /****************************************************************************/
dmacHw_getInterruptStatus(dmacHw_HANDLE_t handle)410 dmacHw_INTERRUPT_STATUS_e dmacHw_getInterruptStatus(dmacHw_HANDLE_t handle /* [ IN ] DMA Channel handle */
411 ) {
412 dmacHw_CBLK_t *pCblk = dmacHw_HANDLE_TO_CBLK(handle);
413 dmacHw_INTERRUPT_STATUS_e status = dmacHw_INTERRUPT_STATUS_NONE;
414
415 if (dmacHw_REG_INT_STAT_TRAN(pCblk->module) &
416 ((0x00000001 << pCblk->channel))) {
417 status |= dmacHw_INTERRUPT_STATUS_TRANS;
418 }
419 if (dmacHw_REG_INT_STAT_BLOCK(pCblk->module) &
420 ((0x00000001 << pCblk->channel))) {
421 status |= dmacHw_INTERRUPT_STATUS_BLOCK;
422 }
423 if (dmacHw_REG_INT_STAT_ERROR(pCblk->module) &
424 ((0x00000001 << pCblk->channel))) {
425 status |= dmacHw_INTERRUPT_STATUS_ERROR;
426 }
427
428 return status;
429 }
430
431 /****************************************************************************/
432 /**
433 * @brief Indentifies a DMA channel causing interrupt
434 *
435 * This functions returns a channel causing interrupt of type dmacHw_INTERRUPT_STATUS_e
436 *
437 * @return NULL : No channel causing DMA interrupt
438 * ! NULL : Handle to a channel causing DMA interrupt
439 * @note
440 * dmacHw_clearInterrupt() must be called with a valid handle after calling this function
441 */
442 /****************************************************************************/
dmacHw_getInterruptSource(void)443 dmacHw_HANDLE_t dmacHw_getInterruptSource(void)
444 {
445 uint32_t i;
446
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)))
454 ) {
455 return dmacHw_CBLK_TO_HANDLE(&dmacHw_gCblk[i]);
456 }
457 }
458 return dmacHw_CBLK_TO_HANDLE(NULL);
459 }
460
461 /****************************************************************************/
462 /**
463 * @brief Estimates number of descriptor needed to perform certain DMA transfer
464 *
465 *
466 * @return On failure : -1
467 * On success : Number of descriptor count
468 *
469 *
470 */
471 /****************************************************************************/
dmacHw_calculateDescriptorCount(dmacHw_CONFIG_t * pConfig,void * pSrcAddr,void * pDstAddr,size_t dataLen)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 */
476 ) {
477 int srcTs = 0;
478 int oddSize = 0;
479 int descCount = 0;
480 int dstTrSize = 0;
481 int srcTrSize = 0;
482 uint32_t maxBlockSize = dmacHw_MAX_BLOCKSIZE;
483 dmacHw_TRANSACTION_WIDTH_e dstTrWidth;
484 dmacHw_TRANSACTION_WIDTH_e srcTrWidth;
485
486 dstTrSize = dmacHw_GetTrWidthInBytes(pConfig->dstMaxTransactionWidth);
487 srcTrSize = dmacHw_GetTrWidthInBytes(pConfig->srcMaxTransactionWidth);
488
489 /* Skip Tx if buffer is NULL or length is unknown */
490 if ((pSrcAddr == NULL) || (pDstAddr == NULL) || (dataLen == 0)) {
491 /* Do not initiate transfer */
492 return -1;
493 }
494
495 /* Ensure scatter and gather are transaction aligned */
496 if (pConfig->srcGatherWidth % srcTrSize
497 || pConfig->dstScatterWidth % dstTrSize) {
498 return -1;
499 }
500
501 /*
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.
506 */
507
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);
513 }
514
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);
520 }
521
522 /* Find the maximum transaction per descriptor */
523 if (pConfig->maxDataPerBlock
524 && ((pConfig->maxDataPerBlock / srcTrSize) <
525 dmacHw_MAX_BLOCKSIZE)) {
526 maxBlockSize = pConfig->maxDataPerBlock / srcTrSize;
527 }
528
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);
536 } else {
537 oddSize = dataLen % srcTrSize;
538 }
539 /* Adjust "descCount" due to "oddSize" */
540 if (oddSize) {
541 descCount++;
542 }
543
544 /* Find the number of descriptor needed for total "srcTs" */
545 if (srcTs) {
546 descCount += ((srcTs - 1) / maxBlockSize) + 1;
547 }
548
549 return descCount;
550 }
551
552 /****************************************************************************/
553 /**
554 * @brief Check the existence of pending descriptor
555 *
556 * This function confirmes if there is any pending descriptor in the chain
557 * to program the channel
558 *
559 * @return 1 : Channel need to be programmed with pending descriptor
560 * 0 : No more pending descriptor to programe the channel
561 *
562 * @note
563 * - This function should be called from ISR in case there are pending
564 * descriptor to program the channel.
565 *
566 * Example:
567 *
568 * dmac_isr ()
569 * {
570 * ...
571 * if (dmacHw_descriptorPending (handle))
572 * {
573 * dmacHw_initiateTransfer (handle);
574 * }
575 * }
576 *
577 */
578 /****************************************************************************/
dmacHw_descriptorPending(dmacHw_HANDLE_t handle,void * pDescriptor)579 uint32_t dmacHw_descriptorPending(dmacHw_HANDLE_t handle, /* [ IN ] DMA Channel handle */
580 void *pDescriptor /* [ IN ] Descriptor buffer */
581 ) {
582 dmacHw_CBLK_t *pCblk = dmacHw_HANDLE_TO_CBLK(handle);
583 dmacHw_DESC_RING_t *pRing = dmacHw_GET_DESC_RING(pDescriptor);
584
585 /* Make sure channel is not busy */
586 if (!CHANNEL_BUSY(pCblk->module, pCblk->channel)) {
587 /* Check if pEnd is not processed */
588 if (pRing->pEnd) {
589 /* Something left for processing */
590 return 1;
591 }
592 }
593 return 0;
594 }
595
596 /****************************************************************************/
597 /**
598 * @brief Program channel register to stop transfer
599 *
600 * Ensures the channel is not doing any transfer after calling this function
601 *
602 * @return void
603 *
604 */
605 /****************************************************************************/
dmacHw_stopTransfer(dmacHw_HANDLE_t handle)606 void dmacHw_stopTransfer(dmacHw_HANDLE_t handle /* [ IN ] DMA Channel handle */
607 ) {
608 dmacHw_CBLK_t *pCblk;
609
610 pCblk = dmacHw_HANDLE_TO_CBLK(handle);
611
612 /* Stop the channel */
613 dmacHw_DMA_STOP(pCblk->module, pCblk->channel);
614 }
615
616 /****************************************************************************/
617 /**
618 * @brief Deallocates source or destination memory, allocated
619 *
620 * This function can be called to deallocate data memory that was DMAed successfully
621 *
622 * @return On failure : -1
623 * On success : Number of buffer freed
624 *
625 * @note
626 * This function will be called ONLY, when source OR destination address is pointing
627 * to dynamic memory
628 */
629 /****************************************************************************/
dmacHw_freeMem(dmacHw_CONFIG_t * pConfig,void * pDescriptor,void (* fpFree)(void *))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 */
633 ) {
634 dmacHw_DESC_RING_t *pRing = dmacHw_GET_DESC_RING(pDescriptor);
635 uint32_t count = 0;
636
637 if (fpFree == NULL) {
638 return -1;
639 }
640
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);
647 } else {
648 /* Destination was a peripheral */
649 (*fpFree) ((void *)pRing->pFree->sar);
650 }
651 /* Unmark user memory to indicate it is freed */
652 pRing->pFree->devCtl = ~dmacHw_FREE_USER_MEMORY;
653 }
654 dmacHw_NEXT_DESC(pRing, pFree);
655
656 count++;
657 }
658
659 return count;
660 }
661
662 /****************************************************************************/
663 /**
664 * @brief Prepares descriptor ring, when source peripheral working as a flow controller
665 *
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.
669 *
670 * @return On failure : -1
671 * On success : Number of descriptor updated
672 *
673 *
674 * @note
675 * Channel must be configured for peripheral to memory transfer
676 *
677 */
678 /****************************************************************************/
dmacHw_setVariableDataDescriptor(dmacHw_HANDLE_t handle,dmacHw_CONFIG_t * pConfig,void * pDescriptor,uint32_t srcAddr,void * (* fpAlloc)(int len),int len,int num)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 */
686 ) {
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);
691 uint32_t dstAddr;
692 uint32_t controlParam;
693 int i;
694
695 dmacHw_ASSERT(pConfig->transferType ==
696 dmacHw_TRANSFER_TYPE_PERIPHERAL_TO_MEM);
697
698 if (num > pRing->num) {
699 return -1;
700 }
701
702 pLast = pRing->pEnd; /* Last descriptor updated */
703 pProg = pRing->pHead; /* First descriptor in the new list */
704
705 controlParam = pConfig->srcUpdate |
706 pConfig->dstUpdate |
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;
716
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)
721 ) {
722 /* Rx descriptor is not idle */
723 break;
724 }
725 /* Set source address */
726 pRing->pHead->sar = srcAddr;
727 if (fpAlloc) {
728 /* Allocate memory for buffer in descriptor */
729 dstAddr = (uint32_t) (*fpAlloc) (len);
730 /* Check the destination address */
731 if (dstAddr == 0) {
732 if (i == 0) {
733 /* Not a single descriptor is available */
734 return -1;
735 }
736 break;
737 }
738 /* Set destination address */
739 pRing->pHead->dar = dstAddr;
740 }
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);
751 }
752
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) {
758 pLast->ctl.lo |=
759 dmacHw_REG_CTL_LLP_DST_EN | dmacHw_REG_CTL_LLP_SRC_EN;
760 }
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;
769 }
770
771 return i;
772 }
773
774 /****************************************************************************/
775 /**
776 * @brief Read data DMAed to memory
777 *
778 * This function will read data that has been DMAed to memory while transferring from:
779 * - Memory to memory
780 * - Peripheral to memory
781 *
782 * @param handle -
783 * @param ppBbuf -
784 * @param pLen -
785 *
786 * @return 0 - No more data is available to read
787 * 1 - More data might be available to read
788 *
789 */
790 /****************************************************************************/
dmacHw_readTransferredData(dmacHw_HANDLE_t handle,dmacHw_CONFIG_t * pConfig,void * pDescriptor,void ** ppBbuf,size_t * pLlen)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 */
796 ) {
797 dmacHw_DESC_RING_t *pRing = dmacHw_GET_DESC_RING(pDescriptor);
798
799 (void)handle;
800
801 if (pConfig->transferMode != dmacHw_TRANSFER_MODE_CONTINUOUS) {
802 if (((pRing->pTail->ctl.hi & dmacHw_DESC_FREE) == 0) ||
803 (pRing->pTail == pRing->pHead)
804 ) {
805 /* No receive data available */
806 *ppBbuf = (char *)NULL;
807 *pLlen = 0;
808
809 return 0;
810 }
811 }
812
813 /* Return read buffer and length */
814 *ppBbuf = (char *)pRing->pTail->dar;
815
816 /* Extract length of the received data */
817 if (DmaIsFlowController(pDescriptor)) {
818 uint32_t srcTrSize = 0;
819
820 switch (pRing->pTail->ctl.lo & dmacHw_REG_CTL_SRC_TR_WIDTH_MASK) {
821 case dmacHw_REG_CTL_SRC_TR_WIDTH_8:
822 srcTrSize = 1;
823 break;
824 case dmacHw_REG_CTL_SRC_TR_WIDTH_16:
825 srcTrSize = 2;
826 break;
827 case dmacHw_REG_CTL_SRC_TR_WIDTH_32:
828 srcTrSize = 4;
829 break;
830 case dmacHw_REG_CTL_SRC_TR_WIDTH_64:
831 srcTrSize = 8;
832 break;
833 default:
834 dmacHw_ASSERT(0);
835 }
836 /* Calculate length from the block size */
837 *pLlen =
838 (pRing->pTail->ctl.hi & dmacHw_REG_CTL_BLOCK_TS_MASK) *
839 srcTrSize;
840 } else {
841 /* Extract length from the source peripheral */
842 *pLlen = pRing->pTail->sstat;
843 }
844
845 /* Advance tail to next descriptor */
846 dmacHw_NEXT_DESC(pRing, pTail);
847
848 return 1;
849 }
850
851 /****************************************************************************/
852 /**
853 * @brief Set descriptor carrying control information
854 *
855 * This function will be used to send specific control information to the device
856 * using the DMA channel
857 *
858 *
859 * @return -1 - On failure
860 * 0 - On success
861 *
862 * @note
863 * None
864 */
865 /****************************************************************************/
dmacHw_setControlDescriptor(dmacHw_CONFIG_t * pConfig,void * pDescriptor,uint32_t ctlAddress,uint32_t control)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 */
870 ) {
871 dmacHw_DESC_RING_t *pRing = dmacHw_GET_DESC_RING(pDescriptor);
872
873 if (ctlAddress == 0) {
874 return -1;
875 }
876
877 /* Check the availability of descriptors in the ring */
878 if ((pRing->pHead->ctl.hi & dmacHw_DESC_FREE) == 0) {
879 return -1;
880 }
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;
897 } else {
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;
902 break;
903 case dmacHw_TRANSFER_TYPE_MEM_TO_PERIPHERAL:
904 transferType = dmacHw_REG_CTL_TTFC_MP_PERI;
905 break;
906 default:
907 dmacHw_ASSERT(0);
908 }
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;
919 }
920
921 /* Set block transaction size to one 32 bit transaction */
922 pRing->pHead->ctl.hi = dmacHw_REG_CTL_BLOCK_TS_MASK & 1;
923
924 /* Remember the descriptor to initialize the registers */
925 if (pRing->pProg == dmacHw_DESC_INIT) {
926 pRing->pProg = pRing->pHead;
927 }
928 pRing->pEnd = pRing->pHead;
929
930 /* Advance the descriptor */
931 dmacHw_NEXT_DESC(pRing, pHead);
932
933 /* Update Tail pointer if destination is a peripheral */
934 if (!dmacHw_DST_IS_MEMORY(pConfig->transferType)) {
935 pRing->pTail = pRing->pHead;
936 }
937 return 0;
938 }
939
940 /****************************************************************************/
941 /**
942 * @brief Sets channel specific user data
943 *
944 * This function associates user data to a specific DMA channel
945 *
946 */
947 /****************************************************************************/
dmacHw_setChannelUserData(dmacHw_HANDLE_t handle,void * userData)948 void dmacHw_setChannelUserData(dmacHw_HANDLE_t handle, /* [ IN ] DMA Channel handle */
949 void *userData /* [ IN ] User data */
950 ) {
951 dmacHw_CBLK_t *pCblk = dmacHw_HANDLE_TO_CBLK(handle);
952
953 pCblk->userData = userData;
954 }
955
956 /****************************************************************************/
957 /**
958 * @brief Gets channel specific user data
959 *
960 * This function returns user data specific to a DMA channel
961 *
962 * @return user data
963 */
964 /****************************************************************************/
dmacHw_getChannelUserData(dmacHw_HANDLE_t handle)965 void *dmacHw_getChannelUserData(dmacHw_HANDLE_t handle /* [ IN ] DMA Channel handle */
966 ) {
967 dmacHw_CBLK_t *pCblk = dmacHw_HANDLE_TO_CBLK(handle);
968
969 return pCblk->userData;
970 }
971
972 /****************************************************************************/
973 /**
974 * @brief Resets descriptor control information
975 *
976 * @return void
977 */
978 /****************************************************************************/
dmacHw_resetDescriptorControl(void * pDescriptor)979 void dmacHw_resetDescriptorControl(void *pDescriptor /* [ IN ] Descriptor buffer */
980 ) {
981 int i;
982 dmacHw_DESC_RING_t *pRing;
983 dmacHw_DESC_t *pDesc;
984
985 pRing = dmacHw_GET_DESC_RING(pDescriptor);
986 pDesc = pRing->pHead;
987
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 */
992 pDesc++;
993 }
994 pRing->pFree = pRing->pTail = pRing->pEnd = pRing->pHead;
995 pRing->pProg = dmacHw_DESC_INIT;
996 }
997
998 /****************************************************************************/
999 /**
1000 * @brief Displays channel specific registers and other control parameters
1001 *
1002 * @return void
1003 *
1004 *
1005 * @note
1006 * None
1007 */
1008 /****************************************************************************/
dmacHw_printDebugInfo(dmacHw_HANDLE_t handle,void * pDescriptor,int (* fpPrint)(const char *,...))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 */
1012 ) {
1013 dmacHw_CBLK_t *pCblk = dmacHw_HANDLE_TO_CBLK(handle);
1014
1015 DisplayRegisterContents(pCblk->module, pCblk->channel, fpPrint);
1016 DisplayDescRing(pDescriptor, fpPrint);
1017 }
1018