1 /* 2 * SPDX-FileCopyrightText: Copyright (c) 2011 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-connector.h" 25 #include "nvdp-timer.hpp" 26 #include "nvdp-connector-event-sink.hpp" 27 #include "dp/nvdp-connector-event-sink.h" 28 #include "dp/nvdp-timer.h" 29 30 #include "nvkms-evo.h" 31 #include "nvkms-types.h" 32 #include "nvkms-modeset.h" 33 #include "nvkms-utils.h" 34 #include "nvkms-rmapi.h" 35 36 #include <dp_connector.h> 37 38 // Loop over all display devices attached to a connector. 39 // Connector::enumDevices(NULL) returns the first device, and then 40 // enumDevices(previous) returns each subsequent device. 41 #define for_each_device(connector, dev) \ 42 for (DisplayPort::Device *(dev) = NULL; ((dev) = (connector)->enumDevices(dev)); ) 43 44 NVDPLibConnectorPtr nvDPCreateConnector(NVConnectorEvoPtr pConnectorEvo) 45 { 46 NVDevEvoPtr pDevEvo = pConnectorEvo->pDispEvo->pDevEvo; 47 DisplayPort::Timer *pTimer = &pDevEvo->dpTimer->timer; 48 NVDPLibConnectorPtr pNVDpLibConnector = 49 (NVDPLibConnectorPtr) nvCalloc(1, sizeof(*pNVDpLibConnector)); 50 51 if (!pNVDpLibConnector) { 52 return NULL; 53 } 54 55 pNVDpLibConnector->pConnectorEvo = pConnectorEvo; 56 57 // Create the EVO interface object. 58 pNVDpLibConnector->evoInterface = 59 new nvkmsDisplayPort::EvoInterface(pConnectorEvo); 60 if (!pNVDpLibConnector->evoInterface) { 61 goto fail; 62 } 63 64 // Create the event sink object. 65 pNVDpLibConnector->evtSink = 66 new nvkmsDisplayPort::ConnectorEventSink(pConnectorEvo); 67 if (!pNVDpLibConnector->evtSink) { 68 goto fail; 69 } 70 71 // Create the MainLink object. 72 pNVDpLibConnector->mainLink = 73 DisplayPort::MakeEvoMainLink(pNVDpLibConnector->evoInterface, pTimer); 74 if (!pNVDpLibConnector->mainLink) { 75 goto fail; 76 } 77 78 // Create the AuxBus object. 79 pNVDpLibConnector->auxBus = 80 DisplayPort::MakeEvoAuxBus(pNVDpLibConnector->evoInterface, pTimer); 81 if (!pNVDpLibConnector->auxBus) { 82 goto fail; 83 } 84 85 pNVDpLibConnector->connector = 86 DisplayPort::createConnector(pNVDpLibConnector->mainLink, 87 pNVDpLibConnector->auxBus, 88 pTimer, 89 pNVDpLibConnector->evtSink); 90 if (!pNVDpLibConnector->connector) { 91 goto fail; 92 } 93 94 pNVDpLibConnector->connector->setPolicyAssessLinkSafely(TRUE); 95 96 return pNVDpLibConnector; 97 98 fail: 99 nvDPDestroyConnector(pNVDpLibConnector); 100 return NULL; 101 } 102 103 void nvDPNotifyLongPulse(NVConnectorEvoPtr pConnectorEvo, 104 NvBool connected) 105 { 106 NVDPLibConnectorPtr pNVDpLibConnector = pConnectorEvo->pDpLibConnector; 107 DisplayPort::Connector *c = pNVDpLibConnector->connector; 108 109 pNVDpLibConnector->plugged = connected; 110 111 if (connected && !nvAssignSOREvo(pConnectorEvo, 0 /* sorExcludeMask */)) { 112 // DPLib takes care of skipping LT on unassigned SOR Display. 113 } 114 115 c->notifyLongPulse(connected); 116 117 } 118 119 void nvDPNotifyShortPulse(NVDPLibConnectorPtr pNVDpLibConnector) 120 { 121 DisplayPort::Connector *c = pNVDpLibConnector->connector; 122 123 c->notifyShortPulse(); 124 } 125 126 void nvDPDestroyConnector(NVDPLibConnectorPtr pNVDpLibConnector) 127 { 128 if (!pNVDpLibConnector) return; 129 130 if (pNVDpLibConnector->connector) { 131 pNVDpLibConnector->connector->destroy(); 132 } 133 if (pNVDpLibConnector->auxBus) { 134 delete pNVDpLibConnector->auxBus; 135 } 136 if (pNVDpLibConnector->mainLink) { 137 delete pNVDpLibConnector->mainLink; 138 } 139 if (pNVDpLibConnector->evoInterface) { 140 delete pNVDpLibConnector->evoInterface; 141 } 142 if (pNVDpLibConnector->evtSink) { 143 delete pNVDpLibConnector->evtSink; 144 } 145 146 nvFree(pNVDpLibConnector); 147 } 148 149 NvBool nvDPIsLinkAwaitingTransition(NVConnectorEvoPtr pConnectorEvo) 150 { 151 if (nvConnectorUsesDPLib(pConnectorEvo)) { 152 DisplayPort::Connector *c = pConnectorEvo->pDpLibConnector->connector; 153 return c->isLinkAwaitingTransition(); 154 } 155 156 return FALSE; 157 } 158 159 /* 160 * Start DisplayPort mode validation on all connectors on a disp. 161 */ 162 void nvDPBeginValidation(NVDispEvoPtr pDispEvo) 163 { 164 NVConnectorEvoPtr pConnectorEvo; 165 166 FOR_ALL_EVO_CONNECTORS(pConnectorEvo, pDispEvo) { 167 if (nvConnectorUsesDPLib(pConnectorEvo)) { 168 pConnectorEvo->pDpLibConnector->connector->beginCompoundQuery(); 169 } 170 } 171 } 172 173 /*! 174 * Create a new DisplayPort group and populate it with the devices specified by 175 * dpyIdList. For MST groups, this allocates a dynamic RM display ID. 176 * Otherwise, it uses the connector's display ID. 177 */ 178 static DisplayPort::Group* CreateGroup( 179 const NVDPLibConnectorRec *pDpLibConnector, 180 const NVDpyIdList dpyIdList) 181 { 182 NVDpyEvoPtr pDpyEvo; 183 DisplayPort::Group *pGroup = NULL; 184 185 pGroup = pDpLibConnector->connector->newGroup(); 186 if (pGroup == NULL) { 187 return NULL; 188 } 189 190 // Populate the group 191 FOR_ALL_EVO_DPYS(pDpyEvo, 192 dpyIdList, pDpLibConnector->pConnectorEvo->pDispEvo) { 193 if (pDpyEvo->dp.pDpLibDevice) { 194 pGroup->insert(pDpyEvo->dp.pDpLibDevice->device); 195 } 196 } 197 198 return pGroup; 199 } 200 201 static NvU32 GetColorDepth( 202 const enum NvKmsDpyAttributeCurrentColorSpaceValue colorSpace, 203 const enum NvKmsDpyAttributeColorBpcValue colorBpc) 204 { 205 switch (colorSpace) { 206 case NV_KMS_DPY_ATTRIBUTE_CURRENT_COLOR_SPACE_YCbCr420: 207 /* 208 * In YUV420, HW is programmed with RGB color space and full color 209 * range. The color space conversion and color range compression 210 * happen in a headSurface composite shader. 211 */ 212 case NV_KMS_DPY_ATTRIBUTE_CURRENT_COLOR_SPACE_YCbCr444: 213 case NV_KMS_DPY_ATTRIBUTE_CURRENT_COLOR_SPACE_RGB: 214 /* 215 * For RGB/YCbCr444, each pixel is always 3 components. For 216 * YCbCr/YUV420, we currently always scan out from the headSurface 217 * as RGB. 218 */ 219 return colorBpc * 3; 220 case NV_KMS_DPY_ATTRIBUTE_CURRENT_COLOR_SPACE_YCbCr422: 221 return colorBpc * 2; 222 } 223 224 return 0; 225 } 226 227 static void SetDPMSATiming(const NVDispEvoRec *pDispEvo, 228 const NvU32 displayId, 229 NV0073_CTRL_CMD_DP_SET_MSA_PROPERTIES_PARAMS *msaParams, 230 const NVHwModeTimingsEvo *pTimings) 231 { 232 nvkms_memset(msaParams, 0, sizeof(*msaParams)); 233 234 /* 235 * Fill in displayId and subDeviceInstance unconditionally. 236 * From CL#27980662, dplib started passing the client provided displayId 237 * to RM for setting MSA properties. 238 * Default value of displayId is 0, leading to RMControl failure in 239 * the displayport library. 240 */ 241 msaParams->subDeviceInstance = pDispEvo->displayOwner; 242 msaParams->displayId = displayId; 243 244 if ((pTimings->yuv420Mode == NV_YUV420_MODE_SW) && displayId != 0) { 245 NV0073_CTRL_DP_MSA_PROPERTIES_MASK *featureMask = &msaParams->featureMask; 246 NV0073_CTRL_DP_MSA_PROPERTIES_VALUES *featureValues = &msaParams->featureValues; 247 248 msaParams->bEnableMSA = 1; 249 msaParams->bCacheMsaOverrideForNextModeset = 1; 250 featureMask->bRasterTotalHorizontal = true; 251 featureMask->bActiveStartHorizontal = true; 252 featureMask->bSurfaceTotalHorizontal = true; 253 featureMask->bSyncWidthHorizontal = true; 254 featureValues->rasterTotalHorizontal = 2 * pTimings->rasterSize.x; 255 featureValues->activeStartHorizontal = 2 * (pTimings->rasterBlankEnd.x + 1); 256 featureValues->surfaceTotalHorizontal = 2 * nvEvoVisibleWidth(pTimings); 257 featureValues->syncWidthHorizontal = 2 * (pTimings->rasterSyncEnd.x + 1); 258 } 259 } 260 261 static void InitDpModesetParams( 262 const NVDispEvoRec *pDispEvo, 263 const NvU32 head, 264 const NvU32 displayId, 265 const NVHwModeTimingsEvo *pTimings, 266 const enum NvKmsDpyAttributeCurrentColorSpaceValue colorSpace, 267 const enum NvKmsDpyAttributeColorBpcValue colorBpc, 268 DisplayPort::DpModesetParams *pParams) 269 { 270 pParams->modesetInfo.pixelClockHz = pTimings->pixelClock * 1000; 271 pParams->modesetInfo.rasterWidth = pTimings->rasterSize.x; 272 pParams->modesetInfo.rasterHeight = pTimings->rasterSize.y; 273 pParams->modesetInfo.rasterBlankStartX = pTimings->rasterBlankStart.x; 274 pParams->modesetInfo.rasterBlankEndX = pTimings->rasterBlankEnd.x; 275 pParams->modesetInfo.surfaceWidth = nvEvoVisibleWidth(pTimings); 276 pParams->modesetInfo.surfaceHeight = nvEvoVisibleHeight(pTimings); 277 278 pParams->modesetInfo.depth = 279 GetColorDepth(colorSpace, colorBpc); 280 pParams->modesetInfo.bitsPerComponent = colorBpc; 281 282 pParams->colorFormat = dpColorFormat_Unknown; 283 switch (colorSpace) { 284 case NV_KMS_DPY_ATTRIBUTE_CURRENT_COLOR_SPACE_YCbCr420: 285 /* HW YUV420 mode is only supported for HDMI, not DP */ 286 nvAssert(pTimings->yuv420Mode == NV_YUV420_MODE_SW); 287 pParams->modesetInfo.pixelClockHz *= 2; 288 pParams->colorFormat = dpColorFormat_YCbCr420; 289 break; 290 case NV_KMS_DPY_ATTRIBUTE_CURRENT_COLOR_SPACE_YCbCr444: 291 pParams->colorFormat = dpColorFormat_YCbCr444; 292 break; 293 case NV_KMS_DPY_ATTRIBUTE_CURRENT_COLOR_SPACE_YCbCr422: 294 pParams->colorFormat = dpColorFormat_YCbCr422; 295 break; 296 case NV_KMS_DPY_ATTRIBUTE_CURRENT_COLOR_SPACE_RGB: 297 pParams->colorFormat = dpColorFormat_RGB; 298 break; 299 } 300 301 pParams->headIndex = head; 302 303 SetDPMSATiming(pDispEvo, displayId, &pParams->msaparams, pTimings); 304 } 305 306 NVDPLibModesetStatePtr nvDPLibCreateModesetState( 307 const NVDispEvoRec *pDispEvo, 308 const NvU32 head, 309 const NvU32 displayId, 310 const NVDpyIdList dpyIdList, 311 const enum NvKmsDpyAttributeCurrentColorSpaceValue colorSpace, 312 const enum NvKmsDpyAttributeColorBpcValue colorBpc, 313 NVHwModeTimingsEvo *pTimings) 314 { 315 bool found = false; 316 const NVDPLibConnectorRec *pDpLibConnector = NULL; 317 const NVDpyEvoRec *pDpyEvo; 318 NVDPLibModesetStatePtr pDpLibModesetState = NULL; 319 320 FOR_ALL_EVO_DPYS(pDpyEvo, dpyIdList, pDispEvo) { 321 if (!found) { 322 pDpLibConnector = pDpyEvo->pConnectorEvo->pDpLibConnector; 323 found = true; 324 } else if (pDpLibConnector != pDpyEvo->pConnectorEvo->pDpLibConnector) { 325 /* All Dpys must belongs to same DP connector */ 326 return NULL; 327 } 328 } 329 330 /* Do nothing if any of the display is not DP */ 331 if (pDpLibConnector == NULL) { 332 return NULL; 333 } 334 335 pDpLibModesetState = 336 (NVDPLibModesetStatePtr) nvCalloc(1, sizeof(*pDpLibModesetState)); 337 if (pDpLibModesetState == NULL) { 338 return NULL; 339 } 340 341 InitDpModesetParams(pDispEvo, 342 head, 343 displayId, 344 pTimings, 345 colorSpace, 346 colorBpc, 347 &pDpLibModesetState->modesetParams); 348 if (pTimings->dpDsc.enable) { 349 pDpLibModesetState->modesetParams.modesetInfo.bEnableDsc = true; 350 351 /* 352 * If DSC is enabled then override normal pixel depth with 353 * target bpp rate of DSC encoder, the rate at which it is going to 354 * output compressed stream. 355 */ 356 pDpLibModesetState->modesetParams.modesetInfo.depth = 357 pTimings->dpDsc.bitsPerPixelX16; 358 } 359 pDpLibModesetState->dpyIdList = dpyIdList; 360 361 return pDpLibModesetState; 362 } 363 364 void nvDPLibFreeModesetState(NVDPLibModesetStatePtr pDpLibModesetState) 365 { 366 nvFree(pDpLibModesetState); 367 } 368 369 /* 370 * Validate the mode for a given NVHwModeTimingsEvo + dpyIdList. This 371 * function should be called for each head, and must be called between 372 * nvDPBeginValidation and nvDPEndValidation. 373 * 374 * If validation fails, this function returns FALSE. You must still call 375 * nvDPEndValidation even if an individual head fails. 376 * 377 * If validation succeeds, the DSC fields within pTimings are updated with what 378 * is returned by compoundQueryAttach(). 379 */ 380 NvBool nvDPLibValidateTimings( 381 const NVDispEvoRec *pDispEvo, 382 const NvU32 head, 383 const NvU32 displayId, 384 const NVDpyIdList dpyIdList, 385 const enum NvKmsDpyAttributeCurrentColorSpaceValue colorSpace, 386 const enum NvKmsDpyAttributeColorBpcValue colorBpc, 387 const struct NvKmsModeValidationParams *pModeValidationParams, 388 NVHwModeTimingsEvo *pTimings) 389 { 390 const NVDpyEvoRec *pDpyEvo; 391 const NVDPLibConnectorRec *pDpLibConnector = NULL; 392 bool found = false; 393 394 DisplayPort::Group *pGroup = NULL; 395 DisplayPort::DscOutParams *pDscOutParams = NULL; 396 DisplayPort::DpModesetParams *pModesetParams = NULL; 397 DisplayPort::DscParams dpDscParams; 398 NvBool ret = FALSE; 399 400 FOR_ALL_EVO_DPYS(pDpyEvo, dpyIdList, pDispEvo) { 401 if (!found) { 402 pDpLibConnector = pDpyEvo->pConnectorEvo->pDpLibConnector; 403 found = true; 404 } else if (pDpLibConnector != pDpyEvo->pConnectorEvo->pDpLibConnector) { 405 /* All Dpys must belongs to same DP connector */ 406 return FALSE; 407 } 408 } 409 410 /* Do nothing if any of the display is not DP */ 411 if (pDpLibConnector == NULL) { 412 return TRUE; 413 } 414 415 pGroup = CreateGroup(pDpLibConnector, dpyIdList); 416 if (pGroup == NULL) { 417 nvEvoLogDisp(pDispEvo, EVO_LOG_ERROR, 418 "Failed to create a DisplayPort group"); 419 goto done; 420 } 421 422 pDscOutParams = 423 (DisplayPort::DscOutParams*) nvCalloc(1, sizeof(*pDscOutParams)); 424 if (pDscOutParams == NULL) { 425 goto done; 426 } 427 428 429 pModesetParams = 430 (DisplayPort::DpModesetParams*) nvCalloc(1, sizeof(*pModesetParams)); 431 if (pModesetParams == NULL) { 432 goto done; 433 } 434 435 InitDpModesetParams(pDispEvo, 436 head, 437 displayId, 438 pTimings, 439 colorSpace, 440 colorBpc, 441 pModesetParams); 442 443 dpDscParams.bCheckWithDsc = true; 444 dpDscParams.forceDsc = pModeValidationParams->forceDsc ? 445 DisplayPort::DSC_FORCE_ENABLE : 446 DisplayPort::DSC_DEFAULT; 447 dpDscParams.bitsPerPixelX16 = 448 pModeValidationParams->dscOverrideBitsPerPixelX16; 449 dpDscParams.pDscOutParams = pDscOutParams; 450 451 ret = pDpLibConnector->connector->compoundQueryAttach( 452 pGroup, *pModesetParams, 453 &dpDscParams); 454 455 if (ret) { 456 pTimings->dpDsc.enable = dpDscParams.bEnableDsc; 457 pTimings->dpDsc.bitsPerPixelX16 = dpDscParams.bitsPerPixelX16; 458 459 ct_assert(sizeof(pTimings->dpDsc.pps) == sizeof(pDscOutParams->PPS)); 460 461 nvkms_memcpy(pTimings->dpDsc.pps, 462 pDscOutParams->PPS, sizeof(pTimings->dpDsc.pps)); 463 } 464 465 done: 466 nvFree(pDscOutParams); 467 nvFree(pModesetParams); 468 if (pGroup != NULL) { 469 pGroup->destroy(); 470 } 471 return ret; 472 } 473 474 /* 475 * Finishes DisplayPort mode validation. Returns TRUE if the complete 476 * configuration is possible, and FALSE if it can't be achieved. 477 */ 478 NvBool nvDPEndValidation(NVDispEvoPtr pDispEvo) 479 { 480 NvBool ret = TRUE; 481 NVConnectorEvoPtr pConnectorEvo; 482 483 FOR_ALL_EVO_CONNECTORS(pConnectorEvo, pDispEvo) { 484 if (nvConnectorUsesDPLib(pConnectorEvo)) { 485 DisplayPort::Connector *connector = 486 pConnectorEvo->pDpLibConnector->connector; 487 488 /* endCompoundQuery() must be called for all dp connectors */ 489 ret = connector->endCompoundQuery() && ret; 490 } 491 } 492 493 return ret; 494 } 495 496 NvBool nvDPValidateModeForDpyEvo( 497 const NVDpyEvoRec *pDpyEvo, 498 const enum NvKmsDpyAttributeCurrentColorSpaceValue colorSpace, 499 const enum NvKmsDpyAttributeColorBpcValue colorBpc, 500 const struct NvKmsModeValidationParams *pModeValidationParams, 501 NVHwModeTimingsEvo *pTimings) 502 { 503 const NVConnectorEvoRec *pConnectorEvo = pDpyEvo->pConnectorEvo; 504 505 nvAssert(nvConnectorUsesDPLib(pConnectorEvo)); 506 507 DisplayPort::Connector *connector = 508 pConnectorEvo->pDpLibConnector->connector; 509 510 connector->beginCompoundQuery(); 511 NvBool ret = nvDPLibValidateTimings(pDpyEvo->pDispEvo, 512 0 /* head */, 513 0 /* displayId */, 514 nvAddDpyIdToEmptyDpyIdList(pDpyEvo->id), 515 colorSpace, 516 colorBpc, 517 pModeValidationParams, 518 pTimings); 519 connector->endCompoundQuery(); 520 521 return ret; 522 } 523 524 /* 525 * Notify the DisplayPort library that a given mode is about to be set on a 526 * given head. The configuration for this head must have previously been 527 * validated by a call to nvDPLibValidateTimings. 528 */ 529 static 530 void NotifyAttachBegin(NVDPLibConnectorPtr pDpLibConnector, 531 const NvU32 head, 532 const NVDPLibModesetStateRec *pDpLibModesetState) 533 { 534 const NVConnectorEvoRec *pConnectorEvo = pDpLibConnector->pConnectorEvo; 535 const NVDispEvoRec *pDispEvo = pConnectorEvo->pDispEvo; 536 const DisplayPort::DpModesetParams *pParams = 537 &pDpLibModesetState->modesetParams; 538 const NVDpyEvoRec *pDpyEvo = NULL; 539 540 /* Insert active dpys into group */ 541 pDpLibConnector->dpyIdList[head] = pDpLibModesetState->dpyIdList; 542 FOR_ALL_EVO_DPYS(pDpyEvo, pDpLibConnector->dpyIdList[head], pDispEvo) { 543 if (pDpyEvo->dp.pDpLibDevice) { 544 pDpLibConnector->pGroup[head]->insert( 545 pDpyEvo->dp.pDpLibDevice->device); 546 } 547 } 548 549 pDpLibConnector->connector->notifyAttachBegin( 550 pDpLibConnector->pGroup[head], 551 *pParams); 552 } 553 554 /* 555 * Notify the DisplayPort library that a modeset on a head begun by 556 * nvDPNotifyAttachBegin is finished. 557 */ 558 static void NotifyAttachEnd(NVDPLibConnectorPtr pDpLibConnector, NvU32 head) 559 { 560 pDpLibConnector->connector->notifyAttachEnd(false); 561 pDpLibConnector->headMask |= NVBIT(head); 562 } 563 564 /* 565 * Notify the DisplayPort library that the given head driving displays on this 566 * connector is about to be shut down. 567 */ 568 static void NotifyDetachBegin(NVDPLibConnectorPtr pDpLibConnector, const NvU32 head) 569 { 570 /* 571 * The firmware group is the VBIOS monitor group the DP Library manages 572 * internally. In notifyDetachBegin(NULL), the NULL defaults to firmware 573 * group. 574 */ 575 pDpLibConnector->connector->notifyDetachBegin( 576 pDpLibConnector->headInFirmware ? 577 NULL : pDpLibConnector->pGroup[head]); 578 } 579 580 /* 581 * Notify the DisplayPort library that the driver has finished shutting down a 582 * head that was previously driving this connector. 583 */ 584 static void NotifyDetachEnd(NVDPLibConnectorPtr pDpLibConnector, const NvU32 head) 585 { 586 pDpLibConnector->connector->notifyDetachEnd(); 587 588 if (!pDpLibConnector->headInFirmware) { 589 const NVConnectorEvoRec *pConnectorEvo = 590 pDpLibConnector->pConnectorEvo; 591 const NVDispEvoRec *pDispEvo = pConnectorEvo->pDispEvo; 592 const NVDpyEvoRec *pDpyEvo; 593 594 595 /* Empty inactive group */ 596 FOR_ALL_EVO_DPYS(pDpyEvo, pDpLibConnector->dpyIdList[head], pDispEvo) { 597 if (pDpyEvo->dp.pDpLibDevice) { 598 pDpLibConnector->pGroup[head]->remove( 599 pDpyEvo->dp.pDpLibDevice->device); 600 } 601 } 602 pDpLibConnector->dpyIdList[head] = nvEmptyDpyIdList(); 603 } else { 604 nvAssert(pDpLibConnector->pGroup[head]->enumDevices(0) == NULL); 605 pDpLibConnector->headInFirmware = false; 606 } 607 608 pDpLibConnector->headMask &= ~NVBIT(head); 609 } 610 611 /* 612 * Handles DP stream programming requires to be done before committing MODESET 613 * update. The function should be called for each of affected(change in 614 * head-connector attachment) DpLib connectors, before commit. 615 */ 616 void nvDPPreSetMode(NVDPLibConnectorPtr pDpLibConnector, 617 const NVEvoModesetUpdateState *pModesetUpdateState) 618 { 619 const NVConnectorEvoRec *pConnectorEvo = 620 pDpLibConnector->pConnectorEvo; 621 NVDispEvoRec *pDispEvo = pConnectorEvo->pDispEvo; 622 const NvU32 oldHeadMask = pDpLibConnector->headMask; 623 const NvU32 newHeadMask = 624 nvConnectorGetAttachedHeadMaskEvo(pConnectorEvo); 625 626 for (NvU32 head = 0; head < pDispEvo->pDevEvo->numHeads; head++) { 627 628 if ((newHeadMask & NVBIT(head)) != 0x0 && 629 (oldHeadMask & NVBIT(head)) == 0x0) { 630 631 NotifyAttachBegin(pDpLibConnector, 632 head, 633 pModesetUpdateState->pDpLibModesetState[head]); 634 635 } else if ((newHeadMask & NVBIT(head)) == 0x0 && 636 (oldHeadMask & NVBIT(head)) != 0x0) { 637 638 NotifyDetachBegin(pDpLibConnector, head); 639 640 } 641 } 642 } 643 644 /* 645 * Handles DP stream programming requires to be done before committing MODESET 646 * update. The function should be called for each of affected(change in 647 * head-connector attachment) DpLib connectors, before commit. 648 */ 649 void nvDPPostSetMode(NVDPLibConnectorPtr pDpLibConnector) 650 { 651 const NVConnectorEvoRec *pConnectorEvo = 652 pDpLibConnector->pConnectorEvo; 653 const NVDispEvoRec *pDispEvo = pConnectorEvo->pDispEvo; 654 const NvU32 oldHeadMask = pDpLibConnector->headMask; 655 const NvU32 newHeadMask = 656 nvConnectorGetAttachedHeadMaskEvo(pConnectorEvo); 657 658 for (NvU32 head = 0; head < pDispEvo->pDevEvo->numHeads; head++) { 659 660 if ((newHeadMask & NVBIT(head)) != 0x0 && 661 (oldHeadMask & NVBIT(head)) == 0x0) { 662 663 NotifyAttachEnd(pDpLibConnector, head); 664 665 } else if ((newHeadMask & NVBIT(head)) == 0x0 && 666 (oldHeadMask & NVBIT(head)) != 0x0) { 667 668 NotifyDetachEnd(pDpLibConnector, head); 669 670 } 671 } 672 673 /* 674 * Update DisplayPort link information for all displays on DpLib connector 675 */ 676 if (newHeadMask != oldHeadMask) { 677 NVDpyEvoPtr pDpyEvo; 678 679 FOR_ALL_EVO_DPYS(pDpyEvo, pDispEvo->validDisplays, pDispEvo) { 680 if (pDpyEvo->pConnectorEvo->pDpLibConnector == pDpLibConnector) { 681 nvDPLibUpdateDpyLinkConfiguration(pDpyEvo); 682 } 683 } 684 } 685 } 686 687 void nvDPPause(NVDPLibConnectorPtr pNVDpLibConnector) 688 { 689 DisplayPort::Connector *connector = pNVDpLibConnector->connector; 690 const NVConnectorEvoRec *pConnectorEvo = pNVDpLibConnector->pConnectorEvo; 691 const NVDispEvoRec *pDispEvo = pConnectorEvo->pDispEvo; 692 const NVDevEvoRec *pDevEvo = pDispEvo->pDevEvo; 693 694 if (!pNVDpLibConnector->isActive) { 695 return; 696 } 697 698 if (pDevEvo->skipConsoleRestore && pNVDpLibConnector->headMask != 0) { 699 /* Clear vbios DisplayPort RAD scratch registers, see bug 200471345 */ 700 701 nvAssert(nvPopCount32(pNVDpLibConnector->headMask) == 1); 702 nvAssert(connector->isDp11ProtocolForced()); 703 704 NV0073_CTRL_CMD_DP_CONFIG_RAD_SCRATCH_REG_PARAMS params = {0}; 705 706 params.subDeviceInstance = pDispEvo->displayOwner; 707 params.displayId = nvDpyIdToNvU32(pConnectorEvo->displayId); 708 709 nvAssert(pConnectorEvo->or.protocol == 710 NV0073_CTRL_SPECIFIC_OR_PROTOCOL_SOR_DP_A || 711 pConnectorEvo->or.protocol == 712 NV0073_CTRL_SPECIFIC_OR_PROTOCOL_SOR_DP_B); 713 714 params.dpLink = pConnectorEvo->or.protocol == 715 NV0073_CTRL_SPECIFIC_OR_PROTOCOL_SOR_DP_A ? 0 : 1; 716 params.sorIndex = nvEvoConnectorGetPrimaryOr(pConnectorEvo); 717 718 NvU32 ret = nvRmApiControl( 719 nvEvoGlobal.clientHandle, 720 pDevEvo->displayCommonHandle, 721 NV0073_CTRL_CMD_DP_CONFIG_RAD_SCRATCH_REG, 722 ¶ms, 723 sizeof(params)); 724 725 if (ret != NVOS_STATUS_SUCCESS) { 726 nvEvoLogDispDebug( 727 pDispEvo, 728 EVO_LOG_ERROR, 729 "NV0073_CTRL_CMD_DP_CONFIG_RAD_SCRATCH_REG " 730 "failed, error code 0x%x", 731 ret); 732 } 733 } 734 735 /* Before pausing DpLib, destroy group and clear head bitmask */ 736 for (NvU32 head = 0; head < ARRAY_LEN(pNVDpLibConnector->pGroup); head++) { 737 pNVDpLibConnector->pGroup[head]->destroy(); 738 } 739 pNVDpLibConnector->headMask = 0x0; 740 741 connector->pause(); 742 743 pNVDpLibConnector->isActive = false; 744 } 745 746 /*! 747 * Determine which head, if any, is driving this connector. 748 */ 749 static NvU32 GetFirmwareHead(NVConnectorEvoPtr pConnectorEvo) 750 { 751 NvU32 orIndex = nvEvoConnectorGetPrimaryOr(pConnectorEvo); 752 753 if (orIndex == NV_INVALID_OR || 754 pConnectorEvo->or.ownerHeadMask[orIndex] == 0) { 755 return NV_INVALID_HEAD; 756 } 757 758 return BIT_IDX_32(pConnectorEvo->or.ownerHeadMask[orIndex]); 759 } 760 761 /*! 762 * Determine whether an active connector shares an OR with this connector. 763 */ 764 static bool ConnectorIsSharedWithActiveOR(NVConnectorEvoPtr pConnectorEvo) 765 { 766 NVDispEvoPtr pDispEvo = pConnectorEvo->pDispEvo; 767 NVConnectorEvoPtr pOtherConnectorEvo; 768 769 FOR_ALL_EVO_CONNECTORS(pOtherConnectorEvo, pDispEvo) { 770 if (pOtherConnectorEvo != pConnectorEvo && 771 nvIsConnectorActiveEvo(pOtherConnectorEvo) && 772 (pOtherConnectorEvo->or.mask & pConnectorEvo->or.mask) != 0x0) { 773 return true; 774 } 775 } 776 777 return false; 778 } 779 780 NvBool nvDPResume(NVDPLibConnectorPtr pNVDpLibConnector, NvBool plugged) 781 { 782 NVConnectorEvoRec *pConnectorEvo = 783 pNVDpLibConnector->pConnectorEvo; 784 NVDispEvoPtr pDispEvo = pConnectorEvo->pDispEvo; 785 DisplayPort::Connector *c = pNVDpLibConnector->connector; 786 const unsigned int firmwareHead = GetFirmwareHead(pConnectorEvo); 787 const bool firmwareLinkHandsOff = ConnectorIsSharedWithActiveOR(pConnectorEvo); 788 bool dpyIdIsDynamic = false; 789 /* By default allow MST */ 790 bool allowMST = true; 791 792 if (firmwareHead != NV_INVALID_HEAD) { 793 NVDpyId firmwareDpyId = nvInvalidDpyId(); 794 795 pNVDpLibConnector->headInFirmware = true; 796 pNVDpLibConnector->headMask = NVBIT(firmwareHead); 797 798 // Use the first displayId in the boot display list. 799 // 800 // TODO: What should we do if more than one dpy ID is listed for a boot 801 // display? 802 nvAssert(nvCountDpyIdsInDpyIdList(pDispEvo->vbiosDpyConfig[firmwareHead]) == 1); 803 firmwareDpyId = 804 nvNextDpyIdInDpyIdListUnsorted(nvInvalidDpyId(), 805 pDispEvo->vbiosDpyConfig[firmwareHead]); 806 807 dpyIdIsDynamic = !nvDpyIdsAreEqual(firmwareDpyId, 808 pConnectorEvo->displayId); 809 810 /* Do not allow MST if firmware driving DP connector in SST mode */ 811 if (!dpyIdIsDynamic) { 812 allowMST = false; 813 } 814 } 815 816 pConnectorEvo->detectComplete = FALSE; 817 818 pNVDpLibConnector->plugged = plugged; 819 if (plugged && !pNVDpLibConnector->headInFirmware) { 820 NvBool ret = nvAssignSOREvo(pConnectorEvo, 0 /* sorExcludeMask */); 821 822 nvAssert(ret); 823 if (!ret) { 824 // DP lib skips LT for unassigned SOR. 825 } 826 } 827 828 c->resume(firmwareLinkHandsOff, 829 pNVDpLibConnector->headInFirmware, 830 plugged, 831 false /* isUefiSystem */, 832 firmwareHead, 833 dpyIdIsDynamic /* bFirmwareLinkUseMultistream */, 834 true /* bDisableVbiosScratchRegisterUpdate, bug 200471345 */, 835 allowMST); 836 837 for (NvU32 head = 0; head < ARRAY_LEN(pNVDpLibConnector->pGroup); head++) { 838 pNVDpLibConnector->pGroup[head] = 839 pNVDpLibConnector->connector->newGroup(); 840 841 if (pNVDpLibConnector->pGroup[head] == NULL) { 842 for (NvU32 i = 0; i < head; i++) { 843 pNVDpLibConnector->pGroup[i]->destroy(); 844 } 845 goto failed; 846 } 847 } 848 849 pNVDpLibConnector->isActive = true; 850 return TRUE; 851 852 failed: 853 pNVDpLibConnector->connector->pause(); 854 return FALSE; 855 } 856 857 void nvDPSetAllowMultiStreamingOneConnector( 858 NVDPLibConnectorPtr pDpLibConnector, 859 NvBool allowMST) 860 { 861 NVConnectorEvoRec *pConnectorEvo = 862 pDpLibConnector->pConnectorEvo; 863 864 if (pDpLibConnector->connector->getAllowMultiStreaming() == allowMST) { 865 return; 866 } 867 868 /* 869 * If there is change in MST capability and DPlib re-runs device detection 870 * routine for plugged sink. Reset 'pConnectorEvo->detectComplete' only for 871 * MST capable sinks, in order to track completion of that fresh detection 872 * routine. 873 */ 874 if (pDpLibConnector->plugged && 875 pDpLibConnector->connector->getSinkMultiStreamCap()) { 876 pConnectorEvo->detectComplete = FALSE; 877 } 878 pDpLibConnector->connector->setAllowMultiStreaming(allowMST); 879 } 880 881 static NvBool IsDpSinkMstCapableForceSst(const NVDispEvoRec *pDispEvo, 882 const NvU32 apiHead) 883 { 884 const NVDispApiHeadStateEvoRec *pApiHeadState = 885 &pDispEvo->apiHeadState[apiHead]; 886 const NVDpyEvoRec *pDpyEvo = 887 nvGetOneArbitraryDpyEvo(pApiHeadState->activeDpys, pDispEvo); 888 const NVConnectorEvoRec *pConnectorEvo = (pDpyEvo != NULL) ? 889 pDpyEvo->pConnectorEvo : NULL; 890 891 if ((pConnectorEvo == NULL) || 892 (pConnectorEvo->pDpLibConnector == NULL)) { 893 return FALSE; 894 } 895 896 DisplayPort::Connector *c = 897 pConnectorEvo->pDpLibConnector->connector; 898 899 return (c->getSinkMultiStreamCap() && !c->getAllowMultiStreaming()); 900 } 901 902 static NvBool IsDpLinkTransitionWaitingForHeadShutDown( 903 const NVDispEvoRec *pDispEvo, 904 const NvU32 apiHead) 905 { 906 const NVDispApiHeadStateEvoRec *pApiHeadState = 907 &pDispEvo->apiHeadState[apiHead]; 908 const NVDpyEvoRec *pDpyEvo = 909 nvGetOneArbitraryDpyEvo(pApiHeadState->activeDpys, pDispEvo); 910 911 return (pDpyEvo != NULL) && 912 nvDPIsLinkAwaitingTransition(pDpyEvo->pConnectorEvo); 913 } 914 915 void nvDPSetAllowMultiStreaming(NVDevEvoPtr pDevEvo, NvBool allowMST) 916 { 917 NvBool needUpdate = FALSE; 918 NVDispEvoPtr pDispEvo; 919 NvU32 dispIndex; 920 921 FOR_ALL_EVO_DISPLAYS(pDispEvo, dispIndex, pDevEvo) { 922 NVConnectorEvoPtr pConnectorEvo; 923 924 FOR_ALL_EVO_CONNECTORS(pConnectorEvo, pDispEvo) { 925 NVDPLibConnectorPtr pDpLibConnector = 926 pConnectorEvo->pDpLibConnector; 927 if (pDpLibConnector && 928 pDpLibConnector->connector->getAllowMultiStreaming() 929 != allowMST) { 930 needUpdate = TRUE; 931 } 932 } 933 } 934 935 if (!needUpdate) { 936 return; 937 } 938 939 nvShutDownApiHeads(pDevEvo, IsDpSinkMstCapableForceSst); 940 941 /* 942 * Heads driving MST capable sinks in force SST mode, are shut down. Now you 943 * can allow MST on all DisplayPort Connector, safely in compliance 944 * of DP 1.2 specification. 945 * 946 * The section 5.4 and table 2-75 (of section 2.9.3.1) of DisplayPort 1.2 947 * specification, does not allow to enable/disable MST mode of sink while 948 * transmitting active stream (see description of CL#25551338). 949 */ 950 FOR_ALL_EVO_DISPLAYS(pDispEvo, dispIndex, pDevEvo) { 951 NVConnectorEvoPtr pConnectorEvo; 952 953 FOR_ALL_EVO_CONNECTORS(pConnectorEvo, pDispEvo) { 954 if (!pConnectorEvo->pDpLibConnector) { 955 continue; 956 } 957 nvDPSetAllowMultiStreamingOneConnector( 958 pConnectorEvo->pDpLibConnector, 959 allowMST); 960 } 961 } 962 963 /* Shut down all DisplayPort heads that need to transition to/from SST. */ 964 nvShutDownApiHeads(pDevEvo, 965 IsDpLinkTransitionWaitingForHeadShutDown); 966 967 /* 968 * Handle any pending timers the DP library scheduled to notify us 969 * about changes in the connected device list. 970 */ 971 nvDPFireExpiredTimers(pDevEvo); 972 } 973 974 enum NVDpLinkMode nvDPGetActiveLinkMode(NVDPLibConnectorPtr pDpLibConnector) 975 { 976 DisplayPort::LinkConfiguration linkConfig = 977 pDpLibConnector->connector->getActiveLinkConfig(); 978 if (linkConfig.lanes == 0) { 979 return NV_DP_LINK_MODE_OFF; 980 } 981 return linkConfig.multistream ? NV_DP_LINK_MODE_MST : 982 NV_DP_LINK_MODE_SST; 983 } 984