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