1 //*****************************************************************************
2 //
3 //  SPDX-FileCopyrightText: Copyright (c) 2022 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 
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 
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 
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 
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
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 
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
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
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 
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
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
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
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
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
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 
1057                 // parse HDR related information from the HDR static metadata data block
1058                 parseCea861HdrStaticMetadataDataBlock(p861Info, pInfo, FROM_CTA861_EXTENSION);
1059 
1060                 // parse Dolby Vision related information from the DV vendor specific video data block
1061                 parseCea861DvStaticMetadataDataBlock(p861Info, pInfo, FROM_CTA861_EXTENSION);
1062 
1063                 // parse HDR10+ related information from the HDR10+ LLC Vendor Specific Video Data Block
1064                 parseCea861Hdr10PlusDataBlock(p861Info, pInfo, FROM_CTA861_EXTENSION);
1065 
1066                 // Timings are listed (or shall) be listed in priority order
1067                 // So read SVD, yuv420 SVDs first before reading detailed timings
1068 
1069                 // add the 861B short video timing descriptor
1070                 if (p861Info->revision >= NVT_CEA861_REV_B)
1071                 {
1072                     // base video
1073                     parse861bShortTiming(p861Info, pInfo, FROM_CTA861_EXTENSION);
1074 
1075                     // yuv420-only video
1076                     parse861bShortYuv420Timing(p861Info, pInfo, FROM_CTA861_EXTENSION);
1077                 }
1078 
1079                 // add the detailed timings in 18-byte long display descriptor
1080                 parse861ExtDetailedTiming(pExt, p861Info->basic_caps, pInfo);
1081 
1082                 // CEA861-F at 7.5.12 section about VFPDB block.
1083                 if (p861Info->revision >= NVT_CEA861_REV_F && p861Info->total_vfpdb != 0)
1084                 {
1085                     parse861bShortPreferredTiming(p861Info, pInfo, FROM_CTA861_EXTENSION);
1086                 }
1087 
1088                 k++;
1089                 break;
1090 
1091             case NVT_EDID_EXTENSION_VTB:
1092                 parseVTBExtension(pExt, pInfo);
1093                 break;
1094 
1095             case NVT_EDID_EXTENSION_DISPLAYID:
1096                 if ((pExt[1] & 0xF0) == 0x20) // displayID2.x as EDID extension
1097                 {
1098                     if(getDisplayId20EDIDExtInfo(pExt, sizeof(EDIDV1STRUC),
1099                                                     pInfo) == NVT_STATUS_SUCCESS)
1100                     {
1101                         if (pInfo->ext861.total_y420vdb != 0 || pInfo->ext861.total_y420cmdb != 0)
1102                         {
1103                             pInfo->ext_displayid20.interface_features.yuv420_min_pclk = 0;
1104                         }
1105 
1106                         if (!pInfo->ext861.basic_caps)
1107                         {
1108                             pInfo->ext861.basic_caps = pInfo->ext_displayid20.basic_caps;
1109                         }
1110                     }
1111                 }
1112                 else // displayID13 as EDID extension
1113                 {
1114                     //do not fail function based on return value of getDisplayIdEDIDExtInfo refer bug 3247180 where some rogue monitors don't provide correct DID13 raw data.
1115                     if (getDisplayIdEDIDExtInfo(pExt, sizeof(EDIDV1STRUC),
1116                                                    pInfo) == NVT_STATUS_SUCCESS)
1117                     {
1118                         // Check if YCbCr is supported in base block
1119                         // since it is mandatory if YCbCr is supported on any other display interface as per 5.1.1.1 Video Colorimetry
1120                         if(pInfo->u.feature_ver_1_4_digital.support_ycrcb_444)
1121                         {
1122                             if (!pInfo->ext_displayid.supported_displayId2_0)
1123                             {
1124                                 pInfo->ext_displayid.u4.display_interface.ycbcr444_depth.support_8b = 1;
1125                             }
1126                             else
1127                             {
1128                                 pInfo->ext_displayid.u4.display_interface_features.ycbcr444_depth.support_8b = 1;
1129                             }
1130                         }
1131 
1132                         if(pInfo->u.feature_ver_1_4_digital.support_ycrcb_422)
1133                         {
1134                             if (!pInfo->ext_displayid.supported_displayId2_0)
1135                             {
1136                                 pInfo->ext_displayid.u4.display_interface.ycbcr422_depth.support_8b = 1;
1137                             }
1138                             else
1139                             {
1140                                 pInfo->ext_displayid.u4.display_interface_features.ycbcr422_depth.support_8b = 1;
1141                             }
1142                         }
1143                     }
1144                 }
1145                 break;
1146 
1147             default:
1148                 break;
1149         }
1150     }
1151 
1152     // Copy all the timings(could include type 7/8/9/10) from displayid20->timings[] to pEdidInfo->timings[]
1153     for (i = 0; i < pInfo->ext_displayid20.total_timings; i++)
1154     {
1155         if (!assignNextAvailableTiming(pInfo, &(pInfo->ext_displayid20.timing[i])))
1156         {
1157             return NVT_STATUS_ERR;
1158         }
1159     }
1160 
1161     // check for cvt timings - in display range limits or cvt 3-byte LDD, only for EDID1.4 and above
1162     if (pInfo->version > 0x0103)
1163     {
1164         parseEdidCvtTiming(pInfo);
1165     }
1166 
1167     // now check for standard timings - base EDID and then the LDDs
1168     parseEdidStandardTiming(pInfo);
1169 
1170     // find out the total established timings - base EDID and then the LDDs
1171     parseEdidEstablishedTiming(pInfo);
1172 
1173     getEdidHDM1_4bVsdbTiming(pInfo);
1174 
1175     // Assert if no timings were found (due to a bad EDID) or if we mistakenly
1176     // assigned more timings than we allocated space for (due to bad logic above)
1177     nvt_assert(pInfo->total_timings &&
1178                (pInfo->total_timings <= COUNT(pInfo->timing)));
1179 
1180     // go through all timings and update supported color formats
1181     // consider the supported bpc per color format from parsed EDID / CTA861 / DisplayId
1182     updateColorFormatAndBpcTiming(pInfo);
1183 
1184     return NVT_STATUS_SUCCESS;
1185 }
1186 
1187 CODE_SEGMENT(PAGE_DD_CODE)
1188 void updateColorFormatAndBpcTiming(NVT_EDID_INFO *pInfo)
1189 {
1190     NvU32 i, j, data;
1191 
1192     for (i = 0; i < pInfo->total_timings; i++)
1193     {
1194         data = NVT_GET_TIMING_STATUS_TYPE(pInfo->timing[i].etc.status);
1195         switch (data)
1196         {
1197         case NVT_TYPE_HDMI_STEREO:
1198         case NVT_TYPE_HDMI_EXT:
1199             // VTB timing use the base EDID (block 0) to determine the color format support
1200         case NVT_TYPE_EDID_VTB_EXT:
1201         case NVT_TYPE_EDID_VTB_EXT_STD:
1202         case NVT_TYPE_EDID_VTB_EXT_DTD:
1203         case NVT_TYPE_EDID_VTB_EXT_CVT:
1204             // pInfo->u.feature_ver_1_3.color_type provides mono, rgb, rgy, undefined
1205             // assume RGB 8-bpc support only (VTB is pretty old edid standard)
1206             pInfo->timing[i].etc.rgb444.bpc.bpc8 = 1;
1207             break;
1208             // These are from the CTA block, and relies on
1209             // Since there could be multiple CEA blocks, these are adjusted when the blocks are parsed
1210         case NVT_TYPE_EDID_861ST:
1211         case NVT_TYPE_EDID_EXT_DTD:
1212             if (pInfo->ext_displayid20.as_edid_extension &&
1213                 pInfo->ext_displayid20.valid_data_blocks.cta_data_present)
1214             {
1215                 updateColorFormatForDisplayId20ExtnTimings(pInfo, i);
1216             }
1217             updateBpcForTiming(pInfo, i);
1218             break;
1219         default:
1220             // * the displayID_v1.3/v2.0 EDID extension need to follow the EDID bpc definition.
1221             // * all other default to base edid
1222             updateBpcForTiming(pInfo, i);
1223         }
1224 
1225         // The timings[i] entries need to update the bpc values where are based on the different color format again
1226         // if displayId extension existed it's interface feature data block
1227         if (pInfo->ext_displayid.version == 0x12 || pInfo->ext_displayid.version == 0x13)
1228         {
1229             updateColorFormatForDisplayIdExtnTimings(pInfo, i);
1230         }
1231         else if (pInfo->ext_displayid20.valid_data_blocks.interface_feature_present)
1232         {
1233             // DisplayId2.0 spec has its own way of determining color format support which includes bpc + color format
1234             updateColorFormatForDisplayId20ExtnTimings(pInfo, i);
1235         }
1236     }
1237 
1238     // Go through all the timings and set CTA format accordingly. If a timing is a CTA 861b timing, store the
1239     // index of this CTA 861b standard in NVT_TIMING.etc.status field.
1240     // However parser needs to exclude the DTD timing in EDID base block where is shared same detailed timing in VIC/DTD_ext in CTA861
1241     for (i = 0; i < pInfo->total_timings; i++)
1242     {
1243         data = NvTiming_GetCEA861TimingIndex(&pInfo->timing[i]);
1244         // DisplayID block did not belong to CTA timing and it owned the deep color block itself
1245         if (data && !((NVT_GET_TIMING_STATUS_TYPE(pInfo->timing[i].etc.status) == NVT_TYPE_DISPLAYID_1) ||
1246                       (NVT_GET_TIMING_STATUS_TYPE(pInfo->timing[i].etc.status) == NVT_TYPE_DISPLAYID_2) ||
1247                       (NVT_GET_TIMING_STATUS_TYPE(pInfo->timing[i].etc.status) == NVT_TYPE_DISPLAYID_7) ||
1248                       (NVT_GET_TIMING_STATUS_TYPE(pInfo->timing[i].etc.status) == NVT_TYPE_DISPLAYID_8) ||
1249                       (NVT_GET_TIMING_STATUS_TYPE(pInfo->timing[i].etc.status) == NVT_TYPE_DISPLAYID_9) ||
1250                       (NVT_GET_TIMING_STATUS_TYPE(pInfo->timing[i].etc.status) == NVT_TYPE_DISPLAYID_10)))
1251         {
1252             // CEA timings may be enumerated outside of SVD blocks -- the formats of these timings don't have CEA FORMAT (vic) set
1253             // before marking them CEA, make sure their color formats are updated too
1254             if (NVT_GET_CEA_FORMAT(pInfo->timing[i].etc.status) == 0 &&
1255                 (!NVT_IS_DTD(pInfo->timing[i].etc.status) ||
1256                  isMatchedCTA861Timing(pInfo, &pInfo->timing[i])))
1257             {
1258                 for (j = 0; j < pInfo->total_timings; j++)
1259                 {
1260                     // It is assumed CTA timings that are repeated by the CTA block or different CTA blocks will
1261                     // announce the same color format for the same CTA timings
1262                     if (NVT_GET_CEA_FORMAT(pInfo->timing[j].etc.status) == data)
1263                     {
1264                         // There could be anomalies between EDID 1.4 base block color format vs CEA861 basic caps
1265                         // In this case we assume the union is supported
1266                         pInfo->timing[i].etc.rgb444.bpcs |= pInfo->timing[j].etc.rgb444.bpcs;
1267                         pInfo->timing[i].etc.yuv444.bpcs |= pInfo->timing[j].etc.yuv444.bpcs;
1268                         pInfo->timing[i].etc.yuv422.bpcs |= pInfo->timing[j].etc.yuv422.bpcs;
1269                         pInfo->timing[i].etc.yuv420.bpcs |= pInfo->timing[j].etc.yuv420.bpcs;
1270                         break;
1271                     }
1272                 }
1273 
1274                 // now update the VIC of this timing
1275                 NVT_SET_CEA_FORMAT(pInfo->timing[i].etc.status, data);
1276             }
1277             // see the aspect ratio info if needed
1278             if (pInfo->timing[i].etc.aspect == 0)
1279             {
1280                 pInfo->timing[i].etc.aspect = getCEA861TimingAspectRatio(data);
1281             }
1282         }
1283     }
1284 
1285 }
1286 
1287 CODE_SEGMENT(PAGE_DD_CODE)
1288 NvBool isMatchedCTA861Timing(NVT_EDID_INFO *pInfo, NVT_TIMING *pT)
1289 {
1290     NvU32 j;
1291 
1292     for (j = 0; j < pInfo->total_timings; j++)
1293     {
1294         if (NVT_GET_CEA_FORMAT(pInfo->timing[j].etc.status) && NvTiming_IsTimingExactEqual(&pInfo->timing[j], pT))
1295         {
1296             return NV_TRUE;
1297         }
1298     }
1299     return NV_FALSE;
1300 }
1301 
1302 CODE_SEGMENT(PAGE_DD_CODE)
1303 void updateBpcForTiming(NVT_EDID_INFO *pInfo, NvU32 index)
1304 {
1305     NVT_EDID_CEA861_INFO *p861Info;
1306 
1307     // assume/prefer data from 1st CEA block if multiple exist
1308     p861Info = &pInfo->ext861;
1309 
1310     pInfo->timing[index].etc.rgb444.bpc.bpc8 = 1;
1311 
1312     if (pInfo->version >= NVT_EDID_VER_1_4 && pInfo->input.isDigital)
1313     {
1314         if (pInfo->u.feature_ver_1_4_digital.support_ycrcb_444)
1315         {
1316             pInfo->timing[index].etc.yuv444.bpc.bpc8 = 1;
1317         }
1318         if (pInfo->u.feature_ver_1_4_digital.support_ycrcb_422)
1319         {
1320             pInfo->timing[index].etc.yuv422.bpc.bpc8 = 1;
1321         }
1322         if (pInfo->input.u.digital.video_interface == NVT_EDID_DIGITAL_VIDEO_INTERFACE_STANDARD_DISPLAYPORT_SUPPORTED ||
1323             pInfo->input.u.digital.video_interface == NVT_EDID_DIGITAL_VIDEO_INTERFACE_STANDARD_UNDEFINED)
1324         {
1325             pInfo->timing[index].etc.rgb444.bpc.bpc6 = 1;
1326 
1327             // trust bpc claim in edid base block for DP only
1328             if (pInfo->input.u.digital.bpc >= NVT_EDID_VIDEOSIGNAL_BPC_10)
1329             {
1330                 pInfo->timing[index].etc.rgb444.bpc.bpc10 = 1;
1331                 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);
1332                 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);
1333             }
1334             if (pInfo->input.u.digital.bpc >= NVT_EDID_VIDEOSIGNAL_BPC_12)
1335             {
1336                 pInfo->timing[index].etc.rgb444.bpc.bpc12 = 1;
1337                 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);
1338                 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);
1339             }
1340             if (pInfo->input.u.digital.bpc >= NVT_EDID_VIDEOSIGNAL_BPC_16)
1341             {
1342                 pInfo->timing[index].etc.rgb444.bpc.bpc16 = 1;
1343                 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);
1344                 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);
1345             }
1346         }
1347         else if ((pInfo->input.u.digital.video_interface == NVT_EDID_DIGITAL_VIDEO_INTERFACE_STANDARD_HDMI_A_SUPPORTED ||
1348                   pInfo->input.u.digital.video_interface == NVT_EDID_DIGITAL_VIDEO_INTERFACE_STANDARD_HDMI_B_SUPPORTED ||
1349                   pInfo->input.u.digital.video_interface == NVT_EDID_DIGITAL_VIDEO_INTERFACE_STANDARD_UNDEFINED) &&
1350                  p861Info->revision >= NVT_CEA861_REV_A)
1351         {
1352             updateHDMILLCDeepColorForTiming(pInfo, index);
1353         }
1354     }
1355     else if (p861Info->revision >= NVT_CEA861_REV_A)
1356     {
1357         updateHDMILLCDeepColorForTiming(pInfo, index);
1358     }
1359 }
1360 
1361 CODE_SEGMENT(PAGE_DD_CODE)
1362 NVT_STATUS NvTiming_Get18ByteLongDescriptorIndex(NVT_EDID_INFO *pEdidInfo, NvU8 tag, NvU32 *pDtdIndex)
1363 {
1364     NvU32 dtdIndex;
1365 
1366     if (!pEdidInfo || !pDtdIndex)
1367     {
1368         return NVT_STATUS_ERR;
1369     }
1370 
1371     for (dtdIndex = *pDtdIndex; dtdIndex < NVT_EDID_MAX_LONG_DISPLAY_DESCRIPTOR; dtdIndex++)
1372     {
1373         if (pEdidInfo->ldd[dtdIndex].tag == tag)
1374         {
1375             *pDtdIndex = dtdIndex;
1376             return NVT_STATUS_SUCCESS;
1377         }
1378     }
1379 
1380     return NVT_STATUS_ERR;
1381 }
1382 
1383 // get the edid timing
1384 CODE_SEGMENT(PAGE_DD_CODE)
1385 NVT_STATUS NvTiming_GetEdidTimingEx(NvU32 width, NvU32 height, NvU32 rr, NvU32 flag, NVT_EDID_INFO *pEdidInfo, NVT_TIMING *pT, NvU32 rrx1k)
1386 {
1387     NvU32 i, j;
1388     NvU32 preferred_cea, preferred_displayid_dtd, preferred_dtd1, dtd1, map0, map1, map2, map3, map4, ceaIndex, max, cvt;
1389     NVT_TIMING *pEdidTiming;
1390     NVT_EDID_DD_RANGE_CVT *pCVT = NULL;
1391     NVT_TIMING cvtTiming;
1392 
1393     // input check
1394     if (pEdidInfo == NULL || pEdidInfo->total_timings == 0 || pT == 0)
1395         return NVT_STATUS_ERR;
1396 
1397     if (width == 0 || height == 0 || rr == 0) // rrx1k is optional, can be 0.
1398         return NVT_STATUS_ERR;
1399 
1400     pEdidTiming = pEdidInfo->timing;
1401 
1402     // the timing mapping index :
1403     //
1404     // preferred_cea           - the "prefer SVD" in CEA-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)
1405     // preferred_displayid_dtd - the "prefer detailed timing of DispalyID" extension
1406     // preferred_dtd1          - the first deatiled timing and PTM flag is enable
1407     // dtd1 - the first detailed timing
1408     // 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".
1409     // map1 - the "closest" match with the honor of the interlaced flag
1410     // map2 - the "closest" match without the honor of the interlaced flag
1411     // 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).
1412     // map4 - the "closest" match with the same refresh rate
1413     // max  - the timing with the max visible area
1414     preferred_cea = preferred_displayid_dtd = preferred_dtd1 = dtd1 = map0 = map1 = map2 = map3 = map4 = ceaIndex = pEdidInfo->total_timings;
1415     max = cvt = 0;
1416     for (i = 0; i < pEdidInfo->total_timings; i++)
1417     {
1418         // if the client prefers _NATIVE timing, then don't select custom timing
1419         if ((flag & (NVT_FLAG_NATIVE_TIMING | NVT_FLAG_EDID_TIMING)) != 0 && NVT_IS_CUST_ENTRY(pEdidTiming[i].etc.status) != 0)
1420         {
1421             continue;
1422         }
1423 
1424         // find the perfect match is possible
1425         if ((flag & NVT_FLAG_MAX_EDID_TIMING) == 0 &&
1426             width  == pEdidTiming[i].HVisible &&
1427             height == frame_height(pEdidTiming[i]) &&
1428             rr     == pEdidTiming[i].etc.rr   &&
1429             ((rrx1k == 0) || (rrx1k == pEdidTiming[i].etc.rrx1k)) &&
1430             !!(flag & NVT_PVT_INTERLACED_MASK) == !!pEdidTiming[i].interlaced)
1431         {
1432             if (map0 >= pEdidInfo->total_timings)
1433             {
1434                 // 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.)
1435                 map0 = i;
1436             }
1437 
1438             if ( (NVT_PREFERRED_TIMING_IS_CEA(pEdidTiming[i].etc.flag)) ||
1439                  ((0 == (flag & NVT_FLAG_EDID_861_ST)) && NVT_PREFERRED_TIMING_IS_DTD1(pEdidTiming[i].etc.flag, pEdidTiming[i].etc.status)) ||
1440                  (NVT_PREFERRED_TIMING_IS_DISPLAYID(pEdidTiming[i].etc.flag)) ||
1441                  (NVT_IS_NATIVE_TIMING(pEdidTiming[i].etc.status)))
1442             {
1443                 *pT = pEdidTiming[i];
1444                 return NVT_STATUS_SUCCESS;
1445             }
1446 
1447             if (NVT_GET_TIMING_STATUS_TYPE(pEdidTiming[i].etc.status) == NVT_TYPE_EDID_861ST)
1448             {
1449                 if (ceaIndex == pEdidInfo->total_timings)
1450                 {
1451                     // Save the first entry found.
1452                     ceaIndex = i;
1453                 }
1454                 else
1455                 {
1456                     if (((flag & NVT_FLAG_CEA_4X3_TIMING) && (pEdidTiming[i].etc.aspect == 0x40003)) ||
1457                         ((flag & NVT_FLAG_CEA_16X9_TIMING) && (pEdidTiming[i].etc.aspect == 0x160009)))
1458                     {
1459                         // Use preferred aspect ratio if specified.
1460                         ceaIndex = i;
1461                     }
1462                 }
1463             }
1464         } // if ((flag & NVT_FLAG_MAX_EDID_TIMING) == 0 &&
1465 
1466         // bypass the custom timing to be select for the mismatch case
1467         if (NVT_GET_TIMING_STATUS_TYPE(pEdidTiming[i].etc.status) == NVT_TYPE_CUST ||
1468             NVT_IS_CUST_ENTRY(pEdidTiming[i].etc.status) != 0)
1469         {
1470             if (width != pEdidTiming[i].HVisible || height != frame_height(pEdidTiming[i]) || rr != pEdidTiming[i].etc.rr)
1471             {
1472                 continue;
1473             }
1474         }
1475 
1476         // find out the preferred timing just in case of cea_vfpdb is existed
1477         if (preferred_cea == pEdidInfo->total_timings &&
1478             NVT_PREFERRED_TIMING_IS_CEA(pEdidTiming[i].etc.flag))
1479         {
1480             preferred_cea = i;
1481         }
1482 
1483         // find out the preferred timing just in case
1484         // Caller we will force rr value as 1 to select the DisplayID prefer timing in pEdidTiming if it existed
1485         // however, we can't assign the correct refresh rate we want if we had two and above rr values which shared the same timing.
1486         if (rr != 1)
1487         {
1488             if (pEdidTiming[i].etc.rr == rr && NVT_PREFERRED_TIMING_IS_DISPLAYID(pEdidTiming[i].etc.flag))
1489             {
1490                 preferred_displayid_dtd = i;
1491             }
1492         }
1493         else if (preferred_displayid_dtd == pEdidInfo->total_timings &&
1494                 NVT_PREFERRED_TIMING_IS_DISPLAYID(pEdidTiming[i].etc.flag))
1495         {
1496                 preferred_displayid_dtd = i;
1497         }
1498 
1499         if (NVT_PREFERRED_TIMING_IS_DTD1(pEdidTiming[i].etc.flag, pEdidTiming[i].etc.status))
1500         {
1501             preferred_dtd1 = i;
1502         }
1503 
1504         if (NVT_IS_DTD1(pEdidTiming[i].etc.status))
1505         {
1506             dtd1 = i;
1507         }
1508 
1509         // find out the max mode just in case
1510         if (pEdidTiming[i].HVisible * pEdidTiming[i].VVisible > pEdidTiming[max].HVisible * pEdidTiming[max].VVisible)
1511             max = i;
1512 
1513         // if the requested timing is not in the EDID, try to find out the EDID entry with the same progressive/interlaced setting
1514         if (map1 >= pEdidInfo->total_timings)
1515         {
1516             if (!!(flag & NVT_PVT_INTERLACED_MASK) == !!pEdidTiming[i].interlaced &&
1517                 width  <= pEdidTiming[i].HVisible &&
1518                 height <= frame_height(pEdidTiming[i]))
1519             {
1520                 map1 = i;
1521             }
1522         }
1523         else
1524         {
1525             if (!!(flag & NVT_PVT_INTERLACED_MASK) == !!pEdidTiming[i].interlaced &&
1526                 width  <= pEdidTiming[i].HVisible &&
1527                 height <= frame_height(pEdidTiming[i]) &&
1528                 abs_delta(pEdidTiming[i].HVisible, width) <= abs_delta(pEdidTiming[map1].HVisible, width) &&
1529                 abs_delta(frame_height(pEdidTiming[i]), height) <= abs_delta(frame_height(pEdidTiming[map1]), height))
1530             {
1531                 // if there're 2 timings with the same visible size, choose the one with closer refresh rate
1532                 if (pEdidTiming[i].HVisible == pEdidTiming[map1].HVisible &&
1533                     frame_height(pEdidTiming[i]) == frame_height(pEdidTiming[map1]))
1534                 {
1535                     if (abs_delta(pEdidTiming[i].etc.rr, rr) < abs_delta(pEdidTiming[map1].etc.rr, rr))
1536                     {
1537                         map1 = i;
1538                     }
1539                 }
1540                 else
1541                 {
1542                     map1 = i;
1543                 }
1544             }
1545         }
1546 
1547         // if the requested timing is not in the EDID, try to find out the EDID entry without the progressive/interlaced setting
1548         if (map2 >= pEdidInfo->total_timings)
1549         {
1550             if (width  <= pEdidTiming[i].HVisible &&
1551                 height <= frame_height(pEdidTiming[i]))
1552             {
1553                 map2 = i;
1554             }
1555         }
1556         else
1557         {
1558             if (width  <= pEdidTiming[i].HVisible &&
1559                 height <= frame_height(pEdidTiming[i]) &&
1560                 abs_delta(pEdidTiming[i].HVisible, width) <= abs_delta(pEdidTiming[map2].HVisible, width) &&
1561                 abs_delta(frame_height(pEdidTiming[i]), height) <= abs_delta(frame_height(pEdidTiming[map2]), height))
1562             {
1563                 // if there're 2 timings with the same visible size, choose the one with closer refresh rate
1564                 if (pEdidTiming[i].HVisible == pEdidTiming[map2].HVisible &&
1565                     frame_height(pEdidTiming[i]) == frame_height(pEdidTiming[map2]))
1566                 {
1567                     if (abs_delta(pEdidTiming[i].etc.rr, rr) < abs_delta(pEdidTiming[map2].etc.rr, rr))
1568                     {
1569                         map2 = i;
1570                     }
1571                 }
1572                 else
1573                 {
1574                     map2 = i;
1575                 }
1576             }
1577         }
1578 
1579         // find out the native timing
1580         if (NVT_IS_NATIVE_TIMING(pEdidTiming[i].etc.status) || NVT_IS_DTD1(pEdidTiming[i].etc.status))
1581         {
1582             if (map3 >= pEdidInfo->total_timings)
1583             {
1584                 if (width  <= pEdidTiming[i].HVisible &&
1585                     height <= frame_height(pEdidTiming[i]))
1586                 {
1587                     map3 = i;
1588                 }
1589             }
1590             else if(abs_delta(pEdidTiming[i].HVisible, width) <= abs_delta(pEdidTiming[map3].HVisible, width) &&
1591                 abs_delta(frame_height(pEdidTiming[i]), height) <= abs_delta(frame_height(pEdidTiming[map3]), height) &&
1592                 width  <= pEdidTiming[i].HVisible &&
1593                 height <= frame_height(pEdidTiming[i]))
1594             {
1595                 map3 = i;
1596             }
1597         }
1598 
1599         // find the edid timing with refresh rate matching
1600         if (map4 >= pEdidInfo->total_timings)
1601         {
1602             if (width  <= pEdidTiming[i].HVisible &&
1603                 height <= pEdidTiming[i].VVisible &&
1604                 rr == pEdidTiming[i].etc.rr)
1605             {
1606                 map4 = i;
1607             }
1608         }
1609         else
1610         {
1611             if (width  <= pEdidTiming[i].HVisible &&
1612                 height <= pEdidTiming[i].HVisible &&
1613                 rr     == pEdidTiming[i].etc.rr   &&
1614                 abs_delta(pEdidTiming[i].HVisible, width)  <= abs_delta(pEdidTiming[map4].HVisible, width) &&
1615                 abs_delta(pEdidTiming[i].VVisible, height) <= abs_delta(pEdidTiming[map4].VVisible, height))
1616             {
1617                 map4 = i;
1618             }
1619         }
1620 
1621     }//for (i = 0; i < pEdidInfo->total_timings; i++)
1622 
1623     if ( (preferred_displayid_dtd == preferred_dtd1) && (preferred_dtd1 == dtd1) &&
1624          (dtd1 == map0) &&
1625          (map0 == map1) &&
1626          (map1 == map2) &&
1627          (map2 == map3) &&
1628          (map3 == map4) &&
1629          (map4 == pEdidInfo->total_timings) &&
1630          pEdidInfo->version >= NVT_EDID_VER_1_4 &&
1631          pEdidInfo->u.feature_ver_1_4_digital.continuous_frequency &&
1632          !(flag & NVT_PVT_INTERLACED_MASK))
1633     {
1634         // try to find CVT timing that fits
1635         NvU32 maxHeight, minHeight, tempHeight;
1636 
1637         minHeight = ~0;
1638         maxHeight = tempHeight= 0;
1639 
1640         // looping through long display descriptors
1641         for (i=0; i<NVT_EDID_MAX_LONG_DISPLAY_DESCRIPTOR; i++)
1642         {
1643             if (pEdidInfo->ldd[i].tag != NVT_EDID_DISPLAY_DESCRIPTOR_DRL || pEdidInfo->ldd[i].u.range_limit.timing_support != NVT_EDID_RANGE_SUPPORT_CVT)
1644             {
1645                 continue;
1646             }
1647 
1648             pCVT = &pEdidInfo->ldd[i].u.range_limit.u.cvt;
1649 
1650             if (width <= pCVT->max_active_pixels_per_line || (pCVT->scaling_support & NVT_EDID_CVT_SCALING_HOR_SHRINK))
1651             {
1652                 for (j=0; j<NVT_EDID_CVT_ASPECT_SUPPORT_MAX && !cvt; j++)
1653                 {
1654                     if ( !(pCVT->aspect_supported & (1<<j)))
1655                     {
1656                         continue;
1657                     }
1658 
1659                     switch (1<<j)
1660                     {
1661                         case NVT_EDID_CVT_ASPECT_SUPPORT_4X3:
1662                             tempHeight = axb_div_c(width, 3, 4);
1663                             if (axb_div_c(width, 3, height) ==  4) cvt = 1;
1664                             break;
1665                         case NVT_EDID_CVT_ASPECT_SUPPORT_16X9:
1666                             tempHeight = axb_div_c(width, 9, 16);
1667                             if (axb_div_c(width, 9, height) == 16) cvt = 1;
1668                             break;
1669                         case NVT_EDID_CVT_ASPECT_SUPPORT_16X10:
1670                             tempHeight = axb_div_c(width, 10, 16);
1671                             if (axb_div_c(width,10, height) == 16) cvt = 1;
1672                             break;
1673                         case NVT_EDID_CVT_ASPECT_SUPPORT_5X4:
1674                             tempHeight = axb_div_c(width, 4, 5);
1675                             if (axb_div_c(width, 4, height) ==  5) cvt = 1;
1676                             break;
1677                         case NVT_EDID_CVT_ASPECT_SUPPORT_15X9:
1678                             tempHeight = axb_div_c(width, 9, 15);
1679                             if (axb_div_c(width, 9, height) == 15) cvt = 1;
1680                             break;
1681                     }
1682 
1683                     //keep track of max and min in case NVT_EDID_CVT_SCALING_VER_STRETCH/SHRINK are true
1684                     if (minHeight > tempHeight)
1685                     {
1686                         minHeight = tempHeight;
1687                     }
1688                     if (maxHeight < tempHeight)
1689                     {
1690                         maxHeight = tempHeight;
1691                     }
1692 
1693                 }//for (j=0; j<5; j++)
1694             }//if (width <= pCVT->max_active_pixels_per_line || (pCVT->scaling_support & NVT_EDID_CVT_SCALING_HOR_STRETCH))
1695 
1696             if ( ((minHeight < height) && (pCVT->scaling_support & NVT_EDID_CVT_SCALING_VER_SHRINK)) ||
1697                  ((maxHeight > height) && (pCVT->scaling_support & NVT_EDID_CVT_SCALING_VER_STRETCH)) )
1698             {
1699                 cvt = 1;
1700             }
1701 
1702             if (cvt)
1703             {
1704                 break;
1705             }
1706         }//for (i=0; i<NVT_EDID_MAX_LONG_DISPLAY_DESCRIPTOR; i++)
1707 
1708         if (cvt)
1709         {
1710             //calculate the CVT timing
1711             // 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
1712             if (pCVT->blanking_support & NVT_EDID_CVT_BLANKING_REDUCED && NvTiming_CalcCVT_RB(width, height, rr, NVT_PROGRESSIVE, &cvtTiming) == NVT_STATUS_SUCCESS)
1713             {
1714                 if ( cvtTiming.pclk > (NvU32)((pEdidInfo->ldd[i].u.range_limit.max_pclk_MHz * 100) - (pCVT->pixel_clock_adjustment * 25)) )
1715                 {
1716                     cvt = 0;
1717                 }
1718             }
1719             else if (pCVT->blanking_support & NVT_EDID_CVT_BLANKING_STANDARD && NvTiming_CalcCVT(width, height, rr, NVT_PROGRESSIVE, &cvtTiming) == NVT_STATUS_SUCCESS)
1720             {
1721                 if ( cvtTiming.pclk > (NvU32)((pEdidInfo->ldd[i].u.range_limit.max_pclk_MHz * 100) - (pCVT->pixel_clock_adjustment * 25)) )
1722                 {
1723                     cvt = 0;
1724                 }
1725             }
1726             else
1727             {
1728                 cvt = 0;
1729             }
1730 
1731         }
1732     }//(dtd1 == map0 == map1 == map2 == map3 == pEdidInfo->total_timings) && pEdidInfo->version >= NVT_EDID_VER_1_4 &&
1733      //    pEdidInfo->feature_ver_1_4_digital.continuous_frequency && !(flag & NVT_PVT_INTERLACED_MASK))
1734 
1735     // now return the mismatched EDID timing
1736     if (flag & NVT_FLAG_NV_PREFERRED_TIMING)
1737     {
1738         *pT = (preferred_displayid_dtd != pEdidInfo->total_timings) ? pEdidTiming[preferred_displayid_dtd] :
1739               (preferred_cea != pEdidInfo->total_timings)           ? pEdidTiming[preferred_cea]           :
1740               (preferred_dtd1 != pEdidInfo->total_timings)          ? pEdidTiming[preferred_dtd1]          :
1741                                                                       pEdidTiming[dtd1];
1742         // what if DTD1 itself is filtered out, in such case dtd1 index points to an invalid timing[]?
1743         // (dtd1 != pEdidInfo->total_timings) ? pEdidTiming[dtd1] : pEdidTiming[0];
1744     }
1745     else if (flag & NVT_FLAG_DTD1_TIMING)
1746     {
1747         *pT = pEdidTiming[dtd1];
1748     }
1749     else if ((flag & NVT_FLAG_MAX_EDID_TIMING) && (0 == (flag & NVT_FLAG_EDID_861_ST)))
1750     {
1751         *pT = pEdidTiming[max];
1752     }
1753     else if ((flag & (NVT_FLAG_CEA_4X3_TIMING | NVT_FLAG_CEA_16X9_TIMING | NVT_FLAG_EDID_861_ST)) && ceaIndex < (pEdidInfo->total_timings))
1754     {
1755         *pT = pEdidTiming[ceaIndex];
1756     }
1757     else if ((flag & NVT_FLAG_NATIVE_TIMING) != 0 && map3 < pEdidInfo->total_timings)
1758     {
1759         // Allow closest refresh rate match when EDID has detailed timing for different RR on native resolution.
1760         if (map0 < pEdidInfo->total_timings &&
1761             pEdidTiming[map0].HVisible == pEdidTiming[map3].HVisible &&
1762             pEdidTiming[map0].VVisible == pEdidTiming[map3].VVisible)
1763         {
1764             *pT = pEdidTiming[map0];
1765         }
1766         else
1767         {
1768             *pT = pEdidTiming[map3];
1769         }
1770     }
1771     else if (map0 < pEdidInfo->total_timings)
1772     {
1773         // use the exact mapped timing if possible
1774         *pT = pEdidTiming[map0];
1775     }
1776     else if ((flag & NVT_FLAG_EDID_TIMING_RR_MATCH) && map4 < pEdidInfo->total_timings)
1777     {
1778         *pT = pEdidTiming[map4];
1779     }
1780     else if (map1 < pEdidInfo->total_timings)
1781     {
1782         // use the mapped timing if possible
1783         *pT = pEdidTiming[map1];
1784     }
1785     else if (map2 < pEdidInfo->total_timings)
1786     {
1787         // use the 2nd mapped timing if possible
1788         *pT = pEdidTiming[map2];
1789     }
1790     else if (dtd1 < pEdidInfo->total_timings && width <= pEdidTiming[dtd1].HVisible && height <= pEdidTiming[dtd1].VVisible)
1791     {
1792         // use the 1st detailed timing if possible
1793         *pT = pEdidTiming[dtd1];
1794     }
1795     else if (cvt)
1796     {
1797         // use the cvt timing
1798         *pT = cvtTiming;
1799     }
1800     else
1801     {
1802         // use the max timing for all other cases
1803         *pT = pEdidTiming[max];
1804     }
1805 
1806     // set the mismatch status
1807     if (pT->HVisible != width || frame_height(*pT) != height)
1808     {
1809         NVT_SET_TIMING_STATUS_MISMATCH(pT->etc.status, NVT_STATUS_TIMING_MISMATCH_SIZE);
1810     }
1811     if (!NvTiming_IsRoundedRREqual(pT->etc.rr, pT->etc.rrx1k, (NvU16)rr))
1812     {
1813         NVT_SET_TIMING_STATUS_MISMATCH(pT->etc.status, NVT_STATUS_TIMING_MISMATCH_RR);
1814     }
1815     if (!!pT->interlaced != !!(flag & NVT_PVT_INTERLACED_MASK))
1816     {
1817         NVT_SET_TIMING_STATUS_MISMATCH(pT->etc.status, NVT_STATUS_TIMING_MISMATCH_FORMAT);
1818     }
1819 
1820     return NVT_STATUS_SUCCESS;
1821 }
1822 
1823 // get the edid timing
1824 CODE_SEGMENT(PAGE_DD_CODE)
1825 NVT_STATUS NvTiming_GetEdidTiming(NvU32 width, NvU32 height, NvU32 rr, NvU32 flag, NVT_EDID_INFO *pEdidInfo, NVT_TIMING *pT)
1826 {
1827     return NvTiming_GetEdidTimingEx(width, height, rr, flag, pEdidInfo, pT, 0);
1828 }
1829 CODE_SEGMENT(PAGE_DD_CODE)
1830 NVT_STATUS NvTiming_GetHDMIStereoExtTimingFromEDID(NvU32 width, NvU32 height, NvU32 rr, NvU8 StereoStructureType, NvU8 SideBySideHalfDetail, NvU32 flag, NVT_EDID_INFO *pEdidInfo, NVT_EXT_TIMING *pT)
1831 {
1832     NVT_STATUS  status = NVT_STATUS_ERR;
1833     NvU8        Vic;
1834     NvU32         i;
1835     NVT_TIMING  Timing;
1836 
1837     NVMISC_MEMSET(pT, 0, sizeof(NVT_EXT_TIMING));
1838 
1839     // adjust the flags --
1840     // need EDID timing with RR match,
1841     // not max timing,
1842     flag = flag | NVT_FLAG_EDID_TIMING | NVT_FLAG_EDID_TIMING_RR_MATCH | NVT_FLAG_EDID_861_ST;
1843     flag = flag & ~(NVT_FLAG_MAX_EDID_TIMING);
1844 
1845     status = NvTiming_GetEdidTiming(width, height, rr, flag, pEdidInfo, &Timing);
1846     if (NVT_STATUS_SUCCESS == status)
1847     {
1848         status = NVT_STATUS_ERR;
1849 
1850         // is this an exact match?
1851         if (0 == NVT_GET_TIMING_STATUS_MATCH(Timing.etc.status))
1852         {
1853             if (NVT_TYPE_EDID_861ST == NVT_GET_TIMING_STATUS_TYPE(Timing.etc.status))
1854             {
1855                 // lookup the vic for this timing in the support map.
1856                 Vic = (NvU8) NVT_GET_CEA_FORMAT(Timing.etc.status);
1857                 for (i = 0; i < pEdidInfo->Hdmi3Dsupport.total; ++i)
1858                 {
1859                     if (Vic == pEdidInfo->Hdmi3Dsupport.map[i].Vic)
1860                     {
1861                         break;
1862                     }
1863                 }
1864                 if (i < pEdidInfo->Hdmi3Dsupport.total)
1865                 {
1866                     // does this vic support the requested structure type?
1867                     if (0 != (NVT_HDMI_3D_SUPPORTED_STRUCT_MASK(StereoStructureType) & pEdidInfo->Hdmi3Dsupport.map[i].StereoStructureMask))
1868                     {
1869                         // if this is side-by-side(half) the detail needs to match also.
1870                         if ((NVT_HDMI_VS_BYTE5_HDMI_3DS_SIDEBYSIDEHALF != StereoStructureType) || (SideBySideHalfDetail == pEdidInfo->Hdmi3Dsupport.map[i].SideBySideHalfDetail))
1871                         {
1872                             // convert the 2D timing to 3D.
1873                             NvTiming_GetHDMIStereoTimingFrom2DTiming(&Timing, StereoStructureType, SideBySideHalfDetail, pT);
1874                             status = NVT_STATUS_SUCCESS;
1875                         }
1876                     }
1877                 }
1878             }
1879         }
1880     }
1881     return status;
1882 }
1883 
1884 // EDID based AspectRatio Timing
1885 CODE_SEGMENT(PAGE_DD_CODE)
1886 NVT_STATUS NvTiming_GetEDIDBasedASPRTiming( NvU16 width, NvU16 height, NvU16 rr, NVT_EDID_INFO *pEI, NVT_TIMING *pT)
1887 {
1888     NvU32 i, dwStatus;
1889     NvU32 dwNativeIndex;
1890     NvU32 flag;
1891     NvU32 ret;
1892 
1893     // sanity check
1894     if( pEI == NULL || pEI->total_timings == 0 || pT == NULL )
1895     {
1896         return NVT_STATUS_ERR;
1897     }
1898     if( width == 0 || height == 0 )
1899     {
1900         return NVT_STATUS_ERR;
1901     }
1902 
1903     // get an EDID timing. Return err if it fails as we don't have any timing to tweak.
1904     flag = 0;
1905     ret = NvTiming_GetEdidTiming(width, height, rr, flag, pEI, pT);
1906     if( NVT_STATUS_SUCCESS != ret )
1907     {
1908         return NVT_STATUS_ERR;
1909     }
1910     // in case we have an exact match from EDID (in terms of Size), we return Success.
1911     else if ((NVT_GET_TIMING_STATUS_MATCH(pT->etc.status) & NVT_STATUS_TIMING_MISMATCH_SIZE) == 0)
1912     {
1913         return NVT_STATUS_SUCCESS;
1914     }
1915 
1916     // find the Native timing
1917     for (i = 0, dwNativeIndex = pEI->total_timings + 1; i < pEI->total_timings; i++)
1918     {
1919         dwStatus = pEI->timing[i].etc.status;
1920 
1921         if ((NVT_IS_NATIVE_TIMING(dwStatus)) || NVT_IS_DTD1(dwStatus))
1922         {
1923             dwNativeIndex = i;
1924             break;
1925         }
1926     }
1927 
1928     // we don't want to apply LogicScaling(Letterboxing) to Wide Mode on Wide Panel (or non-Wide Mode on non-Wide Panel)
1929     if( nvt_is_wideaspect(width, height) == nvt_is_wideaspect(pEI->timing[dwNativeIndex].HVisible, pEI->timing[dwNativeIndex].VVisible) )
1930     {
1931         return NVT_STATUS_ERR;
1932     }
1933 
1934     // Letterbox mode enabled by regkey LogicScalingMode
1935     // When we try to set modes not supported in EDID (eg. DFP over DSub) the display may not fit the screen.
1936     // If Logic Scaling is enabled (ie why we are here), we need to tweak the timing (for CRT) provided:
1937     //          1) the aspect ratio of native mode and requested mode differ
1938     //                                      eg. Native AR = 5:4,        1280x1024
1939     //                                          Requested AR = 16:10,   1280x800
1940     //          2) Both Width and Height do not mismatch together; If they do we shall go in for DMT/GTF timing
1941     //             by failing this call.
1942     if( pT->interlaced == 0 &&
1943         dwNativeIndex < pEI->total_timings &&
1944         (pEI->timing[dwNativeIndex].HVisible*height != pEI->timing[dwNativeIndex].VVisible*width) &&
1945         (width == pT->HVisible || height == pT->VVisible))
1946     {
1947         pT->HFrontPorch += (pT->HVisible - width) / 2;
1948         pT->VFrontPorch += (pT->VVisible - height) / 2;
1949         pT->HVisible = width;
1950         pT->VVisible = height;
1951         if(rr != pT->etc.rr)
1952         {
1953             pT->etc.rrx1k = rr * 1000;
1954             pT->pclk = RRx1kToPclk (pT);
1955         }
1956 
1957         pT->etc.status = NVT_STATUS_ASPR;
1958         return NVT_STATUS_SUCCESS;
1959     }
1960 
1961     return NVT_STATUS_ERR;
1962 }
1963 
1964 /**
1965  *
1966  * @brief check EDID raw data is valid or not, and it will return the err flags if it existed
1967  * @param pEdid  : this is a pointer to EDID data
1968  * @param length : read length of EDID
1969  * @param bIsTrongValidation : true - added more check
1970  *                             false- only header and checksum and size check
1971  *
1972  */
1973 CODE_SEGMENT(PAGE_DD_CODE)
1974 NvU32 NvTiming_EDIDValidationMask(NvU8 *pEdid, NvU32 length, NvBool bIsStrongValidation)
1975 {
1976     NvU32                               i, j, version, checkSum;
1977     EDIDV1STRUC                         *p = (EDIDV1STRUC *)pEdid;
1978     EDID_LONG_DISPLAY_DESCRIPTOR        *pLdd;
1979     NvU8                                *pExt;
1980     DETAILEDTIMINGDESCRIPTOR            *pDTD;
1981     NvU32 ret = 0;
1982 
1983     // check the EDID base size to avoid accessing beyond the EDID buffer, do not proceed with
1984     // further validation.
1985     if (length < sizeof(EDIDV1STRUC))
1986     {
1987         ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_SIZE);
1988         return ret;
1989     }
1990 
1991     // check the EDID version and signature
1992     if (getEdidVersion(pEdid, &version) != NVT_STATUS_SUCCESS)
1993     {
1994         ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_VERSION);
1995         return ret;
1996     }
1997 
1998     // check block 0 checksum value
1999     if (!isChecksumValid(pEdid))
2000     {
2001         ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_CHECKSUM);
2002         return ret;
2003     }
2004 
2005     // Strong validation to follow
2006     if (bIsStrongValidation == NV_TRUE)
2007     {
2008         // range limit check
2009         for (i = 0; i < NVT_EDID_MAX_LONG_DISPLAY_DESCRIPTOR; i++)
2010         {
2011             pLdd = (EDID_LONG_DISPLAY_DESCRIPTOR *)&p->DetailedTimingDesc[i];
2012             if (pLdd->tag == NVT_EDID_DISPLAY_DESCRIPTOR_DRL && (version == 0x103 || (version == 0x104 && (p->bFeatureSupport & 1))))
2013             {
2014                 EDID_MONITOR_RANGE_LIMIT *pRangeLimit = (EDID_MONITOR_RANGE_LIMIT *)pLdd->data;
2015                 NvU8    max_v_rate_offset, min_v_rate_offset, max_h_rate_offset, min_h_rate_offset;
2016 
2017                 // add 255Hz offsets as needed before doing the check, use descriptor->rsvd2
2018                 nvt_assert(!(pLdd->rsvd2 & 0xF0));
2019 
2020                 max_v_rate_offset = pLdd->rsvd2 & NVT_PVT_EDID_RANGE_OFFSET_VER_MAX ? NVT_PVT_EDID_RANGE_OFFSET_AMOUNT : 0;
2021                 min_v_rate_offset = pLdd->rsvd2 & NVT_PVT_EDID_RANGE_OFFSET_VER_MIN ? NVT_PVT_EDID_RANGE_OFFSET_AMOUNT : 0;
2022                 max_h_rate_offset = pLdd->rsvd2 & NVT_PVT_EDID_RANGE_OFFSET_HOR_MAX ? NVT_PVT_EDID_RANGE_OFFSET_AMOUNT : 0;
2023                 min_h_rate_offset = pLdd->rsvd2 & NVT_PVT_EDID_RANGE_OFFSET_HOR_MIN ? NVT_PVT_EDID_RANGE_OFFSET_AMOUNT : 0;
2024 
2025                 if ((pRangeLimit->minVRate + min_v_rate_offset) > (pRangeLimit->maxVRate + max_v_rate_offset) ||
2026                     (pRangeLimit->minHRate + min_h_rate_offset) > (pRangeLimit->maxHRate + max_h_rate_offset) ||
2027                     pRangeLimit->maxVRate == 0 ||
2028                     pRangeLimit->maxHRate == 0)
2029                 {
2030                     ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_RANGE_LIMIT);
2031                 }
2032                 break;
2033             }
2034         }
2035 
2036         // extension and size check
2037         if ((NvU32)(p->bExtensionFlag + 1) * sizeof(EDIDV1STRUC) > length)
2038         {
2039             // Do not proceed with further validation if the size is invalid.
2040             ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_SIZE);
2041             return ret;
2042         }
2043 
2044         // validate Detailed Timing Descriptors, 4 blocks
2045         for (i = 0; i < 4; i++)
2046         {
2047             if (*((NvU16 *)&p->DetailedTimingDesc[i]) != 0)
2048             {
2049                 // This block is not a Display Descriptor.
2050                 // It must be a valid timing definition
2051                 // validate the block by passing NULL as the NVTIMING parameter to parseEdidDetailedTimingDescriptor
2052                 if (parseEdidDetailedTimingDescriptor((NvU8 *)&p->DetailedTimingDesc[i], NULL) != NVT_STATUS_SUCCESS)
2053                 {
2054                     ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_DTD);
2055                 }
2056             }
2057             else
2058             {
2059                 // This block is a display descriptor, validate
2060                 if (((EDID_LONG_DISPLAY_DESCRIPTOR *)&p->DetailedTimingDesc[i])->rsvd != 0)
2061                 {
2062                     ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_DTD);
2063                 }
2064             }
2065         }
2066 
2067         // validate extension blocks
2068         for (j = 1; j <= p->bExtensionFlag; j++)
2069         {
2070             pExt = pEdid + sizeof(EDIDV1STRUC) * j;
2071 
2072             // check for 861 extension
2073             switch (*pExt)
2074             {
2075                 case NVT_EDID_EXTENSION_CTA:
2076                     // first sanity check on the extension block
2077                     if (get861ExtInfo(pExt, sizeof(EIA861EXTENSION), NULL) != NVT_STATUS_SUCCESS)
2078                     {
2079                         ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXT);
2080                     }
2081 
2082                     // check sum on CEA extension block
2083                     for (i = 0, checkSum = 0; i < sizeof(EIA861EXTENSION); i ++)
2084                     {
2085                         checkSum += pExt[i];
2086                     }
2087 
2088                     if ((checkSum & 0xFF) != 0)
2089                     {
2090                         ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_CHECKSUM);
2091                     }
2092 
2093                     // 0 indicates no DTD in this block
2094                     if (((EIA861EXTENSION*)pExt)->offset == 0)
2095                     {
2096                         continue;
2097                     }
2098 
2099                     // validate DTD blocks
2100                     pDTD = (DETAILEDTIMINGDESCRIPTOR *)&pExt[((EIA861EXTENSION *)pExt)->offset];
2101                     while (pDTD->wDTPixelClock != 0 &&
2102                             (NvU8 *)pDTD - pExt < (int)sizeof(EIA861EXTENSION))
2103                     {
2104                         if (parseEdidDetailedTimingDescriptor((NvU8 *)pDTD, NULL) != NVT_STATUS_SUCCESS)
2105                         {
2106                             ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXT_DTD);
2107                         }
2108                         pDTD++;
2109                     }
2110                     break;
2111                 case NVT_EDID_EXTENSION_VTB:
2112                     // perform a checksum on the VTB block
2113                     for (i = 0, checkSum = 0; i < sizeof(VTBEXTENSION); i++)
2114                     {
2115                         checkSum += pExt[i];
2116                     }
2117                     if ((checkSum & 0xFF) != 0)
2118                     {
2119                         ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_CHECKSUM);
2120                     }
2121                     break;
2122                 case NVT_EDID_EXTENSION_DISPLAYID:
2123                     // perform a checksum on the VTB block
2124                     for (i = 0, checkSum = 0; i < sizeof(EIA861EXTENSION); i++)
2125                     {
2126                         checkSum += pExt[i];
2127                     }
2128                     if ((checkSum & 0xFF) != 0)
2129                     {
2130                         ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_CHECKSUM);
2131                     }
2132                     break;
2133                 default:
2134                     break;
2135             }
2136         }
2137     }
2138 
2139     return ret;
2140 }
2141 
2142 /**
2143  *
2144  * @brief sanity check EDID binary frequently used data block is valid or not,
2145  *        and it will return error checkpoint flag if it existed
2146  * @param pEdid  : this is a pointer to EDID raw data
2147  * @param length : read length of EDID
2148  *
2149  */
2150 CODE_SEGMENT(PAGE_DD_CODE)
2151 NvU32 NvTiming_EDIDStrongValidationMask(NvU8 *pEdid, NvU32 length)
2152 {
2153     NvU32                               i, j, version, extnCount;
2154     EDIDV1STRUC                         *p = (EDIDV1STRUC *)pEdid;
2155     EDID_LONG_DISPLAY_DESCRIPTOR        *pLdd;
2156     NvU8                                *pExt;
2157     DETAILEDTIMINGDESCRIPTOR            *pDTD;
2158     // For CTA861
2159     NvU8                                ctaDTD_Offset;
2160     NvU8                                *pData_collection;
2161     NvU32                               ctaBlockTag, ctaPayload, vic;
2162     // For DisplayID
2163     DIDEXTENSION                        *pDisplayid;
2164     NvU8                                did_section_length = 0x79;
2165     NvU8                                did2ExtCount = 0;
2166     DISPLAYID_2_0_DATA_BLOCK_HEADER     *pDID2Header;
2167     DISPLAYID_DATA_BLOCK_HEADER         *pHeader;
2168     NvU8                                block_length = 0;
2169     NvBool                              bAllZero = NV_TRUE;
2170     NvU32 ret = 0;
2171 
2172     // check the EDID base size to avoid accessing beyond the EDID buffer, do not proceed with
2173     // further validation.
2174     if (length < sizeof(EDIDV1STRUC))
2175         ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_SIZE);
2176 
2177     // check the EDID version and signature
2178     if (getEdidVersion(pEdid, &version) != NVT_STATUS_SUCCESS)
2179         ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_HEADER);
2180 
2181     // check block 0 checksum value
2182     if (!isChecksumValid(pEdid))
2183         ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_CHECKSUM);
2184 
2185     if (p->bVersionNumber != 0x01 || p->bRevisionNumber > 0x04)
2186     {
2187         ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_VERSION);
2188     }
2189 
2190     // 18bytes in DTD or Display Descriptor check
2191     for (i = 0; i < NVT_EDID_MAX_LONG_DISPLAY_DESCRIPTOR; i++)
2192     {
2193         if (*((NvU16 *)&p->DetailedTimingDesc[i]) != 0)
2194         {
2195             // This block is not a Display Descriptor.
2196             // It must be a valid timing definition
2197             // validate the block by passing NULL as the NVTIMING parameter to parseEdidDetailedTimingDescriptor
2198             if (parseEdidDetailedTimingDescriptor((NvU8 *)&p->DetailedTimingDesc[i], NULL) != NVT_STATUS_SUCCESS)
2199             {
2200                 ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_DTD);
2201             }
2202             else
2203             {
2204                 // check the max image size in monitor and its DTD defines value
2205                 if (p->bMaxHorizImageSize != 0 && p->bMaxVertImageSize != 0)
2206                 {
2207                     DETAILEDTIMINGDESCRIPTOR *pDTD = (DETAILEDTIMINGDESCRIPTOR *)&p->DetailedTimingDesc[i];
2208                     NvU16 hDTDImageSize =  (pDTD->bDTHorizVertImage & 0xF0) << 4 | pDTD->bDTHorizontalImage;
2209                     NvU16 vDTDImageSize =  (pDTD->bDTHorizVertImage & 0x0F) << 8 | pDTD->bDTVerticalImage;
2210 
2211                     if ((hDTDImageSize/10) > p->bMaxHorizImageSize || (vDTDImageSize/10) > p->bMaxVertImageSize)
2212                     {
2213                         ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_DTD);
2214                     }
2215                 }
2216             }
2217         }
2218         else
2219         {
2220             pLdd = (EDID_LONG_DISPLAY_DESCRIPTOR *)&p->DetailedTimingDesc[i];
2221 
2222             // This block is a display descriptor, validate
2223             if (((EDID_LONG_DISPLAY_DESCRIPTOR *)&p->DetailedTimingDesc[i])->rsvd != 0  ||  // (00 00 00)h indicates Display Descriptor
2224                 (pLdd->tag >= 0x11 && pLdd->tag <= 0xF6))                                   // Reserved : Do Not Use
2225                 ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_DESCRIPTOR);
2226 
2227             if (pLdd->tag == NVT_EDID_DISPLAY_DESCRIPTOR_DRL && (version == 0x103 || (version == 0x104 && (p->bFeatureSupport & 1))))
2228             {
2229                 EDID_MONITOR_RANGE_LIMIT *pRangeLimit = (EDID_MONITOR_RANGE_LIMIT *)pLdd->data;
2230                 NvU8    max_v_rate_offset, min_v_rate_offset, max_h_rate_offset, min_h_rate_offset;
2231 
2232                 // add 255Hz offsets as needed before doing the check, use descriptor->rsvd2
2233                 nvt_assert(!(pLdd->rsvd2 & 0xF0));
2234 
2235                 max_v_rate_offset = pLdd->rsvd2 & NVT_PVT_EDID_RANGE_OFFSET_VER_MAX ? NVT_PVT_EDID_RANGE_OFFSET_AMOUNT : 0;
2236                 min_v_rate_offset = pLdd->rsvd2 & NVT_PVT_EDID_RANGE_OFFSET_VER_MIN ? NVT_PVT_EDID_RANGE_OFFSET_AMOUNT : 0;
2237                 max_h_rate_offset = pLdd->rsvd2 & NVT_PVT_EDID_RANGE_OFFSET_HOR_MAX ? NVT_PVT_EDID_RANGE_OFFSET_AMOUNT : 0;
2238                 min_h_rate_offset = pLdd->rsvd2 & NVT_PVT_EDID_RANGE_OFFSET_HOR_MIN ? NVT_PVT_EDID_RANGE_OFFSET_AMOUNT : 0;
2239 
2240                 if ((pRangeLimit->minVRate + min_v_rate_offset) > (pRangeLimit->maxVRate + max_v_rate_offset) ||
2241                     (pRangeLimit->minHRate + min_h_rate_offset) > (pRangeLimit->maxHRate + max_h_rate_offset) ||
2242                     pRangeLimit->maxVRate == 0 ||
2243                     pRangeLimit->maxHRate == 0)
2244                 {
2245                     ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_RANGE_LIMIT);
2246                 }
2247             }
2248         }
2249     }
2250 
2251     // extension and size check
2252     if ((NvU32)(p->bExtensionFlag + 1) * sizeof(EDIDV1STRUC) > length)
2253     {
2254         ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXTENSION_COUNT);
2255     }
2256 
2257     // validate extension blocks
2258     for (j = 1; j <= p->bExtensionFlag; j++)
2259     {
2260         pExt = pEdid + sizeof(EDIDV1STRUC) * j;
2261 
2262         // check for 861 extension
2263         switch (*pExt)
2264         {
2265             case NVT_EDID_EXTENSION_CTA:
2266                 ctaDTD_Offset = ((EIA861EXTENSION *)pExt)->offset;
2267                 // first sanity check on the extension block
2268                 if (get861ExtInfo(pExt, sizeof(EIA861EXTENSION), NULL) != NVT_STATUS_SUCCESS ||
2269                     ((EIA861EXTENSION *)pExt)->revision < NVT_CEA861_REV_B)
2270                 {
2271                     ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXT_CTA_BASIC);
2272                 }
2273 
2274                 // 0 indicated there is no DTD and data collection in this block
2275                 if (ctaDTD_Offset == 0)
2276                 {
2277                     if(!isChecksumValid(pExt))
2278                         ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXT_CTA_CHECKSUM);
2279                     continue;
2280                 }
2281 
2282                 // validate SVD block
2283                 ctaBlockTag = NVT_CEA861_GET_SHORT_DESCRIPTOR_TAG(((EIA861EXTENSION *)pExt)->data[0]);
2284                 pData_collection = ((EIA861EXTENSION *)pExt)->data;
2285 
2286                 while ((ctaDTD_Offset - 4) > 0 && pData_collection != &pExt[ctaDTD_Offset] &&
2287                         ctaBlockTag > NVT_CEA861_TAG_RSVD && ctaBlockTag <= NVT_CEA861_TAG_EXTENDED_FLAG)
2288                 {
2289                     ctaBlockTag = NVT_CEA861_GET_SHORT_DESCRIPTOR_TAG(*pData_collection);
2290                     ctaPayload = NVT_CEA861_GET_SHORT_DESCRIPTOR_SIZE(*pData_collection);
2291 
2292                     if (parseCta861DataBlockInfo(pData_collection, (NvU32)ctaDTD_Offset - 4, NULL) == NVT_STATUS_SUCCESS)
2293                     {
2294                         pData_collection++;
2295                         if (ctaBlockTag == NVT_CEA861_TAG_VIDEO)
2296                         {
2297                             for (i=0; i < ctaPayload; i++)
2298                             {
2299                                 vic = NVT_GET_CTA_8BIT_VIC(*pData_collection);
2300                                 if (vic == 0 || vic > 255 || (vic >= 128 && vic <=192))
2301                                     ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXT_CTA_SVD);
2302                                 pData_collection++;
2303                             }
2304                         }
2305                         else if (ctaBlockTag == NVT_CEA861_TAG_EXTENDED_FLAG)
2306                         {
2307                             if (*pData_collection == NVT_CEA861_EXT_TAG_HF_EEODB)
2308                             {
2309                                 if ((p->bVersionNumber != 0x01) || (p->bRevisionNumber != 0x03))
2310                                 {
2311                                     ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXT_CTA_INVALID_DATA_BLOCK);
2312                                     pData_collection += ctaPayload;
2313                                 }
2314                                 else
2315                                 {
2316                                     ret &= ~NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXTENSION_COUNT);
2317                                     extnCount = *(++pData_collection);
2318                                     // check the EDID extension count value again because EDID extension block count
2319                                     // value in EEODB override it and source shall ignore extension flag > 1 value
2320                                     if ((extnCount + 1) != (length / (sizeof(EDIDV1STRUC))))
2321                                         ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXTENSION_COUNT);
2322                                     pData_collection++;
2323                                 }
2324                             }
2325                             else
2326                                 pData_collection += ctaPayload;
2327                         }
2328                         else if (ctaBlockTag == NVT_CEA861_TAG_RSVD || ctaBlockTag == NVT_CEA861_TAG_RSVD1)
2329                         {
2330                             ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXT_CTA_TAG);
2331                             pData_collection += ctaPayload;
2332                         }
2333                         else
2334                             pData_collection += ctaPayload;
2335                     }
2336                     else
2337                     {
2338                         ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXT_CTA_INVALID_DATA_BLOCK);
2339                         pData_collection += ctaPayload;
2340                     }
2341                 }
2342 
2343                 // validate DTD blocks
2344                 pDTD = (DETAILEDTIMINGDESCRIPTOR *)&pExt[((EIA861EXTENSION *)pExt)->offset];
2345                 while (pDTD->wDTPixelClock != 0 &&
2346                        (NvU8 *)pDTD - pExt < (int)sizeof(EIA861EXTENSION))
2347                 {
2348                     if (parseEdidDetailedTimingDescriptor((NvU8 *)pDTD, NULL) != NVT_STATUS_SUCCESS)
2349                         ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXT_DTD);
2350                     else
2351                     {
2352                         // check the max image size and
2353                         if (p->bMaxHorizImageSize != 0 && p->bMaxVertImageSize != 0)
2354                         {
2355                             NvU16 hDTDImageSize =  (pDTD->bDTHorizVertImage & 0xF0) << 4 | pDTD->bDTHorizontalImage;
2356                             NvU16 vDTDImageSize =  (pDTD->bDTHorizVertImage & 0x0F) << 8 | pDTD->bDTVerticalImage;
2357 
2358                             if ((hDTDImageSize/10) > (p->bMaxHorizImageSize) || (vDTDImageSize/10) > p->bMaxVertImageSize)
2359                                 ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXT_CTA_DTD);
2360                         }
2361                     }
2362                     pDTD++;
2363                 }
2364 
2365                 if(!isChecksumValid(pExt))
2366                     ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXT_CTA_CHECKSUM);
2367             break;
2368             case NVT_EDID_EXTENSION_DISPLAYID:
2369                 pDisplayid = ((DIDEXTENSION *)pExt);
2370                 if (pDisplayid->ext_count != 0)
2371                     ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXT_DID_EXTCOUNT);
2372 
2373                 if (pDisplayid->length != 0x79)
2374                     ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXT_DID_SEC_SIZE);
2375 
2376                 if (!isChecksumValid(pExt))
2377                     ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXT_DID_CHECKSUM);
2378 
2379                 // check the DID2 data blocks
2380                 if ((pDisplayid->struct_version & 0xF0) >> 4 == 2)
2381                 {
2382                     if ((pDisplayid->struct_version & 0xFF) == 0x21)
2383                         ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXT_DID_VERSION);
2384 
2385                     did2ExtCount++;
2386 
2387                     if (pDisplayid->use_case == 0 && did2ExtCount == 1)
2388                         ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXT_DID2_USE_CASE);
2389 
2390                     // check the DisplayId2 valid timing
2391                     pDID2Header = (DISPLAYID_2_0_DATA_BLOCK_HEADER*)pDisplayid->data;
2392                     pData_collection = pDisplayid->data;
2393 
2394                     // Sanity check every data blocks
2395                     while (((pDID2Header->type >= DISPLAYID_2_0_BLOCK_TYPE_PRODUCT_IDENTITY &&
2396                             pDID2Header->type <= DISPLAYID_2_0_BLOCK_TYPE_ARVR_LAYER)  ||
2397                             pDID2Header->type == DISPLAYID_2_0_BLOCK_TYPE_VENDOR_SPEC ||
2398                             pDID2Header->type == DISPLAYID_2_0_BLOCK_TYPE_CTA_DATA) && pDID2Header->data_bytes != 0 &&
2399                             (pData_collection - pExt < (int)sizeof(DIDEXTENSION)))
2400                     {
2401                         if (parseDisplayId20EDIDExtDataBlocks(pData_collection, did_section_length, &block_length, NULL) ==  NVT_STATUS_ERR)
2402                         {
2403                             if (pDID2Header->type == DISPLAYID_2_0_BLOCK_TYPE_TIMING_7)
2404                                 ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXT_DID2_TYPE7);
2405 
2406                             if (pDID2Header->type == DISPLAYID_2_0_BLOCK_TYPE_RANGE_LIMITS)
2407                                 ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXT_RANGE_LIMIT);
2408 
2409                             if (pDID2Header->type == DISPLAYID_2_0_BLOCK_TYPE_ADAPTIVE_SYNC)
2410                                 ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXT_DID2_ADAPTIVE_SYNC);
2411                             // add more data blocks tag here to evaluate
2412                         }
2413                         pData_collection += block_length;
2414                         pDID2Header = (DISPLAYID_2_0_DATA_BLOCK_HEADER*)pData_collection;
2415                     }
2416 
2417                     // compare the remain 0 value are correct or not before meet checksum byte
2418                     for (i = 0; i <= (NvU32)(&pDisplayid->data[NVT_DID_MAX_EXT_PAYLOAD-1] - pData_collection); i++)
2419                     {
2420                         if (pData_collection[i] != 0)
2421                         {
2422                             bAllZero = NV_FALSE;
2423                             break;
2424                         }
2425                     }
2426 
2427                     // if the first tag failed, ignore all the tags afterward then
2428                     if (!bAllZero &&
2429                         (pDID2Header->type < DISPLAYID_2_0_BLOCK_TYPE_PRODUCT_IDENTITY ||
2430                         (pDID2Header->type > DISPLAYID_2_0_BLOCK_TYPE_ARVR_LAYER   &&
2431                         pDID2Header->type != DISPLAYID_2_0_BLOCK_TYPE_VENDOR_SPEC  &&
2432                         pDID2Header->type != DISPLAYID_2_0_BLOCK_TYPE_CTA_DATA))       &&
2433                         (pData_collection - pExt < (int)sizeof(DIDEXTENSION)))
2434                     {
2435                         ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXT_DID2_TAG);
2436                         continue;
2437                     }
2438                 }
2439                 else if ((pDisplayid->struct_version & 0xFF) == 0x12 || (pDisplayid->struct_version & 0xFF) == 0x13)
2440                 {
2441                     if ((pDisplayid->struct_version & 0xFF) == 0x13)
2442                         ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXT_DID_VERSION);
2443 
2444                     pHeader = (DISPLAYID_DATA_BLOCK_HEADER*)pDisplayid->data;
2445                     pData_collection = pDisplayid->data;
2446 
2447                     // Sanity check every data blocks
2448                     while ((pHeader->type <= NVT_DISPLAYID_BLOCK_TYPE_TILEDDISPLAY ||
2449                             pHeader->type == NVT_DISPLAYID_BLOCK_TYPE_CTA_DATA     ||
2450                             pHeader->type == NVT_DISPLAYID_BLOCK_TYPE_VENDOR_SPEC) && pHeader->data_bytes != 0 &&
2451                         (pData_collection - pExt < (int)sizeof(DIDEXTENSION)))
2452                     {
2453                         if (parseDisplayIdBlock(pData_collection, did_section_length, &block_length, NULL) == NVT_STATUS_ERR)
2454                         {
2455                             if (pHeader->type == NVT_DISPLAYID_BLOCK_TYPE_TIMING_1)
2456                                 ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXT_DID13_TYPE1);
2457 
2458                             if (pHeader->type == NVT_DISPLAYID_BLOCK_TYPE_RANGE_LIMITS)
2459                                 ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXT_RANGE_LIMIT);
2460 
2461                             // add more data blocks tag here to evaluate
2462                         }
2463                         pData_collection += block_length;
2464                         pHeader = (DISPLAYID_DATA_BLOCK_HEADER*)pData_collection;
2465                     }
2466 
2467                     // compare the remain 0 value are correct or not before meet checksum byte
2468                     for (i = 0; i <= (NvU32)(&pDisplayid->data[NVT_DID_MAX_EXT_PAYLOAD-1] - pData_collection); i++)
2469                     {
2470                         if (pData_collection[i] != 0)
2471                         {
2472                             bAllZero = NV_FALSE;
2473                             break;
2474                         }
2475                     }
2476 
2477                     // if the first tag failed, ignore all the tags afterward then
2478                     if (!bAllZero                                             &&
2479                         pHeader->type > NVT_DISPLAYID_BLOCK_TYPE_TILEDDISPLAY &&
2480                         pHeader->type != NVT_DISPLAYID_BLOCK_TYPE_CTA_DATA    &&
2481                         pHeader->type != NVT_DISPLAYID_BLOCK_TYPE_VENDOR_SPEC &&
2482                         (pData_collection - pExt < (int)sizeof(DIDEXTENSION)))
2483                     {
2484                         ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXT_DID13_TAG);
2485                         continue;
2486                     }
2487                 }
2488                 else
2489                     ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXT_DID_VERSION);
2490             break;
2491             default:
2492                 // the useful extension only CTA (0x02) and DisplayID (0x70)
2493                 if ( *pExt != NVT_EDID_EXTENSION_VTB && *pExt != NVT_EDID_EXTENSION_DI   &&
2494                     *pExt != NVT_EDID_EXTENSION_LS  && *pExt != NVT_EDID_EXTENSION_DPVL &&
2495                     *pExt != NVT_EDID_EXTENSION_BM  && *pExt != NVT_EDID_EXTENSION_OEM )
2496                 {
2497                     ret |= NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXTENSION_TAG);
2498                 }
2499             break;
2500         }
2501     }
2502 
2503     return ret;
2504 }
2505 
2506 CODE_SEGMENT(PAGE_DD_CODE)
2507 NVT_STATUS NvTiming_EDIDValidation (NvU8 *pEdid, NvU32 length, NvBool bIsStrongValidation)
2508 {
2509     if (NvTiming_EDIDValidationMask(pEdid, length, bIsStrongValidation) != 0) {
2510         return NVT_STATUS_ERR;
2511     } else {
2512         return NVT_STATUS_SUCCESS;
2513     }
2514 }
2515 
2516 // Function Description: Get the first Detailed Timing Descriptor
2517 //
2518 // Parameters:
2519 //        pEdidInfo:  IN - pointer to parsed EDID
2520 //               pT:  OUT - pointer to where the DTD1 timing will be stored
2521 //
2522 // Return:
2523 //             NVT_STATUS_SUCCESS: DTD1 was found in parsed EDID, pT is a valid result
2524 //   NVT_STATUS_INVALID_PARAMETER: one or more parameter was invalid
2525 //           NVT_STATUS_ERR: DTD1 was not found in parsed EDID, pT is invalid
2526 CODE_SEGMENT(PAGE_DD_CODE)
2527 NVT_STATUS NvTiming_GetDTD1Timing (NVT_EDID_INFO * pEdidInfo, NVT_TIMING * pT)
2528 {
2529     NvU32 j;
2530 
2531     // check param
2532     if (pEdidInfo == NULL || pT == NULL)
2533     {
2534         return NVT_STATUS_INVALID_PARAMETER;
2535     }
2536 
2537     // find the PTM mode
2538     for (j = 0; j < pEdidInfo->total_timings; j++)
2539     {
2540         if (NVT_PREFERRED_TIMING_IS_DTD1(pEdidInfo->timing[j].etc.flag, pEdidInfo->timing[j].etc.status))
2541         {
2542             *pT = pEdidInfo->timing[j];
2543             return NVT_STATUS_SUCCESS;
2544         }
2545     }
2546 
2547     // find DisplayID preferred
2548     for (j = 1; j < pEdidInfo->total_timings; j++)
2549     {
2550         if (NVT_PREFERRED_TIMING_IS_DISPLAYID(pEdidInfo->timing[j].etc.flag))
2551         {
2552             *pT = pEdidInfo->timing[j];
2553             return NVT_STATUS_SUCCESS;
2554         }
2555     }
2556 
2557     // DTD1 should exist, but if it doesn't, return not found
2558     for (j = 0; j < pEdidInfo->total_timings; j++)
2559     {
2560         NvU32 data = pEdidInfo->timing[j].etc.status;
2561         if (NVT_IS_DTD1(data))
2562         {
2563             *pT = pEdidInfo->timing[j];
2564             return NVT_STATUS_SUCCESS;
2565         }
2566     }
2567 
2568     // DTD1 should exist, but if it doesn't, return not found
2569     return NVT_STATUS_ERR;
2570 }
2571 
2572 // Description: Parses a VTB extension block into its associated timings
2573 //
2574 // Parameters:
2575 //     pEdidExt: IN - pointer to the beginning of the extension block
2576 //        pInfo: IN - The original block information, including the
2577 //                    array of timings.
2578 //
2579 // NOTE: this function *really* should be in its own separate file, but a certain DVS test
2580 // uses cross build makefiles which do not allow the specification of a new file.
2581 CODE_SEGMENT(PAGE_DD_CODE)
2582 void parseVTBExtension(NvU8 *pEdidExt, NVT_EDID_INFO *pInfo)
2583 {
2584     NvU32 i;
2585     VTBEXTENSION *pExt = (VTBEXTENSION *)pEdidExt;
2586     NvU32 count;
2587     NvU32 bytes;
2588     NVT_TIMING newTiming;
2589 
2590     // Null = bad idea
2591     if (pEdidExt == NULL)
2592     {
2593         return;
2594     }
2595 
2596     // Sanity check for VTB extension block
2597     if (pExt->tag != NVT_EDID_EXTENSION_VTB ||
2598         pExt->revision == NVT_VTB_REV_NONE)
2599     {
2600         return;
2601     }
2602 
2603     // Sanity check - ensure that the # of descriptor does not exceed
2604     // byte size
2605     count = (NvU32)sizeof(EDID_LONG_DISPLAY_DESCRIPTOR) * pExt->num_detailed
2606           + (NvU32)sizeof(EDID_CVT_3BYTE_BLOCK) * pExt->num_cvt
2607           + (NvU32)sizeof(NvU16) * pExt->num_standard;
2608     if (count > NVT_VTB_MAX_PAYLOAD)
2609     {
2610         return;
2611     }
2612 
2613     count = 0;
2614     bytes = 0;
2615 
2616     // Process Detailed Timings
2617     for (i = 0; i < pExt->num_detailed; i++)
2618     {
2619         NVMISC_MEMSET(&newTiming, 0, sizeof(newTiming));
2620 
2621         if (parseEdidDetailedTimingDescriptor((NvU8 *)(pExt->data + bytes),
2622                                               &newTiming) == NVT_STATUS_SUCCESS)
2623         {
2624             newTiming.etc.name[39] = '\0';
2625             newTiming.etc.status = NVT_STATUS_EDID_VTB_EXT_DTDn(++count);
2626 
2627             if (!assignNextAvailableTiming(pInfo, &newTiming))
2628             {
2629                 break;
2630             }
2631 
2632             bytes += (NvU32)(sizeof(EDID_LONG_DISPLAY_DESCRIPTOR));
2633         }
2634     }
2635 
2636     // Process CVT Timings
2637     for (i = 0; i < pExt->num_cvt; i++)
2638     {
2639         parseEdidCvt3ByteDescriptor((NvU8 *)(pExt->data + bytes), pInfo, &count);
2640 
2641         bytes += (NvU32)sizeof(EDID_CVT_3BYTE_BLOCK);
2642     }
2643 
2644     // Process Standard Timings
2645     for (i = 0; i < pExt->num_standard; i++)
2646     {
2647         NVMISC_MEMSET(&newTiming, 0, sizeof(newTiming));
2648 
2649         parseEdidStandardTimingDescriptor(*(NvU16 *)(pExt->data + bytes),
2650                                           pInfo, count, &newTiming);
2651         newTiming.etc.name[39] = '\0';
2652         newTiming.etc.status = NVT_STATUS_EDID_VTB_EXT_STDn(++count);
2653 
2654         if (!assignNextAvailableTiming(pInfo, &newTiming))
2655         {
2656             break;
2657         }
2658 
2659         bytes += (NvU32)sizeof(NvU16);
2660     }
2661 }
2662 
2663 CODE_SEGMENT(PAGE_DD_CODE)
2664 static int IsPrintable(NvU8 c)
2665 {
2666     return ((c >= ' ') && (c <= '~'));
2667 }
2668 
2669 CODE_SEGMENT(PAGE_DD_CODE)
2670 static int IsWhiteSpace(NvU8 c)
2671 {
2672     // consider anything unprintable or single space (ASCII 32)
2673     // to be whitespace
2674     return (!IsPrintable(c) || (c == ' '));
2675 }
2676 
2677 CODE_SEGMENT(PAGE_DD_CODE)
2678 static void RemoveTrailingWhiteSpace(NvU8 *str, int len)
2679 {
2680     int i;
2681 
2682     for (i = len; (i >= 0) && IsWhiteSpace(str[i]); i--)
2683     {
2684         str[i] = '\0';
2685     }
2686 }
2687 
2688 CODE_SEGMENT(PAGE_DD_CODE)
2689 static void RemoveNonPrintableCharacters(NvU8 *str)
2690 {
2691     int i;
2692 
2693     // Check that all characters are printable.
2694     // If not, replace them with '?'
2695     for (i = 0; str[i] != '\0'; i++)
2696     {
2697         if (!IsPrintable(str[i]))
2698         {
2699             str[i] = '?';
2700         }
2701     }
2702 }
2703 
2704 /**
2705  * @brief Assigns this timing to the next available slot in pInfo->timing[] if
2706  *        possible.
2707  * @param pInfo EDID struct containing the parsed timings
2708  * @param pTiming New timing to be copied into pInfo->timing[]
2709  */
2710 CODE_SEGMENT(PAGE_DD_CODE)
2711 NvBool assignNextAvailableTiming(NVT_EDID_INFO *pInfo,
2712                                  const NVT_TIMING *pTiming)
2713 {
2714     if (pInfo == NULL) return NV_TRUE;
2715 
2716     // Don't write past the end of
2717     // pInfo->timing[NVT_EDID_MAX_TOTAL_TIMING]
2718     if (pInfo->total_timings >= COUNT(pInfo->timing)) {
2719         return NV_FALSE;
2720     }
2721 
2722     pInfo->timing[pInfo->total_timings++] = *pTiming;
2723     return NV_TRUE;
2724 }
2725 
2726 CODE_SEGMENT(PAGE_DD_CODE)
2727 NVT_STATUS NvTiming_GetProductName(const NVT_EDID_INFO *pEdidInfo,
2728                                    NvU8 *pProductName,
2729                                    const NvU32 productNameLength)
2730 {
2731     NvU32 i = 0, m = 0, n = 0;
2732 
2733     if( pEdidInfo == NULL || pProductName == NULL )
2734     {
2735         return NVT_STATUS_INVALID_PARAMETER;
2736     }
2737 
2738     for ( i = 0; i < NVT_EDID_MAX_LONG_DISPLAY_DESCRIPTOR; i++)
2739     {
2740         if (pEdidInfo->ldd[i].tag == NVT_EDID_DISPLAY_DESCRITPOR_DPN)
2741         {
2742             for(n = 0; n < NVT_EDID_LDD_PAYLOAD_SIZE && pEdidInfo->ldd[i].u.product_name.str[n] != 0x0; n++)
2743             {
2744                 pProductName[m++] = pEdidInfo->ldd[i].u.product_name.str[n];
2745                 if ((m + 1) >= productNameLength)
2746                 {
2747                     goto done;
2748                 }
2749             }
2750         }
2751     }
2752 done:
2753     pProductName[m] = '\0'; //Ensure a null termination at the end.
2754 
2755     RemoveTrailingWhiteSpace(pProductName, m);
2756     RemoveNonPrintableCharacters(pProductName);
2757 
2758     return NVT_STATUS_SUCCESS;
2759 }
2760 
2761 CODE_SEGMENT(PAGE_DD_CODE)
2762 NvU32 NvTiming_CalculateEDIDCRC32(NvU8* pEDIDBuffer, NvU32 edidsize)
2763 {
2764     return calculateCRC32(pEDIDBuffer, edidsize);
2765 }
2766 
2767 //Calculates EDID/DisplayID2 CRC after purging 'Week of Manufacture', 'Year of Manufacture',
2768 //'Product ID String' & 'Serial Number' from EDID
2769 CODE_SEGMENT(PAGE_DD_CODE)
2770 NvU32 NvTiming_CalculateCommonEDIDCRC32(NvU8* pEDIDBuffer, NvU32 edidVersion)
2771 {
2772     NvU32 commonEDIDBufferSize = 0;
2773     NvU8 CommonEDIDBuffer[256];
2774     NvU32 edidBufferIndex = 0;
2775 
2776     if(pEDIDBuffer==NULL)
2777     {
2778         return 0;
2779     }
2780 
2781     // Transfer over the original EDID buffer
2782     NVMISC_MEMCPY(CommonEDIDBuffer, pEDIDBuffer, 256);
2783 
2784     if ((pEDIDBuffer[0] & 0xF0) == 0x20)
2785     {
2786         /*
2787         typedef struct DisplayId2Struct
2788         {
2789             NvU8   bVersion;                   // 0x00
2790             NvU8   bSectionBytes;              // 0x01 - section length, exclusive the five mandatory bytes.
2791             NvU8   bwPrimaryUseCase;           // 0x02
2792             NvU8   bExtensionCount;            // 0x03
2793             // 0x20 DisplayId2 Standalone always exists Product Identification data block
2794             NvU8   bProductIdtag;              // 0x04
2795             NvU8   bPIDRevision;               // 0x05
2796             NvU8   bPayloadByte;               // 0x06
2797             NvU8   bManuId[3];                 // 0x07-0x09
2798             NvU16  wProductId;                 // 0x0A-0x0B
2799             NvU32  dwSerialNum;                // 0x0C-0x0F
2800             NvU16  wWeekandYear;               // 0x10-0x11
2801             NvU8   SizeOfProductNameString;    // 0x12
2802         } DISPLAY_ID2_FIXED_FORMAT;
2803         */
2804 
2805         // Wipe out the Serial Number, Week of Manufacture, and Year of Manufacture or Model Year
2806         NVMISC_MEMSET(CommonEDIDBuffer + 0x0C, 0, 6);
2807 
2808         // Wipe out the checksums
2809         CommonEDIDBuffer[CommonEDIDBuffer[1]+5/*mandatory bytes*/-1] = 0;
2810         CommonEDIDBuffer[0xFF] = 0;
2811 
2812         // zero out any Produc Name in Prodcut Identification data block
2813         if (CommonEDIDBuffer[0x12] != 0)
2814         {
2815             NVMISC_MEMSET(CommonEDIDBuffer + 0x13, 0, CommonEDIDBuffer[0x12]);
2816             CommonEDIDBuffer[0x12] = 0;
2817         }
2818 
2819         // displayId2 standalone uses 256 length sections
2820         commonEDIDBufferSize = 256;
2821     }
2822     else
2823     {
2824         // Wipe out the Serial Number, Week of Manufacture, and Year of Manufacture or Model Year
2825         NVMISC_MEMSET(CommonEDIDBuffer + 0x0C, 0, 6);
2826 
2827         // Wipe out the checksums
2828         CommonEDIDBuffer[0x7F] = 0;
2829         CommonEDIDBuffer[0xFF] = 0;
2830 
2831         // We also need to zero out any "EDID Other Monitor Descriptors" (http://en.wikipedia.org/wiki/Extended_display_identification_data)
2832         for (edidBufferIndex = 54; edidBufferIndex <= 108; edidBufferIndex += 18)
2833         {
2834             if (CommonEDIDBuffer[edidBufferIndex] == 0 && CommonEDIDBuffer[edidBufferIndex+1] == 0)
2835             {
2836                 // Wipe this block out. It contains OEM-specific details that contain things like serial numbers
2837                 NVMISC_MEMSET(CommonEDIDBuffer + edidBufferIndex, 0, 18);
2838             }
2839         }
2840 
2841         // Check what size we should do the compare against
2842         commonEDIDBufferSize = 128;
2843     }
2844 
2845     return NvTiming_CalculateEDIDCRC32(CommonEDIDBuffer, commonEDIDBufferSize);
2846 } // NvTiming_CalculateCommonEDIDCRC32
2847 
2848 // Calculate the minimum and maximum v_rate and h_rate, as well as
2849 // maximum pclk; initialize with the range of values in the EDID mode
2850 // list, but override with what is in the range limit descriptor section.
2851 //
2852 // based on drivers/modeset.nxt/CODE/edid.c:EdidGetMonitorLimits() and
2853 // EdidBuildRangeLimits()
2854 CODE_SEGMENT(PAGE_DD_CODE)
2855 NVT_STATUS NvTiming_CalculateEDIDLimits(NVT_EDID_INFO *pEdidInfo, NVT_EDID_RANGE_LIMIT *pLimit)
2856 {
2857     NvU32 i;
2858 
2859     NVMISC_MEMSET(pLimit, 0, sizeof(NVT_EDID_RANGE_LIMIT));
2860 
2861     // the below currently only supports 1.x EDIDs
2862     if ((pEdidInfo->version & 0xFF00) != 0x100)
2863     {
2864         return NVT_STATUS_ERR;
2865     }
2866 
2867     pLimit->min_v_rate_hzx1k = ~0;
2868     pLimit->max_v_rate_hzx1k = 0;
2869     pLimit->min_h_rate_hz = ~0;
2870     pLimit->max_h_rate_hz = 0;
2871     pLimit->max_pclk_10khz = 0;
2872 
2873     // find the ranges in the EDID mode list
2874     for (i = 0; i < pEdidInfo->total_timings; i++)
2875     {
2876         NVT_TIMING *pTiming = &pEdidInfo->timing[i];
2877         NvU32 h_rate_hz;
2878 
2879         if (pLimit->min_v_rate_hzx1k > pTiming->etc.rrx1k)
2880         {
2881             pLimit->min_v_rate_hzx1k = pTiming->etc.rrx1k;
2882         }
2883         if (pLimit->max_v_rate_hzx1k < pTiming->etc.rrx1k)
2884         {
2885             pLimit->max_v_rate_hzx1k = pTiming->etc.rrx1k;
2886         }
2887 
2888         h_rate_hz = axb_div_c(pTiming->pclk, 10000, (NvU32)pTiming->HTotal);
2889 
2890         if (pLimit->min_h_rate_hz > h_rate_hz)
2891         {
2892             pLimit->min_h_rate_hz = h_rate_hz;
2893         }
2894         if (pLimit->max_h_rate_hz < h_rate_hz)
2895         {
2896             pLimit->max_h_rate_hz = h_rate_hz;
2897         }
2898 
2899         if (pLimit->max_pclk_10khz < pTiming->pclk)
2900         {
2901             pLimit->max_pclk_10khz = pTiming->pclk;
2902         }
2903     }
2904 
2905     // use the range limit display descriptor, if available: these
2906     // override anything we found in the EDID mode list
2907     for (i = 0; i < NVT_EDID_MAX_LONG_DISPLAY_DESCRIPTOR; i++)
2908     {
2909         if (pEdidInfo->ldd[i].tag == NVT_EDID_DISPLAY_DESCRIPTOR_DRL)
2910         {
2911             NVT_EDID_DD_RANGE_LIMIT *pRangeLimit = &pEdidInfo->ldd[i].u.range_limit;
2912             NvU32 max_pclk_10khz;
2913 
2914             // {min,max}_v_rate is in hz
2915             if (pRangeLimit->min_v_rate != 0) {
2916                 pLimit->min_v_rate_hzx1k = pRangeLimit->min_v_rate * 1000;
2917             }
2918             if (pRangeLimit->max_v_rate != 0) {
2919                 pLimit->max_v_rate_hzx1k = pRangeLimit->max_v_rate * 1000;
2920             }
2921 
2922             // {min,max}_h_rate is in khz
2923             if (pRangeLimit->min_h_rate != 0) {
2924                 pLimit->min_h_rate_hz = pRangeLimit->min_h_rate * 1000;
2925             }
2926             if (pRangeLimit->max_h_rate != 0) {
2927                 pLimit->max_h_rate_hz = pRangeLimit->max_h_rate * 1000;
2928             }
2929 
2930             // EdidGetMonitorLimits() honored the pclk from the
2931             // modelist over what it found in the range limit
2932             // descriptor, so do the same here
2933             max_pclk_10khz = pRangeLimit->max_pclk_MHz * 100;
2934             if (pLimit->max_pclk_10khz < max_pclk_10khz) {
2935                 pLimit->max_pclk_10khz = max_pclk_10khz;
2936             }
2937 
2938             break;
2939         }
2940     }
2941 
2942     return NVT_STATUS_SUCCESS;
2943 }
2944 
2945 // Build a user-friendly name:
2946 //
2947 // * get the vendor name:
2948 //     * use the 3 character PNP ID from the EDID's manufacturer ID field
2949 //     * expand, if possible, the PNP ID using the PNPVendorIds[] table
2950 // * get the product name from the descriptor block(s)
2951 // * prepend the vendor name and the product name, unless the product
2952 //   name already contains the vendor name
2953 // * if any characters in the string are outside the printable ASCII
2954 //   range, replace them with '?'
2955 
2956 #define tolower(c)      (((c) >= 'A' && (c) <= 'Z') ? (c) + ('a'-'A') : (c))
2957 
2958 CODE_SEGMENT(PAGE_DD_CODE)
2959 void NvTiming_GetMonitorName(NVT_EDID_INFO *pEdidInfo,
2960                              NvU8 monitor_name[NVT_EDID_MONITOR_NAME_STRING_LENGTH])
2961 {
2962     NvU8 product_name[NVT_EDID_MONITOR_NAME_STRING_LENGTH];
2963     const NvU8 *vendor_name;
2964     NVT_STATUS status;
2965     NvU32 i, j;
2966     NvBool prepend_vendor;
2967 
2968     NVMISC_MEMSET(monitor_name, 0, NVT_EDID_MONITOR_NAME_STRING_LENGTH);
2969 
2970     // get vendor_name: it is either the manufacturer ID or the PNP vendor name
2971     vendor_name = pEdidInfo->manuf_name;
2972 
2973     for (i = 0; i < (sizeof(PNPVendorIds)/sizeof(PNPVendorIds[0])); i++)
2974     {
2975         if ((vendor_name[0] == PNPVendorIds[i].vendorId[0]) &&
2976             (vendor_name[1] == PNPVendorIds[i].vendorId[1]) &&
2977             (vendor_name[2] == PNPVendorIds[i].vendorId[2]))
2978         {
2979             vendor_name = (const NvU8 *) PNPVendorIds[i].vendorName;
2980             break;
2981         }
2982     }
2983 
2984     // get the product name from the descriptor blocks
2985     status = NvTiming_GetProductName(pEdidInfo, product_name, sizeof(product_name));
2986 
2987     if (status != NVT_STATUS_SUCCESS)
2988     {
2989         product_name[0] = '\0';
2990     }
2991 
2992     // determine if the product name already includes the vendor name;
2993     // if so, do not prepend the vendor name to the monitor name
2994     prepend_vendor = NV_TRUE;
2995 
2996     for (i = 0; i < NVT_EDID_MONITOR_NAME_STRING_LENGTH; i++)
2997     {
2998         if (vendor_name[i] == '\0')
2999         {
3000             prepend_vendor = NV_FALSE;
3001             break;
3002         }
3003 
3004         if (tolower(product_name[i]) != tolower(vendor_name[i]))
3005         {
3006             break;
3007         }
3008     }
3009 
3010     j = 0;
3011 
3012     // prepend the vendor name to the monitor name
3013     if (prepend_vendor)
3014     {
3015         for (i = 0; (i < NVT_EDID_MONITOR_NAME_STRING_LENGTH) && (vendor_name[i] != '\0'); i++)
3016         {
3017             monitor_name[j++] = vendor_name[i];
3018         }
3019     }
3020 
3021     // if we added the vendor name above, add a space between the
3022     // vendor name and the product name
3023     if ((j > 0) && (j < (NVT_EDID_MONITOR_NAME_STRING_LENGTH - 1)))
3024     {
3025         monitor_name[j++] = ' ';
3026     }
3027 
3028     // append the product name to the monitor string
3029     for (i = 0; (i < NVT_EDID_MONITOR_NAME_STRING_LENGTH) && (product_name[i] != '\0'); i++)
3030     {
3031         if (j >= (NVT_EDID_MONITOR_NAME_STRING_LENGTH - 1))
3032         {
3033             break;
3034         }
3035         monitor_name[j++] = product_name[i];
3036     }
3037     monitor_name[j] = '\0';
3038 
3039     RemoveTrailingWhiteSpace(monitor_name, j);
3040     RemoveNonPrintableCharacters(monitor_name);
3041 }
3042 
3043 CODE_SEGMENT(PAGE_DD_CODE)
3044 void updateHDMILLCDeepColorForTiming(NVT_EDID_INFO *pInfo, NvU32 index)
3045 {
3046     NVT_EDID_CEA861_INFO *p861Info = &pInfo->ext861;
3047     // NOTE: EDID and CEA861 does not have clear statement regarding this.
3048     // To be backward compatible with current Nvidia implementation, if not edid >= 1.4 and CEA block exists, follow color format declaration from CEA block.
3049     // update supported color space within each bpc
3050     // rgb 8bpc always supported
3051 
3052     UPDATE_BPC_FOR_COLORFORMAT(pInfo->timing[index].etc.rgb444, 0, 1,
3053                                pInfo->hdmiLlcInfo.dc_30_bit,
3054                                pInfo->hdmiLlcInfo.dc_36_bit,
3055                                0, pInfo->hdmiLlcInfo.dc_48_bit);
3056 
3057     if (p861Info->basic_caps & NVT_CEA861_CAP_YCbCr_444)
3058     {
3059         // pHdmiLlc->dc_y444 assumed basic cap is set; when base cap is set, 8bpc yuv444 always supported
3060         UPDATE_BPC_FOR_COLORFORMAT(pInfo->timing[index].etc.yuv444, 0, 1,
3061                                    pInfo->hdmiLlcInfo.dc_y444 && pInfo->hdmiLlcInfo.dc_30_bit,
3062                                    pInfo->hdmiLlcInfo.dc_y444 && pInfo->hdmiLlcInfo.dc_36_bit,
3063                                    0, pInfo->hdmiLlcInfo.dc_y444 && pInfo->hdmiLlcInfo.dc_48_bit);
3064     }
3065     if (p861Info->basic_caps & NVT_CEA861_CAP_YCbCr_422)
3066     {
3067         // pHdmiLlc->dc_y444 assumed basic cap is set; when base cap is set, 8bpc yuv422 always supported
3068         // newer CEA861/HDMI specs suggest the base cap should support both or neither (Nvidia puts no limitations here)
3069         // 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
3070         UPDATE_BPC_FOR_COLORFORMAT(pInfo->timing[index].etc.yuv422, 0, 1, 1, 1, 0, 0);
3071     }
3072 }
3073 
3074 POP_SEGMENTS
3075