Esempio n. 1
0
/**
 * This function configures KeyHole Write/Read Feature
 *
 * @param	InstancePtr is the driver instance we are working on
 *
 * @param	Direction is WRITE/READ
 * @Select	Select is the option to enable (TRUE) or disable (FALSE).
 *
 * @return	- XST_SUCCESS for success
 *		- XST_DEVICE_BUSY when transfer is in progress
 *		- XST_NO_FEATURE when not configured with feature
 *
 * @note	None.
 *
 *****************************************************************************/
int XAxiCdma_SelectKeyHole(XAxiCdma *InstancePtr, u32 Direction, u32 Select)
{
	u32 Value;

	if (XAxiCdma_IsBusy(InstancePtr)) {
		xdbg_printf(XDBG_DEBUG_ERROR,
		    "KeyHole: Transfer is in Progress\n\r");
		return XST_DEVICE_BUSY;
	}

	Value = XAxiCdma_ReadReg(InstancePtr->BaseAddr, 
				XAXICDMA_CR_OFFSET);

	if (Select) {
		if (XPAR_AXICDMA_0_M_AXI_MAX_BURST_LEN == 16) {
			if (Direction == XAXICDMA_KEYHOLE_WRITE)
				Value |= XAXICDMA_CR_KHOLE_WR_MASK;
			else
				Value |= XAXICDMA_CR_KHOLE_RD_MASK;
		} else {
			xdbg_printf(XDBG_DEBUG_ERROR,
				"KeyHole: Max Burst length should be 16\n\r");
			return XST_NO_FEATURE;
		}
	}
	else {
		if (Direction == XAXICDMA_KEYHOLE_WRITE)
			Value &= ~XAXICDMA_CR_KHOLE_WR_MASK;
		else
			Value &= ~XAXICDMA_CR_KHOLE_RD_MASK; 
	}

	XAxiCdma_WriteReg(InstancePtr->BaseAddr,
			XAXICDMA_CR_OFFSET, Value);

	return XST_SUCCESS;
}
Esempio n. 2
0
/**
 * This function dumps the registers of this DMA instance
 *
 * @param	InstancePtr is the driver instance we are working on
 *
 * @return	None
 *
 * @note	None.
 *
 *****************************************************************************/
void XAxiCdma_DumpRegisters(XAxiCdma *InstancePtr)
{
	u32 RegBase;

	RegBase = InstancePtr->BaseAddr;

	xil_printf("Dump registers:\r\n");
	xil_printf("Control register: %x\r\n",
		XAxiCdma_ReadReg(RegBase, XAXICDMA_CR_OFFSET));
	xil_printf("Status register: %x\r\n",
		XAxiCdma_ReadReg(RegBase, XAXICDMA_SR_OFFSET));
	xil_printf("Current BD register: %x\r\n",
		XAxiCdma_ReadReg(RegBase, XAXICDMA_CDESC_OFFSET));
	xil_printf("Tail BD register: %x\r\n",
		XAxiCdma_ReadReg(RegBase, XAXICDMA_TDESC_OFFSET));
	xil_printf("Source Addr register: %x\r\n",
		XAxiCdma_ReadReg(RegBase, XAXICDMA_SRCADDR_OFFSET));
	xil_printf("Destination Addr register: %x\r\n",
		XAxiCdma_ReadReg(RegBase, XAXICDMA_DSTADDR_OFFSET));
	xil_printf("BTT register: %x\r\n",
		XAxiCdma_ReadReg(RegBase, XAXICDMA_BTT_OFFSET));

	return;
}
Esempio n. 3
0
/**
 * This function gets the mask for the interrupts that are currently enabled
 *
 * @param	InstancePtr is the driver instance we are working on
 *
 * @return	The bit mask for the interrupts that are currently enabled
 *
 * @note	None.
 *
 *****************************************************************************/
u32 XAxiCdma_IntrGetEnabled(XAxiCdma *InstancePtr)
{
	return (XAxiCdma_ReadReg(InstancePtr->BaseAddr, XAXICDMA_CR_OFFSET) &
		XAXICDMA_XR_IRQ_ALL_MASK);
}
Esempio n. 4
0
/**
 * This function is the interrupt handler for the driver, it handles all the
 * interrupts. For the completion of a transfer that has a callback function,
 * the callback function is called.
 *
 * @param	HandlerRef is a reference pointer passed to the interrupt
 *			registration function. It will be a pointer to the driver
 *			instance we are working on
 *
 * @return	None
 *
 * @note	If one transfer does not have all its submitted BDs completed
 *		successfully,then a reset is needed to clean up the mess left
 *		by that transfer.Otherwise, the wrong interrupt callback maybe
 *		called for the following transfers. However, if you always use
 *		the same interrupt callback for all the transfers, and you are
 *		the only user of the DMA engine, then you do not have to worry
 *		about this.
 *****************************************************************************/
void XAxiCdma_IntrHandler(void *HandlerRef)
{
	XAxiCdma *InstancePtr;
	u32 Status;
	u32 Irq;
	u32 Error = 0x0;

	InstancePtr = (XAxiCdma *)HandlerRef;
	Status = XAxiCdma_ReadReg(InstancePtr->BaseAddr, XAXICDMA_SR_OFFSET);

	/* Check what interrupts have fired
	 */
	Irq = Status & XAXICDMA_XR_IRQ_ALL_MASK;

	if (Irq == 0x0) {
		xdbg_printf(XDBG_DEBUG_ERROR, "No interrupt for intr handler\r\n");
		return;
	}

	/* Acknowledge the interrupt
	 */
	XAxiCdma_WriteReg(InstancePtr->BaseAddr, XAXICDMA_SR_OFFSET, Irq);

	/* Pass the interrupt and error status to the callback function
	 * if the transfer has one
	 */

	/* If SimpleNotDone flag is set, then it is a simple transfer
	 */
	if (InstancePtr->SimpleNotDone) {
		if (InstancePtr->SimpleCallBackFn) {
			(InstancePtr->SimpleCallBackFn)(
			    InstancePtr->SimpleCallBackRef, Irq, NULL);

			InstancePtr->SimpleCallBackFn = NULL;
		}

		InstancePtr->SimpleNotDone = 0;

		if (InstancePtr->SGWaiting) {
			XAxiCdma_BdRingStartTransfer(InstancePtr);
		}
	}
	else {	/* SG transfer */
		if (InstancePtr->SgHandlerHead != InstancePtr->SgHandlerTail) {
			int Tmp;

			XAxiCdma_IntrHandlerList Handler =
			    InstancePtr->Handlers[InstancePtr->SgHandlerHead];

			Tmp = Handler.NumBds;

			/* Caution: may have race condition here
			 *
			 * If an interrupt for another transfer happens
			 * while in callback function, then the wrong callback
			 * function may be called.
			 */
			Handler.CallBackFn(Handler.CallBackRef, Irq, &(Tmp));

			InstancePtr->Handlers[InstancePtr->SgHandlerHead].NumBds = Tmp;

			/* Update the handler head if this transfer is done
			 */
			if (Tmp == 0) {
				Tmp = InstancePtr->SgHandlerHead + 1;

				if (Tmp == XAXICDMA_MAXIMUM_MAX_HANDLER) {
					Tmp	= 0;
				}

				InstancePtr->SgHandlerHead = Tmp;
			}
		}
		else {
			xdbg_printf(XDBG_DEBUG_ERROR,
			    "ERROR: SG transfer intr without handler\r\n");
		}
	}

	/* If has error interrupt, hardware needs to be reset
	 */
	Error = Status & XAXICDMA_SR_ERR_ALL_MASK;
	if ((Irq & XAXICDMA_XR_IRQ_ERROR_MASK) && Error) {
		int TimeOut;


		TimeOut = XAXICDMA_RESET_LOOP_LIMIT;

		/* Need to reset the hardware to clear the errors
		 */
		XAxiCdma_Reset(InstancePtr);

		while (TimeOut) {

			if (XAxiCdma_ResetIsDone(InstancePtr)) {
				break;
			}

			TimeOut -= 1;
		}

		/* Reset failed
		 */
		if (!TimeOut) {
			/* Mark the driver/engine is not in working state
			 */
			InstancePtr->Initialized = 0;
		}

		/* In case of error, no further handling is needed
		 *
		 * User should check send/receive buffers to see what happened
		 * as well as check the DMA engine registers
		 */
		return;
 	}

	return;
}
Esempio n. 5
0
/**
 * This function gets the status on error bits.
 *
 * @param	InstancePtr is the driver instance we are working on
 *
 * @return	The error bits in the status register. Zero indicates no errors.
 *
 * @note	None.
 *
 *****************************************************************************/
u32 XAxiCdma_GetError(XAxiCdma *InstancePtr)
{

	return (XAxiCdma_ReadReg(InstancePtr->BaseAddr, XAXICDMA_SR_OFFSET) &
		XAXICDMA_SR_ERR_ALL_MASK);
}
Esempio n. 6
0
/*
 * Change the hardware mode
 *
 * If to switch to SG mode, check whether needs to setup the current BD
 * pointer register.
 *
 * @param	InstancePtr is the driver instance we are working on
 * @param	Mode is the mode to switch to.
 *
 * @return
 *		- XST_SUCCESS if mode switch is successful
 *		- XST_DEVICE_BUSY if the engine is busy, so cannot switch mode
 *		- XST_INVALID_PARAM if pass in invalid mode value
 *		- XST_FAILURE if:Hardware is simple mode only build
 *		Mode switch failed
 *
 * @note	None.
 *
 *****************************************************************************/
int XAxiCdma_SwitchMode(XAxiCdma *InstancePtr, int Mode)
{

	if (Mode == XAXICDMA_SIMPLE_MODE) {

		if (XAxiCdma_IsSimpleMode(InstancePtr)) {
			return XST_SUCCESS;
		}

		if (XAxiCdma_IsBusy(InstancePtr)) {
			xdbg_printf(XDBG_DEBUG_ERROR,
			    "SwitchMode: engine is busy\r\n");
			return XST_DEVICE_BUSY;
		}

		/* Keep the CDESC so that CDESC will be
		 * reloaded when switch to SG mode again
		 *
		 * We know CDESC is valid because the hardware can only
		 * be in SG mode if a SG transfer has been submitted.
		 */
		InstancePtr->BdaRestart = XAxiCdma_BdRingNext(InstancePtr,
		    XAxiCdma_BdRingGetCurrBd(InstancePtr));

		/* Update the CR register to switch to simple mode
		 */
		XAxiCdma_WriteReg(InstancePtr->BaseAddr, XAXICDMA_CR_OFFSET,
		  (XAxiCdma_ReadReg(InstancePtr->BaseAddr, XAXICDMA_CR_OFFSET)
		  & ~XAXICDMA_CR_SGMODE_MASK));

		/* Hardware mode switch is quick, should succeed right away
		 */
		if (XAxiCdma_IsSimpleMode(InstancePtr)) {

			return XST_SUCCESS;
		}
		else {
			return XST_FAILURE;
		}
	}
	else if (Mode == XAXICDMA_SG_MODE) {

		if (!XAxiCdma_IsSimpleMode(InstancePtr)) {
			return XST_SUCCESS;
		}

		if (InstancePtr->SimpleOnlyBuild) {
			xdbg_printf(XDBG_DEBUG_ERROR,
			    "SwitchMode: hardware simple mode only\r\n");
			return XST_FAILURE;
		}

		if (XAxiCdma_IsBusy(InstancePtr)) {
			xdbg_printf(XDBG_DEBUG_ERROR,
			    "SwitchMode: engine is busy\r\n");
			return XST_DEVICE_BUSY;
		}

		/* Update the CR register to switch to SG mode
		 */
		XAxiCdma_WriteReg(InstancePtr->BaseAddr, XAXICDMA_CR_OFFSET,
		  (XAxiCdma_ReadReg(InstancePtr->BaseAddr, XAXICDMA_CR_OFFSET)
		  | XAXICDMA_CR_SGMODE_MASK));

		/* Hardware mode switch is quick, should succeed right away
		 */
		if (!XAxiCdma_IsSimpleMode(InstancePtr)) {

			/* Update the CDESC register, because the hardware is
			 * to start from the CDESC
			 */
			XAxiCdma_BdSetCurBdPtr(InstancePtr,
				(UINTPTR)InstancePtr->BdaRestart);

			return XST_SUCCESS;
		}
		else {
			return XST_FAILURE;
		}
	}
	else {	/* Invalid mode */
		return XST_INVALID_PARAM;
	}
}
Esempio n. 7
0
/*
 * Check whether the hardware is in simple mode
 *
 * @param	InstancePtr is the driver instance we are working on
 *
 * @return
 *		- 1 if the hardware is in simple mode
 *		- 0 if the hardware is in SG mode
 *
 * @note	None.
 *
 *****************************************************************************/
int XAxiCdma_IsSimpleMode(XAxiCdma *InstancePtr)
{
	return ((XAxiCdma_ReadReg(InstancePtr->BaseAddr, XAXICDMA_CR_OFFSET) &
		XAXICDMA_CR_SGMODE_MASK) ? 0 : 1);
}
Esempio n. 8
0
/**
 * This function initializes the driver. It should be called before any other
 * function calls to the driver.
 *
 * It sets up the driver according to the hardware build. It resets the
 * hardware at the end.
 *
 * @param	InstancePtr is the driver instance that is working on
 * @param	CfgPtr is the pointer to the hardware configuration structure
 * @param	EffectiveAddr is the virtual address of the hardware instance.
 *		If address translation is not in use, please use the physical
 *		address
 *
 * @return
 *		- XST_SUCCESS for success
 *		- XST_INVALID_PARAM if word length is less than 4
 *		- XST_FAILURE for reset failure
 *
 * @note	None.
 *
 *****************************************************************************/
u32 XAxiCdma_CfgInitialize(XAxiCdma *InstancePtr, XAxiCdma_Config *CfgPtr,
		u32 EffectiveAddr)
{
	u32 RegValue;
	int TimeOut;

	/* Mark the driver is not in working state yet
	 */
	InstancePtr->Initialized = 0;

	InstancePtr->BaseAddr = EffectiveAddr;
	InstancePtr->HasDRE = CfgPtr->HasDRE;
	InstancePtr->IsLite = CfgPtr->IsLite;
	InstancePtr->WordLength = ((unsigned int)CfgPtr->DataWidth) >> 3;
	InstancePtr->AddrWidth = CfgPtr->AddrWidth;

	/* AXI CDMA supports 32 bits data width and up
	 */
	if (InstancePtr->WordLength < 4) {
		xdbg_printf(XDBG_DEBUG_ERROR,
		    "Word length too short %d\r\n", InstancePtr->WordLength);

		return XST_INVALID_PARAM;
	}

	RegValue = XAxiCdma_ReadReg(CfgPtr->BaseAddress, XAXICDMA_SR_OFFSET);

	InstancePtr->SimpleOnlyBuild = !(RegValue & XAXICDMA_SR_SGINCLD_MASK);

	/* Lite mode only supports data_width * burst_len
	 *
	 * Lite mode is ignored if SG mode is selected
	 */
	if (InstancePtr->SimpleOnlyBuild && CfgPtr->IsLite) {
		InstancePtr->MaxTransLen = InstancePtr->WordLength *
		      CfgPtr->BurstLen;
	}
	else {
		InstancePtr->MaxTransLen = XAXICDMA_MAX_TRANSFER_LEN;
	}

	TimeOut = XAXICDMA_RESET_LOOP_LIMIT;

	/* Reset the hardware
	 */
	XAxiCdma_Reset(InstancePtr);

	/* The hardware should be pretty quick on reset, the reset is only
	 * slow if there is an active large transfer
	 */
	while (TimeOut) {

		if (XAxiCdma_ResetIsDone(InstancePtr)) {
			break;
		}

		TimeOut -= 1;
	}

	if (!TimeOut) {
		xdbg_printf(XDBG_DEBUG_ERROR, "Reset failed\r\n");

		return XST_FAILURE;
	}

	/* Initialize the BD ring statistics, to prevent BD ring being used
	 * before being created
	 */
	InstancePtr->AllBdCnt = 0;
	InstancePtr->FreeBdCnt = 0;
	InstancePtr->HwBdCnt = 0;
	InstancePtr->PreBdCnt = 0;
	InstancePtr->PostBdCnt = 0;

	/* Mark that the driver/engine is in working state now
	 */
	InstancePtr->Initialized = 1;

	return XST_SUCCESS;
}