aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLeo Chen <leochen@broadcom.com>2009-08-07 15:08:00 -0400
committerRussell King <rmk+kernel@arm.linux.org.uk>2009-08-15 11:01:47 -0400
commitcf2ddacb567e85f40241f67b240fa445db7a424d (patch)
tree0ddb11ba6cb0244301ac815ac4d62bfd81867055
parent1a4a561bdd838b4455d57edf0deaf83e894d795e (diff)
ARM: 5659/1: bcmring: add csp dmac source files
add csp dmac source files Signed-off-by: Leo Chen <leochen@broadcom.com> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
-rw-r--r--arch/arm/mach-bcmring/csp/dmac/Makefile1
-rw-r--r--arch/arm/mach-bcmring/csp/dmac/dmacHw.c917
-rw-r--r--arch/arm/mach-bcmring/csp/dmac/dmacHw_extra.c1017
3 files changed, 1935 insertions, 0 deletions
diff --git a/arch/arm/mach-bcmring/csp/dmac/Makefile b/arch/arm/mach-bcmring/csp/dmac/Makefile
new file mode 100644
index 000000000000..fb1104fe56b2
--- /dev/null
+++ b/arch/arm/mach-bcmring/csp/dmac/Makefile
@@ -0,0 +1 @@
obj-y += dmacHw.o dmacHw_extra.o \ No newline at end of file
diff --git a/arch/arm/mach-bcmring/csp/dmac/dmacHw.c b/arch/arm/mach-bcmring/csp/dmac/dmacHw.c
new file mode 100644
index 000000000000..7b9bac2d79a5
--- /dev/null
+++ b/arch/arm/mach-bcmring/csp/dmac/dmacHw.c
@@ -0,0 +1,917 @@
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 */
40dmacHw_CBLK_t dmacHw_gCblk[dmacHw_MAX_CHANNEL_COUNT];
41
42uint32_t dmaChannelCount_0 = dmacHw_MAX_CHANNEL_COUNT / 2;
43uint32_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/****************************************************************************/
54static 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/****************************************************************************/
109void 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/****************************************************************************/
226void 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/****************************************************************************/
262void 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/****************************************************************************/
282dmacHw_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/****************************************************************************/
316int 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/****************************************************************************/
360uint32_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/****************************************************************************/
382int 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/****************************************************************************/
450int 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/****************************************************************************/
560dmacHw_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/****************************************************************************/
592int 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/****************************************************************************/
895uint32_t dmacHw_getDmaControllerAttribute(dmacHw_HANDLE_t handle, /* [ IN ] DMA Channel handle */
896 dmacHw_CONTROLLER_ATTRIB_e attr /* [ IN ] DMA Controler 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}
diff --git a/arch/arm/mach-bcmring/csp/dmac/dmacHw_extra.c b/arch/arm/mach-bcmring/csp/dmac/dmacHw_extra.c
new file mode 100644
index 000000000000..ff7b436d0935
--- /dev/null
+++ b/arch/arm/mach-bcmring/csp/dmac/dmacHw_extra.c
@@ -0,0 +1,1017 @@
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
36extern 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/****************************************************************************/
54void 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/****************************************************************************/
70static 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/****************************************************************************/
249static 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 controler
320* 0 : Peripheral is the flow controller
321*
322* @note
323* None
324*/
325/****************************************************************************/
326static 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/****************************************************************************/
356void 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/****************************************************************************/
389void 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/****************************************************************************/
410dmacHw_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/****************************************************************************/
443dmacHw_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/****************************************************************************/
472int 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 existance 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/****************************************************************************/
579uint32_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/****************************************************************************/
606void 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/****************************************************************************/
630int 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/****************************************************************************/
679int 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 transfering 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/****************************************************************************/
791int 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/****************************************************************************/
866int 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 specif DMA channel
945*
946*/
947/****************************************************************************/
948void 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/****************************************************************************/
965void *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/****************************************************************************/
979void 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/****************************************************************************/
1009void 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}