From 14f491934d36fe379369169555b9f66600594b2b Mon Sep 17 00:00:00 2001 From: Andrei-Liviu Simion Date: Thu, 7 Aug 2014 03:20:20 -0700 Subject: [PATCH] dptx: Multi-stream transport (MST) addition. Main chunk of MST code added. Signed-off-by: Andrei-Liviu Simion --- XilinxProcessorIPLib/drivers/dptx/src/xdptx.h | 115 +- .../drivers/dptx/src/xdptx_mst.c | 1325 +++++++++++++++++ .../drivers/dptx/src/xdptx_spm.c | 41 +- 3 files changed, 1470 insertions(+), 11 deletions(-) create mode 100644 XilinxProcessorIPLib/drivers/dptx/src/xdptx_mst.c diff --git a/XilinxProcessorIPLib/drivers/dptx/src/xdptx.h b/XilinxProcessorIPLib/drivers/dptx/src/xdptx.h index 21c14b47..00e43cc6 100644 --- a/XilinxProcessorIPLib/drivers/dptx/src/xdptx.h +++ b/XilinxProcessorIPLib/drivers/dptx/src/xdptx.h @@ -127,7 +127,7 @@ * either the HPD event handler function or the HPD pulse handler function, * depending on whether a an HPD event on an HPD pulse event occurred. * - * The DisplayPort Tx's XDPTX_INTERRUPT_STATUS register indicates the type of + * The DisplayPort TX's XDPTX_INTERRUPT_STATUS register indicates the type of * interrupt that has occured, and the XDptx_HpdInterruptHandler will use this * information to decide which handler to call. An HPD event is identified if * bit XDPTX_INTERRUPT_STATUS_HPD_EVENT_MASK is set, and an HPD pulse is @@ -182,6 +182,32 @@ #include "xil_assert.h" #include "xil_types.h" +/* Need to reorganize this... */ +/* To add to xstatus.h. */ +#define XST_CRC_ERROR 30L + +#define XDPTX_SBMSG_LINK_ADDRESS 0x01 +#define XDPTX_SBMSG_ENUM_PATH_RESOURCES 0x10 +#define XDPTX_SBMSG_ALLOCATE_PAYLOAD 0x11 +#define XDPTX_SBMSG_CLEAR_PAYLOAD_ID_TABLE 0x14 +#define XDPTX_SBMSG_REMOTE_DPCD_READ 0x20 +#define XDPTX_SBMSG_REMOTE_DPCD_WRITE 0x21 +#define XDPTX_SBMSG_REMOTE_I2C_READ 0x22 + +/* When returning the reason for NACK reply, XST_SBREPLY_NACK is added in order + * to differentiate between the return codes in xstatus.h. */ +#define XST_SBREPLY_NACK 1452L +#define XDPTX_SBREPLY_NACK_WRITE_FAILURE 0x01 +#define XDPTX_SBREPLY_NACK_INVALID_RAD 0x02 +#define XDPTX_SBREPLY_NACK_CRC_FAILURE 0x03 +#define XDPTX_SBREPLY_NACK_BAD_PARAM 0x04 +#define XDPTX_SBREPLY_NACK_DEFER 0x05 +#define XDPTX_SBREPLY_NACK_LINK_FAILURE 0x06 +#define XDPTX_SBREPLY_NACK_NO_RESOURCES 0x07 +#define XDPTX_SBREPLY_NACK_DPCD_FAIL 0x08 +#define XDPTX_SBREPLY_NACK_I2C_NAK 0x09 +#define XDPTX_SBREPLY_NACK_ALLOCATE_FAIL 0x0A + /******************* Macros (Inline Functions) Definitions ********************/ /******************************************************************************/ @@ -462,13 +488,46 @@ typedef struct { use by the video stream. */ u8 SynchronousClockMode; /**< Synchronous clock mode is currently in use by the video stream. */ +} XDptx_MainStreamAttributes; + +typedef struct { + u8 LinkCountTotal; /** The total number of DisplayPort + links from the DisplayPort TX + to the sink device that this MST + stream is targeting.*/ + u8 RelativeAddress[15]; /** The relative address from the + DisplayPort TX to the sink + device that this MST stream is + targeting.*/ u16 MstPbn; /**< Payload bandwidth number used to - allocate bandwidth in MST - mode. */ + allocate bandwidth for the MST + stream. */ u8 MstStreamEnable; /**< In MST mode, enables the corresponding stream for this MSA configuration. */ -} XDptx_MainStreamAttributes; +} XDptx_MstStream; + +typedef struct { + u8 InputPort; + u8 PeerDeviceType; + u8 PortNum; + u8 MsgCapStatus; + u8 DpDevPlugStatus; + + u8 LegacyDevPlugStatus; + u8 DpcdRev; + u32 Guid[4]; + u8 NumSdpStreams; + u8 NumSdpStreamSinks; +} XDptx_SbMsgLinkAddressReplyPortDetail; + +typedef struct { + u8 ReplyType; + u8 RequestId; + u32 Guid[4]; + u8 NumPorts; + XDptx_SbMsgLinkAddressReplyPortDetail PortDetails[16]; +} XDptx_SbMsgLinkAddressReplyDeviceInfo; /******************************************************************************/ /** @@ -512,6 +571,22 @@ typedef void (*XDptx_HpdEventHandler)(void *InstancePtr); *******************************************************************************/ typedef void (*XDptx_HpdPulseHandler)(void *InstancePtr); +typedef struct { + u32 Guid[4]; + u8 RelativeAddress[15]; + u8 DeviceType; + u8 LinkCountTotal; + u8 DpcdRev; + u8 MsgCapStatus; +} XDptx_TopologyNode; + +typedef struct { + u8 NodeTotal; + XDptx_TopologyNode NodeTable[63]; + u8 SinkTotal; + XDptx_TopologyNode *SinkList[63]; +} XDptx_Topology; + /** * The XDptx driver instance data. The user is required to allocate a variable * of this type for every XDptx device in the system. A pointer to a variable of @@ -546,6 +621,11 @@ typedef struct { of attributes. When MST mode is disabled, only MsaConfig[0] is used. */ + XDptx_MstStream MstStreamConfig[4]; /**< Configuration structure + for a multi-stream + transport (MST) + stream. */ + XDptx_Topology Topology; XDptx_TimerHandler UserTimerWaitUs; /**< Custom user function for delay/sleep. */ void *UserTimerPtr; /**< Pointer to a timer instance @@ -616,6 +696,7 @@ void XDptx_CfgMsaUseEdidPreferredTiming(XDptx *InstancePtr, u8 Stream); void XDptx_CfgMsaUseCustom(XDptx *InstancePtr, u8 Stream, XDptx_MainStreamAttributes *MsaConfigCustom, u8 Recalculate); void XDptx_CfgMsaSetBpc(XDptx *InstancePtr, u8 Stream, u8 BitsPerColor); +void XDptx_CfgMsaEnSynchClkMode(XDptx *InstancePtr, u8 Stream, u8 Enable); void XDptx_SetVideoMode(XDptx *InstancePtr, u8 Stream); void XDptx_ClearMsaValues(XDptx *InstancePtr, u8 Stream); void XDptx_SetMsaValues(XDptx *InstancePtr, u8 Stream); @@ -633,4 +714,30 @@ u32 XDptx_SelfTest(XDptx *InstancePtr); /* xdptx_sinit.c: Configuration extraction function.*/ XDptx_Config *XDptx_LookupConfig(u16 DeviceId); +/* xdptx_mst.c: Multi-stream transport (MST) functions. */ +void XDptx_MstCfgModeEnable(XDptx *InstancePtr); +void XDptx_MstCfgModeDisable(XDptx *InstancePtr); +void XDptx_MstCfgStreamEnable(XDptx *InstancePtr, u8 Stream); +void XDptx_MstCfgStreamDisable(XDptx *InstancePtr, u8 Stream); +u8 XDptx_MstStreamIsEnabled(XDptx *InstancePtr, u8 Stream); + +u32 XDptx_MstEnable(XDptx *InstancePtr); +u32 XDptx_MstDisable(XDptx *InstancePtr); +u32 XDptx_AllocatePayloadStreams(XDptx *InstancePtr); +void XDptx_SetStreamSelectFromSinkList(XDptx *InstancePtr, u8 Stream, u8 SinkNum); +void XDptx_SetStreamSinkRad(XDptx *InstancePtr, u8 Stream, u8 LinkCountTotal, u8 *RelativeAddress); +u32 XDptx_ClearPayloadVcIdTable(XDptx *InstancePtr); +void XDptx_FindAccessibleDpDevices(XDptx *InstancePtr, u8 LinkCountTotal, u8 *RelativeAddress); +void XDptx_WriteGuid(XDptx *InstancePtr, u8 LinkCountTotal, u8 *RelativeAddress, u32 Guid[4]); +void XDptx_GetGuid(XDptx *InstancePtr, u8 LinkCountTotal, u8 *RelativeAddress, u32 *Guid); + +/* Sideband messages. */ +u32 XDptx_SendSbMsgRemoteDpcdWrite(XDptx *InstancePtr, u8 LinkCountTotal, u8 *RelativeAddress, u32 DpcdAddress, u8 BytesToWrite, u8 *WriteData); +u32 XDptx_SendSbMsgRemoteDpcdRead(XDptx *InstancePtr, u8 LinkCountTotal, u8 *RelativeAddress, u32 DpcdAddress, u8 BytesToRead, u8 *ReadData); +u32 XDptx_SendSbMsgRemoteIicRead(XDptx *InstancePtr, u8 LinkCountTotal, u8 *RelativeAddress, u32 IicDeviceId, u8 BytesToRead, u8 *ReadData); +u32 XDptx_SendSbMsgLinkAddress(XDptx *InstancePtr, u8 LinkCountTotal, u8 *RelativeAddress, XDptx_SbMsgLinkAddressReplyDeviceInfo *FormatReply); +u32 XDptx_SendSbMsgEnumPathResources(XDptx *InstancePtr, u8 LinkCountTotal, u8 *RelativeAddress, u16 *AvailPbn, u16 *FullPbn); +u32 XDptx_SendSbMsgAllocatePayload(XDptx *InstancePtr, u8 LinkCountTotal, u8 *RelativeAddress, u8 VcId, u16 Pbn); +u32 XDptx_SendSbMsgClearPayloadIdTable(XDptx *InstancePtr); + #endif /* XDPTX_H_ */ diff --git a/XilinxProcessorIPLib/drivers/dptx/src/xdptx_mst.c b/XilinxProcessorIPLib/drivers/dptx/src/xdptx_mst.c new file mode 100644 index 00000000..17a946f7 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/dptx/src/xdptx_mst.c @@ -0,0 +1,1325 @@ +/******************************************************************************* + * + * Copyright (C) 2014 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 xdptx_mst.c + * + *
+ * MODIFICATION HISTORY:
+ *
+ * Ver   Who  Date     Changes
+ * ----- ---- -------- -----------------------------------------------
+ * 1.00a als  08/03/14 Initial release.
+ * 
+ * +*******************************************************************************/ + +/******************************* Include Files ********************************/ + +#include "string.h" +#include "xdptx.h" +#include "xstatus.h" + +typedef struct +{ + u8 LinkCountTotal; + u8 LinkCountRemaining; + u8 RelativeAddress[14]; + u8 BroadcastMsg; + u8 PathMsg; + u8 MsgBodyLength; + u8 StartOfMsgTransaction; + u8 EndOfMsgTransaction; + u8 MsgSequenceNum; + u8 Crc; + + u8 MsgHeaderLength; +} XDptx_SidebandMsgHeader; + +typedef struct +{ + u8 MsgData[62]; + u8 MsgDataLength; + u8 Crc; +} XDptx_SidebandMsgBody; + +typedef struct +{ + XDptx_SidebandMsgHeader Header; + XDptx_SidebandMsgBody Body; +} XDptx_SidebandMsg; + +typedef struct +{ + u8 Length; + u8 Data[256]; +} XDptx_SidebandReply; + +static u32 XDptx_SendActTrigger(XDptx *InstancePtr); +static u32 XDptx_AllocatePayloadVcIdTable(XDptx *InstancePtr, u8 LinkCountTotal, + u8 *RelativeAddress, u8 VcId, u16 Pbn, u8 Ts); +static u32 XDptx_GetFirstAvailableTs(XDptx *InstancePtr, u8 *FirstTs); +static void XDptx_AddBranchToList(XDptx_Topology *Topology, + XDptx_SbMsgLinkAddressReplyDeviceInfo *DeviceInfo, + u8 LinkCountTotal, u8 *RelativeAddress); +static void XDptx_AddSinkToList(XDptx_Topology *Topology, + XDptx_SbMsgLinkAddressReplyPortDetail *SinkDevice, + u8 LinkCountTotal, u8 *RelativeAddress); +static void XDptx_IssueGuid(XDptx *InstancePtr, u8 LinkCountTotal, + u8 *RelativeAddress, XDptx_Topology *Topology, + u32 *Guid); +static u32 XDptx_SendSbMsg(XDptx *InstancePtr, XDptx_SidebandMsg *Msg); +static u32 XDptx_WaitSbReply(XDptx *InstancePtr); +static void XDptx_GetDeviceInfoFromSbMsgLinkAddress( + XDptx_SidebandReply *SbReply, + XDptx_SbMsgLinkAddressReplyDeviceInfo *FormatReply); +static u8 XDptx_CrcCalculate(const u8 *Data, u32 NumberOfBits, u8 Polynomial); +static u8 XDptx_Crc4CalculateHeader(XDptx_SidebandMsgHeader *Header); +static u8 XDptx_Crc8CalculateBody(XDptx_SidebandMsgBody *Body); +static u32 XDptx_Transaction2MsgFormat(u8 *Transaction, XDptx_SidebandMsg *Msg); +static u32 XDptx_ReceiveSbMsg(XDptx *InstancePtr, XDptx_SidebandReply *SbReply); + +u32 GuidTable[11][4] = { + {0x12341234, 0x43214321, 0x56785678, 0x87658765}, + {0xDEADBEEF, 0xBEEFDEAD, 0x10011001, 0xDADADADA}, + {0xDABADABA, 0x10011001, 0xBADABADA, 0x5AD5AD5A}, + {0x12345678, 0x43214321, 0xABCDEF98, 0x87658765}, + {0x12141214, 0x41214121, 0x56785678, 0x87658765}, + {0xD1CDB11F, 0xB11FD1CD, 0xFEBCDA90, 0xDCDCDCDC}, + {0xDCBCDCBC, 0xE000E000, 0xBCDCBCDC, 0x5CD5CD5C}, + {0x11111111, 0x11111111, 0x11111111, 0x11111111}, + {0x22222222, 0x22222222, 0x22222222, 0x22222222}, + {0x33333333, 0x33333333, 0x33333333, 0x33333333}, + {0x12145678, 0x41214121, 0xCBCD1F98, 0x87658765} +}; + +/**************************** Function Definitions ****************************/ + +void XDptx_MstCfgModeEnable(XDptx *InstancePtr) +{ + InstancePtr->MstEnable = 1; +} + +void XDptx_MstCfgModeDisable(XDptx *InstancePtr) +{ + InstancePtr->MstEnable = 0; +} + +void XDptx_MstCfgStreamEnable(XDptx *InstancePtr, u8 Stream) +{ + InstancePtr->MstStreamConfig[Stream - 1].MstStreamEnable = 1; +} + +void XDptx_MstCfgStreamDisable(XDptx *InstancePtr, u8 Stream) +{ + InstancePtr->MstStreamConfig[Stream - 1].MstStreamEnable = 0; +} + +u8 XDptx_MstStreamIsEnabled(XDptx *InstancePtr, u8 Stream) +{ + return InstancePtr->MstStreamConfig[Stream - 1].MstStreamEnable; +} + +u32 XDptx_MstEnable(XDptx *InstancePtr) +{ + u32 Status; + u8 AuxData; + + /* HPD long pulse used for upstream notification. */ + AuxData = 0; + Status = XDptx_AuxWrite(InstancePtr, XDPTX_DPCD_BRANCH_DEVICE_CTRL, 1, + &AuxData); + if (Status != XST_SUCCESS) { + /* The AUX write transaction failed. */ + return Status; + } + + /* Enable MST in the immediate branch device and tell it that its + * upstream device is a source (the DisplayPort TX). */ + AuxData = XDPTX_DPCD_UP_IS_SRC_MASK | XDPTX_DPCD_UP_REQ_EN_MASK | + XDPTX_DPCD_MST_EN_MASK; + Status = XDptx_AuxWrite(InstancePtr, XDPTX_DPCD_MSTM_CTRL, 1, &AuxData); + if (Status != XST_SUCCESS) { + /* The AUX write transaction failed. */ + return Status; + } + + /* Enable MST in the DisplayPort TX. */ + XDptx_WriteReg(InstancePtr->Config.BaseAddr, XDPTX_TX_MST_CONFIG, + XDPTX_TX_MST_CONFIG_MST_EN_MASK); + + return XST_SUCCESS; +} + +u32 XDptx_MstDisable(XDptx *InstancePtr) +{ + u32 Status; + u8 AuxData; + + /* Disable MST mode in the immediate branch device. */ + AuxData = 0; + Status = XDptx_AuxWrite(InstancePtr, XDPTX_DPCD_MSTM_CTRL, 1, &AuxData); + if (Status != XST_SUCCESS) { + /* The AUX write transaction failed. */ + return Status; + } + + /* Disable MST mode in the DisplayPort TX. */ + XDptx_WriteReg(InstancePtr->Config.BaseAddr, XDPTX_TX_MST_CONFIG, 0x0); + + return XST_SUCCESS; +} + +void XDptx_SetStreamSelectFromSinkList(XDptx *InstancePtr, u8 Stream, u8 + SinkNum) +{ + u8 Index; + XDptx_MstStream *MstStream = &InstancePtr->MstStreamConfig[Stream]; + XDptx_Topology *Topology = &InstancePtr->Topology; + + /* Check sink count. */ + + MstStream->LinkCountTotal = Topology->SinkList[SinkNum]->LinkCountTotal; + for (Index = 0; Index < MstStream->LinkCountTotal - 1; Index++) { + MstStream->RelativeAddress[Index] = + Topology->SinkList[SinkNum]->RelativeAddress[Index]; + } +} + +void XDptx_SetStreamSinkRad(XDptx *InstancePtr, u8 Stream, u8 LinkCountTotal, + u8 *RelativeAddress) +{ + u8 Index; + XDptx_MstStream *MstStream = &InstancePtr->MstStreamConfig[Stream]; + + MstStream->LinkCountTotal = LinkCountTotal; + for (Index = 0; Index < MstStream->LinkCountTotal - 1; Index++) { + MstStream->RelativeAddress[Index] = RelativeAddress[Index]; + } +} + +u32 XDptx_AllocatePayloadStreams(XDptx *InstancePtr) +{ + u32 Status; + u8 StreamIndex; + + Status = XDptx_ClearPayloadVcIdTable(InstancePtr); + if (Status != XST_SUCCESS) { + /* Either a AUX read or write transaction failed trying to clear + * the payload ID table or read the update status, or waiting + * for an indication that the payload ID table was updated + * timed out. */ + return Status; + } + + /* Allocate the payload table for each stream in both the DisplayPort TX + * and RX device. */ + for (StreamIndex = 0; StreamIndex < 4; StreamIndex++) { + if (XDptx_MstStreamIsEnabled(InstancePtr, StreamIndex + 1)) { + Status = XDptx_AllocatePayloadVcIdTable(InstancePtr, + InstancePtr->MstStreamConfig[StreamIndex].LinkCountTotal, + InstancePtr->MstStreamConfig[StreamIndex].RelativeAddress, + StreamIndex + 1, + InstancePtr->MstStreamConfig[StreamIndex].MstPbn, + InstancePtr->MsaConfig[StreamIndex].TransferUnitSize); + if (Status != XST_SUCCESS) { + return Status; + } + } + } + + /* Generate an ACT event. */ + Status = XDptx_SendActTrigger(InstancePtr); + if (Status != XST_SUCCESS) { + return Status; + } + + /* Send ALLOCATE_PAYLOAD request. */ + for (StreamIndex = 0; StreamIndex < 4; StreamIndex++) { + if (XDptx_MstStreamIsEnabled(InstancePtr, StreamIndex + 1)) { + Status = XDptx_SendSbMsgAllocatePayload(InstancePtr, + InstancePtr->MstStreamConfig[StreamIndex].LinkCountTotal, + InstancePtr->MstStreamConfig[StreamIndex].RelativeAddress, + StreamIndex + 1, + InstancePtr->MstStreamConfig[StreamIndex].MstPbn); + if (Status != XST_SUCCESS) { + return Status; + } + } + } + + return XST_SUCCESS; +} + +static u32 XDptx_AllocatePayloadVcIdTable(XDptx *InstancePtr, u8 LinkCountTotal, + u8 *RelativeAddress, u8 VcId, u16 Pbn, u8 Ts) +{ + u32 Status; + u8 AuxData[3]; + u8 Index; + u8 StartTs; + + /* Find next available timeslot. */ + Status = XDptx_GetFirstAvailableTs(InstancePtr, &StartTs); + if (Status != XST_SUCCESS) { + /* The AUX read transaction failed. */ + return Status; + } + + /* Check that there are enough time slots available. */ + if (((63 - StartTs + 1) < Ts) || + (StartTs == 0)) { + /* Clearing the payload ID table is required to re-allocate + * streams. */ + return XST_BUFFER_TOO_SMALL; + } + + /* Allocate timeslots in TX. */ + for (Index = StartTs; Index < (StartTs + Ts); Index++) { + XDptx_WriteReg(InstancePtr->Config.BaseAddr, + (XDPTX_VC_PAYLOAD_BUFFER_ADDR + (4 * Index)), VcId); + } + + XDptx_WaitUs(InstancePtr, 1000); + + /* Allocate timeslots in sink. */ + + /* Clear the VCP table update bit. */ + AuxData[0] = 0x01; + Status = XDptx_AuxWrite(InstancePtr, + XDPTX_DPCD_PAYLOAD_TABLE_UPDATE_STATUS, 1, AuxData); + if (Status != XST_SUCCESS) { + /* The AUX write transaction failed. */ + return Status; + } + + /* Allocate VC with VcId. */ + AuxData[0] = VcId; + /* Start timeslot for VC with VcId. */ + AuxData[1] = StartTs; + /* Timeslot count for VC with VcId. */ + AuxData[2] = Ts; + Status = XDptx_AuxWrite(InstancePtr, XDPTX_DPCD_PAYLOAD_ALLOCATE_SET, 3, + AuxData); + if (Status != XST_SUCCESS) { + /* The AUX write transaction failed. */ + return Status; + } + + /* Wait for the VC table to be updated. */ + do { + Status = XDptx_AuxRead(InstancePtr, + XDPTX_DPCD_PAYLOAD_TABLE_UPDATE_STATUS, 1, AuxData); + if (Status != XST_SUCCESS) { + /* The AUX read transaction failed. */ + return Status; + } + } while ((AuxData[0] & 0x01) != 0x01); + + XDptx_WaitUs(InstancePtr, 1000); + + return XST_SUCCESS; +} + +static u32 XDptx_SendActTrigger(XDptx *InstancePtr) +{ + u32 Status; + u8 AuxData[1]; + + XDptx_WriteReg(InstancePtr->Config.BaseAddr, XDPTX_TX_MST_CONFIG, 0x3); + + do { + Status = XDptx_AuxRead(InstancePtr, + XDPTX_DPCD_PAYLOAD_TABLE_UPDATE_STATUS, 1, AuxData); + if (Status != XST_SUCCESS) { + /* The AUX read transaction failed. */ + return Status; + } + } while ((AuxData[0] & 0x02) != 0x02); + + return XST_SUCCESS; +} + +static u32 XDptx_GetFirstAvailableTs(XDptx *InstancePtr, u8 *FirstTs) +{ + u32 Status; + u8 Index; + u8 AuxData[64]; + + Status = XDptx_AuxRead(InstancePtr, XDPTX_DPCD_VC_PAYLOAD_ID_SLOT(1), + 64, AuxData); + if (Status != XST_SUCCESS) { + /* The AUX read transaction failed. */ + return Status; + } + + for (Index = 0; Index < 64; Index++) { + if (AuxData[Index] == 0) { + *FirstTs = (Index + 1); + return XST_SUCCESS; + } + } + + /* No free time slots available. */ + *FirstTs = 0; + return XST_SUCCESS; +} + +u32 XDptx_ClearPayloadVcIdTable(XDptx *InstancePtr) +{ + u32 Status; + u8 AuxData[3]; + u8 Index; + + /* Clear the payload table in the transmitter. */ + for (Index = 0; Index < 63; Index++) { + XDptx_WriteReg(InstancePtr->Config.BaseAddr, + (XDPTX_VC_PAYLOAD_BUFFER_ADDR + (4 * Index)), 0); + } + + /* Clear the payload table in the immediate downstream branch device. */ + + /* Clear the VCP table update bit. */ + AuxData[0] = 0x01; + Status = XDptx_AuxWrite(InstancePtr, + XDPTX_DPCD_PAYLOAD_TABLE_UPDATE_STATUS, 1, AuxData); + if (Status != XST_SUCCESS) { + /* The AUX write transaction failed. */ + return Status; + } + + /* Allocate VC with VcId. */ + AuxData[0] = 0; + /* Start timeslot for VC with VcId. */ + AuxData[1] = 0; + /* Timeslot count for VC with VcId. */ + AuxData[2] = 0x3F; + Status = XDptx_AuxWrite(InstancePtr, XDPTX_DPCD_PAYLOAD_ALLOCATE_SET, 3, + AuxData); + if (Status != XST_SUCCESS) { + /* The AUX write transaction failed. */ + return Status; + } + + /* Wait for the VC table to be updated. */ + do { + Status = XDptx_AuxRead(InstancePtr, + XDPTX_DPCD_PAYLOAD_TABLE_UPDATE_STATUS, 1, AuxData); + if (Status != XST_SUCCESS) { + /* The AUX read transaction failed. */ + return Status; + } + } while ((AuxData[0] & 0x01) != 0x01); + + Status = XDptx_SendActTrigger(InstancePtr); + if (Status != XST_SUCCESS) { + return Status; + } + + /* Send CLEAR_PAYLOAD_ID_TABLE request. */ + Status = XDptx_SendSbMsgClearPayloadIdTable(InstancePtr); + + return Status; +} + +void XDptx_FindAccessibleDpDevices(XDptx *InstancePtr, u8 LinkCountTotal, + u8 *RelativeAddress) +{ + u8 Index; + u8 RadIndex; + XDptx_SbMsgLinkAddressReplyDeviceInfo DeviceInfo; + XDptx_Topology *Topology = &InstancePtr->Topology; + + XDptx_SendSbMsgLinkAddress(InstancePtr, LinkCountTotal, RelativeAddress, + &DeviceInfo); + + /* Write GUID to the branch device if it doesn't already have one. */ + XDptx_IssueGuid(InstancePtr, LinkCountTotal, RelativeAddress, Topology, + DeviceInfo.Guid); + + /* Add the branch device to the topology table. */ + XDptx_AddBranchToList(Topology, &DeviceInfo, LinkCountTotal, + RelativeAddress); + + /* Downstream devices will be an extra link away from the source than + * this branch device. */ + LinkCountTotal++; + + /* Any downstream device downstream device will have the RAD of the + * current branch device appended with the port number. */ + u8 DownstreamRelativeAddress[LinkCountTotal - 1]; + /* Copy the branch device's RAD. */ + for (RadIndex = 0; RadIndex < (LinkCountTotal - 2); RadIndex++) { + DownstreamRelativeAddress[RadIndex] = RelativeAddress[RadIndex]; + } + + for (Index = 0; Index < DeviceInfo.NumPorts; Index++) { + if (DeviceInfo.PortDetails[Index].InputPort == 0) { + /* Append the port number to the RAD of the branch + * device. */ + DownstreamRelativeAddress[RadIndex] = + DeviceInfo.PortDetails[Index].PortNum; + + if (DeviceInfo.PortDetails[Index].PeerDeviceType == + 0x2) { + /* Found a branch device; recurse the algorithm + * to see what DisplayPort devices are connected + * to it with the appended RAD. */ + XDptx_FindAccessibleDpDevices(InstancePtr, + LinkCountTotal, + DownstreamRelativeAddress); + } + else if (DeviceInfo.PortDetails[Index].DpDevPlugStatus + == 1) { + if ((DeviceInfo.PortDetails[Index].MsgCapStatus + == 1) && (DeviceInfo.PortDetails[Index].DpcdRev >= 0x12)) { + /* Write GUID to the branch device if it + * doesn't already have one. */ + XDptx_IssueGuid(InstancePtr, + LinkCountTotal, RelativeAddress, + Topology, DeviceInfo.Guid); + } + + XDptx_AddSinkToList(Topology, + &DeviceInfo.PortDetails[Index], + LinkCountTotal, + DownstreamRelativeAddress); + } + } + } +} + +void XDptx_GetGuid(XDptx *InstancePtr, u8 LinkCountTotal, u8 *RelativeAddress, + u32 *Guid) +{ + u8 Index; + u8 Data[30]; + + if (LinkCountTotal == 1) { + XDptx_AuxRead(InstancePtr, 0x30, 16, Data); + + memset(Guid, 0, 16); + for (Index = 0; Index < 16; Index++) { + Guid[Index / 4] <<= 8; + Guid[Index / 4] |= Data[Index]; + } + } + else { + XDptx_SendSbMsgRemoteDpcdRead(InstancePtr, LinkCountTotal, + RelativeAddress, 0x30, 16, Data); + + memset(Guid, 0, 16); + for (Index = 0; Index < 16; Index++) { + Guid[Index / 4] <<= 8; + Guid[Index / 4] |= Data[Index + 3]; + } + } +} + +void XDptx_WriteGuid(XDptx *InstancePtr, u8 LinkCountTotal, u8 *RelativeAddress, + u32 Guid[4]) +{ + u8 AuxData[16]; + u8 Index; + + memset(AuxData, 0, 16); + for (Index = 0; Index < 16; Index++) { + AuxData[Index] = (Guid[Index / 4] >> ((3 - (Index % 4)) * 8)) & + 0xFF; + } + + if (LinkCountTotal == 1) { + XDptx_AuxWrite(InstancePtr, XDPTX_DPCD_GUID, 16, AuxData); + } + else { + XDptx_SendSbMsgRemoteDpcdWrite(InstancePtr, LinkCountTotal, + RelativeAddress, XDPTX_DPCD_GUID, 16, AuxData); + } +} + +u32 XDptx_SendSbMsgRemoteDpcdWrite(XDptx *InstancePtr, u8 LinkCountTotal, + u8 *RelativeAddress, u32 DpcdAddress, u8 BytesToWrite, u8 *WriteData) +{ + u32 Status; + XDptx_SidebandMsg Msg; + XDptx_SidebandReply SbMsgReply; + u8 Index; + + /* Prepare the sideband message header. */ + Msg.Header.LinkCountTotal = LinkCountTotal - 1; + for (Index = 0; Index < (Msg.Header.LinkCountTotal - 1); Index++) { + Msg.Header.RelativeAddress[Index] = RelativeAddress[Index]; + } + Msg.Header.LinkCountRemaining = Msg.Header.LinkCountTotal - 1; + Msg.Header.BroadcastMsg = 0; + Msg.Header.PathMsg = 0; + Msg.Header.MsgBodyLength = 6 + BytesToWrite; + Msg.Header.StartOfMsgTransaction = 1; + Msg.Header.EndOfMsgTransaction = 1; + Msg.Header.MsgSequenceNum = 0; + Msg.Header.Crc = XDptx_Crc4CalculateHeader(&Msg.Header); + + /* Prepare the sideband message body. */ + Msg.Body.MsgData[0] = XDPTX_SBMSG_REMOTE_DPCD_WRITE; + Msg.Body.MsgData[1] = (RelativeAddress[Msg.Header.LinkCountTotal - 1] << + 4) | (DpcdAddress >> 16); + Msg.Body.MsgData[2] = (DpcdAddress & 0x0000FF00) >> 8; + Msg.Body.MsgData[3] = (DpcdAddress & 0x000000FF); + Msg.Body.MsgData[4] = BytesToWrite; + for (Index = 0; Index < BytesToWrite; Index++) { + Msg.Body.MsgData[5 + Index] = WriteData[Index]; + } + Msg.Body.MsgDataLength = Msg.Header.MsgBodyLength - 1; + Msg.Body.Crc = XDptx_Crc8CalculateBody(&Msg.Body); + + /* Submit the REMOTE_DPCD_WRITE transaction message request. */ + Status = XDptx_SendSbMsg(InstancePtr, &Msg); + if (Status != XST_SUCCESS) { + /* The AUX write transaction used to send the sideband message + * failed. */ + return Status; + } + Status = XDptx_ReceiveSbMsg(InstancePtr, &SbMsgReply); + + return Status; +} + +u32 XDptx_SendSbMsgRemoteDpcdRead(XDptx *InstancePtr, u8 LinkCountTotal, + u8 *RelativeAddress, u32 DpcdAddress, u8 BytesToRead, u8 *ReadData) +{ + u32 Status; + XDptx_SidebandMsg Msg; + XDptx_SidebandReply SbMsgReply; + u8 Index; + + /* Prepare the sideband message header. */ + Msg.Header.LinkCountTotal = LinkCountTotal - 1; + for (Index = 0; Index < (Msg.Header.LinkCountTotal - 1); Index++) { + Msg.Header.RelativeAddress[Index] = RelativeAddress[Index]; + } + Msg.Header.LinkCountRemaining = Msg.Header.LinkCountTotal - 1; + Msg.Header.BroadcastMsg = 0; + Msg.Header.PathMsg = 0; + Msg.Header.MsgBodyLength = 6; + Msg.Header.StartOfMsgTransaction = 1; + Msg.Header.EndOfMsgTransaction = 1; + Msg.Header.MsgSequenceNum = 0; + Msg.Header.Crc = XDptx_Crc4CalculateHeader(&Msg.Header); + + /* Prepare the sideband message body. */ + Msg.Body.MsgData[0] = XDPTX_SBMSG_REMOTE_DPCD_READ; + Msg.Body.MsgData[1] = (RelativeAddress[Msg.Header.LinkCountTotal - 1] << + 4) | (DpcdAddress >> 16); + Msg.Body.MsgData[2] = (DpcdAddress & 0x0000FF00) >> 8; + Msg.Body.MsgData[3] = (DpcdAddress & 0x000000FF); + Msg.Body.MsgData[4] = BytesToRead; + Msg.Body.MsgDataLength = Msg.Header.MsgBodyLength - 1; + Msg.Body.Crc = XDptx_Crc8CalculateBody(&Msg.Body); + + /* Submit the REMOTE_DPCD_READ transaction message request. */ + Status = XDptx_SendSbMsg(InstancePtr, &Msg); + if (Status != XST_SUCCESS) { + /* The AUX write transaction used to send the sideband message + * failed. */ + return Status; + } + Status = XDptx_ReceiveSbMsg(InstancePtr, &SbMsgReply); + if (Status != XST_SUCCESS) { + /* Either the reply indicates a NACK, an AUX read or write + * transaction failed, there was a time out waiting for a reply, + * or a CRC check failed. */ + return Status; + } + + /* Collect body data into an array. */ + for (Index = 0; Index < SbMsgReply.Length; Index++) { + ReadData[Index] = SbMsgReply.Data[Index]; + } + + return XST_SUCCESS; +} + +u32 XDptx_SendSbMsgRemoteIicRead(XDptx *InstancePtr, u8 LinkCountTotal, + u8 *RelativeAddress, u32 IicDeviceId, u8 BytesToRead, u8 *ReadData) +{ + u32 Status; + XDptx_SidebandMsg Msg; + XDptx_SidebandReply SbMsgReply; + u8 Index; + + /* Prepare the sideband message header. */ + Msg.Header.LinkCountTotal = LinkCountTotal - 1; + for (Index = 0; Index < (Msg.Header.LinkCountTotal - 1); Index++) { + Msg.Header.RelativeAddress[Index] = RelativeAddress[Index]; + } + Msg.Header.LinkCountRemaining = Msg.Header.LinkCountTotal - 1; + Msg.Header.BroadcastMsg = 0; + Msg.Header.PathMsg = 0; + Msg.Header.MsgBodyLength = 9; + Msg.Header.StartOfMsgTransaction = 1; + Msg.Header.EndOfMsgTransaction = 1; + Msg.Header.MsgSequenceNum = 0; + Msg.Header.Crc = XDptx_Crc4CalculateHeader(&Msg.Header); + + /* Prepare the sideband message body. */ + Msg.Body.MsgData[0] = XDPTX_SBMSG_REMOTE_I2C_READ; + Msg.Body.MsgData[1] = (RelativeAddress[Msg.Header.LinkCountTotal - 1] << + 4) | 1; + Msg.Body.MsgData[2] = IicDeviceId; /* Write I2C device ID. */ + Msg.Body.MsgData[3] = 1; /* Number of bytes to write. */ + Msg.Body.MsgData[4] = 0; /* Write byte[0]. */ + Msg.Body.MsgData[5] = (0 << 4) | 0; + Msg.Body.MsgData[6] = IicDeviceId; /* Read I2C device ID. */ + Msg.Body.MsgData[7] = BytesToRead; + Msg.Body.MsgDataLength = Msg.Header.MsgBodyLength - 1; + Msg.Body.Crc = XDptx_Crc8CalculateBody(&Msg.Body); + + /* Submit the REMOTE_I2C_READ transaction message request. */ + Status = XDptx_SendSbMsg(InstancePtr, &Msg); + if (Status != XST_SUCCESS) { + /* The AUX write transaction used to send the sideband message + * failed. */ + return Status; + } + Status = XDptx_ReceiveSbMsg(InstancePtr, &SbMsgReply); + if (Status != XST_SUCCESS) { + /* Either the reply indicates a NACK, an AUX read or write + * transaction failed, there was a time out waiting for a reply, + * or a CRC check failed. */ + return Status; + } + + /* Collect body data into an array. */ + for (Index = 0; Index < SbMsgReply.Length; Index++) { + ReadData[Index] = SbMsgReply.Data[Index]; + } + + return Status; +} + +u32 XDptx_SendSbMsgLinkAddress(XDptx *InstancePtr, u8 LinkCountTotal, + u8 *RelativeAddress, XDptx_SbMsgLinkAddressReplyDeviceInfo *DeviceInfo) +{ + u32 Status; + XDptx_SidebandMsg Msg; + XDptx_SidebandReply SbMsgReply; + u8 Index; + + /* Prepare the sideband message header. */ + Msg.Header.LinkCountTotal = LinkCountTotal; + for (Index = 0; Index < (LinkCountTotal - 1); Index++) { + Msg.Header.RelativeAddress[Index] = RelativeAddress[Index]; + } + Msg.Header.LinkCountRemaining = Msg.Header.LinkCountTotal - 1; + Msg.Header.BroadcastMsg = 0; + Msg.Header.PathMsg = 0; + Msg.Header.MsgBodyLength = 2; + Msg.Header.StartOfMsgTransaction = 1; + Msg.Header.EndOfMsgTransaction = 1; + Msg.Header.MsgSequenceNum = 0; + Msg.Header.Crc = XDptx_Crc4CalculateHeader(&Msg.Header); + + /* Prepare the sideband message body. */ + Msg.Body.MsgData[0] = XDPTX_SBMSG_LINK_ADDRESS; + Msg.Body.MsgDataLength = Msg.Header.MsgBodyLength - 1; + Msg.Body.Crc = XDptx_Crc8CalculateBody(&Msg.Body); + + /* Submit the LINK_ADDRESS transaction message request. */ + Status = XDptx_SendSbMsg(InstancePtr, &Msg); + if (Status != XST_SUCCESS) { + /* The AUX write transaction used to send the sideband message + * failed. */ + return Status; + } + + XDptx_ReceiveSbMsg(InstancePtr, &SbMsgReply); + XDptx_GetDeviceInfoFromSbMsgLinkAddress(&SbMsgReply, DeviceInfo); + + return Status; +} + +u32 XDptx_SendSbMsgEnumPathResources(XDptx *InstancePtr, u8 LinkCountTotal, + u8 *RelativeAddress, u16 *AvailPbn, u16 *FullPbn) +{ + u32 Status; + XDptx_SidebandMsg Msg; + XDptx_SidebandReply SbMsgReply; + u8 Index; + + /* Prepare the sideband message header. */ + Msg.Header.LinkCountTotal = LinkCountTotal - 1; + for (Index = 0; Index < (LinkCountTotal - 1); Index++) { + Msg.Header.RelativeAddress[Index] = RelativeAddress[Index]; + } + Msg.Header.LinkCountRemaining = Msg.Header.LinkCountTotal - 1; + Msg.Header.BroadcastMsg = 0; + Msg.Header.PathMsg = 1; + Msg.Header.MsgBodyLength = 3; + Msg.Header.StartOfMsgTransaction = 1; + Msg.Header.EndOfMsgTransaction = 1; + Msg.Header.MsgSequenceNum = 0; + Msg.Header.Crc = XDptx_Crc4CalculateHeader(&Msg.Header); + + /* Prepare the sideband message body. */ + Msg.Body.MsgData[0] = XDPTX_SBMSG_ENUM_PATH_RESOURCES; + Msg.Body.MsgData[1] = (RelativeAddress[Msg.Header.LinkCountTotal - 1] << + 4); + Msg.Body.MsgDataLength = Msg.Header.MsgBodyLength - 1; + Msg.Body.Crc = XDptx_Crc8CalculateBody(&Msg.Body); + + /* Submit the LINK_ADDRESS transaction message request. */ + Status = XDptx_SendSbMsg(InstancePtr, &Msg); + if (Status != XST_SUCCESS) { + /* The AUX write transaction used to send the sideband message + * failed. */ + return Status; + } + Status = XDptx_ReceiveSbMsg(InstancePtr, &SbMsgReply); + if (Status != XST_SUCCESS) { + /* Either the reply indicates a NACK, an AUX read or write + * transaction failed, there was a time out waiting for a reply, + * or a CRC check failed. */ + return Status; + } + + *AvailPbn = ((SbMsgReply.Data[4] << 8) | SbMsgReply.Data[5]); + *FullPbn = ((SbMsgReply.Data[2] << 8) | SbMsgReply.Data[3]); + + return XST_SUCCESS; +} + +u32 XDptx_SendSbMsgAllocatePayload(XDptx *InstancePtr, u8 LinkCountTotal, + u8 *RelativeAddress, u8 VcId, u16 Pbn) +{ + u32 Status; + XDptx_SidebandMsg Msg; + XDptx_SidebandReply SbMsgReply; + u8 Index; + + /* Prepare the sideband message header. */ + Msg.Header.LinkCountTotal = LinkCountTotal - 1; + for (Index = 0; Index < (LinkCountTotal - 1); Index++) { + Msg.Header.RelativeAddress[Index] = RelativeAddress[Index]; + } + Msg.Header.LinkCountRemaining = Msg.Header.LinkCountTotal - 1; + Msg.Header.BroadcastMsg = 0; + Msg.Header.PathMsg = 1; + Msg.Header.MsgBodyLength = 6; + Msg.Header.StartOfMsgTransaction = 1; + Msg.Header.EndOfMsgTransaction = 1; + Msg.Header.MsgSequenceNum = 0; + Msg.Header.Crc = XDptx_Crc4CalculateHeader(&Msg.Header); + + /* Prepare the sideband message body. */ + Msg.Body.MsgData[0] = XDPTX_SBMSG_ALLOCATE_PAYLOAD; + Msg.Body.MsgData[1] = (RelativeAddress[Msg.Header.LinkCountTotal - 1] << + 4); + Msg.Body.MsgData[2] = VcId; + Msg.Body.MsgData[3] = (Pbn >> 8); + Msg.Body.MsgData[4] = (Pbn & 0xFFFFFFFF); + Msg.Body.MsgDataLength = Msg.Header.MsgBodyLength - 1; + Msg.Body.Crc = XDptx_Crc8CalculateBody(&Msg.Body); + + /* Submit the ALLOCATE_PAYLOAD transaction message request. */ + Status = XDptx_SendSbMsg(InstancePtr, &Msg); + if (Status != XST_SUCCESS) { + /* The AUX write transaction used to send the sideband message + * failed. */ + return Status; + } + Status = XDptx_ReceiveSbMsg(InstancePtr, &SbMsgReply); + + return Status; +} + +u32 XDptx_SendSbMsgClearPayloadIdTable(XDptx *InstancePtr) +{ + u32 Status; + XDptx_SidebandMsg Msg; + XDptx_SidebandReply SbMsgReply; + + /* Prepare the sideband message header. */ + Msg.Header.LinkCountTotal = 1; + Msg.Header.LinkCountRemaining = 6; + Msg.Header.BroadcastMsg = 1; + Msg.Header.PathMsg = 1; + Msg.Header.MsgBodyLength = 2; + Msg.Header.StartOfMsgTransaction = 1; + Msg.Header.EndOfMsgTransaction = 1; + Msg.Header.MsgSequenceNum = 0; + Msg.Header.Crc = XDptx_Crc4CalculateHeader(&Msg.Header); + + /* Prepare the sideband message body. */ + Msg.Body.MsgData[0] = XDPTX_SBMSG_CLEAR_PAYLOAD_ID_TABLE; + Msg.Body.MsgDataLength = Msg.Header.MsgBodyLength - 1; + Msg.Body.Crc = XDptx_Crc8CalculateBody(&Msg.Body); + + /* Submit the CLEAR_PAYLOAD_ID_TABLE transaction message request. */ + Status = XDptx_SendSbMsg(InstancePtr, &Msg); + if (Status != XST_SUCCESS) { + /* The AUX write transaction used to send the sideband message + * failed. */ + return Status; + } + Status = XDptx_ReceiveSbMsg(InstancePtr, &SbMsgReply); + + return Status; +} + +static void XDptx_IssueGuid(XDptx *InstancePtr, u8 LinkCountTotal, + u8 *RelativeAddress, XDptx_Topology *Topology, u32 *Guid) +{ + XDptx_GetGuid(InstancePtr, LinkCountTotal, RelativeAddress, Guid); + if ((Guid[0] == 0) && (Guid[1] == 0) && (Guid[2] == 0) && + (Guid[3] == 0)) { + XDptx_WriteGuid(InstancePtr, LinkCountTotal, RelativeAddress, + GuidTable[Topology->NodeTotal]); + + XDptx_GetGuid(InstancePtr, LinkCountTotal, RelativeAddress, + Guid); + } +} + +static void XDptx_AddBranchToList(XDptx_Topology *Topology, + XDptx_SbMsgLinkAddressReplyDeviceInfo *DeviceInfo, + u8 LinkCountTotal, u8 *RelativeAddress) +{ + u8 Index; + + for (Index = 0; Index < 4; Index++) { + Topology->NodeTable[Topology->NodeTotal].Guid[Index] = + DeviceInfo->Guid[Index]; + } + for (Index = 0; Index < (LinkCountTotal - 1); Index++) { + Topology->NodeTable[Topology->NodeTotal].RelativeAddress[Index] + = RelativeAddress[Index]; + } + Topology->NodeTable[Topology->NodeTotal].DeviceType = 0x02; + Topology->NodeTable[Topology->NodeTotal].LinkCountTotal = + LinkCountTotal; + Topology->NodeTable[Topology->NodeTotal].DpcdRev = 0x12; + Topology->NodeTable[Topology->NodeTotal].MsgCapStatus = 1; + + Topology->NodeTotal++; +} + +static void XDptx_AddSinkToList(XDptx_Topology *Topology, + XDptx_SbMsgLinkAddressReplyPortDetail *SinkDevice, + u8 LinkCountTotal, u8 *RelativeAddress) +{ + u8 Index; + + /* Copy the GUID of the sink for the new entry in the topology node + * table. */ + for (Index = 0; Index < 4; Index++) { + Topology->NodeTable[Topology->NodeTotal].Guid[Index] = + SinkDevice->Guid[Index]; + } + /* Copy the RAD of the sink for the new entry in the topology node + * table. */ + for (Index = 0; Index < (LinkCountTotal - 2); Index++) { + Topology->NodeTable[Topology->NodeTotal].RelativeAddress[Index] + = RelativeAddress[Index]; + } + Topology->NodeTable[Topology->NodeTotal].RelativeAddress[Index] = + SinkDevice->PortNum; + Topology->NodeTable[Topology->NodeTotal].DeviceType = + SinkDevice->PeerDeviceType; + Topology->NodeTable[Topology->NodeTotal].LinkCountTotal = + LinkCountTotal; + Topology->NodeTable[Topology->NodeTotal].DpcdRev = + SinkDevice->DpcdRev; + Topology->NodeTable[Topology->NodeTotal].MsgCapStatus = + SinkDevice->MsgCapStatus; + + Topology->SinkList[Topology->SinkTotal] = + &Topology->NodeTable[Topology->NodeTotal++]; + Topology->SinkTotal++; +} + +static u32 XDptx_SendSbMsg(XDptx *InstancePtr, XDptx_SidebandMsg *Msg) +{ + u32 Status; + u8 AuxData[10+63]; + XDptx_SidebandMsgHeader *Header = &Msg->Header; + XDptx_SidebandMsgBody *Body = &Msg->Body; + u8 Index; + + /* Add the header to the sideband message transaction. */ + Msg->Header.MsgHeaderLength = 0; + AuxData[Msg->Header.MsgHeaderLength++] = + (Msg->Header.LinkCountTotal << 4) | + Msg->Header.LinkCountRemaining; + for (Index = 0; Index < (Header->LinkCountTotal - 1); Index += 2) { + AuxData[Header->MsgHeaderLength] = + (Header->RelativeAddress[Index] << 4); + + if ((Index + 1) < (Header->LinkCountTotal - 1)) { + AuxData[Header->MsgHeaderLength] |= + Header->RelativeAddress[Index + 1]; + } + /* Else, the lower (4-bit) nibble is all zeros (for + * byte-alignment). */ + + Header->MsgHeaderLength++; + } + AuxData[Header->MsgHeaderLength++] = (Header->BroadcastMsg << 7) | + (Header->PathMsg << 6) | Header->MsgBodyLength; + AuxData[Header->MsgHeaderLength++] = (Header->StartOfMsgTransaction << + 7) | (Header->EndOfMsgTransaction << 6) | + (Header->MsgSequenceNum << 4) | Header->Crc; + + /* Add the body to the transaction. */ + for (Index = 0; Index < Body->MsgDataLength; Index++) { + AuxData[Index + Header->MsgHeaderLength] = Body->MsgData[Index]; + } + AuxData[Index + Header->MsgHeaderLength] = Body->Crc; + + /* Submit the LINK_ADDRESS transaction message request. */ + Status = XDptx_AuxWrite(InstancePtr, XDPTX_DPCD_DOWN_REQ, + Msg->Header.MsgHeaderLength + Msg->Header.MsgBodyLength, + AuxData); + + return Status; +} + +static u32 XDptx_WaitSbReply(XDptx *InstancePtr) +{ + u32 Status; + u8 AuxData[1]; + + do { + Status = XDptx_AuxRead(InstancePtr, + XDPTX_DPCD_SINK_DEVICE_SERVICE_IRQ_VECTOR_ESI0, + 1, AuxData); + if (Status != XST_SUCCESS) { + /* The AUX read transaction failed. */ + return Status; + } + } + while ((AuxData[0] & 0x10) != 0x10); + + return XST_SUCCESS; +} + +static void XDptx_GetDeviceInfoFromSbMsgLinkAddress(XDptx_SidebandReply + *SbReply, XDptx_SbMsgLinkAddressReplyDeviceInfo *FormatReply) +{ + u8 ReplyIndex = 0; + u8 Index, Index2; + + FormatReply->ReplyType = (SbReply->Data[ReplyIndex] >> 7); + FormatReply->RequestId = (SbReply->Data[ReplyIndex++] & 0x7F); + + memset(FormatReply->Guid, 0, 16); + for (Index = 0; Index < 16; Index++) { + FormatReply->Guid[Index / 4] <<= 8; + FormatReply->Guid[Index / 4] |= SbReply->Data[ReplyIndex++]; + } + + FormatReply->NumPorts = SbReply->Data[ReplyIndex++]; + + for (Index = 0; Index < FormatReply->NumPorts; Index++) { + FormatReply->PortDetails[Index].InputPort = + (SbReply->Data[ReplyIndex] >> 7); + FormatReply->PortDetails[Index].PeerDeviceType = + ((SbReply->Data[ReplyIndex] & 0x70) >> 4); + FormatReply->PortDetails[Index].PortNum = + (SbReply->Data[ReplyIndex++] & 0x0F); + FormatReply->PortDetails[Index].MsgCapStatus = + (SbReply->Data[ReplyIndex] >> 7); + FormatReply->PortDetails[Index].DpDevPlugStatus = + ((SbReply->Data[ReplyIndex] & 0x40) >> 6); + + if (FormatReply->PortDetails[Index].InputPort == 0) { + FormatReply->PortDetails[Index].LegacyDevPlugStatus = + ((SbReply->Data[ReplyIndex++] & 0x20) >> 5); + FormatReply->PortDetails[Index].DpcdRev = + (SbReply->Data[ReplyIndex++]); + + memset(FormatReply->PortDetails[Index].Guid, 0, 16); + for (Index2 = 0; Index2 < 16; Index2++) { + FormatReply->PortDetails[Index].Guid[Index2 / 4] + <<= 8; + FormatReply->PortDetails[Index].Guid[Index2 / 4] + |= SbReply->Data[ReplyIndex++]; + } + + FormatReply->PortDetails[Index].NumSdpStreams = + (SbReply->Data[ReplyIndex] >> 4); + FormatReply->PortDetails[Index].NumSdpStreamSinks = + (SbReply->Data[ReplyIndex++] & 0x0F); + } + else { + ReplyIndex++; + } + } +} + +static u32 XDptx_Transaction2MsgFormat(u8 *Transaction, XDptx_SidebandMsg *Msg) +{ + XDptx_SidebandMsgHeader *Header = &Msg->Header; + XDptx_SidebandMsgBody *Body = &Msg->Body; + + u8 Index = 0; + u8 CrcCheck; + + /* Fill the header structure from the reply transaction. */ + Header->MsgHeaderLength = 0; + /* Byte 0. */ + Header->LinkCountTotal = Transaction[Header->MsgHeaderLength] >> 4; + Header->LinkCountRemaining = Transaction[Header->MsgHeaderLength] & + 0x0F; + Header->MsgHeaderLength++; + /* If LinkCountTotal > 1, Byte 1 to Byte (_(LinkCountTotal / 2)_) */ + for (Index = 0; Index < (Header->LinkCountTotal - 1); Index += 2) { + Header->RelativeAddress[Index] = + Transaction[Header->MsgHeaderLength] >> 4; + + if ((Index + 1) < (Header->LinkCountTotal - 1)) { + Header->RelativeAddress[Index + 1] = + Transaction[Header->MsgHeaderLength] & 0x0F; + } + + Header->MsgHeaderLength++; + } + /* Byte (1 + _(LinkCountTotal / 2)_). */ + Header->BroadcastMsg = Transaction[Header->MsgHeaderLength] >> 7; + Header->PathMsg = (Transaction[Header->MsgHeaderLength] & 0x40) >> 6; + Header->MsgBodyLength = Transaction[Header->MsgHeaderLength] & 0x3F; + Header->MsgHeaderLength++; + /* Byte (2 + _(LinkCountTotal / 2)_). */ + Header->StartOfMsgTransaction = Transaction[Header->MsgHeaderLength] >> + 7; + Header->EndOfMsgTransaction = (Transaction[Header->MsgHeaderLength] & + 0x40) >> 6; + Header->MsgSequenceNum = (Transaction[Header->MsgHeaderLength] & + 0x10) >> 4; + Header->Crc = Transaction[Header->MsgHeaderLength] & 0x0F; + Header->MsgHeaderLength++; + /* Verify the header CRC. */ + CrcCheck = XDptx_Crc4CalculateHeader(Header); + if (CrcCheck != Header->Crc) { + /* The calculated CRC for the header did not match the + * response. */ + return XST_CRC_ERROR; + } + + /* Fill the body structure from the reply transaction. */ + Body->MsgDataLength = Header->MsgBodyLength - 1; + for (Index = 0; Index < Body->MsgDataLength; Index++) { + Body->MsgData[Index] = Transaction[Header->MsgHeaderLength + + Index]; + } + Body->Crc = Transaction[Header->MsgHeaderLength + Index]; + /* Verify the body CRC. */ + CrcCheck = XDptx_Crc8CalculateBody(Body); + if (CrcCheck != Body->Crc) { + /* The calculated CRC for the body did not match the + * response. */ + return XST_CRC_ERROR; + } + + return XST_SUCCESS; +} + +static u8 XDptx_CrcCalculate(const u8 *Data, u32 NumberOfBits, u8 Polynomial) +{ + u8 BitMask; + u8 BitShift; + u8 ArrayIndex = 0; + u16 Remainder = 0; + + if (Polynomial == 4) { + /* For CRC4, expecting nibbles (4-bits). */ + BitMask = 0x08; + BitShift = 3; + } + else { + /* For CRC8, expecting bytes (8-bits). */ + BitMask = 0x80; + BitShift = 7; + } + + while (NumberOfBits != 0) { + NumberOfBits--; + + Remainder <<= 1; + Remainder |= (Data[ArrayIndex] & BitMask) >> BitShift; + + BitMask >>= 1; + BitShift--; + + if (BitMask == 0) { + if (Polynomial == 4) { + BitMask = 0x08; + BitShift = 3; + } + else { + BitMask = 0x80; + BitShift = 7; + } + ArrayIndex++; + } + + if ((Remainder & (1 << Polynomial)) != 0) { + if (Polynomial == 4) { + Remainder ^= 0x13; + } + else { + Remainder ^= 0xD5; + } + } + } + + NumberOfBits = Polynomial; + while (NumberOfBits != 0) { + NumberOfBits--; + + Remainder <<= 1; + + if ((Remainder & (1 << Polynomial)) != 0) { + if (Polynomial == 4) { + Remainder ^= 0x13; + Remainder &= 0xFF; + } + else { + Remainder ^= 0xD5; + } + } + } + + return Remainder & 0xFF; +} + +static u8 XDptx_Crc4CalculateHeader(XDptx_SidebandMsgHeader *Header) +{ + u8 Nibbles[20]; + u8 RadOffset = 0; + + /* Arrange header into nibbles for the CRC. */ + Nibbles[0] = Header->LinkCountTotal; + Nibbles[1] = Header->LinkCountRemaining; + + for (RadOffset = 0; RadOffset < (Header->LinkCountTotal - 1); + RadOffset += 2) { + Nibbles[2 + RadOffset] = Header->RelativeAddress[RadOffset]; + + /* Byte (8-bits) align the nibbles (4-bits). */ + if ((RadOffset + 1) < (Header->LinkCountTotal - 1)) { + Nibbles[2 + RadOffset + 1] = + Header->RelativeAddress[RadOffset + 1]; + } + else { + Nibbles[2 + RadOffset + 1] = 0; + } + } + + Nibbles[2 + RadOffset] = (Header->BroadcastMsg << 3) | + (Header->PathMsg << 2) | ((Header->MsgBodyLength & 0x30) >> 4); + Nibbles[3 + RadOffset] = Header->MsgBodyLength & 0x0F; + Nibbles[4 + RadOffset] = (Header->StartOfMsgTransaction << 3) | + (Header->EndOfMsgTransaction << 2) | Header->MsgSequenceNum; + + return XDptx_CrcCalculate(Nibbles, 4 * (5 + RadOffset), 4); +} + +static u8 XDptx_Crc8CalculateBody(XDptx_SidebandMsgBody *Body) +{ + return XDptx_CrcCalculate(Body->MsgData, 8 * Body->MsgDataLength, 8); +} + +static u32 XDptx_ReceiveSbMsg(XDptx *InstancePtr, XDptx_SidebandReply *SbReply) +{ + u32 Status; + u8 Index = 0; + u8 AuxData[80]; + XDptx_SidebandMsg Msg; + + SbReply->Length = 0; + + do { + /* Wait for a reply. */ + Status = XDptx_WaitSbReply(InstancePtr); + if (Status != XST_SUCCESS) { + /* Either the AUX read transaction used to check the + * reply status failed, or waiting for a reply timed + * out. */ + return Status; + } + + /* Receive reply. */ + Status = XDptx_AuxRead(InstancePtr, XDPTX_DPCD_DOWN_REP, 80, + AuxData); + if (Status != XST_SUCCESS) { + /* The AUX read transaction failed. */ + return Status; + } + + /* Convert the reply transaction into XDptx_SidebandReply + * format. */ + Status = XDptx_Transaction2MsgFormat(AuxData, &Msg); + if (Status != XST_SUCCESS) { + /* The CRC of the header or the body did not match the + * calculated value. */ + return XST_CRC_ERROR; + } + + /* Collect body data into an array. */ + for (Index = 0; Index < Msg.Body.MsgDataLength; Index++) { + SbReply->Data[SbReply->Length++] = + Msg.Body.MsgData[Index]; + } + + /* Clear. */ + AuxData[0] = 0x10; + Status = XDptx_AuxWrite(InstancePtr, + XDPTX_DPCD_SINK_DEVICE_SERVICE_IRQ_VECTOR_ESI0, + 1, AuxData); + if (Status != XST_SUCCESS) { + /* The AUX write transaction failed. */ + return Status; + } + } + while (Msg.Header.EndOfMsgTransaction == 0); + + /* Check if the reply indicates a NACK. */ + if ((SbReply->Data[0] & 0x80) == 0x80) { + /* Reply with the reason for NACK. See xdptx.h + * XDPTX_SBREPLY_NACK_* for a list of possible values (range is + * (XST_SBREPLY_NACK + 0x01) to (XST_SBREPLY_NACK + 0x0A)). */ + return (XST_SBREPLY_NACK + SbReply->Data[17]); + } + + return XST_SUCCESS; +} diff --git a/XilinxProcessorIPLib/drivers/dptx/src/xdptx_spm.c b/XilinxProcessorIPLib/drivers/dptx/src/xdptx_spm.c index c417288c..dc174b5d 100644 --- a/XilinxProcessorIPLib/drivers/dptx/src/xdptx_spm.c +++ b/XilinxProcessorIPLib/drivers/dptx/src/xdptx_spm.c @@ -185,9 +185,6 @@ void XDptx_CfgMsaRecalculate(XDptx *InstancePtr, u8 Stream) (MsaConfig->SynchronousClockMode); MsaConfig->Misc1 = 0; - MsaConfig->DataPerLane = (MsaConfig->Dmt.HResolution * - MsaConfig->BitsPerColor * 3 / 16) - LinkConfig->LaneCount; - /* Determine the number of bits per pixel for the specified color * component format. */ if (MsaConfig->ComponentFormat == @@ -202,6 +199,9 @@ void XDptx_CfgMsaRecalculate(XDptx *InstancePtr, u8 Stream) if (InstancePtr->MstEnable == 1) { + MsaConfig->DataPerLane = (MsaConfig->Dmt.HResolution * + MsaConfig->BitsPerColor * 3 / 16) - 4; + /* Do time slot (and payload bandwidth number) calculations for * MST. */ XDptx_CalculateTs(InstancePtr, Stream, BitsPerPixel); @@ -209,6 +209,10 @@ void XDptx_CfgMsaRecalculate(XDptx *InstancePtr, u8 Stream) MsaConfig->InitWait = 0; } else { + MsaConfig->DataPerLane = (MsaConfig->Dmt.HResolution * + MsaConfig->BitsPerColor * 3 / 16) - + LinkConfig->LaneCount; + /* Allocate a fixed size for single-stream transport (SST) * operation. */ MsaConfig->TransferUnitSize = 64; @@ -480,6 +484,27 @@ void XDptx_CfgMsaSetBpc(XDptx *InstancePtr, u8 Stream, u8 BitsPerColor) XDptx_CfgMsaRecalculate(InstancePtr, Stream); } +void XDptx_CfgMsaEnSynchClkMode(XDptx *InstancePtr, u8 Stream, u8 Enable) +{ + XDptx_MainStreamAttributes *MsaConfig = + &InstancePtr->MsaConfig[Stream - 1]; + + /* Verify arguments. */ + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid((Enable == 0) || (Enable == 1)); + + MsaConfig->SynchronousClockMode = Enable; + + if (Enable == 1) { + MsaConfig->Misc0 |= (1 << + XDPTX_MAIN_STREAMX_MISC0_COMPONENT_FORMAT_SHIFT); + } + else { + MsaConfig->Misc0 &= ~(1 << + XDPTX_MAIN_STREAMX_MISC0_COMPONENT_FORMAT_SHIFT); + } +} + /******************************************************************************/ /** * This function clears the main stream attributes registers of the DisplayPort @@ -553,7 +578,6 @@ void XDptx_ClearMsaValues(XDptx *InstancePtr, u8 Stream) XDptx_WriteReg(Config->BaseAddr, XDPTX_N_VID + StreamOffset[Stream - 1], 0); - XDptx_WriteReg(Config->BaseAddr, XDPTX_STREAM0 + (Stream - 1) * 4, 0); XDptx_WriteReg(Config->BaseAddr, XDPTX_TU_SIZE + StreamOffset[Stream - 1], 0); @@ -657,12 +681,14 @@ static void XDptx_CalculateTs(XDptx *InstancePtr, u8 Stream, u8 BitsPerPixel) LinkBw = (LinkConfig->LaneCount * LinkConfig->LinkRate * 27); /* Calculate the payload bandiwdth number (PBN). */ - MsaConfig->MstPbn = ceil(1.006 * PeakPixelBw * ((double)64 / 54)); + InstancePtr->MstStreamConfig[Stream - 1].MstPbn = + ceil(1.006 * PeakPixelBw * ((double)64 / 54)); /* Calculate the average stream symbol time slots per MTP. */ Average_StreamSymbolTimeSlotsPerMTP = (64.0 * PeakPixelBw / LinkBw); MaximumTarget_Average_StreamSymbolTimeSlotsPerMTP = (54.0 * - ((double)MsaConfig->MstPbn / LinkBw)); + ((double)InstancePtr->MstStreamConfig[Stream - 1].MstPbn / + LinkBw)); /* The target value to be found needs to follow the condition: * Average_StreamSymbolTimeSlotsPerMTP <= @@ -700,6 +726,7 @@ static void XDptx_CalculateTs(XDptx *InstancePtr, u8 Stream, u8 BitsPerPixel) } /* Determine the PBN for the stream. */ - MsaConfig->MstPbn = MsaConfig->TransferUnitSize * + InstancePtr->MstStreamConfig[Stream - 1].MstPbn = + MsaConfig->TransferUnitSize * (LinkConfig->LaneCount * LinkConfig->LinkRate / 2); }