📄 xdmaps.c
字号:
Cmd->BD.DstAddr, Cmd->BD.Length); if (Cmd->ChanCtrl.SrcInc) { PDBG("DCachFlushRange for Src 0x%x, Len 0x%x \r\n", Cmd->BD.SrcAddr, Cmd->BD.Length); Xil_DCacheFlushRange(Cmd->BD.SrcAddr, Cmd->BD.Length); } if (Cmd->ChanCtrl.DstInc) { PDBG("DCachInvalidateRange for Dst 0x%x, Len 0x%x \r\n", Cmd->BD.DstAddr, Cmd->BD.Length); Xil_DCacheInvalidateRange(Cmd->BD.DstAddr, Cmd->BD.Length); } Status = XDmaPs_Exec_DMAGO(InstPtr->Config.BaseAddress, Channel, DmaProg); } else { InstPtr->Chans[Channel].DmaCmdToHw = NULL; Status = XST_FAILURE; } return Status;}/****************************************************************************//**** Checks whether the DMA channel is active or idle.** @param InstPtr is the DMA instance.* @param Channel is the DMA channel number.** @return 0: if the channel is idle* 1: otherwise** @note None.******************************************************************************/int XDmaPs_IsActive(XDmaPs *InstPtr, unsigned int Channel){ Xil_AssertNonvoid(InstPtr != NULL); /* Need to assert Channel is in range */ if (Channel > XDMAPS_CHANNELS_PER_DEV) return 0; return InstPtr->Chans[Channel].DmaCmdToHw != NULL;}/****************************************************************************//**** Allocate a buffer of the DMA program buffer from the pool.** @param Pool the DMA program pool.** @return The allocated buffer, NULL if there is any error.** @note None.******************************************************************************/static void *XDmaPs_BufPool_Allocate(XDmaPs_ProgBuf *Pool){ int Index; Xil_AssertNonvoid(Pool != NULL); for (Index = 0; Index < XDMAPS_MAX_CHAN_BUFS; Index++) { if (!Pool[Index].Allocated) { PDBG("Allocate buf %d\r\n", Index); Pool[Index].Allocated = 1; return Pool[Index].Buf; } } return NULL;}/*****************************************************************************//**** Driver done interrupt service routine for channel 0. We need this done ISR* mainly because the driver needs to release the DMA program buffer.* This is the one that connects the GIC** @param InstPtr is the DMA instance.** @return None.** @note None.*******************************************************************************/void XDmaPs_DoneISR_0(XDmaPs *InstPtr){ XDmaPs_DoneISR_n(InstPtr, 0);}/*****************************************************************************//**** Driver done interrupt service routine for channel 1. We need this done ISR* mainly because the driver needs to release the DMA program buffer.* This is the one that connects the GIC** @param InstPtr is the DMA instance.** @return None.** @note None.*******************************************************************************/void XDmaPs_DoneISR_1(XDmaPs *InstPtr){ XDmaPs_DoneISR_n(InstPtr, 1);}/*****************************************************************************//**** Driver done interrupt service routine for channel 2. We need this done ISR* mainly because the driver needs to release the DMA program buffer.* This is the one that connects the GIC** @param InstPtr is the DMA instance.** @return None.** @note None.*******************************************************************************/void XDmaPs_DoneISR_2(XDmaPs *InstPtr){ XDmaPs_DoneISR_n(InstPtr, 2);}/*****************************************************************************//**** Driver done interrupt service routine for channel 3. We need this done ISR* mainly because the driver needs to release the DMA program buffer.* This is the one that connects the GIC** @param InstPtr is the DMA instance.** @return None.** @note None.*******************************************************************************/void XDmaPs_DoneISR_3(XDmaPs *InstPtr){ XDmaPs_DoneISR_n(InstPtr, 3);}/*****************************************************************************//**** Driver done interrupt service routine for channel 4. We need this done ISR* mainly because the driver needs to release the DMA program buffer.* This is the one that connects the GIC** @param InstPtr is the DMA instance.** @return None.** @note None.*******************************************************************************/void XDmaPs_DoneISR_4(XDmaPs *InstPtr){ XDmaPs_DoneISR_n(InstPtr, 4);}/*****************************************************************************//**** Driver done interrupt service routine for channel 5. We need this done ISR* mainly because the driver needs to release the DMA program buffer.* This is the one that connects the GIC** @param InstPtr is the DMA instance.** @return None.** @note None.*******************************************************************************/void XDmaPs_DoneISR_5(XDmaPs *InstPtr){ XDmaPs_DoneISR_n(InstPtr, 5);}/*****************************************************************************//**** Driver done interrupt service routine for channel 6. We need this done ISR* mainly because the driver needs to release the DMA program buffer.* This is the one that connects the GIC** @param InstPtr is the DMA instance.** @return None.** @note None.*******************************************************************************/void XDmaPs_DoneISR_6(XDmaPs *InstPtr){ XDmaPs_DoneISR_n(InstPtr, 6);}/*****************************************************************************//**** Driver done interrupt service routine for channel 7. We need this done ISR* mainly because the driver needs to release the DMA program buffer.* This is the one that connects the GIC** @param InstPtr is the DMA instance.** @return None.** @note None.*******************************************************************************/void XDmaPs_DoneISR_7(XDmaPs *InstPtr){ XDmaPs_DoneISR_n(InstPtr, 7);}#ifndef XDMAPS_MAX_WAIT#define XDMAPS_MAX_WAIT 4000#endif/****************************************************************************//*** Use the debug registers to kill the DMA thread.** @param BaseAddr is DMA device base address.* @param Channel is the DMA channel number.* @param Thread is Debug thread encoding.* 0: DMA manager thread, 1: DMA channel.** @return 0 on success, -1 on time out** @note None.******************************************************************************/static int XDmaPs_Exec_DMAKILL(u32 BaseAddr, unsigned int Channel, unsigned int Thread){ u32 DbgInst0; int WaitCount; PDBG("Inside XDmaPs_Exec_DMAKILL\r\n"); DbgInst0 = XDmaPs_DBGINST0(0, 0x01, Channel, Thread); /* wait while debug status is busy */ WaitCount = 0; PDBG("Checking DBGSTATUS\r\n"); while ((XDmaPs_ReadReg(BaseAddr, XDMAPS_DBGSTATUS_OFFSET) & XDMAPS_DBGSTATUS_BUSY) && (WaitCount < XDMAPS_MAX_WAIT)) WaitCount++; if (WaitCount >= XDMAPS_MAX_WAIT) { /* wait time out */ xil_printf("PL330 device at %x debug status busy time out\n", BaseAddr); return -1; } /* write debug instruction 0 */ PDBG("XDmaPs_Exec_DMAKILL: writing DbgInst0 %#08x\n", DbgInst0); XDmaPs_WriteReg(BaseAddr, XDMAPS_DBGINST0_OFFSET, DbgInst0); PDBG("pl330_exec_dmakill: writing DbgInst1 %#08x\n", 0); XDmaPs_WriteReg(BaseAddr, XDMAPS_DBGINST1_OFFSET, 0); /* run the command in DbgInst0 and DbgInst1 */ XDmaPs_WriteReg(BaseAddr, XDMAPS_DBGCMD_OFFSET, 0); return 0;}/****************************************************************************//***** Free a buffer of the DMA program buffer.* @param Pool the DMA program pool.* @param Buf the DMA program buffer to be release.** @return None** @note None.******************************************************************************/static void XDmaPs_BufPool_Free(XDmaPs_ProgBuf *Pool, void *Buf){ int Index; int Found = 0; Xil_AssertVoid(Pool != NULL); for (Index = 0; Index < XDMAPS_MAX_CHAN_BUFS; Index++) { if (Pool[Index].Buf == Buf) { if (Pool[Index].Allocated) { PDBG("Freed buf %d\r\n", Index); Pool[Index].Allocated = 0; } else { PDBG("Trying to free a free buf %d\r\n", Index); } Found = 1; } } if (!Found) PDBG("Trying to free a buf that is not in the pool\r\n");}/*****************************************************************************//*** XDmaPs_Exec_DMAGO - Execute the DMAGO to start a channel.** @param BaseAddr PL330 device base address* @param Channel Channel number for the device* @param DmaProg DMA program starting address, this should be DMA address** @return 0 on success, -1 on time out** @note None.*****************************************************************************/static int XDmaPs_Exec_DMAGO(u32 BaseAddr, unsigned int Channel, u32 DmaProg){ char DmaGoProg[8]; u32 DbgInst0; u32 DbgInst1; int WaitCount; PDBG("XDmaPs_Exec_DMAGO: entering\r\n"); XDmaPs_Instr_DMAGO(DmaGoProg, Channel, DmaProg, 0); DbgInst0 = XDmaPs_DBGINST0(*(DmaGoProg + 1), *DmaGoProg, 0, 0); DbgInst1 = (u32)DmaProg; PDBG("inside XDmaPs_Exec_DMAGO: base %x, Channel %d, DmaProg %x\r\n", BaseAddr, Channel, DmaProg); PDBG("inside XDmaPs_Exec_DMAGO: DbgInst0 %x, DbgInst1 %x\r\n", DbgInst0, DbgInst1); /* wait while debug status is busy */ WaitCount = 0; PDBG("Checking DBGSTATUS\r\n"); while ((XDmaPs_ReadReg(BaseAddr, XDMAPS_DBGSTATUS_OFFSET) & XDMAPS_DBGSTATUS_BUSY) && (WaitCount < XDMAPS_MAX_WAIT)) { PDBG("dbgstatus %x\r\n", XDmaPs_ReadReg(BaseAddr, XDMAPS_DBGSTATUS_OFFSET)); WaitCount++; } if (WaitCount >= XDMAPS_MAX_WAIT) { xil_printf("PL330 device at %x debug status busy time out\r\n", BaseAddr); return -1; } PDBG("dbgstatus idle\r\n"); /* write debug instruction 0 */ XDmaPs_WriteReg(BaseAddr, XDMAPS_DBGINST0_OFFSET, DbgInst0); /* write debug instruction 1 */ XDmaPs_WriteReg(BaseAddr, XDMAPS_DBGINST1_OFFSET, DbgInst1); /* wait while the DMA Manager is busy */ WaitCount = 0; while ((XDmaPs_ReadReg(BaseAddr, XDMAPS_DS_OFFSET) & XDMAPS_DS_DMA_STATUS) != XDMAPS_DS_DMA_STATUS_STOPPED && WaitCount <= XDMAPS_MAX_WAIT) { PDBG("ds %x\r\n", XDmaPs_ReadReg(BaseAddr, XDMAPS_DS_OFFSET)); WaitCount++; } if (WaitCount >= XDMAPS_MAX_WAIT) { xil_printf("PL330 device at %x debug status busy time out\r\n", BaseAddr); return -1; } /* run the command in DbgInst0 and DbgInst1 */ XDmaPs_WriteReg(BaseAddr, XDMAPS_DBGCMD_OFFSET, 0); PDBG("XDmaPs_Exec_DMAGO done\r\n"); return 0;}/****************************************************************************//**** It's the generic Done ISR.* @param InstPtr is the DMA instance.* @param Channel is the DMA channel numer.** @return None.*** @note None.******************************************************************************/static void XDmaPs_DoneISR_n(XDmaPs *InstPtr, unsigned Channel){ void *DmaProgBuf; XDmaPs_ChannelData *ChanData; XDmaPs_Cmd *DmaCmd; u32 Value; ChanData = InstPtr->Chans + Channel; PDBG("inside Done ISR Channel %d\r\n", ChanData->ChanId); Value = XDmaPs_ReadReg(InstPtr->Config.BaseAddress, XDMAPS_INTSTATUS_OFFSET); PDBG("Interrupt status before clearing %x\r\n", Value); /* clear the interrupt status */ PDBG("Clear the interrupt status %x\r\n", 1<< ChanData->ChanId); XDmaPs_WriteReg(InstPtr->Config.BaseAddress, XDMAPS_INTCLR_OFFSET, 1 << ChanData->ChanId); Value = XDmaPs_ReadReg(InstPtr->Config.BaseAddress, XDMAPS_INTSTATUS_OFFSET); PDBG("Interrupt status after clearing %x\r\n", Value); if (Value) { PDBG("Interrupt status %x\r\n", Value); } if ((DmaCmd = ChanData->DmaCmdToHw)) { if (!ChanData->HoldDmaProg) { DmaProgBuf = (void *)DmaCmd->GeneratedDmaProg; if (DmaProgBuf) XDmaPs_BufPool_Free(ChanData->ProgBufPool, DmaProgBuf); DmaCmd->GeneratedDmaProg = NULL; } DmaCmd->DmaStatus = 0; ChanData->DmaCmdToHw = NULL; ChanData->DmaCmdFromHw = DmaCmd; if (ChanData->DoneHandler) ChanData->DoneHandler(Channel, DmaCmd, ChanData->DoneRef); }}/****************************************************************************//*** Prints the content of the buffer in bytes* @param Buf is the buffer.* @param Length is the length of the DMA program.** @return None.** @note None.****************************************************************************/static void XDmaPs_Print_DmaProgBuf(char *Buf, int Length){ int Index; for (Index = 0; Index < Length; Index++) xil_printf("[%x] %x\r\n", Index, Buf[Index]);}/****************************************************************************//*** Print the Dma Prog Contents.** @param Cmd is the command buffer.** @return None.** @note None.******************************************************************************/ void XDmaPs_Print_DmaProg(XDmaPs_Cmd *Cmd){ if (Cmd->GeneratedDmaProg && Cmd->GeneratedDmaProgLength) { xil_printf("Generated DMA program (%d):\r\n", Cmd->GeneratedDmaProgLength); XDmaPs_Print_DmaProgBuf((char *)Cmd->GeneratedDmaProg, Cmd->GeneratedDmaProgLength); } if (Cmd->UserDmaProg && Cmd->UserDmaProgLength) { xil_printf("User defined DMA program (%d):\r\n", Cmd->UserDmaProgLength); XDmaPs_Print_DmaProgBuf((char *)Cmd->UserDmaProg, Cmd->UserDmaProgLength); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -