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;
import(NvU8 linkBw)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 
getNumLinkRates()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 
LinkRates1x()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 
clear()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 
import(NvU8 linkBw)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 
getLowerRate(LinkRate rate)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 
getMaxRate()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         }
getNumElements()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:
LinkPolicy()150         LinkPolicy() : bNoFallback(false)
151         {
152         }
skipFallback()153         bool skipFallback()
154         {
155             return bNoFallback;
156         }
setSkipFallBack(bool bSkipFallback)157         void setSkipFallBack(bool bSkipFallback)
158         {
159             bNoFallback = bSkipFallback;
160         }
161 
getLinkRates()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         // The counter to record how many times link training happens.
247         // Client can reset the counter by calling setLTCounter(0)
248         //
249         unsigned linkTrainCounter;
250 
LinkConfiguration()251         LinkConfiguration() :
252             lanes(0), peakRatePossible(0), peakRate(0), minRate(0),
253             enhancedFraming(false), multistream(false), disablePostLTRequest(false),
254             bEnableFEC(false), bDisableLTTPR(false),
255             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) :
lanes(lanes)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 
setLTCounter(unsigned counter)274         void setLTCounter(unsigned counter)
275         {
276             linkTrainCounter = counter;
277         }
278 
getLTCounter()279         unsigned getLTCounter()
280         {
281             return linkTrainCounter;
282         }
283 
linkOverhead(NvU64 rate)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.6% downspread.
298                 return rate - 6 * rate/ 1000;
299 
300             }
301         }
302 
enableFEC(bool setFEC)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 
LinkConfiguration(unsigned long TotalLinkPBN)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             //
320             // Reverse engineer a link configuration from Total TotalLinkPBN
321             // Note that HBR2 twice HBR. The table below treats HBR2x1 and HBRx2, etc.
322             //
323             // PBN Calculation
324             // Definition of PBN is "54/64 MBps".
325             // Note this is the "data" actually transmitted in the main link.
326             // So we need to take channel coding into consideration.
327             // Formula: PBN = Lane Count * Link Rate (Gbps) * 1000 * (1/8) * ChannelCoding Efficiency * (64 / 54)
328             // Example:
329             // 1. 4 * HBR2:    4 * 5.4 * 1000 * (1/8) * (8/10) * (64/54) = 2560
330             // 2. 2 * UHBR10:  2 * 10 * 1000 * (1/8) * (128/132) * (64/54) = 2873
331             //
332             // Full list:
333             //
334             //   BW (Gbps)        Lanes              TotalLinkPBN
335             //     1.62             1                     192
336             //     1.62             2                     384
337             //     1.62             4                     768
338             //     2.70             1                     320
339             //     2.70             2                     640
340             //     2.70             4                    1280
341             //     5.40             1                     640
342             //     5.40             2                    1280
343             //     5.40             4                    2560
344             //     8.10             1                     960
345             //     8.10             2                    1920
346             //     8.10             4                    3840
347             //    10.00             1                    1436
348             //    10.00             2                    2873
349             //    10.00             4                    5746
350             //    13.50             1                    1939
351             //    13.50             2                    3878
352             //    13.50             4                    7757
353             //    20.00             1                    2873
354             //    20.00             2                    5746
355             //    20.00             4                   11492
356             //
357 
358             if (TotalLinkPBN <= 90)
359             {
360                 peakRatePossible = peakRate = RBR;
361                 minRate = linkOverhead(RBR);
362                 lanes = 0; // FAIL
363             }
364             if (TotalLinkPBN <= 192)
365             {
366                 peakRatePossible = peakRate = RBR;
367                 minRate = linkOverhead(RBR);
368                 lanes = 1;
369             }
370             else if (TotalLinkPBN <= 320)
371             {
372                 peakRatePossible = peakRate = HBR;
373                 minRate = linkOverhead(HBR);
374                 lanes = 1;
375             }
376             else if (TotalLinkPBN <= 384)
377             {
378                 peakRatePossible = peakRate = RBR;
379                 minRate = linkOverhead(RBR);
380                 lanes = 2;
381             }
382             else if (TotalLinkPBN <= 640)
383             {
384                 // could be HBR2 x 1, but TotalLinkPBN works out same
385                 peakRatePossible = peakRate = HBR;
386                 minRate = linkOverhead(HBR);
387                 lanes = 2;
388             }
389             else if (TotalLinkPBN <= 768)
390             {
391                 peakRatePossible = peakRate = RBR;
392                 minRate = linkOverhead(RBR);
393                 lanes = 4;
394             }
395             else if (TotalLinkPBN <= 960)
396             {
397                 peakRatePossible = peakRate = HBR3;
398                 minRate = linkOverhead(HBR3);
399                 lanes = 1;
400             }
401             else if (TotalLinkPBN <= 1280)
402             {
403                 // could be HBR2 x 2
404                 peakRatePossible = peakRate = HBR;
405                 minRate = linkOverhead(HBR);
406                 lanes = 4;
407             }
408             else if (TotalLinkPBN <= 1920)
409             {
410                 peakRatePossible = peakRate = HBR3;
411                 minRate = linkOverhead(HBR3);
412                 lanes = 2;
413             }
414             else if (TotalLinkPBN <= 2560)
415             {
416                 peakRatePossible = peakRate = HBR2;
417                 minRate = linkOverhead(HBR2);
418                 lanes = 4;
419             }
420             else if (TotalLinkPBN <= 3840)
421             {
422                 peakRatePossible = peakRate = HBR3;
423                 minRate = linkOverhead(HBR3);
424                 lanes = 4;
425             }
426             else {
427                 peakRatePossible = peakRate = RBR, minRate = linkOverhead(RBR), lanes = 0; // FAIL
428                 DP_ASSERT(0 && "Unknown configuration");
429             }
430         }
431 
setEnhancedFraming(bool newEnhancedFraming)432         void setEnhancedFraming(bool newEnhancedFraming)
433         {
434             enhancedFraming = newEnhancedFraming;
435         }
436 
isValid()437         bool isValid()
438         {
439             return lanes != laneCount_0;
440         }
441 
442         bool lowerConfig(bool bReduceLaneCnt = false)
443         {
444             //
445             // TODO: bReduceLaneCnt is set to fallback to 4 lanes with lower
446             //       valid link rate. But we should reset to max lane count
447             //       sink supports instead.
448             //
449 
450             LinkRate lowerRate = policy.getLinkRates()->getLowerRate(peakRate);
451 
452             if(bReduceLaneCnt)
453             {
454                 // Reduce laneCount before reducing linkRate
455                 if(lanes == laneCount_1)
456                 {
457                     if (lowerRate)
458                     {
459                         lanes = laneCount_4;
460                         peakRate = lowerRate;
461                     }
462                     else
463                     {
464                         lanes = laneCount_0;
465                     }
466                 }
467                 else
468                 {
469                     lanes /= 2;
470                 }
471             }
472             else
473             {
474                 // Reduce the link rate instead of lane count
475                 if (lowerRate)
476                 {
477                     peakRate = lowerRate;
478                 }
479                 else
480                 {
481                     lanes /= 2;
482                 }
483             }
484 
485             minRate = linkOverhead(peakRate);
486             return lanes != laneCount_0;
487         }
488 
setLaneRate(LinkRate newRate,unsigned newLanes)489         void setLaneRate(LinkRate newRate, unsigned newLanes)
490         {
491             peakRate  = newRate;
492             lanes = newLanes;
493             minRate = linkOverhead(peakRate);
494         }
495 
pbnTotal()496         unsigned pbnTotal()
497         {
498             return PBNForSlots(totalUsableTimeslots);
499         }
500 
pbnRequired(const ModesetInfo & modesetInfo,unsigned & base_pbn,unsigned & slots,unsigned & slots_pbn)501         void pbnRequired(const ModesetInfo & modesetInfo, unsigned & base_pbn, unsigned & slots, unsigned & slots_pbn)
502         {
503             base_pbn = pbnForMode(modesetInfo);
504             if (bEnableFEC)
505             {
506                 // IF FEC is enabled, we need to consider 3% overhead as per DP1.4 spec.
507                 base_pbn = (NvU32)(divide_ceil(base_pbn * 100, 97));
508             }
509             slots = slotsForPBN(base_pbn);
510             slots_pbn = PBNForSlots(slots);
511         }
512 
513         NvU32 slotsForPBN(NvU32 allocatedPBN, bool usable = false)
514         {
515             NvU64 bytes_per_pbn      = 54 * 1000000 / 64;     // this comes out exact
516             NvU64 bytes_per_timeslot = peakRate * lanes / 64;
517 
518             if (bytes_per_timeslot == 0)
519                 return (NvU32)-1;
520 
521             if (usable)
522             {
523                 // round down to find the usable integral slots for a given value of PBN.
524                 NvU32 slots = (NvU32)divide_floor(allocatedPBN * bytes_per_pbn, bytes_per_timeslot);
525                 DP_ASSERT(slots <= 64);
526 
527                 return slots;
528             }
529             else
530                 return (NvU32)divide_ceil(allocatedPBN * bytes_per_pbn, bytes_per_timeslot);
531         }
532 
PBNForSlots(NvU32 slots)533         NvU32 PBNForSlots(NvU32 slots)                      // Rounded down
534         {
535             NvU64 bytes_per_pbn      = 54 * 1000000 / 64;     // this comes out exact
536             NvU64 bytes_per_timeslot = peakRate * lanes / 64;
537 
538             return (NvU32)(bytes_per_timeslot * slots/ bytes_per_pbn);
539         }
540 
541         bool operator!= (const LinkConfiguration & right) const
542         {
543             return !(*this == right);
544         }
545 
546         bool operator== (const LinkConfiguration & right) const
547         {
548             return (this->lanes == right.lanes &&
549                     this->peakRate == right.peakRate &&
550                     this->enhancedFraming == right.enhancedFraming &&
551                     this->multistream == right.multistream &&
552                     this->bEnableFEC == right.bEnableFEC);
553         }
554 
555         bool operator< (const LinkConfiguration & right) const
556         {
557             NvU64 leftMKBps = peakRate * lanes;
558             NvU64 rightMKBps = right.peakRate * right.lanes;
559 
560             if (leftMKBps == rightMKBps)
561             {
562                 return (lanes < right.lanes);
563             }
564             else
565             {
566                 return (leftMKBps < rightMKBps);
567             }
568         }
569     };
570 }
571 #endif //INCLUDED_DP_LINKCONFIG_H
572