1 /* 2 * SPDX-FileCopyrightText: Copyright (c) 2005-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 * SPDX-License-Identifier: MIT 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a 6 * copy of this software and associated documentation files (the "Software"), 7 * to deal in the Software without restriction, including without limitation 8 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 * and/or sell copies of the Software, and to permit persons to whom the 10 * Software is furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice shall be included in 13 * all copies or substantial portions of the Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 * DEALINGS IN THE SOFTWARE. 22 */ 23 24 #include "dp/nvdp-device.h" 25 #include "dp/nvdp-connector-event-sink.h" 26 27 #include "nvkms-evo.h" 28 #include "nvkms-dpy.h" 29 #include "nvkms-dpy-override.h" 30 #include "nvkms-hdmi.h" 31 #include "nvkms-rm.h" 32 #include "nvkms-rmapi.h" 33 #include "nvkms-types.h" 34 #include "nvkms-attributes.h" 35 #include "nvkms-utils.h" 36 #include "nvkms-3dvision.h" 37 38 #include "nv_mode_timings_utils.h" 39 40 #include "nvkms-api.h" 41 #include "nvkms-private.h" 42 43 #include "nvos.h" 44 #include "timing/dpsdp.h" 45 46 #include "displayport/displayport.h" 47 48 #include <ctrl/ctrl0073/ctrl0073dfp.h> // NV0073_CTRL_DFP_FLAGS_* 49 #include <ctrl/ctrl0073/ctrl0073dp.h> // NV0073_CTRL_CMD_DP_GET_LINK_CONFIG_* 50 51 #define TMDS_SINGLE_LINK_PCLK_MAX 165000 52 #define TMDS_DUAL_LINK_PCLK_MAX 330000 53 54 static void DpyGetDynamicDfpProperties( 55 NVDpyEvoPtr pDpyEvo, 56 const NvBool disableACPIBrightnessHotkeys); 57 58 static void 59 CreateParsedEdidFromNVT_TIMING(NVT_TIMING *pTimings, 60 NvU8 bpc, 61 NVParsedEdidEvoPtr pParsedEdid); 62 63 static NvBool ReadEdidFromDP (const NVDpyEvoRec *pDpyEvo, 64 NVEdidPtr pEdid); 65 static NvBool ReadEdidFromResman (const NVDpyEvoRec *pDpyEvo, 66 NVEdidPtr pEdid, 67 NvKmsEdidReadMode readMode); 68 static NvBool ValidateEdid (const NVDpyEvoRec *pDpyEvo, 69 NVEdidPtr pEdid, 70 NVEvoInfoStringPtr pInfoString, 71 const NvBool ignoreEdidChecksum); 72 static void LogEdid (NVDpyEvoPtr pDpyEvo, 73 NVEvoInfoStringPtr pInfoString); 74 static void ClearEdid (NVDpyEvoPtr pDpyEvo); 75 static void ClearCustomEdid (const NVDpyEvoRec *pDpyEvo); 76 static void WriteEdidToResman (const NVDpyEvoRec *pDpyEvo, 77 const NVEdidRec *pEdid); 78 static void PatchAndParseEdid (const NVDpyEvoRec *pDpyEvo, 79 NVEdidPtr pEdid, 80 NVParsedEdidEvoPtr, 81 NVEvoInfoStringPtr pInfoString); 82 static void ReadAndApplyEdidEvo (NVDpyEvoPtr pDpyEvo, 83 struct NvKmsQueryDpyDynamicDataParams *pParams); 84 static NvBool GetFixedModeTimings (NVDpyEvoPtr pDpyEvo, struct NvKmsSuperframeInfo *pSuperframeInfo); 85 static NvBool ReadDSITimingsFromResman (const NVDpyEvoRec *pDpyEvo, 86 NVT_TIMING *pTimings, 87 NvU8 *pBpc); 88 static void AssignDpyEvoName (NVDpyEvoPtr pDpyEvo); 89 90 static NvBool IsConnectorTMDS (NVConnectorEvoPtr); 91 92 93 static void DpyDisconnectEvo(NVDpyEvoPtr pDpyEvo) 94 { 95 NVDispEvoPtr pDispEvo = pDpyEvo->pDispEvo; 96 97 pDispEvo->connectedDisplays = 98 nvDpyIdListMinusDpyId(pDispEvo->connectedDisplays, pDpyEvo->id); 99 100 ClearEdid(pDpyEvo); 101 } 102 103 static NvBool DpyConnectEvo( 104 NVDpyEvoPtr pDpyEvo, 105 struct NvKmsQueryDpyDynamicDataParams *pParams) 106 { 107 NVDispEvoPtr pDispEvo = pDpyEvo->pDispEvo; 108 109 pDispEvo->connectedDisplays = 110 nvAddDpyIdToDpyIdList(pDpyEvo->id, pDispEvo->connectedDisplays); 111 112 DpyGetDynamicDfpProperties(pDpyEvo, pParams->request.disableACPIBrightnessHotkeys); 113 nvDPGetDpyGUID(pDpyEvo); 114 115 if ((pDpyEvo->pConnectorEvo->signalFormat == NVKMS_CONNECTOR_SIGNAL_FORMAT_DSI) || 116 nvConnectorIsDPSerializer(pDpyEvo->pConnectorEvo)) { 117 if (!GetFixedModeTimings(pDpyEvo, &pParams->reply.superframeInfo)) { 118 return FALSE; 119 } 120 } else { 121 ReadAndApplyEdidEvo(pDpyEvo, pParams); 122 } 123 124 nvUpdateInfoFrames(pDpyEvo); 125 126 return TRUE; 127 } 128 129 /* 130 * DpyAssignColorSpaceCaps() - parse both the CEA-861 extension block and 131 * the EDID 1.4 block to determine YCbCr422/444 capability. 132 */ 133 static void DpyAssignColorSpaceCaps(NVDpyEvoPtr pDpyEvo, 134 NVEvoInfoStringPtr pInfoString) 135 { 136 NvBool ycbr422_cap = FALSE; 137 NvBool ycbr444_cap = FALSE; 138 const NVParsedEdidEvoRec *pParsedEdid = &pDpyEvo->parsedEdid; 139 140 /* check for edid YCbCr422/YCbCr444 capability */ 141 if (pParsedEdid->valid) { 142 NvBool haveCEA861Block = 143 (pParsedEdid->info.ext861.revision != NVT_CEA861_REV_NONE); 144 if (haveCEA861Block) { 145 ycbr422_cap = !!(pParsedEdid->info.ext861.basic_caps & 146 NVT_CEA861_CAP_YCbCr_422); 147 ycbr444_cap = !!(pParsedEdid->info.ext861.basic_caps & 148 NVT_CEA861_CAP_YCbCr_444); 149 } 150 /* check EDID 1.4 base block */ 151 if (pParsedEdid->info.version == 0x104 && 152 pParsedEdid->info.input.isDigital) { 153 NvBool edid14_ycbr422 = 154 pParsedEdid->info.u.feature_ver_1_4_digital.support_ycrcb_422; 155 NvBool edid14_ycbr444 = 156 pParsedEdid->info.u.feature_ver_1_4_digital.support_ycrcb_444; 157 if (haveCEA861Block && ycbr422_cap != edid14_ycbr422) { 158 nvEvoLogInfoString(pInfoString, 159 "%s EDID inconsistency: the EDID 1.4 base block %s " 160 "YCbCr 4:2:2 support, but the CEA-861 extension block " 161 "%s. Assuming YCbCr 4:2:2 is supported.", 162 pDpyEvo->name, 163 edid14_ycbr422 ? "indicates" : "does not indicate", 164 ycbr422_cap ? "does" : "does not"); 165 } 166 if (edid14_ycbr422) { 167 ycbr422_cap = TRUE; 168 } 169 if (haveCEA861Block && ycbr444_cap != edid14_ycbr444) { 170 nvEvoLogInfoString(pInfoString, 171 "%s EDID inconsistency: the EDID 1.4 base block %s " 172 "YCbCr 4:4:4 support, but the CEA-861 extension block " 173 "%s. Assuming YCbCr 4:4:4 is supported.", 174 pDpyEvo->name, 175 edid14_ycbr444 ? "indicates" : "does not indicate", 176 ycbr444_cap ? "does" : "does not"); 177 } 178 if (edid14_ycbr444) { 179 ycbr444_cap = TRUE; 180 } 181 } 182 } 183 pDpyEvo->colorSpaceCaps.ycbcr422Capable = ycbr422_cap; 184 pDpyEvo->colorSpaceCaps.ycbcr444Capable = ycbr444_cap; 185 } 186 187 188 189 static NvBool GetEdidOverride( 190 const struct NvKmsQueryDpyDynamicDataRequest *pRequest, 191 NVEdidRec *pEdid) 192 { 193 if ((pRequest == NULL) || 194 !pRequest->overrideEdid || 195 (pRequest->edid.bufferSize == 0) || 196 (pRequest->edid.bufferSize > sizeof(pRequest->edid.buffer))) { 197 return FALSE; 198 } 199 200 pEdid->buffer = nvAlloc(pRequest->edid.bufferSize); 201 202 if (pEdid->buffer == NULL) { 203 return FALSE; 204 } 205 206 nvkms_memcpy(pEdid->buffer, pRequest->edid.buffer, pRequest->edid.bufferSize); 207 208 pEdid->length = pRequest->edid.bufferSize; 209 210 return TRUE; 211 } 212 213 /*! 214 * Query resman for the EDID for the pDpyEvo, then parse the EDID into usable 215 * data. Do not modify the pDpyEvoRec. 216 */ 217 218 NvBool nvDpyReadAndParseEdidEvo( 219 const NVDpyEvoRec *pDpyEvo, 220 const struct NvKmsQueryDpyDynamicDataRequest *pRequest, 221 NvKmsEdidReadMode readMode, 222 NVEdidRec *pEdid, 223 NVParsedEdidEvoPtr *ppParsedEdid, 224 NVEvoInfoStringPtr pInfoString) 225 { 226 NvBool ignoreEdid = FALSE; 227 NvBool ignoreEdidChecksum = FALSE; 228 229 if (pRequest != NULL) { 230 ignoreEdid = pRequest->ignoreEdid; 231 ignoreEdidChecksum = pRequest->ignoreEdidChecksum; 232 } 233 234 nvkms_memset(pEdid, 0, sizeof(*pEdid)); 235 236 /* Just return an empty EDID if requested. */ 237 if (ignoreEdid) { 238 return TRUE; 239 } 240 241 /* Load any custom EDID, (or see if DP lib has EDID) */ 242 ClearCustomEdid(pDpyEvo); 243 244 if ((pRequest && GetEdidOverride(pRequest, pEdid)) || 245 ReadEdidFromDP(pDpyEvo, pEdid)) { 246 /* XXX [VSM] Write, clear and re-read the EDID to/from RM here to make 247 * sure RM and X agree on the final EDID bits. Once RM no longer 248 * parses the EDID, we can avoid doing this for DP devices. 249 * 250 * If it's a DisplayPort 1.2 multistream device then don't bother trying 251 * to ping-pong the EDID through RM. 252 */ 253 if (nvDpyEvoIsDPMST(pDpyEvo)) { 254 goto validateEdid; 255 } 256 257 WriteEdidToResman(pDpyEvo, pEdid); 258 259 nvFree(pEdid->buffer); 260 pEdid->buffer = NULL; 261 pEdid->length = 0; 262 } 263 264 if (!ReadEdidFromResman(pDpyEvo, pEdid, readMode)) { 265 goto fail; 266 } 267 268 validateEdid: 269 /* Validate the EDID */ 270 if (!ValidateEdid(pDpyEvo, pEdid, pInfoString, ignoreEdidChecksum)) { 271 goto fail; 272 } 273 274 *ppParsedEdid = nvCalloc(1, sizeof(**ppParsedEdid)); 275 if (*ppParsedEdid == NULL) { 276 goto fail; 277 } 278 /* Parse the EDID. Note this may *change* the EDID bytes. */ 279 PatchAndParseEdid(pDpyEvo, pEdid, *ppParsedEdid, pInfoString); 280 281 return TRUE; 282 283 fail: 284 285 /* We failed to read a valid EDID. Free any EDID buffer allocated above. */ 286 nvFree(pEdid->buffer); 287 pEdid->buffer = NULL; 288 pEdid->length = 0; 289 290 return FALSE; 291 } 292 293 static void AssignIsVrHmd(NVDpyEvoRec *pDpyEvo) 294 { 295 NV0073_CTRL_SPECIFIC_IS_DIRECTMODE_DISPLAY_PARAMS params = { }; 296 NVDispEvoPtr pDispEvo = pDpyEvo->pDispEvo; 297 NVDevEvoPtr pDevEvo = pDispEvo->pDevEvo; 298 NvU32 ret; 299 300 pDpyEvo->isVrHmd = FALSE; 301 302 if (!pDpyEvo->parsedEdid.valid) { 303 return; 304 } 305 306 params.manufacturerID = pDpyEvo->parsedEdid.info.manuf_id; 307 params.productID = pDpyEvo->parsedEdid.info.product_id; 308 309 ret = nvRmApiControl(nvEvoGlobal.clientHandle, 310 pDevEvo->displayCommonHandle, 311 NV0073_CTRL_CMD_SPECIFIC_IS_DIRECTMODE_DISPLAY, 312 ¶ms, sizeof(params)); 313 314 if (ret != NVOS_STATUS_SUCCESS) { 315 nvEvoLogDisp(pDispEvo, EVO_LOG_ERROR, 316 "Failed to query VR headset for %s", pDpyEvo->name); 317 return; 318 } 319 320 /* 321 * bIsDirectmode indicates any monitor that by default shouldn't be part of 322 * a desktop (VR headset, touch panel, etc). But, close enough for our 323 * usage of isVrHmd. 324 */ 325 pDpyEvo->isVrHmd = params.bIsDirectmode; 326 } 327 328 static NvBool EdidHasChanged( 329 const NVDpyEvoRec *pDpyEvo, 330 const NVEdidRec *pEdid, 331 const NVParsedEdidEvoRec *pParsedEdid) 332 { 333 /* Compare EDID bytes */ 334 if (pEdid->length != pDpyEvo->edid.length || 335 nvkms_memcmp(pEdid->buffer, pDpyEvo->edid.buffer, pEdid->length) != 0) { 336 return TRUE; 337 } 338 339 /* Compare parsed data */ 340 if (pParsedEdid != NULL) { 341 if (nvkms_memcmp(pParsedEdid, &pDpyEvo->parsedEdid, 342 sizeof(*pParsedEdid)) != 0) { 343 return TRUE; 344 } 345 } else if (pDpyEvo->parsedEdid.valid) { 346 return TRUE; 347 } 348 349 return FALSE; 350 } 351 352 static void ApplyNewEdid( 353 NVDpyEvoPtr pDpyEvo, 354 const NVEdidRec *pEdid, 355 const NVParsedEdidEvoRec *pParsedEdid, 356 NVEvoInfoStringPtr pInfoString) 357 { 358 if (pDpyEvo->edid.buffer != NULL) { 359 nvFree(pDpyEvo->edid.buffer); 360 } 361 pDpyEvo->edid.buffer = pEdid->buffer; 362 pDpyEvo->edid.length = pEdid->length; 363 364 if (pParsedEdid != NULL) { 365 nvkms_memcpy(&pDpyEvo->parsedEdid, pParsedEdid, 366 sizeof(pDpyEvo->parsedEdid)); 367 } else { 368 nvkms_memset(&pDpyEvo->parsedEdid, 0, sizeof(pDpyEvo->parsedEdid)); 369 } 370 371 /* 372 * Regenerate the dpy's name, because the parsed EDID monitorName 373 * may have changed. 374 */ 375 AssignDpyEvoName(pDpyEvo); 376 377 /* Write information about the parsed EDID to the infoString. */ 378 LogEdid(pDpyEvo, pInfoString); 379 380 if (pDpyEvo->parsedEdid.valid) { 381 /* 382 * check 3D Vision capability 383 */ 384 nvDpyCheck3DVisionCapsEvo(pDpyEvo); 385 386 /* 387 * Check HDMI VRR capability 388 */ 389 nvDpyUpdateHdmiVRRCaps(pDpyEvo); 390 } 391 392 if (pDpyEvo->pConnectorEvo->legacyType == 393 NV0073_CTRL_SPECIFIC_DISPLAY_TYPE_DFP) { 394 DpyAssignColorSpaceCaps(pDpyEvo, pInfoString); 395 } 396 397 nvUpdateHdmiCaps(pDpyEvo); 398 399 nvDpyProbeMaxPixelClock(pDpyEvo); 400 401 AssignIsVrHmd(pDpyEvo); 402 } 403 404 /* 405 * ReadDSITimingsFromResman() - Obtains modetimings for a DSI connector, 406 * passing it into pTimings 407 */ 408 static NvBool ReadDSITimingsFromResman( 409 const NVDpyEvoRec *pDpyEvo, 410 NVT_TIMING *pTimings, 411 NvU8 *pBpc) 412 { 413 NvU32 ret; 414 NV0073_CTRL_CMD_DFP_GET_DSI_MODE_TIMING_PARAMS dsiModeTimingParams = { 0 }; 415 416 NVDispEvoPtr pDispEvo = pDpyEvo->pDispEvo; 417 NVDevEvoPtr pDevEvo = pDispEvo->pDevEvo; 418 dsiModeTimingParams.subDeviceInstance = pDispEvo->displayOwner; 419 420 /* 421 * Currently displayId must be hardcoded to 0 to receive timings from RM. 422 * Once the corresponding DCB support is added for DSI, this hack will be 423 * removed and NVKMS will use the actual displayId instead. 424 */ 425 dsiModeTimingParams.displayId = 0; 426 427 ret = nvRmApiControl(nvEvoGlobal.clientHandle, 428 pDevEvo->displayCommonHandle, 429 NV0073_CTRL_CMD_DFP_GET_DSI_MODE_TIMING, 430 &dsiModeTimingParams, sizeof(dsiModeTimingParams)); 431 432 if (ret != NVOS_STATUS_SUCCESS) { 433 nvEvoLogDisp(pDispEvo, EVO_LOG_WARN, 434 "Unable to read DSI mode timings for display device %s", 435 pDpyEvo->name); 436 return FALSE; 437 } 438 439 // Converts refresh (Hz) into appropriate units for rr1k (units of 0.001Hz) 440 pTimings->etc.rrx1k = dsiModeTimingParams.refresh * 1000; 441 pTimings->HVisible = dsiModeTimingParams.hActive; 442 pTimings->HFrontPorch = dsiModeTimingParams.hFrontPorch; 443 pTimings->HSyncWidth = dsiModeTimingParams.hSyncWidth; 444 pTimings->HTotal = dsiModeTimingParams.hActive + 445 dsiModeTimingParams.hFrontPorch + 446 dsiModeTimingParams.hSyncWidth + 447 dsiModeTimingParams.hBackPorch; 448 449 pTimings->VVisible = dsiModeTimingParams.vActive; 450 pTimings->VFrontPorch = dsiModeTimingParams.vFrontPorch; 451 pTimings->VSyncWidth = dsiModeTimingParams.vSyncWidth; 452 pTimings->VTotal = dsiModeTimingParams.vActive + 453 dsiModeTimingParams.vFrontPorch + 454 dsiModeTimingParams.vSyncWidth + 455 dsiModeTimingParams.vBackPorch; 456 457 pTimings->pclk = HzToKHz(dsiModeTimingParams.pclkHz) / 10; 458 459 // DSI only supports RGB444 460 *pBpc = dsiModeTimingParams.bpp / 3; 461 462 return TRUE; 463 } 464 465 static NvBool ParseSuperframeInfo( 466 NVDpyEvoRec *pDpyEvo, 467 const NV0073_CTRL_DFP_GET_FIXED_MODE_TIMING_PARAMS *pParams, 468 struct NvKmsSuperframeInfo *pSuperframeInfo) 469 { 470 NvU8 i; 471 472 if (pParams->superframeInfo.numViews == 0) { 473 return TRUE; 474 } 475 476 // Currently, we support only dual view superframe. 477 if (pParams->superframeInfo.numViews != 2) { 478 nvEvoLog(EVO_LOG_ERROR, "Invalid number of superframe views"); 479 return FALSE; 480 } 481 482 // Currently, we support only packed symmetrical side-by-side superframe. 483 if ((pParams->superframeInfo.view[0].width * pParams->superframeInfo.numViews) != 484 pParams->hActive) { 485 nvEvoLog(EVO_LOG_ERROR, "The width of Superframe view[0] is invalid"); 486 return FALSE; 487 } 488 489 if (pParams->superframeInfo.view[0].height != pParams->vActive) { 490 nvEvoLog(EVO_LOG_ERROR, "The height of Superframe view[0] is invalid"); 491 return FALSE; 492 } 493 494 pSuperframeInfo->numViews = 0; 495 496 for (i = 0; i < pParams->superframeInfo.numViews; i++) { 497 // All superframe views must not have horizontal spacing in between them. 498 if ((pParams->superframeInfo.view[0].width * i) != 499 pParams->superframeInfo.view[i].x) { 500 nvEvoLog(EVO_LOG_ERROR, "The x offset of Superframe view[%u] is invalid", i); 501 goto fail; 502 } 503 504 // All superframe views must have y offset as 0. 505 if (pParams->superframeInfo.view[i].y != 0) { 506 nvEvoLog(EVO_LOG_ERROR, "The y offset of Superframe view[%u] is invalid", i); 507 goto fail; 508 } 509 510 // All superframe views must have the same width. 511 if (pParams->superframeInfo.view[0].width != 512 pParams->superframeInfo.view[i].width) { 513 nvEvoLog(EVO_LOG_ERROR, "The width of Superframe view[%u] is invalid", i); 514 goto fail; 515 } 516 517 // All superframe views must have the same height. 518 if (pParams->superframeInfo.view[0].height != 519 pParams->superframeInfo.view[i].height) { 520 nvEvoLog(EVO_LOG_ERROR, "The height of Superframe view[%u] is invalid", i); 521 goto fail; 522 } 523 524 pSuperframeInfo->view[i].x = pParams->superframeInfo.view[i].x; 525 pSuperframeInfo->view[i].width = pParams->superframeInfo.view[i].width; 526 pSuperframeInfo->view[i].y = pParams->superframeInfo.view[i].y; 527 pSuperframeInfo->view[i].height = pParams->superframeInfo.view[i].height; 528 pSuperframeInfo->numViews++; 529 } 530 531 return TRUE; 532 533 fail: 534 nvkms_memset(pSuperframeInfo, 0, sizeof(*pSuperframeInfo)); 535 return FALSE; 536 } 537 538 static NvBool ReadDPSerializerTimings( 539 NVDpyEvoRec *pDpyEvo, 540 NVT_TIMING *pTimings, 541 NvU8 *pBpc, 542 struct NvKmsSuperframeInfo *pSuperframeInfo) 543 { 544 NV0073_CTRL_DFP_GET_FIXED_MODE_TIMING_PARAMS timingParams = { }; 545 NVDispEvoPtr pDispEvo = pDpyEvo->pDispEvo; 546 NVDevEvoPtr pDevEvo = pDispEvo->pDevEvo; 547 NvU32 ret; 548 549 timingParams.subDeviceInstance = pDispEvo->displayOwner; 550 timingParams.displayId = nvDpyIdToNvU32(pDpyEvo->pConnectorEvo->displayId); 551 timingParams.stream = pDpyEvo->dp.serializerStreamIndex; 552 553 ret = nvRmApiControl(nvEvoGlobal.clientHandle, 554 pDevEvo->displayCommonHandle, 555 NV0073_CTRL_CMD_DFP_GET_FIXED_MODE_TIMING, 556 &timingParams, sizeof(timingParams)); 557 if (ret != NVOS_STATUS_SUCCESS) { 558 nvEvoLogDisp(pDispEvo, EVO_LOG_WARN, 559 "Unable to read fixed mode timings for display device %s", 560 pDpyEvo->name); 561 return FALSE; 562 } 563 564 if (!timingParams.valid) { 565 nvEvoLogDisp(pDispEvo, EVO_LOG_WARN, 566 "Fixed mode timings are invalid for display device %s", 567 pDpyEvo->name); 568 return FALSE; 569 } 570 571 if (!ParseSuperframeInfo(pDpyEvo, &timingParams, pSuperframeInfo)) { 572 return FALSE; 573 } 574 575 nvkms_memset(pTimings, 0, sizeof(NVT_TIMING)); 576 577 pTimings->HVisible = timingParams.hActive; 578 pTimings->HFrontPorch = timingParams.hFrontPorch; 579 pTimings->HSyncWidth = timingParams.hSyncWidth; 580 pTimings->HTotal = timingParams.hActive + timingParams.hFrontPorch + 581 timingParams.hSyncWidth + timingParams.hBackPorch; 582 583 pTimings->VVisible = timingParams.vActive; 584 pTimings->VFrontPorch = timingParams.vFrontPorch; 585 pTimings->VSyncWidth = timingParams.vSyncWidth; 586 pTimings->VTotal = timingParams.vActive + timingParams.vFrontPorch + 587 timingParams.vSyncWidth + timingParams.vBackPorch; 588 589 pTimings->pclk = timingParams.pclkKHz / 10; 590 pTimings->etc.rrx1k = timingParams.rrx1k; 591 592 *pBpc = 0; 593 594 return TRUE; 595 } 596 597 static NvBool GetFixedModeTimings( 598 NVDpyEvoPtr pDpyEvo, 599 struct NvKmsSuperframeInfo *pSuperframeInfo) 600 { 601 NVT_TIMING timings = { }; 602 NvBool ret = FALSE; 603 NvU8 bpc; 604 605 if (pDpyEvo->pConnectorEvo->signalFormat == NVKMS_CONNECTOR_SIGNAL_FORMAT_DSI) { 606 ret = ReadDSITimingsFromResman(pDpyEvo, &timings, &bpc); 607 } else if (nvConnectorIsDPSerializer(pDpyEvo->pConnectorEvo)) { 608 ret = ReadDPSerializerTimings(pDpyEvo, &timings, &bpc, 609 pSuperframeInfo); 610 } 611 612 if (!ret) { 613 return ret; 614 } 615 616 CreateParsedEdidFromNVT_TIMING(&timings, bpc, &pDpyEvo->parsedEdid); 617 618 AssignDpyEvoName(pDpyEvo); 619 nvDpyProbeMaxPixelClock(pDpyEvo); 620 621 return TRUE; 622 } 623 624 static void ReadAndApplyEdidEvo( 625 NVDpyEvoPtr pDpyEvo, 626 struct NvKmsQueryDpyDynamicDataParams *pParams) 627 { 628 const struct NvKmsQueryDpyDynamicDataRequest *pRequest = NULL; 629 NVEdidRec edid = {NULL, 0}; 630 NVParsedEdidEvoPtr pParsedEdid = NULL; 631 NVEvoInfoStringRec infoString; 632 NvBool readSuccess; 633 634 if (pParams != NULL) { 635 nvInitInfoString(&infoString, pParams->reply.edid.infoString, 636 sizeof(pParams->reply.edid.infoString)); 637 pRequest = &pParams->request; 638 } else { 639 nvInitInfoString(&infoString, NULL, 0); 640 } 641 642 readSuccess = nvDpyReadAndParseEdidEvo(pDpyEvo, pRequest, 643 NVKMS_EDID_READ_MODE_DEFAULT, 644 &edid, &pParsedEdid, &infoString); 645 646 if (pParams != NULL) { 647 pParams->reply.edid.valid = readSuccess; 648 } 649 650 if (EdidHasChanged(pDpyEvo, &edid, pParsedEdid)) { 651 /* 652 * Do not plumb pRequest into ApplyNewEdid(). This helps ensure that 653 * its operation is purely a function of the EDID and parsed EDID data, 654 * which means that if we get into this function again with the same 655 * EDID and parsed EDID data, we can safely skip ApplyNewEdid() without 656 * worrying that this request has different parameters (like CustomEdid 657 * or mode validation overrides). 658 */ 659 ApplyNewEdid(pDpyEvo, &edid, pParsedEdid, &infoString); 660 } else { 661 nvFree(edid.buffer); 662 } 663 nvFree(pParsedEdid); 664 } 665 666 667 /*! 668 * Get the maximum allowed pixel clock for pDpyEvo. 669 * 670 * This depends on the following conditions: 671 * 672 * - The RM's returned value is sufficient for non-TMDS connectors 673 * - For HDMI, the SOR capabilities exceed the RM's returned value to allow 674 * for HDMI 1.4 modes that exceed 165MHz on a single link, or 675 * for HDMI 2.1 modes if the source and sink is capable of FRL 676 * - For DVI, the user is allowed to set an option to exceed the 165MHz 677 * per-TMDS limit if the SOR capabilities allow it 678 * - Contrary to the above, passive DP->DVI and DP->HDMI dongles have their 679 * own limits 680 */ 681 void nvDpyProbeMaxPixelClock(NVDpyEvoPtr pDpyEvo) 682 { 683 NvU32 ret; 684 NVDispEvoPtr pDispEvo = pDpyEvo->pDispEvo; 685 NVDevEvoPtr pDevEvo = pDispEvo->pDevEvo; 686 NVConnectorEvoPtr pConnectorEvo = pDpyEvo->pConnectorEvo; 687 NvU32 displayOwner = pDispEvo->displayOwner; 688 NVEvoPassiveDpDongleType passiveDpDongleType; 689 NV0073_CTRL_SPECIFIC_GET_PCLK_LIMIT_PARAMS params = { 0 }; 690 NvU32 passiveDpDongleMaxPclkKHz; 691 692 /* First, get the RM-reported value. */ 693 694 params.displayId = nvDpyIdToNvU32(pDpyEvo->pConnectorEvo->displayId); 695 params.subDeviceInstance = pDispEvo->displayOwner; 696 697 ret = nvRmApiControl(nvEvoGlobal.clientHandle, 698 pDevEvo->displayCommonHandle, 699 NV0073_CTRL_CMD_SPECIFIC_GET_PCLK_LIMIT, 700 ¶ms, sizeof(params)); 701 702 if (ret != NVOS_STATUS_SUCCESS) { 703 nvEvoLogDisp(pDispEvo, EVO_LOG_ERROR, 704 "Failure reading maximum pixel clock value " 705 "for display device %s.", pDpyEvo->name); 706 pDpyEvo->maxPixelClockKHz = 100000; 707 pDpyEvo->maxSingleLinkPixelClockKHz = pDpyEvo->maxPixelClockKHz; 708 return; 709 } 710 711 pDpyEvo->maxPixelClockKHz = params.orPclkLimit; 712 pDpyEvo->maxSingleLinkPixelClockKHz = pDpyEvo->maxPixelClockKHz; 713 714 /* 715 * The RM's returned max pclk value is sufficient for non-TMDS 716 * connectors 717 */ 718 if (!IsConnectorTMDS(pConnectorEvo)) { 719 return; 720 } 721 722 /* 723 * The RM returns a 165MHz max pclk for single link TMDS and 330MHz 724 * max pclk for dual link TMDS. We can exceed that in the 725 * following cases: 726 * 727 * - HDMI 1.4a 4Kx2K and 1080p60hz frame packed stereo modes 728 * require a 297MHz single TMDS link pixel clock, and HDMI 2.0 729 * allows an even higher pixel clock. 730 * - While the DVI spec mandates a limit of 165MHz per TMDS link, 731 * since certain GPUs and certain displays support DVI 732 * connections at higher pixel clocks, we allow users to 733 * override this limit to allow validation of higher maximum 734 * pixel clocks over DVI. 735 */ 736 if (pDevEvo->gpus != NULL) { 737 738 NVEvoSorCaps *sorCaps = pDevEvo->gpus[displayOwner].capabilities.sor; 739 NvU32 orIndex = pConnectorEvo->or.primary; 740 741 if (NV0073_CTRL_SYSTEM_GET_CAP(pDevEvo->commonCapsBits, 742 NV0073_CTRL_SYSTEM_CAPS_CROSS_BAR_SUPPORTED)) { 743 /* 744 * With the SOR crossbar, pConnectorEvo->or.mask is unknown, 745 * and may change at modeset time. Use the caps of SOR 0 746 * for validation. 747 */ 748 orIndex = 0; 749 } 750 751 if (nvDpyIsHdmiEvo(pDpyEvo)) { 752 pDpyEvo->maxPixelClockKHz = 753 pDpyEvo->maxSingleLinkPixelClockKHz = 754 sorCaps[orIndex].maxTMDSClkKHz; 755 756 nvkms_memset(&pDpyEvo->hdmi.srcCaps, 0, sizeof(pDpyEvo->hdmi.srcCaps)); 757 nvkms_memset(&pDpyEvo->hdmi.sinkCaps, 0, sizeof(pDpyEvo->hdmi.sinkCaps)); 758 759 if (nvHdmiDpySupportsFrl(pDpyEvo)) { 760 /* 761 * An SOR needs to be assigned temporarily to do FRL training. 762 * 763 * Since the only other SORs in use at the moment (if any) are 764 * those driving heads, we don't need to exclude RM from 765 * selecting any SOR, so an sorExcludeMask of 0 is appropriate. 766 */ 767 if (nvAssignSOREvo(pDispEvo, 768 nvDpyIdToNvU32(pConnectorEvo->displayId), 769 FALSE /* b2Heads1Or */, 770 0 /* sorExcludeMask */) && 771 nvHdmiFrlAssessLink(pDpyEvo)) { 772 /* 773 * Note that although we "assessed" the link above, the 774 * maximum pixel clock set here doesn't take that into 775 * account -- it's the maximum the GPU hardware is capable 776 * of on the most capable link, mostly for reporting 777 * purposes. 778 * 779 * The calculation for if a given mode can fit in the 780 * assessed FRL configuration is complex and depends on 781 * things like the amount of blanking, rather than a simple 782 * pclk cutoff. So, we query the hdmi library when 783 * validating each individual mode, when we know actual 784 * timings. 785 */ 786 787 /* 788 * This comes from the Windows display driver: (4 lanes * 789 * 12Gb per lane * FRL encoding i.e 16/18) / 1K 790 */ 791 pDpyEvo->maxPixelClockKHz = 792 ((4 * 12 * 1000 * 1000 * 16) / 18); 793 } 794 } 795 } else { 796 /* 797 * Connector and SOR both must be capable to drive dual-TMDS 798 * resolutions. 799 */ 800 NvBool bDualTMDS = sorCaps[orIndex].dualTMDS && 801 FLD_TEST_DRF(0073, _CTRL_DFP_FLAGS, _LINK, _DUAL, 802 pDpyEvo->pConnectorEvo->dfpInfo); 803 804 pDpyEvo->maxPixelClockKHz = (bDualTMDS ? 805 TMDS_DUAL_LINK_PCLK_MAX : 806 TMDS_SINGLE_LINK_PCLK_MAX); 807 808 pDpyEvo->maxSingleLinkPixelClockKHz = TMDS_SINGLE_LINK_PCLK_MAX; 809 810 if (pDpyEvo->allowDVISpecPClkOverride) { 811 pDpyEvo->maxPixelClockKHz = sorCaps[orIndex].maxTMDSClkKHz * 812 (bDualTMDS ? 2 : 1); 813 pDpyEvo->maxSingleLinkPixelClockKHz = 814 sorCaps[orIndex].maxTMDSClkKHz; 815 } 816 } 817 } 818 819 /* 820 * Passive DP->DVI and DP->HDMI dongles may have a limit more 821 * restrictive than the one described above. Check whether one of 822 * these dongles is in use, and override the limit accordingly. 823 */ 824 passiveDpDongleType = 825 nvDpyGetPassiveDpDongleType(pDpyEvo, &passiveDpDongleMaxPclkKHz); 826 827 if (passiveDpDongleType != NV_EVO_PASSIVE_DP_DONGLE_UNUSED) { 828 pDpyEvo->maxPixelClockKHz = NV_MIN(passiveDpDongleMaxPclkKHz, 829 pDpyEvo->maxPixelClockKHz); 830 pDpyEvo->maxSingleLinkPixelClockKHz = pDpyEvo->maxPixelClockKHz; 831 } 832 } 833 834 static void DpyGetDynamicDfpProperties( 835 NVDpyEvoPtr pDpyEvo, 836 const NvBool disableACPIBrightnessHotkeys) 837 { 838 if (disableACPIBrightnessHotkeys) { 839 return; 840 } 841 if (!disableACPIBrightnessHotkeys) { 842 struct NvKmsGetDpyAttributeParams params; 843 nvkms_memset(¶ms, 0, sizeof(params)); 844 params.request.attribute = NV_KMS_DPY_ATTRIBUTE_BACKLIGHT_BRIGHTNESS; 845 846 pDpyEvo->hasBacklightBrightness = 847 nvGetDpyAttributeEvo(pDpyEvo, ¶ms); 848 } 849 } 850 /* 851 * DpyGetDfpProperties() - get DFP properties: reduced blanking flags 852 * and general DFP flags 853 */ 854 855 static void DpyGetStaticDfpProperties(NVDpyEvoPtr pDpyEvo) 856 { 857 NVConnectorEvoPtr pConnectorEvo = pDpyEvo->pConnectorEvo; 858 859 if (pConnectorEvo->legacyType != NV0073_CTRL_SPECIFIC_DISPLAY_TYPE_DFP) { 860 return; 861 } 862 863 if (nvDpyEvoIsDPMST(pDpyEvo)) { 864 // None of this stuff can be queried directly for dynamic DP MST 865 // displays. 866 // XXX DP MST: Should we fill in these fields somehow anyway? 867 return; 868 } 869 870 pDpyEvo->internal = FALSE; 871 pDpyEvo->hdmiCapable = FALSE; 872 873 if (pConnectorEvo->dfpInfo == 0x0) { 874 return; 875 } 876 /* Check if the connected DFP is HDMI capable */ 877 878 if (FLD_TEST_DRF(0073, _CTRL_DFP_FLAGS, _HDMI_CAPABLE, _TRUE, 879 pConnectorEvo->dfpInfo)) { 880 pDpyEvo->hdmiCapable = TRUE; 881 } 882 883 pDpyEvo->internal = nvConnectorIsInternal(pDpyEvo->pConnectorEvo); 884 } 885 886 /*! 887 * Return true if the connector is single or dual link TMDS (not CRT, not DP). 888 */ 889 static NvBool IsConnectorTMDS(NVConnectorEvoPtr pConnectorEvo) 890 { 891 NvU32 protocol = pConnectorEvo->or.protocol; 892 return ((pConnectorEvo->or.type == NV0073_CTRL_SPECIFIC_OR_TYPE_SOR) && 893 ((protocol == NV0073_CTRL_SPECIFIC_OR_PROTOCOL_SOR_SINGLE_TMDS_A) || 894 (protocol == NV0073_CTRL_SPECIFIC_OR_PROTOCOL_SOR_SINGLE_TMDS_B) || 895 (protocol == NV0073_CTRL_SPECIFIC_OR_PROTOCOL_SOR_DUAL_TMDS))); 896 } 897 898 /*! 899 * Query RM for the passive Displayport dongle type; this can influence 900 * the maximum pixel clock allowed on that display. 901 */ 902 NVEvoPassiveDpDongleType 903 nvDpyGetPassiveDpDongleType(const NVDpyEvoRec *pDpyEvo, 904 NvU32 *passiveDpDongleMaxPclkKHz) 905 { 906 NV0073_CTRL_DFP_GET_DISPLAYPORT_DONGLE_INFO_PARAMS params = { 0 }; 907 NvU32 ret; 908 NVConnectorEvoPtr pConnectorEvo = pDpyEvo->pConnectorEvo; 909 NVDispEvoPtr pDispEvo = pDpyEvo->pDispEvo; 910 NVDevEvoPtr pDevEvo = pDispEvo->pDevEvo; 911 912 NVEvoPassiveDpDongleType passiveDpDongleType = 913 NV_EVO_PASSIVE_DP_DONGLE_UNUSED; 914 915 // The rmcontrol below fails if we try querying the dongle info on 916 // non-TMDS connectors. 917 if (!IsConnectorTMDS(pConnectorEvo)) { 918 return passiveDpDongleType; 919 } 920 921 params.displayId = nvDpyIdToNvU32(pConnectorEvo->displayId); 922 params.subDeviceInstance = pDispEvo->displayOwner; 923 params.flags = 0; 924 925 ret = nvRmApiControl(nvEvoGlobal.clientHandle, 926 pDevEvo->displayCommonHandle, 927 NV0073_CTRL_CMD_DFP_GET_DISPLAYPORT_DONGLE_INFO, 928 ¶ms, sizeof(params)); 929 930 if (ret != NVOS_STATUS_SUCCESS) { 931 nvEvoLogDisp(pDispEvo, EVO_LOG_ERROR, 932 "Failure reading DP dongle info " 933 "for display device %s.", pDpyEvo->name); 934 return passiveDpDongleType; 935 } 936 937 if (FLD_TEST_DRF(0073_CTRL_DFP, 938 _GET_DISPLAYPORT_DONGLE_INFO_FLAGS, 939 _ATTACHED, _TRUE, params.flags)) 940 { 941 if (FLD_TEST_DRF(0073_CTRL_DFP, 942 _GET_DISPLAYPORT_DONGLE_INFO_FLAGS, _TYPE, _DP2DVI, 943 params.flags)) { 944 945 passiveDpDongleType = NV_EVO_PASSIVE_DP_DONGLE_DP2DVI; 946 947 if (passiveDpDongleMaxPclkKHz) { 948 *passiveDpDongleMaxPclkKHz = TMDS_SINGLE_LINK_PCLK_MAX; 949 } 950 } else if (FLD_TEST_DRF(0073_CTRL_DFP, 951 _GET_DISPLAYPORT_DONGLE_INFO_FLAGS, _TYPE, _DP2HDMI, 952 params.flags)) { 953 if (FLD_TEST_DRF(0073_CTRL_DFP, 954 _GET_DISPLAYPORT_DONGLE_INFO_FLAGS_DP2TMDS_DONGLE, _TYPE, _1, 955 params.flags)) { 956 957 passiveDpDongleType = NV_EVO_PASSIVE_DP_DONGLE_DP2HDMI_TYPE_1; 958 959 if (passiveDpDongleMaxPclkKHz) { 960 *passiveDpDongleMaxPclkKHz = params.maxTmdsClkRateHz / 1000; 961 } 962 } else if (FLD_TEST_DRF(0073_CTRL_DFP, 963 _GET_DISPLAYPORT_DONGLE_INFO_FLAGS_DP2TMDS_DONGLE, _TYPE, _2, 964 params.flags)) { 965 966 passiveDpDongleType = NV_EVO_PASSIVE_DP_DONGLE_DP2HDMI_TYPE_2; 967 968 if (passiveDpDongleMaxPclkKHz) { 969 *passiveDpDongleMaxPclkKHz = params.maxTmdsClkRateHz / 1000; 970 } 971 } 972 // For other dongle types: LFH_DVI (DMS59-DVI) and LFH_VGA (DMS59-VGA) breakout dongles, 973 // We consider them as native connection, hence we don't track passiveDpDongleType here 974 } 975 } 976 977 return passiveDpDongleType; 978 } 979 980 981 /*! 982 * Validate an NVKMS client-specified NvKmsModeValidationFrequencyRanges. 983 */ 984 static NvBool ValidateFrequencyRanges( 985 const struct NvKmsModeValidationFrequencyRanges *pRanges) 986 { 987 NvU32 i; 988 989 if (pRanges->numRanges >= ARRAY_LEN(pRanges->range)) { 990 return FALSE; 991 } 992 993 for (i = 0; i < pRanges->numRanges; i++) { 994 if (pRanges->range[i].high < pRanges->range[i].low) { 995 return FALSE; 996 } 997 if (pRanges->range[i].high == 0) { 998 return FALSE; 999 } 1000 } 1001 1002 return TRUE; 1003 } 1004 1005 1006 static void DpySetValidSyncsHelper( 1007 struct NvKmsModeValidationFrequencyRanges *pRanges, 1008 const NVParsedEdidEvoRec *pParsedEdid, 1009 NvBool isHorizSync, NvBool ignoreEdidSource) 1010 { 1011 NvBool found = FALSE; 1012 NvU32 edidMin = 0, edidMax = 0; 1013 1014 if (pParsedEdid->valid) { 1015 if (isHorizSync) { 1016 edidMin = pParsedEdid->limits.min_h_rate_hz; 1017 edidMax = pParsedEdid->limits.max_h_rate_hz; 1018 } else { 1019 edidMin = pParsedEdid->limits.min_v_rate_hzx1k; 1020 edidMax = pParsedEdid->limits.max_v_rate_hzx1k; 1021 } 1022 } 1023 1024 /* If the client-specified ranges are invalid, clear them. */ 1025 1026 if ((pRanges->source == 1027 NVKMS_MODE_VALIDATION_FREQUENCY_RANGE_SOURCE_CLIENT_BEFORE_EDID) || 1028 (pRanges->source == 1029 NVKMS_MODE_VALIDATION_FREQUENCY_RANGE_SOURCE_CLIENT_AFTER_EDID)) { 1030 1031 if (!ValidateFrequencyRanges(pRanges)) { 1032 nvkms_memset(pRanges, 0, sizeof(*pRanges)); 1033 pRanges->source = NVKMS_MODE_VALIDATION_FREQUENCY_RANGE_SOURCE_NONE; 1034 } 1035 } 1036 1037 /* Use CLIENT_BEFORE_EDID, if provided. */ 1038 1039 if (pRanges->source == 1040 NVKMS_MODE_VALIDATION_FREQUENCY_RANGE_SOURCE_CLIENT_BEFORE_EDID) { 1041 found = TRUE; 1042 } 1043 1044 /* 1045 * Otherwise, if EDID-reported sync ranges are available, use 1046 * those. 1047 */ 1048 if (!found && 1049 !ignoreEdidSource && 1050 (edidMin != 0) && (edidMax != 0)) { 1051 1052 pRanges->numRanges = 1; 1053 pRanges->range[0].low = edidMin; 1054 pRanges->range[0].high = edidMax; 1055 pRanges->source = NVKMS_MODE_VALIDATION_FREQUENCY_RANGE_SOURCE_EDID; 1056 found = TRUE; 1057 } 1058 1059 /* 1060 * Otherwise, use CLIENT_AFTER_EDID, if available. 1061 */ 1062 if (!found && 1063 (pRanges->source == 1064 NVKMS_MODE_VALIDATION_FREQUENCY_RANGE_SOURCE_CLIENT_AFTER_EDID)) { 1065 found = TRUE; 1066 } 1067 1068 /* 1069 * Finally, fall back to conservative defaults if we could not 1070 * find anything else; this will validate 1024x768 @ 60Hz. 1071 */ 1072 if (!found) { 1073 1074 pRanges->numRanges = 1; 1075 1076 if (isHorizSync) { 1077 pRanges->range[0].low = 28000; 1078 pRanges->range[0].high = 55000; 1079 } else { 1080 pRanges->range[0].low = 43000; 1081 pRanges->range[0].high = 72000; 1082 } 1083 1084 pRanges->source = 1085 NVKMS_MODE_VALIDATION_FREQUENCY_RANGE_SOURCE_CONSERVATIVE_DEFAULTS; 1086 } 1087 } 1088 1089 1090 /*! 1091 * Assign NvKmsModeValidationValidSyncs 1092 * 1093 * Assign the HorizSync and VertRefresh ranges in 1094 * NvKmsModeValidationValidSyncs. The priority order is: 1095 * 1096 * (1) Any HorizSync and VertRefresh provided by the client that 1097 * overrides the EDID (CLIENT_BEFORE_EDID). 1098 * (2) Valid range information from the EDID. 1099 * (3) Any HorizSync and VertRefresh specified by the client as a 1100 * fallback for the EDID (CLIENT_AFTER_EDID). 1101 * (4) Conservative builtin defaults. 1102 * 1103 * HorizSync and VertRefresh can come from different sources. (1) and 1104 * (3) are provided through pValidSyncs. (2) and (4) get written to 1105 * pValidSyncs. 1106 * 1107 * \param[in] pDpy The dpy whose EDID will be used. 1108 * \param[in,out] pValidSyncs This is initialized by the client, and 1109 * will be updated based on the frequency 1110 * range priority described above. 1111 */ 1112 void nvDpySetValidSyncsEvo(const NVDpyEvoRec *pDpyEvo, 1113 struct NvKmsModeValidationValidSyncs *pValidSyncs) 1114 { 1115 const NVParsedEdidEvoRec *pParsedEdid = &pDpyEvo->parsedEdid; 1116 1117 DpySetValidSyncsHelper(&pValidSyncs->horizSyncHz, 1118 pParsedEdid, 1119 TRUE, /* isHorizSync */ 1120 pValidSyncs->ignoreEdidSource); 1121 1122 DpySetValidSyncsHelper(&pValidSyncs->vertRefreshHz1k, 1123 pParsedEdid, 1124 FALSE, /* isHorizSync */ 1125 pValidSyncs->ignoreEdidSource); 1126 } 1127 1128 1129 /* 1130 * ReadEdidFromDP() - query the EDID for the specified display device from the 1131 * DP lib. 1132 */ 1133 1134 static NvBool ReadEdidFromDP(const NVDpyEvoRec *pDpyEvo, NVEdidPtr pEdid) 1135 { 1136 NVDispEvoPtr pDispEvo = pDpyEvo->pDispEvo; 1137 NvU8 *pNewEdid = NULL; 1138 int newEdidLength; 1139 1140 if (!nvDpyUsesDPLib(pDpyEvo)) { 1141 return FALSE; 1142 } 1143 1144 /* get size and allocate space for the EDID data */ 1145 newEdidLength = nvDPGetEDIDSize(pDpyEvo); 1146 if (newEdidLength == 0) { 1147 goto fail; 1148 } 1149 1150 pNewEdid = nvCalloc(newEdidLength, 1); 1151 1152 if (pNewEdid == NULL) { 1153 goto fail; 1154 } 1155 1156 if (!nvDPGetEDID(pDpyEvo, pNewEdid, newEdidLength)) { 1157 goto fail; 1158 } 1159 1160 pEdid->buffer = pNewEdid; 1161 pEdid->length = newEdidLength; 1162 1163 return TRUE; 1164 1165 fail: 1166 1167 nvFree(pNewEdid); 1168 1169 nvEvoLogDisp(pDispEvo, EVO_LOG_WARN, 1170 "Unable to read EDID for display device %s", 1171 pDpyEvo->name); 1172 return FALSE; 1173 1174 } // ReadEdidFromDP() 1175 1176 1177 1178 /* 1179 * ReadEdidFromResman() - query the EDID for the specified display device 1180 */ 1181 1182 static NvBool ReadEdidFromResman(const NVDpyEvoRec *pDpyEvo, NVEdidPtr pEdid, 1183 NvKmsEdidReadMode readMode) 1184 { 1185 NvU32 ret; 1186 NVDispEvoPtr pDispEvo = pDpyEvo->pDispEvo; 1187 NVDevEvoPtr pDevEvo = pDispEvo->pDevEvo; 1188 NV0073_CTRL_SPECIFIC_GET_EDID_V2_PARAMS *getEdidParams; 1189 int retryEdidReadCount = 0; 1190 NvBool success = FALSE; 1191 1192 if (nvDpyEvoIsDPMST(pDpyEvo)) { 1193 // RM doesn't track this device, so leave the EDID alone. 1194 return TRUE; 1195 } 1196 1197 getEdidParams = nvCalloc(sizeof(*getEdidParams), 1); 1198 if (getEdidParams == NULL) { 1199 goto done; 1200 } 1201 1202 query_edid: 1203 1204 getEdidParams->subDeviceInstance = pDispEvo->displayOwner; 1205 getEdidParams->displayId = nvDpyEvoGetConnectorId(pDpyEvo); 1206 getEdidParams->flags = NV0073_CTRL_SPECIFIC_GET_EDID_FLAGS_COPY_CACHE_NO; 1207 1208 if (readMode == NVKMS_EDID_READ_MODE_ACPI) { 1209 getEdidParams->flags |= DRF_DEF(0073_CTRL_SPECIFIC, _GET_EDID_FLAGS, 1210 _DISPMUX_READ_MODE, _ACPI); 1211 } 1212 1213 ret = nvRmApiControl(nvEvoGlobal.clientHandle, 1214 pDevEvo->displayCommonHandle, 1215 NV0073_CTRL_CMD_SPECIFIC_GET_EDID_V2, 1216 getEdidParams, sizeof(*getEdidParams)); 1217 1218 if ((ret != NVOS_STATUS_SUCCESS) || (getEdidParams->bufferSize <= 0)) { 1219 /* WAR for Bug 777646: retry reading the EDID on error for DP 1220 * devices to avoid possible TDR assertion in the RM. 1221 * 1222 * XXX This should be moved to the DP library. 1223 */ 1224 if (nvConnectorUsesDPLib(pDpyEvo->pConnectorEvo) && 1225 (retryEdidReadCount < NV_DP_READ_EDID_RETRIES)) { 1226 retryEdidReadCount++; 1227 1228 nvkms_usleep(NV_DP_REREAD_EDID_DELAY_USEC); 1229 1230 goto query_edid; 1231 } 1232 goto done; 1233 } 1234 1235 pEdid->buffer = nvCalloc(getEdidParams->bufferSize, 1); 1236 1237 if (pEdid->buffer == NULL) { 1238 goto done; 1239 } 1240 1241 nvkms_memcpy(pEdid->buffer, &getEdidParams->edidBuffer, 1242 getEdidParams->bufferSize); 1243 pEdid->length = getEdidParams->bufferSize; 1244 1245 success = TRUE; 1246 1247 done: 1248 1249 nvFree(getEdidParams); 1250 1251 if (!success) { 1252 nvEvoLogDisp(pDispEvo, EVO_LOG_WARN, 1253 "Unable to read EDID for display device %s", 1254 pDpyEvo->name); 1255 } 1256 1257 return success; 1258 } // ReadEdidFromResman() 1259 1260 1261 /* 1262 * Check if the EDID meets basic validation criteria. 1263 */ 1264 static NvBool ValidateEdid(const NVDpyEvoRec *pDpyEvo, NVEdidPtr pEdid, 1265 NVEvoInfoStringPtr pInfoString, 1266 const NvBool ignoreEdidChecksum) 1267 { 1268 NvU32 status, tmpStatus; 1269 1270 status = NvTiming_EDIDValidationMask(pEdid->buffer, pEdid->length, TRUE); 1271 tmpStatus = status; 1272 1273 if (status == 0) { 1274 return TRUE; 1275 } 1276 1277 nvEvoLogInfoString(pInfoString, 1278 "The EDID read for display device %s is invalid:", 1279 pDpyEvo->name); 1280 1281 /* 1282 * Warn about every error we know about, masking it out of tmpStatus, then 1283 * warn about an unknown error if there are still any bits remaining in 1284 * tmpStatus. 1285 */ 1286 if (status & 1287 NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_VERSION)) { 1288 nvEvoLogInfoString(pInfoString, 1289 "- The EDID has an unrecognized version."); 1290 tmpStatus &= ~NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_VERSION); 1291 } 1292 1293 if (status & 1294 NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_SIZE)) { 1295 nvEvoLogInfoString(pInfoString, 1296 "- The EDID is too short."); 1297 tmpStatus &= ~NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_SIZE); 1298 } 1299 1300 if (status & 1301 NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_CHECKSUM)) { 1302 /* 1303 * XXX NVKMS TODO: massage wording to not reference X 1304 * configuration option. 1305 */ 1306 nvEvoLogInfoString(pInfoString, 1307 "- The EDID has a bad checksum. %s", 1308 ignoreEdidChecksum ? "This error will be ignored. Note " 1309 "that an EDID with a bad checksum could indicate a " 1310 "corrupt EDID. A corrupt EDID may have mode timings " 1311 "beyond the capabilities of your display, and could " 1312 "damage your hardware. Please use with care." : 1313 "The \"IgnoreEDIDChecksum\" X configuration option may " 1314 "be used to attempt using mode timings in this EDID in " 1315 "spite of this error. A corrupt EDID may have mode " 1316 "timings beyond the capabilities of your display, and " 1317 "could damage your hardware. Please use with care."); 1318 tmpStatus &= ~NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_CHECKSUM); 1319 } 1320 1321 if (status & 1322 NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_RANGE_LIMIT)) { 1323 nvEvoLogInfoString(pInfoString, 1324 "- The EDID has a bad range limit."); 1325 tmpStatus &= ~NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_RANGE_LIMIT); 1326 } 1327 1328 if (status & 1329 NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_DTD)) { 1330 nvEvoLogInfoString(pInfoString, 1331 "- The EDID has a bad detailed timing descriptor."); 1332 tmpStatus &= ~NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_DTD); 1333 } 1334 1335 if (status & 1336 NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXT_DTD)) { 1337 nvEvoLogInfoString(pInfoString, 1338 "- The EDID has an extension block with a bad detailed " 1339 "timing descriptor."); 1340 tmpStatus &= ~NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXT_DTD); 1341 } 1342 1343 if (status & 1344 NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXT)) { 1345 nvEvoLogInfoString(pInfoString, 1346 "- The EDID extension block is invalid."); 1347 tmpStatus &= ~NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXT); 1348 } 1349 1350 if (tmpStatus) { 1351 nvEvoLogInfoString(pInfoString, 1352 "- The EDID has an unrecognized error."); 1353 } 1354 1355 /* 1356 * Unset the bits for errors we don't care about (invalid DTDs in the 1357 * extension block, or checksum errors if ignoreEdidChecksum is in use) 1358 * then return true if there are any remaining errors we do care about. 1359 */ 1360 if (ignoreEdidChecksum) { 1361 status &= ~(NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_CHECKSUM)); 1362 } 1363 1364 if (status == 1365 NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXT_DTD)) { 1366 /* 1367 * If the only problem with the EDID is invalid DTDs in the extension 1368 * block, don't reject the EDID; those timings can be safely skipped in 1369 * NvTiming_ParseEDIDInfo()/parse861ExtDetailedTiming() 1370 */ 1371 nvEvoLogInfoString(pInfoString, 1372 "This bad detailed timing descriptor will be ignored."); 1373 } 1374 1375 status &= ~(NVT_EDID_VALIDATION_ERR_MASK(NVT_EDID_VALIDATION_ERR_EXT_DTD)); 1376 1377 return (status == 0); 1378 } 1379 1380 static const char *GetColorDepthBpc(NVT_COLORDEPTH colorDepth) 1381 { 1382 static char buffer[32]; 1383 NVEvoInfoStringRec infoString; 1384 NvBool first = TRUE; 1385 int i; 1386 1387 struct { 1388 NvBool val; 1389 int bpc; 1390 } table[] = { 1391 { colorDepth.bpc.bpc6, 6 }, 1392 { colorDepth.bpc.bpc8, 8 }, 1393 { colorDepth.bpc.bpc10, 10 }, 1394 { colorDepth.bpc.bpc12, 12 }, 1395 { colorDepth.bpc.bpc14, 14 }, 1396 { colorDepth.bpc.bpc16, 16 }, 1397 }; 1398 1399 nvInitInfoString(&infoString, buffer, sizeof(buffer)); 1400 1401 buffer[0] = '\0'; 1402 1403 for (i = 0; i < ARRAY_LEN(table); i++) { 1404 if (table[i].val) { 1405 nvEvoLogInfoStringRaw(&infoString, "%s%d", 1406 first ? "" : ", ", 1407 table[i].bpc); 1408 first = FALSE; 1409 } 1410 } 1411 1412 return buffer; 1413 } 1414 1415 1416 /* 1417 * Log information about the EDID. 1418 */ 1419 1420 static void LogEdid(NVDpyEvoPtr pDpyEvo, NVEvoInfoStringPtr pInfoString) 1421 { 1422 int k; 1423 NVParsedEdidEvoPtr pParsedEdid; 1424 1425 static const struct { 1426 NVT_TIMING_TYPE type; 1427 const char *name; 1428 } mode_type_table[] = { 1429 { NVT_TYPE_DMT, "Display Monitor Timings" }, 1430 { NVT_TYPE_GTF, "Generalized Timing Formula Timings" }, 1431 { NVT_TYPE_ASPR, "ASPR Timings"}, 1432 { NVT_TYPE_NTSC_TV, "NTSC Timings" }, 1433 { NVT_TYPE_PAL_TV, "PAL Timings" }, 1434 { NVT_TYPE_CVT, "Coordinated Video Timings"}, 1435 { NVT_TYPE_CVT_RB, "Reduced Blanking Coordinated Video Timings" }, 1436 { NVT_TYPE_CUST, "Customized Timings" }, 1437 { NVT_TYPE_EDID_STD, "Standard Timings" }, 1438 { NVT_TYPE_EDID_DTD, "Detailed Timings" }, 1439 { NVT_TYPE_EDID_CVT, "Coordinated Video Timings" }, 1440 { NVT_TYPE_EDID_EST, "Established Timings"}, 1441 { NVT_TYPE_EDID_861ST, "CEA-861B Timings" }, 1442 { NVT_TYPE_NV_PREDEFINED, "Predefined Timings" }, 1443 { NVT_TYPE_DMT_RB, "Reduced Blanking Display Monitor Timings" }, 1444 { NVT_TYPE_EDID_EXT_DTD, "Extension Block Detailed Timings" }, 1445 { NVT_TYPE_SDTV, "SDTV Timings "}, 1446 { NVT_TYPE_HDTV, "HDTV Timings" }, 1447 { NVT_TYPE_SMPTE, "SMPTE Timings" }, 1448 { NVT_TYPE_EDID_VTB_EXT, "VTB Extension Timings" }, 1449 { NVT_TYPE_EDID_VTB_EXT_STD, "VTB Extension Detailed Timings" }, 1450 { NVT_TYPE_EDID_VTB_EXT_DTD, "VTB Extension Standard Timings" }, 1451 { NVT_TYPE_EDID_VTB_EXT_CVT, "VTB Extension CVT Timings" }, 1452 { NVT_TYPE_HDMI_STEREO, "HDMI Stereo Timings" }, 1453 { NVT_TYPE_DISPLAYID_1, "DisplayID Type 1 Timings" }, 1454 { NVT_TYPE_DISPLAYID_2, "DisplayID Type 2 Timings" }, 1455 { NVT_TYPE_HDMI_EXT, "HDMI Extended Resolution Timings" }, 1456 { NVT_TYPE_CUST_AUTO, "Customized Auto Timings" }, 1457 { NVT_TYPE_CUST_MANUAL, "Customized Manual Timings" }, 1458 { NVT_TYPE_CVT_RB_2,"Reduced Blanking Coordinated Video Timings, v2" }, 1459 { NVT_TYPE_DMT_RB_2, "Display Monitor Timings, V2" }, 1460 { NVT_TYPE_DISPLAYID_7, "DisplayID Type 7 Timings" }, 1461 { NVT_TYPE_DISPLAYID_8, "DisplayID Type 8 Timings" }, 1462 { NVT_TYPE_DISPLAYID_9, "DisplayID Type 9 Timings" }, 1463 { NVT_TYPE_DISPLAYID_10, "DisplayID Type 10 Timings" }, 1464 { NVT_TYPE_CVT_RB_3, "Reduced Blanking Coordinated Video Timings, v3" }, 1465 }; 1466 1467 /* 1468 * Trigger a warning if new NVT_TIMING_TYPE values are added 1469 * without updating this function. 1470 * 1471 * If a warning is produced about unhandled enum in the below 1472 * switch statement, please update both the switch statement and 1473 * mode_type_table[], or contact the sw-nvkms email alias. 1474 */ 1475 if (pDpyEvo->parsedEdid.valid) { 1476 for (k = 0; k < pDpyEvo->parsedEdid.info.total_timings; k++) { 1477 NvU32 status = pDpyEvo->parsedEdid.info.timing[k].etc.status; 1478 NVT_TIMING_TYPE type = NVT_GET_TIMING_STATUS_TYPE(status); 1479 1480 switch (type) { 1481 case NVT_TYPE_DMT: 1482 case NVT_TYPE_GTF: 1483 case NVT_TYPE_ASPR: 1484 case NVT_TYPE_NTSC_TV: 1485 case NVT_TYPE_PAL_TV: 1486 case NVT_TYPE_CVT: 1487 case NVT_TYPE_CVT_RB: 1488 case NVT_TYPE_CUST: 1489 case NVT_TYPE_EDID_DTD: 1490 case NVT_TYPE_EDID_STD: 1491 case NVT_TYPE_EDID_EST: 1492 case NVT_TYPE_EDID_CVT: 1493 case NVT_TYPE_EDID_861ST: 1494 case NVT_TYPE_NV_PREDEFINED: 1495 case NVT_TYPE_DMT_RB: 1496 case NVT_TYPE_EDID_EXT_DTD: 1497 case NVT_TYPE_SDTV: 1498 case NVT_TYPE_HDTV: 1499 case NVT_TYPE_SMPTE: 1500 case NVT_TYPE_EDID_VTB_EXT: 1501 case NVT_TYPE_EDID_VTB_EXT_STD: 1502 case NVT_TYPE_EDID_VTB_EXT_DTD: 1503 case NVT_TYPE_EDID_VTB_EXT_CVT: 1504 case NVT_TYPE_HDMI_STEREO: 1505 case NVT_TYPE_DISPLAYID_1: 1506 case NVT_TYPE_DISPLAYID_2: 1507 case NVT_TYPE_HDMI_EXT: 1508 case NVT_TYPE_CUST_AUTO: 1509 case NVT_TYPE_CUST_MANUAL: 1510 case NVT_TYPE_CVT_RB_2: 1511 case NVT_TYPE_DMT_RB_2: 1512 case NVT_TYPE_DISPLAYID_7: 1513 case NVT_TYPE_DISPLAYID_8: 1514 case NVT_TYPE_DISPLAYID_9: 1515 case NVT_TYPE_DISPLAYID_10: 1516 case NVT_TYPE_CVT_RB_3: 1517 /* 1518 * XXX temporarily disable the warning so that additional 1519 * NVT_TYPEs_ can be added to nvtiming.h. Bug 3849339. 1520 */ 1521 default: 1522 break; 1523 } 1524 break; 1525 } 1526 } 1527 1528 nvEvoLogInfoString(pInfoString, ""); 1529 nvEvoLogInfoString(pInfoString, 1530 "--- EDID for %s ---", pDpyEvo->name); 1531 1532 if (!pDpyEvo->parsedEdid.valid) { 1533 nvEvoLogInfoString(pInfoString, ""); 1534 nvEvoLogInfoString(pInfoString, "No EDID Available."); 1535 nvEvoLogInfoString(pInfoString, ""); 1536 goto done; 1537 } 1538 1539 pParsedEdid = &pDpyEvo->parsedEdid; 1540 1541 nvEvoLogInfoString(pInfoString, 1542 "EDID Version : %d.%d", 1543 pParsedEdid->info.version >> 8, 1544 pParsedEdid->info.version & 0xff); 1545 1546 nvEvoLogInfoString(pInfoString, 1547 "Manufacturer : %s", 1548 pParsedEdid->info.manuf_name); 1549 1550 nvEvoLogInfoString(pInfoString, 1551 "Monitor Name : %s", 1552 pParsedEdid->monitorName); 1553 1554 nvEvoLogInfoString(pInfoString, 1555 "Product ID : 0x%04x", 1556 pParsedEdid->info.product_id); 1557 1558 nvEvoLogInfoString(pInfoString, 1559 "32-bit Serial Number : 0x%08x", 1560 pParsedEdid->info.serial_number); 1561 1562 nvEvoLogInfoString(pInfoString, 1563 "Serial Number String : %s", 1564 pParsedEdid->serialNumberString); 1565 1566 nvEvoLogInfoString(pInfoString, 1567 "Manufacture Date : %d, week %d", 1568 pParsedEdid->info.year, 1569 pParsedEdid->info.week); 1570 1571 /* 1572 * despite the name feature_ver_1_3, the below features are 1573 * reported on all EDID versions 1574 */ 1575 nvEvoLogInfoString(pInfoString, 1576 "DPMS Capabilities :%s%s%s", 1577 pParsedEdid->info.u.feature_ver_1_3.support_standby ? 1578 " Standby" : "", 1579 pParsedEdid->info.u.feature_ver_1_3.support_suspend ? 1580 " Suspend" : "", 1581 pParsedEdid->info.u.feature_ver_1_3.support_active_off ? 1582 " Active Off" : ""); 1583 1584 nvEvoLogInfoString(pInfoString, 1585 "Input Type : %s", 1586 pParsedEdid->info.input.isDigital ? 1587 "Digital" : "Analog"); 1588 1589 nvEvoLogInfoString(pInfoString, 1590 "Prefer first detailed timing : %s", 1591 pParsedEdid->info.u.feature_ver_1_3.preferred_timing_is_native ? 1592 "Yes" : "No"); 1593 1594 if (pParsedEdid->info.version == NVT_EDID_VER_1_3) { 1595 nvEvoLogInfoString(pInfoString, 1596 "Supports GTF : %s", 1597 pParsedEdid->info.u.feature_ver_1_3.support_gtf ? 1598 "Yes" : "No"); 1599 } 1600 1601 if (pParsedEdid->info.version >= NVT_EDID_VER_1_4) { 1602 NvBool continuousFrequency = FALSE; 1603 if (pParsedEdid->info.input.isDigital) { 1604 continuousFrequency = 1605 pParsedEdid->info.u.feature_ver_1_4_digital.continuous_frequency; 1606 } else { 1607 continuousFrequency = 1608 pParsedEdid->info.u.feature_ver_1_4_analog.continuous_frequency; 1609 } 1610 1611 nvEvoLogInfoString(pInfoString, 1612 "Supports Continuous Frequency: %s", 1613 continuousFrequency ? "Yes" : "No"); 1614 1615 nvEvoLogInfoString(pInfoString, 1616 "EDID 1.4 YCbCr 422 support : %s", 1617 pParsedEdid->info.u.feature_ver_1_4_digital.support_ycrcb_422 1618 ? "Yes" : "No"); 1619 1620 nvEvoLogInfoString(pInfoString, 1621 "EDID 1.4 YCbCr 444 support : %s", 1622 pParsedEdid->info.u.feature_ver_1_4_digital.support_ycrcb_444 1623 ? "Yes" : "No"); 1624 } 1625 1626 nvEvoLogInfoString(pInfoString, 1627 "Maximum Image Size : %d mm x %d mm", 1628 pParsedEdid->info.screen_size_x * 10, /* screen_size_* is in cm */ 1629 pParsedEdid->info.screen_size_y * 10); 1630 1631 nvEvoLogInfoString(pInfoString, 1632 "Valid HSync Range : " 1633 NV_FMT_DIV_1000_POINT_1 1634 " kHz - " NV_FMT_DIV_1000_POINT_1 " kHz", 1635 NV_VA_DIV_1000_POINT_1(pParsedEdid->limits.min_h_rate_hz), 1636 NV_VA_DIV_1000_POINT_1(pParsedEdid->limits.max_h_rate_hz)); 1637 1638 nvEvoLogInfoString(pInfoString, 1639 "Valid VRefresh Range : " 1640 NV_FMT_DIV_1000_POINT_1 " Hz - " 1641 NV_FMT_DIV_1000_POINT_1 " Hz", 1642 NV_VA_DIV_1000_POINT_1(pParsedEdid->limits.min_v_rate_hzx1k), 1643 NV_VA_DIV_1000_POINT_1(pParsedEdid->limits.max_v_rate_hzx1k)); 1644 1645 nvEvoLogInfoString(pInfoString, 1646 "EDID maximum pixel clock : " 1647 NV_FMT_DIV_1000_POINT_1 " MHz", 1648 NV_VA_DIV_1000_POINT_1(pParsedEdid->limits.max_pclk_10khz * 10)); 1649 1650 if (pParsedEdid->info.nvdaVsdbInfo.valid) { 1651 nvEvoLogInfoString(pInfoString, 1652 "G-Sync capable : %s", 1653 pParsedEdid->info.nvdaVsdbInfo.vrrData.v1.supportsVrr 1654 ? "Yes" : "No"); 1655 nvEvoLogInfoString(pInfoString, 1656 "G-Sync minimum refresh rate : %d Hz", 1657 pParsedEdid->info.nvdaVsdbInfo.vrrData.v1.minRefreshRate); 1658 } 1659 1660 nvLogEdidCea861InfoEvo(pDpyEvo, pInfoString); 1661 1662 if (pParsedEdid->info.input.isDigital && 1663 pParsedEdid->info.version >= NVT_EDID_VER_1_4) { 1664 nvEvoLogInfoString(pInfoString, 1665 "EDID bits per component : %d", 1666 pParsedEdid->info.input.u.digital.bpc); 1667 } 1668 1669 /* print the tiled display extension block, if present */ 1670 if (pParsedEdid->info.ext_displayid.tile_topology_id.vendor_id) { 1671 const NVT_DISPLAYID_INFO *tile = &pParsedEdid->info.ext_displayid; 1672 const char *tmp; 1673 1674 nvEvoLogInfoString(pInfoString, 1675 "Tiled display information :"); 1676 nvEvoLogInfoString(pInfoString, 1677 " Revision : %d", 1678 tile->tiled_display_revision); 1679 nvEvoLogInfoString(pInfoString, 1680 " Single Enclosure : %s", 1681 tile->tile_capability.bSingleEnclosure ? 1682 "Yes" : "No"); 1683 1684 tmp = "Unknown"; 1685 switch (tile->tile_capability.multi_tile_behavior) { 1686 case NVT_MULTI_TILE_BEHAVIOR_OTHER: 1687 tmp = "Other"; 1688 break; 1689 case NVT_MULTI_TILE_BEHAVIOR_SOURCE_DRIVEN: 1690 tmp = "Source-driven"; 1691 break; 1692 } 1693 nvEvoLogInfoString(pInfoString, 1694 " Multi-tile Behavior : %s", tmp); 1695 1696 tmp = "Unknown"; 1697 switch (tile->tile_capability.single_tile_behavior) { 1698 case NVT_SINGLE_TILE_BEHAVIOR_OTHER: 1699 tmp = "Other"; 1700 break; 1701 case NVT_SINGLE_TILE_BEHAVIOR_SOURCE_DRIVEN: 1702 tmp = "Source-driven"; 1703 break; 1704 case NVT_SINGLE_TILE_BEHAVIOR_SCALE: 1705 tmp = "Scale"; 1706 break; 1707 case NVT_SINGLE_TILE_BEHAVIOR_CLONE: 1708 tmp = "Clone"; 1709 break; 1710 } 1711 nvEvoLogInfoString(pInfoString, 1712 " Single-tile Behavior : %s", tmp); 1713 nvEvoLogInfoString(pInfoString, 1714 " Topology : %d row%s, %d column%s", 1715 tile->tile_topology.row, 1716 (tile->tile_topology.row == 1) ? "" : "s", 1717 tile->tile_topology.col, 1718 (tile->tile_topology.col == 1) ? "" : "s"); 1719 nvEvoLogInfoString(pInfoString, 1720 " Location : (%d,%d)", 1721 tile->tile_location.x, tile->tile_location.y); 1722 nvEvoLogInfoString(pInfoString, 1723 " Native Resolution : %dx%d", 1724 tile->native_resolution.width, 1725 tile->native_resolution.height); 1726 if (tile->tile_capability.bHasBezelInfo) { 1727 nvEvoLogInfoString(pInfoString, 1728 " Bezel Information :"); 1729 nvEvoLogInfoString(pInfoString, 1730 " Pixel Density : %d", 1731 tile->bezel_info.pixel_density); 1732 nvEvoLogInfoString(pInfoString, 1733 " Top : %d", 1734 tile->bezel_info.top); 1735 nvEvoLogInfoString(pInfoString, 1736 " Bottom : %d", 1737 tile->bezel_info.bottom); 1738 nvEvoLogInfoString(pInfoString, 1739 " Left : %d", 1740 tile->bezel_info.right); 1741 nvEvoLogInfoString(pInfoString, 1742 " Right : %d", 1743 tile->bezel_info.left); 1744 } 1745 nvEvoLogInfoString(pInfoString, 1746 " Vendor ID : 0x%x", 1747 tile->tile_topology_id.vendor_id); 1748 nvEvoLogInfoString(pInfoString, 1749 " Product ID : 0x%x", 1750 tile->tile_topology_id.product_id); 1751 nvEvoLogInfoString(pInfoString, 1752 " Serial Number : 0x%x", 1753 tile->tile_topology_id.serial_number); 1754 } 1755 1756 for (k = 0; k < ARRAY_LEN(mode_type_table); k++) { 1757 1758 int i; 1759 1760 /* scan through the ModeList to find a mode of the current type */ 1761 1762 for (i = 0; i < pParsedEdid->info.total_timings; i++) { 1763 NVT_TIMING *pTiming = &pParsedEdid->info.timing[i]; 1764 if (mode_type_table[k].type == 1765 NVT_GET_TIMING_STATUS_TYPE(pTiming->etc.status)) { 1766 break; 1767 } 1768 } 1769 1770 /* if there are none of this type, skip to the next mode type */ 1771 1772 if (i == pParsedEdid->info.total_timings) { 1773 continue; 1774 } 1775 1776 nvEvoLogInfoString(pInfoString, ""); 1777 nvEvoLogInfoString(pInfoString, "%s:", mode_type_table[k].name); 1778 1779 for (i = 0; i < pParsedEdid->info.total_timings; i++) { 1780 1781 NVT_TIMING *pTiming = &pParsedEdid->info.timing[i]; 1782 NVT_TIMING_TYPE type = 1783 NVT_GET_TIMING_STATUS_TYPE(pTiming->etc.status); 1784 int vScale = 1; 1785 1786 if (mode_type_table[k].type != type) { 1787 continue; 1788 } 1789 1790 if ((type == NVT_TYPE_EDID_EST) || 1791 (type == NVT_TYPE_EDID_STD)) { 1792 1793 nvEvoLogInfoString(pInfoString, 1794 " %-4d x %-4d @ %d Hz", 1795 NV_NVT_TIMING_HVISIBLE(pTiming), 1796 NV_NVT_TIMING_VVISIBLE(pTiming), 1797 pTiming->etc.rr); 1798 continue; 1799 } 1800 1801 if (pTiming->interlaced) { 1802 vScale = 2; 1803 } 1804 1805 nvEvoLogInfoString(pInfoString, 1806 " %-4d x %-4d @ %d Hz", 1807 NV_NVT_TIMING_HVISIBLE(pTiming), 1808 NV_NVT_TIMING_VVISIBLE(pTiming), 1809 pTiming->etc.rr); 1810 1811 nvEvoLogInfoString(pInfoString, 1812 " Pixel Clock : " 1813 NV_FMT_DIV_1000_POINT_2 " MHz", 1814 NV_VA_DIV_1000_POINT_2(pTiming->pclk 1815 * 10)); 1816 1817 nvEvoLogInfoString(pInfoString, 1818 " HRes, HSyncStart : %d, %d", 1819 pTiming->HVisible, 1820 pTiming->HVisible + 1821 pTiming->HFrontPorch); 1822 1823 nvEvoLogInfoString(pInfoString, 1824 " HSyncEnd, HTotal : %d, %d", 1825 pTiming->HVisible + 1826 pTiming->HFrontPorch + 1827 pTiming->HSyncWidth, 1828 pTiming->HTotal); 1829 1830 nvEvoLogInfoString(pInfoString, 1831 " VRes, VSyncStart : %d, %d", 1832 pTiming->VVisible * vScale, 1833 (pTiming->VVisible + 1834 pTiming->VFrontPorch) * vScale); 1835 1836 nvEvoLogInfoString(pInfoString, 1837 " VSyncEnd, VTotal : %d, %d", 1838 (pTiming->VVisible + 1839 pTiming->VFrontPorch + 1840 pTiming->VSyncWidth) * vScale, 1841 pTiming->VTotal * vScale); 1842 1843 nvEvoLogInfoString(pInfoString, 1844 " H/V Polarity : %s/%s", 1845 (pTiming->HSyncPol == NVT_H_SYNC_NEGATIVE) ? 1846 "-" : "+", 1847 (pTiming->VSyncPol == NVT_V_SYNC_NEGATIVE) ? 1848 "-" : "+"); 1849 1850 if (pTiming->interlaced) { 1851 nvEvoLogInfoString(pInfoString, 1852 " Interlaced : yes"); 1853 } 1854 if (pTiming->etc.flag & NVT_FLAG_NV_DOUBLE_SCAN_TIMING) { 1855 nvEvoLogInfoString(pInfoString, 1856 " Double Scanned : yes"); 1857 } 1858 1859 if (type == NVT_TYPE_EDID_861ST) { 1860 nvEvoLogInfoString(pInfoString, 1861 " CEA Format : %d", 1862 NVT_GET_CEA_FORMAT(pTiming->etc.status)); 1863 } 1864 1865 if (NV_NVT_TIMING_HAS_ASPECT_RATIO(pTiming)) { 1866 nvEvoLogInfoString(pInfoString, 1867 " Aspect Ratio : %d:%d", 1868 NV_NVT_TIMING_IMAGE_SIZE_WIDTH(pTiming), 1869 NV_NVT_TIMING_IMAGE_SIZE_HEIGHT(pTiming)); 1870 } 1871 1872 if (NV_NVT_TIMING_HAS_IMAGE_SIZE(pTiming)) { 1873 nvEvoLogInfoString(pInfoString, 1874 " Image Size : %d mm x %d mm", 1875 NV_NVT_TIMING_IMAGE_SIZE_WIDTH(pTiming), 1876 NV_NVT_TIMING_IMAGE_SIZE_HEIGHT(pTiming)); 1877 } 1878 1879 if (IS_BPC_SUPPORTED_COLORFORMAT(pTiming->etc.rgb444.bpcs)) { 1880 nvEvoLogInfoString(pInfoString, 1881 " RGB 444 bpcs : %s", 1882 GetColorDepthBpc(pTiming->etc.rgb444)); 1883 } 1884 1885 if (IS_BPC_SUPPORTED_COLORFORMAT(pTiming->etc.yuv444.bpcs)) { 1886 nvEvoLogInfoString(pInfoString, 1887 " YUV 444 bpcs : %s", 1888 GetColorDepthBpc(pTiming->etc.yuv444)); 1889 } 1890 1891 if (IS_BPC_SUPPORTED_COLORFORMAT(pTiming->etc.yuv422.bpcs)) { 1892 nvEvoLogInfoString(pInfoString, 1893 " YUV 422 bpcs : %s", 1894 GetColorDepthBpc(pTiming->etc.yuv422)); 1895 } 1896 1897 if (IS_BPC_SUPPORTED_COLORFORMAT(pTiming->etc.yuv420.bpcs)) { 1898 nvEvoLogInfoString(pInfoString, 1899 " YUV 420 bpcs : %s", 1900 GetColorDepthBpc(pTiming->etc.yuv420)); 1901 } 1902 } // i 1903 } // k 1904 1905 nvEvoLogInfoString(pInfoString, ""); 1906 1907 done: 1908 nvEvoLogInfoString(pInfoString, 1909 "--- End of EDID for %s ---", pDpyEvo->name); 1910 nvEvoLogInfoString(pInfoString, ""); 1911 } 1912 1913 1914 1915 /* 1916 * Clear the EDID and related fields in the display device data 1917 * structure. 1918 */ 1919 1920 static void ClearEdid(NVDpyEvoPtr pDpyEvo) 1921 { 1922 NVEdidRec edid = { }; 1923 NVEvoInfoStringRec infoString; 1924 nvInitInfoString(&infoString, NULL, 0); 1925 1926 if (EdidHasChanged(pDpyEvo, &edid, NULL)) { 1927 ApplyNewEdid(pDpyEvo, &edid, NULL, &infoString); 1928 } 1929 } 1930 1931 1932 1933 /* 1934 * ClearCustomEdid() - send an empty custom EDID to RM; this is to 1935 * clear out any stale state in RM about custom EDIDs that we may have 1936 * told RM about previous runs of X. 1937 */ 1938 1939 static void ClearCustomEdid(const NVDpyEvoRec *pDpyEvo) 1940 { 1941 NVDispEvoPtr pDispEvo = pDpyEvo->pDispEvo; 1942 NVDevEvoPtr pDevEvo = pDispEvo->pDevEvo; 1943 NV0073_CTRL_SPECIFIC_SET_EDID_V2_PARAMS *setEdidParams; 1944 1945 if (nvDpyEvoIsDPMST(pDpyEvo)) { 1946 // RM doesn't track this device, so leave the EDID alone. 1947 return; 1948 } 1949 1950 setEdidParams = nvCalloc(sizeof(*setEdidParams), 1); 1951 if (setEdidParams == NULL) { 1952 nvEvoLogDisp(pDispEvo, EVO_LOG_WARN, 1953 "Unable to clear custom EDID for display device %s", 1954 pDpyEvo->name); 1955 return; 1956 } 1957 1958 setEdidParams->subDeviceInstance = pDispEvo->displayOwner; 1959 setEdidParams->displayId = nvDpyEvoGetConnectorId(pDpyEvo); 1960 setEdidParams->bufferSize = 0; 1961 1962 /* ignore the NvRmControl() return value */ 1963 1964 (void) nvRmApiControl(nvEvoGlobal.clientHandle, 1965 pDevEvo->displayCommonHandle, 1966 NV0073_CTRL_CMD_SPECIFIC_SET_EDID_V2, 1967 setEdidParams, sizeof(*setEdidParams)); 1968 1969 nvFree(setEdidParams); 1970 } // ClearCustomEdid() 1971 1972 1973 1974 /* 1975 * WriteEdidToResman() - send a custom EDID to RM. 1976 */ 1977 1978 static void WriteEdidToResman(const NVDpyEvoRec *pDpyEvo, 1979 const NVEdidRec *pEdid) 1980 { 1981 NVDispEvoPtr pDispEvo = pDpyEvo->pDispEvo; 1982 NVDevEvoPtr pDevEvo = pDispEvo->pDevEvo; 1983 NV0073_CTRL_SPECIFIC_SET_EDID_V2_PARAMS *setEdidParams = NULL; 1984 NvU32 status = NVOS_STATUS_ERROR_OPERATING_SYSTEM; 1985 1986 if (pEdid->length > sizeof(setEdidParams->edidBuffer)) { 1987 nvEvoLogDisp(pDispEvo, EVO_LOG_ERROR, 1988 "EDID for display device %s is too long for NV0073_CTRL_CMD_SPECIFIC_SET_EDID_V2", 1989 pDpyEvo->name); 1990 goto done; 1991 } 1992 1993 setEdidParams = nvCalloc(sizeof(*setEdidParams), 1); 1994 if (setEdidParams == NULL) { 1995 goto done; 1996 } 1997 1998 setEdidParams->subDeviceInstance = pDispEvo->displayOwner; 1999 setEdidParams->displayId = nvDpyEvoGetConnectorId(pDpyEvo); 2000 nvkms_memcpy(&setEdidParams->edidBuffer, pEdid->buffer, pEdid->length); 2001 setEdidParams->bufferSize = pEdid->length; 2002 2003 status = nvRmApiControl(nvEvoGlobal.clientHandle, 2004 pDevEvo->displayCommonHandle, 2005 NV0073_CTRL_CMD_SPECIFIC_SET_EDID_V2, 2006 setEdidParams, sizeof(*setEdidParams)); 2007 2008 done: 2009 if (status != NVOS_STATUS_SUCCESS) { 2010 nvEvoLogDisp(pDispEvo, EVO_LOG_WARN, 2011 "Failure processing EDID for display device " 2012 "%s.", pDpyEvo->name); 2013 } 2014 2015 nvFree(setEdidParams); 2016 } // WriteEdidToResman() 2017 2018 2019 /* 2020 * NvTiming_ParseEDIDInfo() will ignore some modes that are blatantly 2021 * wrong, so we need to apply any patching to the EDID bytes before 2022 * parsing the EDID. 2023 */ 2024 static void PrePatchEdid(const NVDpyEvoRec *pDpyEvo, NVEdidPtr pEdid, 2025 NVEvoInfoStringPtr pInfoString) 2026 { 2027 NvU8 *pEdidData = pEdid->buffer; 2028 2029 if (pEdid->buffer == NULL || pEdid->length < 128) { 2030 return; 2031 } 2032 2033 /* 2034 * Work around bug 628240: some AUO flat panels have invalid 2035 * native modes where HSyncEnd is larger than HTotal, putting the 2036 * end of the sync pulse several columns into the active region of 2037 * the next frame. AUO confirmed these corrected timings: 2038 * 2039 * "1366x768" 69.30 1366 1398 1422 1432 768 771 775 806 -hsync -vsync 2040 */ 2041 if (pDpyEvo->pConnectorEvo->legacyType == 2042 NV0073_CTRL_SPECIFIC_DISPLAY_TYPE_DFP && 2043 pEdidData[0x36] == 0x26 && 2044 pEdidData[0x37] == 0x1b && 2045 pEdidData[0x38] == 0x56 && 2046 pEdidData[0x39] == 0x47 && 2047 pEdidData[0x3a] == 0x50 && 2048 pEdidData[0x3b] == 0x00 && 2049 pEdidData[0x3c] == 0x26 && 2050 pEdidData[0x3d] == 0x30 && 2051 pEdidData[0x3e] == 0x30 && 2052 pEdidData[0x3f] == 0x20 && 2053 pEdidData[0x40] == 0x34 && 2054 pEdidData[0x41] == 0x00 && 2055 pEdidData[0x42] == 0x58 && 2056 pEdidData[0x43] == 0xc1 && 2057 pEdidData[0x44] == 0x10 && 2058 pEdidData[0x45] == 0x00 && 2059 pEdidData[0x46] == 0x00 && 2060 pEdidData[0x47] == 0x18 && 2061 pEdidData[0x7f] == 0x2e) { 2062 2063 pEdidData[0x36] = 0x12; 2064 pEdidData[0x37] = 0x1b; 2065 pEdidData[0x38] = 0x56; 2066 pEdidData[0x39] = 0x42; 2067 pEdidData[0x3a] = 0x50; 2068 pEdidData[0x3b] = 0x00; 2069 pEdidData[0x3c] = 0x26; 2070 pEdidData[0x3d] = 0x30; 2071 pEdidData[0x3e] = 0x20; 2072 pEdidData[0x3f] = 0x18; 2073 pEdidData[0x40] = 0x34; 2074 pEdidData[0x41] = 0x00; 2075 pEdidData[0x42] = 0x58; 2076 pEdidData[0x43] = 0xc1; 2077 pEdidData[0x44] = 0x10; 2078 pEdidData[0x45] = 0x00; 2079 pEdidData[0x46] = 0x00; 2080 pEdidData[0x47] = 0x18; 2081 pEdidData[0x7f] = 0x5f; 2082 2083 nvEvoLogInfoString(pInfoString, "Fixed invalid mode for 1366x768"); 2084 } 2085 } 2086 2087 /* 2088 * CreateParsedEdidFromNVT_TIMING() - Puts modetiming data from RM into an EDID format 2089 */ 2090 static void CreateParsedEdidFromNVT_TIMING( 2091 NVT_TIMING *pTimings, 2092 NvU8 bpc, 2093 NVParsedEdidEvoPtr pParsedEdid) 2094 { 2095 nvkms_memset(pParsedEdid, 0, sizeof(*pParsedEdid)); 2096 pParsedEdid->info.total_timings = 1; 2097 nvkms_memcpy(&pParsedEdid->info.timing[0], pTimings, sizeof(*pTimings)); 2098 pParsedEdid->info.timing[0].etc.status = NVT_STATUS_CUST; 2099 pParsedEdid->info.u.feature_ver_1_4_digital.continuous_frequency = FALSE; 2100 pParsedEdid->info.version = NVT_EDID_VER_1_4; 2101 pParsedEdid->info.input.isDigital = TRUE; 2102 pParsedEdid->info.input.u.digital.bpc = bpc; 2103 pParsedEdid->limits.min_h_rate_hz = 1; 2104 pParsedEdid->limits.min_v_rate_hzx1k = 1; 2105 pParsedEdid->limits.max_h_rate_hz = NV_U32_MAX; 2106 pParsedEdid->limits.max_v_rate_hzx1k = NV_U32_MAX; 2107 pParsedEdid->valid = TRUE; 2108 } 2109 2110 /* 2111 * PatchAndParseEdid() - use the nvtiming library to parse the EDID data. The 2112 * EDID data provided in the 'pEdid' argument may be patched or modified. 2113 */ 2114 2115 static void PatchAndParseEdid( 2116 const NVDpyEvoRec *pDpyEvo, 2117 NVEdidPtr pEdid, 2118 NVParsedEdidEvoPtr pParsedEdid, 2119 NVEvoInfoStringPtr pInfoString) 2120 { 2121 int i; 2122 NVT_STATUS status; 2123 NvU32 edidSize; 2124 2125 if (pEdid->buffer == NULL || pEdid->length == 0) { 2126 return; 2127 } 2128 2129 nvkms_memset(pParsedEdid, 0, sizeof(*pParsedEdid)); 2130 2131 PrePatchEdid(pDpyEvo, pEdid, pInfoString); 2132 2133 /* parse the majority of information from the EDID */ 2134 2135 status = NvTiming_ParseEDIDInfo(pEdid->buffer, pEdid->length, 2136 &pParsedEdid->info); 2137 2138 if (status != NVT_STATUS_SUCCESS) { 2139 return; 2140 } 2141 2142 /* interpret the frequency range limits from the EDID */ 2143 2144 NvTiming_CalculateEDIDLimits(&pParsedEdid->info, &pParsedEdid->limits); 2145 2146 /* get the user-friendly monitor name */ 2147 2148 NvTiming_GetMonitorName(&pParsedEdid->info, 2149 (NvU8 *) &pParsedEdid->monitorName); 2150 nvAssert(pParsedEdid->monitorName[0] != '\0'); 2151 2152 /* find the serial number string */ 2153 2154 pParsedEdid->serialNumberString[0] = '\0'; 2155 2156 for (i = 0; i < NVT_EDID_MAX_LONG_DISPLAY_DESCRIPTOR; i++) { 2157 if (pParsedEdid->info.ldd[i].tag == NVT_EDID_DISPLAY_DESCRIPTOR_DPSN) { 2158 nvkms_strncpy( 2159 pParsedEdid->serialNumberString, 2160 (const char *)pParsedEdid->info.ldd[i].u.serial_number.str, 2161 sizeof(pParsedEdid->serialNumberString)); 2162 pParsedEdid->serialNumberString[ 2163 sizeof(pParsedEdid->serialNumberString) - 1] = '\0'; 2164 break; 2165 } 2166 } 2167 2168 2169 for (i = 0; i < pParsedEdid->info.total_timings; i++) { 2170 NVT_TIMING *pTiming = &pParsedEdid->info.timing[i]; 2171 2172 /* patch up RRx1k for 640x480@60Hz */ 2173 2174 if (IsEdid640x480_60_NVT_TIMING(pTiming)) { 2175 pTiming->etc.rrx1k = 59940; 2176 } 2177 2178 /* 2179 * Invalidate modes that require pixel repetition (i.e., modes 2180 * that don't support Pixel Repetition 0). See bug 1459376. 2181 */ 2182 2183 nvAssert(pTiming->etc.rep != 0); 2184 2185 if ((pTiming->etc.rep & NVBIT(0)) == 0) { 2186 pTiming->etc.status = 0; 2187 } 2188 } 2189 2190 pParsedEdid->valid = TRUE; 2191 2192 /* resize the EDID buffer, if necessary */ 2193 2194 edidSize = NVT_EDID_ACTUAL_SIZE(&pParsedEdid->info); 2195 2196 if (edidSize < pEdid->length) { 2197 NvU8 *pEdidData = nvAlloc(edidSize); 2198 2199 if (pEdidData != NULL) { 2200 nvkms_memcpy(pEdidData, pEdid->buffer, edidSize); 2201 2202 nvFree(pEdid->buffer); 2203 2204 pEdid->buffer = pEdidData; 2205 pEdid->length = edidSize; 2206 } 2207 } 2208 } 2209 2210 2211 /*! 2212 * Assign NVDpyEvoRec::name. 2213 * 2214 * The name has the form: 2215 * 2216 * "edidName (typeName-N.dpAddress)" 2217 * 2218 * If edidName is unavailable, then it, and the parentheses are omitted: 2219 * 2220 * "typeName-N.dpAddress" 2221 * "typeName-N" 2222 * 2223 * if dpAddress is unavailable, then the ".dpAddress" is omitted: 2224 * 2225 * "edidName (typeName-N)" 2226 * "typeName-N" 2227 */ 2228 static void AssignDpyEvoName(NVDpyEvoPtr pDpyEvo) 2229 { 2230 const NVConnectorEvoRec *pConnectorEvo = pDpyEvo->pConnectorEvo; 2231 const char *edidName = ""; 2232 const char *openParen = ""; 2233 const char *closeParen = ""; 2234 const char *dpAddress = ""; 2235 const char *dpAddressSeparator = ""; 2236 2237 if (pDpyEvo->parsedEdid.valid && 2238 pDpyEvo->parsedEdid.monitorName[0] != '\0') { 2239 edidName = pDpyEvo->parsedEdid.monitorName; 2240 openParen = " ("; 2241 closeParen = ")"; 2242 } 2243 2244 if (pDpyEvo->dp.addressString != NULL) { 2245 dpAddress = pDpyEvo->dp.addressString; 2246 dpAddressSeparator = "."; 2247 } 2248 2249 nvkms_snprintf(pDpyEvo->name, sizeof(pDpyEvo->name), 2250 "%s%s%s%s%s%s", 2251 edidName, 2252 openParen, 2253 pConnectorEvo->name, 2254 dpAddressSeparator, 2255 dpAddress, 2256 closeParen); 2257 2258 pDpyEvo->name[sizeof(pDpyEvo->name) - 1] = '\0'; 2259 } 2260 2261 enum NvKmsDpyAttributeDigitalSignalValue 2262 nvGetDefaultDpyAttributeDigitalSignalValue(const NVConnectorEvoRec *pConnectorEvo) 2263 { 2264 enum NvKmsDpyAttributeDigitalSignalValue signal = 2265 NV_KMS_DPY_ATTRIBUTE_DIGITAL_SIGNAL_LVDS; 2266 2267 if (pConnectorEvo->legacyType == NV0073_CTRL_SPECIFIC_DISPLAY_TYPE_DFP) { 2268 if (nvConnectorUsesDPLib(pConnectorEvo)) { 2269 signal = NV_KMS_DPY_ATTRIBUTE_DIGITAL_SIGNAL_DISPLAYPORT; 2270 } else { 2271 nvAssert((pConnectorEvo->or.type == NV0073_CTRL_SPECIFIC_OR_TYPE_SOR) || 2272 (pConnectorEvo->or.type == NV0073_CTRL_SPECIFIC_OR_TYPE_DSI)); 2273 2274 if (pConnectorEvo->or.protocol == 2275 NV0073_CTRL_SPECIFIC_OR_PROTOCOL_SOR_LVDS_CUSTOM) { 2276 signal = NV_KMS_DPY_ATTRIBUTE_DIGITAL_SIGNAL_LVDS; 2277 } else if (pConnectorEvo->or.protocol == 2278 NV0073_CTRL_SPECIFIC_OR_PROTOCOL_DSI) { 2279 signal = NV_KMS_DPY_ATTRIBUTE_DIGITAL_SIGNAL_DSI; 2280 } else { 2281 // May be later changed to HDMI_FRL at modeset time. 2282 signal = NV_KMS_DPY_ATTRIBUTE_DIGITAL_SIGNAL_TMDS; 2283 } 2284 } 2285 } 2286 2287 return signal; 2288 } 2289 2290 NVDpyEvoPtr nvAllocDpyEvo(NVDispEvoPtr pDispEvo, 2291 NVConnectorEvoPtr pConnectorEvo, 2292 NVDpyId dpyId, const char *dpAddress) 2293 { 2294 NVDpyEvoPtr pDpyEvo; 2295 2296 pDpyEvo = nvCalloc(1, sizeof(*pDpyEvo)); 2297 2298 if (pDpyEvo == NULL) { 2299 return NULL; 2300 } 2301 2302 pDpyEvo->pDispEvo = pDispEvo; 2303 pDpyEvo->pConnectorEvo = pConnectorEvo; 2304 pDpyEvo->apiHead = NV_INVALID_HEAD; 2305 pDpyEvo->id = dpyId; 2306 2307 nvListAdd(&pDpyEvo->dpyListEntry, &pDispEvo->dpyList); 2308 2309 if (dpAddress) { 2310 pDpyEvo->dp.addressString = nvStrDup(dpAddress); 2311 pDispEvo->displayPortMSTIds = 2312 nvAddDpyIdToDpyIdList(dpyId, pDispEvo->displayPortMSTIds); 2313 2314 if (!nvConnectorIsDPSerializer(pConnectorEvo)) { 2315 pDispEvo->dynamicDpyIds = 2316 nvAddDpyIdToDpyIdList(dpyId, pDispEvo->dynamicDpyIds); 2317 } 2318 } 2319 2320 AssignDpyEvoName(pDpyEvo); 2321 2322 nvDpyProbeMaxPixelClock(pDpyEvo); 2323 2324 pDpyEvo->requestedDithering.state = 2325 NV_KMS_DPY_ATTRIBUTE_REQUESTED_DITHERING_AUTO; 2326 pDpyEvo->requestedDithering.mode = 2327 NV_KMS_DPY_ATTRIBUTE_REQUESTED_DITHERING_MODE_AUTO; 2328 pDpyEvo->requestedDithering.depth = 2329 NV_KMS_DPY_ATTRIBUTE_REQUESTED_DITHERING_DEPTH_AUTO; 2330 2331 // Initialize DP link rate and lane count to sane values. 2332 // This is normally done in nvDPLibUpdateDpyLinkConfiguration, 2333 // but do it here as well in case we query flat panel properties for 2334 // screenless DP devices. 2335 if (nvConnectorUsesDPLib(pConnectorEvo)) { 2336 pDpyEvo->dp.linkRate = 0; 2337 pDpyEvo->dp.laneCount = NV0073_CTRL_CMD_DP_GET_LINK_CONFIG_LANE_COUNT_1; 2338 pDpyEvo->dp.connectorType = NV_KMS_DPY_ATTRIBUTE_DISPLAYPORT_CONNECTOR_TYPE_UNKNOWN; 2339 pDpyEvo->dp.sinkIsAudioCapable = FALSE; 2340 } 2341 2342 pDpyEvo->requestedColorSpace = 2343 NV_KMS_DPY_ATTRIBUTE_REQUESTED_COLOR_SPACE_RGB; 2344 pDpyEvo->requestedColorRange = 2345 NV_KMS_DPY_ATTRIBUTE_COLOR_RANGE_FULL; 2346 2347 pDpyEvo->currentAttributes = NV_EVO_DEFAULT_ATTRIBUTES_SET; 2348 pDpyEvo->currentAttributes.digitalSignal = 2349 nvGetDefaultDpyAttributeDigitalSignalValue(pConnectorEvo); 2350 2351 DpyGetStaticDfpProperties(pDpyEvo); 2352 2353 return pDpyEvo; 2354 } 2355 2356 2357 void nvFreeDpyEvo(NVDispEvoPtr pDispEvo, NVDpyEvoPtr pDpyEvo) 2358 { 2359 nvCancelSDRTransitionTimer(pDpyEvo); 2360 2361 DpyDisconnectEvo(pDpyEvo); 2362 2363 // Let the DP library host implementation handle deleting a pDpy as if the 2364 // library had notified it of a lost device. 2365 nvDPDpyFree(pDpyEvo); 2366 nvAssert(!pDpyEvo->dp.pDpLibDevice); 2367 2368 pDispEvo->validDisplays = 2369 nvDpyIdListMinusDpyId(pDispEvo->validDisplays, pDpyEvo->id); 2370 2371 pDispEvo->displayPortMSTIds = 2372 nvDpyIdListMinusDpyId(pDispEvo->displayPortMSTIds, pDpyEvo->id); 2373 pDispEvo->dynamicDpyIds = 2374 nvDpyIdListMinusDpyId(pDispEvo->dynamicDpyIds, pDpyEvo->id); 2375 2376 nvListDel(&pDpyEvo->dpyListEntry); 2377 2378 nvFree(pDpyEvo->dp.addressString); 2379 nvFree(pDpyEvo); 2380 } 2381 2382 2383 /*! 2384 * Return the pConnectorEvo associated with the given (static) display ID. 2385 * 2386 * XXX[DP] not valid for DP monitors, the connector will be known before 2387 * initialization so this will not be needed. 2388 * 2389 * \param[in] pDisp The pDisp on which to search for the pConnector. 2390 * \param[in] dpyId The ID of the connector to search for. 2391 * 2392 * \return The pConnectorEvo from pDisp that matches the ID, or NULL if 2393 * no connector is found. 2394 */ 2395 NVConnectorEvoPtr nvGetConnectorFromDisp(NVDispEvoPtr pDispEvo, NVDpyId dpyId) 2396 { 2397 NVConnectorEvoPtr pConnectorEvo; 2398 2399 nvAssert(nvDpyIdIsInDpyIdList(dpyId, pDispEvo->connectorIds)); 2400 2401 FOR_ALL_EVO_CONNECTORS(pConnectorEvo, pDispEvo) { 2402 if (nvDpyIdsAreEqual(dpyId, pConnectorEvo->displayId)) { 2403 return pConnectorEvo; 2404 } 2405 } 2406 2407 nvAssert(!"Failed to find pDpy's connector!"); 2408 return NULL; 2409 } 2410 2411 void nvDpyAssignSDRInfoFramePayload(NVT_HDR_INFOFRAME_PAYLOAD *pPayload) 2412 { 2413 nvkms_memset(pPayload, 0, sizeof(*pPayload)); 2414 pPayload->eotf = NVT_CEA861_HDR_INFOFRAME_EOTF_SDR_GAMMA; 2415 pPayload->static_metadata_desc_id = NVT_CEA861_STATIC_METADATA_SM0; 2416 } 2417 2418 static void UpdateDpHDRInfoFrame(const NVDispEvoRec *pDispEvo, const NvU32 head) 2419 { 2420 NvU32 ret; 2421 const NVDispHeadStateEvoRec *pHeadState = 2422 &pDispEvo->headState[head]; 2423 NVDevEvoPtr pDevEvo = pDispEvo->pDevEvo; 2424 2425 NV0073_CTRL_SPECIFIC_SET_OD_PACKET_PARAMS params = { 2426 .subDeviceInstance = pDispEvo->displayOwner, 2427 .displayId = pHeadState->activeRmId 2428 }; 2429 2430 // DPSDP_DESCRIPTOR has a (dataSize, hb, db) layout, while 2431 // NV0073_CTRL_SPECIFIC_SET_OD_PACKET_PARAMS.aPacket needs to contain 2432 // (hb, db) without dataSize, so this makes sdp->hb align with aPacket. 2433 DPSDP_DESCRIPTOR *sdp = 2434 (DPSDP_DESCRIPTOR *)(params.aPacket - 2435 offsetof(DPSDP_DESCRIPTOR, hb)); 2436 2437 nvAssert((void *)&sdp->hb == (void *)params.aPacket); 2438 2439 sdp->hb.hb0 = 0; 2440 sdp->hb.hb1 = dp_pktType_DynamicRangeMasteringInfoFrame; 2441 sdp->hb.hb2 = DP_INFOFRAME_SDP_V1_3_NON_AUDIO_SIZE - 1; 2442 sdp->hb.hb3 = DP_INFOFRAME_SDP_V1_3_VERSION << 2443 DP_INFOFRAME_SDP_V1_3_HB3_VERSION_SHIFT; 2444 2445 sdp->db.db0 = NVT_VIDEO_INFOFRAME_VERSION_1; 2446 sdp->db.db1 = sizeof(NVT_HDR_INFOFRAME) - sizeof(NVT_INFOFRAME_HEADER); 2447 2448 nvAssert((sizeof(sdp->db) - 2) >= sizeof(NVT_HDR_INFOFRAME_PAYLOAD)); 2449 2450 if (pHeadState->hdrInfoFrame.state == NVKMS_HDR_INFOFRAME_STATE_ENABLED) { 2451 NVT_HDR_INFOFRAME_PAYLOAD *payload = 2452 (NVT_HDR_INFOFRAME_PAYLOAD *) &sdp->db.db2; 2453 2454 payload->eotf = pHeadState->hdrInfoFrame.eotf; 2455 2456 payload->static_metadata_desc_id = NVT_CEA861_STATIC_METADATA_SM0; 2457 2458 // payload->type1 = static metadata 2459 nvAssert(sizeof(NVT_HDR_INFOFRAME_MASTERING_DATA) == 2460 (sizeof(struct NvKmsHDRStaticMetadata))); 2461 nvkms_memcpy(&payload->type1, 2462 &pHeadState->hdrInfoFrame.staticMetadata, 2463 sizeof(NVT_HDR_INFOFRAME_MASTERING_DATA)); 2464 2465 params.transmitControl = 2466 DRF_DEF(0073_CTRL_SPECIFIC, _SET_OD_PACKET_TRANSMIT_CONTROL, _SINGLE_FRAME, _DISABLE); 2467 } else if (pHeadState->hdrInfoFrame.state == 2468 NVKMS_HDR_INFOFRAME_STATE_TRANSITIONING) { 2469 nvDpyAssignSDRInfoFramePayload((NVT_HDR_INFOFRAME_PAYLOAD *) &sdp->db.db2); 2470 2471 params.transmitControl = 2472 DRF_DEF(0073_CTRL_SPECIFIC, _SET_OD_PACKET_TRANSMIT_CONTROL, _SINGLE_FRAME, _DISABLE); 2473 } else { 2474 nvAssert(pHeadState->hdrInfoFrame.state == NVKMS_HDR_INFOFRAME_STATE_DISABLED); 2475 2476 nvDpyAssignSDRInfoFramePayload((NVT_HDR_INFOFRAME_PAYLOAD *) &sdp->db.db2); 2477 2478 params.transmitControl = 2479 DRF_DEF(0073_CTRL_SPECIFIC, _SET_OD_PACKET_TRANSMIT_CONTROL, _SINGLE_FRAME, _ENABLE); 2480 } 2481 2482 params.transmitControl |= 2483 DRF_DEF(0073_CTRL_SPECIFIC, _SET_OD_PACKET_TRANSMIT_CONTROL, _OTHER_FRAME, _DISABLE) | 2484 DRF_DEF(0073_CTRL_SPECIFIC, _SET_OD_PACKET_TRANSMIT_CONTROL, _ENABLE, _YES) | 2485 DRF_DEF(0073_CTRL_SPECIFIC, _SET_OD_PACKET_TRANSMIT_CONTROL, _GEN_INFOFRAME_MODE, _INFOFRAME1) | 2486 DRF_DEF(0073_CTRL_SPECIFIC, _SET_OD_PACKET_TRANSMIT_CONTROL, _ON_HBLANK, _DISABLE); 2487 2488 params.packetSize = sizeof(sdp->hb) + sizeof(NVT_HDR_INFOFRAME); 2489 2490 ret = nvRmApiControl(nvEvoGlobal.clientHandle, 2491 pDevEvo->displayCommonHandle, 2492 NV0073_CTRL_CMD_SPECIFIC_SET_OD_PACKET, 2493 ¶ms, 2494 sizeof(params)); 2495 2496 if (ret != NVOS_STATUS_SUCCESS) { 2497 nvAssert(!"NV0073_CTRL_CMD_SPECIFIC_SET_OD_PACKET failed"); 2498 } 2499 } 2500 2501 /* 2502 * Construct the DP 1.3 YUV420 infoframe, and toggle it on or off based on 2503 * whether or not YUV420 mode is in use. 2504 */ 2505 static void UpdateDpYUV420InfoFrame(const NVDispEvoRec *pDispEvo, 2506 const NvU32 head, 2507 const NVAttributesSetEvoRec *pAttributesSet) 2508 { 2509 const NVDispHeadStateEvoRec *pHeadState = 2510 &pDispEvo->headState[head]; 2511 NV0073_CTRL_SPECIFIC_SET_OD_PACKET_PARAMS params = { 0 }; 2512 NVDevEvoPtr pDevEvo = pDispEvo->pDevEvo; 2513 NvU32 ret; 2514 2515 params.subDeviceInstance = pDispEvo->displayOwner; 2516 params.displayId = pHeadState->activeRmId; 2517 2518 if (pAttributesSet->colorSpace == 2519 NV_KMS_DPY_ATTRIBUTE_CURRENT_COLOR_SPACE_YCbCr420) { 2520 2521 // DPSDP_DP_VSC_SDP_DESCRIPTOR has a (dataSize, hb, db) layout, while 2522 // NV0073_CTRL_SPECIFIC_SET_OD_PACKET_PARAMS.aPacket needs to contain 2523 // (hb, db) without dataSize, so this makes sdp->hb align with aPacket. 2524 DPSDP_DP_VSC_SDP_DESCRIPTOR *sdp = 2525 (DPSDP_DP_VSC_SDP_DESCRIPTOR *)(params.aPacket - 2526 offsetof(DPSDP_DP_VSC_SDP_DESCRIPTOR, hb)); 2527 2528 nvAssert((void *)&sdp->hb == (void *)params.aPacket); 2529 2530 // Header 2531 // Per DP1.3 spec 2532 sdp->hb.hb0 = 0; 2533 sdp->hb.hb1 = SDP_PACKET_TYPE_VSC; 2534 sdp->hb.revisionNumber = SDP_VSC_REVNUM_STEREO_PSR2_COLOR; 2535 sdp->hb.numValidDataBytes = SDP_VSC_VALID_DATA_BYTES_PSR2_COLOR; 2536 2537 sdp->db.stereoInterface = 0; 2538 sdp->db.psrState = 0; 2539 sdp->db.contentType = SDP_VSC_CONTENT_TYPE_GRAPHICS; 2540 sdp->db.pixEncoding = SDP_VSC_PIX_ENC_YCBCR420; 2541 sdp->db.colorimetryFormat = SDP_VSC_COLOR_FMT_YCBCR_COLORIMETRY_ITU_R_BT709; 2542 2543 switch (pAttributesSet->colorBpc) { 2544 case NV_KMS_DPY_ATTRIBUTE_CURRENT_COLOR_BPC_10: 2545 sdp->db.bitDepth = SDP_VSC_BIT_DEPTH_YCBCR_10BPC; 2546 break; 2547 case NV_KMS_DPY_ATTRIBUTE_CURRENT_COLOR_BPC_8: 2548 sdp->db.bitDepth = SDP_VSC_BIT_DEPTH_YCBCR_8BPC; 2549 break; 2550 default: 2551 nvAssert(!"Invalid pixelDepth value"); 2552 break; 2553 } 2554 2555 switch (pAttributesSet->colorRange) { 2556 case NV_KMS_DPY_ATTRIBUTE_COLOR_RANGE_FULL: 2557 sdp->db.dynamicRange = SDP_VSC_DYNAMIC_RANGE_VESA; 2558 break; 2559 case NV_KMS_DPY_ATTRIBUTE_COLOR_RANGE_LIMITED: 2560 sdp->db.dynamicRange = SDP_VSC_DYNAMIC_RANGE_CEA; 2561 break; 2562 default: 2563 nvAssert(!"Invalid colorRange value"); 2564 break; 2565 } 2566 2567 params.packetSize = sizeof(sdp->hb) + sdp->hb.numValidDataBytes; 2568 2569 params.transmitControl = 2570 DRF_DEF(0073_CTRL_SPECIFIC, _SET_OD_PACKET_TRANSMIT_CONTROL, _ENABLE, _YES) | 2571 DRF_DEF(0073_CTRL_SPECIFIC, _SET_OD_PACKET_TRANSMIT_CONTROL, _OTHER_FRAME, _DISABLE) | 2572 DRF_DEF(0073_CTRL_SPECIFIC, _SET_OD_PACKET_TRANSMIT_CONTROL, _SINGLE_FRAME, _DISABLE) | 2573 DRF_DEF(0073_CTRL_SPECIFIC, _SET_OD_PACKET_TRANSMIT_CONTROL, _ON_HBLANK, _DISABLE); 2574 } else { 2575 params.transmitControl = 2576 DRF_DEF(0073_CTRL_SPECIFIC, _SET_OD_PACKET_TRANSMIT_CONTROL, _ENABLE, _NO); 2577 } 2578 2579 ret = nvRmApiControl(nvEvoGlobal.clientHandle, 2580 pDevEvo->displayCommonHandle, 2581 NV0073_CTRL_CMD_SPECIFIC_SET_OD_PACKET, 2582 ¶ms, 2583 sizeof(params)); 2584 2585 if (ret != NVOS_STATUS_SUCCESS) { 2586 nvAssert(!"NV0073_CTRL_CMD_SPECIFIC_SET_OD_PACKET failed"); 2587 } 2588 } 2589 2590 static void UpdateDpInfoFrames(const NVDispEvoRec *pDispEvo, 2591 const NvU32 head, 2592 const NVAttributesSetEvoRec *pAttributesSet) 2593 { 2594 UpdateDpHDRInfoFrame(pDispEvo, head); 2595 2596 UpdateDpYUV420InfoFrame(pDispEvo, head, pAttributesSet); 2597 } 2598 2599 void nvCancelSDRTransitionTimer(NVDpyEvoRec *pDpyEvo) 2600 { 2601 nvkms_free_timer(pDpyEvo->hdrToSdrTransitionTimer); 2602 pDpyEvo->hdrToSdrTransitionTimer = NULL; 2603 } 2604 2605 static void SDRTransition(void *dataPtr, NvU32 dataU32) 2606 { 2607 NvU32 head; 2608 NVDpyEvoRec *pDpyEvo = dataPtr; 2609 NVDispEvoRec *pDispEvo = pDpyEvo->pDispEvo; 2610 NVDispApiHeadStateEvoRec *pApiHeadState = 2611 &pDispEvo->apiHeadState[pDpyEvo->apiHead]; 2612 2613 nvCancelSDRTransitionTimer(pDpyEvo); 2614 2615 nvAssert(pApiHeadState->hwHeadsMask != 0); 2616 2617 FOR_EACH_EVO_HW_HEAD_IN_MASK(pApiHeadState->hwHeadsMask, head) { 2618 NVDispHeadStateEvoRec *pHeadState = 2619 &pDispEvo->headState[head]; 2620 nvAssert(pHeadState->hdrInfoFrame.state == 2621 NVKMS_HDR_INFOFRAME_STATE_TRANSITIONING); 2622 pHeadState->hdrInfoFrame.state = NVKMS_HDR_INFOFRAME_STATE_DISABLED; 2623 } 2624 2625 nvUpdateInfoFrames(pDpyEvo); 2626 } 2627 2628 static 2629 void ScheduleSDRTransitionTimer(NVDpyEvoRec *pDpyEvo) 2630 { 2631 if (pDpyEvo->hdrToSdrTransitionTimer) { 2632 return; 2633 } 2634 2635 pDpyEvo->hdrToSdrTransitionTimer = 2636 nvkms_alloc_timer(SDRTransition, 2637 pDpyEvo, 2638 0, 2639 2000000 /* 2 seconds */); 2640 } 2641 2642 void nvUpdateInfoFrames(NVDpyEvoRec *pDpyEvo) 2643 { 2644 NVDispEvoRec *pDispEvo = pDpyEvo->pDispEvo; 2645 const NVDispApiHeadStateEvoRec *pApiHeadState; 2646 const NVDispHeadStateEvoRec *pHeadState; 2647 NvU32 head; 2648 2649 if (pDpyEvo->apiHead == NV_INVALID_HEAD) { 2650 return; 2651 } 2652 pApiHeadState = &pDispEvo->apiHeadState[pDpyEvo->apiHead]; 2653 2654 nvAssert((pApiHeadState->hwHeadsMask) != 0x0 && 2655 (nvDpyIdIsInDpyIdList(pDpyEvo->id, pApiHeadState->activeDpys))); 2656 2657 head = nvGetPrimaryHwHead(pDispEvo, pDpyEvo->apiHead); 2658 2659 nvAssert(head != NV_INVALID_HEAD); 2660 2661 pHeadState = &pDispEvo->headState[head]; 2662 2663 if (nvConnectorUsesDPLib(pDpyEvo->pConnectorEvo)) { 2664 UpdateDpInfoFrames(pDispEvo, head, &pApiHeadState->attributes); 2665 } else { 2666 nvUpdateHdmiInfoFrames(pDispEvo, 2667 head, 2668 &pApiHeadState->attributes, 2669 &pApiHeadState->infoFrame, 2670 pDpyEvo); 2671 } 2672 2673 if (pHeadState->hdrInfoFrame.state == NVKMS_HDR_INFOFRAME_STATE_ENABLED) { 2674 nvCancelSDRTransitionTimer(pDpyEvo); 2675 } else if (pHeadState->hdrInfoFrame.state == 2676 NVKMS_HDR_INFOFRAME_STATE_TRANSITIONING) { 2677 ScheduleSDRTransitionTimer(pDpyEvo); 2678 } 2679 } 2680 2681 /*! 2682 * nvDpyRequiresDualLinkEvo() - Returns whether or not the given mode exceeds 2683 * the maximum single TMDS link pixel clock. 2684 * 2685 * \param[in] pDpyEvo display to check the maximum single link pixel clock 2686 * 2687 * \param[in] pTimings mode timings to check pixel clock 2688 * 2689 * \return TRUE if pixel clock exceeds display's maximum single link pixel 2690 * clock 2691 */ 2692 NvBool nvDpyRequiresDualLinkEvo(const NVDpyEvoRec *pDpyEvo, 2693 const NVHwModeTimingsEvo *pTimings) 2694 { 2695 const NvU32 pixelClock = (pTimings->yuv420Mode == NV_YUV420_MODE_HW) ? 2696 (pTimings->pixelClock / 2) : pTimings->pixelClock; 2697 2698 // Dual link HDMI is not possible. 2699 nvAssert(!(nvDpyIsHdmiEvo(pDpyEvo) && 2700 (pixelClock > pDpyEvo->maxSingleLinkPixelClockKHz))); 2701 return (pixelClock > pDpyEvo->maxSingleLinkPixelClockKHz); 2702 } 2703 2704 /*! 2705 * Return the NVDpyEvoPtr that corresponds to the given dpyId, on the 2706 * given NVDispEvoPtr, or NULL if no matching NVDpyEvoPtr can be 2707 * found. 2708 */ 2709 NVDpyEvoPtr nvGetDpyEvoFromDispEvo(const NVDispEvoRec *pDispEvo, NVDpyId dpyId) 2710 { 2711 NVDpyEvoPtr pDpyEvo; 2712 2713 FOR_ALL_EVO_DPYS(pDpyEvo, nvAddDpyIdToEmptyDpyIdList(dpyId), pDispEvo) { 2714 return pDpyEvo; 2715 } 2716 2717 return NULL; 2718 } 2719 2720 /* 2721 * Find or create a pDpy with a given root connector and topology path. 2722 */ 2723 NVDpyEvoPtr nvGetDPMSTDpyEvo(NVConnectorEvoPtr pConnectorEvo, 2724 const char *address, NvBool *pDynamicDpyCreated) 2725 { 2726 NVDispEvoPtr pDispEvo = pConnectorEvo->pDispEvo; 2727 NVDpyEvoPtr pDpyEvo = NULL, pTmpDpyEvo; 2728 NVDpyId dpyId; 2729 2730 // Look for a pDpyEvo on pConnectorEvo whose dp address matches. 2731 FOR_ALL_EVO_DPYS(pTmpDpyEvo, pDispEvo->validDisplays, pDispEvo) { 2732 if (pTmpDpyEvo->pConnectorEvo != pConnectorEvo) { 2733 continue; 2734 } 2735 if (pTmpDpyEvo->dp.addressString == NULL) { 2736 continue; 2737 } 2738 if (nvkms_strcmp(pTmpDpyEvo->dp.addressString, address) == 0) { 2739 pDpyEvo = pTmpDpyEvo; 2740 goto done; 2741 } 2742 } 2743 2744 // Find a display ID that is not used on this GPU. 2745 dpyId = nvNewDpyId(pDispEvo->validDisplays); 2746 if (nvDpyIdIsInvalid(dpyId)) { 2747 nvEvoLogDisp(pDispEvo, EVO_LOG_ERROR, 2748 "Failed to allocate a display ID for device %s.%s", 2749 pConnectorEvo->name, 2750 address); 2751 goto done; 2752 } 2753 2754 // Create a new pDpy for this address. 2755 pDpyEvo = nvAllocDpyEvo(pDispEvo, pConnectorEvo, dpyId, address); 2756 if (pDpyEvo == NULL) { 2757 nvEvoLogDisp(pDispEvo, EVO_LOG_ERROR, 2758 "Failed to create a display device object for %s-%u.%s", 2759 NvKmsConnectorTypeString(pConnectorEvo->type), 2760 pConnectorEvo->typeIndex, 2761 address); 2762 goto done; 2763 } 2764 2765 pDispEvo->validDisplays = 2766 nvAddDpyIdToDpyIdList(dpyId, pDispEvo->validDisplays); 2767 2768 *pDynamicDpyCreated = TRUE; 2769 2770 done: 2771 return pDpyEvo; 2772 } 2773 2774 /*! 2775 * Return a string with a comma-separated list of dpy names, for all 2776 * dpys in dpyIdList. 2777 * 2778 * If there are no dpys in the dpyIdList, return "none". 2779 * 2780 * The string is dynamically allocated and should be freed by the caller. 2781 * 2782 * Return NULL if an allocation failure occurs. 2783 */ 2784 char *nvGetDpyIdListStringEvo(NVDispEvoPtr pDispEvo, 2785 const NVDpyIdList dpyIdList) 2786 { 2787 NVDpyEvoPtr pDpyEvo; 2788 char *listString = NULL; 2789 NvU32 lengths[NV_DPY_ID_MAX_DPYS_IN_LIST]; 2790 NvU32 totalLength = 0; 2791 NvU32 currentOffset; 2792 NvU32 index; 2793 2794 index = 0; 2795 FOR_ALL_EVO_DPYS(pDpyEvo, dpyIdList, pDispEvo) { 2796 2797 nvAssert(index < ARRAY_LEN(lengths)); 2798 2799 lengths[index] = nvkms_strlen(pDpyEvo->name); 2800 2801 totalLength += lengths[index]; 2802 2803 if (index != 0) { 2804 totalLength += 2; /* nvkms_strlen(", ") */ 2805 } 2806 2807 index++; 2808 } 2809 2810 totalLength += 1; /* for nul terminator */ 2811 2812 if (index == 0) { 2813 return nvStrDup("none"); 2814 } 2815 2816 listString = nvAlloc(totalLength); 2817 2818 if (listString == NULL) { 2819 return NULL; 2820 } 2821 2822 index = 0; 2823 currentOffset = 0; 2824 2825 FOR_ALL_EVO_DPYS(pDpyEvo, dpyIdList, pDispEvo) { 2826 2827 if (index != 0) { 2828 listString[currentOffset] = ','; 2829 listString[currentOffset+1] = ' '; 2830 currentOffset += 2; 2831 } 2832 2833 nvkms_memcpy(listString + currentOffset, pDpyEvo->name, lengths[index]); 2834 2835 currentOffset += lengths[index]; 2836 2837 index++; 2838 } 2839 2840 listString[currentOffset] = '\0'; 2841 currentOffset += 1; 2842 2843 nvAssert(currentOffset == totalLength); 2844 2845 return listString; 2846 } 2847 2848 NvBool nvDpyGetDynamicData( 2849 NVDpyEvoPtr pDpyEvo, 2850 struct NvKmsQueryDpyDynamicDataParams *pParams) 2851 { 2852 NVDispEvoPtr pDispEvo = pDpyEvo->pDispEvo; 2853 struct NvKmsQueryDpyDynamicDataRequest *pRequest = &pParams->request; 2854 struct NvKmsQueryDpyDynamicDataReply *pReply = &pParams->reply; 2855 NVConnectorEvoPtr pConnectorEvo = pDpyEvo->pConnectorEvo; 2856 NVDpyIdList connectedList; 2857 NVDpyIdList oneDpyIdList = nvAddDpyIdToEmptyDpyIdList(pDpyEvo->id); 2858 NVDpyOverridePtr pDpyOverride = nvDpyEvoGetOverride(pDpyEvo); 2859 2860 nvkms_memset(pReply, 0, sizeof(*pReply)); 2861 2862 if (pDpyOverride != NULL) { 2863 if (pDpyOverride->connected && !pRequest->forceDisconnected) { 2864 /* 2865 * If display is overridden as connected, treat the request as if it 2866 * had both forceConnected and overrideEdid set, unless the request 2867 * had forceDisconnected set. 2868 * 2869 * If the request already had an EDID override, honor that EDID instead 2870 * of the display override EDID. 2871 */ 2872 NvBool old = pRequest->forceConnected; 2873 pRequest->forceConnected = TRUE; 2874 2875 if (!pRequest->overrideEdid) { 2876 size_t len = nvReadDpyOverrideEdid(pDpyOverride, 2877 pRequest->edid.buffer, 2878 ARRAY_LEN(pRequest->edid.buffer)); 2879 2880 if (len != 0) { 2881 pRequest->overrideEdid = TRUE; 2882 pRequest->edid.bufferSize = len; 2883 } else { 2884 pRequest->forceConnected = old; 2885 } 2886 } 2887 } else if (!pDpyOverride->connected && !pRequest->forceConnected) { 2888 /* 2889 * If display is overriden as disconnected, treat the request as if it 2890 * had forceDisconnected set, unless the request had forceConnected set. 2891 */ 2892 pRequest->forceDisconnected = TRUE; 2893 } 2894 } 2895 2896 /* 2897 * Check for the connection state of the dpy. 2898 * 2899 * For DP MST, we need to honor the current DPlib state; if a DP 2900 * MST monitor is physically connected but forceDisconnected, its 2901 * hotplug events won't get serviced and DPlib will complain 2902 * loudly. This doesn't apply to DP serializer (which is not managed 2903 * by DPLib) since we don't need to do any topology/branch detection, 2904 * and we can honor force{Connected,Disconnected} in MST & SST mode. 2905 * 2906 * Otherwise, allow the client to override detection. 2907 * 2908 * Otherwise, honor the current DPlib state. 2909 * 2910 * If we're using a DP serializer connector in MST mode, don't expose any 2911 * SST displays as connected. In all other cases, assume that everything 2912 * is connected since the serializer connector has a fixed topology. 2913 * 2914 * Lastly, call RM to check if the dpy is connected. 2915 */ 2916 2917 if (nvDpyEvoIsDPMST(pDpyEvo) && 2918 nvConnectorUsesDPLib(pConnectorEvo)) { 2919 /* honor DP MST connectedness */ 2920 connectedList = nvDPLibDpyIsConnected(pDpyEvo) ? 2921 oneDpyIdList : nvEmptyDpyIdList(); 2922 } else if (pRequest->forceConnected) { 2923 connectedList = oneDpyIdList; 2924 } else if (pRequest->forceDisconnected) { 2925 connectedList = nvEmptyDpyIdList(); 2926 } else if (nvConnectorUsesDPLib(pConnectorEvo)) { 2927 connectedList = nvDPLibDpyIsConnected(pDpyEvo) ? 2928 oneDpyIdList : nvEmptyDpyIdList(); 2929 } else if (nvConnectorIsDPSerializer(pConnectorEvo)) { 2930 if (pConnectorEvo->dpSerializerCaps.supportsMST && 2931 !nvDpyEvoIsDPMST(pDpyEvo)) { 2932 connectedList = nvEmptyDpyIdList(); 2933 } else { 2934 connectedList = oneDpyIdList; 2935 } 2936 } else { 2937 connectedList = nvRmGetConnectedDpys(pDispEvo, oneDpyIdList); 2938 } 2939 2940 pDpyEvo->dp.inbandStereoSignaling = pRequest->dpInbandStereoSignaling; 2941 2942 /* 2943 * XXX NVKMS TODO: once NVKMS is in the kernel and 2944 * nvAllocCoreChannelEvo() is guaranteed to happen before 2945 * nvDpyGetDynamicData(), pass allowDVISpecPClkOverride through to 2946 * nvDpyProbeMaxPixelClock() rather than cache it. 2947 */ 2948 pDpyEvo->allowDVISpecPClkOverride = pRequest->allowDVISpecPClkOverride; 2949 2950 if (nvDpyIdIsInDpyIdList(pDpyEvo->id, connectedList)) { 2951 if (!DpyConnectEvo(pDpyEvo, pParams)) { 2952 return FALSE; 2953 } 2954 } else { 2955 DpyDisconnectEvo(pDpyEvo); 2956 } 2957 2958 if (nvConnectorUsesDPLib(pConnectorEvo)) { 2959 nvDPLibUpdateDpyLinkConfiguration(pDpyEvo); 2960 } 2961 2962 ct_assert(sizeof(pDpyEvo->name) == sizeof(pReply->name)); 2963 2964 nvkms_memcpy(pReply->name, pDpyEvo->name, sizeof(pDpyEvo->name)); 2965 2966 if (pDpyEvo->parsedEdid.valid) { 2967 pReply->physicalDimensions.heightInCM = 2968 pDpyEvo->parsedEdid.info.screen_size_y; 2969 pReply->physicalDimensions.widthInCM = 2970 pDpyEvo->parsedEdid.info.screen_size_x; 2971 } 2972 2973 /* 2974 * XXX NVKMS until NVKMS is in the kernel and 2975 * nvAllocCoreChannelEvo() is guaranteed to happen before 2976 * nvDpyGetDynamicData(), pDpyEvo->maxPixelClockKHz could change 2977 * later after the assignment here. 2978 */ 2979 pReply->maxPixelClockKHz = pDpyEvo->maxPixelClockKHz; 2980 2981 pReply->connected = 2982 nvDpyIdIsInDpyIdList(pDpyEvo->id, pDispEvo->connectedDisplays); 2983 2984 pReply->isVirtualRealityHeadMountedDisplay = pDpyEvo->isVrHmd; 2985 2986 pReply->vrrType = pDpyEvo->vrr.type; 2987 2988 pReply->stereo3DVision.supported = pDpyEvo->stereo3DVision.supported; 2989 pReply->stereo3DVision.isDLP = pDpyEvo->stereo3DVision.isDLP; 2990 pReply->stereo3DVision.isAegis = pDpyEvo->stereo3DVision.isAegis; 2991 pReply->stereo3DVision.subType = pDpyEvo->stereo3DVision.subType; 2992 2993 pReply->dp.guid.valid = pDpyEvo->dp.guid.valid; 2994 2995 ct_assert(sizeof(pReply->dp.guid.buffer) == 2996 sizeof(pDpyEvo->dp.guid.buffer)); 2997 nvkms_memcpy(pReply->dp.guid.buffer, pDpyEvo->dp.guid.buffer, 2998 sizeof(pDpyEvo->dp.guid.buffer)); 2999 3000 ct_assert(sizeof(pReply->dp.guid.str) == sizeof(pDpyEvo->dp.guid.str)); 3001 nvkms_memcpy(pReply->dp.guid.str, pDpyEvo->dp.guid.str, 3002 sizeof(pDpyEvo->dp.guid.str)); 3003 3004 if (pDpyEvo->edid.length > sizeof(pReply->edid.buffer)) { 3005 nvAssert(!"EDID larger than can be returned in NVKMS API"); 3006 return FALSE; 3007 } 3008 3009 if (pDpyEvo->edid.length > 0) { 3010 pReply->edid.bufferSize = pDpyEvo->edid.length; 3011 nvkms_memcpy(pReply->edid.buffer, pDpyEvo->edid.buffer, pDpyEvo->edid.length); 3012 } 3013 3014 return TRUE; 3015 } 3016 3017 void nvDpyUpdateCurrentAttributes(NVDpyEvoRec *pDpyEvo) 3018 { 3019 NVAttributesSetEvoRec newAttributes = pDpyEvo->currentAttributes; 3020 3021 if (pDpyEvo->apiHead != NV_INVALID_HEAD) { 3022 newAttributes = 3023 pDpyEvo->pDispEvo->apiHeadState[pDpyEvo->apiHead].attributes; 3024 } else { 3025 newAttributes.dithering.enabled = FALSE; 3026 newAttributes.dithering.depth = NV_KMS_DPY_ATTRIBUTE_CURRENT_DITHERING_DEPTH_NONE; 3027 newAttributes.dithering.mode = NV_KMS_DPY_ATTRIBUTE_CURRENT_DITHERING_MODE_NONE; 3028 newAttributes.digitalSignal = 3029 nvGetDefaultDpyAttributeDigitalSignalValue(pDpyEvo->pConnectorEvo); 3030 newAttributes.numberOfHardwareHeadsUsed = 0; 3031 } 3032 3033 if (newAttributes.colorSpace != 3034 pDpyEvo->currentAttributes.colorSpace) { 3035 nvSendDpyAttributeChangedEventEvo( 3036 pDpyEvo, 3037 NV_KMS_DPY_ATTRIBUTE_CURRENT_COLOR_SPACE, 3038 newAttributes.colorSpace); 3039 } 3040 3041 if (newAttributes.colorRange != 3042 pDpyEvo->currentAttributes.colorRange) { 3043 nvSendDpyAttributeChangedEventEvo( 3044 pDpyEvo, 3045 NV_KMS_DPY_ATTRIBUTE_CURRENT_COLOR_RANGE, 3046 newAttributes.colorRange); 3047 } 3048 3049 if (newAttributes.dithering.enabled != 3050 pDpyEvo->currentAttributes.dithering.enabled) { 3051 nvSendDpyAttributeChangedEventEvo( 3052 pDpyEvo, 3053 NV_KMS_DPY_ATTRIBUTE_CURRENT_DITHERING, 3054 newAttributes.dithering.enabled); 3055 } 3056 3057 if (newAttributes.dithering.depth != 3058 pDpyEvo->currentAttributes.dithering.depth) { 3059 nvSendDpyAttributeChangedEventEvo( 3060 pDpyEvo, 3061 NV_KMS_DPY_ATTRIBUTE_CURRENT_DITHERING_DEPTH, 3062 newAttributes.dithering.depth); 3063 } 3064 3065 if (newAttributes.dithering.mode != 3066 pDpyEvo->currentAttributes.dithering.mode) { 3067 nvSendDpyAttributeChangedEventEvo( 3068 pDpyEvo, 3069 NV_KMS_DPY_ATTRIBUTE_CURRENT_DITHERING_MODE, 3070 newAttributes.dithering.mode); 3071 } 3072 3073 if (newAttributes.imageSharpening.available != 3074 pDpyEvo->currentAttributes.imageSharpening.available) { 3075 nvSendDpyAttributeChangedEventEvo( 3076 pDpyEvo, 3077 NV_KMS_DPY_ATTRIBUTE_IMAGE_SHARPENING_AVAILABLE, 3078 newAttributes.imageSharpening.available); 3079 } 3080 3081 if (newAttributes.digitalSignal != 3082 pDpyEvo->currentAttributes.digitalSignal) { 3083 nvSendDpyAttributeChangedEventEvo( 3084 pDpyEvo, 3085 NV_KMS_DPY_ATTRIBUTE_DIGITAL_SIGNAL, 3086 newAttributes.digitalSignal); 3087 } 3088 3089 if (newAttributes.numberOfHardwareHeadsUsed != 3090 pDpyEvo->currentAttributes.numberOfHardwareHeadsUsed) { 3091 nvSendDpyAttributeChangedEventEvo( 3092 pDpyEvo, 3093 NV_KMS_DPY_ATTRIBUTE_NUMBER_OF_HARDWARE_HEADS_USED, 3094 newAttributes.numberOfHardwareHeadsUsed); 3095 } 3096 3097 pDpyEvo->currentAttributes = newAttributes; 3098 } 3099 3100 // Returns TRUE if this display is capable of Adaptive-Sync 3101 NvBool nvDpyIsAdaptiveSync(const NVDpyEvoRec *pDpyEvo) 3102 { 3103 return ((pDpyEvo->vrr.type == 3104 NVKMS_DPY_VRR_TYPE_ADAPTIVE_SYNC_DEFAULTLISTED) || 3105 (pDpyEvo->vrr.type == 3106 NVKMS_DPY_VRR_TYPE_ADAPTIVE_SYNC_NON_DEFAULTLISTED)); 3107 } 3108 3109 // Returns TRUE if this display is in the Adaptive-Sync defaultlist 3110 NvBool nvDpyIsAdaptiveSyncDefaultlisted(const NVDpyEvoRec *pDpyEvo) 3111 { 3112 NV0073_CTRL_SPECIFIC_DEFAULT_ADAPTIVESYNC_DISPLAY_PARAMS params = { }; 3113 NVDispEvoPtr pDispEvo = pDpyEvo->pDispEvo; 3114 NVDevEvoPtr pDevEvo = pDispEvo->pDevEvo; 3115 NvU32 ret; 3116 3117 if (!pDpyEvo->parsedEdid.valid) { 3118 return FALSE; 3119 } 3120 3121 params.manufacturerID = pDpyEvo->parsedEdid.info.manuf_id; 3122 params.productID = pDpyEvo->parsedEdid.info.product_id; 3123 3124 ret = nvRmApiControl(nvEvoGlobal.clientHandle, 3125 pDevEvo->displayCommonHandle, 3126 NV0073_CTRL_CMD_SPECIFIC_DEFAULT_ADAPTIVESYNC_DISPLAY, 3127 ¶ms, sizeof(params)); 3128 3129 if (ret != NVOS_STATUS_SUCCESS) { 3130 nvEvoLogDisp(pDispEvo, EVO_LOG_ERROR, 3131 "Failed to query default adaptivesync listing for %s", pDpyEvo->name); 3132 return FALSE; 3133 } 3134 3135 return params.bDefaultAdaptivesync; 3136 } 3137 3138 static enum NvKmsDpyAttributeColorBpcValue GetYuv422MaxBpc( 3139 const NVDpyEvoRec *pDpyEvo) 3140 { 3141 const NVT_EDID_CEA861_INFO *p861Info = 3142 &pDpyEvo->parsedEdid.info.ext861; 3143 3144 nvAssert(nvDpyIsHdmiEvo(pDpyEvo) || 3145 nvConnectorUsesDPLib(pDpyEvo->pConnectorEvo)); 3146 3147 if (!pDpyEvo->parsedEdid.valid || 3148 !pDpyEvo->parsedEdid.info.input.isDigital) { 3149 return NV_KMS_DPY_ATTRIBUTE_CURRENT_COLOR_BPC_UNKNOWN; 3150 } 3151 3152 if (pDpyEvo->parsedEdid.info.version >= NVT_EDID_VER_1_4) { 3153 if (pDpyEvo->parsedEdid.info.u.feature_ver_1_4_digital.support_ycrcb_422) { 3154 if (pDpyEvo->parsedEdid.info.input.u.digital.bpc >= 10) { 3155 return NV_KMS_DPY_ATTRIBUTE_CURRENT_COLOR_BPC_10; 3156 } else if (pDpyEvo->parsedEdid.info.input.u.digital.bpc >= 8) { 3157 return NV_KMS_DPY_ATTRIBUTE_CURRENT_COLOR_BPC_8; 3158 } 3159 } 3160 } else { 3161 nvAssert(!nvConnectorUsesDPLib(pDpyEvo->pConnectorEvo)); 3162 3163 if (p861Info->revision >= NVT_CEA861_REV_A && 3164 !!(p861Info->basic_caps & NVT_CEA861_CAP_YCbCr_422)) { 3165 return NV_KMS_DPY_ATTRIBUTE_CURRENT_COLOR_BPC_10; 3166 } 3167 } 3168 3169 return NV_KMS_DPY_ATTRIBUTE_CURRENT_COLOR_BPC_UNKNOWN; 3170 } 3171 3172 NVColorFormatInfoRec nvGetColorFormatInfo(const NVDpyEvoRec *pDpyEvo) 3173 { 3174 const NVConnectorEvoRec *pConnectorEvo = 3175 pDpyEvo->pConnectorEvo; 3176 NVColorFormatInfoRec colorFormatsInfo = { }; 3177 3178 if (pConnectorEvo->legacyType == 3179 NV0073_CTRL_SPECIFIC_DISPLAY_TYPE_CRT) { 3180 3181 colorFormatsInfo.rgb444.maxBpc = 3182 NV_KMS_DPY_ATTRIBUTE_CURRENT_COLOR_BPC_10; 3183 } else if (pConnectorEvo->legacyType == 3184 NV0073_CTRL_SPECIFIC_DISPLAY_TYPE_DFP) { 3185 3186 if (pConnectorEvo->signalFormat == 3187 NVKMS_CONNECTOR_SIGNAL_FORMAT_DSI) { 3188 3189 if (pDpyEvo->parsedEdid.valid) { 3190 switch (pDpyEvo->parsedEdid.info.input.u.digital.bpc) { 3191 case 10: 3192 colorFormatsInfo.rgb444.maxBpc = 3193 NV_KMS_DPY_ATTRIBUTE_CURRENT_COLOR_BPC_10; 3194 break; 3195 case 6: 3196 colorFormatsInfo.rgb444.maxBpc = 3197 NV_KMS_DPY_ATTRIBUTE_CURRENT_COLOR_BPC_6; 3198 break; 3199 default: 3200 nvAssert(!"Unsupported bpc for DSI"); 3201 // fall through 3202 case 8: 3203 colorFormatsInfo.rgb444.maxBpc = 3204 NV_KMS_DPY_ATTRIBUTE_CURRENT_COLOR_BPC_8; 3205 break; 3206 } 3207 } else { 3208 colorFormatsInfo.rgb444.maxBpc = 3209 NV_KMS_DPY_ATTRIBUTE_CURRENT_COLOR_BPC_8; 3210 } 3211 } else if (nvConnectorUsesDPLib(pDpyEvo->pConnectorEvo)) { 3212 3213 if (pDpyEvo->parsedEdid.valid && 3214 pDpyEvo->parsedEdid.info.input.isDigital && 3215 pDpyEvo->parsedEdid.info.version >= NVT_EDID_VER_1_4) { 3216 if (pDpyEvo->parsedEdid.info.input.u.digital.bpc >= 10) { 3217 colorFormatsInfo.rgb444.maxBpc = 3218 NV_KMS_DPY_ATTRIBUTE_CURRENT_COLOR_BPC_10; 3219 } else if (pDpyEvo->parsedEdid.info.input.u.digital.bpc < 8) { 3220 colorFormatsInfo.rgb444.maxBpc = 3221 NV_KMS_DPY_ATTRIBUTE_CURRENT_COLOR_BPC_6; 3222 } else { 3223 colorFormatsInfo.rgb444.maxBpc = 3224 NV_KMS_DPY_ATTRIBUTE_CURRENT_COLOR_BPC_8; 3225 colorFormatsInfo.yuv444.maxBpc = 3226 NV_KMS_DPY_ATTRIBUTE_CURRENT_COLOR_BPC_8; 3227 } 3228 3229 colorFormatsInfo.yuv422.maxBpc = GetYuv422MaxBpc(pDpyEvo); 3230 } else { 3231 colorFormatsInfo.rgb444.maxBpc = 3232 NV_KMS_DPY_ATTRIBUTE_CURRENT_COLOR_BPC_8; 3233 } 3234 } else { 3235 colorFormatsInfo.rgb444.maxBpc = 3236 nvDpyIsHdmiDepth30Evo(pDpyEvo) ? 3237 NV_KMS_DPY_ATTRIBUTE_CURRENT_COLOR_BPC_10 : 3238 NV_KMS_DPY_ATTRIBUTE_CURRENT_COLOR_BPC_8; 3239 3240 if (nvDpyIsHdmiEvo(pDpyEvo)) { 3241 // TODO: Handle depth 30 YUV 3242 colorFormatsInfo.yuv444.maxBpc = 3243 NV_KMS_DPY_ATTRIBUTE_CURRENT_COLOR_BPC_8; 3244 colorFormatsInfo.yuv422.maxBpc = 3245 GetYuv422MaxBpc(pDpyEvo); 3246 } 3247 } 3248 } 3249 3250 return colorFormatsInfo; 3251 } 3252 3253 NvU32 nvDpyGetPossibleApiHeadsMask(const NVDpyEvoRec *pDpyEvo) 3254 { 3255 NvU32 possibleApiHeadMask = 0x0; 3256 NvU32 possibleNumLayers = NVKMS_MAX_LAYERS_PER_HEAD; 3257 const NVDevEvoRec *pDevEvo = pDpyEvo->pDispEvo->pDevEvo; 3258 3259 /* 3260 * DSI supports only the hardware head-0 assigment, and the 3261 * dp-serializer dpys are bound to the specific hardware head; 3262 * the modeset client can be allowed to choose only those 3263 * api-heads to drive these dpys which has the number of layers 3264 * less than or equal to the number of layers supported by the 3265 * bound hardware heads. 3266 */ 3267 if (pDpyEvo->pConnectorEvo->signalFormat == 3268 NVKMS_CONNECTOR_SIGNAL_FORMAT_DSI) { 3269 possibleNumLayers = pDevEvo->head[0].numLayers; 3270 } else if (nvConnectorIsDPSerializer(pDpyEvo->pConnectorEvo)) { 3271 const NvU32 boundHead = pDpyEvo->dp.serializerStreamIndex; 3272 possibleNumLayers = pDevEvo->head[boundHead].numLayers; 3273 } 3274 3275 for (NvU32 apiHead = 0; apiHead < pDevEvo->numApiHeads; apiHead++) { 3276 if (pDevEvo->apiHead[apiHead].numLayers <= possibleNumLayers) { 3277 possibleApiHeadMask |= NVBIT(apiHead); 3278 } 3279 } 3280 3281 return possibleApiHeadMask; 3282 } 3283 3284 NvBool nvDpyIsHDRCapable(const NVDpyEvoRec *pDpyEvo) 3285 { 3286 const NVDispEvoRec *pDispEvo = pDpyEvo->pDispEvo; 3287 const NVDevEvoRec *pDevEvo = pDispEvo->pDevEvo; 3288 3289 const NVT_EDID_INFO *pInfo = &pDpyEvo->parsedEdid.info; 3290 const NVT_HDR_STATIC_METADATA *pHdrInfo = 3291 &pInfo->hdr_static_metadata_info; 3292 3293 // Only supported on DP 1.3+ or HDMI 3294 if (nvDpyUsesDPLib(pDpyEvo)) { 3295 unsigned int major; 3296 unsigned int minor; 3297 3298 if(!pDevEvo->caps.supportsDP13) { 3299 return FALSE; 3300 } 3301 3302 if (!nvDPDpyGetDpcdRevision(pDpyEvo, &major, &minor)) { 3303 return FALSE; 3304 } 3305 3306 if ((major < 1) || (minor < 3)) { 3307 return FALSE; 3308 } 3309 } else if (!nvDpyIsHdmiEvo(pDpyEvo)) { 3310 return FALSE; 3311 } 3312 3313 if (!pDpyEvo->parsedEdid.valid) { 3314 return FALSE; 3315 } 3316 3317 /* 3318 * XXX HDR is not supported with HDMI 3D due to both using VSI 3319 * infoframes. 3320 */ 3321 if (pInfo->HDMI3DSupported) { 3322 return FALSE; 3323 } 3324 3325 // Sink should support ST2084 EOTF. 3326 if (!pHdrInfo->supported_eotf.smpte_st_2084_eotf) { 3327 return FALSE; 3328 } 3329 3330 /* 3331 * Sink should support static metadata type1. Nvtiming sets 3332 * static_metadata_type to 1 if the sink supports static metadata type1. 3333 */ 3334 if (pHdrInfo->static_metadata_type != 1) { 3335 return FALSE; 3336 } 3337 3338 return TRUE; 3339 } 3340