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