Files
open-gpu-kernel-modules/src/common/displayport/src/dp_configcaps2x.cpp
Bernhard Stoeckner 0bf68f06cc 570.190
2025-09-10 16:52:44 +02:00

759 lines
29 KiB
C++

/*
* SPDX-FileCopyrightText: Copyright (c) 2024-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: MIT
*
* 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.
*
* 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 AUTHORS OR COPYRIGHT HOLDERS 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.
*/
/******************************* DisplayPort********************************\
* *
* Module: dp_configcaps2x.cpp *
* Abstraction for DP2x caps registers *
* *
\***************************************************************************/
#include "dp_internal.h"
#include "dp_auxbus.h"
#include "dp_auxdefs.h"
#include "displayport.h"
#include "dp_configcaps2x.h"
using namespace DisplayPort;
void DPCDHALImpl2x::parseAndSetCableId(NvU8 cableId)
{
caps2x.cableCaps.bUHBR_10GSupported = true;
caps2x.cableCaps.bUHBR_20GSupported =
FLD_TEST_DRF(_DPCD20, _CABLE_ATTRIBUTES_UPDATED_BY_DPRX, _UHBR20_10_CAPABILITY, _10_AND_20_GBPS_SUPPORTED, cableId);
caps2x.cableCaps.bUHBR_13_5GSupported =
FLD_TEST_DRF(_DPCD20, _CABLE_ATTRIBUTES_UPDATED_BY_DPRX, _13_5_GBPS_SUPPORTED, _YES, cableId);
switch (DRF_VAL(_DPCD20, _CABLE_ATTRIBUTES_UPDATED_BY_DPRX, _CABLE_TYPE, cableId))
{
case NV_DPCD20_CABLE_ATTRIBUTES_UPDATED_BY_DPRX_CABLE_TYPE_CABLE_TYPE_UNKNOWN:
caps2x.cableCaps.cableType = CableTypeUnknown;
break;
case NV_DPCD20_CABLE_ATTRIBUTES_UPDATED_BY_DPRX_CABLE_TYPE_PASSIVE:
caps2x.cableCaps.cableType = CableTypePassive;
break;
case NV_DPCD20_CABLE_ATTRIBUTES_UPDATED_BY_DPRX_CABLE_TYPE_LRD:
caps2x.cableCaps.cableType = CableTypeLRD;
break;
case NV_DPCD20_CABLE_ATTRIBUTES_UPDATED_BY_DPRX_CABLE_TYPE_ACTIVE_RETIMER:
caps2x.cableCaps.cableType = CableTypeActiveReTimer;
break;
default:
DP_PRINTF(DP_ERROR, "Unknown cable type\n");
break;
}
}
void DPCDHALImpl2x::performCableIdHandshakeForTypeC()
{
NvU8 txCableCaps = 0;
NvU8 rxCableCaps = 0;
// Write sink caps to NV_DPCD20_CABLE_ATTRIBUTES_UPDATED_BY_DPTX first.
if (caps2x.bUHBR_20GSupported)
{
txCableCaps = FLD_SET_DRF(_DPCD20, _CABLE_ATTRIBUTES_UPDATED_BY_DPTX, _UHBR20_10_CAPABILITY,
_10_AND_20_GBPS_SUPPORTED, txCableCaps);
}
else
{
txCableCaps = FLD_SET_DRF(_DPCD20, _CABLE_ATTRIBUTES_UPDATED_BY_DPTX, _UHBR20_10_CAPABILITY,
_10_0_GBPS_SUPPORTED, txCableCaps);
}
if (caps2x.bUHBR_13_5GSupported)
{
txCableCaps = FLD_SET_DRF(_DPCD20, _CABLE_ATTRIBUTES_UPDATED_BY_DPTX, _13_5_GBPS_SUPPORTED,
_YES, txCableCaps);
}
// Set cable type based on if any LTTPR is detected.
if (!bLttprSupported || (this->caps.phyRepeaterCount == 0))
{
txCableCaps = FLD_SET_DRF(_DPCD20, _CABLE_ATTRIBUTES_UPDATED_BY_DPTX, _CABLE_TYPE,
_PASSIVE, txCableCaps);
}
else
{
txCableCaps = FLD_SET_DRF(_DPCD20, _CABLE_ATTRIBUTES_UPDATED_BY_DPTX, _CABLE_TYPE,
_ACTIVE_RETIMER, txCableCaps);
}
if (AuxRetry::ack != bus.write(NV_DPCD20_CABLE_ATTRIBUTES_UPDATED_BY_DPTX, &txCableCaps,
sizeof txCableCaps))
{
DP_PRINTF(DP_WARNING, "Failed to write NV_DPCD20_CABLE_ATTRIBUTES_UPDATED_BY_DPTX");
}
// Check Cable ID from DPRX
if (AuxRetry::ack !=
bus.read(NV_DPCD20_CABLE_ATTRIBUTES_UPDATED_BY_DPRX, &rxCableCaps, sizeof rxCableCaps))
{
DP_PRINTF(DP_WARNING, "Failed to read NV_DPCD20_CABLE_ATTRIBUTES_UPDATED_BY_DPRX for updated results");
}
parseAndSetCableId(rxCableCaps);
// If no matches, reflect that to the DPRX
if (txCableCaps != rxCableCaps)
{
if (AuxRetry::ack !=
bus.write(NV_DPCD20_CABLE_ATTRIBUTES_UPDATED_BY_DPTX, &rxCableCaps, sizeof rxCableCaps))
{
DP_PRINTF(DP_WARNING, "Failed to update NV_DPCD20_CABLE_ATTRIBUTES_UPDATED_BY_DPTX -> %02x", rxCableCaps);
}
}
}
void DPCDHALImpl2x::performCableIdHandshake()
{
NvU8 rxCableCaps = 0;
if (this->bConnectorIsTypeC)
{
return performCableIdHandshakeForTypeC();
}
// Read Cable ID from DPRX
if (AuxRetry::ack ==
bus.read(NV_DPCD20_CABLE_ATTRIBUTES_UPDATED_BY_DPRX, &rxCableCaps, sizeof rxCableCaps))
{
parseAndSetCableId(rxCableCaps);
}
}
void DPCDHALImpl2x::parseAndReadCaps()
{
NvU8 buffer[16];
NvU8 byte = 0;
unsigned retries = 16;
DPCDHALImpl::parseAndReadCaps();
// reset DP tunneling UHBR caps
caps2x.dpInTunnelingCaps.bUHBR_10GSupported = NV_FALSE;
caps2x.dpInTunnelingCaps.bUHBR_13_5GSupported = NV_FALSE;
caps2x.dpInTunnelingCaps.bUHBR_20GSupported = NV_FALSE;
// reset CableCaps
caps2x.cableCaps.bUHBR_10GSupported = NV_TRUE;
caps2x.cableCaps.bUHBR_13_5GSupported = NV_TRUE;
caps2x.cableCaps.bUHBR_20GSupported = NV_TRUE;
// 02206h
if (AuxRetry::ack == bus.read(NV_DPCD14_EXTENDED_MAIN_LINK_CHANNEL_CODING, &buffer[0], 1))
{
caps2x.bDP2xChannelCodingSupported = FLD_TEST_DRF(_DPCD20, _EXTENDED_MAIN_LINK_CHANNEL_CODING,
_ANSI_128B_132B, _YES,
buffer[0]);
// Read this unconditionally when the connection is tunneled
if (caps2x.bDP2xChannelCodingSupported == true || caps.dpInTunnelingCaps.bIsSupported)
{
// 0x2215
if (AuxRetry::ack == bus.read(NV_DPCD20_128B_132B_SUPPORTED_LINK_RATES, &buffer[0], 1))
{
caps2x.bUHBR_10GSupported =
FLD_TEST_DRF(_DPCD20,
_128B_132B_SUPPORTED_LINK_RATES,
_UHBR10,
_YES,
buffer[0]);
caps2x.bUHBR_13_5GSupported =
FLD_TEST_DRF(_DPCD20,
_128B_132B_SUPPORTED_LINK_RATES,
_UHBR13_5,
_YES,
buffer[0]);
caps2x.bUHBR_20GSupported =
FLD_TEST_DRF(_DPCD20,
_128B_132B_SUPPORTED_LINK_RATES,
_UHBR20,
_YES,
buffer[0]);
}
DP_ASSERT(caps2x.bUHBR_10GSupported && "Failed to read UHBR link rates or 128B/132B supported without UHBR10");
if (AuxRetry::ack == bus.read(NV_DPCD14_FEC_CAPABILITY, &buffer[0], 1))
{
caps.bFECSupported = FLD_TEST_DRF(_DPCD14, _FEC_CAPABILITY,
_FEC_CAPABLE,
_YES,
buffer[0]);
}
DP_ASSERT(caps.bFECSupported && "Failed to read FEC Capability or 128B/132B supported without FEC");
}
else
{
caps2x.bUHBR_10GSupported = NV_FALSE;
caps2x.bUHBR_13_5GSupported = NV_FALSE;
caps2x.bUHBR_20GSupported = NV_FALSE;
}
}
if (bLttprSupported)
{
if (AuxRetry::ack == bus.read(NV_DPCD14_LT_TUNABLE_PHY_REPEATER_REV, &buffer[0], 0x8, retries))
{
caps2x.repeaterCaps.bDP2xChannelCodingSupported =
FLD_TEST_DRF(_DPCD20,
_PHY_REPEATER_MAIN_LINK_CHANNEL_CODING,
_128B_132B_SUPPORTED,
_YES,
buffer[6]);
caps2x.repeaterCaps.bUHBR_10GSupported =
FLD_TEST_DRF(_DPCD20,
_PHY_REPEATER_128B_132B_RATES,
_10G_SUPPORTED,
_YES,
buffer[7]);
caps2x.repeaterCaps.bUHBR_13_5GSupported =
FLD_TEST_DRF(_DPCD20,
_PHY_REPEATER_128B_132B_RATES,
_13_5G_SUPPORTED,
_YES,
buffer[7]);
caps2x.repeaterCaps.bUHBR_20GSupported =
FLD_TEST_DRF(_DPCD20,
_PHY_REPEATER_128B_132B_RATES,
_20G_SUPPORTED,
_YES,
buffer[7]);
if (buffer[7] && !caps2x.repeaterCaps.bDP2xChannelCodingSupported)
{
DP_ASSERT(0 && "LTTPR: UHBR is supported without 128b/132b Channel Encoding Supported!");
}
if (caps2x.repeaterCaps.bDP2xChannelCodingSupported)
{
DP_ASSERT(caps.repeaterCaps.bFECSupported &&
"LTTPR: UHBR is supported without FEC Support!");
}
}
}
if (caps2x.bDP2xChannelCodingSupported && !bIgnoreCableIdCaps)
{
performCableIdHandshake();
}
if (caps.dpInTunnelingCaps.bIsSupported)
{
if (AuxRetry::ack ==
bus.read(NV_DPCD20_DP_TUNNELING_MAIN_LINK_CHANNEL_CODING, &byte, sizeof byte))
{
caps2x.dpInTunnelingCaps.bDP2xChannelCodingSupported =
FLD_TEST_DRF(_DPCD20, _DP_TUNNELING_128B132B,
_DP_SUPPORTED, _YES, byte);
}
}
if (caps2x.dpInTunnelingCaps.bDP2xChannelCodingSupported)
{
if (AuxRetry::ack ==
bus.read(NV_DPCD20_DP_TUNNELING_128B132B_LINK_RATES, &byte, sizeof byte))
{
caps2x.dpInTunnelingCaps.bUHBR_10GSupported =
FLD_TEST_DRF(_DPCD20, _DP_TUNNELING_128B132B_LINK_RATES, _10_0_GPBS_SUPPORTED, _YES, byte);
caps2x.dpInTunnelingCaps.bUHBR_13_5GSupported =
FLD_TEST_DRF(_DPCD20, _DP_TUNNELING_128B132B_LINK_RATES, _13_5_GPBS_SUPPORTED, _YES, byte);
caps2x.dpInTunnelingCaps.bUHBR_20GSupported =
FLD_TEST_DRF(_DPCD20, _DP_TUNNELING_128B132B_LINK_RATES, _20_0_GPBS_SUPPORTED, _YES, byte);
}
}
}
void DPCDHALImpl2x::setGpuDPSupportedVersions(NvU32 _gpuDPSupportedVersions)
{
bool bSupportDp1_2 = FLD_TEST_DRF(0073_CTRL_CMD_DP, _GET_CAPS_DP_VERSIONS_SUPPORTED, _DP1_2,
_YES, _gpuDPSupportedVersions);
bool bSupportDp1_4 = FLD_TEST_DRF(0073_CTRL_CMD_DP, _GET_CAPS_DP_VERSIONS_SUPPORTED, _DP1_4,
_YES, _gpuDPSupportedVersions);
bool bSupportDp2_0 = FLD_TEST_DRF(0073_CTRL_CMD_DP, _GET_CAPS_DP_VERSIONS_SUPPORTED, _DP2_0,
_YES, _gpuDPSupportedVersions);
if (bSupportDp2_0)
{
DP_ASSERT(bSupportDp1_4 && bSupportDp1_2 && "GPU supports DP1.4 should also support DP1.4 and DP1.2!");
}
return DPCDHALImpl::setGpuDPSupportedVersions(_gpuDPSupportedVersions);
}
void DPCDHALImpl2x::setConnectorTypeC(bool bTypeC)
{
this->bConnectorIsTypeC = bTypeC;
}
AuxRetry::status DPCDHALImpl2x::notifySDPErrDetectionCapability()
{
NvU8 config = 0;
AuxRetry::status status = AuxRetry::ack;
if (!FLD_TEST_DRF(0073_CTRL_CMD_DP,
_GET_CAPS_DP_VERSIONS_SUPPORTED,
_DP2_0, _YES, gpuDPSupportedVersions))
{
// If the GPU does not support DP2.0 features, don't do anything.
return status;
}
if (!isAtLeastVersion(1, 4) || !(caps2x.bDP2xChannelCodingSupported))
{
//
// If the root device is less then DP1.4 or does not support 128b/132b channel encoding,
// don't do anything.
//
return status;
}
if ((caps.phyRepeaterCount != 0) &&
(!caps2x.repeaterCaps.bDP2xChannelCodingSupported))
{
// If there are LTTPRs that does not support 128b/132b channel encoding, don't do anything.
return status;
}
config = FLD_SET_DRF(_DPCD20, _SDP_ERR_DETECTION_CONF, _CRC16_128B_132B_SUPPORTED,
_YES, config);
status = bus.write(NV_DPCD20_SDP_ERR_DETECTION_CONF, &config, sizeof(config));
if (AuxRetry::ack != status)
{
DP_PRINTF(DP_WARNING, "Failed to write NV_DPCD20_SDP_ERR_DETECTION_CONF");
}
return status;
}
bool DPCDHALImpl2x::isDp2xChannelCodingCapable()
{
// return false if the device does not support 128b/132b.
// However when dpTunneling is enabled, read the tunneling cap instead
if (caps.dpInTunnelingCaps.bIsSupported)
{
// return false if DP-IN Tunneling is supported but not support 128b/132b.
if (!caps2x.dpInTunnelingCaps.bDP2xChannelCodingSupported)
return false;
}
else
{
if (!caps2x.bDP2xChannelCodingSupported)
return false;
}
// return true if there is no LTTPR.
if (!bLttprSupported || (caps.phyRepeaterCount == 0))
return true;
// If there is any LTTPR, return false if any of the LTTPR does not support 128b/132b
if (!caps2x.repeaterCaps.bDP2xChannelCodingSupported || !lttprIsAtLeastVersion(2, 0))
{
// If there are LTTPRs that does not support 128b/132b channel encoding, it's not DP2x capable.
return false;
}
return true;
}
//
// Legacy link rates: DPCD offset 1 * 27000000
// ILRs: DPCD offset: 0x10~0x1F
// UHBR sink: DPCD offset: 0x2215
// LTTPR: DPCD offset: 0xF0007
//
LinkRate DPCDHALImpl2x::getMaxLinkRate()
{
LinkRate maxLinkRate = DPCDHALImpl::getMaxLinkRate();
NvU32 uhbrCaps = getUHBRSupported();
bool bDP2xChannelCodingSupported = isDp2xChannelCodingCapable();
if (bDP2xChannelCodingSupported)
{
if(FLD_TEST_DRF(0073_CTRL_CMD_DP, _GET_CAPS_UHBR_SUPPORTED, _UHBR10_0, _YES, uhbrCaps))
{
maxLinkRate = dp2LinkRate_10_0Gbps;
}
if(FLD_TEST_DRF(0073_CTRL_CMD_DP, _GET_CAPS_UHBR_SUPPORTED, _UHBR13_5, _YES, uhbrCaps))
{
maxLinkRate = dp2LinkRate_13_5Gbps;
}
if(FLD_TEST_DRF(0073_CTRL_CMD_DP, _GET_CAPS_UHBR_SUPPORTED, _UHBR20_0, _YES, uhbrCaps))
{
maxLinkRate = dp2LinkRate_20_0Gbps;
}
}
return maxLinkRate;
}
//
// The function checks for sink side UHBR capabilities as a combination of
// a. Sink Caps.
// b. Cable ID Caps
// c. LTTPR Caps.
// d. DP Tunneling Caps.
//
NvU32 DPCDHALImpl2x::getUHBRSupported()
{
NvU32 uhbrCaps = 0;
bool bUHBR_10GSupported = caps2x.bUHBR_10GSupported;
bool bUHBR_13_5GSupported = caps2x.bUHBR_13_5GSupported;
bool bUHBR_20GSupported = caps2x.bUHBR_20GSupported;
// When tunneling is supported and bw allocation is enabled, override the caps from tunneling caps
if (caps.dpInTunnelingCaps.bIsSupported && bIsDpTunnelBwAllocationEnabled)
{
bUHBR_10GSupported = caps2x.dpInTunnelingCaps.bUHBR_10GSupported;
bUHBR_13_5GSupported = caps2x.dpInTunnelingCaps.bUHBR_13_5GSupported;
bUHBR_20GSupported = caps2x.dpInTunnelingCaps.bUHBR_20GSupported;
}
if (!bIgnoreCableIdCaps)
{
bUHBR_10GSupported = bUHBR_10GSupported && caps2x.cableCaps.bUHBR_10GSupported;
bUHBR_13_5GSupported = bUHBR_13_5GSupported && caps2x.cableCaps.bUHBR_13_5GSupported;
bUHBR_20GSupported = bUHBR_20GSupported && caps2x.cableCaps.bUHBR_20GSupported;
}
if (caps.phyRepeaterCount > 0)
{
bUHBR_10GSupported = bUHBR_10GSupported && caps2x.repeaterCaps.bUHBR_10GSupported;
bUHBR_13_5GSupported = bUHBR_13_5GSupported && caps2x.repeaterCaps.bUHBR_13_5GSupported;
bUHBR_20GSupported = bUHBR_20GSupported && caps2x.repeaterCaps.bUHBR_20GSupported;
}
if (bUHBR_10GSupported)
{
uhbrCaps = FLD_SET_DRF(0073_CTRL_CMD_DP, _GET_CAPS_UHBR_SUPPORTED, _UHBR10_0, _YES, uhbrCaps);
}
if (bUHBR_13_5GSupported)
{
uhbrCaps = FLD_SET_DRF(0073_CTRL_CMD_DP, _GET_CAPS_UHBR_SUPPORTED, _UHBR13_5, _YES, uhbrCaps);
}
if (bUHBR_20GSupported)
{
uhbrCaps = FLD_SET_DRF(0073_CTRL_CMD_DP, _GET_CAPS_UHBR_SUPPORTED, _UHBR20_0, _YES, uhbrCaps);
}
return uhbrCaps;
}
void DPCDHALImpl2x::overrideCableIdCap(LinkRate linkRate, bool bEnable)
{
switch (linkRate)
{
case dp2LinkRate_20_0Gbps:
caps2x.cableCaps.bUHBR_20GSupported = bEnable;
break;
case dp2LinkRate_13_5Gbps:
caps2x.cableCaps.bUHBR_13_5GSupported = bEnable;
break;
case dp2LinkRate_10_0Gbps:
caps2x.cableCaps.bUHBR_10GSupported = bEnable;
break;
default:
DP_PRINTF(DP_ERROR, "DPHAL> Invalid link rate (%d) to override.", linkRate);
}
}
bool DPCDHALImpl2x::parseTestRequestPhy()
{
NvU8 buffer[2] = {0};
if (AuxRetry::ack != bus.read(NV_DPCD20_PHY_TEST_PATTERN, &buffer[0], 2))
{
DP_PRINTF(DP_ERROR, "DPHAL> ERROR! Test pattern request found but unable to read NV_DPCD20_PHY_TEST_PATTERN register.");
return false;
}
switch (DRF_VAL(_DPCD20, _PHY_TEST_PATTERN_SEL, _DP20, buffer[0]))
{
case NV_DPCD20_PHY_TEST_PATTERN_SEL_128B132B_TPS1:
interrupts2x.testPhyCompliance2x.phyTestPattern = LINK_QUAL_128B132B_TPS1;
break;
case NV_DPCD20_PHY_TEST_PATTERN_SEL_128B132B_TPS2:
interrupts2x.testPhyCompliance2x.phyTestPattern = LINK_QUAL_128B132B_TPS2;
break;
case NV_DPCD20_PHY_TEST_PATTERN_SEL_PRBS9:
interrupts2x.testPhyCompliance2x.phyTestPattern = LINK_QUAL_PRBS9;
break;
case NV_DPCD20_PHY_TEST_PATTERN_SEL_PRBS11:
interrupts2x.testPhyCompliance2x.phyTestPattern = LINK_QUAL_PRBS11;
break;
case NV_DPCD20_PHY_TEST_PATTERN_SEL_PRBS15:
interrupts2x.testPhyCompliance2x.phyTestPattern = LINK_QUAL_PRBS15;
break;
case NV_DPCD20_PHY_TEST_PATTERN_SEL_PRBS23:
interrupts2x.testPhyCompliance2x.phyTestPattern = LINK_QUAL_PRBS23;
break;
case NV_DPCD20_PHY_TEST_PATTERN_SEL_PRBS31:
interrupts2x.testPhyCompliance2x.phyTestPattern = LINK_QUAL_PRBS31;
break;
case NV_DPCD20_PHY_TEST_PATTERN_SEL_264_BIT_CUSTOM:
interrupts2x.testPhyCompliance2x.phyTestPattern = LINK_QUAL_264BIT_CUST;
break;
case NV_DPCD20_PHY_TEST_PATTERN_SEL_SQUARE_SEQ_WITH_PRESHOOT_ON_DE_EMPHASIS_ON:
interrupts2x.testPhyCompliance2x.phyTestPattern = LINK_QUAL_SQUARE_SEQ_WITH_PRESHOOT_ON_DE_EMPHASIS_ON;
interrupts2x.testPhyCompliance2x.sqNum = buffer[1];
break;
case NV_DPCD20_PHY_TEST_PATTERN_SEL_SQUARE_SEQ_WITH_PRESHOOT_OFF_DE_EMPHASIS_ON:
interrupts2x.testPhyCompliance2x.phyTestPattern = LINK_QUAL_SQUARE_SEQ_WITH_PRESHOOT_OFF_DE_EMPHASIS_ON;
interrupts2x.testPhyCompliance2x.sqNum = buffer[1];
break;
case NV_DPCD20_PHY_TEST_PATTERN_SEL_SQUARE_SEQ_WITH_PRESHOOT_ON_DE_EMPHASIS_OFF:
interrupts2x.testPhyCompliance2x.phyTestPattern = LINK_QUAL_SQUARE_SEQ_WITH_PRESHOOT_ON_DE_EMPHASIS_OFF;
interrupts2x.testPhyCompliance2x.sqNum = buffer[1];
break;
case NV_DPCD20_PHY_TEST_PATTERN_SEL_SQUARE_SEQ_WITH_PRESHOOT_OFF_DE_EMPHASIS_OFF:
interrupts2x.testPhyCompliance2x.phyTestPattern = LINK_QUAL_SQUARE_SEQ_WITH_PRESHOOT_OFF_DE_EMPHASIS_OFF;
interrupts2x.testPhyCompliance2x.sqNum = buffer[1];
break;
default:
// now look for DP1.X test patterns
interrupts2x.testPhyCompliance2x.phyTestPattern = LINK_QUAL_DISABLED;
return DPCDHALImpl::parseTestRequestPhy();
}
if (interrupts2x.testPhyCompliance2x.phyTestPattern == LINK_QUAL_264BIT_CUST)
{
if (AuxRetry::ack != bus.read(NV_DPCD20_TEST_264BIT_CUSTOM_PATTERN(0),
&(interrupts2x.cstm264Bits[0]),
NV_DPCD20_TEST_264BIT_CUSTOM_PATTERN__SIZE))
{
DP_PRINTF(DP_ERROR, "DPHAL> ERROR! Request for 264bit custom pattern. Can't read from 0x%08xh.",
NV_DPCD20_TEST_264BIT_CUSTOM_PATTERN(0));
return false;
}
}
// copy the parsed interrupt info to parent struct
interrupts.testPhyCompliance.phyTestPattern = interrupts2x.testPhyCompliance2x.phyTestPattern;
interrupts2x.testPhyCompliance2x.testRequestPhyCompliance = true;
return true;
}
bool DPCDHALImpl2x::parseTestRequestTraining(NvU8 * buffer)
{
if (buffer == NULL)
{
DP_ASSERT(0 && "Buffer invalid, bail out");
return false;
}
// 0x218, bit 4
bool bDP2xChannelCodingRequested = FLD_TEST_DRF(_DPCD20, _TEST_REQUEST,
_PHY_TEST_CHANNEL_CODING, _128B132B, buffer[0]);
if (!bDP2xChannelCodingRequested)
return DPCDHALImpl::parseTestRequestTraining(buffer);
// 0x219
switch (buffer[1])
{
case NV_DPCD20_TEST_LINK_RATE_TYPE_20_0G:
interrupts.testTraining.testRequestLinkRate = dp2LinkRate_20_0Gbps;
break;
case NV_DPCD20_TEST_LINK_RATE_TYPE_13_5G:
case NV_DPCD20_TEST_LINK_RATE_TYPE_13_5G_2:
interrupts.testTraining.testRequestLinkRate = dp2LinkRate_13_5Gbps;
break;
case NV_DPCD20_TEST_LINK_RATE_TYPE_10_0G:
interrupts.testTraining.testRequestLinkRate = dp2LinkRate_10_0Gbps;
break;
default:
interrupts.testTraining.testRequestLinkRate = dp2LinkRate_10_0Gbps;
DP_ASSERT(0 && "Unknown requested link rate. Assuming UHBR10");
break;
}
// 0x220.
interrupts.testTraining.testRequestLaneCount = buffer[(0x220 - 0x218)] & 0xf;
return true;
}
void DPCDHALImpl2x::get264BitsCustomTestPattern(NvU8 *testPattern)
{
int i;
for (i = 0; i < NV_DPCD20_TEST_264BIT_CUSTOM_PATTERN__SIZE; i++)
{
testPattern[i] = interrupts2x.cstm264Bits[i];
}
}
void DPCDHALImpl2x::getSquarePatternNum(NvU8 *sqNum)
{
if (sqNum != NULL)
{
*sqNum = interrupts2x.testPhyCompliance2x.sqNum;
}
return;
}
AuxRetry::status DPCDHALImpl2x::setLinkQualPatternSet
(
DP2xPatternInfo& patternInfo,
unsigned laneCount
)
{
unsigned writeAddr = NV_DPCD20_LINK_SQUARE_PATTERN_NUM_PLUS_1;
if ((patternInfo.lqsPattern == LINK_QUAL_SQUARE_SEQ_WITH_PRESHOOT_ON_DE_EMPHASIS_ON) ||
(patternInfo.lqsPattern == LINK_QUAL_SQUARE_SEQ_WITH_PRESHOOT_OFF_DE_EMPHASIS_ON) ||
(patternInfo.lqsPattern == LINK_QUAL_SQUARE_SEQ_WITH_PRESHOOT_ON_DE_EMPHASIS_OFF) ||
(patternInfo.lqsPattern == LINK_QUAL_SQUARE_SEQ_WITH_PRESHOOT_OFF_DE_EMPHASIS_OFF))
{
if (AuxRetry::ack != bus.write(writeAddr, &(patternInfo.sqNum), sizeof (patternInfo.sqNum)))
{
DP_ASSERT(0 && "Could not set LINK_SQUARE_PATTERN_NUM_PLUS_1");
}
}
return DPCDHALImpl::setLinkQualPatternSet(patternInfo.lqsPattern, laneCount);
}
AuxRetry::status DPCDHALImpl2x::setLinkQualLaneSet(unsigned lane, LinkQualityPatternType linkQualPattern)
{
NvU8 linkQuality = 0;
unsigned writeAddress = NV_DPCD20_LINK_QUAL_LANE_SET(lane);
if (caps.revisionMajor <= 0)
DP_ASSERT(0 && "Something is wrong, revision major should be > 0");
if (isAtLeastVersion(1, 2) == false)
{
DP_ASSERT(0 && "Regs only supported for DP1.2");
return AuxRetry::unsupportedRegister;
}
// check if parameter is valid
if (lane >= displayPort_LaneSupported)
{
DP_ASSERT(0 && "Unknown lane selected. Assuming Lane 0");
writeAddress = NV_DPCD20_LINK_QUAL_LANE_SET(0);
}
switch (linkQualPattern)
{
case LINK_QUAL_DISABLED:
linkQuality = FLD_SET_DRF(_DPCD, _LINK_QUAL_LANE_SET, _LQS, _NO, linkQuality);
break;
case LINK_QUAL_D10_2:
linkQuality = FLD_SET_DRF(_DPCD, _LINK_QUAL_LANE_SET, _LQS, _D10_2, linkQuality);
break;
case LINK_QUAL_SYM_ERROR:
linkQuality = FLD_SET_DRF(_DPCD, _LINK_QUAL_LANE_SET, _LQS, _SYM_ERR_MEASUREMENT_CNT, linkQuality);
break;
case LINK_QUAL_PRBS7:
linkQuality = FLD_SET_DRF(_DPCD, _LINK_QUAL_LANE_SET, _LQS, _PRBS7, linkQuality);
break;
case LINK_QUAL_80BIT_CUST:
linkQuality = FLD_SET_DRF(_DPCD, _LINK_QUAL_LANE_SET, _LQS, _80_BIT_CUSTOM, linkQuality);
break;
case LINK_QUAL_HBR2_COMPLIANCE_EYE:
linkQuality = FLD_SET_DRF(_DPCD, _LINK_QUAL_LANE_SET, _LQS, _HBR2, linkQuality);
break;
case LINK_QUAL_CP2520PAT3:
linkQuality = FLD_SET_DRF(_DPCD14, _LINK_QUAL_LANE_SET, _LQS, _CP2520PAT3, linkQuality);
break;
case LINK_QUAL_128B132B_TPS1:
linkQuality = FLD_SET_DRF(_DPCD20, _LINK_QUAL_LANE_SET, _LQS, _128B132B_TPS1, linkQuality);
break;
case LINK_QUAL_128B132B_TPS2:
linkQuality = FLD_SET_DRF(_DPCD20, _LINK_QUAL_LANE_SET, _LQS, _128B132B_TPS2, linkQuality);
break;
case LINK_QUAL_PRBS9:
linkQuality = FLD_SET_DRF(_DPCD20, _LINK_QUAL_LANE_SET, _LQS, _PRBS9, linkQuality);
break;
case LINK_QUAL_PRBS11:
linkQuality = FLD_SET_DRF(_DPCD20, _LINK_QUAL_LANE_SET, _LQS, _PRBS11, linkQuality);
break;
case LINK_QUAL_PRBS15:
linkQuality = FLD_SET_DRF(_DPCD20, _LINK_QUAL_LANE_SET, _LQS, _PRBS15, linkQuality);
break;
case LINK_QUAL_PRBS23:
linkQuality = FLD_SET_DRF(_DPCD20, _LINK_QUAL_LANE_SET, _LQS, _PRBS23, linkQuality);
break;
case LINK_QUAL_PRBS31:
linkQuality = FLD_SET_DRF(_DPCD20, _LINK_QUAL_LANE_SET, _LQS, _PRBS31, linkQuality);
break;
case LINK_QUAL_264BIT_CUST:
linkQuality = FLD_SET_DRF(_DPCD20, _LINK_QUAL_LANE_SET, _LQS, _264_BIT_CUSTOM, linkQuality);
break;
case LINK_QUAL_SQUARE_SEQ_WITH_PRESHOOT_ON_DE_EMPHASIS_ON:
linkQuality = FLD_SET_DRF(_DPCD20, _LINK_QUAL_LANE_SET, _LQS, _SQUARE_SEQ_WITH_PRESHOOT_ON_DE_EMPHASIS_ON, linkQuality);
break;
case LINK_QUAL_SQUARE_SEQ_WITH_PRESHOOT_OFF_DE_EMPHASIS_ON:
linkQuality = FLD_SET_DRF(_DPCD20, _LINK_QUAL_LANE_SET, _LQS, _SQUARE_SEQ_WITH_PRESHOOT_OFF_DE_EMPHASIS_ON, linkQuality);
break;
case LINK_QUAL_SQUARE_SEQ_WITH_PRESHOOT_ON_DE_EMPHASIS_OFF:
linkQuality = FLD_SET_DRF(_DPCD20, _LINK_QUAL_LANE_SET, _LQS, _SQUARE_SEQ_WITH_PRESHOOT_ON_DE_EMPHASIS_OFF, linkQuality);
break;
case LINK_QUAL_SQUARE_SEQ_WITH_PRESHOOT_OFF_DE_EMPHASIS_OFF:
linkQuality = FLD_SET_DRF(_DPCD20, _LINK_QUAL_LANE_SET, _LQS, _SQUARE_SEQ_WITH_PRESHOOT_OFF_DE_EMPHASIS_OFF, linkQuality);
break;
}
return bus.write(writeAddress, &linkQuality, sizeof linkQuality);
}
AuxRetry::status DPCDHALImpl2x::setMainLinkChannelCoding(MainLinkChannelCoding channelCoding)
{
NvU8 channelCodingSet = 0;
switch (channelCoding)
{
case ChannelCoding8B10B:
channelCodingSet = FLD_SET_DRF(_DPCD, _MAIN_LINK_CHANNEL_CODING_SET, _ANSI_8B_10B, _TRUE, channelCodingSet);
break;
case ChannelCoding128B132B:
channelCodingSet = FLD_SET_DRF(_DPCD, _MAIN_LINK_CHANNEL_CODING_SET, _ANSI_128B_132B, _TRUE, channelCodingSet);
break;
}
return bus.write(NV_DPCD_MAIN_LINK_CHANNEL_CODING_SET, &channelCodingSet , sizeof channelCodingSet);
}
MainLinkChannelCoding DPCDHALImpl2x::getMainLinkChannelCoding()
{
NvU8 channelCodingSet = 0;
if (!isDp2xChannelCodingCapable())
return ChannelCoding8B10B;
if (AuxRetry::ack != bus.read(NV_DPCD_MAIN_LINK_CHANNEL_CODING_SET, &channelCodingSet , sizeof channelCodingSet))
return ChannelCoding8B10B;
if (FLD_TEST_DRF(_DPCD, _MAIN_LINK_CHANNEL_CODING_SET, _ANSI_128B_132B, _TRUE, channelCodingSet))
return ChannelCoding128B132B;
return ChannelCoding8B10B;
}