/****************************************************************************** * * Copyright (C) 2015 Xilinx, Inc. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * Use of the Software is limited solely to applications: * (a) running on a Xilinx device, or * (b) that interact with a Xilinx device through a bus or interconnect. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Except as contained in this notice, the name of the Xilinx shall not be used * in advertising or otherwise to promote the sale, use or other dealings in * this Software without prior written authorization from Xilinx. * ******************************************************************************/ /*****************************************************************************/ /** * * @file xdprxss_mst_example.c * * This file contains a design example using the XDpRxSs driver in single stream * (SST) transport or multi-stream transport (MST) mode. * * @note For this example to display output, the user need to implement * initialization of the system (DpRxSs_PlatformInit), Video Phy * (DpRxSs_VideoPhyInit), start DisplayPort RX subsystem * (XDpRxSs_Start) and DisplayPort TX Subsystem setup * (DpTxSs_Setup). * The input to the Subsystem is from RX (GT). * This example requires an interrupt controller in the system. * The functions DpRxSs_PlatformInit, DpRxSs_VideoPhyInit and * DpTxSs_Setup are declared and are left up to the user to * implement. * *
* MODIFICATION HISTORY: * * Ver Who Date Changes * ---- --- -------- -------------------------------------------------- * 1.00 sha 07/29/15 Initial release. ** ******************************************************************************/ /***************************** Include Files *********************************/ #include "xdprxss.h" #include "xil_printf.h" #include "xil_types.h" #include "xparameters.h" #include "xstatus.h" #include "xtmrctr.h" #ifdef XPAR_INTC_0_DEVICE_ID /* For MicroBlaze systems. */ #include "xintc.h" #else /* For ARM/Zynq SoC systems. */ #include "xscugic.h" #endif /* XPAR_INTC_0_DEVICE_ID */ /************************** Constant Definitions *****************************/ /* * The following constants map to the names of the hardware instances. * They are only defined here such that a user can easily change all the * needed device IDs in one place. * There is only one interrupt controlled to be selected from SCUGIC and GPIO * INTC. INTC selection is based on INTC parameters defined xparameters.h file. */ #ifdef XPAR_INTC_0_DEVICE_ID #define XINTC_DPRXSS_DP_INTERRUPT_ID XPAR_INTC_0_DPRXSS_0_DPRXSS_DP_IRQ_VEC_ID #define XINTC_DEVICE_ID XPAR_INTC_0_DEVICE_ID #define XINTC XIntc #define XINTC_HANDLER XIntc_InterruptHandler #else /* Else part */ #define XINTC_DPRXSS_DP_INTERRUPT_ID XPAR_INTC_0_DPRXSS_0_DPRXSS_DP_IRQ_VEC_ID #define XINTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID #define XINTC XScuGic #define XINTC_HANDLER XScuGic_InterruptHandler #endif /* XPAR_INTC_0_DEVICE_ID */ /* The unique device ID of the Timer controller instance to be used */ #define XTMR_CTRL_DEVICE_ID XPAR_TMRCTR_0_DEVICE_ID /* The unique device ID of the DisplayPort Receiver Subsystem HIP instance * to be used */ #define XDPRXSS_DEVICE_ID XPAR_DPRXSS_0_DEVICE_ID /* Example will run either in MST or SST mode based upon config parameters. * In MST mode, this example exposes maximum number of input and output ports * of DP RX that will be included while replying to sideband messages from TX. */ #define DPRXSS_LINK_RATE XDPRXSS_LINK_BW_SET_540GBPS #define DPRXSS_LANE_COUNT XDPRXSS_LANE_COUNT_SET_4 /***************** Macros (Inline Functions) Definitions *********************/ /**************************** Type Definitions *******************************/ /************************** Function Prototypes ******************************/ u32 DpRxSs_MstExample(u16 DeviceId); u32 DpRxSs_PlatformInit(void); u32 DpRxSs_VideoPhyInit(void); u32 DpTxSs_Setup(void); /* Interrupt helper functions */ u32 DpRxSs_SetupIntrSystem(void); void DpRxSs_VideoModeHandler(void *InstancePtr); void DpRxSs_NoVideoHandler(void *InstancePtr); void DpRxSs_VerticalBlankHandler(void *InstancePtr); void DpRxSs_TrainingLostHandler(void *InstancePtr); void DpRxSs_TrainingDoneHandler(void *InstancePtr); void DpRxSs_DownReqestHandler(void *InstancePtr); void DpRxSs_DownReplyHandler(void *InstancePtr); void DpRxSs_UnplugHandler(void *InstancePtr); void DpRxSs_LinkBandwidthHandler(void *InstancePtr); void DpRxSs_PllResetHandler(void *InstancePtr); u32 DpRxSs_SetupTimerHandler(void); void DpRxSs_CustomWaitUs(void *InstancePtr, u32 MicroSeconds); void DpRxSs_DetectResolution(XDpRxSs *InstancePtr); /************************** Variable Definitions *****************************/ XDpRxSs DpRxSsInst; /* The DPRX Subsystem instance.*/ XINTC IntcInst; /* The interrupt controller instance. */ XTmrCtr TmrCtrInst; /* The timer counter instance. */ /************************** Function Definitions *****************************/ /*****************************************************************************/ /** * * This is the main function for XDpRxSs SST/MST example. * * @param None. * * @return * - XST_SUCCESS if the MST/SST example passed. * - XST_FAILURE if the MST/SST example was unsuccessful. * * @note None. * ******************************************************************************/ int main() { u32 Status; xil_printf("------------------------------------------\n\r"); xil_printf("DisplayPort RX Subsystem SST/MST example\n\r"); xil_printf("(c) 2015 by Xilinx\n\r"); xil_printf("-------------------------------------------\n\r\n\r"); Status = DpRxSs_MstExample(XDPRXSS_DEVICE_ID); if (Status != XST_SUCCESS) { xil_printf("DisplayPort RX Subsystem SST/MST example failed." "\n\r"); return XST_FAILURE; } xil_printf("DisplayPort RX Subsystem SST/MST example passed\n\r"); return XST_SUCCESS; } /*****************************************************************************/ /** * * This function is the main entry point for the MST/SST example using the * XDpRxSs driver. * * @param DeviceId is the unique device ID of the DisplayPort RX * Subsystem core. * * @return * - XST_SUCCESS if DisplayPort RX Subsystem configured in SST/MST * successfully. * - XST_FAILURE, if DisplayPort RX Subsystem failed to configure * in SST/MST. * * @note None. * ******************************************************************************/ u32 DpRxSs_MstExample(u16 DeviceId) { u32 Status; XDpRxSs_Config *ConfigPtr; /* Do platform initialization in this function. This is hardware * system specific. It is up to the user to implement this function. */ xil_printf("PlatformInit\n\r"); Status = DpRxSs_PlatformInit(); if (Status != XST_SUCCESS) { xil_printf("Platform init failed!\n\r"); } xil_printf("Platform initialization done.\n\r"); /* Obtain the device configuration for the DisplayPort RX Subsystem */ ConfigPtr = XDpRxSs_LookupConfig(DeviceId); if (!ConfigPtr) { return XST_FAILURE; } /* Copy the device configuration into the DpRxSsInst's Config * structure. */ Status = XDpRxSs_CfgInitialize(&DpRxSsInst, ConfigPtr, ConfigPtr->BaseAddress); if (Status != XST_SUCCESS) { xil_printf("DPRXSS config initialization failed.\n\r"); return XST_FAILURE; } /* Check for SST/MST support */ if (DpRxSsInst.UsrOpt.MstSupport) { xil_printf("\n\rINFO:DPRXSS is MST enabled. DPRXSS can be " "switched to SST/MST\n\r\n\r"); } else { xil_printf("\n\rINFO:DPRXSS is SST enabled. DPRXSS works " "only in SST mode.\n\r\n\r"); } /* Set up a timer. */ DpRxSs_SetupTimerHandler(); Status = DpRxSs_SetupIntrSystem(); if (Status != XST_SUCCESS) { xil_printf("ERR: Interrupt system setup failed.\n\r"); return XST_FAILURE; } /* Set Link rate and lane count to maximum */ XDpRxSs_SetLinkRate(&DpRxSsInst, DPRXSS_LINK_RATE); XDpRxSs_SetLaneCount(&DpRxSsInst, DPRXSS_LANE_COUNT); /* Start DPRXSS */ Status = XDpRxSs_Start(&DpRxSsInst); if (Status != XST_SUCCESS) { xil_printf("ERR:DPRX SS start failed\n\r"); return XST_FAILURE; } /* Setup Video Phy, left to the user for implementation */ DpRxSs_VideoPhyInit(); /* Setup DPTX SS, left to the user for implementation */ DpTxSs_Setup(); return XST_SUCCESS; } /*****************************************************************************/ /** * * This function initialize required platform specific peripherals. * * @param None. * * @return * - XST_SUCCESS if required peripherals are initialized and * configured successfully. * - XST_FAILURE, otherwise. * * @note None. * ******************************************************************************/ u32 DpRxSs_PlatformInit(void) { /* User is responsible to setup platform specific initialization */ return XST_SUCCESS; } /*****************************************************************************/ /** * * This function configures Video Phy. * * @param None. * * @return * - XST_SUCCESS if Video Phy configured successfully. * - XST_FAILURE, otherwise. * * @note None. * ******************************************************************************/ u32 DpRxSs_VideoPhyInit(void) { /* User is responsible to setup Video Phy */ return XST_SUCCESS; } /*****************************************************************************/ /** * * This function configures DisplayPort TX Subsystem. * * @param None. * * @return * - XST_SUCCESS if DPTX Subsystem configured successfully. * - XST_FAILURE, otherwise. * * @note None. * ******************************************************************************/ u32 DpTxSs_Setup(void) { /* User is responsible to setup Video Phy */ return XST_SUCCESS; } /*****************************************************************************/ /** * * This function sets up a custom timer which the driver will use for MicroBlaze * systems. * * @param None. * * @return * - XST_SUCCESS if a timer controller exists for use. * - XST_FAILURE otherwise. * * @note A timer controller must be present in the system. * ******************************************************************************/ u32 DpRxSs_SetupTimerHandler(void) { u32 Status; Status = XTmrCtr_Initialize(&TmrCtrInst, XTMR_CTRL_DEVICE_ID); if (Status != XST_SUCCESS) { return XST_FAILURE; } /* Set a custom timer handler for improved delay accuracy on MicroBlaze * systems since the driver does not assume/have a dependency on the * system having a timer in the FPGA. * Note: This only has an affect for MicroBlaze systems since the Zynq * ARM SoC contains a timer, which is used when the driver calls the * delay function. */ XDpRxSs_SetUserTimerHandler(&DpRxSsInst, &DpRxSs_CustomWaitUs, &TmrCtrInst); XTmrCtr_SetResetValue(DpRxSsInst.DpPtr->UserTimerPtr, 0, 0); XTmrCtr_Reset(DpRxSsInst.DpPtr->UserTimerPtr, 0); return XST_SUCCESS; } /*****************************************************************************/ /** * * This function is used to override the driver's default sleep functionality. * For MicroBlaze systems, the XDpRxSs_WaitUs driver function's default behavior * is to use the MB_Sleep function from microblaze_sleep.h, which is implemented * in software and only has millisecond accuracy. For this reason, using a * hardware timer is preferable. For ARM/Zynq SoC systems, the SoC's timer is * used - XDpRxSs_WaitUs will ignore this custom timer handler. * * @param InstancePtr is a pointer to the XDpRxSs core instance. * @param MicroSeconds is the number of microseconds to delay/sleep for. * * @return None. * * @note Use the XDpRxSs_SetUserTimerHandler driver function to set this * function as the handler for when the XDpRxSs_WaitUs driver * function is called. * ******************************************************************************/ void DpRxSs_CustomWaitUs(void *InstancePtr, u32 MicroSeconds) { XDpRxSs *DpRxSsPtr = (XDpRxSs *)InstancePtr; u32 TimerVal; XTmrCtr_Start(DpRxSsPtr->DpPtr->UserTimerPtr, 0); /* Wait specified number of useconds. */ do { TimerVal = XTmrCtr_GetValue(DpRxSsPtr->DpPtr->UserTimerPtr, 0); } while (TimerVal < (MicroSeconds * (DpRxSsPtr->DpPtr->Config.SAxiClkHz / 1000000))); XTmrCtr_Stop(DpRxSsPtr->DpPtr->UserTimerPtr, 0); } /*****************************************************************************/ /** * * This function sets up the interrupt system so interrupts can occur for the * DisplayPort RX Subsystem core. The function is application-specific since * the actual system may or may not have an interrupt controller. The DPRX * Subsystem core could be directly connected to a processor without an * interrupt controller. The user should modify this function to fit the * application. * * @param None * * @return * - XST_SUCCESS if interrupt setup was successful. * - A specific error code defined in "xstatus.h" if an error * occurs. * * @note None. * ******************************************************************************/ u32 DpRxSs_SetupIntrSystem(void) { u32 Status; XINTC *IntcInstPtr = &IntcInst; /* Set callbacks for the required interrupts */ XDpRxSs_SetCallBack(&DpRxSsInst, XDPRXSS_HANDLER_DP_VM_CHG_EVENT, DpRxSs_VideoModeHandler, &DpRxSsInst); XDpRxSs_SetCallBack(&DpRxSsInst, XDPRXSS_HANDLER_DP_NO_VID_EVENT, DpRxSs_NoVideoHandler, &DpRxSsInst); XDpRxSs_SetCallBack(&DpRxSsInst, XDPRXSS_HANDLER_DP_VBLANK_EVENT, DpRxSs_VerticalBlankHandler, &DpRxSsInst); XDpRxSs_SetCallBack(&DpRxSsInst, XDPRXSS_HANDLER_DP_TLOST_EVENT, DpRxSs_TrainingLostHandler, &DpRxSsInst); XDpRxSs_SetCallBack(&DpRxSsInst, XDPRXSS_HANDLER_DP_TDONE_EVENT, DpRxSs_TrainingDoneHandler, &DpRxSsInst); XDpRxSs_SetCallBack(&DpRxSsInst, XDPRXSS_HANDLER_DP_DWN_REQ_EVENT, DpRxSs_DownReqestHandler, &DpRxSsInst); XDpRxSs_SetCallBack(&DpRxSsInst, XDPRXSS_HANDLER_DP_DWN_REP_EVENT, DpRxSs_DownReplyHandler, &DpRxSsInst); XDpRxSs_SetCallBack(&DpRxSsInst, XDPRXSS_HANDLER_UNPLUG_EVENT, DpRxSs_UnplugHandler, &DpRxSsInst); XDpRxSs_SetCallBack(&DpRxSsInst, XDPRXSS_HANDLER_LINKBW_EVENT, DpRxSs_LinkBandwidthHandler, &DpRxSsInst); XDpRxSs_SetCallBack(&DpRxSsInst, XDPRXSS_HANDLER_PLL_RESET_EVENT, DpRxSs_PllResetHandler, &DpRxSsInst); #ifdef XPAR_INTC_0_DEVICE_ID /* Initialize the interrupt controller driver so that it's ready to * use, specify the device ID that was generated in xparameters.h */ Status = XIntc_Initialize(IntcInstPtr, XINTC_DEVICE_ID); if (Status != XST_SUCCESS) { xil_printf("Intc initialization failed!\n\r"); return XST_FAILURE; } /* Hook up interrupt service routine */ Status = XIntc_Connect(IntcInstPtr, XINTC_DPRXSS_DP_INTERRUPT_ID, (XInterruptHandler)XDpRxSs_DpIntrHandler, &DpRxSsInst); if (Status != XST_SUCCESS) { xil_printf("ERR: DP RX SS DP interrupt connect failed!\n\r"); return XST_FAILURE; } /* Enable the interrupt vector at the interrupt controller */ XIntc_Enable(IntcInstPtr, XINTC_DPRXSS_DP_INTERRUPT_ID); /* Start the interrupt controller such that interrupts are recognized * and handled by the processor */ Status = XIntc_Start(IntcInstPtr, XIN_REAL_MODE); if (Status != XST_SUCCESS) { return XST_FAILURE; } #else /* The configuration parameters of the interrupt controller */ XScuGic_Config *IntcConfig; /* Initialize the interrupt controller driver so that it is ready to * use. */ IntcConfig = XScuGic_LookupConfig(XINTC_DEVICE_ID); if (NULL == IntcConfig) { return XST_FAILURE; } Status = XScuGic_CfgInitialize(IntcInstPtr, IntcConfig, IntcConfig->CpuBaseAddress); if (Status != XST_SUCCESS) { return XST_FAILURE; } /* Connect the device driver handler that will be called when an * interrupt for the device occurs, the handler defined above performs * the specific interrupt processing for the device */ Status = XScuGic_Connect(IntcInstPtr, XINTC_DPRXSS_DP_INTERRUPT_ID, (Xil_InterruptHandler)XDpRxSs_DpIntrHandler, &DpRxSsInst); if (Status != XST_SUCCESS) { xil_printf("ERR: DP RX SS DP interrupt connect failed!\n\r"); return XST_FAILURE; } /* Enable the interrupt for the Pixel Splitter device */ XScuGic_Enable(IntcInstance, XINTC_DPRXSS_DP_INTERRUPT_ID); #endif /* Initialize the exception table. */ Xil_ExceptionInit(); /* Register the interrupt controller handler with the exception * table. */ Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT, (Xil_ExceptionHandler)XINTC_HANDLER, IntcInstPtr); /* Enable exceptions. */ Xil_ExceptionEnable(); return (XST_SUCCESS); } /*****************************************************************************/ /** * * This function is the callback function for when a video mode change interrupt * occurs. * * @param InstancePtr is a pointer to the XDpRxSs instance. * * @return None. * * @note None. * ******************************************************************************/ void DpRxSs_VideoModeHandler(void *InstancePtr) { XDpRxSs *DpRxSsPtr = (XDpRxSs *)InstancePtr; xil_printf("Interrupt: video mode change.\n\r"); if (DpRxSsPtr->VBlankCount >= 20) { DpRxSs_DetectResolution(DpRxSsPtr); /* User is responsible for resetting the video pipe */ } } /*****************************************************************************/ /** * * This function will present the resolution of the incoming video stream. * * @param InstancePtr is a pointer to the XDpRxSs instance. * * @return None. * * @note The resolution will be rounded up to the nearest resolution * present in the XVidC_VideoTimingModes table. * ******************************************************************************/ void DpRxSs_DetectResolution(XDpRxSs *InstancePtr) { u32 DpHres, DpVres; u32 GetResCount = 0; do { DpHres = XDpRxSs_ReadReg(InstancePtr->DpPtr->Config.BaseAddr, XDPRXSS_MSA_HRES); DpVres = XDpRxSs_ReadReg(InstancePtr->DpPtr->Config.BaseAddr, XDPRXSS_MSA_VRES); GetResCount++; XDpRxSs_WaitUs(InstancePtr, 1000); } while (((DpHres == 0) || (DpVres == 0)) && (GetResCount < 2000)); xil_printf("\n*** Detected resolution: %u x %u ***\n", DpHres, DpVres); } /*****************************************************************************/ /** * * This function is the callback function for when a no video interrupt occurs. * * @param InstancePtr is a pointer to the XDpRxSs instance. * * @return None. * * @note None. * ******************************************************************************/ void DpRxSs_NoVideoHandler(void *InstancePtr) { xil_printf("Interrupt: no-video flags in the VBID field after active " "video has been received.\n\r"); } /*****************************************************************************/ /** * * This function is the callback function for when the training done interrupt * occurs. * * @param InstancePtr is a pointer to the XDpRxSs instance. * * @return None. * * @note None. * ******************************************************************************/ void DpRxSs_TrainingDoneHandler(void *InstancePtr) { xil_printf("Interrupt: training done.\n\r"); } /*****************************************************************************/ /** * * This function is the callback function for when a down request interrupt * occurs. * * @param InstancePtr is a pointer to the XDpRxSs instance. * * @return None. * * @note None. * ******************************************************************************/ void DpRxSs_DownReqestHandler(void *InstancePtr) { XDpRxSs *DpRxSsPtr = (XDpRxSs *)InstancePtr; xil_printf("Interrupt: down request.\n\r"); XDpRxSs_HandleDownReq(DpRxSsPtr); } /*****************************************************************************/ /** * * This function is the callback function for when a down reply interrupt * occurs. * * @param InstancePtr is a pointer to the XDpRxSs instance. * * @return None. * * @note None. * ******************************************************************************/ void DpRxSs_DownReplyHandler(void *InstancePtr) { xil_printf("Interrupt: down reply.\n\r"); } /*****************************************************************************/ /** * * This function is the callback function for when a vertical blank interrupt * occurs. * * @param InstancePtr is a pointer to the XDpRxSs instance. * * @return None. * * @note None. * ******************************************************************************/ void DpRxSs_VerticalBlankHandler(void *InstancePtr) { XDpRxSs *DpRxSsPtr = (XDpRxSs *)InstancePtr; u32 Status; if (DpRxSsPtr->VBlankEnable) { DpRxSsPtr->VBlankCount++; xil_printf("Interrupt: vertical blanking (frame %d).\n", DpRxSsPtr->VBlankCount); /* Wait until 20 frames have been received before forwarding or * outputting any video stream. */ if (DpRxSsPtr->VBlankCount >= 20) { DpRxSsPtr->VBlankEnable = 0; DpRxSsPtr->VBlankCount = 0; XDp_RxInterruptDisable(DpRxSsPtr->DpPtr, XDP_RX_INTERRUPT_MASK_VBLANK_MASK); Status = XDpRxSs_CheckLinkStatus(InstancePtr); if (Status == XST_SUCCESS) { /* User is responsible for resetting the video * pipe. */ /* Detect resolution */ DpRxSs_DetectResolution(InstancePtr); } } } } /*****************************************************************************/ /** * * This function is the callback function for when a training lost interrupt * occurs. * * @param InstancePtr is a pointer to the XDpRxSs instance. * * @return None. * * @note None. * ******************************************************************************/ void DpRxSs_TrainingLostHandler(void *InstancePtr) { xil_printf("Interrupt: training done.\n\r"); } /*****************************************************************************/ /** * * This function is the callback function for when the unplug event occurs. * * @param InstancePtr is a pointer to the XDpRxSs instance. * * @return None. * * @note None. * ******************************************************************************/ void DpRxSs_UnplugHandler(void *InstancePtr) { xil_printf("Interrupt: unplug event.\n\r"); /* User is responsible to take corrective actions */ } /*****************************************************************************/ /** * * This function is the callback function for when the link bandwidth change * occurs. * * @param InstancePtr is a pointer to the XDpRxSs instance. * * @return None. * * @note None. * ******************************************************************************/ void DpRxSs_LinkBandwidthHandler(void *InstancePtr) { xil_printf("Interrupt: link bandwidth change request.\n\r"); /* User is responsible to re-initialize Video Phy if link rate * is mismatching. */ } /*****************************************************************************/ /** * * This function is the callback function for PLL reset request. * * @param InstancePtr is a pointer to the XDpRxSs instance. * * @return None. * * @note None. * ******************************************************************************/ void DpRxSs_PllResetHandler(void *InstancePtr) { xil_printf("Interrupt: PLL reset request.\n\r"); /* User is responsible to reset Video Phy */ }