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