
It seems that monitors capable of MST, upon switching to SST mode in the monitor options menu, respond with NACK when the segment pointer is written. These same monitors ACK segment pointer writes when running in MST mode. Tested monitors that are SST only monitors also ACK segment pointer writes. The issue here is that MST monitors running in SST mode will error out when the I2C read function is called because the segment pointer is always being written to 0 (segment pointer is reset), and thus receives a NACK. This patch prevents this from happening. From now on, if the user changes the segment pointer, it is up to them to reset it to 0. The I2C read will only increment the segment pointer when required to do a read outside of the base EDID block. Signed-off-by: Andrei-Liviu Simion <andrei.simion@xilinx.com>
3179 lines
100 KiB
C
3179 lines
100 KiB
C
/*******************************************************************************
|
|
*
|
|
* 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.
|
|
*
|
|
* <pre>
|
|
* MODIFICATION HISTORY:
|
|
*
|
|
* Ver Who Date Changes
|
|
* ----- ---- -------- -----------------------------------------------
|
|
* 1.0 als 01/20/15 Initial release. TX code merged from the dptx driver.
|
|
* </pre>
|
|
*
|
|
*******************************************************************************/
|
|
|
|
/******************************* 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_GetCoreType(InstancePtr) == 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_GetCoreType(InstancePtr) == 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(XDp_GetCoreType(InstancePtr) == XDP_TX);
|
|
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);
|
|
Xil_AssertNonvoid(XDp_GetCoreType(InstancePtr) == XDP_TX);
|
|
/* 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(XDp_GetCoreType(InstancePtr) == XDP_TX);
|
|
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);
|
|
if (ReenableMainLink) {
|
|
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(XDp_GetCoreType(InstancePtr) == XDP_TX);
|
|
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(XDp_GetCoreType(InstancePtr) == XDP_TX);
|
|
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(XDp_GetCoreType(InstancePtr) == XDP_TX);
|
|
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(XDp_GetCoreType(InstancePtr) == XDP_TX);
|
|
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(XDp_GetCoreType(InstancePtr) == XDP_TX);
|
|
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(XDp_GetCoreType(InstancePtr) == XDP_TX);
|
|
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;
|
|
|
|
/* Verify arguments. */
|
|
Xil_AssertNonvoid(InstancePtr != NULL);
|
|
Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
|
|
Xil_AssertNonvoid(XDp_GetCoreType(InstancePtr) == XDP_TX);
|
|
|
|
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(XDp_GetCoreType(InstancePtr) == XDP_TX);
|
|
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(XDp_GetCoreType(InstancePtr) == XDP_TX);
|
|
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(XDp_GetCoreType(InstancePtr) == XDP_TX);
|
|
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. */
|
|
if (SegPtr != 0) {
|
|
XDp_TxIicWrite(InstancePtr, XDP_SEGPTR_ADDR, 1, &SegPtr);
|
|
}
|
|
|
|
/* 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++;
|
|
|
|
XDp_TxIicWrite(InstancePtr, XDP_SEGPTR_ADDR,
|
|
1, &SegPtr);
|
|
}
|
|
}
|
|
/* Last I2C read. */
|
|
else {
|
|
BytesLeft = 0;
|
|
}
|
|
}
|
|
|
|
/* Reset the segment pointer to 0. */
|
|
if (SegPtr != 0) {
|
|
SegPtr = 0;
|
|
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(XDp_GetCoreType(InstancePtr) == XDP_TX);
|
|
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(XDp_GetCoreType(InstancePtr) == XDP_TX);
|
|
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(XDp_GetCoreType(InstancePtr) == XDP_TX);
|
|
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(XDp_GetCoreType(InstancePtr) == XDP_TX);
|
|
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(XDp_GetCoreType(InstancePtr) == XDP_TX);
|
|
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(XDp_GetCoreType(InstancePtr) == XDP_TX);
|
|
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);
|
|
Xil_AssertVoid(XDp_GetCoreType(InstancePtr) == XDP_TX);
|
|
|
|
/* 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);
|
|
Xil_AssertVoid(XDp_GetCoreType(InstancePtr) == XDP_TX);
|
|
|
|
/* 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);
|
|
Xil_AssertVoid(XDp_GetCoreType(InstancePtr) == XDP_TX);
|
|
|
|
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 sets the PHY polarity on all lanes.
|
|
*
|
|
* @param InstancePtr is a pointer to the XDp instance.
|
|
* @param Polarity is the value to set for the polarity (0 or 1).
|
|
*
|
|
* @return None.
|
|
*
|
|
* @note The individual PHY polarity option will be disabled if set.
|
|
*
|
|
*******************************************************************************/
|
|
void XDp_TxSetPhyPolarityAll(XDp *InstancePtr, u8 Polarity)
|
|
{
|
|
u32 RegVal;
|
|
|
|
/* Verify arguments. */
|
|
Xil_AssertVoid(InstancePtr != NULL);
|
|
Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
|
|
Xil_AssertVoid(XDp_GetCoreType(InstancePtr) == XDP_TX);
|
|
Xil_AssertVoid((Polarity == 0) || (Polarity == 1));
|
|
|
|
/* Preserve current settings. */
|
|
RegVal = XDp_ReadReg(InstancePtr->Config.BaseAddr, XDP_TX_PHY_CONFIG);
|
|
|
|
/* Set the polarity. */
|
|
if (Polarity) {
|
|
RegVal |= XDP_TX_PHY_CONFIG_TX_PHY_POLARITY_MASK;
|
|
}
|
|
else {
|
|
RegVal &= ~XDP_TX_PHY_CONFIG_TX_PHY_POLARITY_MASK;
|
|
}
|
|
|
|
/* Disable individual polarity setting. */
|
|
RegVal &= ~XDP_TX_PHY_CONFIG_TX_PHY_POLARITY_IND_LANE_MASK;
|
|
|
|
/* Write the new settings. */
|
|
XDp_WriteReg(InstancePtr->Config.BaseAddr, XDP_TX_PHY_CONFIG, RegVal);
|
|
}
|
|
|
|
/******************************************************************************/
|
|
/**
|
|
* This function sets the PHY polarity on a specified lane.
|
|
*
|
|
* @param InstancePtr is a pointer to the XDp instance.
|
|
* @param Lane is the lane number (0-3) to set the polarity for.
|
|
* @param Polarity is the value to set for the polarity (0 or 1).
|
|
*
|
|
* @return None.
|
|
*
|
|
* @note If individual lane polarity is used, it is recommended that this
|
|
* function is called for every lane in use.
|
|
*
|
|
*******************************************************************************/
|
|
void XDp_TxSetPhyPolarityLane(XDp *InstancePtr, u8 Lane, u8 Polarity)
|
|
{
|
|
u32 RegVal;
|
|
u32 MaskVal;
|
|
|
|
/* Verify arguments. */
|
|
Xil_AssertVoid(InstancePtr != NULL);
|
|
Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
|
|
Xil_AssertVoid(XDp_GetCoreType(InstancePtr) == XDP_TX);
|
|
Xil_AssertVoid((Lane >= 0) && (Lane <= 3));
|
|
Xil_AssertVoid((Polarity == 0) || (Polarity == 1));
|
|
|
|
/* Preserve current settings. */
|
|
RegVal = XDp_ReadReg(InstancePtr->Config.BaseAddr, XDP_TX_PHY_CONFIG);
|
|
|
|
/* Determine bit mask to use. */
|
|
switch (Lane) {
|
|
case 0:
|
|
MaskVal = XDP_TX_PHY_CONFIG_TX_PHY_POLARITY_LANE0_MASK;
|
|
break;
|
|
case 1:
|
|
MaskVal = XDP_TX_PHY_CONFIG_TX_PHY_POLARITY_LANE1_MASK;
|
|
break;
|
|
case 2:
|
|
MaskVal = XDP_TX_PHY_CONFIG_TX_PHY_POLARITY_LANE2_MASK;
|
|
break;
|
|
case 3:
|
|
MaskVal = XDP_TX_PHY_CONFIG_TX_PHY_POLARITY_LANE3_MASK;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
/* Set the polarity. */
|
|
if (Polarity) {
|
|
RegVal |= MaskVal;
|
|
}
|
|
else {
|
|
RegVal &= ~MaskVal;
|
|
}
|
|
|
|
/* Enable individual polarity setting. */
|
|
RegVal |= XDP_TX_PHY_CONFIG_TX_PHY_POLARITY_IND_LANE_MASK;
|
|
|
|
/* Write the new settings. */
|
|
XDp_WriteReg(InstancePtr->Config.BaseAddr, XDP_TX_PHY_CONFIG, RegVal);
|
|
}
|
|
|
|
/******************************************************************************/
|
|
/**
|
|
* 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);
|
|
Xil_AssertNonvoid(XDp_GetCoreType(InstancePtr) == XDP_RX);
|
|
|
|
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);
|
|
Xil_AssertVoid(XDp_GetCoreType(InstancePtr) == XDP_RX);
|
|
|
|
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);
|
|
Xil_AssertVoid(XDp_GetCoreType(InstancePtr) == XDP_RX);
|
|
|
|
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(XDp_GetCoreType(InstancePtr) == XDP_RX);
|
|
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(XDp_GetCoreType(InstancePtr) == XDP_RX);
|
|
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 enables audio stream packets on the main link.
|
|
*
|
|
* @param InstancePtr is a pointer to the XDp instance.
|
|
*
|
|
* @return None.
|
|
*
|
|
* @note None.
|
|
*
|
|
*******************************************************************************/
|
|
void XDp_RxAudioEn(XDp *InstancePtr)
|
|
{
|
|
/* 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_AUDIO_CONTROL, 0x1);
|
|
}
|
|
|
|
/******************************************************************************/
|
|
/**
|
|
* This function disables audio stream packets on the main link.
|
|
*
|
|
* @param InstancePtr is a pointer to the XDp instance.
|
|
*
|
|
* @return None.
|
|
*
|
|
* @note None.
|
|
*
|
|
*******************************************************************************/
|
|
void XDp_RxAudioDis(XDp *InstancePtr)
|
|
{
|
|
/* 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_AUDIO_CONTROL, 0x0);
|
|
}
|
|
|
|
/******************************************************************************/
|
|
/**
|
|
* This function resets the RX core's reception of audio stream packets on the
|
|
* main link.
|
|
*
|
|
* @param InstancePtr is a pointer to the XDp instance.
|
|
*
|
|
* @return None.
|
|
*
|
|
* @note None.
|
|
*
|
|
*******************************************************************************/
|
|
void XDp_RxAudioReset(XDp *InstancePtr)
|
|
{
|
|
/* Verify arguments. */
|
|
Xil_AssertVoid(InstancePtr != NULL);
|
|
Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
|
|
Xil_AssertVoid(XDp_GetCoreType(InstancePtr) == XDP_RX);
|
|
|
|
XDp_RxAudioDis(InstancePtr);
|
|
XDp_WaitUs(InstancePtr, 1000);
|
|
XDp_RxAudioEn(InstancePtr);
|
|
}
|
|
|
|
/******************************************************************************/
|
|
/**
|
|
* 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. */
|
|
if (InstancePtr->Config.MaxLaneCount > 2) {
|
|
Status = XDp_WaitPhyReady(InstancePtr,
|
|
XDP_RX_PHY_STATUS_PLL_LANE0_1_LOCK_MASK |
|
|
XDP_RX_PHY_STATUS_PLL_LANE2_3_LOCK_MASK);
|
|
}
|
|
else {
|
|
Status = XDp_WaitPhyReady(InstancePtr,
|
|
XDP_RX_PHY_STATUS_PLL_LANE0_1_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. */
|
|
if (InstancePtr->Config.MaxLaneCount > 2) {
|
|
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);
|
|
}
|
|
else {
|
|
Status = XDp_WaitPhyReady(InstancePtr,
|
|
XDP_RX_PHY_STATUS_LANES_0_1_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;
|
|
}
|
|
if ((TrainingState == XDP_TX_TS_ADJUST_LINK_RATE) ||
|
|
(TrainingState == XDP_TX_TS_ADJUST_LANE_COUNT)) {
|
|
Status = XDp_TxSetTrainingPattern(InstancePtr,
|
|
XDP_TX_TRAINING_PATTERN_SET_OFF);
|
|
if (Status != XST_SUCCESS) {
|
|
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]);
|
|
if (Pattern == XDP_TX_TRAINING_PATTERN_SET_OFF) {
|
|
Status = XDp_TxAuxWrite(InstancePtr, XDP_DPCD_TP_SET, 1,
|
|
AuxData);
|
|
}
|
|
else {
|
|
/* 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_GetCoreType(InstancePtr) == 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;
|
|
}
|