1 //*****************************************************************************
2 //
3 //  SPDX-FileCopyrightText: Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
4 //  SPDX-License-Identifier: MIT
5 //
6 //  Permission is hereby granted, free of charge, to any person obtaining a
7 //  copy of this software and associated documentation files (the "Software"),
8 //  to deal in the Software without restriction, including without limitation
9 //  the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 //  and/or sell copies of the Software, and to permit persons to whom the
11 //  Software is furnished to do so, subject to the following conditions:
12 //
13 //  The above copyright notice and this permission notice shall be included in
14 //  all copies or substantial portions of the Software.
15 //
16 //  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 //  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 //  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 //  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 //  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 //  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 //  DEALINGS IN THE SOFTWARE.
23 //
24 //  File:       nvt_edid.c
25 //
26 //  Purpose:    the provide edid related services
27 //
28 //*****************************************************************************
29 
30 #include "nvBinSegment.h"
31 #include "nvmisc.h"
32 
33 #include "edid.h"
34 
35 
36 
37 PUSH_SEGMENTS
38 
39 // Macro to declare a TIMING initializer for given parameters without border
40 #define EST_TIMING(hv,hfp,hsw,ht,hsp,vv,vfp,vsw,vt,vsp,rr,pclk,format) \
41 {hv,0,hfp,hsw,ht,(hsp)=='-',vv,0,vfp,vsw,vt,(vsp)=='-',NVT_PROGRESSIVE,pclk,{0,rr,set_rrx1k(pclk,ht,vt),0,1,{0},{0},{0},{0},format,"VESA Established"}}
42 
43 DATA_SEGMENT(PAGE_DATA)
44 #if !defined(NV_WSA)
45 CONS_SEGMENT(PAGE_CONS)
46 #endif // wsa
47 
48 // There is a large table of strings that translate 3-character PNP vendor IDs to a more user-friendly name in the following header.
49 // Mark this constant table as pageable.
50 #include "nvPNPVendorIds.h"
51 
52 static const NVT_TIMING EDID_EST[] =
53 {
54     EST_TIMING( 720, 0,  0, 720,'-', 400, 0,0, 400,'-',70,    0,NVT_STATUS_EDID_EST), // 720x400x70Hz   (IBM, VGA)
55     EST_TIMING( 720, 0,  0, 720,'-', 400, 0,0, 400,'-',88,    0,NVT_STATUS_EDID_EST), // 720x400x88Hz   (IBM, XGA2)
56     {640,0,16,96,800,NVT_H_SYNC_NEGATIVE,480,0,10,2,525,NVT_V_SYNC_NEGATIVE,NVT_PROGRESSIVE,2518,{0,60,60000,0,1,{0},{0},{0},{0},NVT_STATUS_EDID_EST,"EDID_Established"}},
57 
58     EST_TIMING( 640, 0,  0, 640,'-', 480, 0,0, 480,'-',67,    0,NVT_STATUS_EDID_EST), // 640x480x67Hz   (Apple, Mac II)
59 
60     // 640x480x72Hz (VESA) - this entry have borders
61     {640,8,16,40,832,NVT_H_SYNC_NEGATIVE,480,8,1,3,520,NVT_V_SYNC_NEGATIVE,NVT_PROGRESSIVE,3150,{0,72,72000,0,1,{0},{0},{0},{0},NVT_STATUS_EDID_EST,"EDID_Established"}},
62     EST_TIMING( 640,16, 64, 840,'-', 480, 1,3, 500,'-',75, 3150,NVT_STATUS_EDID_EST), // 640x480x75Hz   (VESA)
63     EST_TIMING( 800,24, 72,1024,'+', 600, 1,2, 625,'+',56, 3600,NVT_STATUS_EDID_EST), // 800x600x56Hz   (VESA)
64     EST_TIMING( 800,40,128,1056,'+', 600, 1,4, 628,'+',60, 4000,NVT_STATUS_EDID_EST), // 800x600x60Hz   (VESA)
65 
66     EST_TIMING( 800,56,120,1040,'+', 600,37,6, 666,'+',72, 5000,NVT_STATUS_EDID_EST), // 800x600x72Hz   (VESA)
67     EST_TIMING( 800,16, 80,1056,'+', 600, 1,3, 625,'+',75, 4950,NVT_STATUS_EDID_EST), // 800x600x75Hz   (VESA)
68     EST_TIMING( 832, 0,  0, 832,'-', 624, 0,0, 624,'-',75,    0,NVT_STATUS_EDID_EST), // 832x624x75Hz   (Apple, Mac II)
69     EST_TIMING(1024, 0,  0,1024,'-', 768, 0,0, 768,'-',87,    0,NVT_STATUS_EDID_EST), // 1024x768x87Hz  (IBM, Interlaced)
70 
71     EST_TIMING(1024,24,136,1344,'-', 768, 3,6, 806,'-',60, 6500,NVT_STATUS_EDID_EST), // 1024x768x60Hz  (VESA)
72     EST_TIMING(1024,24,136,1328,'-', 768, 3,6, 806,'-',70, 7500,NVT_STATUS_EDID_EST), // 1024x768x70Hz  (VESA)
73     EST_TIMING(1024,16, 96,1312,'+', 768, 1,3, 800,'+',75, 7875,NVT_STATUS_EDID_EST), // 1024x768x75Hz  (VESA)
74     EST_TIMING(1280,16,144,1688,'+',1024, 1,3,1066,'+',75,13500,NVT_STATUS_EDID_EST), // 1280x1024x75Hz (VESA)
75 
76     // the end
77     NVT_TIMING_SENTINEL
78 };
79 
80 static NvU32 MAX_EST_FORMAT = sizeof(EDID_EST)/sizeof(EDID_EST[0]) - 1;
81 
82 static const NVT_TIMING EDID_ESTIII[] =
83 {
84     EST_TIMING( 640, 32, 64, 832,'+', 350,32,3, 445,'-',85, 3150,NVT_STATUS_EDID_EST), // 640x350x85Hz
85     EST_TIMING( 640, 32, 64, 832,'-', 400, 1,3, 445,'+',85, 3150,NVT_STATUS_EDID_EST), // 640x400x85Hz
86     EST_TIMING( 720, 36, 72, 936,'-', 400, 1,3, 446,'+',85, 3550,NVT_STATUS_EDID_EST), // 720x400x85Hz
87     EST_TIMING( 640, 56, 56, 832,'-', 480, 1,3, 509,'-',85, 3600,NVT_STATUS_EDID_EST), // 640x480x85Hz
88     EST_TIMING( 848, 16,112,1088,'+', 480, 6,8, 517,'+',60, 3375,NVT_STATUS_EDID_EST), // 848x480x60HZ
89     EST_TIMING( 800, 32, 64,1048,'+', 600, 1,3, 631,'+',85, 5625,NVT_STATUS_EDID_EST), // 800x600x85Hz
90     EST_TIMING(1024, 48, 96,1376,'+', 768, 1,3, 808,'+',85, 9450,NVT_STATUS_EDID_EST), // 1024x768x85Hz
91     EST_TIMING(1152, 64,128,1600,'+', 864, 1,3, 900,'+',75,10800,NVT_STATUS_EDID_EST), // 1152x864x75Hz
92 
93     EST_TIMING(1280, 48, 32,1440,'+', 768, 3,7, 790,'-',60, 6825,NVT_STATUS_EDID_EST), // 1280x768x60Hz (RB)
94     EST_TIMING(1280, 64,128,1664,'-', 768, 3,7, 798,'+',60, 7950,NVT_STATUS_EDID_EST), // 1280x768x60Hz
95     EST_TIMING(1280, 80,128,1696,'-', 768, 3,7, 805,'+',75,10225,NVT_STATUS_EDID_EST), // 1280x768x75Hz
96     EST_TIMING(1280, 80,136,1712,'-', 768, 3,7, 809,'+',85,11750,NVT_STATUS_EDID_EST), // 1280x768x85Hz
97     EST_TIMING(1280, 96,112,1800,'+', 960, 1,3,1000,'+',60,10800,NVT_STATUS_EDID_EST), // 1280x960x60Hz
98     EST_TIMING(1280, 64,160,1728,'+', 960, 1,3,1011,'+',85,14850,NVT_STATUS_EDID_EST), // 1280x960x85Hz
99     EST_TIMING(1280, 48,112,1688,'+',1024, 1,3,1066,'+',60,10800,NVT_STATUS_EDID_EST), // 1280x1024x60Hz
100     EST_TIMING(1280, 64,160,1728,'+',1024, 1,3,1072,'+',85,15750,NVT_STATUS_EDID_EST), // 1280x1024x85Hz
101 
102     EST_TIMING(1360, 64,112,1792,'+', 768, 3,6, 795,'+',60, 8550,NVT_STATUS_EDID_EST), // 1360x768x60Hz
103     EST_TIMING(1440, 48, 32,1600,'+', 900, 3,6, 926,'-',60, 8875,NVT_STATUS_EDID_EST), // 1440x900x60Hz (RB)
104     EST_TIMING(1440, 80,152,1904,'-', 900, 3,6, 934,'+',60,10650,NVT_STATUS_EDID_EST), // 1440x900x60Hz
105     EST_TIMING(1440, 96,152,1936,'-', 900, 3,6, 942,'+',75,13675,NVT_STATUS_EDID_EST), // 1440x900x75Hz
106     EST_TIMING(1440,104,152,1952,'-', 900, 3,6, 948,'+',85,15700,NVT_STATUS_EDID_EST), // 1440x900x85Hz
107     EST_TIMING(1400, 48, 32,1560,'+',1050, 3,4,1080,'-',60,10100,NVT_STATUS_EDID_EST), // 1440x1050x60Hz (RB)
108     EST_TIMING(1400, 88,144,1864,'-',1050, 3,4,1089,'+',60,12175,NVT_STATUS_EDID_EST), // 1440x1050x60Hz
109     EST_TIMING(1400,104,144,1896,'-',1050, 3,4,1099,'+',75,15600,NVT_STATUS_EDID_EST), // 1440x1050x75Hz
110 
111     EST_TIMING(1400,104,152,1912,'-',1050, 3,4,1105,'+',85,17950,NVT_STATUS_EDID_EST), // 1440x1050x85Hz
112     EST_TIMING(1680, 48, 32,1840,'+',1050, 3,6,1080,'-',60,11900,NVT_STATUS_EDID_EST), // 1680x1050x60Hz (RB)
113     EST_TIMING(1680,104,176,2240,'-',1050, 3,6,1089,'+',60,14625,NVT_STATUS_EDID_EST), // 1680x1050x60Hz
114     EST_TIMING(1680,120,176,2272,'-',1050, 3,6,1099,'+',75,18700,NVT_STATUS_EDID_EST), // 1680x1050x75Hz
115     EST_TIMING(1680,128,176,2288,'-',1050, 3,6,1105,'+',85,21475,NVT_STATUS_EDID_EST), // 1680x1050x85Hz
116     EST_TIMING(1600, 64,192,2160,'+',1200, 1,3,1250,'+',60,16200,NVT_STATUS_EDID_EST), // 1600x1200x60Hz
117     EST_TIMING(1600, 64,192,2160,'+',1200, 1,3,1250,'+',65,17550,NVT_STATUS_EDID_EST), // 1600x1200x65Hz
118     EST_TIMING(1600, 64,192,2160,'+',1200, 1,3,1250,'+',70,18900,NVT_STATUS_EDID_EST), // 1600x1200x70Hz
119 
120     EST_TIMING(1600, 64,192,2160,'+',1200, 1,3,1250,'+',75,20250,NVT_STATUS_EDID_EST), // 1600x1200x75Hz
121     EST_TIMING(1600, 64,192,2160,'+',1200, 1,3,1250,'+',85,22950,NVT_STATUS_EDID_EST), // 1600x1200x85Hz
122     EST_TIMING(1792,128,200,2448,'-',1344, 1,3,1394,'+',60,20475,NVT_STATUS_EDID_EST), // 1792x1344x60Hz
123     EST_TIMING(1792, 96,216,2456,'-',1344, 1,3,1417,'+',75,26100,NVT_STATUS_EDID_EST), // 1792x1344x75Hz
124     EST_TIMING(1856, 96,224,2528,'-',1392, 1,3,1439,'+',60,21825,NVT_STATUS_EDID_EST), // 1856x1392x60Hz
125     EST_TIMING(1856,128,224,2560,'-',1392, 1,3,1500,'+',75,28800,NVT_STATUS_EDID_EST), // 1856x1392x75Hz
126     EST_TIMING(1920, 48, 32,2080,'+',1200, 3,6,1235,'-',60,15400,NVT_STATUS_EDID_EST), // 1920x1200x60Hz (RB)
127     EST_TIMING(1920,136,200,2592,'-',1200, 3,6,1245,'+',60,19325,NVT_STATUS_EDID_EST), // 1920x1200x60Hz
128 
129     EST_TIMING(1920,136,208,2608,'-',1200, 3,6,1255,'+',75,24525,NVT_STATUS_EDID_EST), // 1920x1200x75Hz
130     EST_TIMING(1920,144,208,2624,'-',1200, 3,6,1262,'+',85,28125,NVT_STATUS_EDID_EST), // 1920x1200x85Hz
131     EST_TIMING(1920,128,208,2600,'-',1440, 1,3,1500,'+',60,23400,NVT_STATUS_EDID_EST), // 1920x1440x60Hz
132     EST_TIMING(1920,144,224,2640,'-',1440, 1,3,1500,'+',75,29700,NVT_STATUS_EDID_EST), // 1920x1440x75Hz
133 
134     NVT_TIMING_SENTINEL,
135     NVT_TIMING_SENTINEL,
136     NVT_TIMING_SENTINEL,
137     NVT_TIMING_SENTINEL
138 };
139 
140 static NvU32 MAX_ESTIII_FORMAT = sizeof(EDID_ESTIII)/sizeof(EDID_ESTIII[0]) - 1;
141 
CODE_SEGMENT(PAGE_DD_CODE)142 CODE_SEGMENT(PAGE_DD_CODE)
143 NVT_STATUS NvTiming_EnumEST(NvU32 index, NVT_TIMING *pT)
144 {
145     if ((pT == NULL) || (index > MAX_EST_FORMAT))
146     {
147         return NVT_STATUS_ERR;
148     }
149 
150     *pT = EDID_EST[index];
151 
152     if (pT->HTotal == 0 || pT->VTotal == 0)
153     {
154         return NVT_STATUS_ERR;
155     }
156 
157     pT->etc.rrx1k = axb_div_c((NvU32)pT->pclk,
158                               (NvU32)10000*(NvU32)1000,
159                               (NvU32)pT->HTotal*(NvU32)pT->VTotal);
160 
161     return NVT_STATUS_SUCCESS;
162 }
163 
CODE_SEGMENT(PAGE_DD_CODE)164 CODE_SEGMENT(PAGE_DD_CODE)
165 NVT_STATUS NvTiming_EnumESTIII(NvU32 index, NVT_TIMING *pT)
166 {
167     if ((pT == NULL) || (index > MAX_ESTIII_FORMAT))
168     {
169         return NVT_STATUS_ERR;
170     }
171 
172     *pT = EDID_ESTIII[index];
173 
174     if (pT->HTotal == 0 || pT->VTotal == 0)
175     {
176         return NVT_STATUS_ERR;
177     }
178 
179     pT->etc.rrx1k = axb_div_c((NvU32)pT->pclk,
180                               (NvU32)10000*(NvU32)1000,
181                               (NvU32)pT->HTotal*(NvU32)pT->VTotal);
182 
183     return NVT_STATUS_SUCCESS;
184 }
185 
CODE_SEGMENT(PAGE_DD_CODE)186 CODE_SEGMENT(PAGE_DD_CODE)
187 NvU32 isHdmi3DStereoType(NvU8 StereoStructureType)
188 {
189     return ((NVT_HDMI_VS_BYTE5_HDMI_3DS_FRAMEPACK      == StereoStructureType) ||
190             (NVT_HDMI_VS_BYTE5_HDMI_3DS_FIELD_ALT      == StereoStructureType) ||
191             (NVT_HDMI_VS_BYTE5_HDMI_3DS_LINE_ALT       == StereoStructureType) ||
192             (NVT_HDMI_VS_BYTE5_HDMI_3DS_SIDEBYSIDEFULL == StereoStructureType) ||
193             (NVT_HDMI_VS_BYTE5_HDMI_3DS_LDEPTH         == StereoStructureType) ||
194             (NVT_HDMI_VS_BYTE5_HDMI_3DS_LDEPTHGFX      == StereoStructureType) ||
195             (NVT_HDMI_VS_BYTE5_HDMI_3DS_TOPBOTTOM      == StereoStructureType) ||
196             (NVT_HDMI_VS_BYTE5_HDMI_3DS_SIDEBYSIDEHALF == StereoStructureType));
197 }
198 
CODE_SEGMENT(PAGE_DD_CODE)199 CODE_SEGMENT(PAGE_DD_CODE)
200 NvU32 NvTiming_GetVESADisplayDescriptorVersion(NvU8 *rawData, NvU32 *pVer)
201 {
202     return getEdidVersion(rawData, pVer);
203 }
204 
205 // get the EDID version
CODE_SEGMENT(PAGE_DD_CODE)206 CODE_SEGMENT(PAGE_DD_CODE)
207 NvU32 getEdidVersion(NvU8 *pEdid, NvU32 *pVer)
208 {
209     EDIDV1STRUC *p = (EDIDV1STRUC *) pEdid;
210 
211     if (pEdid[0] == 0x00)
212     {
213         // For Version 1.x, first 8 bytes of EDID must be 00h, FFh, FFh, FFh, FFh, FFh, FFh, 00h.
214         // Beware of Endian-ness and signed-ness.
215         if (p->bHeader[1] != 0xFF || p->bHeader[2] != 0xFF || p->bHeader[3] != 0xFF ||
216             p->bHeader[4] != 0xFF || p->bHeader[5] != 0xFF || p->bHeader[6] != 0xFF ||
217             p->bHeader[7] != 0x00)
218             return NVT_STATUS_ERR;
219 
220         *pVer = (((NvU32) p->bVersionNumber) << 8) + ((NvU32) p->bRevisionNumber);
221     }
222     else if ((pEdid[0] & 0xF0) == 0x20)
223         *pVer = (((NvU32) (pEdid[0] & 0XF0) << 4) + (NvU32) (pEdid[0] & 0X0F)) ;  // DisplayID version 2.x
224     else
225         return NVT_STATUS_ERR;          // un-recongnized EDID version
226 
227     return NVT_STATUS_SUCCESS;
228 }
229 
CODE_SEGMENT(PAGE_DD_CODE)230 CODE_SEGMENT(PAGE_DD_CODE)
231 void parseEdidCvt3ByteDescriptor(NvU8 *p, NVT_EDID_INFO *pInfo, NvU32 *vtbCount)
232 {
233     NvU32 k;
234     NvU32 width, height, aspect, rr = 0;
235     NVT_EDID_DD_CVT_3BYTE_BLOCK *pTiming = (NVT_EDID_DD_CVT_3BYTE_BLOCK *)p;
236     NVT_TIMING newTiming;
237     NVT_STATUS status;
238 
239 
240     if (pTiming->addressable_lines == 0)
241         return;
242 
243     height = pTiming->addressable_lines;
244     aspect = pTiming->aspect_ratio;
245 
246     if (aspect == NVT_EDID_CVT3_ASPECT_4X3)
247         width = height * 4 / 3;
248     else if (aspect == NVT_EDID_CVT3_ASPECT_16X9)
249         width = height * 16 / 9;
250     else if (aspect == NVT_EDID_CVT3_ASPECT_16X10)
251         width = height * 16 / 10;
252     else                         //15:9
253         width = height * 15 / 9;
254 
255     width &= 0xFFFFFFF8; // round down to nearest 8
256 
257     // loop through bits4:0 of supported_vert_rate so we can add a timing
258     // for each supported rate
259     for (k=1; k<=0x10; k<<=1)
260     {
261         // skip if this bit indicate no support for the rate;
262         if ( (pTiming->supported_vert_rates & (k)) == 0)
263             continue;
264 
265         // find the correct refresh rate for this bit
266         switch (k)
267         {
268             case NVT_EDID_CVT3_SUPPORTED_RATE_60HZ_REDUCED_BLANKING :
269             case NVT_EDID_CVT3_SUPPORTED_RATE_60HZ :
270                 rr = 60;
271                 break;
272             case NVT_EDID_CVT3_SUPPORTED_RATE_85HZ :
273                 rr = 85;
274                 break;
275             case NVT_EDID_CVT3_SUPPORTED_RATE_75HZ :
276                 rr = 75;
277                 break;
278             case NVT_EDID_CVT3_SUPPORTED_RATE_50HZ :
279                 rr = 50;
280                 break;
281         }
282 
283         NVMISC_MEMSET(&newTiming, 0, sizeof(newTiming));
284 
285         if ( (k) != NVT_EDID_CVT3_SUPPORTED_RATE_60HZ_REDUCED_BLANKING) // standard blanking
286         {
287             status = NvTiming_CalcCVT(width, height, rr,
288                                       NVT_PROGRESSIVE,
289                                       &newTiming);
290         }
291         else // reduced blanking
292         {
293             status = NvTiming_CalcCVT_RB(width, height, rr,
294                                          NVT_PROGRESSIVE,
295                                          &newTiming);
296         }
297 
298         if (status == NVT_STATUS_SUCCESS)
299         {
300             // For VTB timings, add additional information
301             if (vtbCount)
302             {
303                 (*vtbCount)++;
304                 newTiming.etc.status = NVT_STATUS_EDID_VTB_EXT_CVTn(*vtbCount);
305                 newTiming.etc.name[39] = '\0';
306             }
307 
308             if (!assignNextAvailableTiming(pInfo, &newTiming))
309             {
310                 break;
311             }
312         }
313     } // for (k=1; k<=0x10; k<<=1)
314 
315 }
316 
317 // parse the EDID 1.x based cvt timing info
CODE_SEGMENT(PAGE_DD_CODE)318 CODE_SEGMENT(PAGE_DD_CODE)
319 void parseEdidCvtTiming(NVT_EDID_INFO *pInfo)
320 {
321     NvU32 i, j;
322 
323     // find display range limit with cvt, or cvt 3-byte LDDs
324     for (i=0; i<NVT_EDID_MAX_LONG_DISPLAY_DESCRIPTOR; i++)
325     {
326         if ( pInfo->ldd[i].tag == NVT_EDID_DISPLAY_DESCRIPTOR_CVT )
327         {
328             NVT_EDID_DD_CVT_3BYTE *pCVT = (NVT_EDID_DD_CVT_3BYTE *)&pInfo->ldd[i].u.cvt;
329 
330             // loop through cvt 3-byte blocks
331             for (j=0; j<NVT_EDID_DD_MAX_CVT3_PER_DESCRITPOR; j++)
332             {
333                 parseEdidCvt3ByteDescriptor((NvU8 *)(pCVT->block + j),
334                                             pInfo, NULL);
335             } // for(j=0; j<NVT_EDID_DD_CVT3_BLOCK_NUM; j++)
336         } // else if CVT 3-byte block
337     } // for (i=0; i<NVT_EDID_MAX_LONG_DISPLAY_DESCRIPTOR; i++)
338 }
339 
340 // parse the EDID 1.x based established timing info
CODE_SEGMENT(PAGE_DD_CODE)341 CODE_SEGMENT(PAGE_DD_CODE)
342 void parseEdidEstablishedTiming(NVT_EDID_INFO *pInfo)
343 {
344     NvU32 i, j, k;
345     NvU32 count = 0;
346     NVT_TIMING newTiming;
347 
348     for (i = 1 << (sizeof(pInfo->established_timings_1_2) * 8 - 1), j = 0; i != 0; i >>= 1, j ++)
349     {
350         if ((pInfo->established_timings_1_2 & i) != 0 && EDID_EST[j].pclk != 0)
351         {
352             // count the timing
353             newTiming = EDID_EST[j];
354             newTiming.etc.status = NVT_STATUS_EDID_ESTn(++count);
355             NVT_SNPRINTF((char *)newTiming.etc.name, 40,
356                          "EDID-EST(VESA):%dx%dx%dHz",
357                          (int)newTiming.HVisible,
358                          (int)newTiming.VVisible,
359                          (int)newTiming.etc.rr);
360             newTiming.etc.name[39] = '\0';
361 
362             if (!assignNextAvailableTiming(pInfo, &newTiming))
363             {
364                 break;
365             }
366         }
367     }
368 
369     // ESTIII block in ldd only supported in EDID1.4 and above
370     if (pInfo->version  < NVT_EDID_VER_1_4)
371         return;
372 
373     for (i=0; i<NVT_EDID_MAX_LONG_DISPLAY_DESCRIPTOR; i++)
374     {
375         if ( pInfo->ldd[i].tag == NVT_EDID_DISPLAY_DESCRIPTOR_ESTIII )
376         {
377             NVT_EDID_DD_EST_TIMING3* pEST = &pInfo->ldd[i].u.est3;
378 
379             for (j=0; j<NVT_EDID_DD_EST_TIMING3_NUM; j++) // loop through each byte
380             {
381                 // loop through each bit in the byte
382                 for (k=7; k<=7; k--)
383                 {
384                     // find if the bit is 1 and we have a valid associated timing
385                     if (pEST->data[j] & (1<<k) && EDID_ESTIII[(j*8)+(7-k)].pclk != 0)
386                     {
387                         newTiming = EDID_ESTIII[(j*8)+(7-k)];
388                         newTiming.etc.status = NVT_STATUS_EDID_ESTn(++count);
389                         NVT_SNPRINTF((char *)newTiming.etc.name, 40,
390                                      "EDID-EST(III):%dx%dx%dHz",
391                                      (int)newTiming.HVisible,
392                                      (int)newTiming.VVisible,
393                                      (int)newTiming.etc.rr);
394                         newTiming.etc.name[39] = '\0';
395 
396                         if (!assignNextAvailableTiming(pInfo, &newTiming))
397                         {
398                             break;
399                         }
400                     }
401                 }
402             }
403             break;
404         }
405     }
406 }
407 
CODE_SEGMENT(PAGE_DD_CODE)408 CODE_SEGMENT(PAGE_DD_CODE)
409 void parseEdidStandardTimingDescriptor(NvU16 timing, NVT_EDID_INFO *pInfo, NvU32 count, NVT_TIMING * pT)
410 {
411     NvU32 aspect, width, height, rr;
412     count++;
413 
414     // The value in the EDID = (Horizontal active pixels/8) - 31
415     width = (timing & 0x0FF) + 31;
416     width <<= 3;
417     rr = ((timing >> 8) & 0x3F) + 60; // bits 5->0
418 
419     // get the height
420     aspect = ((timing >> 8) & 0xC0); // aspect ratio at bit 7:6
421     if (aspect == 0x00)
422         height = (pInfo->version < 0x103) ? width : (width * 5 / 8); //16:10 per EDID1.3 and 1:1 with earlier EDID
423     else if (aspect == 0x40)
424         height = width * 3 / 4;                                    //4:3
425     else if (aspect == 0x80)
426         height = width * 4 / 5;                                    //5:4
427     else
428         height = width * 9 / 16;                                   //16:9
429 
430     // try to get the timing from DMT first
431     if (NvTiming_CalcDMT(width, height, rr, 0, pT) == NVT_STATUS_SUCCESS)
432     {
433         pT->etc.status = NVT_STATUS_EDID_STDn(count);
434         NVT_SNPRINTF((char *)pT->etc.name, 40, "EDID-STD(DMT):%dx%dx%dHz", (int)width, (int)height, (int)rr);
435         pT->etc.name[39] = '\0';
436     }
437     // EDID1.4 and above defaults to CVT, instead of GTF. GTF is deprecated as of 1.4.
438     else if ((pInfo->version >= NVT_EDID_VER_1_4) && (NvTiming_CalcCVT(width, height, rr, NVT_PROGRESSIVE, pT) == NVT_STATUS_SUCCESS))
439     {
440         pT->etc.status = NVT_STATUS_EDID_STDn(count);
441         NVT_SNPRINTF((char *)pT->etc.name, 40, "EDID-STD(CVT):%dx%dx%dHz", (int)width, (int)height, (int)rr);
442         pT->etc.name[39] = '\0';
443     }
444     else
445     {
446         // if the mode is not found in DMT, use GTF timing
447         if (NvTiming_CalcGTF(width, height, rr, NVT_PROGRESSIVE, pT) == NVT_STATUS_SUCCESS)
448         {
449             NVT_SNPRINTF((char *)pT->etc.name, 40, "EDID-STD(GTF):%dx%dx%dHz", (int)width, (int)height, (int)rr);
450             pT->etc.name[39] = '\0';
451         }
452         pT->etc.status = NVT_STATUS_EDID_STDn(count);
453     }
454 }
455 
456 // parse the EDID 1.x based standard timing info
CODE_SEGMENT(PAGE_DD_CODE)457 CODE_SEGMENT(PAGE_DD_CODE)
458 void parseEdidStandardTiming(NVT_EDID_INFO *pInfo)
459 {
460     NvU32 i, j;
461     NVT_TIMING newTiming;
462     NvU32 count = 0;
463 
464     // now check for standard timings
465     for (i=0; i<NVT_EDID_MAX_STANDARD_TIMINGS; i++)
466     {
467         if (((pInfo->standard_timings[i] & 0x0FF) != 0x1) &&    //proper indication of unused field
468              (pInfo->standard_timings[i] != 0x0))               //improper indication (bad edid)
469         {
470             NVMISC_MEMSET(&newTiming, 0, sizeof(newTiming));
471 
472             parseEdidStandardTimingDescriptor(pInfo->standard_timings[i],
473                                               pInfo, count, &newTiming);
474 
475             if (!assignNextAvailableTiming(pInfo, &newTiming))
476             {
477                 break;
478             }
479 
480             count++;
481         }//if ((pInfo->standard_timings[i] & 0x0FF) != 0x1)
482     } //for (i=0; i<NVT_EDID_MAX_STANDARD_TIMINGS; i++)
483 
484     // STI block in ldd only supported in EDID1.4 and above
485     if (pInfo->version < NVT_EDID_VER_1_4)
486         return;
487 
488     // now check for standard timings in long display descriptors
489     for (i=0; i<NVT_EDID_MAX_LONG_DISPLAY_DESCRIPTOR; i++)
490     {
491         if ( pInfo->ldd[i].tag == NVT_EDID_DISPLAY_DESCRIPTOR_STI )
492         {
493             NVT_EDID_DD_STD_TIMING* pSTI = &pInfo->ldd[i].u.std_timing;
494             for (j=0; j<NVT_EDID_DD_STI_NUM; j++)
495             {
496                 if ((pSTI->descriptor[j] & 0x0FF) != 0x00)
497                 {
498                     NVMISC_MEMSET(&newTiming, 0, sizeof(newTiming));
499 
500                     parseEdidStandardTimingDescriptor(pSTI->descriptor[j],
501                                                       pInfo, count, &newTiming);
502 
503                     if (!assignNextAvailableTiming(pInfo, &newTiming))
504                     {
505                         break;
506                     }
507 
508                     count++;
509                 } // if ((pSTI->std_timing[i] & 0x0FF) != 0x1)
510             } //for (j=0; j<NVT_EDID_DD_STI_NUM; j++)
511         } //if ( ((EDID_LONG_DISPLAY_DESCRIPTOR)p->DetailedTimingDesc[i]).tag = NVT_EDID_DISPLAY_DESCRIPTOR_STI )
512     } //for (i=0; i<NVT_EDID_MAX_LONG_DISPLAY_DESCRIPTOR; i++)
513 }
514 
515 // parse the signal detailed timing descriptor
CODE_SEGMENT(PAGE_DD_CODE)516 CODE_SEGMENT(PAGE_DD_CODE)
517 NVT_STATUS parseEdidDetailedTimingDescriptor(NvU8 *p, NVT_TIMING *pT)
518 {
519     DETAILEDTIMINGDESCRIPTOR *pDTD = (DETAILEDTIMINGDESCRIPTOR *)p;
520     NvU32 dwTotalPixels;
521     NvS32 hvisible, vvisible;
522 
523     // bypass input parameter check  in the private function
524 
525 
526     // For EDID ver 1.1 & 1.2:
527     // All bytes filled with 1 are considered as an empty block and should be skipped.
528     // Here we just check first 5 bytes.
529     // Release 5th byte zero check. Now we only check first 4 bytes. Some buggy EDID has
530     // data in 5th byte.
531     if(pDTD && (pDTD->wDTPixelClock !=0          || pDTD->bDTHorizontalActive !=0)
532             && (pDTD->wDTPixelClock != 0x0101    || pDTD->bDTHorizontalActive != 1 ||
533                 pDTD->bDTHorizontalBlanking != 1 || pDTD->bDTHorizActiveBlank != 1))
534     {
535         // Note that hvisible and vvisible here correspond to the "Addressable Video" portion of the
536         // "Active Video" defined in the EDID spec (see section 3.12: Note Regarding Borders)
537         hvisible = (pDTD->bDTHorizontalActive + ((pDTD->bDTHorizActiveBlank & 0xF0) << 4)) - 2 * pDTD->bDTHorizontalBorder;
538         vvisible = (pDTD->bDTVerticalActive + ((pDTD->bDTVertActiveBlank & 0xF0) << 4)) - 2 * pDTD->bDTVerticalBorder;
539 
540         // Sanity check since we are getting values from the monitor
541         if (hvisible <= 0 || vvisible <= 0 || pDTD->wDTPixelClock == 0)
542         {
543             if (pT)
544                 pT->HVisible = 0;
545             return NVT_STATUS_ERR;
546         }
547 
548         // if the output timing buffer is not provide, simply return here to indicate a legal descriptor
549         if (pT == NULL)
550             return NVT_STATUS_SUCCESS;
551 
552         // horizontal timing parameters
553         pT->HVisible    = (NvU16)hvisible;
554         pT->HBorder     = (NvU16)pDTD->bDTHorizontalBorder;
555         pT->HTotal      = (NvU16)hvisible + (NvU16)(pDTD->bDTHorizontalBlanking + ((pDTD->bDTHorizActiveBlank & 0x0F) << 8)) + pT->HBorder * 2;
556         pT->HFrontPorch = (NvU16)(pDTD->bDTHorizontalSync + ((pDTD->bDTHorizVertSyncOverFlow & 0xC0) << 2));
557         pT->HSyncWidth  = (NvU16)(pDTD->bDTHorizontalSyncWidth + ((pDTD->bDTHorizVertSyncOverFlow & 0x30) << 4));
558 
559         // vertical timing parameters
560         pT->VVisible    = (NvU16)vvisible;
561         pT->VBorder     = (NvU16)pDTD->bDTVerticalBorder;
562         pT->VTotal      = (NvU16)vvisible + (NvU16)(pDTD->bDTVerticalBlanking + ((pDTD->bDTVertActiveBlank & 0x0F) << 8)) + pT->VBorder * 2;
563         pT->VFrontPorch = (NvU16)(((pDTD->bDTVerticalSync & 0xF0) >> 4) + ((pDTD->bDTHorizVertSyncOverFlow & 0x0C) << 2));
564         pT->VSyncWidth  = (NvU16)((pDTD->bDTVerticalSync & 0x0F) + ((pDTD->bDTHorizVertSyncOverFlow & 0x03) << 4));
565 
566         // pixel clock
567         pT->pclk = (NvU32)pDTD->wDTPixelClock;
568 
569         // sync polarities
570         if ((pDTD->bDTFlags & 0x18) == 0x18)
571         {
572             pT->HSyncPol = ((pDTD->bDTFlags & 0x2) != 0) ? NVT_H_SYNC_POSITIVE : NVT_H_SYNC_NEGATIVE;
573             pT->VSyncPol = ((pDTD->bDTFlags & 0x4) != 0) ? NVT_V_SYNC_POSITIVE : NVT_V_SYNC_NEGATIVE;
574         }
575         else if ((pDTD->bDTFlags & 0x18) == 0x10)
576         {
577             pT->HSyncPol = ((pDTD->bDTFlags & 0x2) != 0) ? NVT_H_SYNC_POSITIVE : NVT_H_SYNC_NEGATIVE;
578             pT->VSyncPol = NVT_V_SYNC_POSITIVE;
579         }
580         else
581         {
582             pT->HSyncPol = NVT_H_SYNC_NEGATIVE;
583             pT->VSyncPol = NVT_V_SYNC_POSITIVE;
584         }
585 
586         // interlaced
587         if ((pDTD->bDTFlags & 0x80) == 0x80)
588             pT->interlaced = 1;
589         else
590             pT->interlaced = 0;
591 
592         // Eizo split EDID case, using 0th bit to indicate split display capability
593         if (((pDTD->bDTFlags & 1) == 1) && !(((pDTD->bDTFlags & 0x20) == 0x20) || ((pDTD->bDTFlags & 0x40) == 0x40)))
594         {
595             pT->etc.flag |= NVT_FLAG_EDID_DTD_EIZO_SPLIT;
596         }
597         if (pT->interlaced)
598         {
599             // Adjust for one extra blank line in every other frame.
600             dwTotalPixels = (((NvU32)pT->HTotal * pT->VTotal) +
601                             ((NvU32)pT->HTotal * (pT->VTotal + 1))) / 2;
602         }
603         else
604         {
605             dwTotalPixels = (NvU32)pT->HTotal * pT->VTotal;
606         }
607 
608         pT->etc.rr = (NvU16)(((NvU32)pDTD->wDTPixelClock*10000+dwTotalPixels/2)/dwTotalPixels);
609         // Using utility call to multiply and divide to take care of overflow and truncation of large values
610         // How did we arrive at 10000000? It comes from the fact that Pixel clock mentioned in EDID is in mulitples of 10KHz = 10000
611         // and the refresh rate is mentioned in 0.001Hz, that is 60Hz will be represented as 60000, which brings in the factor of 1000.
612         // And hence 10000 * 1000 = 10000000
613         pT->etc.rrx1k = axb_div_c(pDTD->wDTPixelClock, 10000000, dwTotalPixels);
614         pT->etc.status = NVT_STATUS_EDID_DTD;
615         NVT_SNPRINTF((char *)pT->etc.name, sizeof(pT->etc.name), "EDID-Detailed:%dx%dx%d.%03dHz%s", (int)pT->HVisible, (int)(pT->interlaced ? 2 : 1)*pT->VVisible , (int)pT->etc.rrx1k/1000, (int)pT->etc.rrx1k%1000, (pT->interlaced ? "/i" : ""));
616         pT->etc.name[sizeof(pT->etc.name) - 1] = '\0';
617 
618         // aspect ratio
619         pT->etc.aspect = (pDTD->bDTHorizVertImage & 0xF0) << 20 | pDTD->bDTHorizontalImage << 16 |
620                          (pDTD->bDTHorizVertImage & 0x0F) << 8  | pDTD->bDTVerticalImage;
621 
622         pT->etc.rep = 0x1; // Bit mask for no pixel repetition.
623 
624         return NVT_STATUS_SUCCESS;
625     }
626 
627     return NVT_STATUS_ERR;
628 }
629 
630 // parse the EDID 1.x based standard timing info
CODE_SEGMENT(PAGE_DD_CODE)631 CODE_SEGMENT(PAGE_DD_CODE)
632 void parseEdidDetailedTiming(NvU8 *pEdid, NVT_EDID_INFO *pInfo)
633 {
634     EDIDV1STRUC *p = (EDIDV1STRUC *) pEdid;
635     NVT_TIMING newTiming;
636     NvU32 i;
637     NvBool found = NV_FALSE;
638 
639     for (i = 0; i < 4; i++)
640     {
641         NVMISC_MEMSET(&newTiming, 0, sizeof(newTiming));
642 
643         if (parseEdidDetailedTimingDescriptor((NvU8 *)&p->DetailedTimingDesc[i],
644                                               &newTiming) == NVT_STATUS_SUCCESS)
645         {
646             newTiming.etc.status = NVT_STATUS_EDID_DTDn(i+1);
647 
648             if (!assignNextAvailableTiming(pInfo, &newTiming))
649             {
650                 break;
651             }
652 
653             found = NV_TRUE;
654         }
655     }
656 
657     if (found)
658     {
659         // if edid_ver 1.3, PTM flag should be set
660         //nvt_assert(pInfo->version > 0x103 || (pInfo->u.feature &
661         //           NVT_EDID_OTHER_FEATURES_PTM_INCLUDE_NATIVE));
662 
663         if (pInfo->u.feature & NVT_EDID_OTHER_FEATURES_PTM_INCLUDE_NATIVE)
664         {
665             pInfo->timing[0].etc.flag |= NVT_FLAG_DTD1_PREFERRED_TIMING;
666         }
667     }
668 }
669 
670 
671 // parse the EDID 1.x 18-byte long display descriptor
CODE_SEGMENT(PAGE_DD_CODE)672 CODE_SEGMENT(PAGE_DD_CODE)
673 static void parseEdidLongDisplayDescriptor(EDID_LONG_DISPLAY_DESCRIPTOR *descriptor, NVT_EDID_18BYTE_DESCRIPTOR *p, NvU32 version)
674 {
675     NvU32 i;
676 
677     // bypass the input pointer check in this private function
678 
679     // return if it's a detailed timing descriptor
680     if (descriptor->prefix[0] != 0 || descriptor->prefix[1] != 0)
681         return;
682 
683     // other sanity check for the input data
684     if (descriptor->rsvd != 0)
685         return;
686 
687     p->tag = descriptor->tag;
688 
689     // now translate the descriptor
690     switch (descriptor->tag)
691     {
692         case NVT_EDID_DISPLAY_DESCRIPTOR_DPSN:    // display product serial number
693         case NVT_EDID_DISPLAY_DESCRITPOR_DPN:     // display product name
694         case NVT_EDID_DISPLAY_DESCRIPTOR_ADS:     // alphanumeric data string (ASCII)
695 
696             // copy the 13 characters payload from the 18-byte descriptor
697             for (i = 0; i < NVT_PVT_EDID_LDD_PAYLOAD_SIZE; i++)
698             {
699                 if (descriptor->data[i] == 0x0A)
700                     p->u.serial_number.str[i] = '\0';
701                 else
702                     p->u.serial_number.str[i] = descriptor->data[i];
703             }
704             break;
705 
706         case NVT_EDID_DISPLAY_DESCRIPTOR_DRL:     // display range limit
707             {
708                 EDID_MONITOR_RANGE_LIMIT *pRangeLimit = (EDID_MONITOR_RANGE_LIMIT *)&descriptor->data[0];
709 
710                 p->u.range_limit.min_v_rate   = pRangeLimit->minVRate;
711                 p->u.range_limit.max_v_rate   = pRangeLimit->maxVRate;
712                 p->u.range_limit.min_h_rate   = pRangeLimit->minHRate;
713                 p->u.range_limit.max_h_rate   = pRangeLimit->maxHRate;
714                 p->u.range_limit.max_pclk_MHz = pRangeLimit->maxPClock10M * 10;
715                 p->u.range_limit.timing_support = pRangeLimit->timing_support;
716 
717                 // add 255Hz offsets if needed, use descriptor->rsvd2
718                 // to offset the min values their max MUST be offset as well
719                 if (version >= NVT_EDID_VER_1_4)
720                 {
721                     if (descriptor->rsvd2 & NVT_PVT_EDID_RANGE_OFFSET_VER_MAX)
722                     {
723                         p->u.range_limit.max_v_rate += NVT_PVT_EDID_RANGE_OFFSET_AMOUNT;
724                         if (descriptor->rsvd2 & NVT_PVT_EDID_RANGE_OFFSET_VER_MIN)
725                         {
726                             p->u.range_limit.min_v_rate += NVT_PVT_EDID_RANGE_OFFSET_AMOUNT;
727                         }
728                     }
729                     if (descriptor->rsvd2 & NVT_PVT_EDID_RANGE_OFFSET_HOR_MAX)
730                     {
731                         p->u.range_limit.max_h_rate += NVT_PVT_EDID_RANGE_OFFSET_AMOUNT;
732                         if (descriptor->rsvd2 & NVT_PVT_EDID_RANGE_OFFSET_HOR_MIN)
733                         {
734                             p->u.range_limit.min_h_rate += NVT_PVT_EDID_RANGE_OFFSET_AMOUNT;
735                         }
736                     }
737                 }
738 
739                 if (p->u.range_limit.timing_support == NVT_EDID_RANGE_SUPPORT_GTF2)
740                 {
741                     // descriptor->data[7]
742                     // Start frequency for secondary curve, hor freq./2[kHz]
743                     p->u.range_limit.u.gtf2.C     = pRangeLimit->u.gtf2.C / 2;       // 0 <= C <= 127
744                     p->u.range_limit.u.gtf2.K     = pRangeLimit->u.gtf2.K;           // 0 <= K <= 255
745                     p->u.range_limit.u.gtf2.J     = pRangeLimit->u.gtf2.J / 2;       // 0 <= J <= 127
746                     p->u.range_limit.u.gtf2.M     = (pRangeLimit->u.gtf2.M_MSB << 8)
747                                                   +  pRangeLimit->u.gtf2.M_LSB;      // 0 <= M <= 65535
748                 }
749                 else if (p->u.range_limit.timing_support == NVT_EDID_RANGE_SUPPORT_CVT)
750                 {
751                     // the pixel clock adjustment is in cvt.pixel_clock @ bits7:2
752                     // that number is in 0.25MHz, ie actual max clock is  max_pclk_MHz - (0.25 x cvt_pixel_clock)
753                     // subtract the whole number part from max_pclk_MHz, save the remainder
754                     p->u.range_limit.max_pclk_MHz -= (pRangeLimit->u.cvt.pixel_clock & NVT_PVT_EDID_CVT_PIXEL_CLOCK_MASK) >> NVT_PVT_EDID_CVT_PIXEL_CLOCK_SHIFT >> 2; // ie divide by 4 to get whole number
755                     p->u.range_limit.u.cvt.pixel_clock_adjustment = ((pRangeLimit->u.cvt.pixel_clock & NVT_PVT_EDID_CVT_PIXEL_CLOCK_MASK) >> NVT_PVT_EDID_CVT_PIXEL_CLOCK_SHIFT) & 0x03; // ie modulus 4
756 
757                     p->u.range_limit.u.cvt.max_active_pixels_per_line = (pRangeLimit->u.cvt.pixel_clock & NVT_PVT_EDID_CVT_ACTIVE_MSB_MASK) << NVT_PVT_EDID_CVT_ACTIVE_MSB_SHIFT;
758                     p->u.range_limit.u.cvt.max_active_pixels_per_line |= pRangeLimit->u.cvt.max_active;
759                     p->u.range_limit.u.cvt.max_active_pixels_per_line <<= 3; // ie multiply 8
760 
761                     p->u.range_limit.u.cvt.aspect_supported = (pRangeLimit->u.cvt.aspect_supported & NVT_PVT_EDID_CVT_ASPECT_SUPPORTED_MASK) >> NVT_PVT_EDID_CVT_ASPECT_SUPPORTED_SHIFT;
762 
763                     p->u.range_limit.u.cvt.aspect_preferred = ( pRangeLimit->u.cvt.aspect_preferred_blanking & NVT_PVT_EDID_CVT_ASPECT_PREFERRED_MASK) >> NVT_PVT_EDID_CVT_ASPECT_PREFERRED_SHIFT;
764                     p->u.range_limit.u.cvt.blanking_support = ( pRangeLimit->u.cvt.aspect_preferred_blanking & NVT_PVT_EDID_CVT_BLANKING_MASK) >> NVT_PVT_EDID_CVT_BLANKING_SHIFT;
765 
766                     p->u.range_limit.u.cvt.scaling_support  = (pRangeLimit->u.cvt.scaling_support & NVT_PVT_EDID_CVT_SCALING_MASK) >> NVT_PVT_EDID_CVT_SCALING_SHIFT;
767 
768                     p->u.range_limit.u.cvt.preferred_refresh_rate     = pRangeLimit->u.cvt.preferred_refresh_rate;
769                 }
770             }
771 
772             break;
773 
774         case NVT_EDID_DISPLAY_DESCRIPTOR_CPD:     // color point data
775             {
776                 EDID_COLOR_POINT_DATA *pColorPoint = (EDID_COLOR_POINT_DATA *)&descriptor->data[0];
777 
778                 p->u.color_point.wp1_index = pColorPoint->wp1_index;
779                 p->u.color_point.wp1_x = pColorPoint->wp1_x << 2;
780                 p->u.color_point.wp1_x |= (pColorPoint->wp1_x_y & NVT_PVT_EDID_CPD_WP_X_MASK) >> NVT_PVT_EDID_CPD_WP_X_SHIFT;
781                 p->u.color_point.wp1_y = pColorPoint->wp1_y << 2;
782                 p->u.color_point.wp1_y |= (pColorPoint->wp1_x_y & NVT_PVT_EDID_CPD_WP_Y_MASK) >> NVT_PVT_EDID_CPD_WP_Y_SHIFT;
783                 p->u.color_point.wp1_gamma = pColorPoint->wp1_gamma + 100;
784 
785                 p->u.color_point.wp2_index = pColorPoint->wp2_index;
786                 p->u.color_point.wp2_x = pColorPoint->wp2_x << 2;
787                 p->u.color_point.wp2_x |= (pColorPoint->wp2_x_y & NVT_PVT_EDID_CPD_WP_X_MASK) >> NVT_PVT_EDID_CPD_WP_X_SHIFT;
788                 p->u.color_point.wp2_y = pColorPoint->wp2_y << 2;
789                 p->u.color_point.wp2_y |= (pColorPoint->wp2_x_y & NVT_PVT_EDID_CPD_WP_Y_MASK) >> NVT_PVT_EDID_CPD_WP_Y_SHIFT;
790                 p->u.color_point.wp2_gamma = pColorPoint->wp2_gamma + 100;
791             }
792             break;
793 
794         case NVT_EDID_DISPLAY_DESCRIPTOR_STI:     // standard timing identification
795             {
796                 EDID_STANDARD_TIMING_ID *pStdTiming = (EDID_STANDARD_TIMING_ID *)&descriptor->data[0];
797 
798                 for(i=0; i<NVT_EDID_DD_STI_NUM; i++)
799                 {
800                     p->u.std_timing.descriptor[i] = pStdTiming->std_timing[i];
801                 }
802             }
803             break;
804 
805         case NVT_EDID_DISPLAY_DESCRIPTOR_DCM:     // display color management
806             {
807                 EDID_COLOR_MANAGEMENT_DATA *pColorMan = (EDID_COLOR_MANAGEMENT_DATA *)&descriptor->data[0];
808 
809                 p->u.color_man.red_a3 = pColorMan->red_a3_lsb | (pColorMan->red_a3_msb << 8);
810                 p->u.color_man.red_a2 = pColorMan->red_a2_lsb | (pColorMan->red_a2_msb << 8);
811 
812                 p->u.color_man.green_a3 = pColorMan->green_a3_lsb | (pColorMan->green_a3_msb << 8);
813                 p->u.color_man.green_a2 = pColorMan->green_a2_lsb | (pColorMan->green_a2_msb << 8);
814 
815                 p->u.color_man.blue_a3 = pColorMan->blue_a3_lsb | (pColorMan->blue_a3_msb << 8);
816                 p->u.color_man.blue_a2 = pColorMan->blue_a2_lsb | (pColorMan->blue_a2_msb << 8);
817             }
818             break;
819 
820         case NVT_EDID_DISPLAY_DESCRIPTOR_CVT:     // CVT 3-byte timing code
821             {
822                 EDID_CVT_3BYTE *pCVT_3byte = (EDID_CVT_3BYTE *)&descriptor->data[0];
823 
824                 for (i=0; i<NVT_EDID_DD_MAX_CVT3_PER_DESCRITPOR; i++)
825                 {
826                     if (pCVT_3byte->block[i].addressable_lines != 0)
827                     {
828                         p->u.cvt.block[i].addressable_lines = pCVT_3byte->block[i].addressable_lines;
829                         p->u.cvt.block[i].addressable_lines |= (pCVT_3byte->block[i].lines_ratio & NVT_PVT_EDID_CVT3_LINES_MSB_MASK) << NVT_PVT_EDID_CVT3_LINES_MSB_SHIFT;
830                         p->u.cvt.block[i].addressable_lines +=1;
831                         p->u.cvt.block[i].addressable_lines <<= 1;
832 
833                         p->u.cvt.block[i].aspect_ratio = (pCVT_3byte->block[i].lines_ratio & NVT_PVT_EDID_CVT3_ASPECT_MASK) >> NVT_PVT_EDID_CVT3_ASPECT_SHIFT;
834 
835                         p->u.cvt.block[i].preferred_vert_rates = (pCVT_3byte->block[i].refresh_rates & NVT_PVT_EDID_CVT3_PREFERRED_RATE_MASK) >> NVT_PVT_EDID_CVT3_PREFERRED_RATE_SHIFT;
836                         p->u.cvt.block[i].supported_vert_rates = (pCVT_3byte->block[i].refresh_rates & NVT_PVT_EDID_CVT3_SUPPORTED_RATE_MASK) >> NVT_PVT_EDID_CVT3_SUPPORTED_RATE_SHIFT;
837                     }
838                 }
839             }
840             break;
841 
842         case NVT_EDID_DISPLAY_DESCRIPTOR_ESTIII:  // establishied timing III
843             {
844                 EDID_EST_TIMINGS_III *pEstTiming = (EDID_EST_TIMINGS_III *)&descriptor->data[0];
845 
846                 for(i=0; i<NVT_EDID_DD_EST_TIMING3_NUM; i++)
847                 {
848                     p->u.est3.data[i] = pEstTiming->timing_byte[i];
849                 }
850             }
851             break;
852 
853         case NVT_EDID_DISPLAY_DESCRIPTOR_DUMMY:   // dummy descriptor
854         default:
855             // unresolved descriptor yet
856             for (i = 0; i < NVT_PVT_EDID_LDD_PAYLOAD_SIZE; i++)
857             {
858                 p->u.dummy.data[i] = descriptor->data[i];
859             }
860             break;
861     }
862 
863 }
864 
865 // get generic EDID info
CODE_SEGMENT(PAGE_DD_CODE)866 CODE_SEGMENT(PAGE_DD_CODE)
867 NVT_STATUS NV_STDCALL NvTiming_ParseEDIDInfo(NvU8 *pEdid, NvU32 length, NVT_EDID_INFO *pInfo)
868 {
869     NvU32 i, j, k, data;
870     EDIDV1STRUC *p;
871     NvU8 *pExt;
872     NVT_EDID_CEA861_INFO *p861Info;
873 
874     // parameter check
875     if (pEdid == NULL || length < 128 || pInfo == NULL)
876     {
877         return NVT_STATUS_ERR;
878     }
879 
880     NVMISC_MEMSET(pInfo, 0, sizeof(NVT_EDID_INFO));
881 
882     // get the EDID version
883     if (getEdidVersion(pEdid, &pInfo->version) == NVT_STATUS_ERR)
884     {
885         return NVT_STATUS_ERR;
886     }
887 
888     p = (EDIDV1STRUC *) pEdid;
889 
890     // get the IDs
891     pInfo->manuf_id = p->wIDManufName;
892     pInfo->product_id = p->wIDProductCode;
893 
894     // translate the ID into manufacturer's name
895     pInfo->manuf_name[0] = 'A' + (NvU8)((pInfo->manuf_id & 0x007c) >> 2) - 1;
896     pInfo->manuf_name[1] = 'A' + (NvU8)((pInfo->manuf_id & 0x0003) << 3 | (pInfo->manuf_id & 0xe000) >> 13) - 1;
897     pInfo->manuf_name[2] = 'A' + (NvU8)((pInfo->manuf_id & 0x1f00) >> 8) - 1;
898     pInfo->manuf_name[3] = '\0';
899 
900     // get serial number
901     pInfo->serial_number = p->dwIDSerialNumber;
902 
903     // get the week and year
904     pInfo->week = p->bWeekManuf;
905     pInfo->year = p->bYearManuf + 1990;
906 
907     // get the interface info
908     pInfo->input.isDigital = (p->bVideoInputDef & NVT_PVT_EDID_INPUT_ISDIGITAL_MASK) >> NVT_PVT_EDID_INPUT_ISDIGITAL_SHIFT;
909 
910     if (pInfo->input.isDigital && pInfo->version > 0x103) // must be at least EDID1.4 to support the following fields
911     {
912         switch ( (p->bVideoInputDef & NVT_PVT_EDID_INPUT_BPC_MASK) >> NVT_PVT_EDID_INPUT_BPC_SHIFT)
913         {
914             case NVT_PVT_EDID_INPUT_BPC_6  :
915                 pInfo->input.u.digital.bpc = 6;
916                 break;
917             case NVT_PVT_EDID_INPUT_BPC_8  :
918                 pInfo->input.u.digital.bpc = 8;
919                 break;
920             case NVT_PVT_EDID_INPUT_BPC_10 :
921                 pInfo->input.u.digital.bpc = 10;
922                 break;
923             case NVT_PVT_EDID_INPUT_BPC_12 :
924                 pInfo->input.u.digital.bpc = 12;
925                 break;
926             case NVT_PVT_EDID_INPUT_BPC_14 :
927                 pInfo->input.u.digital.bpc = 14;
928                 break;
929             case NVT_PVT_EDID_INPUT_BPC_16 :
930                 pInfo->input.u.digital.bpc = 16;
931                 break;
932             default :
933                 pInfo->input.u.digital.bpc = 0;
934                 break;
935         }
936         pInfo->input.u.digital.video_interface = (p->bVideoInputDef & NVT_PVT_EDID_INPUT_INTERFACE_MASK) >> NVT_PVT_EDID_INPUT_INTERFACE_SHIFT;
937     }
938     else if (!pInfo->input.isDigital)
939     {
940         pInfo->input.u.analog_data = (p->bVideoInputDef & NVT_PVT_EDID_INPUT_ANALOG_ETC_MASK) >> NVT_PVT_EDID_INPUT_ANALOG_ETC_SHIFT;
941     }
942 
943     // get the max image size and aspect ratio
944     if (p->bMaxHorizImageSize != 0 && p->bMaxVertImageSize != 0)
945     {
946         pInfo->screen_size_x = p->bMaxHorizImageSize;
947         pInfo->screen_size_y = p->bMaxVertImageSize;
948         pInfo->screen_aspect_x = 0;
949         pInfo->screen_aspect_y = 0;
950     }
951     else if (p->bMaxHorizImageSize != 0 && p->bMaxVertImageSize == 0)
952     {
953         pInfo->screen_size_x = 0;
954         pInfo->screen_size_y = 0;
955         pInfo->screen_aspect_x = 99 + p->bMaxHorizImageSize;
956         pInfo->screen_aspect_y = 100;
957     }
958     else if (p->bMaxHorizImageSize == 0 && p->bMaxVertImageSize != 0)
959     {
960         pInfo->screen_size_x = 0;
961         pInfo->screen_size_y = 0;
962         pInfo->screen_aspect_x = 100;
963         pInfo->screen_aspect_y = 99 + p->bMaxVertImageSize;
964     }
965 
966     // get the gamma
967     pInfo->gamma = p->bDisplayXferChar + 100;
968 
969     // get the features
970     pInfo->u.feature = p->bFeatureSupport;
971 
972     // get chromaticity coordinates
973     pInfo->cc_red_x =  p->Chromaticity[2] << 2;
974     pInfo->cc_red_x |= (p->Chromaticity[0] & NVT_PVT_EDID_CC_RED_X1_X0_MASK) >> NVT_PVT_EDID_CC_RED_X1_X0_SHIFT;
975     pInfo->cc_red_y =  p->Chromaticity[3] << 2;
976     pInfo->cc_red_y |= (p->Chromaticity[0] & NVT_PVT_EDID_CC_RED_Y1_Y0_MASK) >> NVT_PVT_EDID_CC_RED_Y1_Y0_SHIFT;
977 
978     pInfo->cc_green_x =  p->Chromaticity[4] << 2;
979     pInfo->cc_green_x |= (p->Chromaticity[0] & NVT_PVT_EDID_CC_GREEN_X1_X0_MASK) >> NVT_PVT_EDID_CC_GREEN_X1_X0_SHIFT;
980     pInfo->cc_green_y =  p->Chromaticity[5] << 2;
981     pInfo->cc_green_y |= (p->Chromaticity[0] & NVT_PVT_EDID_CC_GREEN_Y1_Y0_MASK) >> NVT_PVT_EDID_CC_GREEN_Y1_Y0_SHIFT;
982 
983     pInfo->cc_blue_x =  p->Chromaticity[6] << 2;
984     pInfo->cc_blue_x |= (p->Chromaticity[1] & NVT_PVT_EDID_CC_BLUE_X1_X0_MASK) >> NVT_PVT_EDID_CC_BLUE_X1_X0_SHIFT;
985     pInfo->cc_blue_y =  p->Chromaticity[7] << 2;
986     pInfo->cc_blue_y |= (p->Chromaticity[1] & NVT_PVT_EDID_CC_BLUE_Y1_Y0_MASK) >> NVT_PVT_EDID_CC_BLUE_Y1_Y0_SHIFT;
987 
988     pInfo->cc_white_x =  p->Chromaticity[8] << 2;
989     pInfo->cc_white_x |= (p->Chromaticity[1] & NVT_PVT_EDID_CC_WHITE_X1_X0_MASK) >> NVT_PVT_EDID_CC_WHITE_X1_X0_SHIFT;
990     pInfo->cc_white_y =  p->Chromaticity[9] << 2;
991     pInfo->cc_white_y |= (p->Chromaticity[1] & NVT_PVT_EDID_CC_WHITE_Y1_Y0_MASK) >> NVT_PVT_EDID_CC_WHITE_Y1_Y0_SHIFT;
992 
993     // copy established timings
994     pInfo->established_timings_1_2  = (NvU16)p->bEstablishedTimings1 << 8;
995     pInfo->established_timings_1_2 |= (NvU16)p->bEstablishedTimings2;
996 
997     // copy manuf reserved timings
998     pInfo->manufReservedTimings = p->bManufReservedTimings;
999 
1000     // copy standard timings
1001     for (i = 0; i < NVT_EDID_MAX_STANDARD_TIMINGS; i++)
1002     {
1003         pInfo->standard_timings[i] = p->wStandardTimingID[i];
1004     }
1005 
1006     // get the number of extensions
1007     pInfo->total_extensions = p->bExtensionFlag;
1008 
1009     // check_sum
1010     for (i = 0, data = 0; i < length; i++)
1011     {
1012         data += pEdid[i];
1013     }
1014     pInfo->checksum_ok = !(data & 0xFF);
1015     pInfo->checksum = p->bChecksum;
1016 
1017 
1018     // now find out the total number of all of the timings in the EDID
1019     pInfo->total_timings = 0;
1020 
1021     // now find out the detailed timings
1022     parseEdidDetailedTiming(pEdid, pInfo);
1023 
1024     // now parse all 18-byte long display descriptors (not detailed timing)
1025     for (i = 0; i < NVT_EDID_MAX_LONG_DISPLAY_DESCRIPTOR; i++)
1026     {
1027         parseEdidLongDisplayDescriptor((EDID_LONG_DISPLAY_DESCRIPTOR *)&p->DetailedTimingDesc[i], &pInfo->ldd[i], pInfo->version);
1028     }
1029 
1030     // now check the number of timings in the extension
1031     for (k = 0, j = 1; j <= pInfo->total_extensions && (j + 1) * sizeof(EDIDV1STRUC) <= length; j++)
1032     {
1033         pExt = pEdid + sizeof(EDIDV1STRUC) * j;
1034 
1035         // check for 861 extension first
1036         switch (*pExt)
1037         {
1038             case NVT_EDID_EXTENSION_CTA:
1039                 p861Info = (k == 0) ? &pInfo->ext861 : &pInfo->ext861_2;
1040 
1041                 get861ExtInfo(pExt, sizeof(EDIDV1STRUC), p861Info);
1042 
1043                 // HF EEODB is present in edid v1.3 and v1.4 does not need this.Also, it is always present in the 1st CTA extension block.
1044                 if (j == 1 && pInfo->version == NVT_EDID_VER_1_3)
1045                 {
1046                     parseCta861HfEeodb(p861Info, &pInfo->total_extensions);
1047                 }
1048 
1049                 // update pInfo with basic hdmi info
1050                 // assumes each edid will only have one such block across multiple cta861 blocks (otherwise may create declaration conflict)
1051                 // In case of multiple such blocks, the last one takes precedence, except for SCDB
1052 
1053                 // parseCta861VsdbBlocks() uses hfScdb info so need to be parsed first
1054                 parseCta861HfScdb(p861Info, pInfo, FROM_CTA861_EXTENSION);
1055                 parseCta861VsdbBlocks(p861Info, pInfo, FROM_CTA861_EXTENSION);
1056                 parseCta861VsvdbBlocks(p861Info, pInfo, FROM_CTA861_EXTENSION);
1057 
1058                 // parse HDR related information from the HDR static metadata data block
1059                 parseCea861HdrStaticMetadataDataBlock(p861Info, pInfo, FROM_CTA861_EXTENSION);
1060 
1061                 // Timings are listed (or shall) be listed in priority order
1062                 // So read SVD, yuv420 SVDs first before reading detailed timings
1063 
1064                 // add the 861B short video timing descriptor
1065                 if (p861Info->revision >= NVT_CEA861_REV_B)
1066                 {
1067                     // base video
1068                     parse861bShortTiming(p861Info, pInfo, FROM_CTA861_EXTENSION);
1069 
1070                     // yuv420-only video
1071                     parse861bShortYuv420Timing(p861Info, pInfo, FROM_CTA861_EXTENSION);
1072                 }
1073 
1074                 // add the detailed timings in 18-byte long display descriptor
1075                 parse861ExtDetailedTiming(pExt, p861Info->basic_caps, pInfo);
1076 
1077                 if (p861Info->revision >= NVT_CTA861_REV_H)
1078                 {
1079                     if (p861Info->total_vfdb         != 0)  parseCta861VideoFormatDataBlock(p861Info, pInfo);
1080                     if (p861Info->total_did_type7db  != 0)  parseCta861DIDType7VideoTimingDataBlock(p861Info, pInfo);
1081                     if (p861Info->total_did_type8db  != 0)  parseCta861DIDType8VideoTimingDataBlock(p861Info, pInfo);
1082                     if (p861Info->total_did_type10db != 0)  parseCta861DIDType10VideoTimingDataBlock(p861Info, pInfo);
1083                 }
1084 
1085                 // CEA861-F at 7.5.12 section about VFPDB block.
1086                 if (p861Info->revision >= NVT_CEA861_REV_F && (p861Info->total_svr != 0 || p861Info->valid.NVRDB == 1))
1087                 {
1088                     parseCta861NativeOrPreferredTiming(p861Info, pInfo, FROM_CTA861_EXTENSION);
1089                 }
1090 
1091                 k++;
1092                 break;
1093 
1094             case NVT_EDID_EXTENSION_VTB:
1095                 parseVTBExtension(pExt, pInfo);
1096                 break;
1097 
1098             case NVT_EDID_EXTENSION_DISPLAYID:
1099                 if ((pExt[1] & 0xF0) == 0x20) // displayID2.x as EDID extension
1100                 {
1101                     if(getDisplayId20EDIDExtInfo(pExt, sizeof(EDIDV1STRUC),
1102                                                     pInfo) == NVT_STATUS_SUCCESS)
1103                     {
1104                         if (pInfo->ext861.total_y420vdb != 0 || pInfo->ext861.total_y420cmdb != 0)
1105                         {
1106                             pInfo->ext_displayid20.interface_features.yuv420_min_pclk = 0;
1107                         }
1108 
1109                         if (pInfo->ext_displayid20.valid_data_blocks.interface_feature_present)
1110                         {
1111                             pInfo->ext861.basic_caps |= pInfo->ext_displayid20.basic_caps;
1112                         }
1113                     }
1114                 }
1115                 else // displayID13 as EDID extension
1116                 {
1117                     //do not fail function based on return value of getDisplayIdEDIDExtInfo refer bug 3247180 where some rogue monitors don't provide correct DID13 raw data.
1118                     if (getDisplayIdEDIDExtInfo(pExt, sizeof(EDIDV1STRUC),
1119                                                    pInfo) == NVT_STATUS_SUCCESS)
1120                     {
1121                         // Check if YCbCr is supported in base block
1122                         // since it is mandatory if YCbCr is supported on any other display interface as per 5.1.1.1 Video Colorimetry
1123                         if(pInfo->u.feature_ver_1_4_digital.support_ycrcb_444)
1124                         {
1125                             if (!pInfo->ext_displayid.supported_displayId2_0)
1126                             {
1127                                 pInfo->ext_displayid.u4.display_interface.ycbcr444_depth.support_8b = 1;
1128                             }
1129                             else
1130                             {
1131                                 pInfo->ext_displayid.u4.display_interface_features.ycbcr444_depth.support_8b = 1;
1132                             }
1133                         }
1134 
1135                         if(pInfo->u.feature_ver_1_4_digital.support_ycrcb_422)
1136                         {
1137                             if (!pInfo->ext_displayid.supported_displayId2_0)
1138                             {
1139                                 pInfo->ext_displayid.u4.display_interface.ycbcr422_depth.support_8b = 1;
1140                             }
1141                             else
1142                             {
1143                                 pInfo->ext_displayid.u4.display_interface_features.ycbcr422_depth.support_8b = 1;
1144                             }
1145                         }
1146                     }
1147                 }
1148                 break;
1149 
1150             default:
1151                 break;
1152         }
1153     }
1154 
1155     // Copy all the timings(could include type 7/8/9/10) from displayid20->timings[] to pEdidInfo->timings[]
1156     for (i = 0; i < pInfo->ext_displayid20.total_timings; i++)
1157     {
1158         if (!assignNextAvailableTiming(pInfo, &(pInfo->ext_displayid20.timing[i])))
1159         {
1160             return NVT_STATUS_ERR;
1161         }
1162     }
1163 
1164     // check for cvt timings - in display range limits or cvt 3-byte LDD, only for EDID1.4 and above
1165     if (pInfo->version > NVT_EDID_VER_1_3)
1166     {
1167         parseEdidCvtTiming(pInfo);
1168     }
1169 
1170     // now check for standard timings - base EDID and then the LDDs
1171     parseEdidStandardTiming(pInfo);
1172 
1173     // find out the total established timings - base EDID and then the LDDs
1174     parseEdidEstablishedTiming(pInfo);
1175 
1176     // remove the T8VTDB timing if it co-existed in standard or established timings
1177     if (pInfo->ext861.revision >= NVT_CTA861_REV_H && pInfo->ext861.total_did_type8db != 0 && pInfo->total_timings > 1)
1178     {
1179         for (i = 0; i < pInfo->total_timings; i++)
1180         {
1181             if (NVT_GET_TIMING_STATUS_TYPE(pInfo->timing[i].etc.status) == NVT_TYPE_CTA861_DID_T8)
1182             {
1183                 if (isMatchedStandardTiming(pInfo, &pInfo->timing[i]) || isMatchedEstablishedTiming(pInfo, &pInfo->timing[i]))
1184                 {
1185                     for (j = i; j < pInfo->total_timings - 1; j++)
1186                     {
1187                         // remove the entry by moving the next entry up.
1188                         pInfo->timing[j] = pInfo->timing[j+1];
1189                     }
1190                     NVMISC_MEMSET(&pInfo->timing[pInfo->total_timings-1], 0, sizeof(NVT_TIMING));
1191                     pInfo->total_timings--; i--;
1192                 }
1193             }
1194         }
1195     }
1196 
1197     getEdidHDM1_4bVsdbTiming(pInfo);
1198 
1199     // Assert if no timings were found (due to a bad EDID) or if we mistakenly
1200     // assigned more timings than we allocated space for (due to bad logic above)
1201     nvt_assert(pInfo->total_timings &&
1202                (pInfo->total_timings <= COUNT(pInfo->timing)));
1203 
1204     // go through all timings and update supported color formats
1205     // consider the supported bpc per color format from parsed EDID / CTA861 / DisplayId
1206     updateColorFormatAndBpcTiming(pInfo);
1207 
1208     return NVT_STATUS_SUCCESS;
1209 }
1210 
CODE_SEGMENT(PAGE_DD_CODE)1211 CODE_SEGMENT(PAGE_DD_CODE)
1212 void updateColorFormatAndBpcTiming(NVT_EDID_INFO *pInfo)
1213 {
1214     NvU32 i, j, data;
1215 
1216     for (i = 0; i < pInfo->total_timings; i++)
1217     {
1218         data = NVT_GET_TIMING_STATUS_TYPE(pInfo->timing[i].etc.status);
1219         switch (data)
1220         {
1221         case NVT_TYPE_HDMI_STEREO:
1222         case NVT_TYPE_HDMI_EXT:
1223             // VTB timing use the base EDID (block 0) to determine the color format support
1224         case NVT_TYPE_EDID_VTB_EXT:
1225         case NVT_TYPE_EDID_VTB_EXT_STD:
1226         case NVT_TYPE_EDID_VTB_EXT_DTD:
1227         case NVT_TYPE_EDID_VTB_EXT_CVT:
1228             // pInfo->u.feature_ver_1_3.color_type provides mono, rgb, rgy, undefined
1229             // assume RGB 8-bpc support only (VTB is pretty old edid standard)
1230             pInfo->timing[i].etc.rgb444.bpc.bpc8 = 1;
1231             break;
1232             // These are from the CTA block, and relies on
1233             // Since there could be multiple CEA blocks, these are adjusted when the blocks are parsed
1234         case NVT_TYPE_EDID_861ST:
1235         case NVT_TYPE_EDID_EXT_DTD:
1236             if (pInfo->ext_displayid20.as_edid_extension &&
1237                 pInfo->ext_displayid20.valid_data_blocks.cta_data_present)
1238             {
1239                 updateColorFormatForDisplayId20ExtnTimings(pInfo, i);
1240             }
1241             updateBpcForTiming(pInfo, i);
1242             break;
1243         default:
1244             // * the displayID_v1.3/v2.0 EDID extension need to follow the EDID bpc definition.
1245             // * all other default to base edid
1246             updateBpcForTiming(pInfo, i);
1247         }
1248 
1249         // The timings[i] entries need to update the bpc values where are based on the different color format again
1250         // if displayId extension existed it's interface feature data block
1251         if (pInfo->ext_displayid.version == 0x12 || pInfo->ext_displayid.version == 0x13)
1252         {
1253             updateColorFormatForDisplayIdExtnTimings(pInfo, i);
1254         }
1255         else if (pInfo->ext_displayid20.valid_data_blocks.interface_feature_present)
1256         {
1257             // DisplayId2.0 spec has its own way of determining color format support which includes bpc + color format
1258             updateColorFormatForDisplayId20ExtnTimings(pInfo, i);
1259         }
1260     }
1261 
1262     // Go through all the timings and set CTA format accordingly. If a timing is a CTA 861b timing, store the
1263     // index of this CTA 861b standard in NVT_TIMING.etc.status field.
1264     // However parser needs to exclude the DTD timing in EDID base block where is shared same detailed timing in VIC/DTD_ext in CTA861
1265     for (i = 0; i < pInfo->total_timings; i++)
1266     {
1267         data = NvTiming_GetCEA861TimingIndex(&pInfo->timing[i]);
1268         // DisplayID block did not belong to CTA timing and it owned the deep color block itself
1269         if (data && !((NVT_GET_TIMING_STATUS_TYPE(pInfo->timing[i].etc.status) == NVT_TYPE_DISPLAYID_1) ||
1270                       (NVT_GET_TIMING_STATUS_TYPE(pInfo->timing[i].etc.status) == NVT_TYPE_DISPLAYID_2) ||
1271                       (NVT_GET_TIMING_STATUS_TYPE(pInfo->timing[i].etc.status) == NVT_TYPE_DISPLAYID_7) ||
1272                       (NVT_GET_TIMING_STATUS_TYPE(pInfo->timing[i].etc.status) == NVT_TYPE_DISPLAYID_8) ||
1273                       (NVT_GET_TIMING_STATUS_TYPE(pInfo->timing[i].etc.status) == NVT_TYPE_DISPLAYID_9) ||
1274                       (NVT_GET_TIMING_STATUS_TYPE(pInfo->timing[i].etc.status) == NVT_TYPE_DISPLAYID_10)))
1275         {
1276             // CEA timings may be enumerated outside of SVD blocks -- the formats of these timings don't have CEA FORMAT (vic) set
1277             // before marking them CEA, make sure their color formats are updated too
1278             if (NVT_GET_CEA_FORMAT(pInfo->timing[i].etc.status) == 0 &&
1279                 (!NVT_IS_DTD(pInfo->timing[i].etc.status) ||
1280                  isMatchedCTA861Timing(pInfo, &pInfo->timing[i])))
1281             {
1282                 for (j = 0; j < pInfo->total_timings; j++)
1283                 {
1284                     // It is assumed CTA timings that are repeated by the CTA block or different CTA blocks will
1285                     // announce the same color format for the same CTA timings
1286                     if (NVT_GET_CEA_FORMAT(pInfo->timing[j].etc.status) == data)
1287                     {
1288                         // There could be anomalies between EDID 1.4 base block color format vs CEA861 basic caps
1289                         // In this case we assume the union is supported
1290                         pInfo->timing[i].etc.rgb444.bpcs |= pInfo->timing[j].etc.rgb444.bpcs;
1291                         pInfo->timing[i].etc.yuv444.bpcs |= pInfo->timing[j].etc.yuv444.bpcs;
1292                         pInfo->timing[i].etc.yuv422.bpcs |= pInfo->timing[j].etc.yuv422.bpcs;
1293                         pInfo->timing[i].etc.yuv420.bpcs |= pInfo->timing[j].etc.yuv420.bpcs;
1294                         break;
1295                     }
1296                 }
1297 
1298                 // now update the VIC of this timing
1299                 NVT_SET_CEA_FORMAT(pInfo->timing[i].etc.status, data);
1300             }
1301             // see the aspect ratio info if needed
1302             if (pInfo->timing[i].etc.aspect == 0)
1303             {
1304                 pInfo->timing[i].etc.aspect = getCEA861TimingAspectRatio(data);
1305             }
1306         }
1307     }
1308 }
1309 
CODE_SEGMENT(PAGE_DD_CODE)1310 CODE_SEGMENT(PAGE_DD_CODE)
1311 NvBool isMatchedStandardTiming(NVT_EDID_INFO *pInfo, NVT_TIMING *pT)
1312 {
1313     NvU32 j;
1314 
1315     for (j = 0; j < pInfo->total_timings; j++)
1316     {
1317         if (NVT_GET_TIMING_STATUS_TYPE(pInfo->timing[j].etc.status) == NVT_TYPE_EDID_STD &&
1318             NvTiming_IsTimingRelaxedEqual(&pInfo->timing[j], pT))
1319         {
1320             return NV_TRUE;
1321         }
1322     }
1323     return NV_FALSE;
1324 }
1325 
CODE_SEGMENT(PAGE_DD_CODE)1326 CODE_SEGMENT(PAGE_DD_CODE)
1327 NvBool isMatchedEstablishedTiming(NVT_EDID_INFO *pInfo, NVT_TIMING *pT)
1328 {
1329     NvU32 j;
1330 
1331     for (j = 0; j < pInfo->total_timings; j++)
1332     {
1333         if (NVT_GET_TIMING_STATUS_TYPE(pInfo->timing[j].etc.status) == NVT_TYPE_EDID_EST &&
1334             NvTiming_IsTimingRelaxedEqual(&pInfo->timing[j], pT))
1335         {
1336             return NV_TRUE;
1337         }
1338     }
1339     return NV_FALSE;
1340 }
1341 
CODE_SEGMENT(PAGE_DD_CODE)1342 CODE_SEGMENT(PAGE_DD_CODE)
1343 NvBool isMatchedCTA861Timing(NVT_EDID_INFO *pInfo, NVT_TIMING *pT)
1344 {
1345     NvU32 j;
1346 
1347     for (j = 0; j < pInfo->total_timings; j++)
1348     {
1349         if (NVT_GET_CEA_FORMAT(pInfo->timing[j].etc.status) && NvTiming_IsTimingExactEqual(&pInfo->timing[j], pT))
1350         {
1351             return NV_TRUE;
1352         }
1353     }
1354     return NV_FALSE;
1355 }
1356 
CODE_SEGMENT(PAGE_DD_CODE)1357 CODE_SEGMENT(PAGE_DD_CODE)
1358 void updateBpcForTiming(NVT_EDID_INFO *pInfo, NvU32 index)
1359 {
1360     NVT_EDID_CEA861_INFO *p861Info;
1361 
1362     // assume/prefer data from 1st CEA block if multiple exist
1363     p861Info = &pInfo->ext861;
1364 
1365     pInfo->timing[index].etc.rgb444.bpc.bpc8 = 1;
1366 
1367     if (pInfo->version >= NVT_EDID_VER_1_4 && pInfo->input.isDigital)
1368     {
1369         if (pInfo->u.feature_ver_1_4_digital.support_ycrcb_444)
1370         {
1371             pInfo->timing[index].etc.yuv444.bpc.bpc8 = 1;
1372         }
1373         if (pInfo->u.feature_ver_1_4_digital.support_ycrcb_422)
1374         {
1375             pInfo->timing[index].etc.yuv422.bpc.bpc8 = 1;
1376         }
1377         if (pInfo->input.u.digital.video_interface == NVT_EDID_DIGITAL_VIDEO_INTERFACE_STANDARD_DISPLAYPORT_SUPPORTED ||
1378             pInfo->input.u.digital.video_interface == NVT_EDID_DIGITAL_VIDEO_INTERFACE_STANDARD_UNDEFINED)
1379         {
1380             pInfo->timing[index].etc.rgb444.bpc.bpc6 = 1;
1381 
1382             // trust bpc claim in edid base block for DP only
1383             if (pInfo->input.u.digital.bpc >= NVT_EDID_VIDEOSIGNAL_BPC_10)
1384             {
1385                 pInfo->timing[index].etc.rgb444.bpc.bpc10 = 1;
1386                 pInfo->timing[index].etc.yuv444.bpc.bpc10 = pInfo->u.feature_ver_1_4_digital.support_ycrcb_444 || (p861Info->basic_caps & NVT_CEA861_CAP_YCbCr_444);
1387                 pInfo->timing[index].etc.yuv422.bpc.bpc10 = pInfo->u.feature_ver_1_4_digital.support_ycrcb_422 || (p861Info->basic_caps & NVT_CEA861_CAP_YCbCr_422);
1388             }
1389             if (pInfo->input.u.digital.bpc >= NVT_EDID_VIDEOSIGNAL_BPC_12)
1390             {
1391                 pInfo->timing[index].etc.rgb444.bpc.bpc12 = 1;
1392                 pInfo->timing[index].etc.yuv444.bpc.bpc12 = pInfo->u.feature_ver_1_4_digital.support_ycrcb_444 || (p861Info->basic_caps & NVT_CEA861_CAP_YCbCr_444);
1393                 pInfo->timing[index].etc.yuv422.bpc.bpc12 = pInfo->u.feature_ver_1_4_digital.support_ycrcb_422 || (p861Info->basic_caps & NVT_CEA861_CAP_YCbCr_422);
1394             }
1395             if (pInfo->input.u.digital.bpc >= NVT_EDID_VIDEOSIGNAL_BPC_16)
1396             {
1397                 pInfo->timing[index].etc.rgb444.bpc.bpc16 = 1;
1398                 pInfo->timing[index].etc.yuv444.bpc.bpc16 = pInfo->u.feature_ver_1_4_digital.support_ycrcb_444 || (p861Info->basic_caps & NVT_CEA861_CAP_YCbCr_444);
1399                 pInfo->timing[index].etc.yuv422.bpc.bpc16 = pInfo->u.feature_ver_1_4_digital.support_ycrcb_422 || (p861Info->basic_caps & NVT_CEA861_CAP_YCbCr_422);
1400             }
1401         }
1402         else if ((pInfo->input.u.digital.video_interface == NVT_EDID_DIGITAL_VIDEO_INTERFACE_STANDARD_HDMI_A_SUPPORTED ||
1403                   pInfo->input.u.digital.video_interface == NVT_EDID_DIGITAL_VIDEO_INTERFACE_STANDARD_HDMI_B_SUPPORTED ||
1404                   pInfo->input.u.digital.video_interface == NVT_EDID_DIGITAL_VIDEO_INTERFACE_STANDARD_UNDEFINED) &&
1405                  p861Info->revision >= NVT_CEA861_REV_A)
1406         {
1407             updateHDMILLCDeepColorForTiming(pInfo, index);
1408         }
1409     }
1410     else if (p861Info->revision >= NVT_CEA861_REV_A)
1411     {
1412         updateHDMILLCDeepColorForTiming(pInfo, index);
1413     }
1414 }
1415 
CODE_SEGMENT(PAGE_DD_CODE)1416 CODE_SEGMENT(PAGE_DD_CODE)
1417 NVT_STATUS NvTiming_Get18ByteLongDescriptorIndex(NVT_EDID_INFO *pEdidInfo, NvU8 tag, NvU32 *pDtdIndex)
1418 {
1419     NvU32 dtdIndex;
1420 
1421     if (!pEdidInfo || !pDtdIndex)
1422     {
1423         return NVT_STATUS_ERR;
1424     }
1425 
1426     for (dtdIndex = *pDtdIndex; dtdIndex < NVT_EDID_MAX_LONG_DISPLAY_DESCRIPTOR; dtdIndex++)
1427     {
1428         if (pEdidInfo->ldd[dtdIndex].tag == tag)
1429         {
1430             *pDtdIndex = dtdIndex;
1431             return NVT_STATUS_SUCCESS;
1432         }
1433     }
1434 
1435     return NVT_STATUS_ERR;
1436 }
1437 
1438 // get the edid timing
CODE_SEGMENT(PAGE_DD_CODE)1439 CODE_SEGMENT(PAGE_DD_CODE)
1440 NVT_STATUS NvTiming_GetEdidTimingExWithPclk(NvU32 width, NvU32 height, NvU32 rr, NvU32 flag, NVT_EDID_INFO *pEdidInfo, NVT_TIMING *pT, NvU32 rrx1k, NvU32 pclk)
1441 {
1442     NvU8 kth = 0;
1443     NvU32 i, j;
1444     NvU32 native_cta, preferred_cta, preferred_displayid_dtd, preferred_dtd1, dtd1, map0, map1, map2, map3, map4, ceaIndex, max, cvt;
1445     NVT_TIMING *pEdidTiming;
1446     NVT_EDID_DD_RANGE_CVT *pCVT = NULL;
1447     NVT_TIMING cvtTiming;
1448 
1449     // input check
1450     if (pEdidInfo == NULL || pEdidInfo->total_timings == 0 || pT == 0)
1451         return NVT_STATUS_ERR;
1452 
1453     if (width == 0 || height == 0 || rr == 0 ) // rrx1k and pclk are optional, can be 0.
1454         return NVT_STATUS_ERR;
1455 
1456     pEdidTiming = pEdidInfo->timing;
1457 
1458     // the timing mapping index :
1459     //
1460     // native_cta              - the "native resoluiotn of the sink" in the CTA861.6 A Source shall override any other native video resolution indicators
1461     //                           if the Source supports NVRDB and the NVRDB was found in the E-EDID
1462     // preferred_cta           - the "prefer SVD" in CTA-861-F (i.e. A Sink that prefers a Video Format that is not listed as an SVD in Video Data Block, but instead listed in YCBCR 4:2:0 VDB)
1463     // preferred_displayid_dtd - the "prefer detailed timing of DispalyID" extension
1464     // preferred_dtd1          - the first deatiled timing and PTM flag is enable
1465     // dtd1 - the first detailed timing
1466     // map0 - the "perfect" match (the timing's H/V-visible and pixel clock(refresh rate) are the same as the asking "width", "height" and "rr".
1467     // map1 - the "closest" match with the honor of the interlaced flag
1468     // map2 - the "closest" match without the honor of the interlaced flag
1469     // map3 - the "closest" match to the panel's native timing (i.e. the first DTD timing or the short 861B/C/D timings with "native" flag).
1470     // map4 - the "closest" match with the same refresh rate
1471     // max  - the timing with the max visible area
1472     native_cta = preferred_cta = preferred_displayid_dtd = preferred_dtd1 = dtd1 = map0 = map1 = map2 = map3 = map4 = ceaIndex = pEdidInfo->total_timings;
1473     max = cvt = 0;
1474 
1475     if (pEdidInfo->ext861.total_svr > 1)
1476     {
1477         kth = getHighestPrioritySVRIdx(&pEdidInfo->ext861);
1478     }
1479 
1480     for (i = 0; i < pEdidInfo->total_timings; i++)
1481     {
1482         // if the client prefers _NATIVE timing, then don't select custom timing
1483         if ((flag & (NVT_FLAG_NATIVE_TIMING | NVT_FLAG_EDID_TIMING)) != 0 && NVT_IS_CUST_ENTRY(pEdidTiming[i].etc.status) != 0)
1484         {
1485             continue;
1486         }
1487 
1488         // find the perfect match is possible
1489         if ((flag & NVT_FLAG_MAX_EDID_TIMING) == 0 &&
1490             width  == pEdidTiming[i].HVisible &&
1491             height == frame_height(pEdidTiming[i]) &&
1492             rr     == pEdidTiming[i].etc.rr   &&
1493             ((rrx1k == 0) || (rrx1k == pEdidTiming[i].etc.rrx1k)) &&
1494             !!(flag & NVT_PVT_INTERLACED_MASK) == !!pEdidTiming[i].interlaced)
1495         {
1496             if (map0 >= pEdidInfo->total_timings || pEdidTiming[i].pclk == pclk)
1497             {
1498                 // make sure we take the priority as "detailed>standard>established". (The array timing[] always have the detailed timings in the front and then the standard and established.)
1499                 map0 = i;
1500             }
1501 
1502             if ( (NVT_PREFERRED_TIMING_IS_CTA(pEdidTiming[i].etc.flag)) ||
1503                  ((0 == (flag & NVT_FLAG_EDID_861_ST)) && NVT_PREFERRED_TIMING_IS_DTD1(pEdidTiming[i].etc.flag, pEdidTiming[i].etc.status)) ||
1504                  (NVT_PREFERRED_TIMING_IS_DISPLAYID(pEdidTiming[i].etc.flag)) ||
1505                  (NVT_IS_NATIVE_TIMING(pEdidTiming[i].etc.status)))
1506             {
1507                 *pT = pEdidTiming[i];
1508                 return NVT_STATUS_SUCCESS;
1509             }
1510 
1511             if (NVT_GET_TIMING_STATUS_TYPE(pEdidTiming[i].etc.status) == NVT_TYPE_EDID_861ST)
1512             {
1513                 if (ceaIndex == pEdidInfo->total_timings)
1514                 {
1515                     // Save the first entry found.
1516                     ceaIndex = i;
1517                 }
1518                 else
1519                 {
1520                     if (((flag & NVT_FLAG_CEA_4X3_TIMING) && (pEdidTiming[i].etc.aspect == 0x40003)) ||
1521                         ((flag & NVT_FLAG_CEA_16X9_TIMING) && (pEdidTiming[i].etc.aspect == 0x160009)))
1522                     {
1523                         // Use preferred aspect ratio if specified.
1524                         ceaIndex = i;
1525                     }
1526                 }
1527             }
1528         } // if ((flag & NVT_FLAG_MAX_EDID_TIMING) == 0 &&
1529 
1530         // bypass the custom timing to be select for the mismatch case
1531         if (NVT_GET_TIMING_STATUS_TYPE(pEdidTiming[i].etc.status) == NVT_TYPE_CUST ||
1532             NVT_IS_CUST_ENTRY(pEdidTiming[i].etc.status) != 0)
1533         {
1534             if (width != pEdidTiming[i].HVisible || height != frame_height(pEdidTiming[i]) || rr != pEdidTiming[i].etc.rr)
1535             {
1536                 continue;
1537             }
1538         }
1539 
1540         // find out the preferred timing just in case of cea_vfpdb is existed
1541         if (native_cta == pEdidInfo->total_timings && NVT_NATIVE_TIMING_IS_CTA(pEdidTiming[i].etc.flag))
1542         {
1543             native_cta = i;
1544         }
1545 
1546         if (preferred_cta == pEdidInfo->total_timings && NVT_PREFERRED_TIMING_IS_CTA(pEdidTiming[i].etc.flag))
1547         {
1548             if (pEdidInfo->ext861.total_svr > 1)
1549             {
1550                 if (kth != 0)
1551                 {
1552                     // svr == vic
1553                     if (NVT_IS_CTA861(pEdidTiming[i].etc.status) && (NVT_GET_CEA_FORMAT(pEdidTiming[i].etc.status) == kth))
1554                     {
1555                         preferred_cta = i;
1556                     }
1557                     else if (NVT_GET_TIMING_STATUS_SEQ(pEdidTiming[i].etc.status) == kth)
1558                     {
1559                         preferred_cta = i;
1560                     }
1561                 }
1562             }
1563             else
1564             {
1565                 preferred_cta = i;
1566             }
1567         }
1568 
1569         // find out the preferred timing just in case
1570         // Caller we will force rr value as 1 to select the DisplayID prefer timing in pEdidTiming if it existed
1571         // however, we can't assign the correct refresh rate we want if we had two and above rr values which shared the same timing.
1572         if (rr != 1)
1573         {
1574             if (pEdidTiming[i].etc.rr == rr && NVT_PREFERRED_TIMING_IS_DISPLAYID(pEdidTiming[i].etc.flag))
1575             {
1576                 preferred_displayid_dtd = i;
1577             }
1578         }
1579         else if (preferred_displayid_dtd == pEdidInfo->total_timings &&
1580                 NVT_PREFERRED_TIMING_IS_DISPLAYID(pEdidTiming[i].etc.flag))
1581         {
1582                 preferred_displayid_dtd = i;
1583         }
1584 
1585         if (NVT_PREFERRED_TIMING_IS_DTD1(pEdidTiming[i].etc.flag, pEdidTiming[i].etc.status))
1586         {
1587             preferred_dtd1 = i;
1588         }
1589 
1590         if (NVT_IS_DTD1(pEdidTiming[i].etc.status))
1591         {
1592             dtd1 = i;
1593         }
1594 
1595         // find out the max mode just in case
1596         if (pEdidTiming[i].HVisible * pEdidTiming[i].VVisible > pEdidTiming[max].HVisible * pEdidTiming[max].VVisible)
1597             max = i;
1598 
1599         // if the requested timing is not in the EDID, try to find out the EDID entry with the same progressive/interlaced setting
1600         if (map1 >= pEdidInfo->total_timings)
1601         {
1602             if (!!(flag & NVT_PVT_INTERLACED_MASK) == !!pEdidTiming[i].interlaced &&
1603                 width  <= pEdidTiming[i].HVisible &&
1604                 height <= frame_height(pEdidTiming[i]))
1605             {
1606                 map1 = i;
1607             }
1608         }
1609         else
1610         {
1611             if (!!(flag & NVT_PVT_INTERLACED_MASK) == !!pEdidTiming[i].interlaced &&
1612                 width  <= pEdidTiming[i].HVisible &&
1613                 height <= frame_height(pEdidTiming[i]) &&
1614                 abs_delta(pEdidTiming[i].HVisible, width) <= abs_delta(pEdidTiming[map1].HVisible, width) &&
1615                 abs_delta(frame_height(pEdidTiming[i]), height) <= abs_delta(frame_height(pEdidTiming[map1]), height))
1616             {
1617                 // if there're 2 timings with the same visible size, choose the one with closer refresh rate
1618                 if (pEdidTiming[i].HVisible == pEdidTiming[map1].HVisible &&
1619                     frame_height(pEdidTiming[i]) == frame_height(pEdidTiming[map1]))
1620                 {
1621                     if (abs_delta(pEdidTiming[i].etc.rr, rr) < abs_delta(pEdidTiming[map1].etc.rr, rr))
1622                     {
1623                         map1 = i;
1624                     }
1625                 }
1626                 else
1627                 {
1628                     map1 = i;
1629                 }
1630             }
1631         }
1632 
1633         // if the requested timing is not in the EDID, try to find out the EDID entry without the progressive/interlaced setting
1634         if (map2 >= pEdidInfo->total_timings)
1635         {
1636             if (width  <= pEdidTiming[i].HVisible &&
1637                 height <= frame_height(pEdidTiming[i]))
1638             {
1639                 map2 = i;
1640             }
1641         }
1642         else
1643         {
1644             if (width  <= pEdidTiming[i].HVisible &&
1645                 height <= frame_height(pEdidTiming[i]) &&
1646                 abs_delta(pEdidTiming[i].HVisible, width) <= abs_delta(pEdidTiming[map2].HVisible, width) &&
1647                 abs_delta(frame_height(pEdidTiming[i]), height) <= abs_delta(frame_height(pEdidTiming[map2]), height))
1648             {
1649                 // if there're 2 timings with the same visible size, choose the one with closer refresh rate
1650                 if (pEdidTiming[i].HVisible == pEdidTiming[map2].HVisible &&
1651                     frame_height(pEdidTiming[i]) == frame_height(pEdidTiming[map2]))
1652                 {
1653                     if (abs_delta(pEdidTiming[i].etc.rr, rr) < abs_delta(pEdidTiming[map2].etc.rr, rr))
1654                     {
1655                         map2 = i;
1656                     }
1657                 }
1658                 else
1659                 {
1660                     map2 = i;
1661                 }
1662             }
1663         }
1664 
1665         // find out the native timing
1666         if (NVT_IS_NATIVE_TIMING(pEdidTiming[i].etc.status) || NVT_IS_DTD1(pEdidTiming[i].etc.status))
1667         {
1668             if (map3 >= pEdidInfo->total_timings)
1669             {
1670                 if (width  <= pEdidTiming[i].HVisible &&
1671                     height <= frame_height(pEdidTiming[i]))
1672                 {
1673                     map3 = i;
1674                 }
1675             }
1676             else if(abs_delta(pEdidTiming[i].HVisible, width) <= abs_delta(pEdidTiming[map3].HVisible, width) &&
1677                 abs_delta(frame_height(pEdidTiming[i]), height) <= abs_delta(frame_height(pEdidTiming[map3]), height) &&
1678                 width  <= pEdidTiming[i].HVisible &&
1679                 height <= frame_height(pEdidTiming[i]))
1680             {
1681                 map3 = i;
1682             }
1683         }
1684 
1685         // find the edid timing with refresh rate matching
1686         if (map4 >= pEdidInfo->total_timings)
1687         {
1688             if (width  <= pEdidTiming[i].HVisible &&
1689                 height <= pEdidTiming[i].VVisible &&
1690                 rr == pEdidTiming[i].etc.rr)
1691             {
1692                 map4 = i;
1693             }
1694         }
1695         else
1696         {
1697             if (width  <= pEdidTiming[i].HVisible &&
1698                 height <= pEdidTiming[i].HVisible &&
1699                 rr     == pEdidTiming[i].etc.rr   &&
1700                 abs_delta(pEdidTiming[i].HVisible, width)  <= abs_delta(pEdidTiming[map4].HVisible, width) &&
1701                 abs_delta(pEdidTiming[i].VVisible, height) <= abs_delta(pEdidTiming[map4].VVisible, height))
1702             {
1703                 map4 = i;
1704             }
1705         }
1706 
1707     }//for (i = 0; i < pEdidInfo->total_timings; i++)
1708 
1709     if ( (preferred_displayid_dtd == preferred_dtd1) && (preferred_dtd1 == dtd1) &&
1710          (dtd1 == map0) &&
1711          (map0 == map1) &&
1712          (map1 == map2) &&
1713          (map2 == map3) &&
1714          (map3 == map4) &&
1715          (map4 == pEdidInfo->total_timings) &&
1716          pEdidInfo->version >= NVT_EDID_VER_1_4 &&
1717          pEdidInfo->u.feature_ver_1_4_digital.continuous_frequency &&
1718          !(flag & NVT_PVT_INTERLACED_MASK))
1719     {
1720         // try to find CVT timing that fits
1721         NvU32 maxHeight, minHeight, tempHeight;
1722 
1723         minHeight = ~0;
1724         maxHeight = tempHeight= 0;
1725 
1726         // looping through long display descriptors
1727         for (i=0; i<NVT_EDID_MAX_LONG_DISPLAY_DESCRIPTOR; i++)
1728         {
1729             if (pEdidInfo->ldd[i].tag != NVT_EDID_DISPLAY_DESCRIPTOR_DRL || pEdidInfo->ldd[i].u.range_limit.timing_support != NVT_EDID_RANGE_SUPPORT_CVT)
1730             {
1731                 continue;
1732             }
1733 
1734             pCVT = &pEdidInfo->ldd[i].u.range_limit.u.cvt;
1735 
1736             if (width <= pCVT->max_active_pixels_per_line || (pCVT->scaling_support & NVT_EDID_CVT_SCALING_HOR_SHRINK))
1737             {
1738                 for (j=0; j<NVT_EDID_CVT_ASPECT_SUPPORT_MAX && !cvt; j++)
1739                 {
1740                     if ( !(pCVT->aspect_supported & (1<<j)))
1741                     {
1742                         continue;
1743                     }
1744 
1745                     switch (1<<j)
1746                     {
1747                         case NVT_EDID_CVT_ASPECT_SUPPORT_4X3:
1748                             tempHeight = axb_div_c(width, 3, 4);
1749                             if (axb_div_c(width, 3, height) ==  4) cvt = 1;
1750                             break;
1751                         case NVT_EDID_CVT_ASPECT_SUPPORT_16X9:
1752                             tempHeight = axb_div_c(width, 9, 16);
1753                             if (axb_div_c(width, 9, height) == 16) cvt = 1;
1754                             break;
1755                         case NVT_EDID_CVT_ASPECT_SUPPORT_16X10:
1756                             tempHeight = axb_div_c(width, 10, 16);
1757                             if (axb_div_c(width,10, height) == 16) cvt = 1;
1758                             break;
1759                         case NVT_EDID_CVT_ASPECT_SUPPORT_5X4:
1760                             tempHeight = axb_div_c(width, 4, 5);
1761                             if (axb_div_c(width, 4, height) ==  5) cvt = 1;
1762                             break;
1763                         case NVT_EDID_CVT_ASPECT_SUPPORT_15X9:
1764                             tempHeight = axb_div_c(width, 9, 15);
1765                             if (axb_div_c(width, 9, height) == 15) cvt = 1;
1766                             break;
1767                     }
1768 
1769                     //keep track of max and min in case NVT_EDID_CVT_SCALING_VER_STRETCH/SHRINK are true
1770                     if (minHeight > tempHeight)
1771                     {
1772                         minHeight = tempHeight;
1773                     }
1774                     if (maxHeight < tempHeight)
1775                     {
1776                         maxHeight = tempHeight;
1777                     }
1778 
1779                 }//for (j=0; j<5; j++)
1780             }//if (width <= pCVT->max_active_pixels_per_line || (pCVT->scaling_support & NVT_EDID_CVT_SCALING_HOR_STRETCH))
1781 
1782             if ( ((minHeight < height) && (pCVT->scaling_support & NVT_EDID_CVT_SCALING_VER_SHRINK)) ||
1783                  ((maxHeight > height) && (pCVT->scaling_support & NVT_EDID_CVT_SCALING_VER_STRETCH)) )
1784             {
1785                 cvt = 1;
1786             }
1787 
1788             if (cvt)
1789             {
1790                 break;
1791             }
1792         }//for (i=0; i<NVT_EDID_MAX_LONG_DISPLAY_DESCRIPTOR; i++)
1793 
1794         if (cvt)
1795         {
1796             //calculate the CVT timing
1797             // pclk is in 10KHz, max_pclk_MHz is in MHz, pixel_clock_adjustment is in .25MHz - make sure timing pclk is inside the max pclk declared in the EDID
1798             if (pCVT->blanking_support & NVT_EDID_CVT_BLANKING_REDUCED && NvTiming_CalcCVT_RB(width, height, rr, NVT_PROGRESSIVE, &cvtTiming) == NVT_STATUS_SUCCESS)
1799             {
1800                 if ( cvtTiming.pclk > (NvU32)((pEdidInfo->ldd[i].u.range_limit.max_pclk_MHz * 100) - (pCVT->pixel_clock_adjustment * 25)) )
1801                 {
1802                     cvt = 0;
1803                 }
1804             }
1805             else if (pCVT->blanking_support & NVT_EDID_CVT_BLANKING_STANDARD && NvTiming_CalcCVT(width, height, rr, NVT_PROGRESSIVE, &cvtTiming) == NVT_STATUS_SUCCESS)
1806             {
1807                 if ( cvtTiming.pclk > (NvU32)((pEdidInfo->ldd[i].u.range_limit.max_pclk_MHz * 100) - (pCVT->pixel_clock_adjustment * 25)) )
1808                 {
1809                     cvt = 0;
1810                 }
1811             }
1812             else
1813             {
1814                 cvt = 0;
1815             }
1816 
1817         }
1818     }//(dtd1 == map0 == map1 == map2 == map3 == pEdidInfo->total_timings) && pEdidInfo->version >= NVT_EDID_VER_1_4 &&
1819      //    pEdidInfo->feature_ver_1_4_digital.continuous_frequency && !(flag & NVT_PVT_INTERLACED_MASK))
1820 
1821     // now return the mismatched EDID timing
1822     if (flag & NVT_FLAG_NV_PREFERRED_TIMING)
1823     {
1824         *pT = (preferred_displayid_dtd != pEdidInfo->total_timings) ? pEdidTiming[preferred_displayid_dtd] :
1825               (native_cta     != pEdidInfo->total_timings)          ? pEdidTiming[native_cta]              :
1826               (preferred_cta  != pEdidInfo->total_timings)          ? pEdidTiming[preferred_cta]           :
1827               (preferred_dtd1 != pEdidInfo->total_timings)          ? pEdidTiming[preferred_dtd1]          :
1828                                                                       pEdidTiming[dtd1];
1829         // what if DTD1 itself is filtered out, in such case dtd1 index points to an invalid timing[]?
1830         // (dtd1 != pEdidInfo->total_timings) ? pEdidTiming[dtd1] : pEdidTiming[0];
1831     }
1832     else if (flag & NVT_FLAG_DTD1_TIMING)
1833     {
1834         *pT = pEdidTiming[dtd1];
1835     }
1836     else if ((flag & NVT_FLAG_MAX_EDID_TIMING) && (0 == (flag & NVT_FLAG_EDID_861_ST)))
1837     {
1838         *pT = pEdidTiming[max];
1839     }
1840     else if ((flag & (NVT_FLAG_CEA_4X3_TIMING | NVT_FLAG_CEA_16X9_TIMING | NVT_FLAG_EDID_861_ST)) && ceaIndex < (pEdidInfo->total_timings))
1841     {
1842         *pT = pEdidTiming[ceaIndex];
1843     }
1844     else if ((flag & NVT_FLAG_NATIVE_TIMING) != 0 && map3 < pEdidInfo->total_timings)
1845     {
1846         // Allow closest refresh rate match when EDID has detailed timing for different RR on native resolution.
1847         if (map0 < pEdidInfo->total_timings &&
1848             pEdidTiming[map0].HVisible == pEdidTiming[map3].HVisible &&
1849             pEdidTiming[map0].VVisible == pEdidTiming[map3].VVisible)
1850         {
1851             *pT = pEdidTiming[map0];
1852         }
1853         else
1854         {
1855             *pT = pEdidTiming[map3];
1856         }
1857     }
1858     else if (map0 < pEdidInfo->total_timings)
1859     {
1860         // use the exact mapped timing if possible
1861         *pT = pEdidTiming[map0];
1862     }
1863     else if ((flag & NVT_FLAG_EDID_TIMING_RR_MATCH) && map4 < pEdidInfo->total_timings)
1864     {
1865         *pT = pEdidTiming[map4];
1866     }
1867     else if (map1 < pEdidInfo->total_timings)
1868     {
1869         // use the mapped timing if possible
1870         *pT = pEdidTiming[map1];
1871     }
1872     else if (map2 < pEdidInfo->total_timings)
1873     {
1874         // use the 2nd mapped timing if possible
1875         *pT = pEdidTiming[map2];
1876     }
1877     else if (dtd1 < pEdidInfo->total_timings && width <= pEdidTiming[dtd1].HVisible && height <= pEdidTiming[dtd1].VVisible)
1878     {
1879         // use the 1st detailed timing if possible
1880         *pT = pEdidTiming[dtd1];
1881     }
1882     else if (cvt)
1883     {
1884         // use the cvt timing
1885         *pT = cvtTiming;
1886     }
1887     else
1888     {
1889         // use the max timing for all other cases
1890         *pT = pEdidTiming[max];
1891     }
1892 
1893     // set the mismatch status
1894     if (pT->HVisible != width || frame_height(*pT) != height)
1895     {
1896         NVT_SET_TIMING_STATUS_MISMATCH(pT->etc.status, NVT_STATUS_TIMING_MISMATCH_SIZE);
1897     }
1898     if (!NvTiming_IsRoundedRREqual(pT->etc.rr, pT->etc.rrx1k, (NvU16)rr))
1899     {
1900         NVT_SET_TIMING_STATUS_MISMATCH(pT->etc.status, NVT_STATUS_TIMING_MISMATCH_RR);
1901     }
1902     if (!!pT->interlaced != !!(flag & NVT_PVT_INTERLACED_MASK))
1903     {
1904         NVT_SET_TIMING_STATUS_MISMATCH(pT->etc.status, NVT_STATUS_TIMING_MISMATCH_FORMAT);
1905     }
1906 
1907     return NVT_STATUS_SUCCESS;
1908 }
1909 
CODE_SEGMENT(PAGE_DD_CODE)1910 CODE_SEGMENT(PAGE_DD_CODE)
1911 NVT_STATUS NvTiming_GetEdidTimingEx(NvU32 width, NvU32 height, NvU32 rr, NvU32 flag, NVT_EDID_INFO *pEdidInfo, NVT_TIMING *pT, NvU32 rrx1k)
1912 {
1913     return NvTiming_GetEdidTimingExWithPclk(width, height, rr, flag, pEdidInfo, pT, rrx1k, 0);
1914 }
1915 
1916 // get the edid timing
CODE_SEGMENT(PAGE_DD_CODE)1917 CODE_SEGMENT(PAGE_DD_CODE)
1918 NVT_STATUS NvTiming_GetEdidTiming(NvU32 width, NvU32 height, NvU32 rr, NvU32 flag, NVT_EDID_INFO *pEdidInfo, NVT_TIMING *pT)
1919 {
1920     return NvTiming_GetEdidTimingEx(width, height, rr, flag, pEdidInfo, pT, 0);
1921 }
CODE_SEGMENT(PAGE_DD_CODE)1922 CODE_SEGMENT(PAGE_DD_CODE)
1923 NVT_STATUS NvTiming_GetHDMIStereoExtTimingFromEDID(NvU32 width, NvU32 height, NvU32 rr, NvU8 StereoStructureType, NvU8 SideBySideHalfDetail, NvU32 flag, NVT_EDID_INFO *pEdidInfo, NVT_EXT_TIMING *pT)
1924 {
1925     NVT_STATUS  status = NVT_STATUS_ERR;
1926     NvU8        Vic;
1927     NvU32         i;
1928     NVT_TIMING  Timing;
1929 
1930     NVMISC_MEMSET(pT, 0, sizeof(NVT_EXT_TIMING));
1931 
1932     // adjust the flags --
1933     // need EDID timing with RR match,
1934     // not max timing,
1935     flag = flag | NVT_FLAG_EDID_TIMING | NVT_FLAG_EDID_TIMING_RR_MATCH | NVT_FLAG_EDID_861_ST;
1936     flag = flag & ~(NVT_FLAG_MAX_EDID_TIMING);
1937 
1938     status = NvTiming_GetEdidTiming(width, height, rr, flag, pEdidInfo, &Timing);
1939     if (NVT_STATUS_SUCCESS == status)
1940     {
1941         status = NVT_STATUS_ERR;
1942 
1943         // is this an exact match?
1944         if (0 == NVT_GET_TIMING_STATUS_MATCH(Timing.etc.status))
1945         {
1946             if (NVT_TYPE_EDID_861ST == NVT_GET_TIMING_STATUS_TYPE(Timing.etc.status))
1947             {
1948                 // lookup the vic for this timing in the support map.
1949                 Vic = (NvU8) NVT_GET_CEA_FORMAT(Timing.etc.status);
1950                 for (i = 0; i < pEdidInfo->Hdmi3Dsupport.total; ++i)
1951                 {
1952                     if (Vic == pEdidInfo->Hdmi3Dsupport.map[i].Vic)
1953                     {
1954                         break;
1955                     }
1956                 }
1957                 if (i < pEdidInfo->Hdmi3Dsupport.total)
1958                 {
1959                     // does this vic support the requested structure type?
1960                     if (0 != (NVT_HDMI_3D_SUPPORTED_STRUCT_MASK(StereoStructureType) & pEdidInfo->Hdmi3Dsupport.map[i].StereoStructureMask))
1961                     {
1962                         // if this is side-by-side(half) the detail needs to match also.
1963                         if ((NVT_HDMI_VS_BYTE5_HDMI_3DS_SIDEBYSIDEHALF != StereoStructureType) || (SideBySideHalfDetail == pEdidInfo->Hdmi3Dsupport.map[i].SideBySideHalfDetail))
1964                         {
1965                             // convert the 2D timing to 3D.
1966                             NvTiming_GetHDMIStereoTimingFrom2DTiming(&Timing, StereoStructureType, SideBySideHalfDetail, pT);
1967                             status = NVT_STATUS_SUCCESS;
1968                         }
1969                     }
1970                 }
1971             }
1972         }
1973     }
1974     return status;
1975 }
1976 
1977 // EDID based AspectRatio Timing
CODE_SEGMENT(PAGE_DD_CODE)1978 CODE_SEGMENT(PAGE_DD_CODE)
1979 NVT_STATUS NvTiming_GetEDIDBasedASPRTiming( NvU16 width, NvU16 height, NvU16 rr, NVT_EDID_INFO *pEI, NVT_TIMING *pT)
1980 {
1981     NvU32 i, dwStatus;
1982     NvU32 dwNativeIndex;
1983     NvU32 flag;
1984     NvU32 ret;
1985 
1986     // sanity check
1987     if( pEI == NULL || pEI->total_timings == 0 || pT == NULL )
1988     {
1989         return NVT_STATUS_ERR;
1990     }
1991     if( width == 0 || height == 0 )
1992     {
1993         return NVT_STATUS_ERR;
1994     }
1995 
1996     // get an EDID timing. Return err if it fails as we don't have any timing to tweak.
1997     flag = 0;
1998     ret = NvTiming_GetEdidTiming(width, height, rr, flag, pEI, pT);
1999     if( NVT_STATUS_SUCCESS != ret )
2000     {
2001         return NVT_STATUS_ERR;
2002     }
2003     // in case we have an exact match from EDID (in terms of Size), we return Success.
2004     else if ((NVT_GET_TIMING_STATUS_MATCH(pT->etc.status) & NVT_STATUS_TIMING_MISMATCH_SIZE) == 0)
2005     {
2006         return NVT_STATUS_SUCCESS;
2007     }
2008 
2009     // find the Native timing
2010     for (i = 0, dwNativeIndex = pEI->total_timings + 1; i < pEI->total_timings; i++)
2011     {
2012         dwStatus = pEI->timing[i].etc.status;
2013 
2014         if ((NVT_IS_NATIVE_TIMING(dwStatus)) || NVT_IS_DTD1(dwStatus))
2015         {
2016             dwNativeIndex = i;
2017             break;
2018         }
2019     }
2020 
2021     // we don't want to apply LogicScaling(Letterboxing) to Wide Mode on Wide Panel (or non-Wide Mode on non-Wide Panel)
2022     if( nvt_is_wideaspect(width, height) == nvt_is_wideaspect(pEI->timing[dwNativeIndex].HVisible, pEI->timing[dwNativeIndex].VVisible) )
2023     {
2024         return NVT_STATUS_ERR;
2025     }
2026 
2027     // Letterbox mode enabled by regkey LogicScalingMode
2028     // When we try to set modes not supported in EDID (eg. DFP over DSub) the display may not fit the screen.
2029     // If Logic Scaling is enabled (ie why we are here), we need to tweak the timing (for CRT) provided:
2030     //          1) the aspect ratio of native mode and requested mode differ
2031     //                                      eg. Native AR = 5:4,        1280x1024
2032     //                                          Requested AR = 16:10,   1280x800
2033     //          2) Both Width and Height do not mismatch together; If they do we shall go in for DMT/GTF timing
2034     //             by failing this call.
2035     if( pT->interlaced == 0 &&
2036         dwNativeIndex < pEI->total_timings &&
2037         (pEI->timing[dwNativeIndex].HVisible*height != pEI->timing[dwNativeIndex].VVisible*width) &&
2038         (width == pT->HVisible || height == pT->VVisible))
2039     {
2040         pT->HFrontPorch += (pT->HVisible - width) / 2;
2041         pT->VFrontPorch += (pT->VVisible - height) / 2;
2042         pT->HVisible = width;
2043         pT->VVisible = height;
2044         if(rr != pT->etc.rr)
2045         {
2046             pT->etc.rrx1k = rr * 1000;
2047             pT->pclk = RRx1kToPclk (pT);
2048         }
2049 
2050         pT->etc.status = NVT_STATUS_ASPR;
2051         return NVT_STATUS_SUCCESS;
2052     }
2053 
2054     return NVT_STATUS_ERR;
2055 }
2056 
2057 /**
2058  *
2059  * @brief check EDID raw data is valid or not, and it will return the err flags if it existed
2060  * @param pEdid  : this is a pointer to EDID data
2061  * @param length : read length of EDID
2062  * @param bIsTrongValidation : true - added more check
2063  *                             false- only header and checksum and size check
2064  *
2065  */
CODE_SEGMENT(PAGE_DD_CODE)2066 CODE_SEGMENT(PAGE_DD_CODE)
2067 NvU32 NvTiming_EDIDValidationMask(NvU8 *pEdid, NvU32 length, NvBool bIsStrongValidation)
2068 {
2069     NvU32                               i, j, version, checkSum;
2070     EDIDV1STRUC                         *p = (EDIDV1STRUC *)pEdid;
2071     EDID_LONG_DISPLAY_DESCRIPTOR        *pLdd;
2072     NvU8                                *pExt;
2073     DETAILEDTIMINGDESCRIPTOR            *pDTD;
2074     NvU32 ret = 0;
2075 
2076     // check the EDID base size to avoid accessing beyond the EDID buffer, do not proceed with
2077     // further validation.
2078     if (length < sizeof(EDIDV1STRUC))
2079     {
2080         ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_SIZE);
2081         return ret;
2082     }
2083 
2084     // check the EDID version and signature
2085     if (getEdidVersion(pEdid, &version) != NVT_STATUS_SUCCESS)
2086     {
2087         ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_VERSION);
2088         return ret;
2089     }
2090 
2091     // check block 0 checksum value
2092     if (!isChecksumValid(pEdid))
2093     {
2094         ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_CHECKSUM);
2095         return ret;
2096     }
2097 
2098     // Strong validation to follow
2099     if (bIsStrongValidation == NV_TRUE)
2100     {
2101         // range limit check
2102         for (i = 0; i < NVT_EDID_MAX_LONG_DISPLAY_DESCRIPTOR; i++)
2103         {
2104             pLdd = (EDID_LONG_DISPLAY_DESCRIPTOR *)&p->DetailedTimingDesc[i];
2105             if (pLdd->tag == NVT_EDID_DISPLAY_DESCRIPTOR_DRL && (version == 0x103 || (version == 0x104 && (p->bFeatureSupport & 1))))
2106             {
2107                 EDID_MONITOR_RANGE_LIMIT *pRangeLimit = (EDID_MONITOR_RANGE_LIMIT *)pLdd->data;
2108                 NvU8    max_v_rate_offset, min_v_rate_offset, max_h_rate_offset, min_h_rate_offset;
2109 
2110                 // add 255Hz offsets as needed before doing the check, use descriptor->rsvd2
2111                 nvt_assert(!(pLdd->rsvd2 & 0xF0));
2112 
2113                 max_v_rate_offset = pLdd->rsvd2 & NVT_PVT_EDID_RANGE_OFFSET_VER_MAX ? NVT_PVT_EDID_RANGE_OFFSET_AMOUNT : 0;
2114                 min_v_rate_offset = pLdd->rsvd2 & NVT_PVT_EDID_RANGE_OFFSET_VER_MIN ? NVT_PVT_EDID_RANGE_OFFSET_AMOUNT : 0;
2115                 max_h_rate_offset = pLdd->rsvd2 & NVT_PVT_EDID_RANGE_OFFSET_HOR_MAX ? NVT_PVT_EDID_RANGE_OFFSET_AMOUNT : 0;
2116                 min_h_rate_offset = pLdd->rsvd2 & NVT_PVT_EDID_RANGE_OFFSET_HOR_MIN ? NVT_PVT_EDID_RANGE_OFFSET_AMOUNT : 0;
2117 
2118                 if ((pRangeLimit->minVRate + min_v_rate_offset) > (pRangeLimit->maxVRate + max_v_rate_offset) ||
2119                     (pRangeLimit->minHRate + min_h_rate_offset) > (pRangeLimit->maxHRate + max_h_rate_offset) ||
2120                     pRangeLimit->maxVRate == 0 ||
2121                     pRangeLimit->maxHRate == 0)
2122                 {
2123                     ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_RANGE_LIMIT);
2124                 }
2125                 break;
2126             }
2127         }
2128 
2129         // extension and size check
2130         if ((NvU32)(p->bExtensionFlag + 1) * sizeof(EDIDV1STRUC) > length)
2131         {
2132             // Do not proceed with further validation if the size is invalid.
2133             ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_SIZE);
2134             return ret;
2135         }
2136 
2137         // validate Detailed Timing Descriptors, 4 blocks
2138         for (i = 0; i < 4; i++)
2139         {
2140             if (*((NvU16 *)&p->DetailedTimingDesc[i]) != 0)
2141             {
2142                 // This block is not a Display Descriptor.
2143                 // It must be a valid timing definition
2144                 // validate the block by passing NULL as the NVTIMING parameter to parseEdidDetailedTimingDescriptor
2145                 if (parseEdidDetailedTimingDescriptor((NvU8 *)&p->DetailedTimingDesc[i], NULL) != NVT_STATUS_SUCCESS)
2146                 {
2147                     ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_DTD);
2148                 }
2149             }
2150             else
2151             {
2152                 // This block is a display descriptor, validate
2153                 if (((EDID_LONG_DISPLAY_DESCRIPTOR *)&p->DetailedTimingDesc[i])->rsvd != 0)
2154                 {
2155                     ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_DTD);
2156                 }
2157             }
2158         }
2159 
2160         // validate extension blocks
2161         for (j = 1; j <= p->bExtensionFlag; j++)
2162         {
2163             pExt = pEdid + sizeof(EDIDV1STRUC) * j;
2164 
2165             // check for 861 extension
2166             switch (*pExt)
2167             {
2168                 case NVT_EDID_EXTENSION_CTA:
2169                     // first sanity check on the extension block
2170                     if (get861ExtInfo(pExt, sizeof(EIA861EXTENSION), NULL) != NVT_STATUS_SUCCESS)
2171                     {
2172                         ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXT);
2173                     }
2174 
2175                     // check sum on CEA extension block
2176                     for (i = 0, checkSum = 0; i < sizeof(EIA861EXTENSION); i ++)
2177                     {
2178                         checkSum += pExt[i];
2179                     }
2180 
2181                     if ((checkSum & 0xFF) != 0)
2182                     {
2183                         ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_CHECKSUM);
2184                     }
2185 
2186                     // 0 indicates no DTD in this block
2187                     if (((EIA861EXTENSION*)pExt)->offset == 0)
2188                     {
2189                         continue;
2190                     }
2191 
2192                     // validate DTD blocks
2193                     pDTD = (DETAILEDTIMINGDESCRIPTOR *)&pExt[((EIA861EXTENSION *)pExt)->offset];
2194                     while ((pDTD->wDTPixelClock != 0) &&
2195                            (((NvU8 *)pDTD - pExt + sizeof(DETAILEDTIMINGDESCRIPTOR)) < ((NvU8)sizeof(EIA861EXTENSION))))
2196                     {
2197                         if (parseEdidDetailedTimingDescriptor((NvU8 *)pDTD, NULL) != NVT_STATUS_SUCCESS)
2198                         {
2199                             ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXT_DTD);
2200                         }
2201                         pDTD++;
2202                     }
2203                     break;
2204                 case NVT_EDID_EXTENSION_VTB:
2205                     // perform a checksum on the VTB block
2206                     for (i = 0, checkSum = 0; i < sizeof(VTBEXTENSION); i++)
2207                     {
2208                         checkSum += pExt[i];
2209                     }
2210                     if ((checkSum & 0xFF) != 0)
2211                     {
2212                         ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_CHECKSUM);
2213                     }
2214                     break;
2215                 case NVT_EDID_EXTENSION_DISPLAYID:
2216                     // perform a checksum on the VTB block
2217                     for (i = 0, checkSum = 0; i < sizeof(EIA861EXTENSION); i++)
2218                     {
2219                         checkSum += pExt[i];
2220                     }
2221                     if ((checkSum & 0xFF) != 0)
2222                     {
2223                         ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_CHECKSUM);
2224                     }
2225                     break;
2226                 default:
2227                     break;
2228             }
2229         }
2230     }
2231 
2232     return ret;
2233 }
2234 
2235 /**
2236  *
2237  * @brief sanity check EDID binary frequently used data block is valid or not,
2238  *        and it will return error checkpoint flag if it existed
2239  * @param pEdid  : this is a pointer to EDID raw data
2240  * @param length : read length of EDID
2241  *
2242  */
CODE_SEGMENT(PAGE_DD_CODE)2243 CODE_SEGMENT(PAGE_DD_CODE)
2244 NvU32 NvTiming_EDIDStrongValidationMask(NvU8 *pEdid, NvU32 length)
2245 {
2246     NvU32                               i, j, version, extnCount;
2247     EDIDV1STRUC                         *p = (EDIDV1STRUC *)pEdid;
2248     EDID_LONG_DISPLAY_DESCRIPTOR        *pLdd;
2249     NvU8                                *pExt;
2250     DETAILEDTIMINGDESCRIPTOR            *pDTD;
2251     // For CTA861
2252     NvU8                                ctaDTD_Offset;
2253     NvU8                                *pData_collection;
2254     NvU32                               ctaBlockTag, ctaPayload, vic;
2255     // For DisplayID
2256     DIDEXTENSION                        *pDisplayid;
2257     NvU8                                did_section_length = 0x79;
2258     NvU8                                did2ExtCount = 0;
2259     DISPLAYID_2_0_DATA_BLOCK_HEADER     *pDID2Header;
2260     DISPLAYID_DATA_BLOCK_HEADER         *pHeader;
2261     NvU8                                block_length = 0;
2262     NvBool                              bAllZero = NV_TRUE;
2263     NvU32 ret = 0;
2264 
2265     // check the EDID base size to avoid accessing beyond the EDID buffer
2266     if (length < sizeof(EDIDV1STRUC) || (length > sizeof(EDIDV1STRUC) && (length % sizeof(EDIDV1STRUC) != 0)))
2267         ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_SIZE);
2268 
2269     // check the EDID version and signature
2270     if (getEdidVersion(pEdid, &version) != NVT_STATUS_SUCCESS)
2271         ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_HEADER);
2272 
2273     // check block 0 checksum value
2274     if (!isChecksumValid(pEdid))
2275         ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_CHECKSUM);
2276 
2277     if (p->bVersionNumber != 0x01 || p->bRevisionNumber > 0x04)
2278     {
2279         ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_VERSION);
2280     }
2281 
2282     // 18bytes in DTD or Display Descriptor check
2283     for (i = 0; i < NVT_EDID_MAX_LONG_DISPLAY_DESCRIPTOR; i++)
2284     {
2285         if (*((NvU16 *)&p->DetailedTimingDesc[i]) != 0)
2286         {
2287             // This block is not a Display Descriptor.
2288             // It must be a valid timing definition
2289             // validate the block by passing NULL as the NVTIMING parameter to parseEdidDetailedTimingDescriptor
2290             if (parseEdidDetailedTimingDescriptor((NvU8 *)&p->DetailedTimingDesc[i], NULL) != NVT_STATUS_SUCCESS)
2291             {
2292                 ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_DTD);
2293             }
2294             else
2295             {
2296                 // check the max image size in monitor and its DTD defines value
2297                 if (p->bMaxHorizImageSize != 0 && p->bMaxVertImageSize != 0)
2298                 {
2299                     DETAILEDTIMINGDESCRIPTOR *pDTD = (DETAILEDTIMINGDESCRIPTOR *)&p->DetailedTimingDesc[i];
2300                     NvU16 hDTDImageSize =  (pDTD->bDTHorizVertImage & 0xF0) << 4 | pDTD->bDTHorizontalImage;
2301                     NvU16 vDTDImageSize =  (pDTD->bDTHorizVertImage & 0x0F) << 8 | pDTD->bDTVerticalImage;
2302 
2303                     if ((hDTDImageSize/10) > p->bMaxHorizImageSize || (vDTDImageSize/10) > p->bMaxVertImageSize)
2304                     {
2305                         ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_DTD);
2306                     }
2307                 }
2308             }
2309         }
2310         else
2311         {
2312             pLdd = (EDID_LONG_DISPLAY_DESCRIPTOR *)&p->DetailedTimingDesc[i];
2313 
2314             // This block is a display descriptor, validate
2315             if (((EDID_LONG_DISPLAY_DESCRIPTOR *)&p->DetailedTimingDesc[i])->rsvd != 0  ||  // (00 00 00)h indicates Display Descriptor
2316                 (pLdd->tag >= 0x11 && pLdd->tag <= 0xF6))                                   // Reserved : Do Not Use
2317                 ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_DESCRIPTOR);
2318 
2319             if (pLdd->tag == NVT_EDID_DISPLAY_DESCRIPTOR_DRL && (version == 0x103 || (version == 0x104 && (p->bFeatureSupport & 1))))
2320             {
2321                 EDID_MONITOR_RANGE_LIMIT *pRangeLimit = (EDID_MONITOR_RANGE_LIMIT *)pLdd->data;
2322                 NvU8    max_v_rate_offset, min_v_rate_offset, max_h_rate_offset, min_h_rate_offset;
2323 
2324                 // add 255Hz offsets as needed before doing the check, use descriptor->rsvd2
2325                 nvt_assert(!(pLdd->rsvd2 & 0xF0));
2326 
2327                 max_v_rate_offset = pLdd->rsvd2 & NVT_PVT_EDID_RANGE_OFFSET_VER_MAX ? NVT_PVT_EDID_RANGE_OFFSET_AMOUNT : 0;
2328                 min_v_rate_offset = pLdd->rsvd2 & NVT_PVT_EDID_RANGE_OFFSET_VER_MIN ? NVT_PVT_EDID_RANGE_OFFSET_AMOUNT : 0;
2329                 max_h_rate_offset = pLdd->rsvd2 & NVT_PVT_EDID_RANGE_OFFSET_HOR_MAX ? NVT_PVT_EDID_RANGE_OFFSET_AMOUNT : 0;
2330                 min_h_rate_offset = pLdd->rsvd2 & NVT_PVT_EDID_RANGE_OFFSET_HOR_MIN ? NVT_PVT_EDID_RANGE_OFFSET_AMOUNT : 0;
2331 
2332                 if ((pRangeLimit->minVRate + min_v_rate_offset) > (pRangeLimit->maxVRate + max_v_rate_offset) ||
2333                     (pRangeLimit->minHRate + min_h_rate_offset) > (pRangeLimit->maxHRate + max_h_rate_offset) ||
2334                     pRangeLimit->maxVRate == 0 ||
2335                     pRangeLimit->maxHRate == 0)
2336                 {
2337                     ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_RANGE_LIMIT);
2338                 }
2339             }
2340         }
2341     }
2342 
2343     // extension and size check
2344     if ((NvU32)(p->bExtensionFlag + 1) * sizeof(EDIDV1STRUC) > length)
2345     {
2346         ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXTENSION_COUNT);
2347     }
2348 
2349     // we shall not trust any extension blocks with wrong input EDID size
2350     if (NVT_IS_EDID_VALIDATION_FLAGS(ret, NVT_EDID_VALIDATION_ERR_SIZE) ||
2351         NVT_IS_EDID_VALIDATION_FLAGS(ret, NVT_EDID_VALIDATION_ERR_EXTENSION_COUNT))
2352         return ret;
2353 
2354     // validate extension blocks
2355     for (j = 1; j <= p->bExtensionFlag; j++)
2356     {
2357         pExt = pEdid + sizeof(EDIDV1STRUC) * j;
2358 
2359         // check for 861 extension
2360         switch (*pExt)
2361         {
2362             case NVT_EDID_EXTENSION_CTA:
2363                 ctaDTD_Offset = ((EIA861EXTENSION *)pExt)->offset;
2364                 // first sanity check on the extension block
2365                 if (get861ExtInfo(pExt, sizeof(EIA861EXTENSION), NULL) != NVT_STATUS_SUCCESS ||
2366                     ((EIA861EXTENSION *)pExt)->revision < NVT_CEA861_REV_B)
2367                 {
2368                     ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXT_CTA_BASIC);
2369                 }
2370 
2371                 // 0 indicated there is no DTD and data collection in this block
2372                 if (ctaDTD_Offset == 0)
2373                 {
2374                     if(!isChecksumValid(pExt))
2375                         ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXT_CTA_CHECKSUM);
2376                     continue;
2377                 }
2378 
2379                 // validate SVD block
2380                 ctaBlockTag = NVT_CEA861_GET_SHORT_DESCRIPTOR_TAG(((EIA861EXTENSION *)pExt)->data[0]);
2381                 pData_collection = ((EIA861EXTENSION *)pExt)->data;
2382 
2383                 while ((ctaDTD_Offset - 4) > 0 && pData_collection != &pExt[ctaDTD_Offset] &&
2384                         ctaBlockTag > NVT_CEA861_TAG_RSVD && ctaBlockTag <= NVT_CEA861_TAG_EXTENDED_FLAG)
2385                 {
2386                     ctaBlockTag = NVT_CEA861_GET_SHORT_DESCRIPTOR_TAG(*pData_collection);
2387                     ctaPayload = NVT_CEA861_GET_SHORT_DESCRIPTOR_SIZE(*pData_collection);
2388 
2389                     if (parseCta861DataBlockInfo(pData_collection, (NvU32)ctaDTD_Offset - 4, NULL) == NVT_STATUS_SUCCESS)
2390                     {
2391                         pData_collection++; // go to the next byte. skip Tag+Length byte
2392 
2393                         if (ctaBlockTag == NVT_CEA861_TAG_VIDEO)
2394                         {
2395                             for (i=0; i < ctaPayload; i++)
2396                             {
2397                                 vic = NVT_GET_CTA_8BIT_VIC(*pData_collection);
2398                                 if (vic == 0 || vic > 255 || (vic >= 128 && vic <=192))
2399                                     ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXT_CTA_SVD);
2400                                 pData_collection++;
2401                             }
2402                         }
2403                         else if (ctaBlockTag == NVT_CEA861_TAG_EXTENDED_FLAG)
2404                         {
2405                             if (*pData_collection == NVT_CTA861_EXT_TAG_HF_EEODB)
2406                             {
2407                                 if ((p->bVersionNumber != 0x01) || (p->bRevisionNumber != 0x03))
2408                                 {
2409                                     ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXT_CTA_INVALID_DATA_BLOCK);
2410                                     pData_collection += ctaPayload;
2411                                 }
2412                                 else
2413                                 {
2414                                     ret &= ~NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXTENSION_COUNT);
2415                                     extnCount = *(++pData_collection);
2416                                     // check the EDID extension count value again because EDID extension block count
2417                                     // value in EEODB override it and source shall ignore extension flag > 1 value
2418                                     if ((extnCount + 1) != (length / (sizeof(EDIDV1STRUC))))
2419                                         ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXTENSION_COUNT);
2420                                     pData_collection++;
2421                                 }
2422                             }
2423                             else
2424                                 pData_collection += ctaPayload;
2425                         }
2426                         else if (ctaBlockTag == NVT_CEA861_TAG_RSVD)
2427                         {
2428                             ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXT_CTA_TAG);
2429                             pData_collection += ctaPayload;
2430                         }
2431                         else
2432                             pData_collection += ctaPayload;
2433                     }
2434                     else
2435                     {
2436                         pData_collection++; // go to the next byte. skip Tag+Length byte
2437 
2438                         ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXT_CTA_INVALID_DATA_BLOCK);
2439                         pData_collection += ctaPayload;
2440                     }
2441                 }
2442 
2443                 // validate DTD blocks
2444                 pDTD = (DETAILEDTIMINGDESCRIPTOR *)&pExt[((EIA861EXTENSION *)pExt)->offset];
2445                 while ((pDTD->wDTPixelClock != 0) &&
2446                        (((NvU8 *)pDTD - pExt + sizeof(DETAILEDTIMINGDESCRIPTOR)) < ((NvU8)sizeof(EIA861EXTENSION))))
2447                 {
2448                     if (parseEdidDetailedTimingDescriptor((NvU8 *)pDTD, NULL) != NVT_STATUS_SUCCESS)
2449                         ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXT_DTD);
2450                     else
2451                     {
2452                         // check the max image size and
2453                         if (p->bMaxHorizImageSize != 0 && p->bMaxVertImageSize != 0)
2454                         {
2455                             NvU16 hDTDImageSize =  (pDTD->bDTHorizVertImage & 0xF0) << 4 | pDTD->bDTHorizontalImage;
2456                             NvU16 vDTDImageSize =  (pDTD->bDTHorizVertImage & 0x0F) << 8 | pDTD->bDTVerticalImage;
2457 
2458                             if ((hDTDImageSize/10) > (p->bMaxHorizImageSize) || (vDTDImageSize/10) > p->bMaxVertImageSize)
2459                                 ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXT_CTA_DTD);
2460                         }
2461                     }
2462                     pDTD++;
2463                 }
2464 
2465                 if(!isChecksumValid(pExt))
2466                     ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXT_CTA_CHECKSUM);
2467             break;
2468             case NVT_EDID_EXTENSION_DISPLAYID:
2469                 pDisplayid = ((DIDEXTENSION *)pExt);
2470                 if (pDisplayid->ext_count != 0)
2471                     ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXT_DID_EXTCOUNT);
2472 
2473                 if (pDisplayid->length != 0x79)
2474                     ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXT_DID_SEC_SIZE);
2475 
2476                 if (!isChecksumValid(pExt))
2477                     ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXT_DID_CHECKSUM);
2478 
2479                 // check the DID2 data blocks
2480                 if ((pDisplayid->struct_version & 0xF0) >> 4 == 2)
2481                 {
2482                     if ((pDisplayid->struct_version & 0xFF) == 0x21)
2483                         ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXT_DID_VERSION);
2484 
2485                     did2ExtCount++;
2486 
2487                     if (pDisplayid->use_case == 0 && did2ExtCount == 1)
2488                         ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXT_DID2_USE_CASE);
2489 
2490                     // check the DisplayId2 valid timing
2491                     pDID2Header = (DISPLAYID_2_0_DATA_BLOCK_HEADER*)pDisplayid->data;
2492                     pData_collection = pDisplayid->data;
2493 
2494                     // Sanity check every data blocks
2495                     while (((pDID2Header->type >= DISPLAYID_2_0_BLOCK_TYPE_PRODUCT_IDENTITY &&
2496                             pDID2Header->type <= DISPLAYID_2_0_BLOCK_TYPE_BRIGHTNESS_LUMINANCE_RANGE) ||
2497                             pDID2Header->type == DISPLAYID_2_0_BLOCK_TYPE_VENDOR_SPEC                 ||
2498                             pDID2Header->type == DISPLAYID_2_0_BLOCK_TYPE_CTA_DATA) && pDID2Header->data_bytes != 0 &&
2499                             (pData_collection - pExt < (int)sizeof(DIDEXTENSION)))
2500                     {
2501                         if (parseDisplayId20EDIDExtDataBlocks(pData_collection, did_section_length, &block_length, NULL) ==  NVT_STATUS_ERR)
2502                         {
2503                             if (pDID2Header->type == DISPLAYID_2_0_BLOCK_TYPE_TIMING_7)
2504                                 ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXT_DID2_TYPE7);
2505 
2506                             if (pDID2Header->type == DISPLAYID_2_0_BLOCK_TYPE_RANGE_LIMITS)
2507                                 ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXT_RANGE_LIMIT);
2508 
2509                             if (pDID2Header->type == DISPLAYID_2_0_BLOCK_TYPE_ADAPTIVE_SYNC)
2510                                 ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXT_DID2_ADAPTIVE_SYNC);
2511                             // add more data blocks tag here to evaluate
2512                         }
2513                         pData_collection += block_length;
2514                         pDID2Header = (DISPLAYID_2_0_DATA_BLOCK_HEADER*)pData_collection;
2515                     }
2516 
2517                     // compare the remain 0 value are correct or not before meet checksum byte
2518                     for (i = 0; i < (NvU32)(&pDisplayid->data[NVT_DID_MAX_EXT_PAYLOAD-1] - pData_collection); i++)
2519                     {
2520                         if (pData_collection[i] != 0)
2521                         {
2522                             bAllZero = NV_FALSE;
2523                             break;
2524                         }
2525                     }
2526 
2527                     // if the first tag failed, ignore all the tags afterward then
2528                     if (!bAllZero &&
2529                         (pDID2Header->type < DISPLAYID_2_0_BLOCK_TYPE_PRODUCT_IDENTITY ||
2530                         (pDID2Header->type > DISPLAYID_2_0_BLOCK_TYPE_BRIGHTNESS_LUMINANCE_RANGE   &&
2531                         pDID2Header->type != DISPLAYID_2_0_BLOCK_TYPE_VENDOR_SPEC                  &&
2532                         pDID2Header->type != DISPLAYID_2_0_BLOCK_TYPE_CTA_DATA))       &&
2533                         (pData_collection - pExt < (int)sizeof(DIDEXTENSION)))
2534                     {
2535                         ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXT_DID2_TAG);
2536                         continue;
2537                     }
2538                 }
2539                 else if ((pDisplayid->struct_version & 0xFF) == 0x12 || (pDisplayid->struct_version & 0xFF) == 0x13)
2540                 {
2541                     if ((pDisplayid->struct_version & 0xFF) == 0x13)
2542                         ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXT_DID_VERSION);
2543 
2544                     pHeader = (DISPLAYID_DATA_BLOCK_HEADER*)pDisplayid->data;
2545                     pData_collection = pDisplayid->data;
2546 
2547                     // Sanity check every data blocks
2548                     while ((pHeader->type <= NVT_DISPLAYID_BLOCK_TYPE_TILEDDISPLAY ||
2549                             pHeader->type == NVT_DISPLAYID_BLOCK_TYPE_CTA_DATA     ||
2550                             pHeader->type == NVT_DISPLAYID_BLOCK_TYPE_VENDOR_SPEC) && pHeader->data_bytes != 0 &&
2551                         (pData_collection - pExt < (int)sizeof(DIDEXTENSION)))
2552                     {
2553                         if (parseDisplayIdBlock(pData_collection, did_section_length, &block_length, NULL) == NVT_STATUS_ERR)
2554                         {
2555                             if (pHeader->type == NVT_DISPLAYID_BLOCK_TYPE_TIMING_1)
2556                                 ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXT_DID13_TYPE1);
2557 
2558                             if (pHeader->type == NVT_DISPLAYID_BLOCK_TYPE_RANGE_LIMITS)
2559                                 ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXT_RANGE_LIMIT);
2560 
2561                             // add more data blocks tag here to evaluate
2562                         }
2563                         pData_collection += block_length;
2564                         pHeader = (DISPLAYID_DATA_BLOCK_HEADER*)pData_collection;
2565                     }
2566 
2567                     // compare the remain 0 value are correct or not before meet checksum byte
2568                     for (i = 0; i < (NvU32)(&pDisplayid->data[NVT_DID_MAX_EXT_PAYLOAD-1] - pData_collection); i++)
2569                     {
2570                         if (pData_collection[i] != 0)
2571                         {
2572                             bAllZero = NV_FALSE;
2573                             break;
2574                         }
2575                     }
2576 
2577                     // if the first tag failed, ignore all the tags afterward then
2578                     if (!bAllZero                                             &&
2579                         pHeader->type > NVT_DISPLAYID_BLOCK_TYPE_TILEDDISPLAY &&
2580                         pHeader->type != NVT_DISPLAYID_BLOCK_TYPE_CTA_DATA    &&
2581                         pHeader->type != NVT_DISPLAYID_BLOCK_TYPE_VENDOR_SPEC &&
2582                         (pData_collection - pExt < (int)sizeof(DIDEXTENSION)))
2583                     {
2584                         ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXT_DID13_TAG);
2585                         continue;
2586                     }
2587                 }
2588                 else
2589                     ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXT_DID_VERSION);
2590             break;
2591             default:
2592                 // the useful extension only CTA (0x02) and DisplayID (0x70)
2593                 if ( *pExt != NVT_EDID_EXTENSION_VTB && *pExt != NVT_EDID_EXTENSION_DI   &&
2594                     *pExt != NVT_EDID_EXTENSION_LS  && *pExt != NVT_EDID_EXTENSION_DPVL &&
2595                     *pExt != NVT_EDID_EXTENSION_BM  && *pExt != NVT_EDID_EXTENSION_OEM )
2596                 {
2597                     ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXTENSION_TAG);
2598                 }
2599             break;
2600         }
2601     }
2602 
2603     return ret;
2604 }
2605 
CODE_SEGMENT(PAGE_DD_CODE)2606 CODE_SEGMENT(PAGE_DD_CODE)
2607 NVT_STATUS NvTiming_EDIDValidation (NvU8 *pEdid, NvU32 length, NvBool bIsStrongValidation)
2608 {
2609     if (NvTiming_EDIDValidationMask(pEdid, length, bIsStrongValidation) != 0) {
2610         return NVT_STATUS_ERR;
2611     } else {
2612         return NVT_STATUS_SUCCESS;
2613     }
2614 }
2615 
2616 // Function Description: Get the first Detailed Timing Descriptor
2617 //
2618 // Parameters:
2619 //        pEdidInfo:  IN - pointer to parsed EDID
2620 //               pT:  OUT - pointer to where the DTD1 timing will be stored
2621 //
2622 // Return:
2623 //             NVT_STATUS_SUCCESS: DTD1 was found in parsed EDID, pT is a valid result
2624 //   NVT_STATUS_INVALID_PARAMETER: one or more parameter was invalid
2625 //           NVT_STATUS_ERR: DTD1 was not found in parsed EDID, pT is invalid
CODE_SEGMENT(PAGE_DD_CODE)2626 CODE_SEGMENT(PAGE_DD_CODE)
2627 NVT_STATUS NvTiming_GetDTD1Timing (NVT_EDID_INFO * pEdidInfo, NVT_TIMING * pT)
2628 {
2629     NvU32 j;
2630 
2631     // check param
2632     if (pEdidInfo == NULL || pT == NULL)
2633     {
2634         return NVT_STATUS_INVALID_PARAMETER;
2635     }
2636 
2637     // find the PTM mode
2638     for (j = 0; j < pEdidInfo->total_timings; j++)
2639     {
2640         if (NVT_PREFERRED_TIMING_IS_DTD1(pEdidInfo->timing[j].etc.flag, pEdidInfo->timing[j].etc.status))
2641         {
2642             *pT = pEdidInfo->timing[j];
2643             return NVT_STATUS_SUCCESS;
2644         }
2645     }
2646 
2647     // find DisplayID preferred
2648     for (j = 1; j < pEdidInfo->total_timings; j++)
2649     {
2650         if (NVT_PREFERRED_TIMING_IS_DISPLAYID(pEdidInfo->timing[j].etc.flag))
2651         {
2652             *pT = pEdidInfo->timing[j];
2653             return NVT_STATUS_SUCCESS;
2654         }
2655     }
2656 
2657     // DTD1 should exist, but if it doesn't, return not found
2658     for (j = 0; j < pEdidInfo->total_timings; j++)
2659     {
2660         NvU32 data = pEdidInfo->timing[j].etc.status;
2661         if (NVT_IS_DTD1(data))
2662         {
2663             *pT = pEdidInfo->timing[j];
2664             return NVT_STATUS_SUCCESS;
2665         }
2666     }
2667 
2668     // DTD1 should exist, but if it doesn't, return not found
2669     return NVT_STATUS_ERR;
2670 }
2671 
2672 // Description: Parses a VTB extension block into its associated timings
2673 //
2674 // Parameters:
2675 //     pEdidExt: IN - pointer to the beginning of the extension block
2676 //        pInfo: IN - The original block information, including the
2677 //                    array of timings.
2678 //
2679 // NOTE: this function *really* should be in its own separate file, but a certain DVS test
2680 // uses cross build makefiles which do not allow the specification of a new file.
CODE_SEGMENT(PAGE_DD_CODE)2681 CODE_SEGMENT(PAGE_DD_CODE)
2682 void parseVTBExtension(NvU8 *pEdidExt, NVT_EDID_INFO *pInfo)
2683 {
2684     NvU32 i;
2685     VTBEXTENSION *pExt = (VTBEXTENSION *)pEdidExt;
2686     NvU32 count;
2687     NvU32 bytes;
2688     NVT_TIMING newTiming;
2689 
2690     // Null = bad idea
2691     if (pEdidExt == NULL)
2692     {
2693         return;
2694     }
2695 
2696     // Sanity check for VTB extension block
2697     if (pExt->tag != NVT_EDID_EXTENSION_VTB ||
2698         pExt->revision == NVT_VTB_REV_NONE)
2699     {
2700         return;
2701     }
2702 
2703     // Sanity check - ensure that the # of descriptor does not exceed
2704     // byte size
2705     count = (NvU32)sizeof(EDID_LONG_DISPLAY_DESCRIPTOR) * pExt->num_detailed
2706           + (NvU32)sizeof(EDID_CVT_3BYTE_BLOCK) * pExt->num_cvt
2707           + (NvU32)sizeof(NvU16) * pExt->num_standard;
2708     if (count > NVT_VTB_MAX_PAYLOAD)
2709     {
2710         return;
2711     }
2712 
2713     count = 0;
2714     bytes = 0;
2715 
2716     // Process Detailed Timings
2717     for (i = 0; i < pExt->num_detailed; i++)
2718     {
2719         NVMISC_MEMSET(&newTiming, 0, sizeof(newTiming));
2720 
2721         if (parseEdidDetailedTimingDescriptor((NvU8 *)(pExt->data + bytes),
2722                                               &newTiming) == NVT_STATUS_SUCCESS)
2723         {
2724             newTiming.etc.name[39] = '\0';
2725             newTiming.etc.status = NVT_STATUS_EDID_VTB_EXT_DTDn(++count);
2726 
2727             if (!assignNextAvailableTiming(pInfo, &newTiming))
2728             {
2729                 break;
2730             }
2731 
2732             bytes += (NvU32)(sizeof(EDID_LONG_DISPLAY_DESCRIPTOR));
2733         }
2734     }
2735 
2736     // Process CVT Timings
2737     for (i = 0; i < pExt->num_cvt; i++)
2738     {
2739         parseEdidCvt3ByteDescriptor((NvU8 *)(pExt->data + bytes), pInfo, &count);
2740 
2741         bytes += (NvU32)sizeof(EDID_CVT_3BYTE_BLOCK);
2742     }
2743 
2744     // Process Standard Timings
2745     for (i = 0; i < pExt->num_standard; i++)
2746     {
2747         NVMISC_MEMSET(&newTiming, 0, sizeof(newTiming));
2748 
2749         parseEdidStandardTimingDescriptor(*(NvU16 *)(pExt->data + bytes),
2750                                           pInfo, count, &newTiming);
2751         newTiming.etc.name[39] = '\0';
2752         newTiming.etc.status = NVT_STATUS_EDID_VTB_EXT_STDn(++count);
2753 
2754         if (!assignNextAvailableTiming(pInfo, &newTiming))
2755         {
2756             break;
2757         }
2758 
2759         bytes += (NvU32)sizeof(NvU16);
2760     }
2761 }
2762 
CODE_SEGMENT(PAGE_DD_CODE)2763 CODE_SEGMENT(PAGE_DD_CODE)
2764 static int IsPrintable(NvU8 c)
2765 {
2766     return ((c >= ' ') && (c <= '~'));
2767 }
2768 
CODE_SEGMENT(PAGE_DD_CODE)2769 CODE_SEGMENT(PAGE_DD_CODE)
2770 static int IsWhiteSpace(NvU8 c)
2771 {
2772     // consider anything unprintable or single space (ASCII 32)
2773     // to be whitespace
2774     return (!IsPrintable(c) || (c == ' '));
2775 }
2776 
CODE_SEGMENT(PAGE_DD_CODE)2777 CODE_SEGMENT(PAGE_DD_CODE)
2778 static void RemoveTrailingWhiteSpace(NvU8 *str, int len)
2779 {
2780     int i;
2781 
2782     for (i = len; (i >= 0) && IsWhiteSpace(str[i]); i--)
2783     {
2784         str[i] = '\0';
2785     }
2786 }
2787 
CODE_SEGMENT(PAGE_DD_CODE)2788 CODE_SEGMENT(PAGE_DD_CODE)
2789 static void RemoveNonPrintableCharacters(NvU8 *str)
2790 {
2791     int i;
2792 
2793     // Check that all characters are printable.
2794     // If not, replace them with '?'
2795     for (i = 0; str[i] != '\0'; i++)
2796     {
2797         if (!IsPrintable(str[i]))
2798         {
2799             str[i] = '?';
2800         }
2801     }
2802 }
2803 
2804 /**
2805  * @brief Assigns this timing to the next available slot in pInfo->timing[] if
2806  *        possible.
2807  * @param pInfo EDID struct containing the parsed timings
2808  * @param pTiming New timing to be copied into pInfo->timing[]
2809  */
CODE_SEGMENT(PAGE_DD_CODE)2810 CODE_SEGMENT(PAGE_DD_CODE)
2811 NvBool assignNextAvailableTiming(NVT_EDID_INFO *pInfo,
2812                                  const NVT_TIMING *pTiming)
2813 {
2814     if (pInfo == NULL) return NV_TRUE;
2815 
2816     // Don't write past the end of
2817     // pInfo->timing[NVT_EDID_MAX_TOTAL_TIMING]
2818     if (pInfo->total_timings >= COUNT(pInfo->timing)) {
2819         return NV_FALSE;
2820     }
2821 
2822     pInfo->timing[pInfo->total_timings++] = *pTiming;
2823     return NV_TRUE;
2824 }
2825 
2826 /**
2827  * @brief Return the nth highest priority index based on the different SVR
2828  * @param svr Short Video Reference
2829  */
CODE_SEGMENT(PAGE_DD_CODE)2830 CODE_SEGMENT(PAGE_DD_CODE)
2831 NvU8 getHighestPrioritySVRIdx(const NVT_EDID_CEA861_INFO *pExt861)
2832 {
2833     // In general, sink shall define the first one timing sequence
2834     NvU8 kth = 1;
2835     NvU8 i = 0;
2836 
2837     for (i = 0; i < pExt861->total_svr; i++)
2838     {
2839         NvU8 svr = pExt861->svr_vfpdb[i];
2840 
2841         // Reserved
2842         if (svr == 0 || svr == 128 || (svr >= 176 && svr <= 192) || svr == 255)
2843             continue;
2844 
2845         if (svr >= 129 && svr <= 144)      return svr - 128;  // Interpret as the Kth 18-byte DTD in both base0 and CTA block (for N = 1 to 16)
2846         else if (svr >= 145 && svr <= 160) return svr - 144;  // Interpret as the Nth 20-byte DTD or 6- or 7-byte CVT-based descriptor. (for N = 1 to 16)
2847         else if (svr >= 161 && svr <= 175) return svr - 160;  // Interpret as the video format indicated by the first VFD of the first VFDB with Frame Rates of Rate Index N (for N = 1 to 15)
2848         else if (svr == 254)               return kth;        // Interpret as the timing format indicated by the first code of the first T8VTDB (for N = 1)
2849         else // assign corresponding CTA format's timing from pre-defined CE timing table, EIA861B
2850         {
2851             // ( SVR >= 1 and SVR <= 127) and (SVR >= 193 and SVR <= 253) needs to handle it by client
2852             return svr;
2853         }
2854     }
2855 
2856     return 0;
2857 }
2858 
CODE_SEGMENT(PAGE_DD_CODE)2859 CODE_SEGMENT(PAGE_DD_CODE)
2860 NVT_STATUS NvTiming_GetProductName(const NVT_EDID_INFO *pEdidInfo,
2861                                    NvU8 *pProductName,
2862                                    const NvU32 productNameLength)
2863 {
2864     NvU32 i = 0, m = 0, n = 0;
2865 
2866     if( pEdidInfo == NULL || pProductName == NULL )
2867     {
2868         return NVT_STATUS_INVALID_PARAMETER;
2869     }
2870 
2871     for ( i = 0; i < NVT_EDID_MAX_LONG_DISPLAY_DESCRIPTOR; i++)
2872     {
2873         if (pEdidInfo->ldd[i].tag == NVT_EDID_DISPLAY_DESCRITPOR_DPN)
2874         {
2875             for(n = 0; n < NVT_EDID_LDD_PAYLOAD_SIZE && pEdidInfo->ldd[i].u.product_name.str[n] != 0x0; n++)
2876             {
2877                 pProductName[m++] = pEdidInfo->ldd[i].u.product_name.str[n];
2878                 if ((m + 1) >= productNameLength)
2879                 {
2880                     goto done;
2881                 }
2882             }
2883         }
2884     }
2885 done:
2886     pProductName[m] = '\0'; //Ensure a null termination at the end.
2887 
2888     RemoveTrailingWhiteSpace(pProductName, m);
2889     RemoveNonPrintableCharacters(pProductName);
2890 
2891     return NVT_STATUS_SUCCESS;
2892 }
2893 
CODE_SEGMENT(PAGE_DD_CODE)2894 CODE_SEGMENT(PAGE_DD_CODE)
2895 NvU32 NvTiming_CalculateEDIDCRC32(NvU8* pEDIDBuffer, NvU32 edidsize)
2896 {
2897     return calculateCRC32(pEDIDBuffer, edidsize);
2898 }
2899 
2900 //Calculates EDID/DisplayID2 CRC after purging 'Week of Manufacture', 'Year of Manufacture',
2901 //'Product ID String' & 'Serial Number' from EDID
CODE_SEGMENT(PAGE_DD_CODE)2902 CODE_SEGMENT(PAGE_DD_CODE)
2903 NvU32 NvTiming_CalculateCommonEDIDCRC32(NvU8* pEDIDBuffer, NvU32 edidVersion)
2904 {
2905     NvU32 commonEDIDBufferSize = 0;
2906     NvU8 CommonEDIDBuffer[256];
2907     NvU32 edidBufferIndex = 0;
2908 
2909     if(pEDIDBuffer==NULL)
2910     {
2911         return 0;
2912     }
2913 
2914     // Transfer over the original EDID buffer
2915     NVMISC_MEMCPY(CommonEDIDBuffer, pEDIDBuffer, 256);
2916 
2917     if ((pEDIDBuffer[0] & 0xF0) == 0x20)
2918     {
2919         /*
2920         typedef struct DisplayId2Struct
2921         {
2922             NvU8   bVersion;                   // 0x00
2923             NvU8   bSectionBytes;              // 0x01 - section length, exclusive the five mandatory bytes.
2924             NvU8   bwPrimaryUseCase;           // 0x02
2925             NvU8   bExtensionCount;            // 0x03
2926             // 0x20 DisplayId2 Standalone always exists Product Identification data block
2927             NvU8   bProductIdtag;              // 0x04
2928             NvU8   bPIDRevision;               // 0x05
2929             NvU8   bPayloadByte;               // 0x06
2930             NvU8   bManuId[3];                 // 0x07-0x09
2931             NvU16  wProductId;                 // 0x0A-0x0B
2932             NvU32  dwSerialNum;                // 0x0C-0x0F
2933             NvU16  wWeekandYear;               // 0x10-0x11
2934             NvU8   SizeOfProductNameString;    // 0x12
2935         } DISPLAY_ID2_FIXED_FORMAT;
2936         */
2937 
2938         // Wipe out the Serial Number, Week of Manufacture, and Year of Manufacture or Model Year
2939         NVMISC_MEMSET(CommonEDIDBuffer + 0x0C, 0, 6);
2940 
2941         // Wipe out the checksums
2942         CommonEDIDBuffer[CommonEDIDBuffer[1]+5/*mandatory bytes*/-1] = 0;
2943         CommonEDIDBuffer[0xFF] = 0;
2944 
2945         // zero out any Produc Name in Prodcut Identification data block
2946         if (CommonEDIDBuffer[0x12] != 0)
2947         {
2948             NVMISC_MEMSET(CommonEDIDBuffer + 0x13, 0, CommonEDIDBuffer[0x12]);
2949             CommonEDIDBuffer[0x12] = 0;
2950         }
2951 
2952         // displayId2 standalone uses 256 length sections
2953         commonEDIDBufferSize = 256;
2954     }
2955     else
2956     {
2957         // Wipe out the Serial Number, Week of Manufacture, and Year of Manufacture or Model Year
2958         NVMISC_MEMSET(CommonEDIDBuffer + 0x0C, 0, 6);
2959 
2960         // Wipe out the checksums
2961         CommonEDIDBuffer[0x7F] = 0;
2962         CommonEDIDBuffer[0xFF] = 0;
2963 
2964         // We also need to zero out any "EDID Other Monitor Descriptors" (http://en.wikipedia.org/wiki/Extended_display_identification_data)
2965         for (edidBufferIndex = 54; edidBufferIndex <= 108; edidBufferIndex += 18)
2966         {
2967             if (CommonEDIDBuffer[edidBufferIndex] == 0 && CommonEDIDBuffer[edidBufferIndex+1] == 0)
2968             {
2969                 // Wipe this block out. It contains OEM-specific details that contain things like serial numbers
2970                 NVMISC_MEMSET(CommonEDIDBuffer + edidBufferIndex, 0, 18);
2971             }
2972         }
2973 
2974         // Check what size we should do the compare against
2975         commonEDIDBufferSize = 128;
2976     }
2977 
2978     return NvTiming_CalculateEDIDCRC32(CommonEDIDBuffer, commonEDIDBufferSize);
2979 } // NvTiming_CalculateCommonEDIDCRC32
2980 
2981 // Calculate the minimum and maximum v_rate and h_rate, as well as
2982 // maximum pclk; initialize with the range of values in the EDID mode
2983 // list, but override with what is in the range limit descriptor section.
2984 //
2985 // based on drivers/modeset.nxt/CODE/edid.c:EdidGetMonitorLimits() and
2986 // EdidBuildRangeLimits()
CODE_SEGMENT(PAGE_DD_CODE)2987 CODE_SEGMENT(PAGE_DD_CODE)
2988 NVT_STATUS NvTiming_CalculateEDIDLimits(NVT_EDID_INFO *pEdidInfo, NVT_EDID_RANGE_LIMIT *pLimit)
2989 {
2990     NvU32 i;
2991 
2992     NVMISC_MEMSET(pLimit, 0, sizeof(NVT_EDID_RANGE_LIMIT));
2993 
2994     // the below currently only supports 1.x EDIDs
2995     if ((pEdidInfo->version & 0xFF00) != 0x100)
2996     {
2997         return NVT_STATUS_ERR;
2998     }
2999 
3000     pLimit->min_v_rate_hzx1k = ~0;
3001     pLimit->max_v_rate_hzx1k = 0;
3002     pLimit->min_h_rate_hz = ~0;
3003     pLimit->max_h_rate_hz = 0;
3004     pLimit->max_pclk_10khz = 0;
3005 
3006     // find the ranges in the EDID mode list
3007     for (i = 0; i < pEdidInfo->total_timings; i++)
3008     {
3009         NVT_TIMING *pTiming = &pEdidInfo->timing[i];
3010         NvU32 h_rate_hz;
3011 
3012         if (pLimit->min_v_rate_hzx1k > pTiming->etc.rrx1k)
3013         {
3014             pLimit->min_v_rate_hzx1k = pTiming->etc.rrx1k;
3015         }
3016         if (pLimit->max_v_rate_hzx1k < pTiming->etc.rrx1k)
3017         {
3018             pLimit->max_v_rate_hzx1k = pTiming->etc.rrx1k;
3019         }
3020 
3021         h_rate_hz = axb_div_c(pTiming->pclk, 10000, (NvU32)pTiming->HTotal);
3022 
3023         if (pLimit->min_h_rate_hz > h_rate_hz)
3024         {
3025             pLimit->min_h_rate_hz = h_rate_hz;
3026         }
3027         if (pLimit->max_h_rate_hz < h_rate_hz)
3028         {
3029             pLimit->max_h_rate_hz = h_rate_hz;
3030         }
3031 
3032         if (pLimit->max_pclk_10khz < pTiming->pclk)
3033         {
3034             pLimit->max_pclk_10khz = pTiming->pclk;
3035         }
3036     }
3037 
3038     // use the range limit display descriptor, if available: these
3039     // override anything we found in the EDID mode list
3040     for (i = 0; i < NVT_EDID_MAX_LONG_DISPLAY_DESCRIPTOR; i++)
3041     {
3042         if (pEdidInfo->ldd[i].tag == NVT_EDID_DISPLAY_DESCRIPTOR_DRL)
3043         {
3044             NVT_EDID_DD_RANGE_LIMIT *pRangeLimit = &pEdidInfo->ldd[i].u.range_limit;
3045             NvU32 max_pclk_10khz;
3046 
3047             // {min,max}_v_rate is in hz
3048             if (pRangeLimit->min_v_rate != 0) {
3049                 pLimit->min_v_rate_hzx1k = pRangeLimit->min_v_rate * 1000;
3050             }
3051             if (pRangeLimit->max_v_rate != 0) {
3052                 pLimit->max_v_rate_hzx1k = pRangeLimit->max_v_rate * 1000;
3053             }
3054 
3055             // {min,max}_h_rate is in khz
3056             if (pRangeLimit->min_h_rate != 0) {
3057                 pLimit->min_h_rate_hz = pRangeLimit->min_h_rate * 1000;
3058             }
3059             if (pRangeLimit->max_h_rate != 0) {
3060                 pLimit->max_h_rate_hz = pRangeLimit->max_h_rate * 1000;
3061             }
3062 
3063             // EdidGetMonitorLimits() honored the pclk from the
3064             // modelist over what it found in the range limit
3065             // descriptor, so do the same here
3066             max_pclk_10khz = pRangeLimit->max_pclk_MHz * 100;
3067             if (pLimit->max_pclk_10khz < max_pclk_10khz) {
3068                 pLimit->max_pclk_10khz = max_pclk_10khz;
3069             }
3070 
3071             break;
3072         }
3073     }
3074 
3075     return NVT_STATUS_SUCCESS;
3076 }
3077 
3078 // Build a user-friendly name:
3079 //
3080 // * get the vendor name:
3081 //     * use the 3 character PNP ID from the EDID's manufacturer ID field
3082 //     * expand, if possible, the PNP ID using the PNPVendorIds[] table
3083 // * get the product name from the descriptor block(s)
3084 // * prepend the vendor name and the product name, unless the product
3085 //   name already contains the vendor name
3086 // * if any characters in the string are outside the printable ASCII
3087 //   range, replace them with '?'
3088 
3089 #define tolower(c)      (((c) >= 'A' && (c) <= 'Z') ? (c) + ('a'-'A') : (c))
3090 
CODE_SEGMENT(PAGE_DD_CODE)3091 CODE_SEGMENT(PAGE_DD_CODE)
3092 void NvTiming_GetMonitorName(NVT_EDID_INFO *pEdidInfo,
3093                              NvU8 monitor_name[NVT_EDID_MONITOR_NAME_STRING_LENGTH])
3094 {
3095     NvU8 product_name[NVT_EDID_MONITOR_NAME_STRING_LENGTH];
3096     const NvU8 *vendor_name;
3097     NVT_STATUS status;
3098     NvU32 i, j;
3099     NvBool prepend_vendor;
3100 
3101     NVMISC_MEMSET(monitor_name, 0, NVT_EDID_MONITOR_NAME_STRING_LENGTH);
3102 
3103     // get vendor_name: it is either the manufacturer ID or the PNP vendor name
3104     vendor_name = pEdidInfo->manuf_name;
3105 
3106     for (i = 0; i < (sizeof(PNPVendorIds)/sizeof(PNPVendorIds[0])); i++)
3107     {
3108         if ((vendor_name[0] == PNPVendorIds[i].vendorId[0]) &&
3109             (vendor_name[1] == PNPVendorIds[i].vendorId[1]) &&
3110             (vendor_name[2] == PNPVendorIds[i].vendorId[2]))
3111         {
3112             vendor_name = (const NvU8 *) PNPVendorIds[i].vendorName;
3113             break;
3114         }
3115     }
3116 
3117     // get the product name from the descriptor blocks
3118     status = NvTiming_GetProductName(pEdidInfo, product_name, sizeof(product_name));
3119 
3120     if (status != NVT_STATUS_SUCCESS)
3121     {
3122         product_name[0] = '\0';
3123     }
3124 
3125     // determine if the product name already includes the vendor name;
3126     // if so, do not prepend the vendor name to the monitor name
3127     prepend_vendor = NV_TRUE;
3128 
3129     for (i = 0; i < NVT_EDID_MONITOR_NAME_STRING_LENGTH; i++)
3130     {
3131         if (vendor_name[i] == '\0')
3132         {
3133             prepend_vendor = NV_FALSE;
3134             break;
3135         }
3136 
3137         if (tolower(product_name[i]) != tolower(vendor_name[i]))
3138         {
3139             break;
3140         }
3141     }
3142 
3143     j = 0;
3144 
3145     // prepend the vendor name to the monitor name
3146     if (prepend_vendor)
3147     {
3148         for (i = 0; (i < NVT_EDID_MONITOR_NAME_STRING_LENGTH) && (vendor_name[i] != '\0'); i++)
3149         {
3150             monitor_name[j++] = vendor_name[i];
3151         }
3152     }
3153 
3154     // if we added the vendor name above, add a space between the
3155     // vendor name and the product name
3156     if ((j > 0) && (j < (NVT_EDID_MONITOR_NAME_STRING_LENGTH - 1)))
3157     {
3158         monitor_name[j++] = ' ';
3159     }
3160 
3161     // append the product name to the monitor string
3162     for (i = 0; (i < NVT_EDID_MONITOR_NAME_STRING_LENGTH) && (product_name[i] != '\0'); i++)
3163     {
3164         if (j >= (NVT_EDID_MONITOR_NAME_STRING_LENGTH - 1))
3165         {
3166             break;
3167         }
3168         monitor_name[j++] = product_name[i];
3169     }
3170     monitor_name[j] = '\0';
3171 
3172     RemoveTrailingWhiteSpace(monitor_name, j);
3173     RemoveNonPrintableCharacters(monitor_name);
3174 }
3175 
CODE_SEGMENT(PAGE_DD_CODE)3176 CODE_SEGMENT(PAGE_DD_CODE)
3177 void updateHDMILLCDeepColorForTiming(NVT_EDID_INFO *pInfo, NvU32 index)
3178 {
3179     NVT_EDID_CEA861_INFO *p861Info = &pInfo->ext861;
3180     // NOTE: EDID and CEA861 does not have clear statement regarding this.
3181     // To be backward compatible with current Nvidia implementation, if not edid >= 1.4 and CEA block exists, follow color format declaration from CEA block.
3182     // update supported color space within each bpc
3183     // rgb 8bpc always supported
3184 
3185     UPDATE_BPC_FOR_COLORFORMAT(pInfo->timing[index].etc.rgb444, 0, 1,
3186                                pInfo->hdmiLlcInfo.dc_30_bit,
3187                                pInfo->hdmiLlcInfo.dc_36_bit,
3188                                0, pInfo->hdmiLlcInfo.dc_48_bit);
3189 
3190     if (p861Info->basic_caps & NVT_CEA861_CAP_YCbCr_444)
3191     {
3192         // pHdmiLlc->dc_y444 assumed basic cap is set; when base cap is set, 8bpc yuv444 always supported
3193         UPDATE_BPC_FOR_COLORFORMAT(pInfo->timing[index].etc.yuv444, 0, 1,
3194                                    pInfo->hdmiLlcInfo.dc_y444 && pInfo->hdmiLlcInfo.dc_30_bit,
3195                                    pInfo->hdmiLlcInfo.dc_y444 && pInfo->hdmiLlcInfo.dc_36_bit,
3196                                    0, pInfo->hdmiLlcInfo.dc_y444 && pInfo->hdmiLlcInfo.dc_48_bit);
3197     }
3198     if (p861Info->basic_caps & NVT_CEA861_CAP_YCbCr_422)
3199     {
3200         // pHdmiLlc->dc_y444 assumed basic cap is set; when base cap is set, 8bpc yuv422 always supported
3201         // newer CEA861/HDMI specs suggest the base cap should support both or neither (Nvidia puts no limitations here)
3202         // HDMI1.4b spec  Section 6.2.4 Color Depth Requirements states that YCbCr 4:2:2 format is 36-bit mode, which means 8, 10 and 12bpc output is supported as soon as there is enough bandwidth
3203         UPDATE_BPC_FOR_COLORFORMAT(pInfo->timing[index].etc.yuv422, 0, 1, 1, 1, 0, 0);
3204     }
3205 }
3206 
3207 POP_SEGMENTS
3208