1 /*****************************************************************************
2 * Copyright 2003 - 2008 Broadcom Corporation. All rights reserved.
4 * Unless you and Broadcom execute a separate written software license
5 * agreement governing use of this software, this software is licensed to you
6 * under the terms of the GNU General Public License version 2, available at
7 * http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
9 * Notwithstanding the above, under no circumstances may you combine this
10 * software in any way with any other Broadcom software provided under a
11 * license other than the GPL, without Broadcom's express prior written
13 *****************************************************************************/
15 /****************************************************************************/
19 * @brief Low level DMA controller driver routines
23 * These routines provide basic DMA functionality only.
25 /****************************************************************************/
27 /* ---- Include Files ---------------------------------------------------- */
28 #include <csp/stdint.h>
29 #include <csp/string.h>
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>
37 /* ---- External Function Prototypes ------------------------------------- */
39 /* Allocate DMA control blocks */
40 dmacHw_CBLK_t dmacHw_gCblk
[dmacHw_MAX_CHANNEL_COUNT
];
42 uint32_t dmaChannelCount_0
= dmacHw_MAX_CHANNEL_COUNT
/ 2;
43 uint32_t dmaChannelCount_1
= dmacHw_MAX_CHANNEL_COUNT
/ 2;
45 /****************************************************************************/
47 * @brief Get maximum FIFO for a DMA channel
49 * @return Maximum allowable FIFO size
53 /****************************************************************************/
54 static uint32_t GetFifoSize(dmacHw_HANDLE_t handle
/* [ IN ] DMA Channel handle */
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
);
61 switch (pCblk
->channel
) {
63 val
= (pMiscReg
->CompParm2
.lo
& 0x70000000) >> 28;
66 val
= (pMiscReg
->CompParm3
.hi
& 0x70000000) >> 28;
69 val
= (pMiscReg
->CompParm3
.lo
& 0x70000000) >> 28;
72 val
= (pMiscReg
->CompParm4
.hi
& 0x70000000) >> 28;
75 val
= (pMiscReg
->CompParm4
.lo
& 0x70000000) >> 28;
78 val
= (pMiscReg
->CompParm5
.hi
& 0x70000000) >> 28;
81 val
= (pMiscReg
->CompParm5
.lo
& 0x70000000) >> 28;
84 val
= (pMiscReg
->CompParm6
.hi
& 0x70000000) >> 28;
96 /****************************************************************************/
98 * @brief Program channel register to initiate transfer
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
108 /****************************************************************************/
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 */
113 dmacHw_DESC_RING_t
*pRing
;
114 dmacHw_DESC_t
*pProg
;
115 dmacHw_CBLK_t
*pCblk
;
117 pCblk
= dmacHw_HANDLE_TO_CBLK(handle
);
118 pRing
= dmacHw_GET_DESC_RING(pDescriptor
);
120 if (CHANNEL_BUSY(pCblk
->module
, pCblk
->channel
)) {
121 /* Not safe yet to program the channel */
125 if (pCblk
->varDataStarted
) {
126 if (pCblk
->descUpdated
) {
127 pCblk
->descUpdated
= 0;
129 (dmacHw_DESC_t
*) ((uint32_t)
130 dmacHw_REG_LLP(pCblk
->module
,
132 pRing
->virt2PhyOffset
);
134 /* Load descriptor if not loaded */
135 if (!(pProg
->ctl
.hi
& dmacHw_REG_CTL_DONE
)) {
136 dmacHw_SET_SAR(pCblk
->module
, pCblk
->channel
,
138 dmacHw_SET_DAR(pCblk
->module
, pCblk
->channel
,
140 dmacHw_REG_CTL_LO(pCblk
->module
,
143 dmacHw_REG_CTL_HI(pCblk
->module
,
146 } else if (pProg
== (dmacHw_DESC_t
*) pRing
->pEnd
->llp
) {
147 /* Return as end descriptor is processed */
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
);
162 /* Return if no more pending descriptor */
163 if (pRing
->pEnd
== NULL
) {
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
==
176 /* Make a complete ring */
178 pRing
->pProg
->ctl
.lo
|=
179 (dmacHw_REG_CTL_LLP_DST_EN
|
180 dmacHw_REG_CTL_LLP_SRC_EN
);
182 (dmacHw_DESC_t
*) pRing
->pProg
->llp
;
183 } while (pRing
->pProg
!= pRing
->pHead
);
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
);
191 (dmacHw_DESC_t
*) pRing
->pProg
->llp
;
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
) =
203 dmacHw_REG_CTL_HI(pCblk
->module
, pCblk
->channel
) =
206 /* Remember the descriptor to use next */
207 pRing
->pProg
= (dmacHw_DESC_t
*) pRing
->pEnd
->llp
;
209 /* Indicate no more pending descriptor */
210 pRing
->pEnd
= (dmacHw_DESC_t
*) NULL
;
212 /* Start DMA operation */
213 dmacHw_DMA_START(pCblk
->module
, pCblk
->channel
);
216 /****************************************************************************/
218 * @brief Initializes DMA
220 * This function initializes DMA CSP driver
223 * Must be called before using any DMA channel
225 /****************************************************************************/
226 void dmacHw_initDma(void)
231 dmaChannelCount_0
= dmacHw_GET_NUM_CHANNEL(0);
232 dmaChannelCount_1
= dmacHw_GET_NUM_CHANNEL(1);
234 /* Enable access to the DMA block */
235 chipcHw_busInterfaceClockEnable(chipcHw_REG_BUS_CLOCK_DMAC0
);
236 chipcHw_busInterfaceClockEnable(chipcHw_REG_BUS_CLOCK_DMAC1
);
238 if ((dmaChannelCount_0
+ dmaChannelCount_1
) > dmacHw_MAX_CHANNEL_COUNT
) {
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
;
248 for (i
= 0; i
< dmaChannelCount_1
; i
++) {
249 dmacHw_gCblk
[i
+ dmaChannelCount_0
].module
= 1;
250 dmacHw_gCblk
[i
+ dmaChannelCount_0
].channel
= i
;
254 /****************************************************************************/
256 * @brief Exit function for DMA
258 * This function isolates DMA from the system
261 /****************************************************************************/
262 void dmacHw_exitDma(void)
264 /* Disable access to the DMA block */
265 chipcHw_busInterfaceClockDisable(chipcHw_REG_BUS_CLOCK_DMAC0
);
266 chipcHw_busInterfaceClockDisable(chipcHw_REG_BUS_CLOCK_DMAC1
);
269 /****************************************************************************/
271 * @brief Gets a handle to a DMA channel
273 * This function returns a handle, representing a control block of a particular DMA channel
275 * @return -1 - On Failure
276 * handle - On Success, representing a channel control block
279 * None Channel ID must be created using "dmacHw_MAKE_CHANNEL_ID" macro
281 /****************************************************************************/
282 dmacHw_HANDLE_t
dmacHw_getChannelHandle(dmacHw_ID_t channelId
/* [ IN ] DMA Channel Id */
286 switch ((channelId
>> 8)) {
288 dmacHw_ASSERT((channelId
& 0xff) < dmaChannelCount_0
);
289 idx
= (channelId
& 0xff);
292 dmacHw_ASSERT((channelId
& 0xff) < dmaChannelCount_1
);
293 idx
= dmaChannelCount_0
+ (channelId
& 0xff);
297 return (dmacHw_HANDLE_t
) -1;
300 return dmacHw_CBLK_TO_HANDLE(&dmacHw_gCblk
[idx
]);
303 /****************************************************************************/
305 * @brief Initializes a DMA channel for use
307 * This function initializes and resets a DMA channel for use
309 * @return -1 - On Failure
315 /****************************************************************************/
316 int dmacHw_initChannel(dmacHw_HANDLE_t handle
/* [ IN ] DMA Channel handle */
318 dmacHw_CBLK_t
*pCblk
= dmacHw_HANDLE_TO_CBLK(handle
);
319 int module
= pCblk
->module
;
320 int channel
= pCblk
->channel
;
322 /* Reinitialize the control block */
323 memset((void *)pCblk
, 0, sizeof(dmacHw_CBLK_t
));
324 pCblk
->module
= module
;
325 pCblk
->channel
= channel
;
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
);
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
);
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
);
350 /****************************************************************************/
352 * @brief Finds amount of memory required to form a descriptor ring
355 * @return Number of bytes required to form a descriptor ring
359 /****************************************************************************/
360 uint32_t dmacHw_descriptorLen(uint32_t descCnt
/* [ IN ] Number of descriptor in the ring */
362 /* Need extra 4 byte to ensure 32 bit alignment */
363 return (descCnt
* sizeof(dmacHw_DESC_t
)) + sizeof(dmacHw_DESC_RING_t
) +
367 /****************************************************************************/
369 * @brief Initializes descriptor ring
371 * This function will initializes the descriptor ring of a DMA channel
374 * @return -1 - On failure
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
381 /****************************************************************************/
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 */
388 dmacHw_DESC_RING_t
*pRing
;
389 dmacHw_DESC_t
*pDesc
;
391 /* Check the alignment of the descriptor */
392 if ((uint32_t) pDescriptorVirt
& 0x00000003) {
397 /* Check if enough space has been allocated for descriptor ring */
398 if (len
< dmacHw_descriptorLen(num
)) {
402 pRing
= dmacHw_GET_DESC_RING(pDescriptorVirt
);
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
;
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 */
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
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 */
442 /****************************************************************************/
444 * @brief Configure DMA channel
446 * @return 0 : On success
449 /****************************************************************************/
450 int dmacHw_configChannel(dmacHw_HANDLE_t handle
, /* [ IN ] DMA Channel handle */
451 dmacHw_CONFIG_t
*pConfig
/* [ IN ] Configuration settings */
453 dmacHw_CBLK_t
*pCblk
= dmacHw_HANDLE_TO_CBLK(handle
);
454 uint32_t cfgHigh
= 0;
458 pCblk
->varDataStarted
= 0;
459 pCblk
->userData
= NULL
;
462 - Burst transaction when enough data in available in FIFO
463 - AHB Access protection 1
464 - Source and destination peripheral ports
467 dmacHw_REG_CFG_HI_FIFO_ENOUGH
| dmacHw_REG_CFG_HI_AHB_HPROT_1
|
468 dmacHw_SRC_PERI_INTF(pConfig
->
470 dmacHw_DST_PERI_INTF(pConfig
->dstPeripheralPort
);
472 dmacHw_SET_CHANNEL_PRIORITY(pCblk
->module
, pCblk
->channel
,
473 pConfig
->channelPriority
);
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
);
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
);
490 /* Configure the config high register */
491 dmacHw_GET_CONFIG_HI(pCblk
->module
, pCblk
->channel
) = cfgHigh
;
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
);
498 /* Configure block interrupt */
499 if (pConfig
->blockTransferInterrupt
== dmacHw_INTERRUPT_ENABLE
) {
500 dmacHw_BLOCK_INT_ENABLE(pCblk
->module
, pCblk
->channel
);
502 dmacHw_BLOCK_INT_DISABLE(pCblk
->module
, pCblk
->channel
);
504 /* Configure complete transfer interrupt */
505 if (pConfig
->completeTransferInterrupt
== dmacHw_INTERRUPT_ENABLE
) {
506 dmacHw_TRAN_INT_ENABLE(pCblk
->module
, pCblk
->channel
);
508 dmacHw_TRAN_INT_DISABLE(pCblk
->module
, pCblk
->channel
);
510 /* Configure error interrupt */
511 if (pConfig
->errorInterrupt
== dmacHw_INTERRUPT_ENABLE
) {
512 dmacHw_ERROR_INT_ENABLE(pCblk
->module
, pCblk
->channel
);
514 dmacHw_ERROR_INT_DISABLE(pCblk
->module
, pCblk
->channel
);
516 /* Configure gather register */
517 if (pConfig
->srcGatherWidth
) {
519 dmacHw_GetTrWidthInBytes(pConfig
->srcMaxTransactionWidth
);
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
/
531 /* Configure scatter register */
532 if (pConfig
->dstScatterWidth
) {
534 dmacHw_GetTrWidthInBytes(pConfig
->dstMaxTransactionWidth
);
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
/
549 /****************************************************************************/
551 * @brief Indicates whether DMA transfer is in progress or completed
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
559 /****************************************************************************/
560 dmacHw_TRANSFER_STATUS_e
dmacHw_transferCompleted(dmacHw_HANDLE_t handle
/* [ IN ] DMA Channel handle */
562 dmacHw_CBLK_t
*pCblk
= dmacHw_HANDLE_TO_CBLK(handle
);
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
;
571 return dmacHw_TRANSFER_STATUS_DONE
;
574 /****************************************************************************/
576 * @brief Set descriptors for known data length
578 * When DMA has to work as a flow controller, this function prepares the
579 * descriptor chain to transfer data
583 * - Peripheral to memory
584 * - Memory to Peripheral
585 * - Peripheral to Peripheral
587 * @return -1 - On failure
591 /****************************************************************************/
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 */
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
;
610 uint32_t maxBlockSize
= dmacHw_MAX_BLOCKSIZE
;
612 dstTrSize
= dmacHw_GetTrWidthInBytes(pConfig
->dstMaxTransactionWidth
);
613 srcTrSize
= dmacHw_GetTrWidthInBytes(pConfig
->srcMaxTransactionWidth
);
615 /* Skip Tx if buffer is NULL or length is unknown */
616 if ((pSrcAddr
== NULL
) || (pDstAddr
== NULL
) || (dataLen
== 0)) {
617 /* Do not initiate transfer */
621 /* Ensure scatter and gather are transaction aligned */
622 if ((pConfig
->srcGatherWidth
% srcTrSize
)
623 || (pConfig
->dstScatterWidth
% dstTrSize
)) {
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.
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
);
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
);
648 /* Find the maximum transaction per descriptor */
649 if (pConfig
->maxDataPerBlock
650 && ((pConfig
->maxDataPerBlock
/ srcTrSize
) <
651 dmacHw_MAX_BLOCKSIZE
)) {
652 maxBlockSize
= pConfig
->maxDataPerBlock
/ srcTrSize
;
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
);
663 oddSize
= dataLen
% srcTrSize
;
665 /* Adjust "descCount" due to "oddSize" */
669 /* Find the number of descriptor needed for total "srcTs" */
671 descCount
+= ((srcTs
- 1) / maxBlockSize
) + 1;
674 /* Check the availability of "descCount" discriptors in the ring */
675 pProg
= pRing
->pHead
;
676 for (count
= 0; (descCount
<= pRing
->num
) && (count
< descCount
);
678 if ((pProg
->ctl
.hi
& dmacHw_DESC_FREE
) == 0) {
679 /* Sufficient descriptors are not available */
682 pProg
= (dmacHw_DESC_t
*) pProg
->llp
;
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 */
689 /* Reset channel control information */
691 /* Enable source gather if configured */
692 if (pConfig
->srcGatherWidth
) {
693 pProg
->ctl
.lo
|= dmacHw_REG_CTL_SG_ENABLE
;
695 /* Enable destination scatter if configured */
696 if (pConfig
->dstScatterWidth
) {
697 pProg
->ctl
.lo
|= dmacHw_REG_CTL_DS_ENABLE
;
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
;
711 /* Special treatmeant for last descriptor */
713 /* Mark the last descriptor */
715 ~(dmacHw_REG_CTL_LLP_DST_EN
|
716 dmacHw_REG_CTL_LLP_SRC_EN
);
717 /* Treatment for odd data bytes */
719 /* Adjust for single byte transaction width */
720 switch (pConfig
->transferType
) {
721 case dmacHw_TRANSFER_TYPE_PERIPHERAL_TO_MEM
:
723 dmacHw_DST_TRANSACTION_WIDTH_8
;
725 (oddSize
/ srcTrSize
) +
726 ((oddSize
% srcTrSize
) ? 1 : 0);
728 case dmacHw_TRANSFER_TYPE_MEM_TO_PERIPHERAL
:
730 dmacHw_SRC_TRANSACTION_WIDTH_8
;
733 case dmacHw_TRANSFER_TYPE_MEM_TO_MEM
:
735 dmacHw_SRC_TRANSACTION_WIDTH_8
;
737 dmacHw_DST_TRANSACTION_WIDTH_8
;
740 case dmacHw_TRANSFER_TYPE_PERIPHERAL_TO_PERIPHERAL
:
741 /* Do not adjust the transaction width */
748 if (srcTs
/ maxBlockSize
) {
749 blkTs
= maxBlockSize
;
751 /* Remaining source transactions for next iteration */
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
|
763 pConfig
->srcMaxBurstWidth
|
764 pConfig
->dstMaxBurstWidth
|
765 pConfig
->srcMasterInterface
|
766 pConfig
->dstMasterInterface
| dmacHw_REG_CTL_INT_EN
;
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
;
773 case dmacHw_TRANSFER_TYPE_MEM_TO_PERIPHERAL
:
774 transferType
= dmacHw_REG_CTL_TTFC_MP_PERI
;
779 pProg
->ctl
.lo
|= transferType
|
784 pConfig
->srcMaxBurstWidth
|
785 pConfig
->dstMaxBurstWidth
|
786 pConfig
->srcMasterInterface
|
787 pConfig
->dstMasterInterface
| dmacHw_REG_CTL_INT_EN
;
790 /* Set block transaction size */
791 pProg
->ctl
.hi
= blkTs
& dmacHw_REG_CTL_BLOCK_TS_MASK
;
792 /* Look for next descriptor */
794 /* Point to the next descriptor */
795 pProg
= (dmacHw_DESC_t
*) pProg
->llp
;
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
) {
804 (((blkTs
* srcTrSize
) /
805 pConfig
->dstScatterWidth
) *
806 pConfig
->dstScatterJump
);
813 case dmacHw_TRANSFER_TYPE_MEM_TO_PERIPHERAL
:
814 if (pConfig
->srcGatherWidth
) {
818 (((blkTs
* srcTrSize
) /
819 pConfig
->srcGatherWidth
) *
820 pConfig
->srcGatherJump
);
827 case dmacHw_TRANSFER_TYPE_MEM_TO_MEM
:
828 if (pConfig
->dstScatterWidth
) {
832 (((blkTs
* srcTrSize
) /
833 pConfig
->dstScatterWidth
) *
834 pConfig
->dstScatterJump
);
841 if (pConfig
->srcGatherWidth
) {
845 (((blkTs
* srcTrSize
) /
846 pConfig
->srcGatherWidth
) *
847 pConfig
->srcGatherJump
);
854 case dmacHw_TRANSFER_TYPE_PERIPHERAL_TO_PERIPHERAL
:
855 /* Do not adjust the address */
861 /* At the end of transfer "srcTs" must be zero */
862 dmacHw_ASSERT(srcTs
== 0);
867 /* Remember the descriptor to initialize the registers */
868 if (pRing
->pProg
== dmacHw_DESC_INIT
) {
869 pRing
->pProg
= pStart
;
871 /* Indicate that the descriptor is updated */
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
878 if (!dmacHw_DST_IS_MEMORY(pConfig
->transferType
)) {
879 pRing
->pTail
= pRing
->pHead
;
884 /****************************************************************************/
886 * @brief Provides DMA controller attributes
889 * @return DMA controller attributes
894 /****************************************************************************/
895 uint32_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 */
898 dmacHw_CBLK_t
*pCblk
= dmacHw_HANDLE_TO_CBLK(handle
);
901 case dmacHw_CONTROLLER_ATTRIB_CHANNEL_NUM
:
902 return dmacHw_GET_NUM_CHANNEL(pCblk
->module
);
903 case dmacHw_CONTROLLER_ATTRIB_CHANNEL_MAX_BLOCK_SIZE
:
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
,
912 case dmacHw_CONTROLLER_ATTRIB_CHANNEL_FIFO_SIZE
:
913 return GetFifoSize(handle
);