/** * 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 generates a pulse on the hot-plug-detect (HPD) line of the * specified duration. * * @param InstancePtr is a pointer to the XDp instance. * @param DurationUs is the duration of the HPD pulse, in microseconds. * * @return None. * * @note None. * *******************************************************************************/ void XDp_RxGenerateHpdInterrupt(XDp *InstancePtr, u16 DurationUs) { /* Verify arguments. */ Xil_AssertVoid(InstancePtr != NULL); Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); Xil_AssertVoid(XDp_GetCoreType(InstancePtr) == XDP_RX); XDp_WriteReg(InstancePtr->Config.BaseAddr, XDP_RX_HPD_INTERRUPT, (DurationUs << XDP_RX_HPD_INTERRUPT_LENGTH_US_SHIFT) | XDP_RX_HPD_INTERRUPT_ASSERT_MASK); }
/** * 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; }