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