mirror of
https://github.com/NVIDIA/open-gpu-kernel-modules.git
synced 2026-02-19 22:44:19 +00:00
600 lines
19 KiB
C++
600 lines
19 KiB
C++
/*
|
|
* SPDX-FileCopyrightText: Copyright (c) 2010-2024 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.
|
|
*/
|
|
|
|
/******************************* List **************************************\
|
|
* *
|
|
* Module: dp_linkconfig.h *
|
|
* Link Configuration object implementation *
|
|
* *
|
|
\***************************************************************************/
|
|
#ifndef INCLUDED_DP_LINKCONFIG_H
|
|
#define INCLUDED_DP_LINKCONFIG_H
|
|
|
|
#include "dp_auxdefs.h"
|
|
#include "dp_internal.h"
|
|
#include "dp_watermark.h"
|
|
#include "ctrl/ctrl0073/ctrl0073specific.h" // NV0073_CTRL_HDCP_VPRIME_SIZE
|
|
#include "displayport.h"
|
|
|
|
#define NV_SUPPORTED_DP_LINK_RATES__SIZE NV_SUPPORTED_DP1X_LINK_RATES__SIZE
|
|
namespace DisplayPort
|
|
{
|
|
typedef NvU64 LinkRate;
|
|
|
|
class LinkRates : virtual public Object
|
|
{
|
|
public:
|
|
NvU8 entries;
|
|
// Store link rate in multipler of 10MBPS to save space
|
|
NvU16 element[NV_SUPPORTED_DP_LINK_RATES__SIZE];
|
|
|
|
LinkRates()
|
|
{
|
|
entries = 0;
|
|
for (int i = 0; i < NV_SUPPORTED_DP_LINK_RATES__SIZE; i++)
|
|
{
|
|
element[i] = 0;
|
|
}
|
|
}
|
|
|
|
void clear()
|
|
{
|
|
entries = 0;
|
|
for (int i = 0; i < NV_SUPPORTED_DP_LINK_RATES__SIZE; i++)
|
|
{
|
|
element[i] = 0;
|
|
}
|
|
}
|
|
|
|
bool import(NvU16 linkBw)
|
|
{
|
|
if (!IS_VALID_LINKBW_10M(linkBw))
|
|
{
|
|
DP_ASSERT(0 && "Unsupported Link Bandwidth");
|
|
return false;
|
|
}
|
|
|
|
if (entries < NV_SUPPORTED_DP_LINK_RATES__SIZE)
|
|
{
|
|
element[entries] = linkBw;
|
|
entries++;
|
|
return true;
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
|
|
LinkRate getLowerRate(LinkRate rate)
|
|
{
|
|
int i;
|
|
|
|
if ((entries == 0) || (rate <= element[0]))
|
|
return 0;
|
|
|
|
for (i = entries - 1; i > 0; i--)
|
|
{
|
|
if (rate > element[i])
|
|
break;
|
|
}
|
|
|
|
return ((LinkRate)element[i]);
|
|
}
|
|
|
|
LinkRate getMaxRate()
|
|
{
|
|
LinkRate rate = 0;
|
|
if ((entries > 0) &&
|
|
(entries <= NV_SUPPORTED_DP_LINK_RATES__SIZE))
|
|
{
|
|
rate = (LinkRate)element[entries - 1];
|
|
}
|
|
return rate;
|
|
}
|
|
|
|
NvU8 getNumElements()
|
|
{
|
|
return NV_SUPPORTED_DP_LINK_RATES__SIZE;
|
|
}
|
|
|
|
NvU8 getNumLinkRates()
|
|
{
|
|
return entries;
|
|
}
|
|
};
|
|
class LinkPolicy : virtual public Object
|
|
{
|
|
protected:
|
|
bool bNoFallback; // No fallback when LT fails
|
|
LinkRates linkRates;
|
|
|
|
public:
|
|
LinkPolicy() : bNoFallback(false)
|
|
{
|
|
}
|
|
bool skipFallback()
|
|
{
|
|
return bNoFallback;
|
|
}
|
|
void setSkipFallBack(bool bSkipFallback)
|
|
{
|
|
bNoFallback = bSkipFallback;
|
|
}
|
|
|
|
LinkRates *getLinkRates()
|
|
{
|
|
return &linkRates;
|
|
}
|
|
};
|
|
|
|
enum
|
|
{
|
|
totalTimeslots = 64,
|
|
totalUsableTimeslots = totalTimeslots - 1
|
|
};
|
|
|
|
//
|
|
// Link Data Rate per DP Lane, in MBPS,
|
|
// For 8b/10b channel coding:
|
|
// Link Data Rate = link rate * (8 / 10) / 8
|
|
// = link rate * 0.1
|
|
// For 128b/132b channel coding:
|
|
// Link Data Rate = link rate * (128 / 132) / 8
|
|
// = link rate * 4 / 33
|
|
// ~= link rate * 0.12
|
|
//
|
|
// Link Bandwidth = Lane Count * Link Data Rate
|
|
//
|
|
enum
|
|
{
|
|
RBR = 162000000,
|
|
EDP_2_16GHZ = 216000000,
|
|
EDP_2_43GHZ = 243000000,
|
|
HBR = 270000000,
|
|
EDP_3_24GHZ = 324000000,
|
|
EDP_4_32GHZ = 432000000,
|
|
HBR2 = 540000000,
|
|
HBR3 = 810000000
|
|
};
|
|
|
|
struct HDCPState
|
|
{
|
|
bool HDCP_State_Encryption;
|
|
bool HDCP_State_1X_Capable;
|
|
bool HDCP_State_22_Capable;
|
|
bool HDCP_State_Authenticated;
|
|
bool HDCP_State_Repeater_Capable;
|
|
};
|
|
|
|
struct HDCPValidateData
|
|
{
|
|
};
|
|
|
|
typedef enum
|
|
{
|
|
DP_SINGLE_HEAD_MULTI_STREAM_MODE_NONE,
|
|
DP_SINGLE_HEAD_MULTI_STREAM_MODE_SST,
|
|
DP_SINGLE_HEAD_MULTI_STREAM_MODE_MST,
|
|
}DP_SINGLE_HEAD_MULTI_STREAM_MODE;
|
|
|
|
#define HEAD_INVALID_STREAMS 0
|
|
#define HEAD_DEFAULT_STREAMS 1
|
|
|
|
typedef enum
|
|
{
|
|
DP_SINGLE_HEAD_MULTI_STREAM_PIPELINE_ID_PRIMARY = 0,
|
|
DP_SINGLE_HEAD_MULTI_STREAM_PIPELINE_ID_SECONDARY = 1,
|
|
DP_SINGLE_HEAD_MULTI_STREAM_PIPELINE_ID_MAX = DP_SINGLE_HEAD_MULTI_STREAM_PIPELINE_ID_SECONDARY,
|
|
} DP_SINGLE_HEAD_MULTI_STREAM_PIPELINE_ID;
|
|
|
|
#define DP_INVALID_SOR_INDEX 0xFFFFFFFF
|
|
#define DSC_DEPTH_FACTOR 16
|
|
|
|
|
|
class LinkConfiguration : virtual public Object
|
|
{
|
|
public:
|
|
LinkPolicy policy;
|
|
unsigned lanes;
|
|
LinkRate peakRatePossible;
|
|
LinkRate peakRate;
|
|
LinkRate minRate;
|
|
bool enhancedFraming;
|
|
bool multistream;
|
|
bool disablePostLTRequest;
|
|
bool bEnableFEC;
|
|
bool bDisableLTTPR;
|
|
//
|
|
// The counter to record how many times link training happens.
|
|
// Client can reset the counter by calling setLTCounter(0)
|
|
//
|
|
unsigned linkTrainCounter;
|
|
|
|
LinkConfiguration() :
|
|
lanes(0), peakRatePossible(0), peakRate(0), minRate(0),
|
|
enhancedFraming(false), multistream(false), disablePostLTRequest(false),
|
|
bEnableFEC(false), bDisableLTTPR(false),
|
|
linkTrainCounter(0) {};
|
|
|
|
LinkConfiguration(LinkPolicy * p, unsigned lanes, LinkRate peakRate,
|
|
bool enhancedFraming, bool MST, bool disablePostLTRequest = false,
|
|
bool bEnableFEC = false, bool bDisableLTTPR = false) :
|
|
lanes(lanes), peakRatePossible(peakRate), peakRate(peakRate),
|
|
enhancedFraming(enhancedFraming), multistream(MST),
|
|
disablePostLTRequest(disablePostLTRequest),
|
|
bEnableFEC(bEnableFEC), bDisableLTTPR(bDisableLTTPR),
|
|
linkTrainCounter(0)
|
|
{
|
|
// downrate for spread and FEC
|
|
minRate = linkOverhead(peakRate);
|
|
if (p)
|
|
{
|
|
policy = *p;
|
|
}
|
|
}
|
|
|
|
void setLTCounter(unsigned counter)
|
|
{
|
|
linkTrainCounter = counter;
|
|
}
|
|
|
|
unsigned getLTCounter()
|
|
{
|
|
return linkTrainCounter;
|
|
}
|
|
|
|
// Returns data rate in Bytes per second
|
|
NvU64 convertLinkRateToDataRate(LinkRate linkRate) const
|
|
{
|
|
NvU64 dataRate;
|
|
dataRate = LINK_RATE_TO_DATA_RATE_8B_10B(linkRate);
|
|
return dataRate;
|
|
}
|
|
|
|
// Returns minRate in data rate in Bytes per second
|
|
NvU64 convertMinRateToDataRate() const
|
|
{
|
|
NvU64 dataRate;
|
|
dataRate = DP_LINK_RATE_BITSPS_TO_BYTESPS(OVERHEAD_8B_10B(minRate));
|
|
return dataRate;
|
|
}
|
|
|
|
NvU64 getTotalDataRate() const
|
|
{
|
|
return (convertLinkRateToDataRate(peakRate) * lanes);
|
|
}
|
|
|
|
NvU64 linkOverhead(NvU64 rate)
|
|
{
|
|
if(IS_VALID_LINKBW_10M(rate))
|
|
{
|
|
// Converting here so that minRate from 10M is converted to bps
|
|
rate = DP_LINK_RATE_10M_TO_BPS(rate);
|
|
}
|
|
else
|
|
{
|
|
// Convert from data rate to bps
|
|
rate = DATA_RATE_8B_10B_TO_LINK_RATE_BPS(rate);
|
|
}
|
|
|
|
if(bEnableFEC)
|
|
{
|
|
|
|
// if FEC is enabled, we have to account for 3% overhead
|
|
// for FEC+downspread according to DP 1.4 spec
|
|
|
|
return rate - 3 * rate/ 100;
|
|
}
|
|
else
|
|
{
|
|
// if FEC is not enabled, link overhead comprises only of
|
|
// 0.6% downspread.
|
|
return rate - 6 * rate/ 1000;
|
|
|
|
}
|
|
}
|
|
|
|
void enableFEC(bool setFEC)
|
|
{
|
|
bEnableFEC = setFEC;
|
|
// If FEC is enabled, update minRate with FEC+downspread overhead.
|
|
minRate = linkOverhead(peakRate);
|
|
}
|
|
|
|
LinkConfiguration(unsigned long TotalLinkPBN)
|
|
: enhancedFraming(true),
|
|
multistream(true),
|
|
disablePostLTRequest(false),
|
|
bEnableFEC(false),
|
|
bDisableLTTPR(false),
|
|
linkTrainCounter(0)
|
|
{
|
|
//
|
|
// Reverse engineer a link configuration from Total TotalLinkPBN
|
|
// Note that HBR2 twice HBR. The table below treats HBR2x1 and HBRx2, etc.
|
|
//
|
|
// PBN Calculation
|
|
// Definition of PBN is "54/64 MBps".
|
|
// Note this is the "data" actually transmitted in the main link.
|
|
// So we need to take channel coding into consideration.
|
|
// Formula: PBN = Lane Count * Link Rate (Gbps) * 1000 * (1/8) * ChannelCoding Efficiency * (64 / 54)
|
|
// Example:
|
|
// 1. 4 * HBR2: 4 * 5.4 * 1000 * (1/8) * (8/10) * (64/54) = 2560
|
|
// 2. 2 * UHBR10: 2 * 10 * 1000 * (1/8) * (128/132) * (64/54) = 2873
|
|
//
|
|
// Full list:
|
|
//
|
|
// BW (Gbps) Lanes TotalLinkPBN
|
|
// 1.62 1 192
|
|
// 1.62 2 384
|
|
// 1.62 4 768
|
|
// 2.70 1 320
|
|
// 2.70 2 640
|
|
// 2.70 4 1280
|
|
// 5.40 1 640
|
|
// 5.40 2 1280
|
|
// 5.40 4 2560
|
|
// 8.10 1 960
|
|
// 8.10 2 1920
|
|
// 8.10 4 3840
|
|
// 10.00 1 1436
|
|
// 10.00 2 2873
|
|
// 10.00 4 5746
|
|
// 13.50 1 1939
|
|
// 13.50 2 3878
|
|
// 13.50 4 7757
|
|
// 20.00 1 2873
|
|
// 20.00 2 5746
|
|
// 20.00 4 11492
|
|
//
|
|
|
|
if (TotalLinkPBN <= 90)
|
|
{
|
|
peakRatePossible = dp2LinkRate_1_62Gbps;
|
|
peakRate = peakRatePossible;
|
|
minRate = linkOverhead(dp2LinkRate_1_62Gbps);
|
|
lanes = 0; // FAIL
|
|
}
|
|
if (TotalLinkPBN <= 192)
|
|
{
|
|
peakRatePossible = dp2LinkRate_1_62Gbps;
|
|
peakRate = peakRatePossible;
|
|
minRate = linkOverhead(dp2LinkRate_1_62Gbps);
|
|
lanes = 1;
|
|
}
|
|
else if (TotalLinkPBN <= 320)
|
|
{
|
|
peakRatePossible = dp2LinkRate_2_70Gbps;
|
|
peakRate = peakRatePossible;
|
|
minRate = linkOverhead(dp2LinkRate_2_70Gbps);
|
|
lanes = 1;
|
|
}
|
|
else if (TotalLinkPBN <= 384)
|
|
{
|
|
peakRatePossible = dp2LinkRate_1_62Gbps;
|
|
peakRate = peakRatePossible;
|
|
minRate = linkOverhead(dp2LinkRate_1_62Gbps);
|
|
lanes = 2;
|
|
}
|
|
else if (TotalLinkPBN <= 640)
|
|
{
|
|
// could be HBR2 x 1, but TotalLinkPBN works out same
|
|
peakRatePossible = dp2LinkRate_2_70Gbps;
|
|
peakRate = peakRatePossible;
|
|
minRate = linkOverhead(dp2LinkRate_2_70Gbps);
|
|
lanes = 2;
|
|
}
|
|
else if (TotalLinkPBN <= 768)
|
|
{
|
|
peakRatePossible = dp2LinkRate_1_62Gbps;
|
|
peakRate = peakRatePossible;
|
|
minRate = linkOverhead(dp2LinkRate_1_62Gbps);
|
|
lanes = 4;
|
|
}
|
|
else if (TotalLinkPBN <= 960)
|
|
{
|
|
peakRatePossible = dp2LinkRate_8_10Gbps;
|
|
peakRate = peakRatePossible;
|
|
minRate = linkOverhead(dp2LinkRate_8_10Gbps);
|
|
lanes = 1;
|
|
}
|
|
else if (TotalLinkPBN <= 1280)
|
|
{
|
|
// could be HBR2 x 2
|
|
peakRatePossible = dp2LinkRate_2_70Gbps;
|
|
peakRate = peakRatePossible;
|
|
minRate = linkOverhead(dp2LinkRate_2_70Gbps);
|
|
lanes = 4;
|
|
}
|
|
else if (TotalLinkPBN <= 1920)
|
|
{
|
|
peakRatePossible = dp2LinkRate_8_10Gbps;
|
|
peakRate = peakRatePossible;
|
|
minRate = linkOverhead(dp2LinkRate_8_10Gbps);
|
|
lanes = 2;
|
|
}
|
|
else if (TotalLinkPBN <= 2560)
|
|
{
|
|
peakRatePossible = dp2LinkRate_5_40Gbps;
|
|
peakRate = peakRatePossible;
|
|
minRate = linkOverhead(dp2LinkRate_5_40Gbps);
|
|
lanes = 4;
|
|
}
|
|
else if (TotalLinkPBN <= 3840)
|
|
{
|
|
peakRatePossible = dp2LinkRate_8_10Gbps;
|
|
peakRate = peakRatePossible;
|
|
minRate = linkOverhead(dp2LinkRate_8_10Gbps);
|
|
lanes = 4;
|
|
}
|
|
else
|
|
{
|
|
peakRatePossible = dp2LinkRate_1_62Gbps;
|
|
peakRate = peakRatePossible;
|
|
minRate = linkOverhead(dp2LinkRate_1_62Gbps);
|
|
lanes = 0; // FAIL
|
|
DP_ASSERT(0 && "Unknown configuration");
|
|
}
|
|
}
|
|
|
|
void setEnhancedFraming(bool newEnhancedFraming)
|
|
{
|
|
enhancedFraming = newEnhancedFraming;
|
|
}
|
|
|
|
bool isValid()
|
|
{
|
|
return lanes != laneCount_0;
|
|
}
|
|
|
|
bool lowerConfig(bool bReduceLaneCnt = false)
|
|
{
|
|
//
|
|
// TODO: bReduceLaneCnt is set to fallback to 4 lanes with lower
|
|
// valid link rate. But we should reset to max lane count
|
|
// sink supports instead.
|
|
//
|
|
|
|
LinkRate lowerRate = policy.getLinkRates()->getLowerRate(peakRate);
|
|
|
|
if(bReduceLaneCnt)
|
|
{
|
|
// Reduce laneCount before reducing linkRate
|
|
if(lanes == laneCount_1)
|
|
{
|
|
if (lowerRate)
|
|
{
|
|
lanes = laneCount_4;
|
|
peakRate = lowerRate;
|
|
}
|
|
else
|
|
{
|
|
lanes = laneCount_0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
lanes /= 2;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Reduce the link rate instead of lane count
|
|
if (lowerRate)
|
|
{
|
|
peakRate = lowerRate;
|
|
}
|
|
else
|
|
{
|
|
lanes /= 2;
|
|
}
|
|
}
|
|
|
|
minRate = linkOverhead(peakRate);
|
|
return lanes != laneCount_0;
|
|
}
|
|
|
|
void setLaneRate(LinkRate newRate, unsigned newLanes)
|
|
{
|
|
peakRate = newRate;
|
|
lanes = newLanes;
|
|
minRate = linkOverhead(peakRate);
|
|
}
|
|
|
|
unsigned pbnTotal()
|
|
{
|
|
return PBNForSlots(totalUsableTimeslots);
|
|
}
|
|
|
|
void pbnRequired(const ModesetInfo & modesetInfo, unsigned & base_pbn, unsigned & slots, unsigned & slots_pbn)
|
|
{
|
|
base_pbn = pbnForMode(modesetInfo);
|
|
if (bEnableFEC)
|
|
{
|
|
// IF FEC is enabled, we need to consider 3% overhead as per DP1.4 spec.
|
|
base_pbn = (NvU32)(divide_ceil(base_pbn * 100, 97));
|
|
}
|
|
slots = slotsForPBN(base_pbn);
|
|
slots_pbn = PBNForSlots(slots);
|
|
}
|
|
|
|
NvU32 slotsForPBN(NvU32 allocatedPBN, bool usable = false)
|
|
{
|
|
NvU64 bytes_per_pbn = 54 * 1000000 / 64; // this comes out exact
|
|
NvU64 bytes_per_timeslot = getTotalDataRate() / 64;
|
|
|
|
if (bytes_per_timeslot == 0)
|
|
return (NvU32)-1;
|
|
|
|
if (usable)
|
|
{
|
|
// round down to find the usable integral slots for a given value of PBN.
|
|
NvU32 slots = (NvU32)divide_floor(allocatedPBN * bytes_per_pbn, bytes_per_timeslot);
|
|
DP_ASSERT(slots <= 64);
|
|
|
|
return slots;
|
|
}
|
|
else
|
|
return (NvU32)divide_ceil(allocatedPBN * bytes_per_pbn, bytes_per_timeslot);
|
|
}
|
|
|
|
NvU32 PBNForSlots(NvU32 slots) // Rounded down
|
|
{
|
|
NvU64 bytes_per_pbn = 54 * 1000000 / 64; // this comes out exact
|
|
NvU64 bytes_per_timeslot = getTotalDataRate() / 64;
|
|
|
|
return (NvU32)(bytes_per_timeslot * slots/ bytes_per_pbn);
|
|
}
|
|
|
|
bool operator!= (const LinkConfiguration & right) const
|
|
{
|
|
return !(*this == right);
|
|
}
|
|
|
|
bool operator== (const LinkConfiguration & right) const
|
|
{
|
|
return (this->lanes == right.lanes &&
|
|
this->peakRate == right.peakRate &&
|
|
this->enhancedFraming == right.enhancedFraming &&
|
|
this->multistream == right.multistream &&
|
|
this->bEnableFEC == right.bEnableFEC);
|
|
}
|
|
|
|
bool operator< (const LinkConfiguration & right) const
|
|
{
|
|
NvU64 leftMKBps = getTotalDataRate();
|
|
NvU64 rightMKBps = right.getTotalDataRate();
|
|
|
|
if (leftMKBps == rightMKBps)
|
|
{
|
|
return (lanes < right.lanes);
|
|
}
|
|
else
|
|
{
|
|
return (leftMKBps < rightMKBps);
|
|
}
|
|
}
|
|
};
|
|
|
|
}
|
|
#endif //INCLUDED_DP_LINKCONFIG_H
|