/****************************************************************************** * * Copyright (C) 2010 - 2014 Xilinx, Inc. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * Use of the Software is limited solely to applications: * (a) running on a Xilinx device, or * (b) that interact with a Xilinx device through a bus or interconnect. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * XILINX CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Except as contained in this notice, the name of the Xilinx shall not be used * in advertising or otherwise to promote the sale, use or other dealings in * this Software without prior written authorization from Xilinx. * ******************************************************************************/ /*****************************************************************************/ /** * * @file xaxidma.c * * This file implements DMA engine-wise initialization and control functions. * For more information on the implementation of this driver, see xaxidma.h. * *
* MODIFICATION HISTORY: * * Ver Who Date Changes * ----- ---- -------- ------------------------------------------------------- * 1.00a jz 05/18/10 First release * 2.00a jz 08/10/10 Second release, added in xaxidma_g.c, xaxidma_sinit.c, * updated tcl file, added xaxidma_porting_guide.h * 3.00a jz 11/22/10 Support IP core parameters change * 4.00a rkv 02/22/11 Added support for simple DMA mode * New API added for simple DMA mode are * - XAxiDma_Busy * - XAxiDma_SimpleTransfer * 6.00a srt 01/24/12 Added support for Multi-Channel DMA mode. * - Changed APIs: * * XAxiDma_Start(XAxiDma * InstancePtr, int RingIndex) * * XAxiDma_Started(XAxiDma * InstancePtr, int RingIndex) * * XAxiDma_Pause(XAxiDma * InstancePtr, int RingIndex) * * XAxiDma_Resume(XAxiDma * InstancePtr, int RingIndex) * * XAxiDma_SimpleTransfer(XAxiDma *InstancePtr, * u32 BuffAddr, u32 Length, * int Direction, int RingIndex) * - New API: * * XAxiDma_SelectKeyHole(XAxiDma *InstancePtr, * int Direction, int Select) * 7.00a srt 06/18/12 All the APIs changed in v6_00_a are reverted back for * backward compatibility. * 7.01a srt 10/26/12 Fixed issue with driver as it fails with IP version * < 6.00a as the parameter C_NUM_*_CHANNELS is not * applicable. * 8.0 srt 01/29/14 Added support for Micro DMA Mode and Cyclic mode of * operations. * - New API: * * XAxiDma_SelectCyclicMode(XAxiDma *InstancePtr, * int Direction, int Select) * *******************************************************************************/ /***************************** Include Files *********************************/ #include "xaxidma.h" /************************** Constant Definitions *****************************/ /* Loop counter to check reset done */ #define XAXIDMA_RESET_TIMEOUT 500 /**************************** Type Definitions *******************************/ /***************** Macros (Inline Functions) Definitions *********************/ /************************** Function Prototypes ******************************/ static int XAxiDma_Start(XAxiDma * InstancePtr); static int XAxiDma_Started(XAxiDma * InstancePtr); /************************** Variable Definitions *****************************/ /*****************************************************************************/ /** * This function initializes a DMA engine. This function must be called * prior to using a DMA engine. Initializing a engine includes setting * up the register base address, setting up the instance data, and ensuring the * hardware is in a quiescent state. * * @param InstancePtr is a pointer to the DMA engine instance to be * worked on. * @param Config is a pointer to an XAxiDma_Config structure. It contains * the information about the hardware build, including base * address,and whether status control stream (StsCntrlStrm), MM2S * and S2MM are included in the build. * * @return * - XST_SUCCESS for successful initialization * - XST_INVALID_PARAM if pointer to the configuration structure * is NULL * - XST_DMA_ERROR if reset operation failed at the end of * initialization * * @note We assume the hardware building tool will check and error out * for a hardware build that has no transfer channels. *****************************************************************************/ int XAxiDma_CfgInitialize(XAxiDma * InstancePtr, XAxiDma_Config *Config) { u32 BaseAddr; int TimeOut; int Index; u32 MaxTransferLen; InstancePtr->Initialized = 0; if(!Config) { return XST_INVALID_PARAM; } BaseAddr = Config->BaseAddr; /* Setup the instance */ memset(InstancePtr, 0, sizeof(XAxiDma)); InstancePtr->RegBase = BaseAddr; /* Get hardware setting information from the configuration structure */ InstancePtr->HasMm2S = Config->HasMm2S; InstancePtr->HasS2Mm = Config->HasS2Mm; InstancePtr->HasSg = Config->HasSg; InstancePtr->MicroDmaMode = Config->MicroDmaMode; /* Get the number of channels */ InstancePtr->TxNumChannels = Config->Mm2sNumChannels; InstancePtr->RxNumChannels = Config->S2MmNumChannels; /* This condition is for IP version < 6.00a */ if (!InstancePtr->TxNumChannels) InstancePtr->TxNumChannels = 1; if (!InstancePtr->RxNumChannels) InstancePtr->RxNumChannels = 1; if ((InstancePtr->RxNumChannels > 1) || (InstancePtr->TxNumChannels > 1)) { MaxTransferLen = XAXIDMA_MCHAN_MAX_TRANSFER_LEN; } else { MaxTransferLen = XAXIDMA_MAX_TRANSFER_LEN; } /* Initialize the ring structures */ InstancePtr->TxBdRing.RunState = AXIDMA_CHANNEL_HALTED; InstancePtr->TxBdRing.IsRxChannel = 0; if (!InstancePtr->MicroDmaMode) { InstancePtr->TxBdRing.MaxTransferLen = MaxTransferLen; } else { /* In MicroDMA mode, Maximum length that can be transferred * is '(Memory Data Width / 4) * Burst Size' */ InstancePtr->TxBdRing.MaxTransferLen = ((Config->Mm2SDataWidth / 4) * Config->Mm2SBurstSize); } InstancePtr->TxBdRing.RingIndex = 0; for (Index = 0; Index < InstancePtr->RxNumChannels; Index++) { InstancePtr->RxBdRing[Index].RunState = AXIDMA_CHANNEL_HALTED; InstancePtr->RxBdRing[Index].IsRxChannel = 1; InstancePtr->RxBdRing[Index].RingIndex = Index; } if (InstancePtr->HasMm2S) { InstancePtr->TxBdRing.ChanBase = BaseAddr + XAXIDMA_TX_OFFSET; InstancePtr->TxBdRing.HasStsCntrlStrm = Config->HasStsCntrlStrm; InstancePtr->TxBdRing.HasDRE = Config->HasMm2SDRE; InstancePtr->TxBdRing.DataWidth = ((unsigned int)Config->Mm2SDataWidth >> 3); } if (InstancePtr->HasS2Mm) { for (Index = 0; Index < InstancePtr->RxNumChannels; Index++) { InstancePtr->RxBdRing[Index].ChanBase = BaseAddr + XAXIDMA_RX_OFFSET; InstancePtr->RxBdRing[Index].HasStsCntrlStrm = Config->HasStsCntrlStrm; InstancePtr->RxBdRing[Index].HasDRE = Config->HasS2MmDRE; InstancePtr->RxBdRing[Index].DataWidth = ((unsigned int)Config->S2MmDataWidth >> 3); if (!InstancePtr->MicroDmaMode) { InstancePtr->RxBdRing[Index].MaxTransferLen = MaxTransferLen; } else { /* In MicroDMA mode, Maximum length that can be transferred * is '(Memory Data Width / 4) * Burst Size' */ InstancePtr->RxBdRing[Index].MaxTransferLen = ((Config->S2MmDataWidth / 4) * Config->S2MmBurstSize); } } } /* Reset the engine so the hardware starts from a known state */ XAxiDma_Reset(InstancePtr); /* At the initialization time, hardware should finish reset quickly */ TimeOut = XAXIDMA_RESET_TIMEOUT; while (TimeOut) { if(XAxiDma_ResetIsDone(InstancePtr)) { break; } TimeOut -= 1; } if (!TimeOut) { xdbg_printf(XDBG_DEBUG_ERROR, "Failed reset in" "initialize\r\n"); /* Need system hard reset to recover */ InstancePtr->Initialized = 0; return XST_DMA_ERROR; } /* Initialization is successful */ InstancePtr->Initialized = 1; return XST_SUCCESS; } /*****************************************************************************/ /** * Reset both TX and RX channels of a DMA engine. * * Reset one channel resets the whole AXI DMA engine. * * Any DMA transaction in progress will finish gracefully before engine starts * reset. Any other transactions that have been submitted to hardware will be * discarded by the hardware. * * @param InstancePtr is a pointer to the DMA engine instance to be * worked on. * * @return None * * @note After the reset: * - All interrupts are disabled. * - Engine is halted * ******************************************************************************/ void XAxiDma_Reset(XAxiDma * InstancePtr) { u32 RegBase; XAxiDma_BdRing *TxRingPtr; XAxiDma_BdRing *RxRingPtr; int RingIndex; TxRingPtr = XAxiDma_GetTxRing(InstancePtr); /* Save the locations of current BDs both rings are working on * before the reset so later we can resume the rings smoothly. */ if(XAxiDma_HasSg(InstancePtr)){ XAxiDma_BdRingSnapShotCurrBd(TxRingPtr); for (RingIndex = 0; RingIndex < InstancePtr->RxNumChannels; RingIndex++) { RxRingPtr = XAxiDma_GetRxIndexRing(InstancePtr, RingIndex); XAxiDma_BdRingSnapShotCurrBd(RxRingPtr); } } /* Reset */ if (InstancePtr->HasMm2S) { RegBase = InstancePtr->RegBase + XAXIDMA_TX_OFFSET; } else { RegBase = InstancePtr->RegBase + XAXIDMA_RX_OFFSET; } XAxiDma_WriteReg(RegBase, XAXIDMA_CR_OFFSET, XAXIDMA_CR_RESET_MASK); /* Set TX/RX Channel state */ if (InstancePtr->HasMm2S) { TxRingPtr->RunState = AXIDMA_CHANNEL_HALTED; } for (RingIndex = 0; RingIndex < InstancePtr->RxNumChannels; RingIndex++) { RxRingPtr = XAxiDma_GetRxIndexRing(InstancePtr, RingIndex); if (InstancePtr->HasS2Mm) { RxRingPtr->RunState = AXIDMA_CHANNEL_HALTED; } } } /*****************************************************************************/ /** * * Check whether reset is done * * @param InstancePtr is a pointer to the DMA engine instance to be * worked on. * * @return * - 1 if reset is done. * - 0 if reset is not done * * @note None * ******************************************************************************/ int XAxiDma_ResetIsDone(XAxiDma * InstancePtr) { u32 RegisterValue; XAxiDma_BdRing *TxRingPtr; XAxiDma_BdRing *RxRingPtr; TxRingPtr = XAxiDma_GetTxRing(InstancePtr); RxRingPtr = XAxiDma_GetRxRing(InstancePtr); /* Check transmit channel */ if (InstancePtr->HasMm2S) { RegisterValue = XAxiDma_ReadReg(TxRingPtr->ChanBase, XAXIDMA_CR_OFFSET); /* Reset is done when the reset bit is low */ if(RegisterValue & XAXIDMA_CR_RESET_MASK) { return 0; } } /* Check receive channel */ if (InstancePtr->HasS2Mm) { RegisterValue = XAxiDma_ReadReg(RxRingPtr->ChanBase, XAXIDMA_CR_OFFSET); /* Reset is done when the reset bit is low */ if(RegisterValue & XAXIDMA_CR_RESET_MASK) { return 0; } } return 1; } /*****************************************************************************/ /* * Start the DMA engine. * * Start a halted engine. Processing of BDs is not started. * * @param InstancePtr is a pointer to the DMA engine instance to be * worked on. * * @return * - XST_SUCCESS for success * - XST_NOT_SGDMA if the driver instance has not been initialized * - XST_DMA_ERROR if starting the hardware channel fails * * @note None * *****************************************************************************/ static int XAxiDma_Start(XAxiDma * InstancePtr) { XAxiDma_BdRing *TxRingPtr; XAxiDma_BdRing *RxRingPtr; int Status; int RingIndex = 0; if (!InstancePtr->Initialized) { xdbg_printf(XDBG_DEBUG_ERROR, "Start: Driver not initialized " "%d\r\n", InstancePtr->Initialized); return XST_NOT_SGDMA; } if (InstancePtr->HasMm2S) { TxRingPtr = XAxiDma_GetTxRing(InstancePtr); if (TxRingPtr->RunState == AXIDMA_CHANNEL_HALTED) { /* Start the channel */ if(XAxiDma_HasSg(InstancePtr)) { Status = XAxiDma_BdRingStart(TxRingPtr); if (Status != XST_SUCCESS) { xdbg_printf(XDBG_DEBUG_ERROR, "Start hw tx channel failed %d\r\n", Status); return XST_DMA_ERROR; } } else { XAxiDma_WriteReg(TxRingPtr->ChanBase, XAXIDMA_CR_OFFSET, XAxiDma_ReadReg(TxRingPtr->ChanBase, XAXIDMA_CR_OFFSET) | XAXIDMA_CR_RUNSTOP_MASK); } TxRingPtr->RunState = AXIDMA_CHANNEL_NOT_HALTED; } } if (InstancePtr->HasS2Mm) { for (RingIndex = 0; RingIndex < InstancePtr->RxNumChannels; RingIndex++) { RxRingPtr = XAxiDma_GetRxIndexRing(InstancePtr, RingIndex); if (RxRingPtr->RunState != AXIDMA_CHANNEL_HALTED) { return XST_SUCCESS; } /* Start the channel */ if(XAxiDma_HasSg(InstancePtr)) { Status = XAxiDma_BdRingStart(RxRingPtr); if (Status != XST_SUCCESS) { xdbg_printf(XDBG_DEBUG_ERROR, "Start hw tx channel failed %d\r\n", Status); return XST_DMA_ERROR; } } else { XAxiDma_WriteReg(RxRingPtr->ChanBase, XAXIDMA_CR_OFFSET, XAxiDma_ReadReg(RxRingPtr->ChanBase, XAXIDMA_CR_OFFSET) | XAXIDMA_CR_RUNSTOP_MASK); } RxRingPtr->RunState = AXIDMA_CHANNEL_NOT_HALTED; } } return XST_SUCCESS; } /*****************************************************************************/ /** * Pause DMA transactions on both channels. * * If the engine is running and doing transfers, this function does not stop * the DMA transactions immediately, because then hardware will throw away * our previously queued transfers. All submitted transfers will finish. * Transfers submitted after this function will not start until * XAxiDma_BdRingStart() or XAxiDma_Resume() is called. * * @param InstancePtr is a pointer to the DMA engine instance to be * worked on. * * @return * - XST_SUCCESS if successful * - XST_NOT_SGDMA, if the driver instance is not initialized * * @note None * *****************************************************************************/ int XAxiDma_Pause(XAxiDma * InstancePtr) { XAxiDma_BdRing *TxRingPtr; XAxiDma_BdRing *RxRingPtr; int RingIndex = 0; if (!InstancePtr->Initialized) { xdbg_printf(XDBG_DEBUG_ERROR, "Pause: Driver not initialized" " %d\r\n",InstancePtr->Initialized); return XST_NOT_SGDMA; } if (InstancePtr->HasMm2S) { TxRingPtr = XAxiDma_GetTxRing(InstancePtr); /* If channel is halted, then we do not need to do anything */ if(!XAxiDma_HasSg(InstancePtr)) { XAxiDma_WriteReg(TxRingPtr->ChanBase, XAXIDMA_CR_OFFSET, XAxiDma_ReadReg(TxRingPtr->ChanBase, XAXIDMA_CR_OFFSET) & ~XAXIDMA_CR_RUNSTOP_MASK); } TxRingPtr->RunState = AXIDMA_CHANNEL_HALTED; } if (InstancePtr->HasS2Mm) { for (RingIndex = 0; RingIndex < InstancePtr->RxNumChannels; RingIndex++) { RxRingPtr = XAxiDma_GetRxIndexRing(InstancePtr, RingIndex); /* If channel is halted, then we do not need to do anything */ if(!XAxiDma_HasSg(InstancePtr) && !RingIndex) { XAxiDma_WriteReg(RxRingPtr->ChanBase, XAXIDMA_CR_OFFSET, XAxiDma_ReadReg(RxRingPtr->ChanBase, XAXIDMA_CR_OFFSET) & ~XAXIDMA_CR_RUNSTOP_MASK); } RxRingPtr->RunState = AXIDMA_CHANNEL_HALTED; } } return XST_SUCCESS; } /*****************************************************************************/ /** * Resume DMA transactions on both channels. * * @param InstancePtr is a pointer to the DMA engine instance to be * worked on. * * @return * - XST_SUCCESS for success * - XST_NOT_SGDMA if the driver instance has not been initialized * - XST_DMA_ERROR if one of the channels fails to start * * @note None * *****************************************************************************/ int XAxiDma_Resume(XAxiDma * InstancePtr) { XAxiDma_BdRing *TxRingPtr; XAxiDma_BdRing *RxRingPtr; int Status; int RingIndex = 0; if (!InstancePtr->Initialized) { xdbg_printf(XDBG_DEBUG_ERROR, "Resume: Driver not initialized" " %d\r\n",InstancePtr->Initialized); return XST_NOT_SGDMA; } /* If the DMA engine is not running, start it. Start may fail. */ if (!XAxiDma_Started(InstancePtr)) { Status = XAxiDma_Start(InstancePtr); if (Status != XST_SUCCESS) { xdbg_printf(XDBG_DEBUG_ERROR, "Resume: failed to start" " engine %d\r\n", Status); return Status; } } /* Mark the state to be not halted */ if (InstancePtr->HasMm2S) { TxRingPtr = XAxiDma_GetTxRing(InstancePtr); if(XAxiDma_HasSg(InstancePtr)) { Status = XAxiDma_BdRingStart(TxRingPtr); if (Status != XST_SUCCESS) { xdbg_printf(XDBG_DEBUG_ERROR, "Resume: failed" " to start tx ring %d\r\n", Status); return XST_DMA_ERROR; } } TxRingPtr->RunState = AXIDMA_CHANNEL_NOT_HALTED; } if (InstancePtr->HasS2Mm) { for (RingIndex = 0 ; RingIndex < InstancePtr->RxNumChannels; RingIndex++) { RxRingPtr = XAxiDma_GetRxIndexRing(InstancePtr, RingIndex); if(XAxiDma_HasSg(InstancePtr)) { Status = XAxiDma_BdRingStart(RxRingPtr); if (Status != XST_SUCCESS) { xdbg_printf(XDBG_DEBUG_ERROR, "Resume: failed" "to start rx ring %d\r\n", Status); return XST_DMA_ERROR; } } RxRingPtr->RunState = AXIDMA_CHANNEL_NOT_HALTED; } } return XST_SUCCESS; } /*****************************************************************************/ /* * Check whether the DMA engine is started. * * @param InstancePtr is a pointer to the DMA engine instance to be * worked on. * * @return * - 1 if engine is started * - 0 otherwise. * * @note None * *****************************************************************************/ static int XAxiDma_Started(XAxiDma * InstancePtr) { XAxiDma_BdRing *TxRingPtr; XAxiDma_BdRing *RxRingPtr; if (!InstancePtr->Initialized) { xdbg_printf(XDBG_DEBUG_ERROR, "Started: Driver not initialized" " %d\r\n",InstancePtr->Initialized); return 0; } if (InstancePtr->HasMm2S) { TxRingPtr = XAxiDma_GetTxRing(InstancePtr); if (!XAxiDma_BdRingHwIsStarted(TxRingPtr)) { xdbg_printf(XDBG_DEBUG_ERROR, "Started: tx ring not started\r\n"); return 0; } } if (InstancePtr->HasS2Mm) { RxRingPtr = XAxiDma_GetRxRing(InstancePtr); if (!XAxiDma_BdRingHwIsStarted(RxRingPtr)) { xdbg_printf(XDBG_DEBUG_ERROR, "Started: rx ring not started\r\n"); return 0; } } return 1; } /*****************************************************************************/ /** * This function checks whether specified DMA channel is busy * * @param InstancePtr is the driver instance we are working on * * @param Direction is DMA transfer direction, valid values are * - XAXIDMA_DMA_TO_DEVICE. * - XAXIDMA_DEVICE_TO_DMA. * * @return - TRUE if channel is busy * - FALSE if channel is idle * * @note None. * *****************************************************************************/ u32 XAxiDma_Busy(XAxiDma *InstancePtr, int Direction) { return ((XAxiDma_ReadReg(InstancePtr->RegBase + (XAXIDMA_RX_OFFSET * Direction), XAXIDMA_SR_OFFSET) & XAXIDMA_IDLE_MASK) ? FALSE : TRUE); } /*****************************************************************************/ /** * This function Enable or Disable KeyHole Feature * * @param InstancePtr is the driver instance we are working on * * @param Direction is DMA transfer direction, valid values are * - XAXIDMA_DMA_TO_DEVICE. * - XAXIDMA_DEVICE_TO_DMA. * @Select Select is the option to enable (TRUE) or disable (FALSE). * * @return - XST_SUCCESS for success * * @note None. * *****************************************************************************/ int XAxiDma_SelectKeyHole(XAxiDma *InstancePtr, int Direction, int Select) { u32 Value; Value = XAxiDma_ReadReg(InstancePtr->RegBase + (XAXIDMA_RX_OFFSET * Direction), XAXIDMA_CR_OFFSET); if (Select) Value |= XAXIDMA_CR_KEYHOLE_MASK; else Value &= ~XAXIDMA_CR_KEYHOLE_MASK; XAxiDma_WriteReg(InstancePtr->RegBase + (XAXIDMA_RX_OFFSET * Direction), XAXIDMA_CR_OFFSET, Value); return XST_SUCCESS; } /*****************************************************************************/ /** * This function Enable or Disable Cyclic Mode Feature * * @param InstancePtr is the driver instance we are working on * * @param Direction is DMA transfer direction, valid values are * - XAXIDMA_DMA_TO_DEVICE. * - XAXIDMA_DEVICE_TO_DMA. * @Select Select is the option to enable (TRUE) or disable (FALSE). * * @return - XST_SUCCESS for success * * @note None. * *****************************************************************************/ int XAxiDma_SelectCyclicMode(XAxiDma *InstancePtr, int Direction, int Select) { u32 Value; Value = XAxiDma_ReadReg(InstancePtr->RegBase + (XAXIDMA_RX_OFFSET * Direction), XAXIDMA_CR_OFFSET); if (Select) Value |= XAXIDMA_CR_CYCLIC_MASK; else Value &= ~XAXIDMA_CR_CYCLIC_MASK; XAxiDma_WriteReg(InstancePtr->RegBase + (XAXIDMA_RX_OFFSET * Direction), XAXIDMA_CR_OFFSET, Value); return XST_SUCCESS; } /*****************************************************************************/ /** * This function does one simple transfer submission * * It checks in the following sequence: * - if engine is busy, cannot submit * - if engine is in SG mode , cannot submit * * @param InstancePtr is the pointer to the driver instance * @param BuffAddr is the address of the source/destination buffer * @param Length is the length of the transfer * @param Direction is DMA transfer direction, valid values are * - XAXIDMA_DMA_TO_DEVICE. * - XAXIDMA_DEVICE_TO_DMA. * @return * - XST_SUCCESS for success of submission * - XST_FAILURE for submission failure, maybe caused by: * Another simple transfer is still going * - XST_INVALID_PARAM if:Length out of valid range [1:8M] * Or, address not aligned when DRE is not built in * * @note This function is used only when system is configured as * Simple mode. * *****************************************************************************/ int XAxiDma_SimpleTransfer(XAxiDma *InstancePtr, u32 BuffAddr, u32 Length, int Direction) { u32 WordBits; int RingIndex = 0; /* If Scatter Gather is included then, cannot submit */ if (XAxiDma_HasSg(InstancePtr)) { xdbg_printf(XDBG_DEBUG_ERROR, "Simple DMA mode is not" " supported\r\n"); return XST_FAILURE; } if(Direction == XAXIDMA_DMA_TO_DEVICE){ if ((Length < 1) || (Length > InstancePtr->TxBdRing.MaxTransferLen)) { return XST_INVALID_PARAM; } if (!InstancePtr->HasMm2S) { xdbg_printf(XDBG_DEBUG_ERROR, "MM2S channel is not" "supported\r\n"); return XST_FAILURE; } /* If the engine is doing transfer, cannot submit */ if(!(XAxiDma_ReadReg(InstancePtr->TxBdRing.ChanBase, XAXIDMA_SR_OFFSET) & XAXIDMA_HALTED_MASK)) { if (XAxiDma_Busy(InstancePtr,Direction)) { xdbg_printf(XDBG_DEBUG_ERROR, "Engine is busy\r\n"); return XST_FAILURE; } } if (!InstancePtr->MicroDmaMode) { WordBits = (u32)((InstancePtr->TxBdRing.DataWidth) - 1); } else { WordBits = XAXIDMA_MICROMODE_MIN_BUF_ALIGN; } if ((BuffAddr & WordBits)) { if (!InstancePtr->TxBdRing.HasDRE) { xdbg_printf(XDBG_DEBUG_ERROR, "Unaligned transfer without" " DRE %x\r\n",(unsigned int)BuffAddr); return XST_INVALID_PARAM; } } XAxiDma_WriteReg(InstancePtr->TxBdRing.ChanBase, XAXIDMA_SRCADDR_OFFSET, BuffAddr); XAxiDma_WriteReg(InstancePtr->TxBdRing.ChanBase, XAXIDMA_CR_OFFSET, XAxiDma_ReadReg( InstancePtr->TxBdRing.ChanBase, XAXIDMA_CR_OFFSET)| XAXIDMA_CR_RUNSTOP_MASK); /* Writing to the BTT register starts the transfer */ XAxiDma_WriteReg(InstancePtr->TxBdRing.ChanBase, XAXIDMA_BUFFLEN_OFFSET, Length); } else if(Direction == XAXIDMA_DEVICE_TO_DMA){ if ((Length < 1) || (Length > InstancePtr->RxBdRing[RingIndex].MaxTransferLen)) { return XST_INVALID_PARAM; } if (!InstancePtr->HasS2Mm) { xdbg_printf(XDBG_DEBUG_ERROR, "S2MM channel is not" " supported\r\n"); return XST_FAILURE; } if(!(XAxiDma_ReadReg(InstancePtr->RxBdRing[RingIndex].ChanBase, XAXIDMA_SR_OFFSET) & XAXIDMA_HALTED_MASK)) { if (XAxiDma_Busy(InstancePtr,Direction)) { xdbg_printf(XDBG_DEBUG_ERROR, "Engine is busy\r\n"); return XST_FAILURE; } } if (!InstancePtr->MicroDmaMode) { WordBits = (u32)((InstancePtr->RxBdRing[RingIndex].DataWidth) - 1); } else { WordBits = XAXIDMA_MICROMODE_MIN_BUF_ALIGN; } if ((BuffAddr & WordBits)) { if (!InstancePtr->RxBdRing[RingIndex].HasDRE) { xdbg_printf(XDBG_DEBUG_ERROR, "Unaligned transfer without" " DRE %x\r\n", (unsigned int)BuffAddr); return XST_INVALID_PARAM; } } XAxiDma_WriteReg(InstancePtr->RxBdRing[RingIndex].ChanBase, XAXIDMA_DESTADDR_OFFSET, BuffAddr); XAxiDma_WriteReg(InstancePtr->RxBdRing[RingIndex].ChanBase, XAXIDMA_CR_OFFSET, XAxiDma_ReadReg(InstancePtr->RxBdRing[RingIndex].ChanBase, XAXIDMA_CR_OFFSET)| XAXIDMA_CR_RUNSTOP_MASK); /* Writing to the BTT register starts the transfer */ XAxiDma_WriteReg(InstancePtr->RxBdRing[RingIndex].ChanBase, XAXIDMA_BUFFLEN_OFFSET, Length); } return XST_SUCCESS; }