/******************************************************************************
* Copyright (C) 2015 - 2020 Xilinx, Inc. All rights reserved. 
* SPDX-License-Identifier: MIT
******************************************************************************/

/*****************************************************************************/
/**
*
* @file xdptxss_intr.c
* @addtogroup dptxss_v5_2
* @{
*
* This file contains interrupt related functions of Xilinx DisplayPort TX
* Subsystem core.  Please see xdptxss.h for more details of the core. 
*
* <pre>
* MODIFICATION HISTORY:
*
* Ver  Who Date     Changes
* ---- --- -------- ---------------------------------------------------------
* 1.00 sha 01/29/15 Initial release. 
* 2.00 sha 08/07/15 Added new handler types: lane count, link rate,
*                   Pre-emphasis voltage swing adjust and Set MSA. 
* 2.00 sha 09/28/15 Added HDCP and Timer Counter interrupt handlers. 
* 3.0  sha 02/19/16 Added switch cases for
*                   XDPTXSS_HANDLER_HDCP_RPTR_DWN_STRM_RDY and
*                   XDPTXSS_HANDLER_HDCP_RPTR_EXCHG to register callback
*                   with HDCP. 
* 4.1  als 08/08/16 Synchronize with new HDCP APIs. 
* 5.0  tu  09/08/17 Added two interrupt handler that addresses driver's
*                   internal callback function of application
*                   DrvHpdEventHandler and DrvHpdPulseHandler
* </pre>
*
******************************************************************************/

/***************************** Include Files *********************************/

#include "xdptxss.h"

/************************** Constant Definitions *****************************/


/***************** Macros (Inline Functions) Definitions *********************/


/**************************** Type Definitions *******************************/


/************************** Function Prototypes ******************************/


/************************** Variable Definitions *****************************/


/************************** Function Definitions *****************************/

/*****************************************************************************/
/**
*
* This function is the interrupt handler for the DisplayPort TX core operating
* in TX mode. 
*
* The application is responsible for connecting this function to the interrupt
* system.  Application beyond this driver is also responsible for providing
* callbacks to handle interrupts and installing the callbacks using
* XDpTxSs_SetCallBack() during initialization phase. 
*
* @param	InstancePtr is a pointer to the XDpTxSs core instance that
*		just interrupted. 
*
* @return	None. 
*
* @note		None. 
*
******************************************************************************/
void XDpTxSs_DpIntrHandler(void *InstancePtr)
{
	XDpTxSs *XDpTxSsPtr = (XDpTxSs *)InstancePtr;

	/* Verify arguments. */ 
	Xil_AssertVoid(XDpTxSsPtr ! = NULL);
	Xil_AssertVoid(XDpTxSsPtr->IsReady == XIL_COMPONENT_IS_READY);

	/* DisplayPort TX interrupt handler */
	XDp_InterruptHandler(XDpTxSsPtr->DpPtr);
}

#if (XPAR_XHDCP_NUM_INSTANCES > 0)
/*****************************************************************************/
/**
*
* This function is the interrupt handler for the HDCP Cipher core. 
*
* The application is responsible for connecting this function to the interrupt
* system. 
*
* @param	InstancePtr is a pointer to the XDpTxSs core instance that
*		just interrupted. 
*
* @return	None. 
*
* @note		None. 
*
******************************************************************************/
void XDpTxSs_HdcpIntrHandler(void *InstancePtr)
{
	XDpTxSs *XDpTxSsPtr = (XDpTxSs *)InstancePtr;

	/* Verify arguments. */ 
	Xil_AssertVoid(XDpTxSsPtr ! = NULL);
	Xil_AssertVoid(XDpTxSsPtr->IsReady == XIL_COMPONENT_IS_READY);

	/* HDCP Cipher interrupt handler */
	XHdcp1x_CipherIntrHandler(XDpTxSsPtr->Hdcp1xPtr);
}

/*****************************************************************************/
/**
*
* This function is the interrupt handler for the Timer Counter core. 
*
* The application is responsible for connecting this function to the interrupt
* system. 
*
* @param	InstancePtr is a pointer to the XDpTxSs core instance that
*		just interrupted. 
*
* @return	None. 
*
* @note		None. 
*
******************************************************************************/
void XDpTxSs_TmrCtrIntrHandler(void *InstancePtr)
{
	XDpTxSs *XDpTxSsPtr = (XDpTxSs *)InstancePtr;

	/* Verify arguments. */ 
	Xil_AssertVoid(XDpTxSsPtr ! = NULL);
	Xil_AssertVoid(XDpTxSsPtr->IsReady == XIL_COMPONENT_IS_READY);

	/* Timer Counter interrupt handler */
	XTmrCtr_InterruptHandler(XDpTxSsPtr->TmrCtrPtr);
}
#endif

/*****************************************************************************/
/**
*
* This function is process some DP driver read as per DP spec on HPD EVENT. 
*
* @param	InstancePtr is a pointer to the XDpTxSs core instance that
*		just interrupted. 
*
* @return	None. 
*
* @note		None. 
*
******************************************************************************/
void XDpTxSs_HpdEventProcess(void *InstancePtr)
{
	u32 Status = XST_SUCCESS;
	XDpTxSs *XDpTxSsPtr = (XDpTxSs *)InstancePtr;

	/* Verify arguments. */ 
	Xil_AssertVoid(XDpTxSsPtr ! = NULL);
	Xil_AssertVoid(XDpTxSsPtr->IsReady == XIL_COMPONENT_IS_READY);
	XDpTxSs_UsrHpdEventData *UsrHpdEventData = &XDpTxSsPtr->UsrHpdEventData;

	if (XDp_TxIsConnected(XDpTxSsPtr->DpPtr)) {
		/* From here is the requirement per DP spec */
		Status = XDp_TxAuxRead(XDpTxSsPtr->DpPtr,
				XDP_DPCD_MAX_LINK_RATE, 1,
				&UsrHpdEventData->MaxCapNew);
		Status |= XDp_TxAuxRead(XDpTxSsPtr->DpPtr,
				XDP_DPCD_MAX_LANE_COUNT, 1,
				&UsrHpdEventData->MaxCapLanesNew);
		Status |= XDp_TxAuxRead(XDpTxSsPtr->DpPtr, XDP_DPCD_REV, 12,
				UsrHpdEventData->Tmp);
		Status |= XDp_TxAuxRead(XDpTxSsPtr->DpPtr,
				XDP_DPCD_SINK_COUNT, 6,	UsrHpdEventData->Tmp);

		Status |= XDp_TxAuxRead(XDpTxSsPtr->DpPtr, XDP_DPCD_REV, 11,
				&UsrHpdEventData->Dpcd);
		Status |= XDp_TxGetEdidBlock(XDpTxSsPtr->DpPtr,
				UsrHpdEventData->EdidOrg, 0);

		if (UsrHpdEventData->EdidOrg[XDP_EDID_EXT_BLOCK_COUNT] > 0)
                       Status |= XDp_TxGetEdidBlock(XDpTxSsPtr->DpPtr,
                                                    UsrHpdEventData->EdidOrg_1,
                                                    1);
               if (UsrHpdEventData->EdidOrg_1[XDP_EDID_EXT_BLOCK_COUNT] > 1)
                        Status |= XDp_TxGetEdidBlock(XDpTxSsPtr->DpPtr,
                                                     UsrHpdEventData->EdidOrg_2,
                                                     2);

		Status |= XDp_TxAuxRead(XDpTxSsPtr->DpPtr, XDP_DPCD_SINK_COUNT,
				1, &UsrHpdEventData->Rd200);
		Status |= XDp_TxAuxRead(XDpTxSsPtr->DpPtr,
				XDP_DPCD_STATUS_LANE_0_1, 1,
				&UsrHpdEventData->Lane0Sts);
		Status |= XDp_TxAuxRead(XDpTxSsPtr->DpPtr,
				XDP_DPCD_STATUS_LANE_2_3, 1,
				&UsrHpdEventData->Lane2Sts);
		Status |= XDp_TxAuxRead(XDpTxSsPtr->DpPtr,
				XDP_DPCD_MAX_LINK_RATE, 1,
				&UsrHpdEventData->MaxCapNew);
		Status |= XDp_TxAuxRead(XDpTxSsPtr->DpPtr,
				XDP_DPCD_MAX_LANE_COUNT, 1,
				&UsrHpdEventData->MaxCapLanesNew);
	}

	if(Status ! = XST_SUCCESS){
		xdbg_printf(XDBG_DEBUG_GENERAL, "AUX access had trouble!\r\n");
	}
}

/*****************************************************************************/
/**
*
* This function is process some DP driver read as per DP spec on HPD Pulse. 
*
* @param	InstancePtr is a pointer to the XDpTxSs core instance that
*		just interrupted. 
*
* @return	None. 
*
* @note		None. 
*
******************************************************************************/
void XDpTxSs_HpdPulseProcess(void *InstancePtr)
{
	u32 Status = XST_SUCCESS;
	XDpTxSs *XDpTxSsPtr = (XDpTxSs *)InstancePtr;

	/* Verify arguments. */ 
	Xil_AssertVoid(XDpTxSsPtr ! = NULL);
	Xil_AssertVoid(XDpTxSsPtr->IsReady == XIL_COMPONENT_IS_READY);
	XDpTxSs_UsrHpdPulseData *UsrHpdPulseData = &XDpTxSsPtr->UsrHpdPulseData;

	//reading the first block of EDID
	Status |= XDp_TxAuxRead(XDpTxSsPtr->DpPtr,
			 XDP_DPCD_SINK_COUNT, 6, UsrHpdPulseData->AuxValues);
	Status |= XDp_TxAuxRead(XDpTxSsPtr->DpPtr,
			 XDP_DPCD_STATUS_LANE_0_1, 1,
			 &UsrHpdPulseData->Lane0Sts);
	Status |= XDp_TxAuxRead(XDpTxSsPtr->DpPtr,
			 XDP_DPCD_STATUS_LANE_2_3, 1,
			 &UsrHpdPulseData->Lane2Sts);
	Status |= XDp_TxAuxRead(XDpTxSsPtr->DpPtr,
			 XDP_DPCD_LANE_ALIGN_STATUS_UPDATED, 1,
			 &UsrHpdPulseData->LaneAlignStatus);
	Status |= XDp_TxAuxRead(XDpTxSsPtr->DpPtr,
			 XDP_DPCD_LANE_COUNT_SET, 1,
			 &UsrHpdPulseData->LaneSet);
	Status |= XDp_TxAuxRead(XDpTxSsPtr->DpPtr,
			 XDP_DPCD_LINK_BW_SET, 1, &UsrHpdPulseData->BwSet);
	Status |= XDp_TxAuxRead(XDpTxSsPtr->DpPtr,
			XDP_DPCD_LINK_BW_SET, 1, &UsrHpdPulseData->BwSet);
	Status |= XDp_TxAuxRead(XDpTxSsPtr->DpPtr,
			XDP_DPCD_LANE_COUNT_SET, 1, &UsrHpdPulseData->LaneSet);
	Status |= XDp_TxGetEdidBlock(XDpTxSsPtr->DpPtr, UsrHpdPulseData->Edid,
		  0);
	if(Status ! = XST_SUCCESS){
		xdbg_printf(XDBG_DEBUG_GENERAL, "AUX access had trouble!\r\n");
	}
}

/*****************************************************************************/
/**
*
* This function installs an asynchronous callback function for the given
* HandlerType:
*
* <pre>
* HandlerType                              Callback Function HandlerType
* ---------------------------------------- ------------------------------------
* (XDPTXSS_HANDLER_DP_HPD_EVENT)           XDP_TX_HANDLER_HPDEVENT
* (XDPTXSS_HANDLER_DP_HPD_PULSE)           XDP_TX_HANDLER_HPDPULSE
* (XDPTXSS_HANDLER_DP_LANE_COUNT_CHG)      XDP_TX_HANDLER_LANECNTCHANGE
* (XDPTXSS_HANDLER_DP_LINK_RATE_CHG)       XDP_TX_HANDLER_LINKRATECHANGE
* (XDPTXSS_HANDLER_DP_PE_VS_ADJUST)        XDP_TX_HANDLER_PEVSADJUST
* (XDPTXSS_HANDLER_HDCP_RPTR_EXCHG)        XHdcp1x_SetCallBack
* (XDPTXSS_HANDLER_DP_SET_MSA)             XDP_TX_HANDLER_SETMSA
* </pre>
*
* @param	InstancePtr is a pointer to the XDpTxSs core instance. 
* @param	HandlerType specifies the type of handler. 
* @param	CallbackFunc is the address of the callback function. 
* @param	CallbackRef is a user data item that will be passed to the
*		callback function when it is invoked. 
*
* @return
*		- XST_SUCCESS if callback function installed successfully. 
*		- XST_INVALID_PARAM when HandlerType is invalid. 
*
* @note		Invoking this function for a handler that already has been
*		installed replaces it with the new handler. 
*
******************************************************************************/
u32 XDpTxSs_SetCallBack(XDpTxSs *InstancePtr, u32 HandlerType,
			void *CallbackFunc, void *CallbackRef)
{
	u32 Status;

	/* Verify arguments. */ 
	Xil_AssertNonvoid(InstancePtr ! = NULL);
	Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
	Xil_AssertNonvoid(HandlerType >= XDPTXSS_HANDLER_DP_HPD_EVENT);
	Xil_AssertNonvoid(CallbackFunc ! = NULL);
	Xil_AssertNonvoid(CallbackRef ! = NULL);

	/* Assign callback based on handler type */
	switch (HandlerType) {
		case XDPTXSS_HANDLER_DP_HPD_EVENT:
			XDp_TxSetCallback(InstancePtr->DpPtr,
					XDP_TX_HANDLER_HPDEVENT,
					CallbackFunc, CallbackRef);
			Status = XST_SUCCESS;
			break;

		case XDPTXSS_DRV_HANDLER_DP_HPD_EVENT:
			XDp_TxSetCallback(InstancePtr->DpPtr,
				XDP_TX_HANDLER_DRV_HPDEVENT,
				CallbackFunc, CallbackRef);
			Status = XST_SUCCESS;
			break;

		case XDPTXSS_HANDLER_DP_HPD_PULSE:
			XDp_TxSetCallback(InstancePtr->DpPtr,
				XDP_TX_HANDLER_HPDPULSE,
				CallbackFunc, CallbackRef);
			Status = XST_SUCCESS;
			break;

		case XDPTXSS_DRV_HANDLER_DP_HPD_PULSE:
			XDp_TxSetCallback(InstancePtr->DpPtr,
				XDP_TX_HANDLER_DRV_HPDPULSE,
				CallbackFunc, CallbackRef);
			Status = XST_SUCCESS;
			break;

		case XDPTXSS_HANDLER_DP_LANE_COUNT_CHG:
			XDp_TxSetCallback(InstancePtr->DpPtr,
				XDP_TX_HANDLER_LANECNTCHANGE,
				CallbackFunc, CallbackRef);
			Status = XST_SUCCESS;
			break;

		case XDPTXSS_HANDLER_DP_LINK_RATE_CHG:
			XDp_TxSetCallback(InstancePtr->DpPtr,
				XDP_TX_HANDLER_LINKRATECHANGE,
				CallbackFunc, CallbackRef);
			Status = XST_SUCCESS;
			break;

		case XDPTXSS_HANDLER_DP_PE_VS_ADJUST:
			XDp_TxSetCallback(InstancePtr->DpPtr,
				XDP_TX_HANDLER_PEVSADJUST,
				CallbackFunc, CallbackRef);
			Status = XST_SUCCESS;
			break;

#if (XPAR_XHDCP_NUM_INSTANCES > 0)
		case XDPTXSS_HANDLER_HDCP_RPTR_EXCHG:
			XHdcp1x_SetCallBack(InstancePtr->Hdcp1xPtr,
				XHDCP1X_RPTR_HDLR_REPEATER_EXCHANGE,
					CallbackFunc, CallbackRef);
			Status = XST_SUCCESS;
			break;
#endif

		case XDPTXSS_HANDLER_DP_SET_MSA:
			XDp_TxSetCallback(InstancePtr->DpPtr,
				XDP_TX_HANDLER_SETMSA,
				CallbackFunc, CallbackRef);
			Status = XST_SUCCESS;
			break;

		default:
			Status = XST_INVALID_PARAM;
			break;
	}

	return Status;
}

/*****************************************************************************/
/**
*
* This function installs a custom delay/sleep function to be used by the
* DisplayPort TX Subsystem. 
*
* @param	InstancePtr is a pointer to the XDpTxSs instance. 
* @param	CallbackFunc is the address to the callback function. 
* @param	CallbackRef is the user data item (microseconds to delay) that
*		will be passed to the custom sleep/delay function when it is
*		invoked. 
*
* @return	None. 
*
* @note		None. 
*
******************************************************************************/
void XDpTxSs_SetUserTimerHandler(XDpTxSs *InstancePtr,
		XDpTxSs_TimerHandler CallbackFunc, void *CallbackRef)
{
	/* Verify arguments. */ 
	Xil_AssertVoid(InstancePtr ! = NULL);
	Xil_AssertVoid(CallbackFunc ! = NULL);
	Xil_AssertVoid(CallbackRef ! = NULL);

	/* Set custom timer wait handler */
	XDp_SetUserTimerHandler(InstancePtr->DpPtr, CallbackFunc, CallbackRef);
}
/** @} */
