⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 xdmaps.c

📁 自学ZedBoard:使用IP通过ARM PS访问FPGA(源代码)
💻 C
📖 第 1 页 / 共 4 页
字号:
		 */		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 + -