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.c
18 *
19 *  @brief   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 #include <csp/stdint.h>
29 #include <csp/string.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 #include <mach/csp/chipcHw_inline.h>
36 
37 /* ---- External Function Prototypes ------------------------------------- */
38 
39 /* Allocate DMA control blocks */
40 dmacHw_CBLK_t dmacHw_gCblk[dmacHw_MAX_CHANNEL_COUNT];
41 
42 uint32_t dmaChannelCount_0 = dmacHw_MAX_CHANNEL_COUNT / 2;
43 uint32_t dmaChannelCount_1 = dmacHw_MAX_CHANNEL_COUNT / 2;
44 
45 /****************************************************************************/
46 /**
47 *  @brief   Get maximum FIFO for a DMA channel
48 *
49 *  @return  Maximum allowable FIFO size
50 *
51 *
52 */
53 /****************************************************************************/
GetFifoSize(dmacHw_HANDLE_t handle)54 static uint32_t GetFifoSize(dmacHw_HANDLE_t handle	/*   [ IN ] DMA Channel handle */
55     ) {
56 	uint32_t val = 0;
57 	dmacHw_CBLK_t *pCblk = dmacHw_HANDLE_TO_CBLK(handle);
58 	dmacHw_MISC_t *pMiscReg =
59 	    (dmacHw_MISC_t *) dmacHw_REG_MISC_BASE(pCblk->module);
60 
61 	switch (pCblk->channel) {
62 	case 0:
63 		val = (pMiscReg->CompParm2.lo & 0x70000000) >> 28;
64 		break;
65 	case 1:
66 		val = (pMiscReg->CompParm3.hi & 0x70000000) >> 28;
67 		break;
68 	case 2:
69 		val = (pMiscReg->CompParm3.lo & 0x70000000) >> 28;
70 		break;
71 	case 3:
72 		val = (pMiscReg->CompParm4.hi & 0x70000000) >> 28;
73 		break;
74 	case 4:
75 		val = (pMiscReg->CompParm4.lo & 0x70000000) >> 28;
76 		break;
77 	case 5:
78 		val = (pMiscReg->CompParm5.hi & 0x70000000) >> 28;
79 		break;
80 	case 6:
81 		val = (pMiscReg->CompParm5.lo & 0x70000000) >> 28;
82 		break;
83 	case 7:
84 		val = (pMiscReg->CompParm6.hi & 0x70000000) >> 28;
85 		break;
86 	}
87 
88 	if (val <= 0x4) {
89 		return 8 << val;
90 	} else {
91 		dmacHw_ASSERT(0);
92 	}
93 	return 0;
94 }
95 
96 /****************************************************************************/
97 /**
98 *  @brief   Program channel register to initiate transfer
99 *
100 *  @return  void
101 *
102 *
103 *  @note
104 *     - Descriptor buffer MUST ALWAYS be flushed before calling this function
105 *     - This function should also be called from ISR to program the channel with
106 *       pending descriptors
107 */
108 /****************************************************************************/
dmacHw_initiateTransfer(dmacHw_HANDLE_t handle,dmacHw_CONFIG_t * pConfig,void * pDescriptor)109 void dmacHw_initiateTransfer(dmacHw_HANDLE_t handle,	/*   [ IN ] DMA Channel handle */
110 			     dmacHw_CONFIG_t *pConfig,	/*   [ IN ] Configuration settings */
111 			     void *pDescriptor	/*   [ IN ] Descriptor buffer */
112     ) {
113 	dmacHw_DESC_RING_t *pRing;
114 	dmacHw_DESC_t *pProg;
115 	dmacHw_CBLK_t *pCblk;
116 
117 	pCblk = dmacHw_HANDLE_TO_CBLK(handle);
118 	pRing = dmacHw_GET_DESC_RING(pDescriptor);
119 
120 	if (CHANNEL_BUSY(pCblk->module, pCblk->channel)) {
121 		/* Not safe yet to program the channel */
122 		return;
123 	}
124 
125 	if (pCblk->varDataStarted) {
126 		if (pCblk->descUpdated) {
127 			pCblk->descUpdated = 0;
128 			pProg =
129 			    (dmacHw_DESC_t *) ((uint32_t)
130 					       dmacHw_REG_LLP(pCblk->module,
131 							      pCblk->channel) +
132 					       pRing->virt2PhyOffset);
133 
134 			/* Load descriptor if not loaded */
135 			if (!(pProg->ctl.hi & dmacHw_REG_CTL_DONE)) {
136 				dmacHw_SET_SAR(pCblk->module, pCblk->channel,
137 					       pProg->sar);
138 				dmacHw_SET_DAR(pCblk->module, pCblk->channel,
139 					       pProg->dar);
140 				dmacHw_REG_CTL_LO(pCblk->module,
141 						  pCblk->channel) =
142 				    pProg->ctl.lo;
143 				dmacHw_REG_CTL_HI(pCblk->module,
144 						  pCblk->channel) =
145 				    pProg->ctl.hi;
146 			} else if (pProg == (dmacHw_DESC_t *) pRing->pEnd->llp) {
147 				/* Return as end descriptor is processed */
148 				return;
149 			} else {
150 				dmacHw_ASSERT(0);
151 			}
152 		} else {
153 			return;
154 		}
155 	} else {
156 		if (pConfig->transferMode == dmacHw_TRANSFER_MODE_PERIODIC) {
157 			/* Do not make a single chain, rather process one descriptor at a time */
158 			pProg = pRing->pHead;
159 			/* Point to the next descriptor for next iteration */
160 			dmacHw_NEXT_DESC(pRing, pHead);
161 		} else {
162 			/* Return if no more pending descriptor */
163 			if (pRing->pEnd == NULL) {
164 				return;
165 			}
166 
167 			pProg = pRing->pProg;
168 			if (pConfig->transferMode ==
169 			    dmacHw_TRANSFER_MODE_CONTINUOUS) {
170 				/* Make sure a complete ring can be formed */
171 				dmacHw_ASSERT((dmacHw_DESC_t *) pRing->pEnd->
172 					      llp == pRing->pProg);
173 				/* Make sure pProg pointing to the pHead */
174 				dmacHw_ASSERT((dmacHw_DESC_t *) pRing->pProg ==
175 					      pRing->pHead);
176 				/* Make a complete ring */
177 				do {
178 					pRing->pProg->ctl.lo |=
179 					    (dmacHw_REG_CTL_LLP_DST_EN |
180 					     dmacHw_REG_CTL_LLP_SRC_EN);
181 					pRing->pProg =
182 					    (dmacHw_DESC_t *) pRing->pProg->llp;
183 				} while (pRing->pProg != pRing->pHead);
184 			} else {
185 				/* Make a single long chain */
186 				while (pRing->pProg != pRing->pEnd) {
187 					pRing->pProg->ctl.lo |=
188 					    (dmacHw_REG_CTL_LLP_DST_EN |
189 					     dmacHw_REG_CTL_LLP_SRC_EN);
190 					pRing->pProg =
191 					    (dmacHw_DESC_t *) pRing->pProg->llp;
192 				}
193 			}
194 		}
195 
196 		/* Program the channel registers */
197 		dmacHw_SET_SAR(pCblk->module, pCblk->channel, pProg->sar);
198 		dmacHw_SET_DAR(pCblk->module, pCblk->channel, pProg->dar);
199 		dmacHw_SET_LLP(pCblk->module, pCblk->channel,
200 			       (uint32_t) pProg - pRing->virt2PhyOffset);
201 		dmacHw_REG_CTL_LO(pCblk->module, pCblk->channel) =
202 		    pProg->ctl.lo;
203 		dmacHw_REG_CTL_HI(pCblk->module, pCblk->channel) =
204 		    pProg->ctl.hi;
205 		if (pRing->pEnd) {
206 			/* Remember the descriptor to use next */
207 			pRing->pProg = (dmacHw_DESC_t *) pRing->pEnd->llp;
208 		}
209 		/* Indicate no more pending descriptor  */
210 		pRing->pEnd = (dmacHw_DESC_t *) NULL;
211 	}
212 	/* Start DMA operation */
213 	dmacHw_DMA_START(pCblk->module, pCblk->channel);
214 }
215 
216 /****************************************************************************/
217 /**
218 *  @brief   Initializes DMA
219 *
220 *  This function initializes DMA CSP driver
221 *
222 *  @note
223 *     Must be called before using any DMA channel
224 */
225 /****************************************************************************/
dmacHw_initDma(void)226 void dmacHw_initDma(void)
227 {
228 
229 	uint32_t i = 0;
230 
231 	dmaChannelCount_0 = dmacHw_GET_NUM_CHANNEL(0);
232 	dmaChannelCount_1 = dmacHw_GET_NUM_CHANNEL(1);
233 
234 	/* Enable access to the DMA block */
235 	chipcHw_busInterfaceClockEnable(chipcHw_REG_BUS_CLOCK_DMAC0);
236 	chipcHw_busInterfaceClockEnable(chipcHw_REG_BUS_CLOCK_DMAC1);
237 
238 	if ((dmaChannelCount_0 + dmaChannelCount_1) > dmacHw_MAX_CHANNEL_COUNT) {
239 		dmacHw_ASSERT(0);
240 	}
241 
242 	memset((void *)dmacHw_gCblk, 0,
243 	       sizeof(dmacHw_CBLK_t) * (dmaChannelCount_0 + dmaChannelCount_1));
244 	for (i = 0; i < dmaChannelCount_0; i++) {
245 		dmacHw_gCblk[i].module = 0;
246 		dmacHw_gCblk[i].channel = i;
247 	}
248 	for (i = 0; i < dmaChannelCount_1; i++) {
249 		dmacHw_gCblk[i + dmaChannelCount_0].module = 1;
250 		dmacHw_gCblk[i + dmaChannelCount_0].channel = i;
251 	}
252 }
253 
254 /****************************************************************************/
255 /**
256 *  @brief   Exit function for  DMA
257 *
258 *  This function isolates DMA from the system
259 *
260 */
261 /****************************************************************************/
dmacHw_exitDma(void)262 void dmacHw_exitDma(void)
263 {
264 	/* Disable access to the DMA block */
265 	chipcHw_busInterfaceClockDisable(chipcHw_REG_BUS_CLOCK_DMAC0);
266 	chipcHw_busInterfaceClockDisable(chipcHw_REG_BUS_CLOCK_DMAC1);
267 }
268 
269 /****************************************************************************/
270 /**
271 *  @brief   Gets a handle to a DMA channel
272 *
273 *  This function returns a handle, representing a control block of a particular DMA channel
274 *
275 *  @return  -1       - On Failure
276 *            handle  - On Success, representing a channel control block
277 *
278 *  @note
279 *     None  Channel ID must be created using "dmacHw_MAKE_CHANNEL_ID" macro
280 */
281 /****************************************************************************/
dmacHw_getChannelHandle(dmacHw_ID_t channelId)282 dmacHw_HANDLE_t dmacHw_getChannelHandle(dmacHw_ID_t channelId	/* [ IN ] DMA Channel Id */
283     ) {
284 	int idx;
285 
286 	switch ((channelId >> 8)) {
287 	case 0:
288 		dmacHw_ASSERT((channelId & 0xff) < dmaChannelCount_0);
289 		idx = (channelId & 0xff);
290 		break;
291 	case 1:
292 		dmacHw_ASSERT((channelId & 0xff) < dmaChannelCount_1);
293 		idx = dmaChannelCount_0 + (channelId & 0xff);
294 		break;
295 	default:
296 		dmacHw_ASSERT(0);
297 		return (dmacHw_HANDLE_t) -1;
298 	}
299 
300 	return dmacHw_CBLK_TO_HANDLE(&dmacHw_gCblk[idx]);
301 }
302 
303 /****************************************************************************/
304 /**
305 *  @brief   Initializes a DMA channel for use
306 *
307 *  This function initializes and resets a DMA channel for use
308 *
309 *  @return  -1     - On Failure
310 *            0     - On Success
311 *
312 *  @note
313 *     None
314 */
315 /****************************************************************************/
dmacHw_initChannel(dmacHw_HANDLE_t handle)316 int dmacHw_initChannel(dmacHw_HANDLE_t handle	/*   [ IN ] DMA Channel handle */
317     ) {
318 	dmacHw_CBLK_t *pCblk = dmacHw_HANDLE_TO_CBLK(handle);
319 	int module = pCblk->module;
320 	int channel = pCblk->channel;
321 
322 	/* Reinitialize the control block */
323 	memset((void *)pCblk, 0, sizeof(dmacHw_CBLK_t));
324 	pCblk->module = module;
325 	pCblk->channel = channel;
326 
327 	/* Enable DMA controller */
328 	dmacHw_DMA_ENABLE(pCblk->module);
329 	/* Reset DMA channel */
330 	dmacHw_RESET_CONTROL_LO(pCblk->module, pCblk->channel);
331 	dmacHw_RESET_CONTROL_HI(pCblk->module, pCblk->channel);
332 	dmacHw_RESET_CONFIG_LO(pCblk->module, pCblk->channel);
333 	dmacHw_RESET_CONFIG_HI(pCblk->module, pCblk->channel);
334 
335 	/* Clear all raw interrupt status */
336 	dmacHw_TRAN_INT_CLEAR(pCblk->module, pCblk->channel);
337 	dmacHw_BLOCK_INT_CLEAR(pCblk->module, pCblk->channel);
338 	dmacHw_ERROR_INT_CLEAR(pCblk->module, pCblk->channel);
339 
340 	/* Mask event specific interrupts */
341 	dmacHw_TRAN_INT_DISABLE(pCblk->module, pCblk->channel);
342 	dmacHw_BLOCK_INT_DISABLE(pCblk->module, pCblk->channel);
343 	dmacHw_STRAN_INT_DISABLE(pCblk->module, pCblk->channel);
344 	dmacHw_DTRAN_INT_DISABLE(pCblk->module, pCblk->channel);
345 	dmacHw_ERROR_INT_DISABLE(pCblk->module, pCblk->channel);
346 
347 	return 0;
348 }
349 
350 /****************************************************************************/
351 /**
352 *  @brief  Finds amount of memory required to form a descriptor ring
353 *
354 *
355 *  @return   Number of bytes required to form a descriptor ring
356 *
357 *
358 */
359 /****************************************************************************/
dmacHw_descriptorLen(uint32_t descCnt)360 uint32_t dmacHw_descriptorLen(uint32_t descCnt	/* [ IN ] Number of descriptor in the ring */
361     ) {
362 	/* Need extra 4 byte to ensure 32 bit alignment  */
363 	return (descCnt * sizeof(dmacHw_DESC_t)) + sizeof(dmacHw_DESC_RING_t) +
364 		sizeof(uint32_t);
365 }
366 
367 /****************************************************************************/
368 /**
369 *  @brief   Initializes descriptor ring
370 *
371 *  This function will initializes the descriptor ring of a DMA channel
372 *
373 *
374 *  @return   -1 - On failure
375 *             0 - On success
376 *  @note
377 *     - "len" parameter should be obtained from "dmacHw_descriptorLen"
378 *     - Descriptor buffer MUST be 32 bit aligned and uncached as it is
379 *       accessed by ARM and DMA
380 */
381 /****************************************************************************/
dmacHw_initDescriptor(void * pDescriptorVirt,uint32_t descriptorPhyAddr,uint32_t len,uint32_t num)382 int dmacHw_initDescriptor(void *pDescriptorVirt,	/*  [ IN ] Virtual address of uncahced buffer allocated to form descriptor ring */
383 			  uint32_t descriptorPhyAddr,	/*  [ IN ] Physical address of pDescriptorVirt (descriptor buffer) */
384 			  uint32_t len,	/*  [ IN ] Size of the pBuf */
385 			  uint32_t num	/*  [ IN ] Number of descriptor in the ring */
386     ) {
387 	uint32_t i;
388 	dmacHw_DESC_RING_t *pRing;
389 	dmacHw_DESC_t *pDesc;
390 
391 	/* Check the alignment of the descriptor */
392 	if ((uint32_t) pDescriptorVirt & 0x00000003) {
393 		dmacHw_ASSERT(0);
394 		return -1;
395 	}
396 
397 	/* Check if enough space has been allocated for descriptor ring */
398 	if (len < dmacHw_descriptorLen(num)) {
399 		return -1;
400 	}
401 
402 	pRing = dmacHw_GET_DESC_RING(pDescriptorVirt);
403 	pRing->pHead =
404 	    (dmacHw_DESC_t *) ((uint32_t) pRing + sizeof(dmacHw_DESC_RING_t));
405 	pRing->pFree = pRing->pTail = pRing->pEnd = pRing->pHead;
406 	pRing->pProg = dmacHw_DESC_INIT;
407 	/* Initialize link item chain, starting from the head */
408 	pDesc = pRing->pHead;
409 	/* Find the offset between virtual to physical address */
410 	pRing->virt2PhyOffset = (uint32_t) pDescriptorVirt - descriptorPhyAddr;
411 
412 	/* Form the descriptor ring */
413 	for (i = 0; i < num - 1; i++) {
414 		/* Clear link list item */
415 		memset((void *)pDesc, 0, sizeof(dmacHw_DESC_t));
416 		/* Point to the next item in the physical address */
417 		pDesc->llpPhy = (uint32_t) (pDesc + 1) - pRing->virt2PhyOffset;
418 		/* Point to the next item in the virtual address */
419 		pDesc->llp = (uint32_t) (pDesc + 1);
420 		/* Mark descriptor is ready to use */
421 		pDesc->ctl.hi = dmacHw_DESC_FREE;
422 		/* Look into next link list item */
423 		pDesc++;
424 	}
425 
426 	/* Clear last link list item */
427 	memset((void *)pDesc, 0, sizeof(dmacHw_DESC_t));
428 	/* Last item pointing to the first item in the
429 	   physical address to complete the ring */
430 	pDesc->llpPhy = (uint32_t) pRing->pHead - pRing->virt2PhyOffset;
431 	/* Last item pointing to the first item in the
432 	   virtual address to complete the ring
433 	 */
434 	pDesc->llp = (uint32_t) pRing->pHead;
435 	/* Mark descriptor is ready to use */
436 	pDesc->ctl.hi = dmacHw_DESC_FREE;
437 	/* Set the number of descriptors in the ring */
438 	pRing->num = num;
439 	return 0;
440 }
441 
442 /****************************************************************************/
443 /**
444 *  @brief   Configure DMA channel
445 *
446 *  @return  0  : On success
447 *           -1 : On failure
448 */
449 /****************************************************************************/
dmacHw_configChannel(dmacHw_HANDLE_t handle,dmacHw_CONFIG_t * pConfig)450 int dmacHw_configChannel(dmacHw_HANDLE_t handle,	/*   [ IN ] DMA Channel handle */
451 			 dmacHw_CONFIG_t *pConfig	/*   [ IN ] Configuration settings */
452     ) {
453 	dmacHw_CBLK_t *pCblk = dmacHw_HANDLE_TO_CBLK(handle);
454 	uint32_t cfgHigh = 0;
455 	int srcTrSize;
456 	int dstTrSize;
457 
458 	pCblk->varDataStarted = 0;
459 	pCblk->userData = NULL;
460 
461 	/* Configure
462 	   - Burst transaction when enough data in available in FIFO
463 	   - AHB Access protection 1
464 	   - Source and destination peripheral ports
465 	 */
466 	cfgHigh =
467 	    dmacHw_REG_CFG_HI_FIFO_ENOUGH | dmacHw_REG_CFG_HI_AHB_HPROT_1 |
468 	    dmacHw_SRC_PERI_INTF(pConfig->
469 				 srcPeripheralPort) |
470 	    dmacHw_DST_PERI_INTF(pConfig->dstPeripheralPort);
471 	/* Set priority */
472 	dmacHw_SET_CHANNEL_PRIORITY(pCblk->module, pCblk->channel,
473 				    pConfig->channelPriority);
474 
475 	if (pConfig->dstStatusRegisterAddress != 0) {
476 		/* Destination status update enable */
477 		cfgHigh |= dmacHw_REG_CFG_HI_UPDATE_DST_STAT;
478 		/* Configure status registers */
479 		dmacHw_SET_DSTATAR(pCblk->module, pCblk->channel,
480 				   pConfig->dstStatusRegisterAddress);
481 	}
482 
483 	if (pConfig->srcStatusRegisterAddress != 0) {
484 		/* Source status update enable */
485 		cfgHigh |= dmacHw_REG_CFG_HI_UPDATE_SRC_STAT;
486 		/* Source status update enable */
487 		dmacHw_SET_SSTATAR(pCblk->module, pCblk->channel,
488 				   pConfig->srcStatusRegisterAddress);
489 	}
490 	/* Configure the config high register */
491 	dmacHw_GET_CONFIG_HI(pCblk->module, pCblk->channel) = cfgHigh;
492 
493 	/* Clear all raw interrupt status */
494 	dmacHw_TRAN_INT_CLEAR(pCblk->module, pCblk->channel);
495 	dmacHw_BLOCK_INT_CLEAR(pCblk->module, pCblk->channel);
496 	dmacHw_ERROR_INT_CLEAR(pCblk->module, pCblk->channel);
497 
498 	/* Configure block interrupt */
499 	if (pConfig->blockTransferInterrupt == dmacHw_INTERRUPT_ENABLE) {
500 		dmacHw_BLOCK_INT_ENABLE(pCblk->module, pCblk->channel);
501 	} else {
502 		dmacHw_BLOCK_INT_DISABLE(pCblk->module, pCblk->channel);
503 	}
504 	/* Configure complete transfer interrupt */
505 	if (pConfig->completeTransferInterrupt == dmacHw_INTERRUPT_ENABLE) {
506 		dmacHw_TRAN_INT_ENABLE(pCblk->module, pCblk->channel);
507 	} else {
508 		dmacHw_TRAN_INT_DISABLE(pCblk->module, pCblk->channel);
509 	}
510 	/* Configure error interrupt */
511 	if (pConfig->errorInterrupt == dmacHw_INTERRUPT_ENABLE) {
512 		dmacHw_ERROR_INT_ENABLE(pCblk->module, pCblk->channel);
513 	} else {
514 		dmacHw_ERROR_INT_DISABLE(pCblk->module, pCblk->channel);
515 	}
516 	/* Configure gather register */
517 	if (pConfig->srcGatherWidth) {
518 		srcTrSize =
519 		    dmacHw_GetTrWidthInBytes(pConfig->srcMaxTransactionWidth);
520 		if (!
521 		    ((pConfig->srcGatherWidth % srcTrSize)
522 		     && (pConfig->srcGatherJump % srcTrSize))) {
523 			dmacHw_REG_SGR_LO(pCblk->module, pCblk->channel) =
524 			    ((pConfig->srcGatherWidth /
525 			      srcTrSize) << 20) | (pConfig->srcGatherJump /
526 						   srcTrSize);
527 		} else {
528 			return -1;
529 		}
530 	}
531 	/* Configure scatter register */
532 	if (pConfig->dstScatterWidth) {
533 		dstTrSize =
534 		    dmacHw_GetTrWidthInBytes(pConfig->dstMaxTransactionWidth);
535 		if (!
536 		    ((pConfig->dstScatterWidth % dstTrSize)
537 		     && (pConfig->dstScatterJump % dstTrSize))) {
538 			dmacHw_REG_DSR_LO(pCblk->module, pCblk->channel) =
539 			    ((pConfig->dstScatterWidth /
540 			      dstTrSize) << 20) | (pConfig->dstScatterJump /
541 						   dstTrSize);
542 		} else {
543 			return -1;
544 		}
545 	}
546 	return 0;
547 }
548 
549 /****************************************************************************/
550 /**
551 *  @brief   Indicates whether DMA transfer is in progress or completed
552 *
553 *  @return   DMA transfer status
554 *          dmacHw_TRANSFER_STATUS_BUSY:         DMA Transfer ongoing
555 *          dmacHw_TRANSFER_STATUS_DONE:         DMA Transfer completed
556 *          dmacHw_TRANSFER_STATUS_ERROR:        DMA Transfer error
557 *
558 */
559 /****************************************************************************/
dmacHw_transferCompleted(dmacHw_HANDLE_t handle)560 dmacHw_TRANSFER_STATUS_e dmacHw_transferCompleted(dmacHw_HANDLE_t handle	/*   [ IN ] DMA Channel handle */
561     ) {
562 	dmacHw_CBLK_t *pCblk = dmacHw_HANDLE_TO_CBLK(handle);
563 
564 	if (CHANNEL_BUSY(pCblk->module, pCblk->channel)) {
565 		return dmacHw_TRANSFER_STATUS_BUSY;
566 	} else if (dmacHw_REG_INT_RAW_ERROR(pCblk->module) &
567 		   (0x00000001 << pCblk->channel)) {
568 		return dmacHw_TRANSFER_STATUS_ERROR;
569 	}
570 
571 	return dmacHw_TRANSFER_STATUS_DONE;
572 }
573 
574 /****************************************************************************/
575 /**
576 *  @brief   Set descriptors for known data length
577 *
578 *  When DMA has to work as a flow controller, this function prepares the
579 *  descriptor chain to transfer data
580 *
581 *  from:
582 *          - Memory to memory
583 *          - Peripheral to memory
584 *          - Memory to Peripheral
585 *          - Peripheral to Peripheral
586 *
587 *  @return   -1 - On failure
588 *             0 - On success
589 *
590 */
591 /****************************************************************************/
dmacHw_setDataDescriptor(dmacHw_CONFIG_t * pConfig,void * pDescriptor,void * pSrcAddr,void * pDstAddr,size_t dataLen)592 int dmacHw_setDataDescriptor(dmacHw_CONFIG_t *pConfig,	/*   [ IN ] Configuration settings */
593 			     void *pDescriptor,	/*   [ IN ] Descriptor buffer */
594 			     void *pSrcAddr,	/*   [ IN ] Source (Peripheral/Memory) address */
595 			     void *pDstAddr,	/*   [ IN ] Destination (Peripheral/Memory) address */
596 			     size_t dataLen	/*   [ IN ] Data length in bytes */
597     ) {
598 	dmacHw_TRANSACTION_WIDTH_e dstTrWidth;
599 	dmacHw_TRANSACTION_WIDTH_e srcTrWidth;
600 	dmacHw_DESC_RING_t *pRing = dmacHw_GET_DESC_RING(pDescriptor);
601 	dmacHw_DESC_t *pStart;
602 	dmacHw_DESC_t *pProg;
603 	int srcTs = 0;
604 	int blkTs = 0;
605 	int oddSize = 0;
606 	int descCount = 0;
607 	int count = 0;
608 	int dstTrSize = 0;
609 	int srcTrSize = 0;
610 	uint32_t maxBlockSize = dmacHw_MAX_BLOCKSIZE;
611 
612 	dstTrSize = dmacHw_GetTrWidthInBytes(pConfig->dstMaxTransactionWidth);
613 	srcTrSize = dmacHw_GetTrWidthInBytes(pConfig->srcMaxTransactionWidth);
614 
615 	/* Skip Tx if buffer is NULL  or length is unknown */
616 	if ((pSrcAddr == NULL) || (pDstAddr == NULL) || (dataLen == 0)) {
617 		/* Do not initiate transfer */
618 		return -1;
619 	}
620 
621 	/* Ensure scatter and gather are transaction aligned */
622 	if ((pConfig->srcGatherWidth % srcTrSize)
623 	    || (pConfig->dstScatterWidth % dstTrSize)) {
624 		return -2;
625 	}
626 
627 	/*
628 	   Background 1: DMAC can not perform DMA if source and destination addresses are
629 	   not properly aligned with the channel's transaction width. So, for successful
630 	   DMA transfer, transaction width must be set according to the alignment of the
631 	   source and destination address.
632 	 */
633 
634 	/* Adjust destination transaction width if destination address is not aligned properly */
635 	dstTrWidth = pConfig->dstMaxTransactionWidth;
636 	while (dmacHw_ADDRESS_MASK(dstTrSize) & (uint32_t) pDstAddr) {
637 		dstTrWidth = dmacHw_GetNextTrWidth(dstTrWidth);
638 		dstTrSize = dmacHw_GetTrWidthInBytes(dstTrWidth);
639 	}
640 
641 	/* Adjust source transaction width if source address is not aligned properly */
642 	srcTrWidth = pConfig->srcMaxTransactionWidth;
643 	while (dmacHw_ADDRESS_MASK(srcTrSize) & (uint32_t) pSrcAddr) {
644 		srcTrWidth = dmacHw_GetNextTrWidth(srcTrWidth);
645 		srcTrSize = dmacHw_GetTrWidthInBytes(srcTrWidth);
646 	}
647 
648 	/* Find the maximum transaction per descriptor */
649 	if (pConfig->maxDataPerBlock
650 	    && ((pConfig->maxDataPerBlock / srcTrSize) <
651 		dmacHw_MAX_BLOCKSIZE)) {
652 		maxBlockSize = pConfig->maxDataPerBlock / srcTrSize;
653 	}
654 
655 	/* Find number of source transactions needed to complete the DMA transfer */
656 	srcTs = dataLen / srcTrSize;
657 	/* Find the odd number of bytes that need to be transferred as single byte transaction width */
658 	if (srcTs && (dstTrSize > srcTrSize)) {
659 		oddSize = dataLen % dstTrSize;
660 		/* Adjust source transaction count due to "oddSize" */
661 		srcTs = srcTs - (oddSize / srcTrSize);
662 	} else {
663 		oddSize = dataLen % srcTrSize;
664 	}
665 	/* Adjust "descCount" due to "oddSize" */
666 	if (oddSize) {
667 		descCount++;
668 	}
669 	/* Find the number of descriptor needed for total "srcTs" */
670 	if (srcTs) {
671 		descCount += ((srcTs - 1) / maxBlockSize) + 1;
672 	}
673 
674 	/* Check the availability of "descCount" discriptors in the ring */
675 	pProg = pRing->pHead;
676 	for (count = 0; (descCount <= pRing->num) && (count < descCount);
677 	     count++) {
678 		if ((pProg->ctl.hi & dmacHw_DESC_FREE) == 0) {
679 			/* Sufficient descriptors are not available */
680 			return -3;
681 		}
682 		pProg = (dmacHw_DESC_t *) pProg->llp;
683 	}
684 
685 	/* Remember the link list item to program the channel registers */
686 	pStart = pProg = pRing->pHead;
687 	/* Make a link list with "descCount(=count)" number of descriptors */
688 	while (count) {
689 		/* Reset channel control information */
690 		pProg->ctl.lo = 0;
691 		/* Enable source gather if configured */
692 		if (pConfig->srcGatherWidth) {
693 			pProg->ctl.lo |= dmacHw_REG_CTL_SG_ENABLE;
694 		}
695 		/* Enable destination scatter if configured */
696 		if (pConfig->dstScatterWidth) {
697 			pProg->ctl.lo |= dmacHw_REG_CTL_DS_ENABLE;
698 		}
699 		/* Set source and destination address */
700 		pProg->sar = (uint32_t) pSrcAddr;
701 		pProg->dar = (uint32_t) pDstAddr;
702 		/* Use "devCtl" to mark that user memory need to be freed later if needed */
703 		if (pProg == pRing->pHead) {
704 			pProg->devCtl = dmacHw_FREE_USER_MEMORY;
705 		} else {
706 			pProg->devCtl = 0;
707 		}
708 
709 		blkTs = srcTs;
710 
711 		/* Special treatmeant for last descriptor */
712 		if (count == 1) {
713 			/* Mark the last descriptor */
714 			pProg->ctl.lo &=
715 			    ~(dmacHw_REG_CTL_LLP_DST_EN |
716 			      dmacHw_REG_CTL_LLP_SRC_EN);
717 			/* Treatment for odd data bytes */
718 			if (oddSize) {
719 				/* Adjust for single byte transaction width */
720 				switch (pConfig->transferType) {
721 				case dmacHw_TRANSFER_TYPE_PERIPHERAL_TO_MEM:
722 					dstTrWidth =
723 					    dmacHw_DST_TRANSACTION_WIDTH_8;
724 					blkTs =
725 					    (oddSize / srcTrSize) +
726 					    ((oddSize % srcTrSize) ? 1 : 0);
727 					break;
728 				case dmacHw_TRANSFER_TYPE_MEM_TO_PERIPHERAL:
729 					srcTrWidth =
730 					    dmacHw_SRC_TRANSACTION_WIDTH_8;
731 					blkTs = oddSize;
732 					break;
733 				case dmacHw_TRANSFER_TYPE_MEM_TO_MEM:
734 					srcTrWidth =
735 					    dmacHw_SRC_TRANSACTION_WIDTH_8;
736 					dstTrWidth =
737 					    dmacHw_DST_TRANSACTION_WIDTH_8;
738 					blkTs = oddSize;
739 					break;
740 				case dmacHw_TRANSFER_TYPE_PERIPHERAL_TO_PERIPHERAL:
741 					/* Do not adjust the transaction width  */
742 					break;
743 				}
744 			} else {
745 				srcTs -= blkTs;
746 			}
747 		} else {
748 			if (srcTs / maxBlockSize) {
749 				blkTs = maxBlockSize;
750 			}
751 			/* Remaining source transactions for next iteration */
752 			srcTs -= blkTs;
753 		}
754 		/* Must have a valid source transactions */
755 		dmacHw_ASSERT(blkTs > 0);
756 		/* Set control information */
757 		if (pConfig->flowControler == dmacHw_FLOW_CONTROL_DMA) {
758 			pProg->ctl.lo |= pConfig->transferType |
759 			    pConfig->srcUpdate |
760 			    pConfig->dstUpdate |
761 			    srcTrWidth |
762 			    dstTrWidth |
763 			    pConfig->srcMaxBurstWidth |
764 			    pConfig->dstMaxBurstWidth |
765 			    pConfig->srcMasterInterface |
766 			    pConfig->dstMasterInterface | dmacHw_REG_CTL_INT_EN;
767 		} else {
768 			uint32_t transferType = 0;
769 			switch (pConfig->transferType) {
770 			case dmacHw_TRANSFER_TYPE_PERIPHERAL_TO_MEM:
771 				transferType = dmacHw_REG_CTL_TTFC_PM_PERI;
772 				break;
773 			case dmacHw_TRANSFER_TYPE_MEM_TO_PERIPHERAL:
774 				transferType = dmacHw_REG_CTL_TTFC_MP_PERI;
775 				break;
776 			default:
777 				dmacHw_ASSERT(0);
778 			}
779 			pProg->ctl.lo |= transferType |
780 			    pConfig->srcUpdate |
781 			    pConfig->dstUpdate |
782 			    srcTrWidth |
783 			    dstTrWidth |
784 			    pConfig->srcMaxBurstWidth |
785 			    pConfig->dstMaxBurstWidth |
786 			    pConfig->srcMasterInterface |
787 			    pConfig->dstMasterInterface | dmacHw_REG_CTL_INT_EN;
788 		}
789 
790 		/* Set block transaction size */
791 		pProg->ctl.hi = blkTs & dmacHw_REG_CTL_BLOCK_TS_MASK;
792 		/* Look for next descriptor */
793 		if (count > 1) {
794 			/* Point to the next descriptor */
795 			pProg = (dmacHw_DESC_t *) pProg->llp;
796 
797 			/* Update source and destination address for next iteration */
798 			switch (pConfig->transferType) {
799 			case dmacHw_TRANSFER_TYPE_PERIPHERAL_TO_MEM:
800 				if (pConfig->dstScatterWidth) {
801 					pDstAddr =
802 					    (char *)pDstAddr +
803 					    blkTs * srcTrSize +
804 					    (((blkTs * srcTrSize) /
805 					      pConfig->dstScatterWidth) *
806 					     pConfig->dstScatterJump);
807 				} else {
808 					pDstAddr =
809 					    (char *)pDstAddr +
810 					    blkTs * srcTrSize;
811 				}
812 				break;
813 			case dmacHw_TRANSFER_TYPE_MEM_TO_PERIPHERAL:
814 				if (pConfig->srcGatherWidth) {
815 					pSrcAddr =
816 					    (char *)pDstAddr +
817 					    blkTs * srcTrSize +
818 					    (((blkTs * srcTrSize) /
819 					      pConfig->srcGatherWidth) *
820 					     pConfig->srcGatherJump);
821 				} else {
822 					pSrcAddr =
823 					    (char *)pSrcAddr +
824 					    blkTs * srcTrSize;
825 				}
826 				break;
827 			case dmacHw_TRANSFER_TYPE_MEM_TO_MEM:
828 				if (pConfig->dstScatterWidth) {
829 					pDstAddr =
830 					    (char *)pDstAddr +
831 					    blkTs * srcTrSize +
832 					    (((blkTs * srcTrSize) /
833 					      pConfig->dstScatterWidth) *
834 					     pConfig->dstScatterJump);
835 				} else {
836 					pDstAddr =
837 					    (char *)pDstAddr +
838 					    blkTs * srcTrSize;
839 				}
840 
841 				if (pConfig->srcGatherWidth) {
842 					pSrcAddr =
843 					    (char *)pDstAddr +
844 					    blkTs * srcTrSize +
845 					    (((blkTs * srcTrSize) /
846 					      pConfig->srcGatherWidth) *
847 					     pConfig->srcGatherJump);
848 				} else {
849 					pSrcAddr =
850 					    (char *)pSrcAddr +
851 					    blkTs * srcTrSize;
852 				}
853 				break;
854 			case dmacHw_TRANSFER_TYPE_PERIPHERAL_TO_PERIPHERAL:
855 				/* Do not adjust the address */
856 				break;
857 			default:
858 				dmacHw_ASSERT(0);
859 			}
860 		} else {
861 			/* At the end of transfer "srcTs" must be zero */
862 			dmacHw_ASSERT(srcTs == 0);
863 		}
864 		count--;
865 	}
866 
867 	/* Remember the descriptor to initialize the registers */
868 	if (pRing->pProg == dmacHw_DESC_INIT) {
869 		pRing->pProg = pStart;
870 	}
871 	/* Indicate that the descriptor is updated */
872 	pRing->pEnd = pProg;
873 	/* Head pointing to the next descriptor */
874 	pRing->pHead = (dmacHw_DESC_t *) pProg->llp;
875 	/* Update Tail pointer if destination is a peripheral,
876 	   because no one is going to read from the pTail
877 	 */
878 	if (!dmacHw_DST_IS_MEMORY(pConfig->transferType)) {
879 		pRing->pTail = pRing->pHead;
880 	}
881 	return 0;
882 }
883 
884 /****************************************************************************/
885 /**
886 *  @brief   Provides DMA controller attributes
887 *
888 *
889 *  @return  DMA controller attributes
890 *
891 *  @note
892 *     None
893 */
894 /****************************************************************************/
dmacHw_getDmaControllerAttribute(dmacHw_HANDLE_t handle,dmacHw_CONTROLLER_ATTRIB_e attr)895 uint32_t dmacHw_getDmaControllerAttribute(dmacHw_HANDLE_t handle,	/*  [ IN ]  DMA Channel handle */
896 					  dmacHw_CONTROLLER_ATTRIB_e attr	/*  [ IN ]  DMA Controller attribute of type  dmacHw_CONTROLLER_ATTRIB_e */
897     ) {
898 	dmacHw_CBLK_t *pCblk = dmacHw_HANDLE_TO_CBLK(handle);
899 
900 	switch (attr) {
901 	case dmacHw_CONTROLLER_ATTRIB_CHANNEL_NUM:
902 		return dmacHw_GET_NUM_CHANNEL(pCblk->module);
903 	case dmacHw_CONTROLLER_ATTRIB_CHANNEL_MAX_BLOCK_SIZE:
904 		return (1 <<
905 			 (dmacHw_GET_MAX_BLOCK_SIZE
906 			  (pCblk->module, pCblk->module) + 2)) - 8;
907 	case dmacHw_CONTROLLER_ATTRIB_MASTER_INTF_NUM:
908 		return dmacHw_GET_NUM_INTERFACE(pCblk->module);
909 	case dmacHw_CONTROLLER_ATTRIB_CHANNEL_BUS_WIDTH:
910 		return 32 << dmacHw_GET_CHANNEL_DATA_WIDTH(pCblk->module,
911 							   pCblk->channel);
912 	case dmacHw_CONTROLLER_ATTRIB_CHANNEL_FIFO_SIZE:
913 		return GetFifoSize(handle);
914 	}
915 	dmacHw_ASSERT(0);
916 	return 0;
917 }
918