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