/** * This function is the interrupt handler for the XDp driver operating in TX * mode. * * When an interrupt happens, it first detects what kind of interrupt happened, * then decides which callback function to invoke. * * @param InstancePtr is a pointer to the XDp instance. * * @return None. * * @note None. * *******************************************************************************/ static void XDp_TxInterruptHandler(XDp *InstancePtr) { u32 IntrStatus; u8 HpdEventDetected; u8 HpdPulseDetected; u32 HpdDuration; u32 IntrMask; /* Determine what kind of interrupt occurred. * Note: XDP_TX_INTERRUPT_STATUS is an RC (read-clear) register. */ IntrStatus = XDp_ReadReg(InstancePtr->Config.BaseAddr, XDP_TX_INTERRUPT_STATUS); IntrStatus &= ~XDp_ReadReg(InstancePtr->Config.BaseAddr, XDP_TX_INTERRUPT_MASK); IntrMask = XDp_ReadReg(InstancePtr->Config.BaseAddr, XDP_TX_INTERRUPT_MASK); HpdEventDetected = IntrStatus & XDP_TX_INTERRUPT_STATUS_HPD_EVENT_MASK; HpdPulseDetected = IntrStatus & XDP_TX_INTERRUPT_STATUS_HPD_PULSE_DETECTED_MASK; if (HpdEventDetected) { /* Mask interrupts while event handling is taking place. API * will error out in case of a disconnection event anyway. */ XDp_WriteReg(InstancePtr->Config.BaseAddr, XDP_TX_INTERRUPT_MASK, IntrMask | XDP_TX_INTERRUPT_MASK_HPD_EVENT_MASK); InstancePtr->TxInstance.HpdEventHandler( InstancePtr->TxInstance.HpdEventCallbackRef); } else if (HpdPulseDetected && XDp_TxIsConnected(InstancePtr)) { /* Mask interrupts while event handling is taking place. */ XDp_WriteReg(InstancePtr->Config.BaseAddr, XDP_TX_INTERRUPT_MASK, IntrMask | XDP_TX_INTERRUPT_MASK_HPD_PULSE_DETECTED_MASK); /* The source device must debounce the incoming HPD signal by * sampling the value at an interval greater than 0.500 ms. An * HPD pulse should be of width 0.5 ms - 1.0 ms. */ HpdDuration = XDp_ReadReg(InstancePtr->Config.BaseAddr, XDP_TX_HPD_DURATION); if (HpdDuration >= 500) { InstancePtr->TxInstance.HpdPulseHandler( InstancePtr->TxInstance.HpdPulseCallbackRef); } } /* Unmask previously masked interrupts once handling is done. */ XDp_WriteReg(InstancePtr->Config.BaseAddr, XDP_TX_INTERRUPT_MASK, IntrMask); }
/** * This function reconfigures the DP159 retimer based on the current lane count * and link rate configuration. * * @param InstancePtr is a pointer to the XDp instance. * @param IicInstancePtr is a pointer to the XIic instance representing * the I2C controller connected to the same I2C bus which the DP159 * is addressable from. * @param ConfigType determines which DP159 programming sequence to use. * * @return None. * * @note None. * *******************************************************************************/ static void Dprx_Dp159Config(XDp *InstancePtr, XIic *IicInstancePtr, u8 ConfigType) { u8 LaneCount; u8 LinkRate; LaneCount = XDp_ReadReg(InstancePtr->Config.BaseAddr, XDP_RX_OVER_LANE_COUNT_SET); LaneCount &= XDP_RX_OVER_LANE_COUNT_SET_MASK; LinkRate = XDp_ReadReg(InstancePtr->Config.BaseAddr, XDP_RX_OVER_LINK_BW_SET); XVidC_Dp159Config(IicInstancePtr, ConfigType, LinkRate, LaneCount); }
/** * This function will present the resolution of the incoming video stream. * * @param InstancePtr is a pointer to the XDp instance. * * @return None. * * @note The resolution will be rounded up to the nearest resolution * present in the XVidC_VideoTimingModes table. * *******************************************************************************/ static void Dprx_DetectResolution(void *InstancePtr) { u32 DpHres, DpVres; u32 GetResCount = 0; do { DpHres = (XDp_ReadReg(((XDp *)InstancePtr)->Config.BaseAddr, XDP_RX_MSA_HRES)); DpVres = (XDp_ReadReg(((XDp *)InstancePtr)->Config.BaseAddr, XDP_RX_MSA_VHEIGHT)); GetResCount++; XDp_WaitUs(InstancePtr, 1000); } while (((DpHres == 0) || (DpVres == 0)) && (GetResCount < 2000)); xil_printf("\n*** Detected resolution: %d x %d ***\n", DpHres, DpVres); }
/** * This function disables interrupts associated with the specified mask. * * @param InstancePtr is a pointer to the XDp instance. * @param Mask specifies which interrupts should be disabled. Bits set to * 1 will disable the corresponding interrupts. * * @return None. * * @note None. * *******************************************************************************/ void XDp_RxInterruptDisable(XDp *InstancePtr, u32 Mask) { u32 MaskVal; /* Verify arguments. */ Xil_AssertVoid(InstancePtr != NULL); Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); Xil_AssertVoid(XDp_GetCoreType(InstancePtr) == XDP_RX); MaskVal = XDp_ReadReg(InstancePtr->Config.BaseAddr, XDP_RX_INTERRUPT_CAUSE); MaskVal |= Mask; XDp_WriteReg(InstancePtr->Config.BaseAddr, XDP_RX_INTERRUPT_MASK, MaskVal); }
/** * This function trains the link and allocates stream payloads. * * @param InstancePtr is a pointer to the XDp instance. * @param DeviceId is the unique device ID of the DisplayPort TX core * instance. * * @return * - XST_SUCCESS if MST allocation was successful. * - XST_ERROR_COUNT_MAX if the ACT trigger was lost. * - XST_FAILURE otherwise. * * @note None. * *******************************************************************************/ u32 Dptx_MstExampleRun(XDp *InstancePtr) { u32 Status; u32 MaskVal; u8 StreamIndex; XVidC_VideoMode VideoMode = USE_VIDEO_MODE; u8 Bpc = USE_BPC; u8 NumStreams = NUM_STREAMS; /* Limit the number of streams to configure based on the configuration * of the DisplayPort core. */ if (NumStreams > InstancePtr->Config.NumMstStreams) { NumStreams = InstancePtr->Config.NumMstStreams; } XDp_TxEnableTrainAdaptive(InstancePtr, TRAIN_ADAPTIVE); XDp_TxSetHasRedriverInPath(InstancePtr, TRAIN_HAS_REDRIVER); /* A DisplayPort connection must exist at this point. See the interrupt * and polling examples for waiting for connection events. */ Status = Dptx_StartLink(InstancePtr); if (Status != XST_SUCCESS) { xil_printf("Link Training failed.\n"); return XST_FAILURE; } #ifdef USE_DELAYS_FOR_MST InstancePtr->TxInstance.AuxDelayUs = 30000; InstancePtr->TxInstance.SbMsgDelayUs = 100000; #else InstancePtr->TxInstance.AuxDelayUs = 0; InstancePtr->TxInstance.SbMsgDelayUs = 0; #endif XDp_TxClearMsaValues(InstancePtr, XDP_TX_STREAM_ID1); XDp_TxClearMsaValues(InstancePtr, XDP_TX_STREAM_ID2); XDp_TxClearMsaValues(InstancePtr, XDP_TX_STREAM_ID3); XDp_TxClearMsaValues(InstancePtr, XDP_TX_STREAM_ID4); #ifdef ALLOCATE_FROM_SINKLIST /* Run topology discovery to determine what devices are accessible to * the DisplayPort TX. */ xil_printf("Find topology >>>\n"); InstancePtr->TxInstance.Topology.NodeTotal = 0; InstancePtr->TxInstance.Topology.SinkTotal = 0; Status = XDp_TxDiscoverTopology(InstancePtr); if (Status != XST_SUCCESS) { xil_printf("!!! A LINK_ADDRESS response from a branch device " "in the MST topology was not successfully received.\n"); return XST_FAILURE; } xil_printf("<<< Find topology DONE; # of sinks found = %d.\n", InstancePtr->TxInstance.Topology.SinkTotal); if (NumStreams > InstancePtr->TxInstance.Topology.SinkTotal) { NumStreams = InstancePtr->TxInstance.Topology.SinkTotal; } #endif /* Enable multi-stream transport (MST) mode for this example. */ XDp_TxMstCfgModeEnable(InstancePtr); for (StreamIndex = 0; StreamIndex < NumStreams; StreamIndex++) { XDp_TxMstCfgStreamEnable(InstancePtr, XDP_TX_STREAM_ID1 + StreamIndex); } for (StreamIndex = NumStreams; StreamIndex < 4; StreamIndex++) { XDp_TxMstCfgStreamDisable(InstancePtr, XDP_TX_STREAM_ID1 + StreamIndex); } /* Specify the DisplayPort sink devices that each enabled stream will be * directed towards. */ #ifndef ALLOCATE_FROM_SINKLIST /* If topology discovery is not used, specify the relative addresses of * the DisplayPort sink devices. */ u8 Lct; u8 Rad[15]; if (XDp_TxMstStreamIsEnabled(InstancePtr, XDP_TX_STREAM_ID1)) { Lct = 2; Rad[0] = 8; XDp_TxSetStreamSinkRad(InstancePtr, XDP_TX_STREAM_ID1, Lct, Rad); } if (XDp_TxMstStreamIsEnabled(InstancePtr, XDP_TX_STREAM_ID2)) { Lct = 3; Rad[0] = 1; Rad[1] = 8; XDp_TxSetStreamSinkRad(InstancePtr, XDP_TX_STREAM_ID2, Lct, Rad); } if (XDp_TxMstStreamIsEnabled(InstancePtr, XDP_TX_STREAM_ID3)) { Lct = 4; Rad[0] = 1; Rad[1] = 1; Rad[2] = 8; XDp_TxSetStreamSinkRad(InstancePtr, XDP_TX_STREAM_ID3, Lct, Rad); } if (XDp_TxMstStreamIsEnabled(InstancePtr, XDP_TX_STREAM_ID4)) { Lct = 4; Rad[0] = 1; Rad[1] = 1; Rad[2] = 9; XDp_TxSetStreamSinkRad(InstancePtr, XDP_TX_STREAM_ID4, Lct, Rad); } #else /* If topology discovery is used, associate a stream number with a sink * number from the sink list obtained during topology discovery. The * sinks are numbered in the order that they were found during topology * discovery. */ if (XDp_TxMstStreamIsEnabled(InstancePtr, XDP_TX_STREAM_ID1)) { XDp_TxSetStreamSelectFromSinkList(InstancePtr, XDP_TX_STREAM_ID1, STREAM1_USE_SINKNUM); } if (XDp_TxMstStreamIsEnabled(InstancePtr, XDP_TX_STREAM_ID2)) { XDp_TxSetStreamSelectFromSinkList(InstancePtr, XDP_TX_STREAM_ID2, STREAM2_USE_SINKNUM); } if (XDp_TxMstStreamIsEnabled(InstancePtr, XDP_TX_STREAM_ID3)) { XDp_TxSetStreamSelectFromSinkList(InstancePtr, XDP_TX_STREAM_ID3, STREAM3_USE_SINKNUM); } if (XDp_TxMstStreamIsEnabled(InstancePtr, XDP_TX_STREAM_ID4)) { XDp_TxSetStreamSelectFromSinkList(InstancePtr, XDP_TX_STREAM_ID4, STREAM4_USE_SINKNUM); } #endif /* Reset MST mode in both the RX and TX. */ XDp_TxMstDisable(InstancePtr); XDp_TxMstEnable(InstancePtr); /* Set the main stream attributes (MSA) for each enabled stream (each * stream has an identical configuration). Then, set the configuration * for that stream in the corresponding DisplayPort TX registers. */ for (StreamIndex = 0; StreamIndex < 4; StreamIndex++) { if (XDp_TxMstStreamIsEnabled(InstancePtr, XDP_TX_STREAM_ID1 + StreamIndex)) { XDp_TxCfgMsaSetBpc(InstancePtr, XDP_TX_STREAM_ID1 + StreamIndex, Bpc); XDp_TxCfgMsaEnSynchClkMode(InstancePtr, XDP_TX_STREAM_ID1 + StreamIndex, 1); XDp_TxCfgMsaUseStandardVideoMode(InstancePtr, XDP_TX_STREAM_ID1 + StreamIndex, VideoMode); XDp_TxSetVideoMode(InstancePtr, XDP_TX_STREAM_ID1 + StreamIndex); } } /* Configure video stream source or generator here. This function needs * to be implemented in order for video to be displayed and is hardware * system specific. It is up to the user to implement this function. */ Dptx_StreamSrcSetup(InstancePtr); Dptx_StreamSrcConfigure(InstancePtr); Dptx_StreamSrcSync(InstancePtr); //////////////////////////////////// /* Mask interrupts while allocating payloads. */ MaskVal = XDp_ReadReg(InstancePtr->Config.BaseAddr, XDP_TX_INTERRUPT_MASK); XDp_WriteReg(InstancePtr->Config.BaseAddr, XDP_TX_INTERRUPT_MASK, 0x3F); /* Clear the payload ID table first. */ Status = XDp_TxClearPayloadVcIdTable(InstancePtr); if (Status != XST_SUCCESS) { return XST_DATA_LOST; } /* Allocate payloads. */ Status = XDp_TxAllocatePayloadStreams(InstancePtr); if (Status != XST_SUCCESS) { return XST_DATA_LOST; } /* Enable the main link. */ XDp_TxEnableMainLink(InstancePtr); /* Unmask interrupts. */ XDp_WriteReg(InstancePtr->Config.BaseAddr, XDP_TX_INTERRUPT_MASK, MaskVal); /* Do a final check to verify that the link wasn't lost. */ Status = XDp_TxCheckLinkStatus(InstancePtr, InstancePtr->TxInstance.LinkConfig.LaneCount); if (Status != XST_SUCCESS) { XDp_WaitUs(InstancePtr, 10000); return XST_DATA_LOST; } return XST_SUCCESS; }
/** * This function is the interrupt handler for the XDp driver operating in RX * mode. * * When an interrupt happens, it first detects what kind of interrupt happened, * then decides which callback function to invoke. * * @param InstancePtr is a pointer to the XDp instance. * * @return None. * * @note None. * *******************************************************************************/ static void XDp_RxInterruptHandler(XDp *InstancePtr) { u32 IntrStatus; /* Determine what kind of interrupts have occurred. * Note: XDP_RX_INTERRUPT_CAUSE is a RC (read-clear) register. */ IntrStatus = XDp_ReadReg(InstancePtr->Config.BaseAddr, XDP_RX_INTERRUPT_CAUSE); /* Training pattern 1 has started. */ if (IntrStatus & XDP_RX_INTERRUPT_CAUSE_TP1_MASK) { InstancePtr->RxInstance.IntrTp1Handler( InstancePtr->RxInstance.IntrTp1CallbackRef); } /* Training pattern 2 has started. */ if (IntrStatus & XDP_RX_INTERRUPT_CAUSE_TP2_MASK) { InstancePtr->RxInstance.IntrTp2Handler( InstancePtr->RxInstance.IntrTp2CallbackRef); } /* Training pattern 3 has started. */ if (IntrStatus & XDP_RX_INTERRUPT_CAUSE_TP3_MASK) { InstancePtr->RxInstance.IntrTp3Handler( InstancePtr->RxInstance.IntrTp3CallbackRef); } /* Training lost - the link has been lost. */ if (IntrStatus & XDP_RX_INTERRUPT_CAUSE_TRAINING_LOST_MASK) { InstancePtr->RxInstance.IntrTrainingLostHandler( InstancePtr->RxInstance.IntrTrainingLostCallbackRef); } /* The link has been trained. */ else if (IntrStatus & XDP_RX_INTERRUPT_CAUSE_TRAINING_DONE_MASK) { InstancePtr->RxInstance.IntrTrainingDoneHandler( InstancePtr->RxInstance.IntrTrainingDoneCallbackRef); } /* A change has been detected in the current video transmitted on the * link as indicated by the main stream attributes (MSA) fields. The * horizontal and vertical resolution parameters are monitored for * changes. */ if (IntrStatus & XDP_RX_INTERRUPT_CAUSE_VM_CHANGE_MASK) { InstancePtr->RxInstance.IntrVmChangeHandler( InstancePtr->RxInstance.IntrVmChangeCallbackRef); } /* The VerticalBlanking_Flag in the VB-ID field of the received stream * indicates the start of the vertical blanking interval. */ if (IntrStatus & XDP_RX_INTERRUPT_CAUSE_VBLANK_MASK) { InstancePtr->RxInstance.IntrVBlankHandler( InstancePtr->RxInstance.IntrVBlankCallbackRef); } /* The receiver has detected the no-video flags in the VB-ID field after * active video has been received. */ if (IntrStatus & XDP_RX_INTERRUPT_CAUSE_NO_VIDEO_MASK) { InstancePtr->RxInstance.IntrNoVideoHandler( InstancePtr->RxInstance.IntrNoVideoCallbackRef); } /* A valid video frame is detected on the main link. */ else if (IntrStatus & XDP_RX_INTERRUPT_CAUSE_VIDEO_MASK) { InstancePtr->RxInstance.IntrVideoHandler( InstancePtr->RxInstance.IntrVideoCallbackRef); } /* The transmitter has requested a change in the current power state of * the receiver core. */ if (IntrStatus & XDP_RX_INTERRUPT_CAUSE_POWER_STATE_MASK) { InstancePtr->RxInstance.IntrPowerStateHandler( InstancePtr->RxInstance.IntrPowerStateCallbackRef); } /* A change in the bandwidth has been detected. */ if (IntrStatus & XDP_RX_INTERRUPT_CAUSE_BW_CHANGE_MASK) { InstancePtr->RxInstance.IntrBwChangeHandler( InstancePtr->RxInstance.IntrBwChangeCallbackRef); } /* An audio info packet has been received. */ if (IntrStatus & XDP_RX_INTERRUPT_CAUSE_INFO_PKT_MASK) { InstancePtr->RxInstance.IntrInfoPktHandler( InstancePtr->RxInstance.IntrInfoPktCallbackRef); } /* An audio extension packet has been received. */ if (IntrStatus & XDP_RX_INTERRUPT_CAUSE_EXT_PKT_MASK) { InstancePtr->RxInstance.IntrExtPktHandler( InstancePtr->RxInstance.IntrExtPktCallbackRef); } }