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 namespace DisplayPort 40 { 41 typedef NvU64 LinkRate; 42 43 class LinkRates : virtual public Object 44 { 45 public: 46 // Store link rate in multipler of 270MBPS to save space 47 NvU8 element[NV_DPCD_SUPPORTED_LINK_RATES__SIZE]; 48 NvU8 entries; 49 50 LinkRates() 51 { 52 entries = 0; 53 54 for (int i = 0; i < NV_DPCD_SUPPORTED_LINK_RATES__SIZE; i++) 55 { 56 element[i] = 0; 57 } 58 } 59 60 void clear() 61 { 62 entries = 0; 63 for (int i = 0; i < NV_DPCD_SUPPORTED_LINK_RATES__SIZE; i++) 64 { 65 element[i] = 0; 66 } 67 } 68 69 bool import(NvU8 linkBw) 70 { 71 if (entries < NV_DPCD_SUPPORTED_LINK_RATES__SIZE) 72 { 73 element[entries] = linkBw; 74 entries++; 75 return true; 76 } 77 else 78 return false; 79 } 80 81 NvU8 getNumLinkRates() 82 { 83 return entries; 84 } 85 86 LinkRate getLowerRate(LinkRate rate) 87 { 88 int i; 89 NvU8 linkBw = (NvU8)(rate / DP_LINK_BW_FREQ_MULTI_MBPS); 90 91 if ((entries == 0) || (linkBw <= element[0])) 92 return 0; 93 94 for (i = entries - 1; i > 0; i--) 95 { 96 if (linkBw > element[i]) 97 break; 98 } 99 100 rate = (LinkRate)element[i] * DP_LINK_BW_FREQ_MULTI_MBPS; 101 return rate; 102 } 103 104 LinkRate getMaxRate() 105 { 106 LinkRate rate = 0; 107 if ((entries > 0) && 108 (entries <= NV_DPCD_SUPPORTED_LINK_RATES__SIZE)) 109 { 110 rate = (LinkRate)element[entries - 1] * DP_LINK_BW_FREQ_MULTI_MBPS; 111 } 112 113 return rate; 114 } 115 }; 116 117 class LinkPolicy : virtual public Object 118 { 119 bool bNoFallback; // No fallback when LT fails 120 LinkRates linkRates; 121 122 public: 123 LinkPolicy() : bNoFallback(false) 124 { 125 } 126 bool skipFallback() 127 { 128 return bNoFallback; 129 } 130 void setSkipFallBack(bool bSkipFallback) 131 { 132 bNoFallback = bSkipFallback; 133 } 134 135 LinkRates *getLinkRates() 136 { 137 return &linkRates; 138 } 139 }; 140 enum 141 { 142 totalTimeslots = 64, 143 totalUsableTimeslots = totalTimeslots - 1 144 }; 145 146 // in MBps 147 enum 148 { 149 RBR = 162000000, 150 EDP_2_16GHZ = 216000000, 151 EDP_2_43GHZ = 243000000, 152 HBR = 270000000, 153 EDP_3_24GHZ = 324000000, 154 EDP_4_32GHZ = 432000000, 155 HBR2 = 540000000, 156 EDP_6_75GHZ = 675000000, 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