📄 xdmaps.c
字号:
*/ CacheStartOffset = DmaProgBuf - DmaProgStart; CacheEndOffset = CacheStartOffset + 7; /* * check whether the body and lpend fit in one cache line */ if (CacheStartOffset / CacheLength != CacheEndOffset / CacheLength) { /* insert the nops */ NumNops = CacheLength - CacheStartOffset % CacheLength; while (NumNops--) { DmaProgBuf += XDmaPs_Instr_DMANOP(DmaProgBuf); } } } /* insert the inner DMALP */ DmaProgBuf += XDmaPs_Instr_DMALP(DmaProgBuf, 0, LoopCountInner); /* DMALD and DMAST instructions */ DmaProgBuf += XDmaPs_Instr_DMALD(DmaProgBuf); DmaProgBuf += XDmaPs_Instr_DMAST(DmaProgBuf); /* inner DMALPEND */ DmaProgBuf += XDmaPs_Instr_DMALPEND(DmaProgBuf, DmaProgBuf - 2, 0); /* outer DMALPEND */ DmaProgBuf += XDmaPs_Instr_DMALPEND(DmaProgBuf, InnerLoopStart, 1); /* return the number of bytes */ return DmaProgBuf - DmaProgLoopStart;}/* * [31:28] endian_swap_size b0000 * [27:25] dst_cache_ctrl b000 * [24:22] dst_prot_ctrl b000 * [21:18] dst_burst_len b0000 * [17:15] dst_burst_size b000 * [14] dst_inc b0 * [27:25] src_cache_ctrl b000 * [24:22] src_prot_ctrl b000 * [21:18] src_burst_len b0000 * [17:15] src_burst_size b000 * [14] src_inc b0 */#define XDMAPS_CCR_SINGLE_BYTE (0x0)#define XDMAPS_CCR_M2M_SINGLE_BYTE ((0x1 << 14) | 0x1)/****************************************************************************//**** Construct the DMA program based on the descriptions of the DMA transfer.* The function handles memory to device and device to memory DMA transfers.* It also handles unalgined head and small amount of residue tail.** @param Channel DMA channel number* @param Cmd is the DMA command.* @param CacheLength is the icache line length, in terms of bytes.* If it's zero, the performance enhancement feature will be* turned off.** @returns The number of bytes for the program.** @note None.******************************************************************************/static int XDmaPs_BuildDmaProg(unsigned Channel, XDmaPs_Cmd *Cmd, unsigned CacheLength){ /* * unpack arguments */ char *DmaProgBuf = (char *)Cmd->GeneratedDmaProg; unsigned DevChan = Channel; unsigned long DmaLength = Cmd->BD.Length; u32 SrcAddr = Cmd->BD.SrcAddr; unsigned SrcInc = Cmd->ChanCtrl.SrcInc; u32 DstAddr = Cmd->BD.DstAddr; unsigned DstInc = Cmd->ChanCtrl.DstInc; char *DmaProgStart = DmaProgBuf; unsigned int BurstBytes; unsigned int LoopCount; unsigned int LoopCount1 = 0; unsigned int LoopResidue = 0; unsigned int TailBytes; unsigned int TailWords; int DmaProgBytes; u32 CCRValue; unsigned int Unaligned; unsigned int UnalignedCount; unsigned int MemBurstSize = 1; unsigned int MemBurstLen = 1; u32 MemAddr = 0; unsigned int Index; unsigned int SrcUnaligned = 0; unsigned int DstUnaligned = 0; int UseM2MByte = 0; XDmaPs_ChanCtrl *ChanCtrl; XDmaPs_ChanCtrl WordChanCtrl; static XDmaPs_ChanCtrl Mem2MemByteCC; Mem2MemByteCC.EndianSwapSize = 0; Mem2MemByteCC.DstCacheCtrl = 0; Mem2MemByteCC.DstProtCtrl = 0; Mem2MemByteCC.DstBurstLen = 1; Mem2MemByteCC.DstBurstSize = 1; Mem2MemByteCC.DstInc = 1; Mem2MemByteCC.SrcCacheCtrl = 0; Mem2MemByteCC.SrcProtCtrl = 0; Mem2MemByteCC.SrcBurstLen = 1; Mem2MemByteCC.SrcBurstSize = 1; Mem2MemByteCC.SrcInc = 1; ChanCtrl = &Cmd->ChanCtrl; /* insert DMAMOV for SAR and DAR */ DmaProgBuf += XDmaPs_Instr_DMAMOV(DmaProgBuf, XDMAPS_MOV_SAR, 0); DmaProgBuf += XDmaPs_Instr_DMAMOV(DmaProgBuf, XDMAPS_MOV_DAR, 0); /* insert DMAMOV for SAR and DAR */ DmaProgBuf += XDmaPs_Instr_DMAMOV(DmaProgBuf, XDMAPS_MOV_SAR, SrcAddr); DmaProgBuf += XDmaPs_Instr_DMAMOV(DmaProgBuf, XDMAPS_MOV_DAR, DstAddr); if (ChanCtrl->SrcInc) SrcUnaligned = SrcAddr % ChanCtrl->SrcBurstSize; if (ChanCtrl->DstInc) DstUnaligned = DstAddr % ChanCtrl->DstBurstSize; if ((SrcUnaligned && DstInc) || (DstUnaligned && SrcInc)) { ChanCtrl = &Mem2MemByteCC; UseM2MByte = 1; } if (ChanCtrl->SrcInc) { MemBurstSize = ChanCtrl->SrcBurstSize; MemBurstLen = ChanCtrl->SrcBurstLen; MemAddr = SrcAddr; } else if (ChanCtrl->DstInc) { MemBurstSize = ChanCtrl->DstBurstSize; MemBurstLen = ChanCtrl->DstBurstLen; MemAddr = DstAddr; } /* check whether the head is aligned or not */ Unaligned = MemAddr % MemBurstSize; if (Unaligned) { /* if head is unaligned, transfer head in bytes */ UnalignedCount = MemBurstSize - Unaligned; CCRValue = XDMAPS_CCR_SINGLE_BYTE | (SrcInc & 1) | ((DstInc & 1) << 14); DmaProgBuf += XDmaPs_Instr_DMAMOV(DmaProgBuf, XDMAPS_MOV_CCR, CCRValue); PDBG("unaligned head count %d\r\n", UnalignedCount); for (Index = 0; Index < UnalignedCount; Index++) { DmaProgBuf += XDmaPs_Instr_DMALD(DmaProgBuf); DmaProgBuf += XDmaPs_Instr_DMAST(DmaProgBuf); } DmaLength -= UnalignedCount; } /* now the burst transfer part */ CCRValue = XDmaPs_ToCCRValue(ChanCtrl); DmaProgBuf += XDmaPs_Instr_DMAMOV(DmaProgBuf, XDMAPS_MOV_CCR, CCRValue); BurstBytes = ChanCtrl->SrcBurstSize * ChanCtrl->SrcBurstLen; LoopCount = DmaLength / BurstBytes; TailBytes = DmaLength % BurstBytes; /* * the loop count register is 8-bit wide, so if we need * a larger loop, we need to have nested loops */ if (LoopCount > 256) { LoopCount1 = LoopCount / 256; if (LoopCount1 > 256) { xil_printf("DMA operation cannot fit in a 2-level " "loop for channel %d, please reduce the " "DMA length or increase the burst size or " "length", Channel); return 0; } LoopResidue = LoopCount % 256; PDBG("loop count %d is greater than 256\r\n", LoopCount); if (LoopCount1 > 1) DmaProgBuf += XDmaPs_ConstructNestedLoop(DmaProgStart, CacheLength, DmaProgBuf, LoopCount1, 256); else DmaProgBuf += XDmaPs_ConstructSingleLoop(DmaProgStart, CacheLength, DmaProgBuf, 256); /* there will be some that cannot be covered by * nested loops */ LoopCount = LoopResidue; } if (LoopCount > 0) { PDBG("now loop count is %d \r\n", LoopCount); DmaProgBuf += XDmaPs_ConstructSingleLoop(DmaProgStart, CacheLength, DmaProgBuf, LoopCount); } if (TailBytes) { /* handle the tail */ TailWords = TailBytes / MemBurstSize; TailBytes = TailBytes % MemBurstSize; if (TailWords) { PDBG("tail words is %d \r\n", TailWords); WordChanCtrl = *ChanCtrl; /* * if we can transfer the tail in words, we will * transfer words as much as possible */ WordChanCtrl.SrcBurstSize = MemBurstSize; WordChanCtrl.SrcBurstLen = 1; WordChanCtrl.DstBurstSize = MemBurstSize; WordChanCtrl.DstBurstLen = 1; /* * the burst length is 1 */ CCRValue = XDmaPs_ToCCRValue(&WordChanCtrl); DmaProgBuf += XDmaPs_Instr_DMAMOV(DmaProgBuf, XDMAPS_MOV_CCR, CCRValue); DmaProgBuf += XDmaPs_ConstructSingleLoop(DmaProgStart, CacheLength, DmaProgBuf, TailWords); } if (TailBytes) { /* * for the rest, we'll tranfer in bytes */ /* * So far just to be safe, the tail bytes * are transfered in a loop. We can optimize a little * to perform a burst. */ CCRValue = XDMAPS_CCR_SINGLE_BYTE | (SrcInc & 1) | ((DstInc & 1) << 14); DmaProgBuf += XDmaPs_Instr_DMAMOV(DmaProgBuf, XDMAPS_MOV_CCR, CCRValue); PDBG("tail bytes is %d \r\n", TailBytes); DmaProgBuf += XDmaPs_ConstructSingleLoop(DmaProgStart, CacheLength, DmaProgBuf, TailBytes); } } DmaProgBuf += XDmaPs_Instr_DMASEV(DmaProgBuf, DevChan); DmaProgBuf += XDmaPs_Instr_DMAEND(DmaProgBuf); DmaProgBytes = DmaProgBuf - DmaProgStart; Xil_DCacheFlushRange((u32)DmaProgStart, DmaProgBytes); return DmaProgBytes;}/****************************************************************************//**** Generate a DMA program based for the DMA command, the buffer will be pointed* by the GeneratedDmaProg field of the command.** @param InstPtr is then DMA instance.* @param Channel is the DMA channel number.* @param Cmd is the DMA command.** @return - XST_SUCCESS on success.* - XST_FAILURE if it fails** @note None.******************************************************************************/int XDmaPs_GenDmaProg(XDmaPs *InstPtr, unsigned int Channel, XDmaPs_Cmd *Cmd){ void *Buf; int ProgLen; XDmaPs_ChannelData *ChanData; XDmaPs_ChanCtrl *ChanCtrl; Xil_AssertNonvoid(InstPtr != NULL); Xil_AssertNonvoid(Cmd != NULL); PDBG("Inside XdmaPs_GenDmaProg\r\n"); if (Channel > XDMAPS_CHANNELS_PER_DEV) return XST_FAILURE; ChanData = InstPtr->Chans + Channel; ChanCtrl = &Cmd->ChanCtrl; if (ChanCtrl->SrcBurstSize * ChanCtrl->SrcBurstLen != ChanCtrl->DstBurstSize * ChanCtrl->DstBurstLen) { xil_printf("source burst_size * burst_len does not match " "that of destination\r\n"); return XST_FAILURE; } /* * unaligned fixed address is not supported */ if (!ChanCtrl->SrcInc && Cmd->BD.SrcAddr % ChanCtrl->SrcBurstSize) { xil_printf("source address is fixed but is unaligned\r\n"); return XST_FAILURE; } if (!ChanCtrl->DstInc && Cmd->BD.DstAddr % ChanCtrl->DstBurstSize) { xil_printf("destination address is fixed but is " "unaligned\r\n"); return XST_FAILURE; } Buf = XDmaPs_BufPool_Allocate(ChanData->ProgBufPool); if (Buf == NULL) { xil_printf("failed to allocate program buffer\r\n"); return XST_FAILURE; } PDBG("Buf allocated %x\r\n", (u32)Buf); Cmd->GeneratedDmaProg = Buf; ProgLen = XDmaPs_BuildDmaProg(Channel, Cmd, InstPtr->CacheLength); Cmd->GeneratedDmaProgLength = ProgLen; PDBG("Generated DMA Prog length is %d\r\n", ProgLen);#ifdef XDMAPS_DEBUG XDmaPs_Print_DmaProg(Cmd);#endif if (ProgLen <= 0) { /* something wrong, release the buffer */ XDmaPs_BufPool_Free(ChanData->ProgBufPool, Buf); Cmd->GeneratedDmaProgLength = 0; Cmd->GeneratedDmaProg = NULL; return XST_FAILURE; } return XST_SUCCESS;}/****************************************************************************//** * Free the DMA program buffer that is pointed by the GeneratedDmaProg field * of the command. * * @param InstPtr is then DMA instance. * @param Channel is the DMA channel number. * @param Cmd is the DMA command. * * @return XST_SUCCESS on success. * XST_FAILURE if there is any error. * * @note None. * ****************************************************************************/int XDmaPs_FreeDmaProg(XDmaPs *InstPtr, unsigned int Channel, XDmaPs_Cmd *Cmd){ void *Buf; XDmaPs_ChannelData *ChanData; Xil_AssertNonvoid(InstPtr != NULL); Xil_AssertNonvoid(Cmd != NULL); if (Channel > XDMAPS_CHANNELS_PER_DEV) return XST_FAILURE; Buf = (void *)Cmd->GeneratedDmaProg; ChanData = InstPtr->Chans + Channel; if (Buf) { XDmaPs_BufPool_Free(ChanData->ProgBufPool, Buf); Cmd->GeneratedDmaProg = 0; Cmd->GeneratedDmaProgLength = 0; } return XST_SUCCESS;}/****************************************************************************//**** Start a DMA command. The command can only be invoked when the channel* is idle. The driver takes the command, generates DMA program if needed,* then pass the program to DMAC to execute.** @param InstPtr is then DMA instance.* @param Channel is the DMA channel number.* @param Cmd is the DMA command.* @param HoldDmaProg is tag indicating whether the driver can release* the allocated DMA buffer or not. If a user wants to examine the* generated DMA program, the flag should be set to 1. After the* DMA program is finished, a user needs to explicity free the* buffer.** @return* - XST_SUCCESS on success* - XST_DEVICE_BUSY if DMA is busy* - XST_FAILURE on other failures** @note None.*****************************************************************************/int XDmaPs_Start(XDmaPs *InstPtr, unsigned int Channel, XDmaPs_Cmd *Cmd, int HoldDmaProg){ int Status; u32 DmaProg = 0; u32 Inten; Xil_AssertNonvoid(InstPtr != NULL); Xil_AssertNonvoid(Cmd != NULL); PDBG("Inside XDmaPs_Start\r\n"); Cmd->DmaStatus = XST_FAILURE; if (XDmaPs_IsActive(InstPtr, Channel)) return XST_DEVICE_BUSY; if (!Cmd->UserDmaProg && !Cmd->GeneratedDmaProg) { Status = XDmaPs_GenDmaProg(InstPtr, Channel, Cmd); if (Status) return XST_FAILURE; } if (Cmd->UserDmaProg) DmaProg = (u32)Cmd->UserDmaProg; else if (Cmd->GeneratedDmaProg) DmaProg = (u32)Cmd->GeneratedDmaProg; if (DmaProg) { /* enable the interrupt */ // PDBG("enable_dma: enabling interrupt\r\n"); PDBG("enable_dma: enabling interrupt\r\n"); Inten = XDmaPs_ReadReg(InstPtr->Config.BaseAddress, XDMAPS_INTEN_OFFSET); Inten |= 0x01 << Channel; /* set the correpsonding bit */ PDBG("enable_dma: writing inten %x\r\n", Inten); XDmaPs_WriteReg(InstPtr->Config.BaseAddress, XDMAPS_INTEN_OFFSET, Inten); PDBG("pl330 interrupt enabled for channel %d\r\n", Channel); Inten = XDmaPs_ReadReg(InstPtr->Config.BaseAddress, XDMAPS_INTEN_OFFSET); if ((Inten & (0x01 << Channel)) == 0) { PDBG("Trouble enabling Intr, INTEN Reg: %x\r\n", XDmaPs_ReadReg(InstPtr->Config.BaseAddress, XDMAPS_INTEN_OFFSET)); } else { PDBG("pl330 interrupt enabled for channel %d\r\n", Channel); } InstPtr->Chans[Channel].DmaCmdToHw = Cmd; PDBG("Src %x, Dst %x, Len %x\r\n", Cmd->BD.SrcAddr,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -