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