1018 lines
		
	
	
		
			34 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1018 lines
		
	
	
		
			34 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*****************************************************************************
 | |
| * Copyright 2003 - 2008 Broadcom Corporation.  All rights reserved.
 | |
| *
 | |
| * Unless you and Broadcom execute a separate written software license
 | |
| * agreement governing use of this software, this software is licensed to you
 | |
| * under the terms of the GNU General Public License version 2, available at
 | |
| * http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
 | |
| *
 | |
| * Notwithstanding the above, under no circumstances may you combine this
 | |
| * software in any way with any other Broadcom software provided under a
 | |
| * license other than the GPL, without Broadcom's express prior written
 | |
| * consent.
 | |
| *****************************************************************************/
 | |
| 
 | |
| /****************************************************************************/
 | |
| /**
 | |
| *  @file    dmacHw_extra.c
 | |
| *
 | |
| *  @brief   Extra Low level DMA controller driver routines
 | |
| *
 | |
| *  @note
 | |
| *
 | |
| *   These routines provide basic DMA functionality only.
 | |
| */
 | |
| /****************************************************************************/
 | |
| 
 | |
| /* ---- Include Files ---------------------------------------------------- */
 | |
| 
 | |
| #include <csp/stdint.h>
 | |
| #include <stddef.h>
 | |
| 
 | |
| #include <csp/dmacHw.h>
 | |
| #include <mach/csp/dmacHw_reg.h>
 | |
| #include <mach/csp/dmacHw_priv.h>
 | |
| 
 | |
| extern dmacHw_CBLK_t dmacHw_gCblk[dmacHw_MAX_CHANNEL_COUNT];	/* Declared in dmacHw.c */
 | |
| 
 | |
| /* ---- External Function Prototypes ------------------------------------- */
 | |
| 
 | |
| /* ---- Internal Use Function Prototypes --------------------------------- */
 | |
| /****************************************************************************/
 | |
| /**
 | |
| *  @brief   Overwrites data length in the descriptor
 | |
| *
 | |
| *  This function overwrites data length in the descriptor
 | |
| *
 | |
| *
 | |
| *  @return   void
 | |
| *
 | |
| *  @note
 | |
| *          This is only used for PCM channel
 | |
| */
 | |
| /****************************************************************************/
 | |
| void dmacHw_setDataLength(dmacHw_CONFIG_t *pConfig,	/*   [ IN ] Configuration settings */
 | |
| 			  void *pDescriptor,	/*   [ IN ] Descriptor buffer */
 | |
| 			  size_t dataLen	/*   [ IN ] Data length in bytes */
 | |
|     );
 | |
| 
 | |
| /****************************************************************************/
 | |
| /**
 | |
| *  @brief   Helper function to display DMA registers
 | |
| *
 | |
| *  @return  void
 | |
| *
 | |
| *
 | |
| *  @note
 | |
| *     None
 | |
| */
 | |
| /****************************************************************************/
 | |
| static void DisplayRegisterContents(int module,	/*   [ IN ] DMA Controller unit  (0-1) */
 | |
| 				    int channel,	/*   [ IN ] DMA Channel          (0-7) / -1(all) */
 | |
| 				    int (*fpPrint) (const char *, ...)	/*   [ IN ] Callback to the print function */
 | |
|     ) {
 | |
| 	int chan;
 | |
| 
 | |
| 	(*fpPrint) ("Displaying register content \n\n");
 | |
| 	(*fpPrint) ("Module %d: Interrupt raw transfer              0x%X\n",
 | |
| 		    module, (uint32_t) (dmacHw_REG_INT_RAW_TRAN(module)));
 | |
| 	(*fpPrint) ("Module %d: Interrupt raw block                 0x%X\n",
 | |
| 		    module, (uint32_t) (dmacHw_REG_INT_RAW_BLOCK(module)));
 | |
| 	(*fpPrint) ("Module %d: Interrupt raw src transfer          0x%X\n",
 | |
| 		    module, (uint32_t) (dmacHw_REG_INT_RAW_STRAN(module)));
 | |
| 	(*fpPrint) ("Module %d: Interrupt raw dst transfer          0x%X\n",
 | |
| 		    module, (uint32_t) (dmacHw_REG_INT_RAW_DTRAN(module)));
 | |
| 	(*fpPrint) ("Module %d: Interrupt raw error                 0x%X\n",
 | |
| 		    module, (uint32_t) (dmacHw_REG_INT_RAW_ERROR(module)));
 | |
| 	(*fpPrint) ("--------------------------------------------------\n");
 | |
| 	(*fpPrint) ("Module %d: Interrupt stat transfer             0x%X\n",
 | |
| 		    module, (uint32_t) (dmacHw_REG_INT_STAT_TRAN(module)));
 | |
| 	(*fpPrint) ("Module %d: Interrupt stat block                0x%X\n",
 | |
| 		    module, (uint32_t) (dmacHw_REG_INT_STAT_BLOCK(module)));
 | |
| 	(*fpPrint) ("Module %d: Interrupt stat src transfer         0x%X\n",
 | |
| 		    module, (uint32_t) (dmacHw_REG_INT_STAT_STRAN(module)));
 | |
| 	(*fpPrint) ("Module %d: Interrupt stat dst transfer         0x%X\n",
 | |
| 		    module, (uint32_t) (dmacHw_REG_INT_STAT_DTRAN(module)));
 | |
| 	(*fpPrint) ("Module %d: Interrupt stat error                0x%X\n",
 | |
| 		    module, (uint32_t) (dmacHw_REG_INT_STAT_ERROR(module)));
 | |
| 	(*fpPrint) ("--------------------------------------------------\n");
 | |
| 	(*fpPrint) ("Module %d: Interrupt mask transfer             0x%X\n",
 | |
| 		    module, (uint32_t) (dmacHw_REG_INT_MASK_TRAN(module)));
 | |
| 	(*fpPrint) ("Module %d: Interrupt mask block                0x%X\n",
 | |
| 		    module, (uint32_t) (dmacHw_REG_INT_MASK_BLOCK(module)));
 | |
| 	(*fpPrint) ("Module %d: Interrupt mask src transfer         0x%X\n",
 | |
| 		    module, (uint32_t) (dmacHw_REG_INT_MASK_STRAN(module)));
 | |
| 	(*fpPrint) ("Module %d: Interrupt mask dst transfer         0x%X\n",
 | |
| 		    module, (uint32_t) (dmacHw_REG_INT_MASK_DTRAN(module)));
 | |
| 	(*fpPrint) ("Module %d: Interrupt mask error                0x%X\n",
 | |
| 		    module, (uint32_t) (dmacHw_REG_INT_MASK_ERROR(module)));
 | |
| 	(*fpPrint) ("--------------------------------------------------\n");
 | |
| 	(*fpPrint) ("Module %d: Interrupt clear transfer            0x%X\n",
 | |
| 		    module, (uint32_t) (dmacHw_REG_INT_CLEAR_TRAN(module)));
 | |
| 	(*fpPrint) ("Module %d: Interrupt clear block               0x%X\n",
 | |
| 		    module, (uint32_t) (dmacHw_REG_INT_CLEAR_BLOCK(module)));
 | |
| 	(*fpPrint) ("Module %d: Interrupt clear src transfer        0x%X\n",
 | |
| 		    module, (uint32_t) (dmacHw_REG_INT_CLEAR_STRAN(module)));
 | |
| 	(*fpPrint) ("Module %d: Interrupt clear dst transfer        0x%X\n",
 | |
| 		    module, (uint32_t) (dmacHw_REG_INT_CLEAR_DTRAN(module)));
 | |
| 	(*fpPrint) ("Module %d: Interrupt clear error               0x%X\n",
 | |
| 		    module, (uint32_t) (dmacHw_REG_INT_CLEAR_ERROR(module)));
 | |
| 	(*fpPrint) ("--------------------------------------------------\n");
 | |
| 	(*fpPrint) ("Module %d: SW source req                       0x%X\n",
 | |
| 		    module, (uint32_t) (dmacHw_REG_SW_HS_SRC_REQ(module)));
 | |
| 	(*fpPrint) ("Module %d: SW dest req                         0x%X\n",
 | |
| 		    module, (uint32_t) (dmacHw_REG_SW_HS_DST_REQ(module)));
 | |
| 	(*fpPrint) ("Module %d: SW source signal                    0x%X\n",
 | |
| 		    module, (uint32_t) (dmacHw_REG_SW_HS_SRC_SGL_REQ(module)));
 | |
| 	(*fpPrint) ("Module %d: SW dest signal                      0x%X\n",
 | |
| 		    module, (uint32_t) (dmacHw_REG_SW_HS_DST_SGL_REQ(module)));
 | |
| 	(*fpPrint) ("Module %d: SW source last                      0x%X\n",
 | |
| 		    module, (uint32_t) (dmacHw_REG_SW_HS_SRC_LST_REQ(module)));
 | |
| 	(*fpPrint) ("Module %d: SW dest last                        0x%X\n",
 | |
| 		    module, (uint32_t) (dmacHw_REG_SW_HS_DST_LST_REQ(module)));
 | |
| 	(*fpPrint) ("--------------------------------------------------\n");
 | |
| 	(*fpPrint) ("Module %d: misc config                         0x%X\n",
 | |
| 		    module, (uint32_t) (dmacHw_REG_MISC_CFG(module)));
 | |
| 	(*fpPrint) ("Module %d: misc channel enable                 0x%X\n",
 | |
| 		    module, (uint32_t) (dmacHw_REG_MISC_CH_ENABLE(module)));
 | |
| 	(*fpPrint) ("Module %d: misc ID                             0x%X\n",
 | |
| 		    module, (uint32_t) (dmacHw_REG_MISC_ID(module)));
 | |
| 	(*fpPrint) ("Module %d: misc test                           0x%X\n",
 | |
| 		    module, (uint32_t) (dmacHw_REG_MISC_TEST(module)));
 | |
| 
 | |
| 	if (channel == -1) {
 | |
| 		for (chan = 0; chan < 8; chan++) {
 | |
| 			(*fpPrint)
 | |
| 			    ("--------------------------------------------------\n");
 | |
| 			(*fpPrint)
 | |
| 			    ("Module %d: Channel %d Source                   0x%X\n",
 | |
| 			     module, chan,
 | |
| 			     (uint32_t) (dmacHw_REG_SAR(module, chan)));
 | |
| 			(*fpPrint)
 | |
| 			    ("Module %d: Channel %d Destination              0x%X\n",
 | |
| 			     module, chan,
 | |
| 			     (uint32_t) (dmacHw_REG_DAR(module, chan)));
 | |
| 			(*fpPrint)
 | |
| 			    ("Module %d: Channel %d LLP                      0x%X\n",
 | |
| 			     module, chan,
 | |
| 			     (uint32_t) (dmacHw_REG_LLP(module, chan)));
 | |
| 			(*fpPrint)
 | |
| 			    ("Module %d: Channel %d Control (LO)             0x%X\n",
 | |
| 			     module, chan,
 | |
| 			     (uint32_t) (dmacHw_REG_CTL_LO(module, chan)));
 | |
| 			(*fpPrint)
 | |
| 			    ("Module %d: Channel %d Control (HI)             0x%X\n",
 | |
| 			     module, chan,
 | |
| 			     (uint32_t) (dmacHw_REG_CTL_HI(module, chan)));
 | |
| 			(*fpPrint)
 | |
| 			    ("Module %d: Channel %d Source Stats             0x%X\n",
 | |
| 			     module, chan,
 | |
| 			     (uint32_t) (dmacHw_REG_SSTAT(module, chan)));
 | |
| 			(*fpPrint)
 | |
| 			    ("Module %d: Channel %d Dest Stats               0x%X\n",
 | |
| 			     module, chan,
 | |
| 			     (uint32_t) (dmacHw_REG_DSTAT(module, chan)));
 | |
| 			(*fpPrint)
 | |
| 			    ("Module %d: Channel %d Source Stats Addr        0x%X\n",
 | |
| 			     module, chan,
 | |
| 			     (uint32_t) (dmacHw_REG_SSTATAR(module, chan)));
 | |
| 			(*fpPrint)
 | |
| 			    ("Module %d: Channel %d Dest Stats Addr          0x%X\n",
 | |
| 			     module, chan,
 | |
| 			     (uint32_t) (dmacHw_REG_DSTATAR(module, chan)));
 | |
| 			(*fpPrint)
 | |
| 			    ("Module %d: Channel %d Config (LO)              0x%X\n",
 | |
| 			     module, chan,
 | |
| 			     (uint32_t) (dmacHw_REG_CFG_LO(module, chan)));
 | |
| 			(*fpPrint)
 | |
| 			    ("Module %d: Channel %d Config (HI)              0x%X\n",
 | |
| 			     module, chan,
 | |
| 			     (uint32_t) (dmacHw_REG_CFG_HI(module, chan)));
 | |
| 		}
 | |
| 	} else {
 | |
| 		chan = channel;
 | |
| 		(*fpPrint)
 | |
| 		    ("--------------------------------------------------\n");
 | |
| 		(*fpPrint)
 | |
| 		    ("Module %d: Channel %d Source                   0x%X\n",
 | |
| 		     module, chan, (uint32_t) (dmacHw_REG_SAR(module, chan)));
 | |
| 		(*fpPrint)
 | |
| 		    ("Module %d: Channel %d Destination              0x%X\n",
 | |
| 		     module, chan, (uint32_t) (dmacHw_REG_DAR(module, chan)));
 | |
| 		(*fpPrint)
 | |
| 		    ("Module %d: Channel %d LLP                      0x%X\n",
 | |
| 		     module, chan, (uint32_t) (dmacHw_REG_LLP(module, chan)));
 | |
| 		(*fpPrint)
 | |
| 		    ("Module %d: Channel %d Control (LO)             0x%X\n",
 | |
| 		     module, chan,
 | |
| 		     (uint32_t) (dmacHw_REG_CTL_LO(module, chan)));
 | |
| 		(*fpPrint)
 | |
| 		    ("Module %d: Channel %d Control (HI)             0x%X\n",
 | |
| 		     module, chan,
 | |
| 		     (uint32_t) (dmacHw_REG_CTL_HI(module, chan)));
 | |
| 		(*fpPrint)
 | |
| 		    ("Module %d: Channel %d Source Stats             0x%X\n",
 | |
| 		     module, chan, (uint32_t) (dmacHw_REG_SSTAT(module, chan)));
 | |
| 		(*fpPrint)
 | |
| 		    ("Module %d: Channel %d Dest Stats               0x%X\n",
 | |
| 		     module, chan, (uint32_t) (dmacHw_REG_DSTAT(module, chan)));
 | |
| 		(*fpPrint)
 | |
| 		    ("Module %d: Channel %d Source Stats Addr        0x%X\n",
 | |
| 		     module, chan,
 | |
| 		     (uint32_t) (dmacHw_REG_SSTATAR(module, chan)));
 | |
| 		(*fpPrint)
 | |
| 		    ("Module %d: Channel %d Dest Stats Addr          0x%X\n",
 | |
| 		     module, chan,
 | |
| 		     (uint32_t) (dmacHw_REG_DSTATAR(module, chan)));
 | |
| 		(*fpPrint)
 | |
| 		    ("Module %d: Channel %d Config (LO)              0x%X\n",
 | |
| 		     module, chan,
 | |
| 		     (uint32_t) (dmacHw_REG_CFG_LO(module, chan)));
 | |
| 		(*fpPrint)
 | |
| 		    ("Module %d: Channel %d Config (HI)              0x%X\n",
 | |
| 		     module, chan,
 | |
| 		     (uint32_t) (dmacHw_REG_CFG_HI(module, chan)));
 | |
| 	}
 | |
| }
 | |
| 
 | |
| /****************************************************************************/
 | |
| /**
 | |
| *  @brief   Helper function to display descriptor ring
 | |
| *
 | |
| *  @return  void
 | |
| *
 | |
| *
 | |
| *  @note
 | |
| *     None
 | |
| */
 | |
| /****************************************************************************/
 | |
| static void DisplayDescRing(void *pDescriptor,	/*   [ IN ] Descriptor buffer */
 | |
| 			    int (*fpPrint) (const char *, ...)	/*   [ IN ] Callback to the print function */
 | |
|     ) {
 | |
| 	dmacHw_DESC_RING_t *pRing = dmacHw_GET_DESC_RING(pDescriptor);
 | |
| 	dmacHw_DESC_t *pStart;
 | |
| 
 | |
| 	if (pRing->pHead == NULL) {
 | |
| 		return;
 | |
| 	}
 | |
| 
 | |
| 	pStart = pRing->pHead;
 | |
| 
 | |
| 	while ((dmacHw_DESC_t *) pStart->llp != pRing->pHead) {
 | |
| 		if (pStart == pRing->pHead) {
 | |
| 			(*fpPrint) ("Head\n");
 | |
| 		}
 | |
| 		if (pStart == pRing->pTail) {
 | |
| 			(*fpPrint) ("Tail\n");
 | |
| 		}
 | |
| 		if (pStart == pRing->pProg) {
 | |
| 			(*fpPrint) ("Prog\n");
 | |
| 		}
 | |
| 		if (pStart == pRing->pEnd) {
 | |
| 			(*fpPrint) ("End\n");
 | |
| 		}
 | |
| 		if (pStart == pRing->pFree) {
 | |
| 			(*fpPrint) ("Free\n");
 | |
| 		}
 | |
| 		(*fpPrint) ("0x%X:\n", (uint32_t) pStart);
 | |
| 		(*fpPrint) ("sar    0x%0X\n", pStart->sar);
 | |
| 		(*fpPrint) ("dar    0x%0X\n", pStart->dar);
 | |
| 		(*fpPrint) ("llp    0x%0X\n", pStart->llp);
 | |
| 		(*fpPrint) ("ctl.lo 0x%0X\n", pStart->ctl.lo);
 | |
| 		(*fpPrint) ("ctl.hi 0x%0X\n", pStart->ctl.hi);
 | |
| 		(*fpPrint) ("sstat  0x%0X\n", pStart->sstat);
 | |
| 		(*fpPrint) ("dstat  0x%0X\n", pStart->dstat);
 | |
| 		(*fpPrint) ("devCtl 0x%0X\n", pStart->devCtl);
 | |
| 
 | |
| 		pStart = (dmacHw_DESC_t *) pStart->llp;
 | |
| 	}
 | |
| 	if (pStart == pRing->pHead) {
 | |
| 		(*fpPrint) ("Head\n");
 | |
| 	}
 | |
| 	if (pStart == pRing->pTail) {
 | |
| 		(*fpPrint) ("Tail\n");
 | |
| 	}
 | |
| 	if (pStart == pRing->pProg) {
 | |
| 		(*fpPrint) ("Prog\n");
 | |
| 	}
 | |
| 	if (pStart == pRing->pEnd) {
 | |
| 		(*fpPrint) ("End\n");
 | |
| 	}
 | |
| 	if (pStart == pRing->pFree) {
 | |
| 		(*fpPrint) ("Free\n");
 | |
| 	}
 | |
| 	(*fpPrint) ("0x%X:\n", (uint32_t) pStart);
 | |
| 	(*fpPrint) ("sar    0x%0X\n", pStart->sar);
 | |
| 	(*fpPrint) ("dar    0x%0X\n", pStart->dar);
 | |
| 	(*fpPrint) ("llp    0x%0X\n", pStart->llp);
 | |
| 	(*fpPrint) ("ctl.lo 0x%0X\n", pStart->ctl.lo);
 | |
| 	(*fpPrint) ("ctl.hi 0x%0X\n", pStart->ctl.hi);
 | |
| 	(*fpPrint) ("sstat  0x%0X\n", pStart->sstat);
 | |
| 	(*fpPrint) ("dstat  0x%0X\n", pStart->dstat);
 | |
| 	(*fpPrint) ("devCtl 0x%0X\n", pStart->devCtl);
 | |
| }
 | |
| 
 | |
| /****************************************************************************/
 | |
| /**
 | |
| *  @brief   Check if DMA channel is the flow controller
 | |
| *
 | |
| *  @return  1 : If DMA is a flow controler
 | |
| *           0 : Peripheral is the flow controller
 | |
| *
 | |
| *  @note
 | |
| *     None
 | |
| */
 | |
| /****************************************************************************/
 | |
| static inline int DmaIsFlowController(void *pDescriptor	/*   [ IN ] Descriptor buffer */
 | |
|     ) {
 | |
| 	uint32_t ttfc =
 | |
| 	    (dmacHw_GET_DESC_RING(pDescriptor))->pTail->ctl.
 | |
| 	    lo & dmacHw_REG_CTL_TTFC_MASK;
 | |
| 
 | |
| 	switch (ttfc) {
 | |
| 	case dmacHw_REG_CTL_TTFC_MM_DMAC:
 | |
| 	case dmacHw_REG_CTL_TTFC_MP_DMAC:
 | |
| 	case dmacHw_REG_CTL_TTFC_PM_DMAC:
 | |
| 	case dmacHw_REG_CTL_TTFC_PP_DMAC:
 | |
| 		return 1;
 | |
| 	}
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| /****************************************************************************/
 | |
| /**
 | |
| *  @brief   Overwrites data length in the descriptor
 | |
| *
 | |
| *  This function overwrites data length in the descriptor
 | |
| *
 | |
| *
 | |
| *  @return   void
 | |
| *
 | |
| *  @note
 | |
| *          This is only used for PCM channel
 | |
| */
 | |
| /****************************************************************************/
 | |
| void dmacHw_setDataLength(dmacHw_CONFIG_t *pConfig,	/*   [ IN ] Configuration settings */
 | |
| 			  void *pDescriptor,	/*   [ IN ] Descriptor buffer */
 | |
| 			  size_t dataLen	/*   [ IN ] Data length in bytes */
 | |
|     ) {
 | |
| 	dmacHw_DESC_t *pProg;
 | |
| 	dmacHw_DESC_t *pHead;
 | |
| 	int srcTs = 0;
 | |
| 	int srcTrSize = 0;
 | |
| 
 | |
| 	pHead = (dmacHw_GET_DESC_RING(pDescriptor))->pHead;
 | |
| 	pProg = pHead;
 | |
| 
 | |
| 	srcTrSize = dmacHw_GetTrWidthInBytes(pConfig->srcMaxTransactionWidth);
 | |
| 	srcTs = dataLen / srcTrSize;
 | |
| 	do {
 | |
| 		pProg->ctl.hi = srcTs & dmacHw_REG_CTL_BLOCK_TS_MASK;
 | |
| 		pProg = (dmacHw_DESC_t *) pProg->llp;
 | |
| 	} while (pProg != pHead);
 | |
| }
 | |
| 
 | |
| /****************************************************************************/
 | |
| /**
 | |
| *  @brief   Clears the interrupt
 | |
| *
 | |
| *  This function clears the DMA channel specific interrupt
 | |
| *
 | |
| *
 | |
| *  @return   void
 | |
| *
 | |
| *  @note
 | |
| *     Must be called under the context of ISR
 | |
| */
 | |
| /****************************************************************************/
 | |
| void dmacHw_clearInterrupt(dmacHw_HANDLE_t handle	/* [ IN ] DMA Channel handle */
 | |
|     ) {
 | |
| 	dmacHw_CBLK_t *pCblk = dmacHw_HANDLE_TO_CBLK(handle);
 | |
| 
 | |
| 	dmacHw_TRAN_INT_CLEAR(pCblk->module, pCblk->channel);
 | |
| 	dmacHw_BLOCK_INT_CLEAR(pCblk->module, pCblk->channel);
 | |
| 	dmacHw_ERROR_INT_CLEAR(pCblk->module, pCblk->channel);
 | |
| }
 | |
| 
 | |
| /****************************************************************************/
 | |
| /**
 | |
| *  @brief   Returns the cause of channel specific DMA interrupt
 | |
| *
 | |
| *  This function returns the cause of interrupt
 | |
| *
 | |
| *  @return  Interrupt status, each bit representing a specific type of interrupt
 | |
| *
 | |
| *  @note
 | |
| *     Should be called under the context of ISR
 | |
| */
 | |
| /****************************************************************************/
 | |
| dmacHw_INTERRUPT_STATUS_e dmacHw_getInterruptStatus(dmacHw_HANDLE_t handle	/* [ IN ] DMA Channel handle */
 | |
|     ) {
 | |
| 	dmacHw_CBLK_t *pCblk = dmacHw_HANDLE_TO_CBLK(handle);
 | |
| 	dmacHw_INTERRUPT_STATUS_e status = dmacHw_INTERRUPT_STATUS_NONE;
 | |
| 
 | |
| 	if (dmacHw_REG_INT_STAT_TRAN(pCblk->module) &
 | |
| 	    ((0x00000001 << pCblk->channel))) {
 | |
| 		status |= dmacHw_INTERRUPT_STATUS_TRANS;
 | |
| 	}
 | |
| 	if (dmacHw_REG_INT_STAT_BLOCK(pCblk->module) &
 | |
| 	    ((0x00000001 << pCblk->channel))) {
 | |
| 		status |= dmacHw_INTERRUPT_STATUS_BLOCK;
 | |
| 	}
 | |
| 	if (dmacHw_REG_INT_STAT_ERROR(pCblk->module) &
 | |
| 	    ((0x00000001 << pCblk->channel))) {
 | |
| 		status |= dmacHw_INTERRUPT_STATUS_ERROR;
 | |
| 	}
 | |
| 
 | |
| 	return status;
 | |
| }
 | |
| 
 | |
| /****************************************************************************/
 | |
| /**
 | |
| *  @brief   Indentifies a DMA channel causing interrupt
 | |
| *
 | |
| *  This functions returns a channel causing interrupt of type dmacHw_INTERRUPT_STATUS_e
 | |
| *
 | |
| *  @return  NULL   : No channel causing DMA interrupt
 | |
| *           ! NULL : Handle to a channel causing DMA interrupt
 | |
| *  @note
 | |
| *     dmacHw_clearInterrupt() must be called with a valid handle after calling this function
 | |
| */
 | |
| /****************************************************************************/
 | |
| dmacHw_HANDLE_t dmacHw_getInterruptSource(void)
 | |
| {
 | |
| 	uint32_t i;
 | |
| 
 | |
| 	for (i = 0; i < dmaChannelCount_0 + dmaChannelCount_1; i++) {
 | |
| 		if ((dmacHw_REG_INT_STAT_TRAN(dmacHw_gCblk[i].module) &
 | |
| 		     ((0x00000001 << dmacHw_gCblk[i].channel)))
 | |
| 		    || (dmacHw_REG_INT_STAT_BLOCK(dmacHw_gCblk[i].module) &
 | |
| 			((0x00000001 << dmacHw_gCblk[i].channel)))
 | |
| 		    || (dmacHw_REG_INT_STAT_ERROR(dmacHw_gCblk[i].module) &
 | |
| 			((0x00000001 << dmacHw_gCblk[i].channel)))
 | |
| 		    ) {
 | |
| 			return dmacHw_CBLK_TO_HANDLE(&dmacHw_gCblk[i]);
 | |
| 		}
 | |
| 	}
 | |
| 	return dmacHw_CBLK_TO_HANDLE(NULL);
 | |
| }
 | |
| 
 | |
| /****************************************************************************/
 | |
| /**
 | |
| *  @brief  Estimates number of descriptor needed to perform certain DMA transfer
 | |
| *
 | |
| *
 | |
| *  @return  On failure : -1
 | |
| *           On success : Number of descriptor count
 | |
| *
 | |
| *
 | |
| */
 | |
| /****************************************************************************/
 | |
| int dmacHw_calculateDescriptorCount(dmacHw_CONFIG_t *pConfig,	/*   [ IN ] Configuration settings */
 | |
| 				    void *pSrcAddr,	/*   [ IN ] Source (Peripheral/Memory) address */
 | |
| 				    void *pDstAddr,	/*   [ IN ] Destination (Peripheral/Memory) address */
 | |
| 				    size_t dataLen	/*   [ IN ] Data length in bytes */
 | |
|     ) {
 | |
| 	int srcTs = 0;
 | |
| 	int oddSize = 0;
 | |
| 	int descCount = 0;
 | |
| 	int dstTrSize = 0;
 | |
| 	int srcTrSize = 0;
 | |
| 	uint32_t maxBlockSize = dmacHw_MAX_BLOCKSIZE;
 | |
| 	dmacHw_TRANSACTION_WIDTH_e dstTrWidth;
 | |
| 	dmacHw_TRANSACTION_WIDTH_e srcTrWidth;
 | |
| 
 | |
| 	dstTrSize = dmacHw_GetTrWidthInBytes(pConfig->dstMaxTransactionWidth);
 | |
| 	srcTrSize = dmacHw_GetTrWidthInBytes(pConfig->srcMaxTransactionWidth);
 | |
| 
 | |
| 	/* Skip Tx if buffer is NULL  or length is unknown */
 | |
| 	if ((pSrcAddr == NULL) || (pDstAddr == NULL) || (dataLen == 0)) {
 | |
| 		/* Do not initiate transfer */
 | |
| 		return -1;
 | |
| 	}
 | |
| 
 | |
| 	/* Ensure scatter and gather are transaction aligned */
 | |
| 	if (pConfig->srcGatherWidth % srcTrSize
 | |
| 	    || pConfig->dstScatterWidth % dstTrSize) {
 | |
| 		return -1;
 | |
| 	}
 | |
| 
 | |
| 	/*
 | |
| 	   Background 1: DMAC can not perform DMA if source and destination addresses are
 | |
| 	   not properly aligned with the channel's transaction width. So, for successful
 | |
| 	   DMA transfer, transaction width must be set according to the alignment of the
 | |
| 	   source and destination address.
 | |
| 	 */
 | |
| 
 | |
| 	/* Adjust destination transaction width if destination address is not aligned properly */
 | |
| 	dstTrWidth = pConfig->dstMaxTransactionWidth;
 | |
| 	while (dmacHw_ADDRESS_MASK(dstTrSize) & (uint32_t) pDstAddr) {
 | |
| 		dstTrWidth = dmacHw_GetNextTrWidth(dstTrWidth);
 | |
| 		dstTrSize = dmacHw_GetTrWidthInBytes(dstTrWidth);
 | |
| 	}
 | |
| 
 | |
| 	/* Adjust source transaction width if source address is not aligned properly */
 | |
| 	srcTrWidth = pConfig->srcMaxTransactionWidth;
 | |
| 	while (dmacHw_ADDRESS_MASK(srcTrSize) & (uint32_t) pSrcAddr) {
 | |
| 		srcTrWidth = dmacHw_GetNextTrWidth(srcTrWidth);
 | |
| 		srcTrSize = dmacHw_GetTrWidthInBytes(srcTrWidth);
 | |
| 	}
 | |
| 
 | |
| 	/* Find the maximum transaction per descriptor */
 | |
| 	if (pConfig->maxDataPerBlock
 | |
| 	    && ((pConfig->maxDataPerBlock / srcTrSize) <
 | |
| 		dmacHw_MAX_BLOCKSIZE)) {
 | |
| 		maxBlockSize = pConfig->maxDataPerBlock / srcTrSize;
 | |
| 	}
 | |
| 
 | |
| 	/* Find number of source transactions needed to complete the DMA transfer */
 | |
| 	srcTs = dataLen / srcTrSize;
 | |
| 	/* Find the odd number of bytes that need to be transferred as single byte transaction width */
 | |
| 	if (srcTs && (dstTrSize > srcTrSize)) {
 | |
| 		oddSize = dataLen % dstTrSize;
 | |
| 		/* Adjust source transaction count due to "oddSize" */
 | |
| 		srcTs = srcTs - (oddSize / srcTrSize);
 | |
| 	} else {
 | |
| 		oddSize = dataLen % srcTrSize;
 | |
| 	}
 | |
| 	/* Adjust "descCount" due to "oddSize" */
 | |
| 	if (oddSize) {
 | |
| 		descCount++;
 | |
| 	}
 | |
| 
 | |
| 	/* Find the number of descriptor needed for total "srcTs" */
 | |
| 	if (srcTs) {
 | |
| 		descCount += ((srcTs - 1) / maxBlockSize) + 1;
 | |
| 	}
 | |
| 
 | |
| 	return descCount;
 | |
| }
 | |
| 
 | |
| /****************************************************************************/
 | |
| /**
 | |
| *  @brief   Check the existance of pending descriptor
 | |
| *
 | |
| *  This function confirmes if there is any pending descriptor in the chain
 | |
| *  to program the channel
 | |
| *
 | |
| *  @return  1 : Channel need to be programmed with pending descriptor
 | |
| *           0 : No more pending descriptor to programe the channel
 | |
| *
 | |
| *  @note
 | |
| *     - This function should be called from ISR in case there are pending
 | |
| *       descriptor to program the channel.
 | |
| *
 | |
| *     Example:
 | |
| *
 | |
| *     dmac_isr ()
 | |
| *     {
 | |
| *         ...
 | |
| *         if (dmacHw_descriptorPending (handle))
 | |
| *         {
 | |
| *            dmacHw_initiateTransfer (handle);
 | |
| *         }
 | |
| *     }
 | |
| *
 | |
| */
 | |
| /****************************************************************************/
 | |
| uint32_t dmacHw_descriptorPending(dmacHw_HANDLE_t handle,	/*   [ IN ] DMA Channel handle */
 | |
| 				  void *pDescriptor	/*   [ IN ] Descriptor buffer */
 | |
|     ) {
 | |
| 	dmacHw_CBLK_t *pCblk = dmacHw_HANDLE_TO_CBLK(handle);
 | |
| 	dmacHw_DESC_RING_t *pRing = dmacHw_GET_DESC_RING(pDescriptor);
 | |
| 
 | |
| 	/* Make sure channel is not busy */
 | |
| 	if (!CHANNEL_BUSY(pCblk->module, pCblk->channel)) {
 | |
| 		/* Check if pEnd is not processed */
 | |
| 		if (pRing->pEnd) {
 | |
| 			/* Something left for processing */
 | |
| 			return 1;
 | |
| 		}
 | |
| 	}
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| /****************************************************************************/
 | |
| /**
 | |
| *  @brief   Program channel register to stop transfer
 | |
| *
 | |
| *  Ensures the channel is not doing any transfer after calling this function
 | |
| *
 | |
| *  @return  void
 | |
| *
 | |
| */
 | |
| /****************************************************************************/
 | |
| void dmacHw_stopTransfer(dmacHw_HANDLE_t handle	/*   [ IN ] DMA Channel handle */
 | |
|     ) {
 | |
| 	dmacHw_CBLK_t *pCblk;
 | |
| 
 | |
| 	pCblk = dmacHw_HANDLE_TO_CBLK(handle);
 | |
| 
 | |
| 	/* Stop the channel */
 | |
| 	dmacHw_DMA_STOP(pCblk->module, pCblk->channel);
 | |
| }
 | |
| 
 | |
| /****************************************************************************/
 | |
| /**
 | |
| *  @brief   Deallocates source or destination memory, allocated
 | |
| *
 | |
| *  This function can be called to deallocate data memory that was DMAed successfully
 | |
| *
 | |
| *  @return  On failure : -1
 | |
| *           On success : Number of buffer freed
 | |
| *
 | |
| *  @note
 | |
| *     This function will be called ONLY, when source OR destination address is pointing
 | |
| *     to dynamic memory
 | |
| */
 | |
| /****************************************************************************/
 | |
| 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;
 | |
| }
 | |
| 
 | |
| /****************************************************************************/
 | |
| /**
 | |
| *  @brief   Prepares descriptor ring, when source peripheral working as a flow controller
 | |
| *
 | |
| *  This function will update the discriptor ring by allocating buffers, when source peripheral
 | |
| *  has to work as a flow controller to transfer data from:
 | |
| *           - Peripheral to memory.
 | |
| *
 | |
| *  @return  On failure : -1
 | |
| *           On success : Number of descriptor updated
 | |
| *
 | |
| *
 | |
| *  @note
 | |
| *     Channel must be configured for peripheral to memory transfer
 | |
| *
 | |
| */
 | |
| /****************************************************************************/
 | |
| 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;
 | |
| }
 | |
| 
 | |
| /****************************************************************************/
 | |
| /**
 | |
| *  @brief   Read data DMAed to memory
 | |
| *
 | |
| *  This function will read data that has been DMAed to memory while transfering from:
 | |
| *          - Memory to memory
 | |
| *          - Peripheral to memory
 | |
| *
 | |
| *  @param    handle     -
 | |
| *  @param    ppBbuf     -
 | |
| *  @param    pLen       -
 | |
| *
 | |
| *  @return  0 - No more data is available to read
 | |
| *           1 - More data might be available to read
 | |
| *
 | |
| */
 | |
| /****************************************************************************/
 | |
| 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;
 | |
| }
 | |
| 
 | |
| /****************************************************************************/
 | |
| /**
 | |
| *  @brief   Set descriptor carrying control information
 | |
| *
 | |
| *  This function will be used to send specific control information to the device
 | |
| *  using the DMA channel
 | |
| *
 | |
| *
 | |
| *  @return  -1 - On failure
 | |
| *            0 - On success
 | |
| *
 | |
| *  @note
 | |
| *     None
 | |
| */
 | |
| /****************************************************************************/
 | |
| 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;
 | |
| }
 | |
| 
 | |
| /****************************************************************************/
 | |
| /**
 | |
| *  @brief   Sets channel specific user data
 | |
| *
 | |
| *  This function associates user data to a specif DMA channel
 | |
| *
 | |
| */
 | |
| /****************************************************************************/
 | |
| void dmacHw_setChannelUserData(dmacHw_HANDLE_t handle,	/*  [ IN ] DMA Channel handle */
 | |
| 			       void *userData	/*  [ IN ] User data */
 | |
|     ) {
 | |
| 	dmacHw_CBLK_t *pCblk = dmacHw_HANDLE_TO_CBLK(handle);
 | |
| 
 | |
| 	pCblk->userData = userData;
 | |
| }
 | |
| 
 | |
| /****************************************************************************/
 | |
| /**
 | |
| *  @brief   Gets channel specific user data
 | |
| *
 | |
| *  This function returns user data specific to a DMA channel
 | |
| *
 | |
| *  @return   user data
 | |
| */
 | |
| /****************************************************************************/
 | |
| void *dmacHw_getChannelUserData(dmacHw_HANDLE_t handle	/*  [ IN ] DMA Channel handle */
 | |
|     ) {
 | |
| 	dmacHw_CBLK_t *pCblk = dmacHw_HANDLE_TO_CBLK(handle);
 | |
| 
 | |
| 	return pCblk->userData;
 | |
| }
 | |
| 
 | |
| /****************************************************************************/
 | |
| /**
 | |
| *  @brief   Resets descriptor control information
 | |
| *
 | |
| *  @return  void
 | |
| */
 | |
| /****************************************************************************/
 | |
| void dmacHw_resetDescriptorControl(void *pDescriptor	/*   [ IN ] Descriptor buffer  */
 | |
|     ) {
 | |
| 	int i;
 | |
| 	dmacHw_DESC_RING_t *pRing;
 | |
| 	dmacHw_DESC_t *pDesc;
 | |
| 
 | |
| 	pRing = dmacHw_GET_DESC_RING(pDescriptor);
 | |
| 	pDesc = pRing->pHead;
 | |
| 
 | |
| 	for (i = 0; i < pRing->num; i++) {
 | |
| 		/* Mark descriptor is ready to use */
 | |
| 		pDesc->ctl.hi = dmacHw_DESC_FREE;
 | |
| 		/* Look into next link list item */
 | |
| 		pDesc++;
 | |
| 	}
 | |
| 	pRing->pFree = pRing->pTail = pRing->pEnd = pRing->pHead;
 | |
| 	pRing->pProg = dmacHw_DESC_INIT;
 | |
| }
 | |
| 
 | |
| /****************************************************************************/
 | |
| /**
 | |
| *  @brief   Displays channel specific registers and other control parameters
 | |
| *
 | |
| *  @return  void
 | |
| *
 | |
| *
 | |
| *  @note
 | |
| *     None
 | |
| */
 | |
| /****************************************************************************/
 | |
| void dmacHw_printDebugInfo(dmacHw_HANDLE_t handle,	/*  [ IN ] DMA Channel handle */
 | |
| 			   void *pDescriptor,	/*   [ IN ] Descriptor buffer */
 | |
| 			   int (*fpPrint) (const char *, ...)	/*  [ IN ] Print callback function */
 | |
|     ) {
 | |
| 	dmacHw_CBLK_t *pCblk = dmacHw_HANDLE_TO_CBLK(handle);
 | |
| 
 | |
| 	DisplayRegisterContents(pCblk->module, pCblk->channel, fpPrint);
 | |
| 	DisplayDescRing(pDescriptor, fpPrint);
 | |
| }
 |