int dmacHw_freeMem(dmacHw_CONFIG_t *pConfig, void *pDescriptor, void (*fpFree) (void *) ) { dmacHw_DESC_RING_t *pRing = dmacHw_GET_DESC_RING(pDescriptor); uint32_t count = 0; if (fpFree == NULL) { return -1; } while ((pRing->pFree != pRing->pTail) && (pRing->pFree->ctl.lo & dmacHw_DESC_FREE)) { if (pRing->pFree->devCtl == dmacHw_FREE_USER_MEMORY) { if (dmacHw_DST_IS_MEMORY(pConfig->transferType)) { (*fpFree) ((void *)pRing->pFree->dar); } else { (*fpFree) ((void *)pRing->pFree->sar); } pRing->pFree->devCtl = ~dmacHw_FREE_USER_MEMORY; } dmacHw_NEXT_DESC(pRing, pFree); count++; } return count; }
int dmacHw_freeMem(dmacHw_CONFIG_t *pConfig, /* [ IN ] Configuration settings */ void *pDescriptor, /* [ IN ] Descriptor buffer */ void (*fpFree) (void *) /* [ IN ] Function pointer to free data memory */ ) { dmacHw_DESC_RING_t *pRing = dmacHw_GET_DESC_RING(pDescriptor); uint32_t count = 0; if (fpFree == NULL) { return -1; } while ((pRing->pFree != pRing->pTail) && (pRing->pFree->ctl.lo & dmacHw_DESC_FREE)) { if (pRing->pFree->devCtl == dmacHw_FREE_USER_MEMORY) { /* Identify, which memory to free */ if (dmacHw_DST_IS_MEMORY(pConfig->transferType)) { (*fpFree) ((void *)pRing->pFree->dar); } else { /* Destination was a peripheral */ (*fpFree) ((void *)pRing->pFree->sar); } /* Unmark user memory to indicate it is freed */ pRing->pFree->devCtl = ~dmacHw_FREE_USER_MEMORY; } dmacHw_NEXT_DESC(pRing, pFree); count++; } return count; }
int dmacHw_readTransferredData(dmacHw_HANDLE_t handle, /* [ IN ] DMA Channel handle */ dmacHw_CONFIG_t *pConfig, /* [ IN ] Configuration settings */ void *pDescriptor, /* [ IN ] Descriptor buffer */ void **ppBbuf, /* [ OUT ] Data received */ size_t *pLlen /* [ OUT ] Length of the data received */ ) { dmacHw_DESC_RING_t *pRing = dmacHw_GET_DESC_RING(pDescriptor); (void)handle; if (pConfig->transferMode != dmacHw_TRANSFER_MODE_CONTINUOUS) { if (((pRing->pTail->ctl.hi & dmacHw_DESC_FREE) == 0) || (pRing->pTail == pRing->pHead) ) { /* No receive data available */ *ppBbuf = (char *)NULL; *pLlen = 0; return 0; } } /* Return read buffer and length */ *ppBbuf = (char *)pRing->pTail->dar; /* Extract length of the received data */ if (DmaIsFlowController(pDescriptor)) { uint32_t srcTrSize = 0; switch (pRing->pTail->ctl.lo & dmacHw_REG_CTL_SRC_TR_WIDTH_MASK) { case dmacHw_REG_CTL_SRC_TR_WIDTH_8: srcTrSize = 1; break; case dmacHw_REG_CTL_SRC_TR_WIDTH_16: srcTrSize = 2; break; case dmacHw_REG_CTL_SRC_TR_WIDTH_32: srcTrSize = 4; break; case dmacHw_REG_CTL_SRC_TR_WIDTH_64: srcTrSize = 8; break; default: dmacHw_ASSERT(0); } /* Calculate length from the block size */ *pLlen = (pRing->pTail->ctl.hi & dmacHw_REG_CTL_BLOCK_TS_MASK) * srcTrSize; } else { /* Extract length from the source peripheral */ *pLlen = pRing->pTail->sstat; } /* Advance tail to next descriptor */ dmacHw_NEXT_DESC(pRing, pTail); return 1; }
int dmacHw_readTransferredData(dmacHw_HANDLE_t handle, dmacHw_CONFIG_t *pConfig, void *pDescriptor, void **ppBbuf, size_t *pLlen ) { dmacHw_DESC_RING_t *pRing = dmacHw_GET_DESC_RING(pDescriptor); (void)handle; if (pConfig->transferMode != dmacHw_TRANSFER_MODE_CONTINUOUS) { if (((pRing->pTail->ctl.hi & dmacHw_DESC_FREE) == 0) || (pRing->pTail == pRing->pHead) ) { *ppBbuf = (char *)NULL; *pLlen = 0; return 0; } } *ppBbuf = (char *)pRing->pTail->dar; if (DmaIsFlowController(pDescriptor)) { uint32_t srcTrSize = 0; switch (pRing->pTail->ctl.lo & dmacHw_REG_CTL_SRC_TR_WIDTH_MASK) { case dmacHw_REG_CTL_SRC_TR_WIDTH_8: srcTrSize = 1; break; case dmacHw_REG_CTL_SRC_TR_WIDTH_16: srcTrSize = 2; break; case dmacHw_REG_CTL_SRC_TR_WIDTH_32: srcTrSize = 4; break; case dmacHw_REG_CTL_SRC_TR_WIDTH_64: srcTrSize = 8; break; default: dmacHw_ASSERT(0); } *pLlen = (pRing->pTail->ctl.hi & dmacHw_REG_CTL_BLOCK_TS_MASK) * srcTrSize; } else { *pLlen = pRing->pTail->sstat; } dmacHw_NEXT_DESC(pRing, pTail); return 1; }
int dmacHw_setControlDescriptor(dmacHw_CONFIG_t *pConfig, /* [ IN ] Configuration settings */ void *pDescriptor, /* [ IN ] Descriptor buffer */ uint32_t ctlAddress, /* [ IN ] Address of the device control register */ uint32_t control /* [ IN ] Device control information */ ) { dmacHw_DESC_RING_t *pRing = dmacHw_GET_DESC_RING(pDescriptor); if (ctlAddress == 0) { return -1; } /* Check the availability of descriptors in the ring */ if ((pRing->pHead->ctl.hi & dmacHw_DESC_FREE) == 0) { return -1; } /* Set control information */ pRing->pHead->devCtl = control; /* Set source and destination address */ pRing->pHead->sar = (uint32_t) &pRing->pHead->devCtl; pRing->pHead->dar = ctlAddress; /* Set control parameters */ if (pConfig->flowControler == dmacHw_FLOW_CONTROL_DMA) { pRing->pHead->ctl.lo = pConfig->transferType | dmacHw_SRC_ADDRESS_UPDATE_MODE_INC | dmacHw_DST_ADDRESS_UPDATE_MODE_INC | dmacHw_SRC_TRANSACTION_WIDTH_32 | pConfig->dstMaxTransactionWidth | dmacHw_SRC_BURST_WIDTH_0 | dmacHw_DST_BURST_WIDTH_0 | pConfig->srcMasterInterface | pConfig->dstMasterInterface | dmacHw_REG_CTL_INT_EN; } else { uint32_t transferType = 0; switch (pConfig->transferType) { case dmacHw_TRANSFER_TYPE_PERIPHERAL_TO_MEM: transferType = dmacHw_REG_CTL_TTFC_PM_PERI; break; case dmacHw_TRANSFER_TYPE_MEM_TO_PERIPHERAL: transferType = dmacHw_REG_CTL_TTFC_MP_PERI; break; default: dmacHw_ASSERT(0); } pRing->pHead->ctl.lo = transferType | dmacHw_SRC_ADDRESS_UPDATE_MODE_INC | dmacHw_DST_ADDRESS_UPDATE_MODE_INC | dmacHw_SRC_TRANSACTION_WIDTH_32 | pConfig->dstMaxTransactionWidth | dmacHw_SRC_BURST_WIDTH_0 | dmacHw_DST_BURST_WIDTH_0 | pConfig->srcMasterInterface | pConfig->dstMasterInterface | pConfig->flowControler | dmacHw_REG_CTL_INT_EN; } /* Set block transaction size to one 32 bit transaction */ pRing->pHead->ctl.hi = dmacHw_REG_CTL_BLOCK_TS_MASK & 1; /* Remember the descriptor to initialize the registers */ if (pRing->pProg == dmacHw_DESC_INIT) { pRing->pProg = pRing->pHead; } pRing->pEnd = pRing->pHead; /* Advance the descriptor */ dmacHw_NEXT_DESC(pRing, pHead); /* Update Tail pointer if destination is a peripheral */ if (!dmacHw_DST_IS_MEMORY(pConfig->transferType)) { pRing->pTail = pRing->pHead; } return 0; }
int dmacHw_setVariableDataDescriptor(dmacHw_HANDLE_t handle, /* [ IN ] DMA Channel handle */ dmacHw_CONFIG_t *pConfig, /* [ IN ] Configuration settings */ void *pDescriptor, /* [ IN ] Descriptor buffer */ uint32_t srcAddr, /* [ IN ] Source peripheral address */ void *(*fpAlloc) (int len), /* [ IN ] Function pointer that provides destination memory */ int len, /* [ IN ] Number of bytes "fpAlloc" will allocate for destination */ int num /* [ IN ] Number of descriptor to set */ ) { dmacHw_CBLK_t *pCblk = dmacHw_HANDLE_TO_CBLK(handle); dmacHw_DESC_t *pProg = NULL; dmacHw_DESC_t *pLast = NULL; dmacHw_DESC_RING_t *pRing = dmacHw_GET_DESC_RING(pDescriptor); uint32_t dstAddr; uint32_t controlParam; int i; dmacHw_ASSERT(pConfig->transferType == dmacHw_TRANSFER_TYPE_PERIPHERAL_TO_MEM); if (num > pRing->num) { return -1; } pLast = pRing->pEnd; /* Last descriptor updated */ pProg = pRing->pHead; /* First descriptor in the new list */ controlParam = pConfig->srcUpdate | pConfig->dstUpdate | pConfig->srcMaxTransactionWidth | pConfig->dstMaxTransactionWidth | pConfig->srcMasterInterface | pConfig->dstMasterInterface | pConfig->srcMaxBurstWidth | pConfig->dstMaxBurstWidth | dmacHw_REG_CTL_TTFC_PM_PERI | dmacHw_REG_CTL_LLP_DST_EN | dmacHw_REG_CTL_LLP_SRC_EN | dmacHw_REG_CTL_INT_EN; for (i = 0; i < num; i++) { /* Allocate Rx buffer only for idle descriptor */ if (((pRing->pHead->ctl.hi & dmacHw_DESC_FREE) == 0) || ((dmacHw_DESC_t *) pRing->pHead->llp == pRing->pTail) ) { /* Rx descriptor is not idle */ break; } /* Set source address */ pRing->pHead->sar = srcAddr; if (fpAlloc) { /* Allocate memory for buffer in descriptor */ dstAddr = (uint32_t) (*fpAlloc) (len); /* Check the destination address */ if (dstAddr == 0) { if (i == 0) { /* Not a single descriptor is available */ return -1; } break; } /* Set destination address */ pRing->pHead->dar = dstAddr; } /* Set control information */ pRing->pHead->ctl.lo = controlParam; /* Use "devCtl" to mark the memory that need to be freed later */ pRing->pHead->devCtl = dmacHw_FREE_USER_MEMORY; /* Descriptor is now owned by the channel */ pRing->pHead->ctl.hi = 0; /* Remember the descriptor last updated */ pRing->pEnd = pRing->pHead; /* Update next descriptor */ dmacHw_NEXT_DESC(pRing, pHead); } /* Mark the end of the list */ pRing->pEnd->ctl.lo &= ~(dmacHw_REG_CTL_LLP_DST_EN | dmacHw_REG_CTL_LLP_SRC_EN); /* Connect the list */ if (pLast != pProg) { pLast->ctl.lo |= dmacHw_REG_CTL_LLP_DST_EN | dmacHw_REG_CTL_LLP_SRC_EN; } /* Mark the descriptors are updated */ pCblk->descUpdated = 1; if (!pCblk->varDataStarted) { /* LLP must be pointing to the first descriptor */ dmacHw_SET_LLP(pCblk->module, pCblk->channel, (uint32_t) pProg - pRing->virt2PhyOffset); /* Channel, handling variable data started */ pCblk->varDataStarted = 1; } return i; }
void dmacHw_initiateTransfer(dmacHw_HANDLE_t handle, dmacHw_CONFIG_t *pConfig, void *pDescriptor ) { dmacHw_DESC_RING_t *pRing; dmacHw_DESC_t *pProg; dmacHw_CBLK_t *pCblk; pCblk = dmacHw_HANDLE_TO_CBLK(handle); pRing = dmacHw_GET_DESC_RING(pDescriptor); if (CHANNEL_BUSY(pCblk->module, pCblk->channel)) { return; } if (pCblk->varDataStarted) { if (pCblk->descUpdated) { pCblk->descUpdated = 0; pProg = (dmacHw_DESC_t *) ((uint32_t) dmacHw_REG_LLP(pCblk->module, pCblk->channel) + pRing->virt2PhyOffset); if (!(pProg->ctl.hi & dmacHw_REG_CTL_DONE)) { dmacHw_SET_SAR(pCblk->module, pCblk->channel, pProg->sar); dmacHw_SET_DAR(pCblk->module, pCblk->channel, pProg->dar); dmacHw_REG_CTL_LO(pCblk->module, pCblk->channel) = pProg->ctl.lo; dmacHw_REG_CTL_HI(pCblk->module, pCblk->channel) = pProg->ctl.hi; } else if (pProg == (dmacHw_DESC_t *) pRing->pEnd->llp) { return; } else { dmacHw_ASSERT(0); } } else { return; } } else { if (pConfig->transferMode == dmacHw_TRANSFER_MODE_PERIODIC) { pProg = pRing->pHead; dmacHw_NEXT_DESC(pRing, pHead); } else { if (pRing->pEnd == NULL) { return; } pProg = pRing->pProg; if (pConfig->transferMode == dmacHw_TRANSFER_MODE_CONTINUOUS) { dmacHw_ASSERT((dmacHw_DESC_t *) pRing->pEnd-> llp == pRing->pProg); dmacHw_ASSERT((dmacHw_DESC_t *) pRing->pProg == pRing->pHead); do { pRing->pProg->ctl.lo |= (dmacHw_REG_CTL_LLP_DST_EN | dmacHw_REG_CTL_LLP_SRC_EN); pRing->pProg = (dmacHw_DESC_t *) pRing->pProg->llp; } while (pRing->pProg != pRing->pHead); } else { while (pRing->pProg != pRing->pEnd) { pRing->pProg->ctl.lo |= (dmacHw_REG_CTL_LLP_DST_EN | dmacHw_REG_CTL_LLP_SRC_EN); pRing->pProg = (dmacHw_DESC_t *) pRing->pProg->llp; } } } dmacHw_SET_SAR(pCblk->module, pCblk->channel, pProg->sar); dmacHw_SET_DAR(pCblk->module, pCblk->channel, pProg->dar); dmacHw_SET_LLP(pCblk->module, pCblk->channel, (uint32_t) pProg - pRing->virt2PhyOffset); dmacHw_REG_CTL_LO(pCblk->module, pCblk->channel) = pProg->ctl.lo; dmacHw_REG_CTL_HI(pCblk->module, pCblk->channel) = pProg->ctl.hi; if (pRing->pEnd) { pRing->pProg = (dmacHw_DESC_t *) pRing->pEnd->llp; } pRing->pEnd = (dmacHw_DESC_t *) NULL; } dmacHw_DMA_START(pCblk->module, pCblk->channel); }
void dmacHw_initiateTransfer(dmacHw_HANDLE_t handle, /* [ IN ] DMA Channel handle */ dmacHw_CONFIG_t *pConfig, /* [ IN ] Configuration settings */ void *pDescriptor /* [ IN ] Descriptor buffer */ ) { dmacHw_DESC_RING_t *pRing; dmacHw_DESC_t *pProg; dmacHw_CBLK_t *pCblk; pCblk = dmacHw_HANDLE_TO_CBLK(handle); pRing = dmacHw_GET_DESC_RING(pDescriptor); if (CHANNEL_BUSY(pCblk->module, pCblk->channel)) { /* Not safe yet to program the channel */ return; } if (pCblk->varDataStarted) { if (pCblk->descUpdated) { pCblk->descUpdated = 0; pProg = (dmacHw_DESC_t *) ((uint32_t) dmacHw_REG_LLP(pCblk->module, pCblk->channel) + pRing->virt2PhyOffset); /* Load descriptor if not loaded */ if (!(pProg->ctl.hi & dmacHw_REG_CTL_DONE)) { dmacHw_SET_SAR(pCblk->module, pCblk->channel, pProg->sar); dmacHw_SET_DAR(pCblk->module, pCblk->channel, pProg->dar); dmacHw_REG_CTL_LO(pCblk->module, pCblk->channel) = pProg->ctl.lo; dmacHw_REG_CTL_HI(pCblk->module, pCblk->channel) = pProg->ctl.hi; } else if (pProg == (dmacHw_DESC_t *) pRing->pEnd->llp) { /* Return as end descriptor is processed */ return; } else { dmacHw_ASSERT(0); } } else { return; } } else { if (pConfig->transferMode == dmacHw_TRANSFER_MODE_PERIODIC) { /* Do not make a single chain, rather process one descriptor at a time */ pProg = pRing->pHead; /* Point to the next descriptor for next iteration */ dmacHw_NEXT_DESC(pRing, pHead); } else { /* Return if no more pending descriptor */ if (pRing->pEnd == NULL) { return; } pProg = pRing->pProg; if (pConfig->transferMode == dmacHw_TRANSFER_MODE_CONTINUOUS) { /* Make sure a complete ring can be formed */ dmacHw_ASSERT((dmacHw_DESC_t *) pRing->pEnd-> llp == pRing->pProg); /* Make sure pProg pointing to the pHead */ dmacHw_ASSERT((dmacHw_DESC_t *) pRing->pProg == pRing->pHead); /* Make a complete ring */ do { pRing->pProg->ctl.lo |= (dmacHw_REG_CTL_LLP_DST_EN | dmacHw_REG_CTL_LLP_SRC_EN); pRing->pProg = (dmacHw_DESC_t *) pRing->pProg->llp; } while (pRing->pProg != pRing->pHead); } else { /* Make a single long chain */ while (pRing->pProg != pRing->pEnd) { pRing->pProg->ctl.lo |= (dmacHw_REG_CTL_LLP_DST_EN | dmacHw_REG_CTL_LLP_SRC_EN); pRing->pProg = (dmacHw_DESC_t *) pRing->pProg->llp; } } } /* Program the channel registers */ dmacHw_SET_SAR(pCblk->module, pCblk->channel, pProg->sar); dmacHw_SET_DAR(pCblk->module, pCblk->channel, pProg->dar); dmacHw_SET_LLP(pCblk->module, pCblk->channel, (uint32_t) pProg - pRing->virt2PhyOffset); dmacHw_REG_CTL_LO(pCblk->module, pCblk->channel) = pProg->ctl.lo; dmacHw_REG_CTL_HI(pCblk->module, pCblk->channel) = pProg->ctl.hi; if (pRing->pEnd) { /* Remember the descriptor to use next */ pRing->pProg = (dmacHw_DESC_t *) pRing->pEnd->llp; } /* Indicate no more pending descriptor */ pRing->pEnd = (dmacHw_DESC_t *) NULL; } /* Start DMA operation */ dmacHw_DMA_START(pCblk->module, pCblk->channel); }
int dmacHw_setControlDescriptor(dmacHw_CONFIG_t *pConfig, void *pDescriptor, uint32_t ctlAddress, uint32_t control ) { dmacHw_DESC_RING_t *pRing = dmacHw_GET_DESC_RING(pDescriptor); if (ctlAddress == 0) { return -1; } if ((pRing->pHead->ctl.hi & dmacHw_DESC_FREE) == 0) { return -1; } pRing->pHead->devCtl = control; pRing->pHead->sar = (uint32_t) &pRing->pHead->devCtl; pRing->pHead->dar = ctlAddress; if (pConfig->flowControler == dmacHw_FLOW_CONTROL_DMA) { pRing->pHead->ctl.lo = pConfig->transferType | dmacHw_SRC_ADDRESS_UPDATE_MODE_INC | dmacHw_DST_ADDRESS_UPDATE_MODE_INC | dmacHw_SRC_TRANSACTION_WIDTH_32 | pConfig->dstMaxTransactionWidth | dmacHw_SRC_BURST_WIDTH_0 | dmacHw_DST_BURST_WIDTH_0 | pConfig->srcMasterInterface | pConfig->dstMasterInterface | dmacHw_REG_CTL_INT_EN; } else { uint32_t transferType = 0; switch (pConfig->transferType) { case dmacHw_TRANSFER_TYPE_PERIPHERAL_TO_MEM: transferType = dmacHw_REG_CTL_TTFC_PM_PERI; break; case dmacHw_TRANSFER_TYPE_MEM_TO_PERIPHERAL: transferType = dmacHw_REG_CTL_TTFC_MP_PERI; break; default: dmacHw_ASSERT(0); } pRing->pHead->ctl.lo = transferType | dmacHw_SRC_ADDRESS_UPDATE_MODE_INC | dmacHw_DST_ADDRESS_UPDATE_MODE_INC | dmacHw_SRC_TRANSACTION_WIDTH_32 | pConfig->dstMaxTransactionWidth | dmacHw_SRC_BURST_WIDTH_0 | dmacHw_DST_BURST_WIDTH_0 | pConfig->srcMasterInterface | pConfig->dstMasterInterface | pConfig->flowControler | dmacHw_REG_CTL_INT_EN; } pRing->pHead->ctl.hi = dmacHw_REG_CTL_BLOCK_TS_MASK & 1; if (pRing->pProg == dmacHw_DESC_INIT) { pRing->pProg = pRing->pHead; } pRing->pEnd = pRing->pHead; dmacHw_NEXT_DESC(pRing, pHead); if (!dmacHw_DST_IS_MEMORY(pConfig->transferType)) { pRing->pTail = pRing->pHead; } return 0; }
int dmacHw_setVariableDataDescriptor(dmacHw_HANDLE_t handle, dmacHw_CONFIG_t *pConfig, void *pDescriptor, uint32_t srcAddr, void *(*fpAlloc) (int len), int len, int num ) { dmacHw_CBLK_t *pCblk = dmacHw_HANDLE_TO_CBLK(handle); dmacHw_DESC_t *pProg = NULL; dmacHw_DESC_t *pLast = NULL; dmacHw_DESC_RING_t *pRing = dmacHw_GET_DESC_RING(pDescriptor); uint32_t dstAddr; uint32_t controlParam; int i; dmacHw_ASSERT(pConfig->transferType == dmacHw_TRANSFER_TYPE_PERIPHERAL_TO_MEM); if (num > pRing->num) { return -1; } pLast = pRing->pEnd; pProg = pRing->pHead; controlParam = pConfig->srcUpdate | pConfig->dstUpdate | pConfig->srcMaxTransactionWidth | pConfig->dstMaxTransactionWidth | pConfig->srcMasterInterface | pConfig->dstMasterInterface | pConfig->srcMaxBurstWidth | pConfig->dstMaxBurstWidth | dmacHw_REG_CTL_TTFC_PM_PERI | dmacHw_REG_CTL_LLP_DST_EN | dmacHw_REG_CTL_LLP_SRC_EN | dmacHw_REG_CTL_INT_EN; for (i = 0; i < num; i++) { if (((pRing->pHead->ctl.hi & dmacHw_DESC_FREE) == 0) || ((dmacHw_DESC_t *) pRing->pHead->llp == pRing->pTail) ) { break; } pRing->pHead->sar = srcAddr; if (fpAlloc) { dstAddr = (uint32_t) (*fpAlloc) (len); if (dstAddr == 0) { if (i == 0) { return -1; } break; } pRing->pHead->dar = dstAddr; } pRing->pHead->ctl.lo = controlParam; pRing->pHead->devCtl = dmacHw_FREE_USER_MEMORY; pRing->pHead->ctl.hi = 0; pRing->pEnd = pRing->pHead; dmacHw_NEXT_DESC(pRing, pHead); } pRing->pEnd->ctl.lo &= ~(dmacHw_REG_CTL_LLP_DST_EN | dmacHw_REG_CTL_LLP_SRC_EN); if (pLast != pProg) { pLast->ctl.lo |= dmacHw_REG_CTL_LLP_DST_EN | dmacHw_REG_CTL_LLP_SRC_EN; } pCblk->descUpdated = 1; if (!pCblk->varDataStarted) { dmacHw_SET_LLP(pCblk->module, pCblk->channel, (uint32_t) pProg - pRing->virt2PhyOffset); pCblk->varDataStarted = 1; } return i; }