1 /* 2 * SPDX-FileCopyrightText: Copyright (c) 2010-2023 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 namespace DisplayPort 40 { 41 typedef NvU64 LinkRate; 42 43 class LinkRates : virtual public Object 44 { 45 public: 46 NvU8 entries; 47 48 virtual void clear() = 0; 49 virtual bool import(NvU8 linkBw) 50 { 51 DP_ASSERT(0); 52 return false; 53 } 54 55 virtual LinkRate getLowerRate(LinkRate rate) = 0; 56 virtual LinkRate getMaxRate() = 0; 57 virtual NvU8 getNumElements() = 0; 58 59 NvU8 getNumLinkRates() 60 { 61 return entries; 62 } 63 64 }; 65 66 class LinkRates1x : virtual public LinkRates 67 { 68 public: 69 // Store link rate in multipler of 270MBPS to save space 70 NvU8 element[NV_SUPPORTED_DP1X_LINK_RATES__SIZE]; 71 72 LinkRates1x() 73 { 74 entries = 0; 75 for (int i = 0; i < NV_SUPPORTED_DP1X_LINK_RATES__SIZE; i++) 76 { 77 element[i] = 0; 78 } 79 } 80 81 virtual void clear() 82 { 83 entries = 0; 84 for (int i = 0; i < NV_SUPPORTED_DP1X_LINK_RATES__SIZE; i++) 85 { 86 element[i] = 0; 87 } 88 } 89 90 virtual bool import(NvU8 linkBw) 91 { 92 if (!IS_VALID_LINKBW(linkBw)) 93 { 94 DP_ASSERT(0 && "Unsupported Link Bandwidth"); 95 return false; 96 } 97 98 if (entries < NV_SUPPORTED_DP1X_LINK_RATES__SIZE) 99 { 100 element[entries] = linkBw; 101 entries++; 102 return true; 103 } 104 else 105 return false; 106 } 107 108 virtual LinkRate getLowerRate(LinkRate rate) 109 { 110 int i; 111 NvU8 linkBw = (NvU8)(rate / DP_LINK_BW_FREQ_MULTI_MBPS); 112 113 if ((entries == 0) || (linkBw <= element[0])) 114 return 0; 115 116 for (i = entries - 1; i > 0; i--) 117 { 118 if (linkBw > element[i]) 119 break; 120 } 121 122 rate = (LinkRate)element[i] * DP_LINK_BW_FREQ_MULTI_MBPS; 123 return rate; 124 } 125 126 virtual LinkRate getMaxRate() 127 { 128 LinkRate rate = 0; 129 if ((entries > 0) && 130 (entries <= NV_SUPPORTED_DP1X_LINK_RATES__SIZE)) 131 { 132 rate = (LinkRate)element[entries - 1] * DP_LINK_BW_FREQ_MULTI_MBPS; 133 } 134 135 return rate; 136 } 137 virtual NvU8 getNumElements() 138 { 139 return NV_SUPPORTED_DP1X_LINK_RATES__SIZE; 140 } 141 142 }; 143 144 class LinkPolicy : virtual public Object 145 { 146 protected: 147 bool bNoFallback; // No fallback when LT fails 148 LinkRates1x linkRates; 149 public: 150 LinkPolicy() : bNoFallback(false) 151 { 152 } 153 bool skipFallback() 154 { 155 return bNoFallback; 156 } 157 void setSkipFallBack(bool bSkipFallback) 158 { 159 bNoFallback = bSkipFallback; 160 } 161 162 LinkRates *getLinkRates() 163 { 164 return &linkRates; 165 } 166 }; 167 168 enum 169 { 170 totalTimeslots = 64, 171 totalUsableTimeslots = totalTimeslots - 1 172 }; 173 174 // 175 // Link Data Rate per DP Lane, in MBPS, 176 // For 8b/10b channel coding: 177 // Link Data Rate = link rate * (8 / 10) / 8 178 // = link rate * 0.1 179 // For 128b/132b channel coding: 180 // Link Data Rate = link rate * (128 / 132) / 8 181 // = link rate * 4 / 33 182 // ~= link rate * 0.12 183 // 184 // Link Bandwidth = Lane Count * Link Data Rate 185 // 186 enum 187 { 188 RBR = 162000000, 189 EDP_2_16GHZ = 216000000, 190 EDP_2_43GHZ = 243000000, 191 HBR = 270000000, 192 EDP_3_24GHZ = 324000000, 193 EDP_4_32GHZ = 432000000, 194 HBR2 = 540000000, 195 HBR3 = 810000000 196 }; 197 198 struct HDCPState 199 { 200 bool HDCP_State_Encryption; 201 bool HDCP_State_1X_Capable; 202 bool HDCP_State_22_Capable; 203 bool HDCP_State_Authenticated; 204 bool HDCP_State_Repeater_Capable; 205 }; 206 207 struct HDCPValidateData 208 { 209 }; 210 211 typedef enum 212 { 213 DP_SINGLE_HEAD_MULTI_STREAM_MODE_NONE, 214 DP_SINGLE_HEAD_MULTI_STREAM_MODE_SST, 215 DP_SINGLE_HEAD_MULTI_STREAM_MODE_MST, 216 }DP_SINGLE_HEAD_MULTI_STREAM_MODE; 217 218 #define HEAD_INVALID_STREAMS 0 219 #define HEAD_DEFAULT_STREAMS 1 220 221 typedef enum 222 { 223 DP_SINGLE_HEAD_MULTI_STREAM_PIPELINE_ID_PRIMARY = 0, 224 DP_SINGLE_HEAD_MULTI_STREAM_PIPELINE_ID_SECONDARY = 1, 225 DP_SINGLE_HEAD_MULTI_STREAM_PIPELINE_ID_MAX = DP_SINGLE_HEAD_MULTI_STREAM_PIPELINE_ID_SECONDARY, 226 } DP_SINGLE_HEAD_MULTI_STREAM_PIPELINE_ID; 227 228 #define DP_INVALID_SOR_INDEX 0xFFFFFFFF 229 #define DSC_DEPTH_FACTOR 16 230 231 232 class LinkConfiguration : virtual public Object 233 { 234 public: 235 LinkPolicy policy; 236 unsigned lanes; 237 LinkRate peakRatePossible; 238 LinkRate peakRate; 239 LinkRate minRate; 240 bool enhancedFraming; 241 bool multistream; 242 bool disablePostLTRequest; 243 bool bEnableFEC; 244 bool bDisableLTTPR; 245 246 // 247 // The counter to record how many times link training happens. 248 // Client can reset the counter by calling setLTCounter(0) 249 // 250 unsigned linkTrainCounter; 251 252 LinkConfiguration() : 253 lanes(0), peakRatePossible(0), peakRate(0), minRate(0), 254 enhancedFraming(false), multistream(false), disablePostLTRequest(false), 255 bEnableFEC(false), bDisableLTTPR(false), linkTrainCounter(0) {}; 256 257 LinkConfiguration(LinkPolicy * p, unsigned lanes, LinkRate peakRate, 258 bool enhancedFraming, bool MST, bool disablePostLTRequest = false, 259 bool bEnableFEC = false, bool bDisableLTTPR = false) : 260 lanes(lanes), peakRatePossible(peakRate), peakRate(peakRate), 261 enhancedFraming(enhancedFraming), multistream(MST), 262 disablePostLTRequest(disablePostLTRequest), 263 bEnableFEC(bEnableFEC), bDisableLTTPR(bDisableLTTPR), 264 linkTrainCounter(0) 265 { 266 // downrate for spread and FEC 267 minRate = linkOverhead(peakRate); 268 if (p) 269 { 270 policy = *p; 271 } 272 } 273 274 void setLTCounter(unsigned counter) 275 { 276 linkTrainCounter = counter; 277 } 278 279 unsigned getLTCounter() 280 { 281 return linkTrainCounter; 282 } 283 284 NvU64 linkOverhead(NvU64 rate) 285 { 286 if(bEnableFEC) 287 { 288 289 // if FEC is enabled, we have to account for 3% overhead 290 // for FEC+downspread according to DP 1.4 spec 291 292 return rate - 3 * rate/ 100; 293 } 294 else 295 { 296 // if FEC is not enabled, link overhead comprises only of 297 // 0.05% downspread. 298 return rate - 5 * rate/ 1000; 299 300 } 301 } 302 303 void enableFEC(bool setFEC) 304 { 305 bEnableFEC = setFEC; 306 307 // If FEC is enabled, update minRate with FEC+downspread overhead. 308 minRate = linkOverhead(peakRate); 309 } 310 311 LinkConfiguration(unsigned long TotalLinkPBN) 312 : enhancedFraming(true), 313 multistream(true), 314 disablePostLTRequest(false), 315 bEnableFEC(false), 316 bDisableLTTPR(false), 317 linkTrainCounter(0) 318 { 319 // Reverse engineer a link configuration from Total TotalLinkPBN 320 // Note that HBR2 twice HBR. The table below treats HBR2x1 and HBRx2, etc. 321 322 // 323 // BW Effective Lanes Total TotalLinkPBN 324 // 165 1 195.5555556 325 // 165 2 391.1111111 326 // 165 4 782.2222222 327 // 270 1 320 328 // 270 2 640 329 // 270 4 1280 330 // 270 8 2560 331 // 332 333 if (TotalLinkPBN <= 90) 334 peakRatePossible = peakRate = RBR, minRate = linkOverhead(RBR), lanes=0; // FAIL 335 if (TotalLinkPBN <= 195) 336 peakRatePossible = peakRate = RBR, minRate = linkOverhead(RBR), lanes=1; 337 else if (TotalLinkPBN <= 320) 338 peakRatePossible = peakRate = HBR, minRate=linkOverhead(HBR), lanes = 1; 339 else if (TotalLinkPBN <= 391) 340 peakRatePossible = peakRate = RBR, minRate=linkOverhead(RBR), lanes = 2; 341 else if (TotalLinkPBN <= 640) 342 peakRatePossible = peakRate = HBR, minRate=linkOverhead(HBR), lanes = 2; // could be HBR2x1, but TotalLinkPBN works out same 343 else if (TotalLinkPBN <= 782) 344 peakRatePossible = peakRate = RBR, minRate=linkOverhead(RBR), lanes = 4; 345 else if (TotalLinkPBN <= 960) 346 peakRatePossible = peakRate = HBR3, minRate=linkOverhead(HBR3), lanes = 1; 347 else if (TotalLinkPBN <= 1280) 348 peakRatePossible = peakRate = HBR, minRate=linkOverhead(HBR), lanes = 4; // could be HBR2x2 349 else if (TotalLinkPBN <= 1920) 350 peakRatePossible = peakRate = HBR3, minRate=linkOverhead(HBR3), lanes = 2; // could be HBR2x 351 else if (TotalLinkPBN <= 2560) 352 peakRatePossible = peakRate = HBR2, minRate=linkOverhead(HBR2), lanes = 4; 353 else if (TotalLinkPBN <= 3840) 354 peakRatePossible = peakRate = HBR3, minRate=linkOverhead(HBR3), lanes = 4; 355 else { 356 peakRatePossible = peakRate = RBR, minRate = linkOverhead(RBR), lanes = 0; // FAIL 357 DP_ASSERT(0 && "Unknown configuration"); 358 } 359 } 360 361 void setEnhancedFraming(bool newEnhancedFraming) 362 { 363 enhancedFraming = newEnhancedFraming; 364 } 365 366 bool isValid() 367 { 368 return lanes != laneCount_0; 369 } 370 371 bool lowerConfig(bool bReduceLaneCnt = false) 372 { 373 // 374 // TODO: bReduceLaneCnt is set to fallback to 4 lanes with lower 375 // valid link rate. But we should reset to max lane count 376 // sink supports instead. 377 // 378 379 LinkRate lowerRate = policy.getLinkRates()->getLowerRate(peakRate); 380 381 if(bReduceLaneCnt) 382 { 383 // Reduce laneCount before reducing linkRate 384 if(lanes == laneCount_1) 385 { 386 if (lowerRate) 387 { 388 lanes = laneCount_4; 389 peakRate = lowerRate; 390 } 391 else 392 { 393 lanes = laneCount_0; 394 } 395 } 396 else 397 { 398 lanes /= 2; 399 } 400 } 401 else 402 { 403 // Reduce the link rate instead of lane count 404 if (lowerRate) 405 { 406 peakRate = lowerRate; 407 } 408 else 409 { 410 lanes /= 2; 411 } 412 } 413 414 minRate = linkOverhead(peakRate); 415 416 return lanes != laneCount_0; 417 } 418 419 void setLaneRate(LinkRate newRate, unsigned newLanes) 420 { 421 peakRate = newRate; 422 lanes = newLanes; 423 minRate = linkOverhead(peakRate); 424 } 425 426 unsigned pbnTotal() 427 { 428 return PBNForSlots(totalUsableTimeslots); 429 } 430 431 void pbnRequired(const ModesetInfo & modesetInfo, unsigned & base_pbn, unsigned & slots, unsigned & slots_pbn) 432 { 433 base_pbn = pbnForMode(modesetInfo); 434 if (bEnableFEC) 435 { 436 // IF FEC is enabled, we need to consider 3% overhead as per DP1.4 spec. 437 base_pbn = (NvU32)(divide_ceil(base_pbn * 100, 97)); 438 } 439 slots = slotsForPBN(base_pbn); 440 slots_pbn = PBNForSlots(slots); 441 } 442 443 NvU32 slotsForPBN(NvU32 allocatedPBN, bool usable = false) 444 { 445 NvU64 bytes_per_pbn = 54 * 1000000 / 64; // this comes out exact 446 NvU64 bytes_per_timeslot = peakRate * lanes / 64; 447 448 if (bytes_per_timeslot == 0) 449 return (NvU32)-1; 450 451 if (usable) 452 { 453 // round down to find the usable integral slots for a given value of PBN. 454 NvU32 slots = (NvU32)divide_floor(allocatedPBN * bytes_per_pbn, bytes_per_timeslot); 455 DP_ASSERT(slots <= 64); 456 457 return slots; 458 } 459 else 460 return (NvU32)divide_ceil(allocatedPBN * bytes_per_pbn, bytes_per_timeslot); 461 } 462 463 NvU32 PBNForSlots(NvU32 slots) // Rounded down 464 { 465 NvU64 bytes_per_pbn = 54 * 1000000 / 64; // this comes out exact 466 NvU64 bytes_per_timeslot = peakRate * lanes / 64; 467 468 return (NvU32)(bytes_per_timeslot * slots/ bytes_per_pbn); 469 } 470 471 bool operator!= (const LinkConfiguration & right) const 472 { 473 return !(*this == right); 474 } 475 476 bool operator== (const LinkConfiguration & right) const 477 { 478 return (this->lanes == right.lanes && 479 this->peakRate == right.peakRate && 480 this->enhancedFraming == right.enhancedFraming && 481 this->multistream == right.multistream && 482 this->bEnableFEC == right.bEnableFEC); 483 } 484 485 bool operator< (const LinkConfiguration & right) const 486 { 487 NvU64 leftMKBps = peakRate * lanes; 488 NvU64 rightMKBps = right.peakRate * right.lanes; 489 490 if (leftMKBps == rightMKBps) 491 { 492 return (lanes < right.lanes); 493 } 494 else 495 { 496 return (leftMKBps < rightMKBps); 497 } 498 } 499 }; 500 } 501 #endif //INCLUDED_DP_LINKCONFIG_H 502