/******************************************************************************* * * 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 THE * XILINX CONSORTIUM 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 xdp.c * * Contains a minimal set of functions for the XDp driver that allow access to * all of the DisplayPort core's functionality. See xdp.h for a detailed * description of the driver. * * @note None. * *
 * MODIFICATION HISTORY:
 *
 * Ver   Who  Date     Changes
 * ----- ---- -------- -----------------------------------------------
 * 1.0   als  01/20/15 Initial release.
 * 
* *******************************************************************************/ /******************************* Include Files ********************************/ #include "xdp.h" #if defined(__arm__) #include "sleep.h" #elif defined(__MICROBLAZE__) #include "microblaze_sleep.h" #endif #include "xenv.h" /**************************** Constant Definitions ****************************/ /* The maximum voltage swing level is 3. */ #define XDP_TX_MAXIMUM_VS_LEVEL 3 /* The maximum pre-emphasis level is 3. */ #define XDP_TX_MAXIMUM_PE_LEVEL 3 /* Error out if an AUX request yields a defer reply more than 50 times. */ #define XDP_AUX_MAX_DEFER_COUNT 50 /* Error out if an AUX request times out more than 50 times awaiting a reply. */ #define XDP_AUX_MAX_TIMEOUT_COUNT 50 /* Error out if checking for a connected device times out more than 50 times. */ #define XDP_IS_CONNECTED_MAX_TIMEOUT_COUNT 50 /****************************** Type Definitions ******************************/ /** * This typedef enumerates the list of training states used in the state machine * during the link training process. */ typedef enum { XDP_TX_TS_CLOCK_RECOVERY, XDP_TX_TS_CHANNEL_EQUALIZATION, XDP_TX_TS_ADJUST_LINK_RATE, XDP_TX_TS_ADJUST_LANE_COUNT, XDP_TX_TS_FAILURE, XDP_TX_TS_SUCCESS } XDp_TxTrainingState; /** * This typedef describes an AUX transaction. */ typedef struct { u16 CmdCode; /**< The AUX command code that specifies what type of AUX transaction is taking place. */ u8 NumBytes; /**< The number of bytes that the AUX transaction will perform work on. */ u32 Address; /**< The AUX or I2C start address that the AUX transaction will perform work on. */ u8 *Data; /**< The data buffer that will store the data read from AUX read transactions or the data to write for AUX write transactions. */ } XDp_AuxTransaction; /**************************** Function Prototypes *****************************/ /* Initialization functions. */ static u32 XDp_TxInitialize(XDp *InstancePtr); static u32 XDp_RxInitialize(XDp *InstancePtr); /* Training functions. */ static u32 XDp_TxRunTraining(XDp *InstancePtr); static XDp_TxTrainingState XDp_TxTrainingStateClockRecovery(XDp *InstancePtr); static XDp_TxTrainingState XDp_TxTrainingStateChannelEqualization( XDp *InstancePtr); static XDp_TxTrainingState XDp_TxTrainingStateAdjustLinkRate( XDp *InstancePtr); static XDp_TxTrainingState XDp_TxTrainingStateAdjustLaneCount( XDp *InstancePtr); static u32 XDp_TxGetLaneStatusAdjReqs(XDp *InstancePtr); static u32 XDp_TxCheckClockRecovery(XDp *InstancePtr, u8 LaneCount); static u32 XDp_TxCheckChannelEqualization(XDp *InstancePtr, u8 LaneCount); static void XDp_TxSetVswingPreemp(XDp *InstancePtr, u8 *AuxData); static u32 XDp_TxAdjVswingPreemp(XDp *InstancePtr); static u32 XDp_TxSetTrainingPattern(XDp *InstancePtr, u32 Pattern); static u32 XDp_TxGetTrainingDelay(XDp *InstancePtr, XDp_TxTrainingState TrainingState); /* AUX transaction functions. */ static u32 XDp_TxAuxCommon(XDp *InstancePtr, u32 CmdType, u32 Address, u32 NumBytes, u8 *Data); static u32 XDp_TxAuxRequest(XDp *InstancePtr, XDp_AuxTransaction *Request); static u32 XDp_TxAuxRequestSend(XDp *InstancePtr, XDp_AuxTransaction *Request); static u32 XDp_TxAuxWaitReply(XDp *InstancePtr); static u32 XDp_TxAuxWaitReady(XDp *InstancePtr); /* Miscellaneous functions. */ static u32 XDp_TxSetClkSpeed(XDp *InstancePtr, u32 Speed); static u32 XDp_WaitPhyReady(XDp *InstancePtr, u32 Mask); /**************************** Function Definitions ****************************/ /******************************************************************************/ /** * This function retrieves the configuration for this DisplayPort instance and * fills in the InstancePtr->Config structure. * * @param InstancePtr is a pointer to the XDp instance. * @param ConfigPtr is a pointer to the configuration structure that will * be used to copy the settings from. * @param EffectiveAddr is the device base address in the virtual memory * space. If the address translation is not used, then the physical * address is passed. * * @return None. * * @note Unexpected errors may occur if the address mapping is changed * after this function is invoked. * *******************************************************************************/ void XDp_CfgInitialize(XDp *InstancePtr, XDp_Config *ConfigPtr, u32 EffectiveAddr) { /* Verify arguments. */ Xil_AssertVoid(InstancePtr != NULL); Xil_AssertVoid(ConfigPtr != NULL); Xil_AssertVoid(EffectiveAddr != 0x0); InstancePtr->IsReady = 0; InstancePtr->Config.DeviceId = ConfigPtr->DeviceId; InstancePtr->Config.BaseAddr = EffectiveAddr; InstancePtr->Config.SAxiClkHz = ConfigPtr->SAxiClkHz; InstancePtr->Config.MaxLaneCount = ConfigPtr->MaxLaneCount; InstancePtr->Config.MaxLinkRate = ConfigPtr->MaxLinkRate; InstancePtr->Config.MaxBitsPerColor = ConfigPtr->MaxBitsPerColor; InstancePtr->Config.QuadPixelEn = ConfigPtr->QuadPixelEn; InstancePtr->Config.DualPixelEn = ConfigPtr->DualPixelEn; InstancePtr->Config.YCrCbEn = ConfigPtr->YCrCbEn; InstancePtr->Config.YOnlyEn = ConfigPtr->YOnlyEn; InstancePtr->Config.PayloadDataWidth = ConfigPtr->PayloadDataWidth; InstancePtr->Config.SecondaryChEn = ConfigPtr->SecondaryChEn; InstancePtr->Config.NumAudioChs = ConfigPtr->NumAudioChs; InstancePtr->Config.MstSupport = ConfigPtr->MstSupport; InstancePtr->Config.NumMstStreams = ConfigPtr->NumMstStreams; InstancePtr->Config.DpProtocol = ConfigPtr->DpProtocol; InstancePtr->Config.IsRx = ConfigPtr->IsRx; if (XDp_CfgGetCoreType(ConfigPtr) == XDP_TX) { /* Set the DisplayPort TX's voltage swing and pre-emphasis * levels to their defaults. */ XDp_TxCfgTxVsOffset(InstancePtr, XDP_TX_VS_LEVEL_OFFSET); XDp_TxCfgTxVsLevel(InstancePtr, 0, XDP_TX_VS_LEVEL_0); XDp_TxCfgTxVsLevel(InstancePtr, 1, XDP_TX_VS_LEVEL_1); XDp_TxCfgTxVsLevel(InstancePtr, 2, XDP_TX_VS_LEVEL_2); XDp_TxCfgTxVsLevel(InstancePtr, 3, XDP_TX_VS_LEVEL_3); XDp_TxCfgTxPeLevel(InstancePtr, 0, XDP_TX_PE_LEVEL_0); XDp_TxCfgTxPeLevel(InstancePtr, 1, XDP_TX_PE_LEVEL_1); XDp_TxCfgTxPeLevel(InstancePtr, 2, XDP_TX_PE_LEVEL_2); XDp_TxCfgTxPeLevel(InstancePtr, 3, XDP_TX_PE_LEVEL_3); } InstancePtr->IsReady = XIL_COMPONENT_IS_READY; } /******************************************************************************/ /** * This function prepares the DisplayPort core for use depending on whether the * core is operating in TX or RX mode. * * @param InstancePtr is a pointer to the XDp instance. * * @return * - XST_SUCCESS if the DisplayPort core was successfully * initialized. * - XST_FAILURE otherwise. * * @note None. * *******************************************************************************/ u32 XDp_Initialize(XDp *InstancePtr) { u32 Status; /* Verify arguments. */ Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); if (XDp_CfgGetCoreType(&InstancePtr->Config) == XDP_TX) { Status = XDp_TxInitialize(InstancePtr); } else { Status = XDp_RxInitialize(InstancePtr); } return Status; } /******************************************************************************/ /** * This function retrieves the RX device's capabilities from the RX device's * DisplayPort Configuration Data (DPCD). * * @param InstancePtr is a pointer to the XDp instance. * * @return * - XST_SUCCESS if the DisplayPort Configuration Data was read * successfully. * - XST_DEVICE_NOT_FOUND if no RX device is connected. * - XST_FAILURE otherwise. * * @note None. * *******************************************************************************/ u32 XDp_TxGetRxCapabilities(XDp *InstancePtr) { u32 Status; u8 *Dpcd = InstancePtr->TxInstance.RxConfig.DpcdRxCapsField; XDp_TxLinkConfig *LinkConfig = &InstancePtr->TxInstance.LinkConfig; XDp_Config *ConfigPtr = &InstancePtr->Config; u8 RxMaxLinkRate; u8 RxMaxLaneCount; /* Verify arguments. */ Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); Xil_AssertNonvoid(Dpcd != NULL); Xil_AssertNonvoid(LinkConfig != NULL); Xil_AssertNonvoid(ConfigPtr != NULL); if (!XDp_TxIsConnected(InstancePtr)) { return XST_DEVICE_NOT_FOUND; } Status = XDp_TxAuxRead(InstancePtr, XDP_DPCD_RECEIVER_CAP_FIELD_START, 16, Dpcd); if (Status != XST_SUCCESS) { return XST_FAILURE; } RxMaxLinkRate = Dpcd[XDP_DPCD_MAX_LINK_RATE]; RxMaxLaneCount = Dpcd[XDP_DPCD_MAX_LANE_COUNT] & XDP_DPCD_MAX_LANE_COUNT_MASK; LinkConfig->MaxLinkRate = (RxMaxLinkRate > ConfigPtr->MaxLinkRate) ? ConfigPtr->MaxLinkRate : RxMaxLinkRate; LinkConfig->MaxLaneCount = (RxMaxLaneCount > ConfigPtr->MaxLaneCount) ? ConfigPtr->MaxLaneCount : RxMaxLaneCount; LinkConfig->SupportEnhancedFramingMode = Dpcd[XDP_DPCD_MAX_LANE_COUNT] & XDP_DPCD_ENHANCED_FRAME_SUPPORT_MASK; LinkConfig->SupportDownspreadControl = Dpcd[XDP_DPCD_MAX_DOWNSPREAD] & XDP_DPCD_MAX_DOWNSPREAD_MASK; return XST_SUCCESS; } /******************************************************************************/ /** * This function determines the common capabilities between the DisplayPort TX * core and the RX device. * * @param InstancePtr is a pointer to the XDp instance. * * @return * - XST_SUCCESS if main link settings were successfully set. * - XST_DEVICE_NOT_FOUND if no RX device is connected. * - XST_FAILURE otherwise. * * @note None. * *******************************************************************************/ u32 XDp_TxCfgMainLinkMax(XDp *InstancePtr) { u32 Status; XDp_TxLinkConfig *LinkConfig = &InstancePtr->TxInstance.LinkConfig; /* Verify arguments. */ Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); /* The link rate and lane count will be checked in XDp_TxSetLinkRate and * XDp_TxSetLaneCount. */ if (!XDp_TxIsConnected(InstancePtr)) { return XST_DEVICE_NOT_FOUND; } /* Configure the main link to the maximum common link rate between the * DisplayPort TX core and the RX device. */ Status = XDp_TxSetLinkRate(InstancePtr, LinkConfig->MaxLinkRate); if (Status != XST_SUCCESS) { return Status; } /* Configure the main link to the maximum common lane count between the * DisplayPort TX core and the RX device. */ Status = XDp_TxSetLaneCount(InstancePtr, LinkConfig->MaxLaneCount); if (Status != XST_SUCCESS) { return Status; } return XST_SUCCESS; } /******************************************************************************/ /** * This function checks if the link needs training and runs the training * sequence if training is required. * * @param InstancePtr is a pointer to the XDp instance. * * @return * - XST_SUCCESS was either already trained, or has been * trained successfully. * - XST_DEVICE_NOT_FOUND if no RX device is connected. * - XST_FAILURE otherwise. * * @note None. * *******************************************************************************/ u32 XDp_TxEstablishLink(XDp *InstancePtr) { u32 Status; u32 Status2; u32 ReenableMainLink; XDp_TxLinkConfig *LinkConfig = &InstancePtr->TxInstance.LinkConfig; /* Verify arguments. */ Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); Xil_AssertNonvoid((LinkConfig->LinkRate == XDP_TX_LINK_BW_SET_162GBPS) || (LinkConfig->LinkRate == XDP_TX_LINK_BW_SET_270GBPS) || (LinkConfig->LinkRate == XDP_TX_LINK_BW_SET_540GBPS)); Xil_AssertNonvoid((LinkConfig->LaneCount == XDP_TX_LANE_COUNT_SET_1) || (LinkConfig->LaneCount == XDP_TX_LANE_COUNT_SET_2) || (LinkConfig->LaneCount == XDP_TX_LANE_COUNT_SET_4)); XDp_TxResetPhy(InstancePtr, XDP_TX_PHY_CONFIG_PHY_RESET_MASK); /* Disable main link during training. */ ReenableMainLink = XDp_ReadReg(InstancePtr->Config.BaseAddr, XDP_TX_ENABLE_MAIN_STREAM); XDp_TxDisableMainLink(InstancePtr); /* Train main link. */ Status = XDp_TxRunTraining(InstancePtr); /* Reenable main link after training if required. */ if (ReenableMainLink != 0) { XDp_TxEnableMainLink(InstancePtr); } /* Turn off the training pattern and enable scrambler. */ Status2 = XDp_TxSetTrainingPattern(InstancePtr, XDP_TX_TRAINING_PATTERN_SET_OFF); if ((Status != XST_SUCCESS) || (Status2 != XST_SUCCESS)) { return XST_FAILURE; } return XST_SUCCESS; } /******************************************************************************/ /** * This function checks if the reciever's DisplayPort Configuration Data (DPCD) * indicates the reciever has achieved and maintained clock recovery, channel * equalization, symbol lock, and interlane alignment for all lanes currently in * use. * * @param InstancePtr is a pointer to the XDp instance. * @param LaneCount is the number of lanes to check. * * @return * - XST_SUCCESS if the RX device has maintained clock recovery, * channel equalization, symbol lock, and interlane alignment. * - XST_DEVICE_NOT_FOUND if no RX device is connected. * - XST_FAILURE otherwise. * * @note None. * *******************************************************************************/ u32 XDp_TxCheckLinkStatus(XDp *InstancePtr, u8 LaneCount) { u32 Status; u8 RetryCount = 0; XDp_TxLinkConfig *LinkConfig = &InstancePtr->TxInstance.LinkConfig; /* Verify arguments. */ Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); Xil_AssertNonvoid((LaneCount == XDP_TX_LANE_COUNT_SET_1) || (LaneCount == XDP_TX_LANE_COUNT_SET_2) || (LaneCount == XDP_TX_LANE_COUNT_SET_4)); if (!XDp_TxIsConnected(InstancePtr)) { return XST_DEVICE_NOT_FOUND; } /* Retrieve AUX info. */ do { /* Get lane and adjustment requests. */ Status = XDp_TxGetLaneStatusAdjReqs(InstancePtr); if (Status != XST_SUCCESS) { /* The AUX read failed. */ return XST_FAILURE; } /* Check if the link needs training. */ if ((XDp_TxCheckClockRecovery( InstancePtr, LaneCount) == XST_SUCCESS) && (XDp_TxCheckChannelEqualization( InstancePtr, LaneCount) == XST_SUCCESS)) { return XST_SUCCESS; } RetryCount++; } while (RetryCount < 5); /* Retry up to 5 times. */ return XST_FAILURE; } /******************************************************************************/ /** * This function enables or disables downshifting during the training process. * * @param InstancePtr is a pointer to the XDp instance. * @param Enable controls the downshift feature in the training process. * * @return None. * * @note None. * *******************************************************************************/ void XDp_TxEnableTrainAdaptive(XDp *InstancePtr, u8 Enable) { /* Verify arguments. */ Xil_AssertVoid(InstancePtr != NULL); Xil_AssertVoid((Enable == 1) || (Enable == 0)); InstancePtr->TxInstance.TrainAdaptive = Enable; } /******************************************************************************/ /** * This function sets a software switch that signifies whether or not a redriver * exists on the DisplayPort output path. XDp_TxSetVswingPreemp uses this switch * to determine which set of voltage swing and pre-emphasis values to use in the * TX core. * * @param InstancePtr is a pointer to the XDp instance. * @param Set establishes that a redriver exists in the DisplayPort output * path. * * @return None. * * @note None. * *******************************************************************************/ void XDp_TxSetHasRedriverInPath(XDp *InstancePtr, u8 Set) { /* Verify arguments. */ Xil_AssertVoid(InstancePtr != NULL); Xil_AssertVoid((Set == 1) || (Set == 0)); InstancePtr->TxInstance.BoardChar.HasRedriverInPath = Set; } /******************************************************************************/ /** * This function sets the voltage swing offset to use during training when no * redriver exists. The offset will be added to the DisplayPort TX's voltage * swing level value when pre-emphasis is used (when the pre-emphasis level not * equal to 0). * * @param InstancePtr is a pointer to the XDp instance. * @param Offset is the value to set for the voltage swing offset. * * @return None. * * @note None. * *******************************************************************************/ void XDp_TxCfgTxVsOffset(XDp *InstancePtr, u8 Offset) { /* Verify arguments. */ Xil_AssertVoid(InstancePtr != NULL); Xil_AssertVoid((Offset >= 0) && (Offset < 16)); InstancePtr->TxInstance.BoardChar.TxVsOffset = Offset; } /******************************************************************************/ /** * This function sets the voltage swing level value in the DisplayPort TX that * will be used during link training for a given voltage swing training level. * * @param InstancePtr is a pointer to the XDp instance. * @param Level is the voltage swing training level to set the DisplayPort * TX level for. * @param TxLevel is the DisplayPort TX voltage swing level value to be * used during link training. * * @return None. * * @note There are 16 possible voltage swing levels in the DisplayPort TX * core that map to 4 possible voltage swing training levels in the * RX device. * *******************************************************************************/ void XDp_TxCfgTxVsLevel(XDp *InstancePtr, u8 Level, u8 TxLevel) { /* Verify arguments. */ Xil_AssertVoid(InstancePtr != NULL); Xil_AssertVoid((Level >= 0) && (Level < 4)); Xil_AssertVoid((TxLevel >= 0) && (TxLevel < 16)); InstancePtr->TxInstance.BoardChar.TxVsLevels[Level] = TxLevel; } /******************************************************************************/ /** * This function sets the pre-emphasis level value in the DisplayPort TX that * will be used during link training for a given pre-emphasis training level. * * @param InstancePtr is a pointer to the XDp instance. * @param Level is the pre-emphasis training level to set the DisplayPort * TX level for. * @param TxLevel is the DisplayPort TX pre-emphasis level value to be * used during link training. * * @return None. * * @note There are 32 possible pre-emphasis levels in the DisplayPort TX * core that map to 4 possible pre-emphasis training levels in the * RX device. * *******************************************************************************/ void XDp_TxCfgTxPeLevel(XDp *InstancePtr, u8 Level, u8 TxLevel) { /* Verify arguments. */ Xil_AssertVoid(InstancePtr != NULL); Xil_AssertVoid((Level >= 0) && (Level < 4)); Xil_AssertVoid((TxLevel >= 0) && (TxLevel < 32)); InstancePtr->TxInstance.BoardChar.TxPeLevels[Level] = TxLevel; } /******************************************************************************/ /** * This function checks if there is a connected RX device. * * @param InstancePtr is a pointer to the XDp instance. * * @return * - TRUE if there is a connection. * - FALSE if there is no connection. * *******************************************************************************/ u32 XDp_TxIsConnected(XDp *InstancePtr) { u32 Status; u8 Retries = 0; do { Status = XDp_ReadReg(InstancePtr->Config.BaseAddr, XDP_TX_INTERRUPT_SIG_STATE) & XDP_TX_INTERRUPT_SIG_STATE_HPD_STATE_MASK; if (Retries > XDP_IS_CONNECTED_MAX_TIMEOUT_COUNT) { return 0; } Retries++; XDp_WaitUs(InstancePtr, 1000); } while (Status == 0); return 1; } /******************************************************************************/ /** * This function issues a read request over the AUX channel that will read from * the RX device's DisplayPort Configuration Data (DPCD) address space. The read * message will be divided into multiple transactions which read a maximum of 16 * bytes each. * * @param InstancePtr is a pointer to the XDp instance. * @param DpcdAddress is the starting address to read from the RX device. * @param BytesToRead is the number of bytes to read from the RX device. * @param ReadData is a pointer to the data buffer that will be filled * with read data. * * @return * - XST_SUCCESS if the AUX read request was successfully * acknowledged. * - XST_DEVICE_NOT_FOUND if no RX device is connected. * - XST_ERROR_COUNT_MAX if the AUX request timed out. * - XST_FAILURE otherwise. * * @note None. * *******************************************************************************/ u32 XDp_TxAuxRead(XDp *InstancePtr, u32 DpcdAddress, u32 BytesToRead, void *ReadData) { u32 Status; XDp_AuxTransaction Request; /* Verify arguments. */ Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); Xil_AssertNonvoid(DpcdAddress <= 0xFFFFF); Xil_AssertNonvoid(BytesToRead <= 0xFFFFF); Xil_AssertNonvoid(ReadData != NULL); if (!XDp_TxIsConnected(InstancePtr)) { return XST_DEVICE_NOT_FOUND; } /* Send AUX read transaction. */ Status = XDp_TxAuxCommon(InstancePtr, XDP_TX_AUX_CMD_READ, DpcdAddress, BytesToRead, (u8 *)ReadData); return Status; } /******************************************************************************/ /** * This function issues a write request over the AUX channel that will write to * the RX device's DisplayPort Configuration Data (DPCD) address space. The * write message will be divided into multiple transactions which write a * maximum of 16 bytes each. * * @param InstancePtr is a pointer to the XDp instance. * @param DpcdAddress is the starting address to write to the RX device. * @param BytesToWrite is the number of bytes to write to the RX device. * @param WriteData is a pointer to the data buffer that contains the data * to be written to the RX device. * * @return * - XST_SUCCESS if the AUX write request was successfully * acknowledged. * - XST_DEVICE_NOT_FOUND if no RX device is connected. * - XST_ERROR_COUNT_MAX if the AUX request timed out. * - XST_FAILURE otherwise. * * @note None. * *******************************************************************************/ u32 XDp_TxAuxWrite(XDp *InstancePtr, u32 DpcdAddress, u32 BytesToWrite, void *WriteData) { u32 Status; XDp_AuxTransaction Request; /* Verify arguments. */ Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); Xil_AssertNonvoid(DpcdAddress <= 0xFFFFF); Xil_AssertNonvoid(BytesToWrite <= 0xFFFFF); Xil_AssertNonvoid(WriteData != NULL); if (!XDp_TxIsConnected(InstancePtr)) { return XST_DEVICE_NOT_FOUND; } /* Send AUX write transaction. */ Status = XDp_TxAuxCommon(InstancePtr, XDP_TX_AUX_CMD_WRITE, DpcdAddress, BytesToWrite, (u8 *)WriteData); return Status; } /******************************************************************************/ /** * This function performs an I2C read over the AUX channel. The read message * will be divided into multiple transactions if the requested data spans * multiple segments. The segment pointer is automatically incremented and the * offset is calibrated as needed. E.g. For an overall offset of: * - 128, an I2C read is done on segptr=0; offset=128. * - 256, an I2C read is done on segptr=1; offset=0. * - 384, an I2C read is done on segptr=1; offset=128. * - 512, an I2C read is done on segptr=2; offset=0. * - etc. * * @param InstancePtr is a pointer to the XDp instance. * @param IicAddress is the address on the I2C bus of the target device. * @param Offset is the offset at the specified address of the targeted * I2C device that the read will start from. * @param BytesToRead is the number of bytes to read. * @param ReadData is a pointer to a buffer that will be filled with the * I2C read data. * * @return * - XST_SUCCESS if the I2C read has successfully completed with no * errors. * - XST_ERROR_COUNT_MAX if the AUX request timed out. * - XST_DEVICE_NOT_FOUND if no RX device is connected. * - XST_FAILURE otherwise. * * @note None. * *******************************************************************************/ u32 XDp_TxIicRead(XDp *InstancePtr, u8 IicAddress, u16 Offset, u16 BytesToRead, void *ReadData) { u32 Status; XDp_AuxTransaction Request; u8 SegPtr; u16 NumBytesLeftInSeg; u16 BytesLeft; u8 CurrBytesToRead; /* Verify arguments. */ Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); Xil_AssertNonvoid(IicAddress <= 0xFF); Xil_AssertNonvoid(Offset <= 0xFFFF); Xil_AssertNonvoid(BytesToRead <= 0xFFFF); Xil_AssertNonvoid(ReadData != NULL); if (!XDp_TxIsConnected(InstancePtr)) { return XST_DEVICE_NOT_FOUND; } BytesLeft = BytesToRead; /* Reposition based on a segment length of 256 bytes. */ SegPtr = 0; if (Offset > 255) { SegPtr += Offset / 256; Offset %= 256; } NumBytesLeftInSeg = 256 - Offset; /* Set the segment pointer to 0. */ Status = XDp_TxIicWrite(InstancePtr, XDP_SEGPTR_ADDR, 1, &SegPtr); if (Status != XST_SUCCESS) { return Status; } /* Send I2C read message. Multiple transactions are required if the * requested data spans multiple segments. */ while (BytesLeft > 0) { /* Read the remaining number of bytes as requested. */ if (NumBytesLeftInSeg >= BytesLeft) { CurrBytesToRead = BytesLeft; } /* Read the remaining data in the current segment boundary. */ else { CurrBytesToRead = NumBytesLeftInSeg; } /* Setup the I2C-over-AUX read transaction with the offset. */ Status = XDp_TxIicWrite(InstancePtr, IicAddress, 1, &Offset); if (Status != XST_SUCCESS) { return Status; } /* Send I2C-over-AUX read transaction. */ Status = XDp_TxAuxCommon(InstancePtr, XDP_TX_AUX_CMD_I2C_READ, IicAddress, CurrBytesToRead, (u8 *)ReadData); if (Status != XST_SUCCESS) { return Status; } /* Previous I2C read was done on the remaining data in the * current segment; prepare for next read. */ if (BytesLeft > CurrBytesToRead) { BytesLeft -= CurrBytesToRead; Offset += CurrBytesToRead; ReadData += CurrBytesToRead; /* Increment the segment pointer to access more I2C * address space, if required. */ if (BytesLeft > 0) { NumBytesLeftInSeg = 256; Offset %= 256; SegPtr++; Status = XDp_TxIicWrite(InstancePtr, XDP_SEGPTR_ADDR, 1, &SegPtr); if (Status != XST_SUCCESS) { return Status; } } } /* Last I2C read. */ else { BytesLeft = 0; } } /* Reset the segment pointer to 0. */ SegPtr = 0; Status = XDp_TxIicWrite(InstancePtr, XDP_SEGPTR_ADDR, 1, &SegPtr); return Status; } /******************************************************************************/ /** * This function performs an I2C write over the AUX channel. * * @param InstancePtr is a pointer to the XDp instance. * @param IicAddress is the address on the I2C bus of the target device. * @param BytesToWrite is the number of bytes to write. * @param WriteData is a pointer to a buffer which will be used as the * data source for the write. * * @return * - XST_SUCCESS if the I2C write has successfully completed with * no errors. * - XST_DEVICE_NOT_FOUND if no RX device is connected. * - XST_ERROR_COUNT_MAX if the AUX request timed out. * - XST_FAILURE otherwise. * * @note None. * *******************************************************************************/ u32 XDp_TxIicWrite(XDp *InstancePtr, u8 IicAddress, u8 BytesToWrite, void *WriteData) { u32 Status; XDp_AuxTransaction Request; /* Verify arguments. */ Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); Xil_AssertNonvoid(IicAddress <= 0xFF); Xil_AssertNonvoid(BytesToWrite <= 0xFF); Xil_AssertNonvoid(WriteData != NULL); if (!XDp_TxIsConnected(InstancePtr)) { return XST_DEVICE_NOT_FOUND; } /* Send I2C-over-AUX read transaction. */ Status = XDp_TxAuxCommon(InstancePtr, XDP_TX_AUX_CMD_I2C_WRITE, IicAddress, BytesToWrite, (u8 *)WriteData); return Status; } /******************************************************************************/ /** * This function enables or disables 0.5% spreading of the clock for both the * DisplayPort and the RX device. * * @param InstancePtr is a pointer to the XDp instance. * @param Enable will downspread the main link signal if set to 1 and * disable downspreading if set to 0. * * @return * - XST_SUCCESS if setting the downspread control enable was * successful. * - XST_DEVICE_NOT_FOUND if no RX device is connected. * - XST_FAILURE otherwise. * * @note None. * *******************************************************************************/ u32 XDp_TxSetDownspread(XDp *InstancePtr, u8 Enable) { u32 Status; u8 RegVal; /* Verify arguments. */ Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); Xil_AssertNonvoid((Enable == 1) || (Enable == 0)); if (!XDp_TxIsConnected(InstancePtr)) { return XST_DEVICE_NOT_FOUND; } InstancePtr->TxInstance.LinkConfig.DownspreadControl = Enable; /* Write downspread enable to the DisplayPort TX core. */ XDp_WriteReg(InstancePtr->Config.BaseAddr, XDP_TX_DOWNSPREAD_CTRL, InstancePtr->TxInstance.LinkConfig.DownspreadControl); /* Preserve the current RX device settings. */ Status = XDp_TxAuxRead(InstancePtr, XDP_DPCD_DOWNSPREAD_CTRL, 0x1, &RegVal); if (Status != XST_SUCCESS) { return XST_FAILURE; } if (InstancePtr->TxInstance.LinkConfig.DownspreadControl) { RegVal |= XDP_DPCD_SPREAD_AMP_MASK; } else { RegVal &= ~XDP_DPCD_SPREAD_AMP_MASK; } /* Write downspread enable to the RX device. */ Status = XDp_TxAuxWrite(InstancePtr, XDP_DPCD_DOWNSPREAD_CTRL, 0x1, &RegVal); if (Status != XST_SUCCESS) { return XST_FAILURE; } return XST_SUCCESS; } /******************************************************************************/ /** * This function enables or disables the enhanced framing symbol sequence for * both the DisplayPort TX core and the RX device. * * @param InstancePtr is a pointer to the XDp instance. * @param Enable will enable enhanced frame mode if set to 1 and disable * it if set to 0. * * @return * - XST_SUCCESS if setting the enhanced frame mode enable was * successful. * - XST_DEVICE_NOT_FOUND if no RX is connected. * - XST_FAILURE otherwise. * * @note None. * *******************************************************************************/ u32 XDp_TxSetEnhancedFrameMode(XDp *InstancePtr, u8 Enable) { u32 Status; u8 RegVal; /* Verify arguments. */ Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); Xil_AssertNonvoid((Enable == 1) || (Enable == 0)); if (!XDp_TxIsConnected(InstancePtr)) { return XST_DEVICE_NOT_FOUND; } InstancePtr->TxInstance.LinkConfig.EnhancedFramingMode = Enable; /* Write enhanced frame mode enable to the DisplayPort TX core. */ XDp_WriteReg(InstancePtr->Config.BaseAddr, XDP_TX_ENHANCED_FRAME_EN, InstancePtr->TxInstance.LinkConfig.EnhancedFramingMode); /* Preserve the current RX device settings. */ Status = XDp_TxAuxRead(InstancePtr, XDP_DPCD_LANE_COUNT_SET, 0x1, &RegVal); if (Status != XST_SUCCESS) { return XST_FAILURE; } if (InstancePtr->TxInstance.LinkConfig.EnhancedFramingMode) { RegVal |= XDP_DPCD_ENHANCED_FRAME_EN_MASK; } else { RegVal &= ~XDP_DPCD_ENHANCED_FRAME_EN_MASK; } /* Write enhanced frame mode enable to the RX device. */ Status = XDp_TxAuxWrite(InstancePtr, XDP_DPCD_LANE_COUNT_SET, 0x1, &RegVal); if (Status != XST_SUCCESS) { return XST_FAILURE; } return XST_SUCCESS; } /******************************************************************************/ /** * This function sets the number of lanes to be used by the main link for both * the DisplayPort TX core and the RX device. * * @param InstancePtr is a pointer to the XDp instance. * @param LaneCount is the number of lanes to be used over the main link. * * @return * - XST_SUCCESS if setting the new lane count was successful. * - XST_DEVICE_NOT_FOUND if no RX is connected. * - XST_FAILURE otherwise. * * @note None. * *******************************************************************************/ u32 XDp_TxSetLaneCount(XDp *InstancePtr, u8 LaneCount) { u32 Status; u8 RegVal; /* Verify arguments. */ Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); Xil_AssertNonvoid((LaneCount == XDP_TX_LANE_COUNT_SET_1) || (LaneCount == XDP_TX_LANE_COUNT_SET_2) || (LaneCount == XDP_TX_LANE_COUNT_SET_4)); if (!XDp_TxIsConnected(InstancePtr)) { return XST_DEVICE_NOT_FOUND; } InstancePtr->TxInstance.LinkConfig.LaneCount = LaneCount; /* Write the new lane count to the DisplayPort TX core. */ XDp_WriteReg(InstancePtr->Config.BaseAddr, XDP_TX_LANE_COUNT_SET, InstancePtr->TxInstance.LinkConfig.LaneCount); /* Preserve the current RX device settings. */ Status = XDp_TxAuxRead(InstancePtr, XDP_DPCD_LANE_COUNT_SET, 0x1, &RegVal); if (Status != XST_SUCCESS) { return XST_FAILURE; } RegVal &= ~XDP_DPCD_LANE_COUNT_SET_MASK; RegVal |= InstancePtr->TxInstance.LinkConfig.LaneCount; /* Write the new lane count to the RX device. */ Status = XDp_TxAuxWrite(InstancePtr, XDP_DPCD_LANE_COUNT_SET, 0x1, &RegVal); if (Status != XST_SUCCESS) { return XST_FAILURE; } return XST_SUCCESS; } /******************************************************************************/ /** * This function sets the data rate to be used by the main link for both the * DisplayPort TX core and the RX device. * * @param InstancePtr is a pointer to the XDp instance. * @param LinkRate is the link rate to be used over the main link based on * one of the following selects: * - XDP_TX_LINK_BW_SET_162GBPS = 0x06 (for a 1.62 Gbps data rate) * - XDP_TX_LINK_BW_SET_270GBPS = 0x0A (for a 2.70 Gbps data rate) * - XDP_TX_LINK_BW_SET_540GBPS = 0x14 (for a 5.40 Gbps data rate) * * @return * - XST_SUCCESS if setting the new link rate was successful. * - XST_DEVICE_NOT_FOUND if no RX device is connected. * - XST_FAILURE otherwise. * * @note None. * *******************************************************************************/ u32 XDp_TxSetLinkRate(XDp *InstancePtr, u8 LinkRate) { u32 Status; /* Verify arguments. */ Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); Xil_AssertNonvoid((LinkRate == XDP_TX_LINK_BW_SET_162GBPS) || (LinkRate == XDP_TX_LINK_BW_SET_270GBPS) || (LinkRate == XDP_TX_LINK_BW_SET_540GBPS)); if (!XDp_TxIsConnected(InstancePtr)) { return XST_DEVICE_NOT_FOUND; } /* Write a corresponding clock frequency to the DisplayPort TX core. */ switch (LinkRate) { case XDP_TX_LINK_BW_SET_162GBPS: Status = XDp_TxSetClkSpeed(InstancePtr, XDP_TX_PHY_CLOCK_SELECT_162GBPS); break; case XDP_TX_LINK_BW_SET_270GBPS: Status = XDp_TxSetClkSpeed(InstancePtr, XDP_TX_PHY_CLOCK_SELECT_270GBPS); break; case XDP_TX_LINK_BW_SET_540GBPS: Status = XDp_TxSetClkSpeed(InstancePtr, XDP_TX_PHY_CLOCK_SELECT_540GBPS); break; default: break; } if (Status != XST_SUCCESS) { return XST_FAILURE; } InstancePtr->TxInstance.LinkConfig.LinkRate = LinkRate; /* Write new link rate to the DisplayPort TX core. */ XDp_WriteReg(InstancePtr->Config.BaseAddr, XDP_TX_LINK_BW_SET, InstancePtr->TxInstance.LinkConfig.LinkRate); /* Write new link rate to the RX device. */ Status = XDp_TxAuxWrite(InstancePtr, XDP_DPCD_LINK_BW_SET, 1, &InstancePtr->TxInstance.LinkConfig.LinkRate); if (Status != XST_SUCCESS) { return XST_FAILURE; } return XST_SUCCESS; } /******************************************************************************/ /** * This function enables or disables scrambling of symbols for both the * DisplayPort and the RX device. * * @param InstancePtr is a pointer to the XDp instance. * @param Enable will enable or disable scrambling. * * @return * - XST_SUCCESS if setting the scrambling enable was successful. * - XST_FAILURE otherwise. * * @note None. * *******************************************************************************/ u32 XDp_TxSetScrambler(XDp *InstancePtr, u8 Enable) { u32 Status; u8 RegVal; /* Verify arguments. */ Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); Xil_AssertNonvoid((Enable == 1) || (Enable == 0)); InstancePtr->TxInstance.LinkConfig.ScramblerEn = Enable; /* Write scrambler disable to the DisplayPort TX core. */ XDp_WriteReg(InstancePtr->Config.BaseAddr, XDP_TX_SCRAMBLING_DISABLE, Enable ? 0x0 : 0x1); /* Preserve the current RX device settings. */ Status = XDp_TxAuxRead(InstancePtr, XDP_DPCD_TP_SET, 1, &RegVal); if (Status != XST_SUCCESS) { return XST_FAILURE; } if (Enable) { RegVal &= ~XDP_DPCD_TP_SET_SCRAMB_DIS_MASK; } else { RegVal |= XDP_DPCD_TP_SET_SCRAMB_DIS_MASK; } /* Write scrambler disable to the RX device. */ Status = XDp_TxAuxWrite(InstancePtr, XDP_DPCD_TP_SET, 1, &RegVal); if (Status != XST_SUCCESS) { return XST_FAILURE; } return XST_SUCCESS; } /******************************************************************************/ /** * This function enables the main link. * * @param InstancePtr is a pointer to the XDp instance. * * @return None. * * @note None. * *******************************************************************************/ void XDp_TxEnableMainLink(XDp *InstancePtr) { /* Verify arguments. */ Xil_AssertVoid(InstancePtr != NULL); Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); /* Reset the scrambler. */ XDp_WriteReg(InstancePtr->Config.BaseAddr, XDP_TX_FORCE_SCRAMBLER_RESET, 0x1); /* Enable the main stream. */ XDp_WriteReg(InstancePtr->Config.BaseAddr, XDP_TX_ENABLE_MAIN_STREAM, 0x1); } /******************************************************************************/ /** * This function disables the main link. * * @param InstancePtr is a pointer to the XDp instance. * * @return None. * * @note None. * *******************************************************************************/ void XDp_TxDisableMainLink(XDp *InstancePtr) { /* Verify arguments. */ Xil_AssertVoid(InstancePtr != NULL); Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); /* Reset the scrambler. */ XDp_WriteReg(InstancePtr->Config.BaseAddr, XDP_TX_FORCE_SCRAMBLER_RESET, 0x1); /* Disable the main stream. */ XDp_WriteReg(InstancePtr->Config.BaseAddr, XDP_TX_ENABLE_MAIN_STREAM, 0x0); } /******************************************************************************/ /** * This function does a PHY reset. * * @param InstancePtr is a pointer to the XDp instance. * @param Reset is the type of reset to assert. * * @return None. * * @note None. * *******************************************************************************/ void XDp_TxResetPhy(XDp *InstancePtr, u32 Reset) { /* Verify arguments. */ Xil_AssertVoid(InstancePtr != NULL); Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); XDp_WriteReg(InstancePtr->Config.BaseAddr, XDP_TX_ENABLE, 0x0); XDp_WriteReg(InstancePtr->Config.BaseAddr, XDP_TX_PHY_CONFIG, Reset); XDp_WriteReg(InstancePtr->Config.BaseAddr, XDP_TX_PHY_CONFIG, XDP_TX_PHY_CONFIG_PHY_RESET_ENABLE_MASK); if (InstancePtr->Config.MaxLaneCount > 2) { XDp_WaitPhyReady(InstancePtr, XDP_TX_PHY_STATUS_ALL_LANES_READY_MASK); } else { XDp_WaitPhyReady(InstancePtr, XDP_TX_PHY_STATUS_LANES_0_1_READY_MASK); } XDp_WriteReg(InstancePtr->Config.BaseAddr, XDP_TX_ENABLE, 0x1); } /******************************************************************************/ /** * This function checks if the reciever's internal registers indicate that link * training has complete. That is, training has achieved channel equalization, * symbol lock, and interlane alignment for all lanes currently in use. * * @param InstancePtr is a pointer to the XDp instance. * * @return * - XST_SUCCESS if the RX device has achieved clock recovery, * channel equalization, symbol lock, and interlane alignment. * - XST_FAILURE otherwise. * * @note None. * *******************************************************************************/ u32 XDp_RxCheckLinkStatus(XDp *InstancePtr) { u8 LaneCount; u8 LaneStatus[2]; /* Verify arguments. */ Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); LaneCount = XDp_ReadReg(InstancePtr->Config.BaseAddr, XDP_RX_DPCD_LANE_COUNT_SET); LaneStatus[0] = XDp_ReadReg(InstancePtr->Config.BaseAddr, XDP_RX_DPCD_LANE01_STATUS); LaneStatus[1] = XDp_ReadReg(InstancePtr->Config.BaseAddr, XDP_RX_DPCD_LANE23_STATUS); switch (LaneCount) { case 4: if (LaneStatus[1] != 0x77) { return XST_FAILURE; } case 2: if ((LaneStatus[0] & 0x70) != 0x70) { return XST_FAILURE; } case 1: if ((LaneStatus[0] & 0x07) != 0x07) { return XST_FAILURE; } } return XST_SUCCESS; } /******************************************************************************/ /** * This function enables the display timing generator (DTG). * * @param InstancePtr is a pointer to the XDp instance. * * @return None. * * @note None. * *******************************************************************************/ void XDp_RxDtgEn(XDp *InstancePtr) { /* Verify arguments. */ Xil_AssertVoid(InstancePtr != NULL); Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); XDp_WriteReg(InstancePtr->Config.BaseAddr, XDP_RX_SOFT_RESET, XDP_RX_SOFT_RESET_VIDEO_MASK); XDp_WriteReg(InstancePtr->Config.BaseAddr, XDP_RX_SOFT_RESET, 0x0); XDp_WriteReg(InstancePtr->Config.BaseAddr, XDP_RX_DTG_ENABLE, 0x1); } /******************************************************************************/ /** * This function disables the display timing generator (DTG). * * @param InstancePtr is a pointer to the XDp instance. * * @return None. * * @note None. * *******************************************************************************/ void XDp_RxDtgDis(XDp *InstancePtr) { /* Verify arguments. */ Xil_AssertVoid(InstancePtr != NULL); Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); XDp_WriteReg(InstancePtr->Config.BaseAddr, XDP_RX_DTG_ENABLE, 0x0); XDp_WriteReg(InstancePtr->Config.BaseAddr, XDP_RX_SOFT_RESET, XDP_RX_SOFT_RESET_VIDEO_MASK); XDp_WriteReg(InstancePtr->Config.BaseAddr, XDP_RX_SOFT_RESET, 0x0); } /******************************************************************************/ /** * This function sets the maximum data rate to be exposed in the RX device's * DisplayPort Configuration Data (DPCD) registers. * * @param InstancePtr is a pointer to the XDp instance. * @param LinkRate is the link rate to be used over the main link based on * one of the following selects: * - XDP_RX_LINK_BW_SET_162GBPS = 0x06 (for a 1.62 Gbps data rate) * - XDP_RX_LINK_BW_SET_270GBPS = 0x0A (for a 2.70 Gbps data rate) * - XDP_RX_LINK_BW_SET_540GBPS = 0x14 (for a 5.40 Gbps data rate) * * @return None. * * @note None. * *******************************************************************************/ void XDp_RxSetLinkRate(XDp *InstancePtr, u8 LinkRate) { /* Verify arguments. */ Xil_AssertVoid(InstancePtr != NULL); Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); Xil_AssertVoid((LinkRate == XDP_RX_OVER_LINK_BW_SET_162GBPS) || (LinkRate == XDP_RX_OVER_LINK_BW_SET_270GBPS) || (LinkRate == XDP_RX_OVER_LINK_BW_SET_540GBPS)); InstancePtr->RxInstance.LinkConfig.LinkRate = LinkRate; XDp_WriteReg(InstancePtr->Config.BaseAddr, XDP_RX_OVER_CTRL_DPCD, 0x1); XDp_WriteReg(InstancePtr->Config.BaseAddr, XDP_RX_OVER_LINK_BW_SET, LinkRate); XDp_WriteReg(InstancePtr->Config.BaseAddr, XDP_RX_OVER_CTRL_DPCD, 0x0); XDp_WriteReg(InstancePtr->Config.BaseAddr, XDP_RX_LOCAL_EDID_VIDEO, 0x1); } /******************************************************************************/ /** * This function sets the maximum lane count to be exposed in the RX device's * DisplayPort Configuration Data (DPCD) registers. * * @param InstancePtr is a pointer to the XDp instance. * @param LaneCount is the number of lanes to be used over the main link. * * @return None. * * @note None. * *******************************************************************************/ void XDp_RxSetLaneCount(XDp *InstancePtr, u8 LaneCount) { /* Verify arguments. */ Xil_AssertVoid(InstancePtr != NULL); Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); Xil_AssertVoid((LaneCount == XDP_RX_OVER_LANE_COUNT_SET_1) || (LaneCount == XDP_RX_OVER_LANE_COUNT_SET_2) || (LaneCount == XDP_RX_OVER_LANE_COUNT_SET_4)); InstancePtr->RxInstance.LinkConfig.LaneCount = LaneCount; XDp_WriteReg(InstancePtr->Config.BaseAddr, XDP_RX_OVER_CTRL_DPCD, 0x1); XDp_WriteReg(InstancePtr->Config.BaseAddr, XDP_RX_OVER_LANE_COUNT_SET, LaneCount); XDp_WriteReg(InstancePtr->Config.BaseAddr, XDP_RX_OVER_CTRL_DPCD, 0x0); XDp_WriteReg(InstancePtr->Config.BaseAddr, XDP_RX_LOCAL_EDID_VIDEO, 0x1); } /******************************************************************************/ /** * This function installs a custom delay/sleep function to be used by the XDp * driver. * * @param InstancePtr is a pointer to the XDp 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 XDp_SetUserTimerHandler(XDp *InstancePtr, XDp_TimerHandler CallbackFunc, void *CallbackRef) { /* Verify arguments. */ Xil_AssertVoid(InstancePtr != NULL); Xil_AssertVoid(CallbackFunc != NULL); Xil_AssertVoid(CallbackRef != NULL); InstancePtr->UserTimerWaitUs = CallbackFunc; InstancePtr->UserTimerPtr = CallbackRef; } /******************************************************************************/ /** * This function is the delay/sleep function for the XDp driver. For the Zynq * family, there exists native sleep functionality. For MicroBlaze however, * there does not exist such functionality. In the MicroBlaze case, the default * method for delaying is to use a predetermined amount of loop iterations. This * method is prone to inaccuracy and dependent on system configuration; for * greater accuracy, the user may supply their own delay/sleep handler, pointed * to by InstancePtr->UserTimerWaitUs, which may have better accuracy if a * hardware timer is used. * * @param InstancePtr is a pointer to the XDp instance. * @param MicroSeconds is the number of microseconds to delay/sleep for. * * @return None. * * @note None. * *******************************************************************************/ void XDp_WaitUs(XDp *InstancePtr, u32 MicroSeconds) { /* Verify arguments. */ Xil_AssertVoid(InstancePtr != NULL); Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); if (MicroSeconds == 0) { return; } #if defined(__arm__) /* Wait the requested amount of time. */ usleep(MicroSeconds); #elif defined(__MICROBLAZE__) if (InstancePtr->UserTimerWaitUs != NULL) { /* Use the timer handler specified by the user for better * accuracy. */ InstancePtr->UserTimerWaitUs(InstancePtr, MicroSeconds); } else { /* MicroBlaze sleep only has millisecond accuracy. Round up. */ u32 MilliSeconds = (MicroSeconds + 999) / 1000; MB_Sleep(MilliSeconds); } #endif } /******************************************************************************/ /** * This function prepares the DisplayPort TX core for use. * * @param InstancePtr is a pointer to the XDp instance. * * @return * - XST_SUCCESS if the DisplayPort TX core was successfully * initialized. * - XST_FAILURE otherwise. * * @note None. * *******************************************************************************/ static u32 XDp_TxInitialize(XDp *InstancePtr) { u32 Status; u32 RegVal; XDp_Config *ConfigPtr = &InstancePtr->Config; /* Place the PHY (and GTTXRESET) into reset. */ XDp_WriteReg(ConfigPtr->BaseAddr, XDP_TX_PHY_CONFIG, XDP_TX_PHY_CONFIG_GT_ALL_RESET_MASK); /* Reset the video streams and AUX logic. */ XDp_WriteReg(ConfigPtr->BaseAddr, XDP_TX_SOFT_RESET, XDP_TX_SOFT_RESET_VIDEO_STREAM_ALL_MASK | XDP_TX_SOFT_RESET_AUX_MASK); /* Disable the DisplayPort TX core. */ XDp_WriteReg(ConfigPtr->BaseAddr, XDP_TX_ENABLE, 0); /* Set the clock divider. */ RegVal = (XDp_ReadReg(ConfigPtr->BaseAddr, XDP_TX_AUX_CLK_DIVIDER) & ~XDP_TX_AUX_CLK_DIVIDER_VAL_MASK) | (ConfigPtr->SAxiClkHz / 1000000); XDp_WriteReg(ConfigPtr->BaseAddr, XDP_TX_AUX_CLK_DIVIDER, RegVal); /* Set the DisplayPort TX core's clock speed. */ switch (ConfigPtr->MaxLinkRate) { case XDP_TX_LINK_BW_SET_540GBPS: XDp_WriteReg(ConfigPtr->BaseAddr, XDP_TX_PHY_CLOCK_SELECT, XDP_TX_PHY_CLOCK_SELECT_540GBPS); break; case XDP_TX_LINK_BW_SET_270GBPS: XDp_WriteReg(ConfigPtr->BaseAddr, XDP_TX_PHY_CLOCK_SELECT, XDP_TX_PHY_CLOCK_SELECT_270GBPS); break; case XDP_TX_LINK_BW_SET_162GBPS: XDp_WriteReg(ConfigPtr->BaseAddr, XDP_TX_PHY_CLOCK_SELECT, XDP_TX_PHY_CLOCK_SELECT_162GBPS); break; default: break; } /* Bring the PHY (and GTTXRESET) out of reset. */ XDp_WriteReg(ConfigPtr->BaseAddr, XDP_TX_PHY_CONFIG, XDP_TX_PHY_CONFIG_PHY_RESET_ENABLE_MASK); /* Wait for the PHY to be ready. */ if (ConfigPtr->MaxLaneCount > 2) { Status = XDp_WaitPhyReady(InstancePtr, XDP_TX_PHY_STATUS_ALL_LANES_READY_MASK); } else { Status = XDp_WaitPhyReady(InstancePtr, XDP_TX_PHY_STATUS_LANES_0_1_READY_MASK); } if (Status != XST_SUCCESS) { return XST_FAILURE; } /* Enable the DisplayPort TX core. */ XDp_WriteReg(ConfigPtr->BaseAddr, XDP_TX_ENABLE, 1); /* Unmask Hot-Plug-Detect (HPD) interrupts. */ XDp_WriteReg(ConfigPtr->BaseAddr, XDP_TX_INTERRUPT_MASK, ~XDP_TX_INTERRUPT_MASK_HPD_PULSE_DETECTED_MASK & ~XDP_TX_INTERRUPT_MASK_HPD_EVENT_MASK & ~XDP_TX_INTERRUPT_MASK_HPD_IRQ_MASK); return XST_SUCCESS; } /******************************************************************************/ /** * This function prepares the DisplayPort RX core for use. * * @param InstancePtr is a pointer to the XDp instance. * * @return * - XST_SUCCESS if the DisplayPort RX core was successfully * initialized. * - XST_FAILURE otherwise. * * @note None. * *******************************************************************************/ static u32 XDp_RxInitialize(XDp *InstancePtr) { u32 Status; /* Disable the main link. */ XDp_WriteReg(InstancePtr->Config.BaseAddr, XDP_RX_LINK_ENABLE, 0x0); /* Set the AUX clock divider. */ XDp_WriteReg(InstancePtr->Config.BaseAddr, XDP_RX_AUX_CLK_DIVIDER, (InstancePtr->Config.SAxiClkHz / 1000000)); /* Put both GT RX/TX and CPLL into reset. */ XDp_WriteReg(InstancePtr->Config.BaseAddr, XDP_RX_PHY_CONFIG, XDP_RX_PHY_CONFIG_GTPLL_RESET_MASK | XDP_RX_PHY_CONFIG_GTRX_RESET_MASK); /* Release CPLL reset. */ XDp_WriteReg(InstancePtr->Config.BaseAddr, XDP_RX_PHY_CONFIG, XDP_RX_PHY_CONFIG_GTRX_RESET_MASK); /* Wait until all lane CPLLs have locked. */ Status = XDp_WaitPhyReady(InstancePtr, XDP_RX_PHY_STATUS_PLL_LANE0_1_LOCK_MASK | XDP_RX_PHY_STATUS_PLL_LANE2_3_LOCK_MASK); if (Status != XST_SUCCESS) { return XST_FAILURE; } /* Remove the reset from the PHY. */ XDp_WriteReg(InstancePtr->Config.BaseAddr, XDP_RX_PHY_CONFIG, XDP_RX_PHY_CONFIG_PHY_RESET_ENABLE_MASK); /* Wait until the PHY has completed the reset cycle. */ Status = XDp_WaitPhyReady(InstancePtr, XDP_RX_PHY_STATUS_ALL_LANES_READY_MASK | XDP_RX_PHY_STATUS_PLL_FABRIC_LOCK_MASK | XDP_RX_PHY_STATUS_RX_CLK_LOCK_MASK); if (Status != XST_SUCCESS) { return XST_FAILURE; } /* Enable the RX core. */ XDp_WriteReg(InstancePtr->Config.BaseAddr, XDP_RX_LINK_ENABLE, 0x1); /* Set other user parameters. */ XDp_WriteReg(InstancePtr->Config.BaseAddr, XDP_RX_MIN_VOLTAGE_SWING, 0x01); XDp_WriteReg(InstancePtr->Config.BaseAddr, XDP_RX_SINK_COUNT, 0x01); /* Set the AUX training interval. */ XDp_WriteReg(InstancePtr->Config.BaseAddr, XDP_RX_OVER_CTRL_DPCD, 0x1); XDp_WriteReg(InstancePtr->Config.BaseAddr, XDP_RX_OVER_TP_SET, (2 << XDP_RX_OVER_TP_SET_TRAINING_AUX_RD_INTERVAL_SHIFT)); XDp_WriteReg(InstancePtr->Config.BaseAddr, XDP_RX_OVER_CTRL_DPCD, 0x0); /* Set the link configuration.*/ XDp_RxSetLinkRate(InstancePtr, InstancePtr->RxInstance.LinkConfig.LinkRate); XDp_RxSetLaneCount(InstancePtr, InstancePtr->RxInstance.LinkConfig.LaneCount); /* Set the interrupt masks. */ XDp_WriteReg(InstancePtr->Config.BaseAddr, XDP_RX_INTERRUPT_MASK, ~XDP_RX_INTERRUPT_MASK_ALL_MASK); /* Enable the display timing generator. */ XDp_RxDtgEn(InstancePtr); return XST_SUCCESS; } /******************************************************************************/ /** * This function runs the link training process. It is implemented as a state * machine, with each state returning the next state. First, the clock recovery * sequence will be run; if successful, the channel equalization sequence will * run. If either the clock recovery or channel equalization sequence failed, * the link rate or the number of lanes used will be reduced and training will * be re-attempted. If training fails at the minimal data rate, 1.62 Gbps with * a single lane, training will no longer re-attempt and fail. * * @param InstancePtr is a pointer to the XDp instance. * * @return * - XST_SUCCESS if the training process succeeded. * - XST_FAILURE otherwise. * * @note None. * *******************************************************************************/ static u32 XDp_TxRunTraining(XDp *InstancePtr) { u32 Status; XDp_TxTrainingState TrainingState = XDP_TX_TS_CLOCK_RECOVERY; while (1) { switch (TrainingState) { case XDP_TX_TS_CLOCK_RECOVERY: TrainingState = XDp_TxTrainingStateClockRecovery( InstancePtr); break; case XDP_TX_TS_CHANNEL_EQUALIZATION: TrainingState = XDp_TxTrainingStateChannelEqualization( InstancePtr); break; case XDP_TX_TS_ADJUST_LINK_RATE: TrainingState = XDp_TxTrainingStateAdjustLinkRate( InstancePtr); break; case XDP_TX_TS_ADJUST_LANE_COUNT: TrainingState = XDp_TxTrainingStateAdjustLaneCount( InstancePtr); break; default: break; } if (TrainingState == XDP_TX_TS_SUCCESS) { break; } else if (TrainingState == XDP_TX_TS_FAILURE) { return XST_FAILURE; } if ((InstancePtr->TxInstance.TrainAdaptive == 0) && ((TrainingState == XDP_TX_TS_ADJUST_LANE_COUNT) || (TrainingState == XDP_TX_TS_ADJUST_LINK_RATE))) { return XST_FAILURE; } } /* Final status check. */ Status = XDp_TxCheckLinkStatus(InstancePtr, InstancePtr->TxInstance.LinkConfig.LaneCount); if (Status != XST_SUCCESS) { return XST_FAILURE; } return XST_SUCCESS; } /******************************************************************************/ /** * This function runs the clock recovery sequence as part of link training. The * sequence is as follows: * 0) Start signaling at the minimum voltage swing, pre-emphasis, and post- * cursor levels. * 1) Transmit training pattern 1 over the main link with symbol scrambling * disabled. * 2) The clock recovery loop. If clock recovery is unsuccessful after * MaxIterations loop iterations, return. * 2a) Wait for at least the period of time specified in the RX device's * DisplayPort Configuration Data (DPCD) register, * TRAINING_AUX_RD_INTERVAL. * 2b) Check if all lanes have achieved clock recovery lock. If so, return. * 2c) Check if the same voltage swing level has been used 5 consecutive * times or if the maximum level has been reached. If so, return. * 2d) Adjust the voltage swing, pre-emphasis, and post-cursor levels as * requested by the RX device. * 2e) Loop back to 2a. * For a more detailed description of the clock recovery sequence, see section * 3.5.1.2.1 of the DisplayPort 1.2a specification document. * * @param InstancePtr is a pointer to the XDp instance. * * @return The next training state: * - XDP_TX_TS_CHANNEL_EQUALIZATION if the clock recovery sequence * completed successfully. * - XDP_TX_TS_FAILURE if writing the drive settings to the RX * device was unsuccesful. * - XDP_TX_TS_ADJUST_LINK_RATE if the clock recovery sequence * did not complete successfully. * * @note None. * *******************************************************************************/ static XDp_TxTrainingState XDp_TxTrainingStateClockRecovery(XDp *InstancePtr) { u32 Status; u32 DelayUs; u8 PrevVsLevel = 0; u8 SameVsLevelCount = 0; XDp_TxLinkConfig *LinkConfig = &InstancePtr->TxInstance.LinkConfig; /* Obtain the required delay for clock recovery as specified by the * RX device. */ DelayUs = XDp_TxGetTrainingDelay(InstancePtr, XDP_TX_TS_CLOCK_RECOVERY); /* Start CRLock. */ /* Transmit training pattern 1. */ /* Disable the scrambler. */ /* Start from minimal voltage swing and pre-emphasis levels. */ InstancePtr->TxInstance.LinkConfig.VsLevel = 0; InstancePtr->TxInstance.LinkConfig.PeLevel = 0; Status = XDp_TxSetTrainingPattern(InstancePtr, XDP_TX_TRAINING_PATTERN_SET_TP1); if (Status != XST_SUCCESS) { return XDP_TX_TS_FAILURE; } while (1) { /* Wait delay specified in TRAINING_AUX_RD_INTERVAL. */ XDp_WaitUs(InstancePtr, DelayUs); /* Get lane and adjustment requests. */ Status = XDp_TxGetLaneStatusAdjReqs(InstancePtr); if (Status != XST_SUCCESS) { /* The AUX read failed. */ return XDP_TX_TS_FAILURE; } /* Check if all lanes have realized and maintained the frequency * lock and get adjustment requests. */ Status = XDp_TxCheckClockRecovery(InstancePtr, InstancePtr->TxInstance.LinkConfig.LaneCount); if (Status == XST_SUCCESS) { return XDP_TX_TS_CHANNEL_EQUALIZATION; } /* Check if the same voltage swing for each lane has been used 5 * consecutive times. */ if (PrevVsLevel == LinkConfig->VsLevel) { SameVsLevelCount++; } else { SameVsLevelCount = 0; PrevVsLevel = LinkConfig->VsLevel; } if (SameVsLevelCount >= 5) { break; } if (LinkConfig->VsLevel == XDP_TX_MAXIMUM_VS_LEVEL) { break; } /* Adjust the drive settings as requested by the RX device. */ Status = XDp_TxAdjVswingPreemp(InstancePtr); if (Status != XST_SUCCESS) { /* The AUX write failed. */ return XDP_TX_TS_FAILURE; } } return XDP_TX_TS_ADJUST_LINK_RATE; } /******************************************************************************/ /** * This function runs the channel equalization sequence as part of link * training. The sequence is as follows: * 0) Start signaling with the same drive settings used at the end of the * clock recovery sequence. * 1) Transmit training pattern 2 (or 3) over the main link with symbol * scrambling disabled. * 2) The channel equalization loop. If channel equalization is * unsuccessful after 5 loop iterations, return. * 2a) Wait for at least the period of time specified in the RX device's * DisplayPort Configuration Data (DPCD) register, * TRAINING_AUX_RD_INTERVAL. * 2b) Check if all lanes have achieved channel equalization, symbol lock, * and interlane alignment. If so, return. * 2c) Check if the same voltage swing level has been used 5 consecutive * times or if the maximum level has been reached. If so, return. * 2d) Adjust the voltage swing, pre-emphasis, and post-cursor levels as * requested by the RX device. * 2e) Loop back to 2a. * For a more detailed description of the channel equalization sequence, see * section 3.5.1.2.2 of the DisplayPort 1.2a specification document. * * @param InstancePtr is a pointer to the XDp instance. * * @return The next training state: * - XDP_TX_TS_SUCCESS if training succeeded. * - XDP_TX_TS_FAILURE if writing the drive settings to the RX * device was unsuccesful. * - XDP_TX_TS_ADJUST_LINK_RATE if, after 5 loop iterations, the * channel equalization sequence did not complete successfully. * * @note None. * *******************************************************************************/ static XDp_TxTrainingState XDp_TxTrainingStateChannelEqualization( XDp *InstancePtr) { u32 Status; u32 DelayUs; u32 IterationCount = 0; XDp_TxLinkConfig *LinkConfig = &InstancePtr->TxInstance.LinkConfig; /* Obtain the required delay for channel equalization as specified by * the RX device. */ DelayUs = XDp_TxGetTrainingDelay(InstancePtr, XDP_TX_TS_CHANNEL_EQUALIZATION); /* Start channel equalization. */ /* Write the current drive settings. */ /* Transmit training pattern 2/3. */ if (InstancePtr->TxInstance.RxConfig. DpcdRxCapsField[XDP_DPCD_MAX_LANE_COUNT] & XDP_DPCD_TPS3_SUPPORT_MASK) { Status = XDp_TxSetTrainingPattern(InstancePtr, XDP_TX_TRAINING_PATTERN_SET_TP3); } else { Status = XDp_TxSetTrainingPattern(InstancePtr, XDP_TX_TRAINING_PATTERN_SET_TP2); } if (Status != XST_SUCCESS) { return XDP_TX_TS_FAILURE; } while (IterationCount < 5) { /* Wait delay specified in TRAINING_AUX_RD_INTERVAL. */ XDp_WaitUs(InstancePtr, DelayUs); /* Get lane and adjustment requests. */ Status = XDp_TxGetLaneStatusAdjReqs(InstancePtr); if (Status != XST_SUCCESS) { /* The AUX read failed. */ return XDP_TX_TS_FAILURE; } /* Check that all lanes still have their clocks locked. */ Status = XDp_TxCheckClockRecovery(InstancePtr, InstancePtr->TxInstance.LinkConfig.LaneCount); if (Status != XST_SUCCESS) { break; } /* Check that all lanes stihave accomplished channel * equalization, symbol lock, and interlane alignment. */ Status = XDp_TxCheckChannelEqualization(InstancePtr, InstancePtr->TxInstance.LinkConfig.LaneCount); if (Status == XST_SUCCESS) { return XDP_TX_TS_SUCCESS; } /* Adjust the drive settings as requested by the RX device. */ Status = XDp_TxAdjVswingPreemp(InstancePtr); if (Status != XST_SUCCESS) { /* The AUX write failed. */ return XDP_TX_TS_FAILURE; } IterationCount++; } /* Tried MaxIteration times with no success. Try a reduced bitrate * first, then reduce the number of lanes. */ return XDP_TX_TS_ADJUST_LINK_RATE; } /******************************************************************************/ /** * This function is reached if either the clock recovery or the channel * equalization process failed during training. As a result, the data rate will * be downshifted, and training will be re-attempted (starting with clock * recovery) at the reduced data rate. If the data rate is already at 1.62 Gbps, * a downshift in lane count will be attempted. * * @param InstancePtr is a pointer to the XDp instance. * * @return The next training state: * - XDP_TX_TS_ADJUST_LANE_COUNT if the minimal data rate is already * in use. Re-attempt training at a reduced lane count. * - XDP_TX_TS_CLOCK_RECOVERY otherwise. Re-attempt training. * * @note None. * *******************************************************************************/ static XDp_TxTrainingState XDp_TxTrainingStateAdjustLinkRate(XDp *InstancePtr) { u32 Status; switch (InstancePtr->TxInstance.LinkConfig.LinkRate) { case XDP_TX_LINK_BW_SET_540GBPS: Status = XDp_TxSetLinkRate(InstancePtr, XDP_TX_LINK_BW_SET_270GBPS); if (Status != XST_SUCCESS) { Status = XDP_TX_TS_FAILURE; break; } Status = XDP_TX_TS_CLOCK_RECOVERY; break; case XDP_TX_LINK_BW_SET_270GBPS: Status = XDp_TxSetLinkRate(InstancePtr, XDP_TX_LINK_BW_SET_162GBPS); if (Status != XST_SUCCESS) { Status = XDP_TX_TS_FAILURE; break; } Status = XDP_TX_TS_CLOCK_RECOVERY; break; default: /* Already at the lowest link rate. Try reducing the lane * count next. */ Status = XDP_TX_TS_ADJUST_LANE_COUNT; break; } return Status; } /******************************************************************************/ /** * This function is reached if either the clock recovery or the channel * equalization process failed during training, and a minimal data rate of 1.62 * Gbps was being used. As a result, the number of lanes in use will be reduced, * and training will be re-attempted (starting with clock recovery) at this * lower lane count. * * @note Training will be re-attempted with the maximum data rate being * used with the reduced lane count to train at the main link at * the maximum bandwidth possible. * * @param InstancePtr is a pointer to the XDp instance. * * @return The next training state: * - XDP_TX_TS_FAILURE if only one lane is already in use. * - XDP_TX_TS_CLOCK_RECOVERY otherwise. Re-attempt training. * * @note None. * *******************************************************************************/ static XDp_TxTrainingState XDp_TxTrainingStateAdjustLaneCount(XDp *InstancePtr) { u32 Status; XDp_TxLinkConfig *LinkConfig = &InstancePtr->TxInstance.LinkConfig; switch (LinkConfig->LaneCount) { case XDP_TX_LANE_COUNT_SET_4: Status = XDp_TxSetLaneCount(InstancePtr, XDP_TX_LANE_COUNT_SET_2); if (Status != XST_SUCCESS) { Status = XDP_TX_TS_FAILURE; break; } Status = XDp_TxSetLinkRate(InstancePtr, LinkConfig->MaxLinkRate); if (Status != XST_SUCCESS) { Status = XDP_TX_TS_FAILURE; break; } Status = XDP_TX_TS_CLOCK_RECOVERY; break; case XDP_TX_LANE_COUNT_SET_2: Status = XDp_TxSetLaneCount(InstancePtr, XDP_TX_LANE_COUNT_SET_1); if (Status != XST_SUCCESS) { Status = XDP_TX_TS_FAILURE; break; } Status = XDp_TxSetLinkRate(InstancePtr, LinkConfig->MaxLinkRate); if (Status != XST_SUCCESS) { Status = XDP_TX_TS_FAILURE; break; } Status = XDP_TX_TS_CLOCK_RECOVERY; break; default: /* Already at the lowest lane count. Training has failed at the * lowest lane count and link rate. */ Status = XDP_TX_TS_FAILURE; break; } return Status; } /******************************************************************************/ /** * This function will do a burst AUX read from the RX device over the AUX * channel. The contents of the status registers will be stored for later use by * XDp_TxCheckClockRecovery, XDp_TxCheckChannelEqualization, and * XDp_TxAdjVswingPreemp. * * @param InstancePtr is a pointer to the XDp instance. * * @return * - XST_SUCCESS if the AUX read was successful. * - XST_FAILURE otherwise. * * @note None. * *******************************************************************************/ static u32 XDp_TxGetLaneStatusAdjReqs(XDp *InstancePtr) { u32 Status; /* Read and store 4 bytes of lane status and 2 bytes of adjustment * requests. */ Status = XDp_TxAuxRead(InstancePtr, XDP_DPCD_STATUS_LANE_0_1, 6, InstancePtr->TxInstance.RxConfig.LaneStatusAdjReqs); if (Status != XST_SUCCESS) { return XST_FAILURE; } return XST_SUCCESS; } /******************************************************************************/ /** * This function checks if the RX device's DisplayPort Configuration Data (DPCD) * indicates that the clock recovery sequence during link training was * successful - the RX device's link clock and data recovery unit has realized * and maintained the frequency lock for all lanes currently in use. * * @param InstancePtr is a pointer to the XDp instance. * @param LaneCount is the number of lanes to check. * * @return * - XST_SUCCESS if the RX device's clock recovery PLL has * achieved frequency lock for all lanes in use. * - XST_FAILURE otherwise. * * @note None. * *******************************************************************************/ static u32 XDp_TxCheckClockRecovery(XDp *InstancePtr, u8 LaneCount) { u32 Status; u8 AuxData[6]; u8 *LaneStatus = InstancePtr->TxInstance.RxConfig.LaneStatusAdjReqs; /* Check that all LANEx_CR_DONE bits are set. */ switch (LaneCount) { case XDP_TX_LANE_COUNT_SET_4: if (!(LaneStatus[1] & XDP_DPCD_STATUS_LANE_3_CR_DONE_MASK)) { return XST_FAILURE; } if (!(LaneStatus[1] & XDP_DPCD_STATUS_LANE_2_CR_DONE_MASK)) { return XST_FAILURE; } /* Drop through and check lane 1. */ case XDP_TX_LANE_COUNT_SET_2: if (!(LaneStatus[0] & XDP_DPCD_STATUS_LANE_1_CR_DONE_MASK)) { return XST_FAILURE; } /* Drop through and check lane 0. */ case XDP_TX_LANE_COUNT_SET_1: if (!(LaneStatus[0] & XDP_DPCD_STATUS_LANE_0_CR_DONE_MASK)) { return XST_FAILURE; } default: /* All (LaneCount) lanes have achieved clock recovery. */ break; } return XST_SUCCESS; } /******************************************************************************/ /** * This function checks if the RX device's DisplayPort Configuration Data (DPCD) * indicates that the channel equalization sequence during link training was * successful - the RX device has achieved channel equalization, symbol lock, * and interlane alignment for all lanes currently in use. * * @param InstancePtr is a pointer to the XDp instance. * @param LaneCount is the number of lanes to check. * * @return * - XST_SUCCESS if the RX device has achieved channel * equalization symbol lock, and interlane alignment for all * lanes in use. * - XST_FAILURE otherwise. * * @note None. * *******************************************************************************/ static u32 XDp_TxCheckChannelEqualization(XDp *InstancePtr, u8 LaneCount) { u32 Status; u8 AuxData[6]; u8 *LaneStatus = InstancePtr->TxInstance.RxConfig.LaneStatusAdjReqs; /* Check that all LANEx_CHANNEL_EQ_DONE bits are set. */ switch (LaneCount) { case XDP_TX_LANE_COUNT_SET_4: if (!(LaneStatus[1] & XDP_DPCD_STATUS_LANE_3_CE_DONE_MASK)) { return XST_FAILURE; } if (!(LaneStatus[1] & XDP_DPCD_STATUS_LANE_2_CE_DONE_MASK)) { return XST_FAILURE; } /* Drop through and check lane 1. */ case XDP_TX_LANE_COUNT_SET_2: if (!(LaneStatus[0] & XDP_DPCD_STATUS_LANE_1_CE_DONE_MASK)) { return XST_FAILURE; } /* Drop through and check lane 0. */ case XDP_TX_LANE_COUNT_SET_1: if (!(LaneStatus[0] & XDP_DPCD_STATUS_LANE_0_CE_DONE_MASK)) { return XST_FAILURE; } default: /* All (LaneCount) lanes have achieved channel equalization. */ break; } /* Check that all LANEx_SYMBOL_LOCKED bits are set. */ switch (LaneCount) { case XDP_TX_LANE_COUNT_SET_4: if (!(LaneStatus[1] & XDP_DPCD_STATUS_LANE_3_SL_DONE_MASK)) { return XST_FAILURE; } if (!(LaneStatus[1] & XDP_DPCD_STATUS_LANE_2_SL_DONE_MASK)) { return XST_FAILURE; } /* Drop through and check lane 1. */ case XDP_TX_LANE_COUNT_SET_2: if (!(LaneStatus[0] & XDP_DPCD_STATUS_LANE_1_SL_DONE_MASK)) { return XST_FAILURE; } /* Drop through and check lane 0. */ case XDP_TX_LANE_COUNT_SET_1: if (!(LaneStatus[0] & XDP_DPCD_STATUS_LANE_0_SL_DONE_MASK)) { return XST_FAILURE; } default: /* All (LaneCount) lanes have achieved symbol lock. */ break; } /* Check that interlane alignment is done. */ if (!(LaneStatus[2] & XDP_DPCD_LANE_ALIGN_STATUS_UPDATED_IA_DONE_MASK)) { return XST_FAILURE; } return XST_SUCCESS; } /******************************************************************************/ /** * This function sets current voltage swing and pre-emphasis level settings from * the LinkConfig structure to hardware. * * @param InstancePtr is a pointer to the XDp instance. * @param AuxData is a pointer to the array used for preparing a burst * write over the AUX channel. * * @return * - XST_SUCCESS if writing the settings was successful. * - XST_FAILURE otherwise. * * @note 7-series FPGAs registers use the terminology POSTCURSOR(1) to * represent the DisplayPort pre-emphasis levels. * *******************************************************************************/ static void XDp_TxSetVswingPreemp(XDp *InstancePtr, u8 *AuxData) { u32 Status; u8 Data; u8 Index; u8 VsLevelRx = InstancePtr->TxInstance.LinkConfig.VsLevel; u8 PeLevelRx = InstancePtr->TxInstance.LinkConfig.PeLevel; u32 VsLevel; u32 PeLevel; if (InstancePtr->TxInstance.BoardChar.HasRedriverInPath == 0) { PeLevel = InstancePtr->TxInstance.BoardChar.TxPeLevels[PeLevelRx]; VsLevel = InstancePtr->TxInstance.BoardChar.TxVsLevels[VsLevelRx]; /* Need to compensate due to no redriver in the path. */ if (PeLevelRx != 0) { VsLevel += InstancePtr->TxInstance.BoardChar.TxVsOffset; } } else { /* No need to compensate since redriver does that. Can evenly * disperse the voltage swing and pre-emphasis levels. */ /* Map 16 possible voltage swing levels in the DisplayPort TX * core to 4 possible in the RX device. */ VsLevel = VsLevelRx * 4 + 2; /* Map 32 possible pre-emphasis levels in the DisplayPort TX * core to 4 possible in the RX device. */ PeLevel = PeLevelRx * 8 + 4; } /* Set up the data buffer for writing to the RX device. */ Data = (PeLevelRx << XDP_DPCD_TRAINING_LANEX_SET_PE_SHIFT) | VsLevelRx; /* The maximum voltage swing has been reached. */ if (VsLevelRx == XDP_TX_MAXIMUM_VS_LEVEL) { Data |= XDP_DPCD_TRAINING_LANEX_SET_MAX_VS_MASK; } /* The maximum pre-emphasis level has been reached. */ if (PeLevelRx == XDP_TX_MAXIMUM_PE_LEVEL) { Data |= XDP_DPCD_TRAINING_LANEX_SET_MAX_PE_MASK; } memset(AuxData, Data, 4); for (Index = 0; Index < InstancePtr->TxInstance.LinkConfig.LaneCount; Index++) { /* Disable pre-cursor levels. */ XDp_WriteReg(InstancePtr->Config.BaseAddr, XDP_TX_PHY_PRECURSOR_LANE_0 + 4 * Index, 0x0); /* Write new voltage swing levels to the TX registers. */ XDp_WriteReg(InstancePtr->Config.BaseAddr, XDP_TX_PHY_VOLTAGE_DIFF_LANE_0 + 4 * Index, VsLevel); /* Write new pre-emphasis levels to the TX registers. */ XDp_WriteReg(InstancePtr->Config.BaseAddr, XDP_TX_PHY_POSTCURSOR_LANE_0 + 4 * Index, PeLevel); } } /******************************************************************************/ /** * This function sets new voltage swing and pre-emphasis levels using the * adjustment requests obtained from the RX device. * * @param InstancePtr is a pointer to the XDp instance. * * @return * - XST_SUCCESS if the new levels were written successfully. * - XST_FAILURE otherwise (an AUX transaction failed). * * @note None. * *******************************************************************************/ static u32 XDp_TxAdjVswingPreemp(XDp *InstancePtr) { u32 Status; u8 Index; u8 VsLevelAdjReq[4]; u8 PeLevelAdjReq[4]; u8 AuxData[4]; u8 *AdjReqs = &InstancePtr->TxInstance.RxConfig.LaneStatusAdjReqs[4]; /* Analyze the adjustment requests for changes in voltage swing and * pre-emphasis levels. */ VsLevelAdjReq[0] = AdjReqs[0] & XDP_DPCD_ADJ_REQ_LANE_0_2_VS_MASK; VsLevelAdjReq[1] = (AdjReqs[0] & XDP_DPCD_ADJ_REQ_LANE_1_3_VS_MASK) >> XDP_DPCD_ADJ_REQ_LANE_1_3_VS_SHIFT; VsLevelAdjReq[2] = AdjReqs[1] & XDP_DPCD_ADJ_REQ_LANE_0_2_VS_MASK; VsLevelAdjReq[3] = (AdjReqs[1] & XDP_DPCD_ADJ_REQ_LANE_1_3_VS_MASK) >> XDP_DPCD_ADJ_REQ_LANE_1_3_VS_SHIFT; PeLevelAdjReq[0] = (AdjReqs[0] & XDP_DPCD_ADJ_REQ_LANE_0_2_PE_MASK) >> XDP_DPCD_ADJ_REQ_LANE_0_2_PE_SHIFT; PeLevelAdjReq[1] = (AdjReqs[0] & XDP_DPCD_ADJ_REQ_LANE_1_3_PE_MASK) >> XDP_DPCD_ADJ_REQ_LANE_1_3_PE_SHIFT; PeLevelAdjReq[2] = (AdjReqs[1] & XDP_DPCD_ADJ_REQ_LANE_0_2_PE_MASK) >> XDP_DPCD_ADJ_REQ_LANE_0_2_PE_SHIFT; PeLevelAdjReq[3] = (AdjReqs[1] & XDP_DPCD_ADJ_REQ_LANE_1_3_PE_MASK) >> XDP_DPCD_ADJ_REQ_LANE_1_3_PE_SHIFT; /* Change the drive settings to match the adjustment requests. Use the * greatest level requested. */ InstancePtr->TxInstance.LinkConfig.VsLevel = 0; InstancePtr->TxInstance.LinkConfig.PeLevel = 0; for (Index = 0; Index < InstancePtr->TxInstance.LinkConfig.LaneCount; Index++) { if (VsLevelAdjReq[Index] > InstancePtr->TxInstance.LinkConfig.VsLevel) { InstancePtr->TxInstance.LinkConfig.VsLevel = VsLevelAdjReq[Index]; } if (PeLevelAdjReq[Index] > InstancePtr->TxInstance.LinkConfig.PeLevel) { InstancePtr->TxInstance.LinkConfig.PeLevel = PeLevelAdjReq[Index]; } } /* Verify that the voltage swing and pre-emphasis combination is * allowed. Some combinations will result in a differential peak-to-peak * voltage that is outside the permissable range. See the VESA * DisplayPort v1.2 Specification, section 3.1.5.2. * The valid combinations are: * PE=0 PE=1 PE=2 PE=3 * VS=0 Valid Valid Valid Valid * VS=1 Valid Valid Valid * VS=2 Valid Valid * VS=3 Valid */ if (InstancePtr->TxInstance.LinkConfig.PeLevel > (4 - InstancePtr->TxInstance.LinkConfig.VsLevel)) { InstancePtr->TxInstance.LinkConfig.PeLevel = 4 - InstancePtr->TxInstance.LinkConfig.VsLevel; } /* Make the adjustments to both the DisplayPort TX core and the RX * device. */ XDp_TxSetVswingPreemp(InstancePtr, AuxData); /* Write the voltage swing and pre-emphasis levels for each lane to the * RX device. */ Status = XDp_TxAuxWrite(InstancePtr, XDP_DPCD_TRAINING_LANE0_SET, 4, AuxData); if (Status != XST_SUCCESS) { return XST_FAILURE; } return XST_SUCCESS; } /******************************************************************************/ /** * This function sets the training pattern to be used during link training for * both the DisplayPort TX core and the RX device. * * @param InstancePtr is a pointer to the XDp instance. * @param Pattern selects the pattern to be used. One of the following: * - XDP_TX_TRAINING_PATTERN_SET_OFF * - XDP_TX_TRAINING_PATTERN_SET_TP1 * - XDP_TX_TRAINING_PATTERN_SET_TP2 * - XDP_TX_TRAINING_PATTERN_SET_TP3 * * @return * - XST_SUCCESS if setting the pattern was successful. * - XST_FAILURE otherwise. * * @note None. * *******************************************************************************/ static u32 XDp_TxSetTrainingPattern(XDp *InstancePtr, u32 Pattern) { u32 Status; u8 AuxData[5]; /* Write to the DisplayPort TX core. */ XDp_WriteReg(InstancePtr->Config.BaseAddr, XDP_TX_TRAINING_PATTERN_SET, Pattern); AuxData[0] = Pattern; /* Write scrambler disable to the DisplayPort TX core. */ switch (Pattern) { case XDP_TX_TRAINING_PATTERN_SET_OFF: XDp_WriteReg(InstancePtr->Config.BaseAddr, XDP_TX_SCRAMBLING_DISABLE, 0); InstancePtr->TxInstance.LinkConfig.ScramblerEn = 1; break; case XDP_TX_TRAINING_PATTERN_SET_TP1: case XDP_TX_TRAINING_PATTERN_SET_TP2: case XDP_TX_TRAINING_PATTERN_SET_TP3: AuxData[0] |= XDP_DPCD_TP_SET_SCRAMB_DIS_MASK; XDp_WriteReg(InstancePtr->Config.BaseAddr, XDP_TX_SCRAMBLING_DISABLE, 1); InstancePtr->TxInstance.LinkConfig.ScramblerEn = 0; break; default: break; } /* Make the adjustments to both the DisplayPort TX core and the RX * device. */ XDp_TxSetVswingPreemp(InstancePtr, &AuxData[1]); /* Write the voltage swing and pre-emphasis levels for each lane to the * RX device. */ Status = XDp_TxAuxWrite(InstancePtr, XDP_DPCD_TP_SET, 5, AuxData); if (Status != XST_SUCCESS) { return XST_FAILURE; } return XST_SUCCESS; } /******************************************************************************/ /** * This function determines what the RX device's required training delay is for * link training. * * @param InstancePtr is a pointer to the XDp instance. * @param TrainingState is the current training state; either clock * recovery or channel equalization. * * @return The training delay specified in the RX device's DisplayPort * Configuration Data (DPCD) register, * XDP_DPCD_TRAIN_AUX_RD_INTERVAL. * * @note None. * *******************************************************************************/ static u32 XDp_TxGetTrainingDelay(XDp *InstancePtr, XDp_TxTrainingState TrainingState) { u8 *Dpcd = InstancePtr->TxInstance.RxConfig.DpcdRxCapsField; u16 Delay; switch (Dpcd[XDP_DPCD_TRAIN_AUX_RD_INTERVAL]) { case XDP_DPCD_TRAIN_AUX_RD_INT_100_400US: if (TrainingState == XDP_TX_TS_CLOCK_RECOVERY) { /* Delay for the clock recovery phase. */ Delay = 100; } else { /* Delay for the channel equalization phase. */ Delay = 400; } break; case XDP_DPCD_TRAIN_AUX_RD_INT_4MS: Delay = 4000; break; case XDP_DPCD_TRAIN_AUX_RD_INT_8MS: Delay = 8000; break; case XDP_DPCD_TRAIN_AUX_RD_INT_12MS: Delay = 12000; break; case XDP_DPCD_TRAIN_AUX_RD_INT_16MS: Delay = 16000; break; default: /* Default to 20 ms. */ Delay = 20000; break; } return Delay; } /******************************************************************************/ /** * This function contains the common sequence of submitting an AUX command for * AUX read, AUX write, I2C-over-AUX read, and I2C-over-AUX write transactions. * If required, the reads and writes are split into multiple requests, each * acting on a maximum of 16 bytes. * * @param InstancePtr is a pointer to the XDp instance. * @param CmdType is the type of AUX command (one of: XDP_TX_AUX_CMD_READ, * XDP_TX_AUX_CMD_WRITE, XDP_TX_AUX_CMD_I2C_READ, or * XDP_TX_AUX_CMD_I2C_WRITE. * @param Address is the starting address that the AUX transaction will * read/write from/to the RX device. * @param NumBytes is the number of bytes to read/write from/to the RX * device. * @param Data is a pointer to the data buffer that contains the data * to be read/written from/to the RX device. * * @return * - XST_SUCCESS if the AUX transaction request was acknowledged. * - XST_ERROR_COUNT_MAX if the AUX request timed out. * - XST_FAILURE otherwise (if the DisplayPort TX core sees a NACK * reply code or if the AUX transaction failed). * * @note None. * *******************************************************************************/ static u32 XDp_TxAuxCommon(XDp *InstancePtr, u32 CmdType, u32 Address, u32 NumBytes, u8 *Data) { u32 Status; XDp_AuxTransaction Request; u32 BytesLeft; /* Set the start address for AUX transactions. For I2C transactions, * this is the address of the I2C bus. */ Request.Address = Address; BytesLeft = NumBytes; while (BytesLeft > 0) { Request.CmdCode = CmdType; if ((CmdType == XDP_TX_AUX_CMD_READ) || (CmdType == XDP_TX_AUX_CMD_WRITE)) { /* Increment address for normal AUX transactions. */ Request.Address = Address + (NumBytes - BytesLeft); } /* Increment the pointer to the supplied data buffer. */ Request.Data = &Data[NumBytes - BytesLeft]; if (BytesLeft > 16) { Request.NumBytes = 16; } else { Request.NumBytes = BytesLeft; } BytesLeft -= Request.NumBytes; if ((CmdType == XDP_TX_AUX_CMD_I2C_READ) && (BytesLeft > 0)) { /* Middle of a transaction I2C read request. Override * the command code that was set to CmdType. */ Request.CmdCode = XDP_TX_AUX_CMD_I2C_READ_MOT; } else if ((CmdType == XDP_TX_AUX_CMD_I2C_WRITE) && (BytesLeft > 0)) { /* Middle of a transaction I2C write request. Override * the command code that was set to CmdType. */ Request.CmdCode = XDP_TX_AUX_CMD_I2C_WRITE_MOT; } XDp_WaitUs(InstancePtr, InstancePtr->TxInstance.AuxDelayUs); Status = XDp_TxAuxRequest(InstancePtr, &Request); if (Status != XST_SUCCESS) { return Status; } } return XST_SUCCESS; } /******************************************************************************/ /** * This function submits the supplied AUX request to the RX device over the AUX * channel. If waiting for a reply times out, or if the DisplayPort TX core * indicates that the request was deferred, the request is sent again (up to a * maximum specified by XDP_AUX_MAX_DEFER_COUNT|XDP_AUX_MAX_TIMEOUT_COUNT). * * @param InstancePtr is a pointer to the XDp instance. * @param Request is a pointer to an initialized XDp_AuxTransaction * structure containing the required information for issuing an * AUX command, as well as a write buffer used for write commands, * and a read buffer for read commands. * * @return * - XST_SUCCESS if the request was acknowledged. * - XST_ERROR_COUNT_MAX if resending the request exceeded the * maximum for deferral and timeout. * - XST_FAILURE otherwise (if the DisplayPort TX core sees a NACK * reply code or if the AUX transaction failed). * * @note None. * *******************************************************************************/ static u32 XDp_TxAuxRequest(XDp *InstancePtr, XDp_AuxTransaction *Request) { u32 Status; u32 DeferCount = 0; u32 TimeoutCount = 0; while ((DeferCount < XDP_AUX_MAX_DEFER_COUNT) && (TimeoutCount < XDP_AUX_MAX_TIMEOUT_COUNT)) { Status = XDp_TxAuxWaitReady(InstancePtr); if (Status != XST_SUCCESS) { /* The RX device isn't ready yet. */ TimeoutCount++; continue; } /* Send the request. */ Status = XDp_TxAuxRequestSend(InstancePtr, Request); if (Status == XST_SEND_ERROR) { /* The request was deferred. */ DeferCount++; } else if (Status == XST_ERROR_COUNT_MAX) { /* Waiting for a reply timed out. */ TimeoutCount++; } else { /* XST_FAILURE indicates that the request was NACK'ed, * XST_SUCCESS indicates that the request was ACK'ed. */ return Status; } XDp_WaitUs(InstancePtr, 100); } /* The request was not successfully received by the RX device. */ return XST_ERROR_COUNT_MAX; } /******************************************************************************/ /** * This function submits the supplied AUX request to the RX device over the AUX * channel by writing the command, the destination address, (the write buffer * for write commands), and the data size to the DisplayPort TX core. * * @param InstancePtr is a pointer to the XDp instance. * @param Request is a pointer to an initialized XDp_AuxTransaction * structure containing the required information for issuing an AUX * command. * * @return * - XST_SUCCESS if the request was acknowledged. * - XST_ERROR_COUNT_MAX if waiting for a reply timed out. * - XST_SEND_ERROR if the request was deferred. * - XST_FAILURE otherwise, if the request was NACK'ed. * * @note None. * *******************************************************************************/ static u32 XDp_TxAuxRequestSend(XDp *InstancePtr, XDp_AuxTransaction *Request) { u32 Status; u8 Index; /* Set the address for the request. */ XDp_WriteReg(InstancePtr->Config.BaseAddr, XDP_TX_AUX_ADDRESS, Request->Address); if ((Request->CmdCode == XDP_TX_AUX_CMD_WRITE) || (Request->CmdCode == XDP_TX_AUX_CMD_I2C_WRITE) || (Request->CmdCode == XDP_TX_AUX_CMD_I2C_WRITE_MOT)) { /* Feed write data into the DisplayPort TX core's write FIFO. */ for (Index = 0; Index < Request->NumBytes; Index++) { XDp_WriteReg(InstancePtr->Config.BaseAddr, XDP_TX_AUX_WRITE_FIFO, Request->Data[Index]); } } /* Submit the command and the data size. */ XDp_WriteReg(InstancePtr->Config.BaseAddr, XDP_TX_AUX_CMD, ((Request->CmdCode << XDP_TX_AUX_CMD_SHIFT) | ((Request->NumBytes - 1) & XDP_TX_AUX_CMD_NBYTES_TRANSFER_MASK))); /* Check for a reply from the RX device to the submitted request. */ Status = XDp_TxAuxWaitReply(InstancePtr); if (Status != XST_SUCCESS) { /* Waiting for a reply timed out. */ return XST_ERROR_COUNT_MAX; } /* Analyze the reply. */ Status = XDp_ReadReg(InstancePtr->Config.BaseAddr, XDP_TX_AUX_REPLY_CODE); if ((Status == XDP_TX_AUX_REPLY_CODE_DEFER) || (Status == XDP_TX_AUX_REPLY_CODE_I2C_DEFER)) { /* The request was deferred. */ return XST_SEND_ERROR; } else if ((Status == XDP_TX_AUX_REPLY_CODE_NACK) || (Status == XDP_TX_AUX_REPLY_CODE_I2C_NACK)) { /* The request was not acknowledged. */ return XST_FAILURE; } /* The request was acknowledged. */ if ((Request->CmdCode == XDP_TX_AUX_CMD_READ) || (Request->CmdCode == XDP_TX_AUX_CMD_I2C_READ) || (Request->CmdCode == XDP_TX_AUX_CMD_I2C_READ_MOT)) { /* Obtain the read data from the reply FIFO. */ for (Index = 0; Index < Request->NumBytes; Index++) { Request->Data[Index] = XDp_ReadReg( InstancePtr->Config.BaseAddr, XDP_TX_AUX_REPLY_DATA); } } return XST_SUCCESS; } /******************************************************************************/ /** * This function waits for a reply indicating that the most recent AUX request * has been received by the RX device. * * @param InstancePtr is a pointer to the XDp instance. * * @return * - XST_SUCCESS if a reply was sent from the RX device. * - XST_ERROR_COUNT_MAX otherwise, if a timeout has occurred. * * @note None. * *******************************************************************************/ static u32 XDp_TxAuxWaitReply(XDp *InstancePtr) { u32 Timeout = 100; u32 Status; while (0 < Timeout) { Status = XDp_ReadReg(InstancePtr->Config.BaseAddr, XDP_TX_INTERRUPT_STATUS); /* Check for a timeout. */ if (Status & XDP_TX_INTERRUPT_STATUS_REPLY_TIMEOUT_MASK) { return XST_ERROR_COUNT_MAX; } /* Check for a reply. */ if (Status & XDP_TX_INTERRUPT_STATUS_REPLY_RECEIVED_MASK) { return XST_SUCCESS; } Timeout--; XDp_WaitUs(InstancePtr, 20); } return XST_ERROR_COUNT_MAX; } /******************************************************************************/ /** * This function waits until another request is no longer in progress. * * @param InstancePtr is a pointer to the XDp instance. * * @return * - XST_SUCCESS if the the RX device is no longer busy. * - XST_ERROR_COUNT_MAX otherwise, if a timeout has occurred. * * @note None. * *******************************************************************************/ static u32 XDp_TxAuxWaitReady(XDp *InstancePtr) { u32 Status; u32 Timeout = 100; /* Wait until the DisplayPort TX core is ready. */ do { Status = XDp_ReadReg(InstancePtr->Config.BaseAddr, XDP_TX_INTERRUPT_SIG_STATE); /* Protect against an infinite loop. */ if (!Timeout--) { return XST_ERROR_COUNT_MAX; } XDp_WaitUs(InstancePtr, 20); } while (Status & XDP_TX_REPLY_STATUS_REPLY_IN_PROGRESS_MASK); return XST_SUCCESS; } /******************************************************************************/ /** * This function sets the clock frequency for the DisplayPort PHY corresponding * to a desired data rate. * * @param InstancePtr is a pointer to the XDp instance. * @param Speed determines what clock frequency will be used based on one * of the following selects: * - XDP_TX_PHY_CLOCK_SELECT_162GBPS = 0x01 * - XDP_TX_PHY_CLOCK_SELECT_270GBPS = 0x03 * - XDP_TX_PHY_CLOCK_SELECT_540GBPS = 0x05 * * @return * - XST_SUCCESS if the reset for each lane is done after the clock * frequency has been set. * - XST_FAILURE otherwise. * * @note None. * *******************************************************************************/ static u32 XDp_TxSetClkSpeed(XDp *InstancePtr, u32 Speed) { u32 Status; u32 RegVal; /* Disable the DisplayPort TX core first. */ RegVal = XDp_ReadReg(InstancePtr->Config.BaseAddr, XDP_TX_ENABLE); XDp_WriteReg(InstancePtr->Config.BaseAddr, XDP_TX_ENABLE, 0x0); /* Change speed of the feedback clock. */ XDp_WriteReg(InstancePtr->Config.BaseAddr, XDP_TX_PHY_CLOCK_SELECT, Speed); /* Re-enable the DisplayPort TX core if it was previously enabled. */ if (RegVal != 0x0) { XDp_WriteReg(InstancePtr->Config.BaseAddr, XDP_TX_ENABLE, 0x1); } /* Wait until the PHY is ready. */ if (InstancePtr->Config.MaxLaneCount > 2) { Status = XDp_WaitPhyReady(InstancePtr, XDP_TX_PHY_STATUS_ALL_LANES_READY_MASK); } else { Status = XDp_WaitPhyReady(InstancePtr, XDP_TX_PHY_STATUS_LANES_0_1_READY_MASK); } if (Status != XST_SUCCESS) { return XST_FAILURE; } return XST_SUCCESS; } /******************************************************************************/ /** * This function waits for the DisplayPort PHY to come out of reset. * * @param InstancePtr is a pointer to the XDp instance. * * @return * - XST_ERROR_COUNT_MAX if the PHY failed to be ready. * - XST_SUCCESS otherwise. * * @note None. * *******************************************************************************/ static u32 XDp_WaitPhyReady(XDp *InstancePtr, u32 Mask) { u16 Timeout = 20000; u32 PhyStatus; u32 RegPhyStatus; if (XDp_CfgGetCoreType(&InstancePtr->Config) == XDP_TX) { RegPhyStatus = XDP_TX_PHY_STATUS; } else { RegPhyStatus = XDP_RX_PHY_STATUS; } /* Wait until the PHY is ready. */ do { PhyStatus = XDp_ReadReg(InstancePtr->Config.BaseAddr, RegPhyStatus) & Mask; /* Protect against an infinite loop. */ if (!Timeout--) { return XST_ERROR_COUNT_MAX; } XDp_WaitUs(InstancePtr, 20); } while (PhyStatus != Mask); return XST_SUCCESS; }