/** * This function resets one DMA channel * * The registers will be default values after the reset * * @param Channel is the pointer to the DMA channel to work on * * @return * None * *****************************************************************************/ void XAxiVdma_ChannelReset(XAxiVdma_Channel *Channel) { XAxiVdma_WriteReg(Channel->ChanBase, XAXIVDMA_CR_OFFSET, XAXIVDMA_CR_RESET_MASK); return; }
/** * Masks the S2MM error interrupt for the provided error mask value * * @param InstancePtr is the XAxiVdma instance to operate on * @param ErrorMask is the mask of error bits for which S2MM error * interrupt can be disabled. * @param Direction is the channel to work on, use XAXIVDMA_READ/WRITE * * @return - XST_SUCCESS, when error bits are cleared. * - XST_INVALID_PARAM, when channel pointer is invalid. * - XST_DEVICE_NOT_FOUND, when the channel is not valid. * * @note The register S2MM_DMA_IRQ_MASK is only applicable from IPv6.01a * which is added at offset XAXIVDMA_S2MM_DMA_IRQ_MASK_OFFSET. * For older versions, this offset location is reserved and so * the API does not have any effect. * *****************************************************************************/ int XAxiVdma_MaskS2MMErrIntr(XAxiVdma *InstancePtr, u32 ErrorMask, u16 Direction) { XAxiVdma_Channel *Channel; if (Direction != XAXIVDMA_WRITE) { return XST_INVALID_PARAM; } Channel = XAxiVdma_GetChannel(InstancePtr, Direction); if (!Channel) { return XST_INVALID_PARAM; } if (Channel->IsValid) { XAxiVdma_WriteReg(Channel->ChanBase, XAXIVDMA_S2MM_DMA_IRQ_MASK_OFFSET, ErrorMask & XAXIVDMA_S2MM_IRQ_ERR_ALL_MASK); return XST_SUCCESS; } return XST_DEVICE_NOT_FOUND; }
/** * Configure buffer addresses for one DMA channel * * The buffer addresses are physical addresses. * Access to 32 Frame Buffer Addresses in direct mode is done through * XAxiVdma_ChannelHiFrmAddrEnable/Disable Functions. * 0 - Access Bank0 Registers (0x5C - 0x98) * 1 - Access Bank1 Registers (0x5C - 0x98) * * @param Channel is the pointer to the channel to work on * @param BufferAddrSet is the set of addresses for the transfers * @param NumFrames is the number of frames to set the address * * @return * - XST_SUCCESS if successful * - XST_FAILURE if channel has not being initialized * - XST_DEVICE_BUSY if the DMA channel is not idle, BDs are still being used * - XST_INVAID_PARAM if buffer address not valid, for example, unaligned * address with no DRE built in the hardware * *****************************************************************************/ int XAxiVdma_ChannelSetBufferAddr(XAxiVdma_Channel *Channel, u32 *BufferAddrSet, int NumFrames) { int i; u32 WordLenBits; int HiFrmAddr = 0; int FrmBound = (XAXIVDMA_MAX_FRAMESTORE)/2 - 1; int Loop16 = 0; if (!Channel->IsValid) { xdbg_printf(XDBG_DEBUG_ERROR, "Channel not initialized\r\n"); return XST_FAILURE; } WordLenBits = (u32)(Channel->WordLength - 1); /* If hardware has no DRE, then buffer addresses must * be word-aligned */ for (i = 0; i < NumFrames; i++) { if (!Channel->HasDRE) { if (BufferAddrSet[i] & WordLenBits) { xdbg_printf(XDBG_DEBUG_ERROR, "Unaligned address %d: %x without DRE\r\n", i, BufferAddrSet[i]); return XST_INVALID_PARAM; } } } for (i = 0; i < NumFrames; i++, Loop16++) { XAxiVdma_Bd *BdPtr = (XAxiVdma_Bd *)(Channel->HeadBdAddr + i * sizeof(XAxiVdma_Bd)); if (Channel->HasSG) { XAxiVdma_BdSetAddr(BdPtr, BufferAddrSet[i]); } else { if ((i > FrmBound) && !HiFrmAddr) { XAxiVdma_ChannelHiFrmAddrEnable(Channel); HiFrmAddr = 1; Loop16 = 0; } XAxiVdma_WriteReg(Channel->StartAddrBase, XAXIVDMA_START_ADDR_OFFSET + Loop16 * XAXIVDMA_START_ADDR_LEN, BufferAddrSet[i]); if ((NumFrames > FrmBound) && (i == (NumFrames - 1))) XAxiVdma_ChannelHiFrmAddrDisable(Channel); } } return XST_SUCCESS; }
/** * Set the channel to run in frame count enable mode * * @param Channel is the pointer to the channel to work on * * @return * None * *****************************************************************************/ void XAxiVdma_ChannelStartFrmCntEnable(XAxiVdma_Channel *Channel) { u32 CrBits; CrBits = XAxiVdma_ReadReg(Channel->ChanBase, XAXIVDMA_CR_OFFSET) | XAXIVDMA_CR_FRMCNT_EN_MASK; XAxiVdma_WriteReg(Channel->ChanBase, XAXIVDMA_CR_OFFSET, CrBits); return; }
/** * Set the channel to run in circular mode, exiting parking mode * * @param Channel is the pointer to the channel to work on * * @return * None * *****************************************************************************/ void XAxiVdma_ChannelStopParking(XAxiVdma_Channel *Channel) { u32 CrBits; CrBits = XAxiVdma_ReadReg(Channel->ChanBase, XAXIVDMA_CR_OFFSET) | XAXIVDMA_CR_TAIL_EN_MASK; XAxiVdma_WriteReg(Channel->ChanBase, XAXIVDMA_CR_OFFSET, CrBits); return; }
/* * Clear DMA channel errors * * @param Channel is the pointer to the channel to work on * @param ErrorMask is the mask of error bits to clear. * * @return * None * *****************************************************************************/ void XAxiVdma_ClearChannelErrors(XAxiVdma_Channel *Channel, u32 ErrorMask) { u32 SrBits; /* Write on Clear bits */ SrBits = XAxiVdma_ReadReg(Channel->ChanBase, XAXIVDMA_SR_OFFSET) | ErrorMask; XAxiVdma_WriteReg(Channel->ChanBase, XAXIVDMA_SR_OFFSET, SrBits); return; }
/** * Stop one DMA channel * * @param Channel is the pointer to the channel to work on * * @return * None * *****************************************************************************/ void XAxiVdma_ChannelStop(XAxiVdma_Channel *Channel) { u32 CrBits; if (!XAxiVdma_ChannelIsRunning(Channel)) { return; } /* Clear the RS bit in CR register */ CrBits = XAxiVdma_ReadReg(Channel->ChanBase, XAXIVDMA_CR_OFFSET) & (~XAXIVDMA_CR_RUNSTOP_MASK); XAxiVdma_WriteReg(Channel->ChanBase, XAXIVDMA_CR_OFFSET, CrBits); return; }
/** * Set the channel to run in parking mode * * @param Channel is the pointer to the channel to work on * * @return * - XST_SUCCESS if everything is fine * - XST_FAILURE if hardware is not running * *****************************************************************************/ int XAxiVdma_ChannelStartParking(XAxiVdma_Channel *Channel) { u32 CrBits; if (!XAxiVdma_ChannelIsRunning(Channel)) { xdbg_printf(XDBG_DEBUG_ERROR, "Channel is not running, cannot start park mode\r\n"); return XST_FAILURE; } CrBits = XAxiVdma_ReadReg(Channel->ChanBase, XAXIVDMA_CR_OFFSET) & ~XAXIVDMA_CR_TAIL_EN_MASK; XAxiVdma_WriteReg(Channel->ChanBase, XAXIVDMA_CR_OFFSET, CrBits); return XST_SUCCESS; }
/** * Set the frame counter and delay counter for one channel * * @param Channel is the pointer to the channel to work on * @param FrmCnt is the frame counter value to be set * @param DlyCnt is the delay counter value to be set * * @return * - XST_SUCCESS if setup finishes successfully * - XST_FAILURE if channel is not initialized * - XST_INVALID_PARAM if the configuration structure has invalid values * - XST_NO_FEATURE if Frame Counter or Delay Counter is disabled * *****************************************************************************/ int XAxiVdma_ChannelSetFrmCnt(XAxiVdma_Channel *Channel, u8 FrmCnt, u8 DlyCnt) { u32 CrBits; if (!Channel->IsValid) { xdbg_printf(XDBG_DEBUG_ERROR, "Channel not initialized\r\n"); return XST_FAILURE; } if (!FrmCnt) { xdbg_printf(XDBG_DEBUG_ERROR, "Frame counter value must be non-zero\r\n"); return XST_INVALID_PARAM; } CrBits = XAxiVdma_ReadReg(Channel->ChanBase, XAXIVDMA_CR_OFFSET) & ~(XAXIVDMA_DELAY_MASK | XAXIVDMA_FRMCNT_MASK); if (Channel->DbgFeatureFlags & XAXIVDMA_ENABLE_DBG_FRM_CNTR) { CrBits |= (FrmCnt << XAXIVDMA_FRMCNT_SHIFT); } else { xdbg_printf(XDBG_DEBUG_ERROR, "Channel Frame counter is disabled\r\n"); return XST_NO_FEATURE; } if (Channel->DbgFeatureFlags & XAXIVDMA_ENABLE_DBG_DLY_CNTR) { CrBits |= (DlyCnt << XAXIVDMA_DELAY_SHIFT); } else { xdbg_printf(XDBG_DEBUG_ERROR, "Channel Delay counter is disabled\r\n"); return XST_NO_FEATURE; } XAxiVdma_WriteReg(Channel->ChanBase, XAXIVDMA_CR_OFFSET, CrBits); return XST_SUCCESS; }
/** * Start one DMA channel * * @param Channel is the pointer to the channel to work on * * @return * - XST_SUCCESS if successful * - XST_FAILURE if channel is not initialized * - XST_DMA_ERROR if: * . The DMA channel fails to stop * . The DMA channel fails to start * - XST_DEVICE_BUSY is the channel is doing transfers * *****************************************************************************/ int XAxiVdma_ChannelStart(XAxiVdma_Channel *Channel) { u32 CrBits; if (!Channel->IsValid) { xdbg_printf(XDBG_DEBUG_ERROR, "Channel not initialized\r\n"); return XST_FAILURE; } if (Channel->HasSG && XAxiVdma_ChannelIsBusy(Channel)) { xdbg_printf(XDBG_DEBUG_ERROR, "Start DMA channel while channel is busy\r\n"); return XST_DEVICE_BUSY; } /* If channel is not running, setup the CDESC register and * set the channel to run */ if (!XAxiVdma_ChannelIsRunning(Channel)) { if (Channel->HasSG) { /* Set up the current bd register * * Can only setup current bd register when channel is halted */ XAxiVdma_WriteReg(Channel->ChanBase, XAXIVDMA_CDESC_OFFSET, Channel->HeadBdPhysAddr); } /* Start DMA hardware */ CrBits = XAxiVdma_ReadReg(Channel->ChanBase, XAXIVDMA_CR_OFFSET); CrBits = XAxiVdma_ReadReg(Channel->ChanBase, XAXIVDMA_CR_OFFSET) | XAXIVDMA_CR_RUNSTOP_MASK; XAxiVdma_WriteReg(Channel->ChanBase, XAXIVDMA_CR_OFFSET, CrBits); } if (XAxiVdma_ChannelIsRunning(Channel)) { /* Start DMA transfers * */ if (Channel->HasSG) { /* SG mode: * Update the tail pointer so that hardware will start * fetching BDs */ XAxiVdma_WriteReg(Channel->ChanBase, XAXIVDMA_TDESC_OFFSET, Channel->TailBdPhysAddr); } else { /* Direct register mode: * Update vsize to start the channel */ XAxiVdma_WriteReg(Channel->StartAddrBase, XAXIVDMA_VSIZE_OFFSET, Channel->Vsize); } return XST_SUCCESS; } else { xdbg_printf(XDBG_DEBUG_ERROR, "Failed to start channel %x\r\n", (unsigned int)Channel->ChanBase); return XST_DMA_ERROR; } }
/** * Configure buffer addresses for one DMA channel * * The buffer addresses are physical addresses. * Access to 32 Frame Buffer Addresses in direct mode is done through * XAxiVdma_ChannelHiFrmAddrEnable/Disable Functions. * 0 - Access Bank0 Registers (0x5C - 0x98) * 1 - Access Bank1 Registers (0x5C - 0x98) * * @param Channel is the pointer to the channel to work on * @param BufferAddrSet is the set of addresses for the transfers * @param NumFrames is the number of frames to set the address * * @return * - XST_SUCCESS if successful * - XST_FAILURE if channel has not being initialized * - XST_DEVICE_BUSY if the DMA channel is not idle, BDs are still being used * - XST_INVAID_PARAM if buffer address not valid, for example, unaligned * address with no DRE built in the hardware * *****************************************************************************/ int XAxiVdma_ChannelSetBufferAddr(XAxiVdma_Channel *Channel, UINTPTR *BufferAddrSet, int NumFrames) { int i; u32 WordLenBits; int HiFrmAddr = 0; int FrmBound; if (Channel->AddrWidth > 32) { FrmBound = (XAXIVDMA_MAX_FRAMESTORE_64)/2 - 1; } else { FrmBound = (XAXIVDMA_MAX_FRAMESTORE)/2 - 1; } int Loop16 = 0; if (!Channel->IsValid) { //xil_printf("channel not initialized \r\n"); xdbg_printf(XDBG_DEBUG_ERROR, "Channel not initialized\r\n"); return XST_FAILURE; } WordLenBits = (u32)(Channel->WordLength - 1); /* If hardware has no DRE, then buffer addresses must * be word-aligned */ for (i = 0; i < NumFrames; i++) { if (!Channel->HasDRE) { if (BufferAddrSet[i] & WordLenBits) { xdbg_printf(XDBG_DEBUG_ERROR, "Unaligned address %d: %x without DRE\r\n", i, BufferAddrSet[i]); //xil_printf("Unaligned address %d: %x without DRE\r\n", //i, BufferAddrSet[i]);///////////// return XST_INVALID_PARAM; } } } for (i = 0; i < NumFrames; i++, Loop16++) { XAxiVdma_Bd *BdPtr = (XAxiVdma_Bd *)(Channel->HeadBdAddr + i * sizeof(XAxiVdma_Bd)); if (Channel->HasSG) { XAxiVdma_BdSetAddr(BdPtr, BufferAddrSet[i]); } else { if ((i > FrmBound) && !HiFrmAddr) { XAxiVdma_ChannelHiFrmAddrEnable(Channel); HiFrmAddr = 1; Loop16 = 0; } if (Channel->AddrWidth > 32) { /* For a 40-bit address XAXIVDMA_MAX_FRAMESTORE * value should be set to 16 */ XAxiVdma_WriteReg(Channel->StartAddrBase, XAXIVDMA_START_ADDR_OFFSET + Loop16 * XAXIVDMA_START_ADDR_LEN + i*4, LOWER_32_BITS(BufferAddrSet[i])); XAxiVdma_WriteReg(Channel->StartAddrBase, XAXIVDMA_START_ADDR_MSB_OFFSET + Loop16 * XAXIVDMA_START_ADDR_LEN + i*4, UPPER_32_BITS((u64)BufferAddrSet[i])); } else { XAxiVdma_WriteReg(Channel->StartAddrBase, XAXIVDMA_START_ADDR_OFFSET + Loop16 * XAXIVDMA_START_ADDR_LEN, BufferAddrSet[i]); } if ((NumFrames > FrmBound) && (i == (NumFrames - 1))) XAxiVdma_ChannelHiFrmAddrDisable(Channel); } } return XST_SUCCESS; }
/** * Configure one DMA channel using the configuration structure * * Setup the control register and BDs, however, BD addresses are not set. * * @param Channel is the pointer to the channel to work on * @param ChannelCfgPtr is the pointer to the setup structure * * @return * - XST_SUCCESS if successful * - XST_FAILURE if channel has not being initialized * - XST_DEVICE_BUSY if the DMA channel is not idle * - XST_INVALID_PARAM if fields in ChannelCfgPtr is not valid * *****************************************************************************/ int XAxiVdma_ChannelConfig(XAxiVdma_Channel *Channel, XAxiVdma_ChannelSetup *ChannelCfgPtr) { u32 CrBits; int i; int NumBds; int Status; u32 hsize_align; u32 stride_align; if (!Channel->IsValid) { //xil_printf("Channel not initialized\r\n"); xdbg_printf(XDBG_DEBUG_ERROR, "Channel not initialized\r\n"); return XST_FAILURE; } if (Channel->HasSG && XAxiVdma_ChannelIsBusy(Channel)) { xdbg_printf(XDBG_DEBUG_ERROR, "Channel is busy, cannot config!\r\n"); //xil_printf("Channel is busy, cannot config!\r\n"); return XST_DEVICE_BUSY; } Channel->Vsize = ChannelCfgPtr->VertSizeInput; /* Check whether Hsize is properly aligned */ if (Channel->direction == XAXIVDMA_WRITE) { if (ChannelCfgPtr->HoriSizeInput < Channel->WordLength) { hsize_align = (u32)Channel->WordLength; } else { hsize_align = (u32)(ChannelCfgPtr->HoriSizeInput % Channel->WordLength); if (hsize_align > 0) hsize_align = (Channel->WordLength - hsize_align); } } else { if (ChannelCfgPtr->HoriSizeInput < Channel->WordLength) { hsize_align = (u32)Channel->WordLength; } else { hsize_align = (u32)(ChannelCfgPtr->HoriSizeInput % Channel->StreamWidth); if (hsize_align > 0) hsize_align = (Channel->StreamWidth - hsize_align); } } /* Check whether Stride is properly aligned */ if (ChannelCfgPtr->Stride < Channel->WordLength) { stride_align = (u32)Channel->WordLength; } else { stride_align = (u32)(ChannelCfgPtr->Stride % Channel->WordLength); if (stride_align > 0) stride_align = (Channel->WordLength - stride_align); } /* If hardware has no DRE, then Hsize and Stride must * be word-aligned */ if (!Channel->HasDRE) { if (hsize_align != 0) { /* Adjust hsize to multiples of stream/mm data width*/ ChannelCfgPtr->HoriSizeInput += hsize_align; } if (stride_align != 0) { /* Adjust stride to multiples of stream/mm data width*/ ChannelCfgPtr->Stride += stride_align; } } Channel->Hsize = ChannelCfgPtr->HoriSizeInput; CrBits = XAxiVdma_ReadReg(Channel->ChanBase, XAXIVDMA_CR_OFFSET); CrBits = XAxiVdma_ReadReg(Channel->ChanBase, XAXIVDMA_CR_OFFSET) & ~(XAXIVDMA_CR_TAIL_EN_MASK | XAXIVDMA_CR_SYNC_EN_MASK | XAXIVDMA_CR_FRMCNT_EN_MASK | XAXIVDMA_CR_RD_PTR_MASK); if (ChannelCfgPtr->EnableCircularBuf) { CrBits |= XAXIVDMA_CR_TAIL_EN_MASK; } else { /* Park mode */ u32 FrmBits; u32 RegValue; if ((!XAxiVdma_ChannelIsRunning(Channel)) && Channel->HasSG) { xdbg_printf(XDBG_DEBUG_ERROR, "Channel is not running, cannot set park mode\r\n"); return XST_INVALID_PARAM; } if (ChannelCfgPtr->FixedFrameStoreAddr > XAXIVDMA_FRM_MAX) { //xil_printf("Invalid frame to park on\n\r"); xdbg_printf(XDBG_DEBUG_ERROR, "Invalid frame to park on %d\r\n", ChannelCfgPtr->FixedFrameStoreAddr); return XST_INVALID_PARAM; } if (Channel->IsRead) { FrmBits = ChannelCfgPtr->FixedFrameStoreAddr & XAXIVDMA_PARKPTR_READREF_MASK; RegValue = XAxiVdma_ReadReg(Channel->InstanceBase, XAXIVDMA_PARKPTR_OFFSET); RegValue &= ~XAXIVDMA_PARKPTR_READREF_MASK; RegValue |= FrmBits; XAxiVdma_WriteReg(Channel->InstanceBase, XAXIVDMA_PARKPTR_OFFSET, RegValue); } else { FrmBits = ChannelCfgPtr->FixedFrameStoreAddr << XAXIVDMA_WRTREF_SHIFT; FrmBits &= XAXIVDMA_PARKPTR_WRTREF_MASK; RegValue = XAxiVdma_ReadReg(Channel->InstanceBase, XAXIVDMA_PARKPTR_OFFSET); RegValue &= ~XAXIVDMA_PARKPTR_WRTREF_MASK; RegValue |= FrmBits; XAxiVdma_WriteReg(Channel->InstanceBase, XAXIVDMA_PARKPTR_OFFSET, RegValue); } } if (ChannelCfgPtr->EnableSync) { if (Channel->GenLock != XAXIVDMA_GENLOCK_MASTER) CrBits |= XAXIVDMA_CR_SYNC_EN_MASK; } if (ChannelCfgPtr->GenLockRepeat) { if ((Channel->GenLock == XAXIVDMA_GENLOCK_MASTER) || (Channel->GenLock == XAXIVDMA_DYN_GENLOCK_MASTER)) CrBits |= XAXIVDMA_CR_GENLCK_RPT_MASK; } if (ChannelCfgPtr->EnableFrameCounter) { CrBits |= XAXIVDMA_CR_FRMCNT_EN_MASK; } CrBits |= (ChannelCfgPtr->PointNum << XAXIVDMA_CR_RD_PTR_SHIFT) & XAXIVDMA_CR_RD_PTR_MASK; /* Write the control register value out */ XAxiVdma_WriteReg(Channel->ChanBase, XAXIVDMA_CR_OFFSET, CrBits); if (Channel->HasSG) { /* Setup the information in BDs * * All information is available except the buffer addrs * Buffer addrs are set through XAxiVdma_ChannelSetBufferAddr() */ NumBds = Channel->AllCnt; for (i = 0; i < NumBds; i++) { XAxiVdma_Bd *BdPtr = (XAxiVdma_Bd *)(Channel->HeadBdAddr + i * sizeof(XAxiVdma_Bd)); Status = XAxiVdma_BdSetVsize(BdPtr, ChannelCfgPtr->VertSizeInput); if (Status != XST_SUCCESS) { xdbg_printf(XDBG_DEBUG_ERROR, "Set vertical size failed %d\r\n", Status); return Status; } Status = XAxiVdma_BdSetHsize(BdPtr, ChannelCfgPtr->HoriSizeInput); if (Status != XST_SUCCESS) { xdbg_printf(XDBG_DEBUG_ERROR, "Set horizontal size failed %d\r\n", Status); return Status; } Status = XAxiVdma_BdSetStride(BdPtr, ChannelCfgPtr->Stride); if (Status != XST_SUCCESS) { xdbg_printf(XDBG_DEBUG_ERROR, "Set stride size failed %d\r\n", Status); return Status; } Status = XAxiVdma_BdSetFrmDly(BdPtr, ChannelCfgPtr->FrameDelay); if (Status != XST_SUCCESS) { xdbg_printf(XDBG_DEBUG_ERROR, "Set frame delay failed %d\r\n", Status); return Status; } } } else { /* direct register mode */ if ((ChannelCfgPtr->VertSizeInput > XAXIVDMA_MAX_VSIZE) || (ChannelCfgPtr->VertSizeInput <= 0) || (ChannelCfgPtr->HoriSizeInput > XAXIVDMA_MAX_HSIZE) || (ChannelCfgPtr->HoriSizeInput <= 0) || (ChannelCfgPtr->Stride > XAXIVDMA_MAX_STRIDE) || (ChannelCfgPtr->Stride <= 0) || (ChannelCfgPtr->FrameDelay < 0) || (ChannelCfgPtr->FrameDelay > XAXIVDMA_FRMDLY_MAX)) { return XST_INVALID_PARAM; } XAxiVdma_WriteReg(Channel->StartAddrBase, XAXIVDMA_HSIZE_OFFSET, ChannelCfgPtr->HoriSizeInput); XAxiVdma_WriteReg(Channel->StartAddrBase, XAXIVDMA_STRD_FRMDLY_OFFSET, (ChannelCfgPtr->FrameDelay << XAXIVDMA_FRMDLY_SHIFT) | ChannelCfgPtr->Stride); } return XST_SUCCESS; }