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