1 /* 2 * SPDX-FileCopyrightText: Copyright (c) 2010-2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 * SPDX-License-Identifier: MIT 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a 6 * copy of this software and associated documentation files (the "Software"), 7 * to deal in the Software without restriction, including without limitation 8 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 * and/or sell copies of the Software, and to permit persons to whom the 10 * Software is furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice shall be included in 13 * all copies or substantial portions of the Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 * DEALINGS IN THE SOFTWARE. 22 */ 23 24 /******************************* List **************************************\ 25 * * 26 * Module: dp_linkconfig.h * 27 * Link Configuration object implementation * 28 * * 29 \***************************************************************************/ 30 #ifndef INCLUDED_DP_LINKCONFIG_H 31 #define INCLUDED_DP_LINKCONFIG_H 32 33 #include "dp_auxdefs.h" 34 #include "dp_internal.h" 35 #include "dp_watermark.h" 36 #include "ctrl/ctrl0073/ctrl0073specific.h" // NV0073_CTRL_HDCP_VPRIME_SIZE 37 #include "displayport.h" 38 39 40 namespace DisplayPort 41 { 42 typedef NvU64 LinkRate; 43 44 class LinkRates : virtual public Object 45 { 46 public: 47 // Store link rate in multipler of 270MBPS to save space 48 NvU8 element[NV_DPCD_SUPPORTED_LINK_RATES__SIZE]; 49 NvU8 entries; 50 51 LinkRates() 52 { 53 entries = 0; 54 55 for (int i = 0; i < NV_DPCD_SUPPORTED_LINK_RATES__SIZE; i++) 56 { 57 element[i] = 0; 58 } 59 } 60 61 void clear() 62 { 63 entries = 0; 64 for (int i = 0; i < NV_DPCD_SUPPORTED_LINK_RATES__SIZE; i++) 65 { 66 element[i] = 0; 67 } 68 } 69 70 bool import(NvU8 linkBw) 71 { 72 if (entries < NV_DPCD_SUPPORTED_LINK_RATES__SIZE) 73 { 74 element[entries] = linkBw; 75 entries++; 76 return true; 77 } 78 else 79 return false; 80 } 81 82 NvU8 getNumLinkRates() 83 { 84 return entries; 85 } 86 87 LinkRate getLowerRate(LinkRate rate) 88 { 89 int i; 90 NvU8 linkBw = (NvU8)(rate / DP_LINK_BW_FREQ_MULTI_MBPS); 91 92 if ((entries == 0) || (linkBw <= element[0])) 93 return 0; 94 95 for (i = entries - 1; i > 0; i--) 96 { 97 if (linkBw > element[i]) 98 break; 99 } 100 101 rate = (LinkRate)element[i] * DP_LINK_BW_FREQ_MULTI_MBPS; 102 return rate; 103 } 104 105 LinkRate getMaxRate() 106 { 107 LinkRate rate = 0; 108 if ((entries > 0) && 109 (entries <= NV_DPCD_SUPPORTED_LINK_RATES__SIZE)) 110 { 111 rate = (LinkRate)element[entries - 1] * DP_LINK_BW_FREQ_MULTI_MBPS; 112 } 113 114 return rate; 115 } 116 }; 117 118 class LinkPolicy : virtual public Object 119 { 120 bool bNoFallback; // No fallback when LT fails 121 LinkRates linkRates; 122 123 public: 124 LinkPolicy() : bNoFallback(false) 125 { 126 } 127 bool skipFallback() 128 { 129 return bNoFallback; 130 } 131 void setSkipFallBack(bool bSkipFallback) 132 { 133 bNoFallback = bSkipFallback; 134 } 135 136 LinkRates *getLinkRates() 137 { 138 return &linkRates; 139 } 140 }; 141 enum 142 { 143 totalTimeslots = 64, 144 totalUsableTimeslots = totalTimeslots - 1 145 }; 146 147 // in 10bps 148 enum 149 { 150 RBR = 162000000, 151 EDP_2_16GHZ = 216000000, 152 EDP_2_43GHZ = 243000000, 153 HBR = 270000000, 154 EDP_3_24GHZ = 324000000, 155 EDP_4_32GHZ = 432000000, 156 HBR2 = 540000000, 157 HBR3 = 810000000 158 }; 159 160 struct HDCPState 161 { 162 bool HDCP_State_Encryption; 163 bool HDCP_State_1X_Capable; 164 bool HDCP_State_22_Capable; 165 bool HDCP_State_Authenticated; 166 bool HDCP_State_Repeater_Capable; 167 }; 168 169 struct HDCPValidateData 170 { 171 }; 172 173 typedef enum 174 { 175 DP_SINGLE_HEAD_MULTI_STREAM_MODE_NONE, 176 DP_SINGLE_HEAD_MULTI_STREAM_MODE_SST, 177 DP_SINGLE_HEAD_MULTI_STREAM_MODE_MST, 178 }DP_SINGLE_HEAD_MULTI_STREAM_MODE; 179 180 #define HEAD_INVALID_STREAMS 0 181 #define HEAD_DEFAULT_STREAMS 1 182 183 typedef enum 184 { 185 DP_SINGLE_HEAD_MULTI_STREAM_PIPELINE_ID_PRIMARY = 0, 186 DP_SINGLE_HEAD_MULTI_STREAM_PIPELINE_ID_SECONDARY = 1, 187 DP_SINGLE_HEAD_MULTI_STREAM_PIPELINE_ID_MAX = DP_SINGLE_HEAD_MULTI_STREAM_PIPELINE_ID_SECONDARY, 188 } DP_SINGLE_HEAD_MULTI_STREAM_PIPELINE_ID; 189 190 #define DP_INVALID_SOR_INDEX 0xFFFFFFFF 191 #define DSC_DEPTH_FACTOR 16 192 193 194 class LinkConfiguration : virtual public Object 195 { 196 public: 197 LinkPolicy policy; 198 unsigned lanes; 199 LinkRate peakRatePossible; 200 LinkRate peakRate; 201 LinkRate minRate; 202 bool enhancedFraming; 203 bool multistream; 204 bool disablePostLTRequest; 205 bool bEnableFEC; 206 bool bDisableLTTPR; 207 208 // 209 // The counter to record how many times link training happens. 210 // Client can reset the counter by calling setLTCounter(0) 211 // 212 unsigned linkTrainCounter; 213 214 LinkConfiguration() : 215 lanes(0), peakRatePossible(0), peakRate(0), minRate(0), 216 enhancedFraming(false), multistream(false), disablePostLTRequest(false), 217 bEnableFEC(false), bDisableLTTPR(false), linkTrainCounter(0) {}; 218 219 LinkConfiguration(LinkPolicy * p, unsigned lanes, LinkRate peakRate, 220 bool enhancedFraming, bool MST, bool disablePostLTRequest = false, 221 bool bEnableFEC = false, bool bDisableLTTPR = false) : 222 lanes(lanes), peakRatePossible(peakRate), peakRate(peakRate), 223 enhancedFraming(enhancedFraming), multistream(MST), 224 disablePostLTRequest(disablePostLTRequest), 225 bEnableFEC(bEnableFEC), bDisableLTTPR(bDisableLTTPR), 226 linkTrainCounter(0) 227 { 228 // downrate for spread and FEC 229 minRate = linkOverhead(peakRate); 230 if (p) 231 { 232 policy = *p; 233 } 234 } 235 236 void setLTCounter(unsigned counter) 237 { 238 linkTrainCounter = counter; 239 } 240 241 unsigned getLTCounter() 242 { 243 return linkTrainCounter; 244 } 245 246 NvU64 linkOverhead(NvU64 rate) 247 { 248 if(bEnableFEC) 249 { 250 251 // if FEC is enabled, we have to account for 3% overhead 252 // for FEC+downspread according to DP 1.4 spec 253 254 return rate - 3 * rate/ 100; 255 } 256 else 257 { 258 // if FEC is not enabled, link overhead comprises only of 259 // 0.05% downspread. 260 return rate - 5 * rate/ 1000; 261 262 } 263 } 264 265 void enableFEC(bool setFEC) 266 { 267 bEnableFEC = setFEC; 268 269 // If FEC is enabled, update minRate with FEC+downspread overhead. 270 minRate = linkOverhead(peakRate); 271 } 272 273 LinkConfiguration(unsigned long TotalLinkPBN) 274 : enhancedFraming(true), 275 multistream(true), 276 disablePostLTRequest(false), 277 bEnableFEC(false), 278 bDisableLTTPR(false), 279 linkTrainCounter(0) 280 { 281 // Reverse engineer a link configuration from Total TotalLinkPBN 282 // Note that HBR2 twice HBR. The table below treats HBR2x1 and HBRx2, etc. 283 284 // 285 // BW Effective Lanes Total TotalLinkPBN 286 // 165 1 195.5555556 287 // 165 2 391.1111111 288 // 165 4 782.2222222 289 // 270 1 320 290 // 270 2 640 291 // 270 4 1280 292 // 270 8 2560 293 // 294 295 if (TotalLinkPBN <= 90) 296 peakRatePossible = peakRate = RBR, minRate = linkOverhead(RBR), lanes=0; // FAIL 297 if (TotalLinkPBN <= 195) 298 peakRatePossible = peakRate = RBR, minRate = linkOverhead(RBR), lanes=1; 299 else if (TotalLinkPBN <= 320) 300 peakRatePossible = peakRate = HBR, minRate=linkOverhead(HBR), lanes = 1; 301 else if (TotalLinkPBN <= 391) 302 peakRatePossible = peakRate = RBR, minRate=linkOverhead(RBR), lanes = 2; 303 else if (TotalLinkPBN <= 640) 304 peakRatePossible = peakRate = HBR, minRate=linkOverhead(HBR), lanes = 2; // could be HBR2x1, but TotalLinkPBN works out same 305 else if (TotalLinkPBN <= 782) 306 peakRatePossible = peakRate = RBR, minRate=linkOverhead(RBR), lanes = 4; 307 else if (TotalLinkPBN <= 960) 308 peakRatePossible = peakRate = HBR3, minRate=linkOverhead(HBR3), lanes = 1; 309 else if (TotalLinkPBN <= 1280) 310 peakRatePossible = peakRate = HBR, minRate=linkOverhead(HBR), lanes = 4; // could be HBR2x2 311 else if (TotalLinkPBN <= 1920) 312 peakRatePossible = peakRate = HBR3, minRate=linkOverhead(HBR3), lanes = 2; // could be HBR2x 313 else if (TotalLinkPBN <= 2560) 314 peakRatePossible = peakRate = HBR2, minRate=linkOverhead(HBR2), lanes = 4; 315 else if (TotalLinkPBN <= 3840) 316 peakRatePossible = peakRate = HBR3, minRate=linkOverhead(HBR3), lanes = 4; 317 else { 318 peakRatePossible = peakRate = RBR, minRate = linkOverhead(RBR), lanes = 0; // FAIL 319 DP_ASSERT(0 && "Unknown configuration"); 320 } 321 } 322 323 void setEnhancedFraming(bool newEnhancedFraming) 324 { 325 enhancedFraming = newEnhancedFraming; 326 } 327 328 bool isValid() 329 { 330 return lanes != laneCount_0; 331 } 332 333 bool lowerConfig(bool bReduceLaneCnt = false) 334 { 335 // 336 // TODO: bReduceLaneCnt is set to fallback to 4 lanes with lower 337 // valid link rate. But we should reset to max lane count 338 // sink supports instead. 339 // 340 341 LinkRate lowerRate = policy.getLinkRates()->getLowerRate(peakRate); 342 343 if(bReduceLaneCnt) 344 { 345 // Reduce laneCount before reducing linkRate 346 if(lanes == laneCount_1) 347 { 348 if (lowerRate) 349 { 350 lanes = laneCount_4; 351 peakRate = lowerRate; 352 } 353 else 354 { 355 lanes = laneCount_0; 356 } 357 } 358 else 359 { 360 lanes /= 2; 361 } 362 } 363 else 364 { 365 // Reduce the link rate instead of lane count 366 if (lowerRate) 367 { 368 peakRate = lowerRate; 369 } 370 else 371 { 372 lanes /= 2; 373 } 374 } 375 376 minRate = linkOverhead(peakRate); 377 378 return lanes != laneCount_0; 379 } 380 381 void setLaneRate(LinkRate newRate, unsigned newLanes) 382 { 383 peakRate = newRate; 384 lanes = newLanes; 385 minRate = linkOverhead(peakRate); 386 } 387 388 unsigned pbnTotal() 389 { 390 return PBNForSlots(totalUsableTimeslots); 391 } 392 393 void pbnRequired(const ModesetInfo & modesetInfo, unsigned & base_pbn, unsigned & slots, unsigned & slots_pbn) 394 { 395 base_pbn = pbnForMode(modesetInfo); 396 if (bEnableFEC) 397 { 398 // IF FEC is enabled, we need to consider 3% overhead as per DP1.4 spec. 399 base_pbn = (NvU32)(divide_ceil(base_pbn * 100, 97)); 400 } 401 slots = slotsForPBN(base_pbn); 402 slots_pbn = PBNForSlots(slots); 403 } 404 405 NvU32 slotsForPBN(NvU32 allocatedPBN, bool usable = false) 406 { 407 NvU64 bytes_per_pbn = 54 * 1000000 / 64; // this comes out exact 408 NvU64 bytes_per_timeslot = peakRate * lanes / 64; 409 410 if (bytes_per_timeslot == 0) 411 return (NvU32)-1; 412 413 if (usable) 414 { 415 // round down to find the usable integral slots for a given value of PBN. 416 NvU32 slots = (NvU32)divide_floor(allocatedPBN * bytes_per_pbn, bytes_per_timeslot); 417 DP_ASSERT(slots <= 64); 418 419 return slots; 420 } 421 else 422 return (NvU32)divide_ceil(allocatedPBN * bytes_per_pbn, bytes_per_timeslot); 423 } 424 425 NvU32 PBNForSlots(NvU32 slots) // Rounded down 426 { 427 NvU64 bytes_per_pbn = 54 * 1000000 / 64; // this comes out exact 428 NvU64 bytes_per_timeslot = peakRate * lanes / 64; 429 430 return (NvU32)(bytes_per_timeslot * slots/ bytes_per_pbn); 431 } 432 433 bool operator!= (const LinkConfiguration & right) const 434 { 435 return !(*this == right); 436 } 437 438 bool operator== (const LinkConfiguration & right) const 439 { 440 return (this->lanes == right.lanes && 441 this->peakRate == right.peakRate && 442 this->enhancedFraming == right.enhancedFraming && 443 this->multistream == right.multistream && 444 this->bEnableFEC == right.bEnableFEC); 445 } 446 447 bool operator< (const LinkConfiguration & right) const 448 { 449 NvU64 leftMKBps = peakRate * lanes; 450 NvU64 rightMKBps = right.peakRate * right.lanes; 451 452 if (leftMKBps == rightMKBps) 453 { 454 return (lanes < right.lanes); 455 } 456 else 457 { 458 return (leftMKBps < rightMKBps); 459 } 460 } 461 }; 462 } 463 #endif //INCLUDED_DP_LINKCONFIG_H 464