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