1 /* 2 * SPDX-FileCopyrightText: Copyright (c) 1993-2022 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 "nvrm_registry.h" 25 #include "objtmr.h" 26 #include "gpu/external_device/gsync.h" 27 #include "dev_p2060.h" 28 #include "gpu/external_device/dac_p2060.h" 29 #include "gpu_mgr/gpu_mgr.h" 30 #include "gpu/disp/kern_disp.h" 31 #include "rmapi/rmapi_utils.h" 32 #include "class/cl402c.h" // NV40_I2C 33 #include "kernel/gpu/i2c/i2c_api.h" 34 /* 35 * statics 36 */ 37 38 static NvBool GpuIsP2060Master (OBJGPU *, PDACP2060EXTERNALDEVICE); 39 static NvBool GpuIsP2060Connected(OBJGPU *, PDACP2060EXTERNALDEVICE); 40 static NvBool GpuIsMosaicTimingSlave(OBJGPU *, PDACP2060EXTERNALDEVICE); 41 static NvBool GpuIsConnectedToMasterViaBridge(OBJGPU *, PDACP2060EXTERNALDEVICE); 42 43 static OBJGPU* GetP2060MasterableGpu (OBJGPU *, PDACP2060EXTERNALDEVICE); 44 static OBJGPU* GetP2060WatchdogGpu (OBJGPU *, PDACP2060EXTERNALDEVICE); 45 46 static NV_STATUS GetP2060GpuLocation (OBJGPU *, PDACP2060EXTERNALDEVICE, NvU32*); 47 static NV_STATUS GetP2060ConnectorIndexFromGpu (OBJGPU *, PDACP2060EXTERNALDEVICE, NvU32*); 48 static NvU32 GetP2060GpuSnapshot (OBJGPU *, PDACP2060EXTERNALDEVICE); 49 50 static void gsyncProgramFramelockEnable_P2060(OBJGPU *, PDACP2060EXTERNALDEVICE, NvU32, NvBool); 51 static NvBool gsyncIsStereoEnabled_p2060 (OBJGPU *, PDACEXTERNALDEVICE); 52 static NV_STATUS gsyncProgramExtStereoPolarity_P2060 (OBJGPU *, PDACEXTERNALDEVICE); 53 54 static NV_STATUS gsyncProgramSlaves_P2060(OBJGPU *, PDACP2060EXTERNALDEVICE, NvU32); 55 static NvU32 gsyncReadSlaves_P2060(OBJGPU *, PDACP2060EXTERNALDEVICE); 56 static NV_STATUS gsyncProgramMaster_P2060(OBJGPU *, PDACP2060EXTERNALDEVICE, NvU32, NvBool, NvBool); 57 static NvU32 gsyncReadMaster_P2060(OBJGPU *, PDACP2060EXTERNALDEVICE); 58 59 static NV_STATUS gsyncUpdateGsyncStatusSnapshot_P2060(OBJGPU *, PDACEXTERNALDEVICE); 60 61 static void gsyncCancelWatchdog_P2060(PDACP2060EXTERNALDEVICE); 62 static NV_STATUS gsyncDisableFrameLockInterrupt_P2060(PDACEXTERNALDEVICE); 63 static NV_STATUS gsyncEnableFramelockInterrupt_P2060(PDACEXTERNALDEVICE); 64 static NV_STATUS gsyncDisableNonFramelockInterrupt_P2060(OBJGPU *, PDACEXTERNALDEVICE); 65 static NV_STATUS gsyncEnableNonFramelockInterrupt_P2060(OBJGPU *, PDACEXTERNALDEVICE); 66 static void gsyncResetMosaicData_P2060(NvU32, PDACP2060EXTERNALDEVICE); 67 static NV_STATUS gsyncUpdateSwapRdyConnectionForGpu_P2060(OBJGPU *, PDACP2060EXTERNALDEVICE, NvBool); 68 69 static NvBool gsyncIsFrameLocked_P2060(PDACP2060EXTERNALDEVICE); 70 static NvBool gsyncIsOnlyFrameLockMaster_P2060(PDACP2060EXTERNALDEVICE); 71 static NvBool gsyncIsFrameLockMaster_P2060(PDACP2060EXTERNALDEVICE); 72 static NvBool gsyncIsP2060MasterBoard(OBJGPU *, PDACP2060EXTERNALDEVICE); 73 74 static NV_STATUS gsyncSetLsrMinTime(OBJGPU *, PDACEXTERNALDEVICE, NvU32); 75 76 static NV_STATUS gsyncUpdateFrameCount_P2060(PDACP2060EXTERNALDEVICE, OBJGPU *); 77 static NvU32 gsyncGetNumberOfGpuFrameCountRollbacks_P2060(NvU32, NvU32, NvU32); 78 static NV_STATUS gsyncFrameCountTimerService_P2060(OBJGPU *, OBJTMR *, void *); 79 static NV_STATUS gsyncResetFrameCountData_P2060(OBJGPU *, PDACP2060EXTERNALDEVICE); 80 81 static NV_STATUS gsyncGpuStereoHeadSync(OBJGPU *, NvU32, PDACEXTERNALDEVICE, NvU32); 82 static NvBool supportsMulDiv(DACEXTERNALDEVICE *); 83 static NvBool needsMasterBarrierWar(PDACEXTERNALDEVICE); 84 static NvBool isFirmwareRevMismatch(OBJGPU *, DAC_EXTERNAL_DEVICE_REVS); 85 86 static NvBool isBoardWithNvlinkQsyncContention(OBJGPU *); 87 static void _extdevService(NvU32 , void *); 88 89 NvBool 90 extdevGetDevice_P2060 91 ( 92 OBJGPU *pGpu, 93 PDACEXTERNALDEVICE pExternalDevice 94 ) 95 { 96 NvU8 revId; 97 NvU8 data; 98 DAC_EXTERNAL_DEVICES externalDeviceId; 99 DAC_EXTERNAL_DEVICE_REVS externalDeviceRev; 100 NV_STATUS status; 101 102 if (!RMCFG_FEATURE_EXTDEV_GSYNC_P2060 || 103 IS_EMULATION(pGpu) || IS_SIMULATION(pGpu)) 104 { 105 return NV_FALSE; 106 } 107 108 // Read the FPGA revision register 109 status = readregu008_extdevice(pGpu, pExternalDevice, (NvU8)NV_P2060_FPGA, &data); 110 if (status != NV_OK) 111 { 112 return NV_FALSE; 113 } 114 revId = data; 115 116 // Decode the register value into device ID 117 if (DRF_VAL(_P2060, _FPGA, _ID, data) == NV_P2060_FPGA_ID_5) 118 { 119 externalDeviceId = DAC_EXTERNAL_DEVICE_P2060; 120 } 121 else if (DRF_VAL(_P2061, _FPGA, _ID, data) == NV_P2061_FPGA_ID_4) 122 { 123 externalDeviceId = DAC_EXTERNAL_DEVICE_P2061; 124 } 125 else 126 { 127 return NV_FALSE; 128 } 129 130 // Decode the register value into device revision (major revision) 131 externalDeviceRev = DRF_VAL(_P2060, _FPGA, _REV, data); 132 133 // Read device extended revision (minor revision) 134 status = readregu008_extdevice(pGpu, pExternalDevice, (NvU8)NV_P2060_FPGA_EXREV, &data); 135 if (status != NV_OK) 136 { 137 return NV_FALSE; 138 } 139 140 // Caching revId, device ID, device revision, and device extended revision 141 pExternalDevice->revId = revId; 142 pExternalDevice->deviceId = externalDeviceId; 143 pExternalDevice->deviceRev = externalDeviceRev; 144 pExternalDevice->deviceExRev = data; 145 146 return NV_TRUE; 147 } 148 149 /* 150 * Return Extdev with setting of the data structures and 151 * function pointers for P2060. 152 */ 153 PDACEXTERNALDEVICE 154 extdevConstruct_P2060 155 ( 156 OBJGPU *pGpu, 157 PDACEXTERNALDEVICE pExternalDevice 158 ) 159 { 160 DACP2060EXTERNALDEVICE *pThis = (PDACP2060EXTERNALDEVICE)pExternalDevice; 161 KernelDisplay *pKernelDisplay = GPU_GET_KERNEL_DISPLAY(pGpu); 162 NvU32 iface, head, i; 163 NvU32 numHeads = kdispGetNumHeads(pKernelDisplay); 164 165 if ( !extdevConstruct_Base(pGpu, pExternalDevice) ) 166 { 167 return 0; 168 } 169 170 // Setup interfaces 171 pThis->ExternalDevice.pI->Destroy = extdevDestroy_P2060; 172 pThis->ExternalDevice.pI->Attach = gsyncAttachExternalDevice_P2060; 173 174 pThis->ExternalDevice.pI->GetDevice = extdevGetDevice_P2060; 175 pThis->ExternalDevice.pI->Init = extdevInit_P2060; 176 177 pThis->ExternalDevice.pI->Service = extdevService_P2060; 178 pThis->ExternalDevice.pI->Watchdog = extdevWatchdog_P2060; 179 pThis->ExternalDevice.pI->setI2cHandles = extdevSaveI2cHandles_P2060; 180 181 182 // Init data members 183 pThis->ExternalDevice.I2CAddr = 0x20; 184 pThis->ExternalDevice.I2CPort = pGpu->i2cPortForExtdev; 185 pThis->ExternalDevice.MaxGpus = NV_P2060_MAX_IFACES_PER_GSYNC * NV_P2060_MAX_GPUS_PER_IFACE; 186 187 pThis->gpuAttachMask = 0; 188 pThis->id = 0; 189 pThis->watchdogCountDownValue = 0; 190 pThis->isNonFramelockInterruptEnabled = NV_FALSE; 191 pThis->interruptEnabledInterface = 0; 192 pThis->tSwapRdyHi = 0; 193 pThis->tSwapRdyHiLsrMinTime = 0; 194 195 //init FrameCountData 196 pThis->FrameCountData.totalFrameCount = 0; 197 pThis->FrameCountData.currentFrameCount = 0; 198 pThis->FrameCountData.initialDifference = 0; 199 pThis->FrameCountData.numberOfRollbacks = 0; 200 pThis->FrameCountData.previousFrameCount = 0; 201 pThis->FrameCountData.lastFrameCounterQueryTime = 0; 202 pThis->FrameCountData.bReCheck = 0; 203 pThis->FrameCountData.vActive = 0; 204 pThis->FrameCountData.isFrmCmpMatchIntMasterEnabled = NV_FALSE; 205 pThis->FrameCountData.enableFrmCmpMatchIntSlave = NV_FALSE; 206 pThis->FrameCountData.head = NV_P2060_MAX_HEADS_PER_GPU; 207 pThis->FrameCountData.iface = NV_P2060_MAX_IFACES_PER_GSYNC; 208 209 for (iface = 0; iface < NV_P2060_MAX_IFACES_PER_GSYNC; iface++) 210 { 211 pThis->Iface[iface].GpuInfo.gpuId = NV0000_CTRL_GPU_INVALID_ID; 212 pThis->Iface[iface].GpuInfo.connected = NV_FALSE; 213 214 pThis->Iface[iface].RasterSyncGpio.saved = NV_FALSE; 215 pThis->Iface[iface].DsiFliplock.saved = NV_FALSE; 216 217 for (head = 0; head < numHeads; head++) 218 { 219 pThis->Iface[iface].Sync.Master[head] = 0; 220 pThis->Iface[iface].Sync.Slaved[head] = 0; 221 pThis->Iface[iface].Sync.LocalSlave[head] = 0; 222 } 223 224 pThis->Iface[iface].lastEventNotified = 0; 225 pThis->Iface[iface].gainedSync = 0; 226 227 pThis->i2cHandles[iface].hClient = 0; 228 pThis->i2cHandles[iface].hDevice = 0; 229 pThis->i2cHandles[iface].hSubdevice = 0; 230 pThis->i2cHandles[iface].hSubscription = 0; 231 pThis->i2cHandles[iface].gpuId = 0; 232 } 233 234 //init MosaicData 235 for (i = 0; i < NV_P2060_MAX_MOSAIC_GROUPS; i++) 236 { 237 gsyncResetMosaicData_P2060(i, pThis); 238 } 239 240 return pExternalDevice; 241 } 242 243 /* 244 * setup device registers 245 */ 246 static void 247 _externalDeviceInit_P2060 248 ( 249 OBJGPU *pGpu, 250 NvBool bExtDevFound 251 ) 252 { 253 KernelDisplay *pKernelDisplay = GPU_GET_KERNEL_DISPLAY(pGpu); 254 RM_API *pRmApi = GPU_GET_PHYSICAL_RMAPI(pGpu); 255 NvU32 hClient = pGpu->hInternalClient; 256 NvU32 hSubdevice = pGpu->hInternalSubdevice; 257 NV_STATUS status = NV_OK; 258 NV2080_CTRL_INTERNAL_GSYNC_ATTACH_AND_INIT_PARAMS ctrlParams = {0}; 259 260 ctrlParams.bExtDevFound = bExtDevFound; 261 262 status = pRmApi->Control(pRmApi, hClient, hSubdevice, 263 NV2080_CTRL_CMD_INTERNAL_GSYNC_ATTACH_AND_INIT, 264 &ctrlParams, sizeof(ctrlParams)); 265 266 if (status != NV_OK) 267 { 268 NV_PRINTF(LEVEL_ERROR, "Extdev GPIO interrupt enable failed\n"); 269 } 270 else 271 { 272 pKernelDisplay->bExtdevIntrSupported = NV_TRUE; 273 } 274 275 return; 276 } 277 278 NV_STATUS 279 gsyncFindGpuHandleLocation 280 ( 281 DACEXTERNALDEVICE *pExternalDevice, 282 NvU32 gpuId, 283 NvU32 *iface 284 ) 285 { 286 DACP2060EXTERNALDEVICE *pThis = (PDACP2060EXTERNALDEVICE)pExternalDevice; 287 NvU32 tempIface; 288 NV_STATUS rmStatus = NV_ERR_GENERIC; 289 290 for (tempIface = 0; tempIface < NV_P2060_MAX_IFACES_PER_GSYNC; tempIface++) 291 { 292 if (pThis->i2cHandles[tempIface].gpuId == gpuId) 293 { 294 *iface = tempIface; 295 rmStatus = NV_OK; 296 } 297 } 298 299 return rmStatus; 300 } 301 302 static NV_STATUS 303 gsyncFindFreeHandleLocation 304 ( 305 DACP2060EXTERNALDEVICE *pThis, 306 NvU32 *iface 307 ) 308 { 309 NvU32 tempIface; 310 NV_STATUS rmStatus = NV_ERR_GENERIC; 311 312 for (tempIface = 0; tempIface < NV_P2060_MAX_IFACES_PER_GSYNC; tempIface++) 313 { 314 if (pThis->i2cHandles[tempIface].gpuId == 0) 315 { 316 *iface = tempIface; 317 rmStatus = NV_OK; 318 } 319 } 320 321 return rmStatus; 322 } 323 324 NvBool 325 extdevSaveI2cHandles_P2060 326 ( 327 OBJGPU *pGpu, 328 DACEXTERNALDEVICE *pExternalDevice 329 ) 330 { 331 DACP2060EXTERNALDEVICE *pThis = (PDACP2060EXTERNALDEVICE)pExternalDevice; 332 RM_API *pRmApi = rmapiGetInterface(RMAPI_GPU_LOCK_INTERNAL); 333 NvHandle hClient; 334 NvHandle hDevice; 335 NvHandle hSubdevice; 336 NvHandle hSubscription = NV01_NULL_OBJECT; 337 NvU32 iface; 338 NV_STATUS rmStatus; 339 340 rmStatus = gsyncFindFreeHandleLocation(pThis, &iface); 341 if (rmStatus != NV_OK) 342 { 343 NV_PRINTF(LEVEL_ERROR, "Maximum number of GPUs have been attached\n"); 344 return NV_FALSE; 345 } 346 347 rmStatus = rmapiutilAllocClientAndDeviceHandles(pRmApi, 348 pGpu, &hClient, &hDevice, &hSubdevice); 349 NV_ASSERT_OR_RETURN(rmStatus == NV_OK, NV_FALSE); 350 351 rmStatus = pRmApi->Alloc(pRmApi, hClient, hSubdevice, 352 &hSubscription, NV40_I2C, NULL); 353 354 NV_ASSERT_OR_RETURN(rmStatus == NV_OK, NV_FALSE); 355 356 pThis->i2cHandles[iface].hClient = hClient; 357 pThis->i2cHandles[iface].hDevice = hDevice; 358 pThis->i2cHandles[iface].hSubdevice = hSubdevice; 359 pThis->i2cHandles[iface].hSubscription = hSubscription; 360 pThis->i2cHandles[iface].gpuId = pGpu->gpuId; 361 362 return NV_TRUE; 363 } 364 365 NV_STATUS 366 i2c_extdeviceHelper 367 ( 368 OBJGPU *pGpu, 369 DACEXTERNALDEVICE *pExternalDevice, 370 NvU32 i2cPort, 371 NvU8 SubAdr, 372 NvU8 *pData, 373 NvBool write 374 ) 375 { 376 RM_API *pRmApi = rmapiGetInterface(RMAPI_GPU_LOCK_INTERNAL); 377 DACP2060EXTERNALDEVICE *pThis = (PDACP2060EXTERNALDEVICE)pExternalDevice; 378 NV_STATUS status = NV_ERR_GENERIC; 379 NvU32 iface; 380 NV402C_CTRL_I2C_TRANSACTION_PARAMS *pParams; 381 382 pParams = portMemAllocNonPaged(sizeof(*pParams)); 383 if (pParams == NULL) 384 { 385 return NV_ERR_NO_MEMORY; 386 } 387 388 status = gsyncFindGpuHandleLocation(pExternalDevice, pGpu->gpuId, &iface); 389 if (status != NV_OK) 390 { 391 NV_PRINTF(LEVEL_ERROR, "Couldn't find saved GPU entry, check saved i2chandles. \n"); 392 return status; 393 } 394 395 portMemSet(pParams, 0, sizeof(*pParams)); 396 397 pParams->portId = (NvU8)i2cPort; 398 pParams->transType = NV402C_CTRL_I2C_TRANSACTION_TYPE_SMBUS_BYTE_RW; 399 pParams->deviceAddress = (NvU16)pExternalDevice->I2CAddr; 400 401 pParams->transData.smbusByteData.bWrite = write; 402 pParams->transData.smbusByteData.registerAddress = SubAdr; 403 if (write) 404 { 405 pParams->transData.smbusByteData.message = *pData; 406 } 407 408 status = pRmApi->Control(pRmApi, pThis->i2cHandles[iface].hClient, 409 pThis->i2cHandles[iface].hSubscription, 410 NV402C_CTRL_CMD_I2C_TRANSACTION, 411 pParams, sizeof(*pParams)); 412 413 if (!write) 414 { 415 *pData = pParams->transData.smbusByteData.message; 416 } 417 418 portMemFree(pParams); 419 420 return status; 421 } 422 423 /* 424 * Initialize P2060 for all GPUs in loop. 425 */ 426 NvBool 427 extdevInit_P2060 428 ( 429 OBJGPU *pGpu, 430 PDACEXTERNALDEVICE pExternalDevice 431 ) 432 { 433 OBJGPU *pGpuTemp; 434 OBJSYS *pSys = SYS_GET_INSTANCE(); 435 OBJGSYNC *pGsyncTemp = NULL; 436 NvU32 gpuAttachCnt, gpuAttachMask, gpuInstance; 437 NvU32 data; 438 439 if (!GpuIsP2060Connected(pGpu, (PDACP2060EXTERNALDEVICE)pExternalDevice)) 440 { 441 return NV_FALSE; 442 } 443 444 if (NV_OK != gsyncProgramExtStereoPolarity_P2060(pGpu, pExternalDevice)) 445 { 446 return NV_FALSE; 447 } 448 449 // Check regkeys 450 if (NV_OK == osReadRegistryDword(pGpu, NV_REG_STR_RM_QSYNC_FW_REV_CHECK, &data)) 451 { 452 if (NV_REG_STR_RM_QSYNC_FW_REV_CHECK_DISABLE == data) 453 { 454 pSys->setProperty(pSys, PDB_PROP_SYS_IS_QSYNC_FW_REVISION_CHECK_DISABLED, NV_TRUE); 455 } 456 } 457 458 // Initialize SyncPolarity to FALLING_EDGE. Refer Bug 1035880 459 if (NV_OK != gsyncSetSyncPolarity_P2060(pGpu, pExternalDevice, gsync_SyncPolarity_FallingEdge)) 460 { 461 return NV_FALSE; 462 } 463 464 // get count of all other gpus in the system 465 gpumgrGetGpuAttachInfo(&gpuAttachCnt, &gpuAttachMask); 466 467 // loop over 468 gpuInstance = 0; 469 while ((pGpuTemp = gpumgrGetNextGpu(gpuAttachMask, &gpuInstance)) != NULL) 470 { 471 pGsyncTemp = gsyncmgrGetGsync(pGpuTemp); 472 473 if (!pGsyncTemp || !pGsyncTemp->pExtDev) 474 continue; 475 476 _externalDeviceInit_P2060(pGpuTemp, (pGpu == pGpuTemp)); 477 } 478 479 return NV_TRUE; 480 } 481 482 static NV_STATUS 483 gsyncReadBoardId_P2060 484 ( 485 OBJGPU *pGpu, 486 PDACEXTERNALDEVICE pExternalDevice, 487 NvU32 *uniqueId 488 ) 489 { 490 NvU8 i, id = 0; 491 NV_STATUS rmStatus = NV_OK; 492 493 *uniqueId = 0; 494 for (i = 0; i < 4; i++) 495 { 496 rmStatus = readregu008_extdeviceTargeted(pGpu, pExternalDevice, 497 NV_P2060_FPGA_ASGN_ID(i), &id); 498 if (rmStatus != NV_OK) 499 { 500 return rmStatus; 501 } 502 *uniqueId |= id << (i * 8); 503 } 504 return NV_OK; 505 } 506 507 /* 508 * Attach P2060 to GPU on correct connector index. 509 */ 510 NvBool 511 gsyncAttachExternalDevice_P2060 512 ( 513 OBJGPU *pGpu, 514 PDACEXTERNALDEVICE *ppExtdevs 515 ) 516 { 517 OBJSYS *pSys = SYS_GET_INSTANCE(); 518 OBJGSYNCMGR *pGsyncMgr = SYS_GET_GSYNCMGR(pSys); 519 OBJGSYNC *pGsync = NULL; 520 OBJGPU *pOtherGpu = NULL; 521 DACP2060EXTERNALDEVICE *pThis, *pExt2060Temp; 522 NvU8 i, id = 0, regCtrl2 = 0; 523 NvU32 iface, connector, uniqueId = 0, pOtherGpuId = 0, bSkipResetForVM = 0, index = 0; 524 NvU32 tempIface; 525 NvBool bExtDevFound = NV_FALSE; 526 NV_STATUS rmStatus = NV_OK; 527 NvU8 ctrl = 0; 528 529 rmStatus = gsyncReadBoardId_P2060(pGpu, *ppExtdevs, &uniqueId); 530 if (rmStatus != NV_OK) 531 { 532 NV_PRINTF(LEVEL_ERROR, "failed to read P2060 device Id.\n"); 533 return NV_FALSE; 534 } 535 536 if (uniqueId != 0x0) 537 { 538 // HW says another GPU has been here first. Confirm this from SW. 539 for (i = 0; i < NV30F1_MAX_GSYNCS; i++) 540 { 541 if (pGsyncMgr->gsyncTable[i].gpuCount) 542 { 543 pGsync = &pGsyncMgr->gsyncTable[i]; 544 if (pGsync->pExtDev) 545 { 546 pThis = (PDACP2060EXTERNALDEVICE) pGsync->pExtDev; 547 if (pThis->id == uniqueId) 548 { 549 pOtherGpuId = pGsync->gpus[0].gpuId; 550 bExtDevFound = NV_TRUE; 551 } 552 } 553 } 554 555 if (bExtDevFound) 556 { 557 break; 558 } 559 } 560 561 if (!bExtDevFound) 562 { 563 if ((IS_PASSTHRU(pGpu))) 564 { 565 // look for master board 566 rmStatus = readregu008_extdeviceTargeted(pGpu, *ppExtdevs, 567 (NvU8)NV_P2060_CONTROL, &ctrl); 568 if (rmStatus != NV_OK) 569 { 570 NV_PRINTF(LEVEL_ERROR, "Failed to read Ctrl data.\n"); 571 return NV_FALSE; 572 } 573 574 pThis = (PDACP2060EXTERNALDEVICE)*ppExtdevs; 575 bSkipResetForVM = FLD_TEST_DRF(_P2060, _CONTROL, _I_AM, _MASTER, (NvU32)ctrl); 576 rmStatus = GetP2060ConnectorIndexFromGpu(pGpu, pThis, &index); 577 578 if (rmStatus != NV_OK) 579 { 580 NV_PRINTF(LEVEL_ERROR, "Failed to get connector index for Gpu.\n"); 581 return NV_FALSE; 582 } 583 584 // Look for SYNC source gpu. 585 bSkipResetForVM = bSkipResetForVM && !(DRF_VAL(_P2060, _CONTROL, _SYNC_SRC, (NvU32)ctrl) == index); 586 } 587 588 if (!bSkipResetForVM) 589 { 590 // ExtDev is not preset in pGsyncMgr. Issue RESET to P2060 HW. 591 regCtrl2 = FLD_SET_DRF_NUM(_P2060, _CONTROL2, _RESET, NV_TRUE, regCtrl2); 592 writeregu008_extdeviceTargeted(pGpu, *ppExtdevs, 593 NV_P2060_CONTROL2, regCtrl2); 594 595 osDelay(5); // Add delay of 5ms before I2C read as board is in reset phase. 596 597 rmStatus = gsyncReadBoardId_P2060(pGpu, *ppExtdevs, &uniqueId); 598 if ((rmStatus != NV_OK) || (uniqueId != 0)) 599 { 600 NV_PRINTF(LEVEL_ERROR, 601 "failed to read P2060 device Id after reset.\n"); 602 return NV_FALSE; 603 } 604 } 605 } 606 else 607 { 608 pOtherGpu = gpumgrGetGpuFromId(pOtherGpuId); 609 pGsync = gsyncmgrGetGsync(pOtherGpu); 610 611 if (!pGsync || !pGsync->pExtDev) 612 { 613 NV_ASSERT(0); 614 return NV_FALSE; 615 } 616 617 NV_ASSERT(pGsync->pExtDev != *ppExtdevs); 618 619 pThis = (PDACP2060EXTERNALDEVICE)*ppExtdevs; 620 pExt2060Temp = (PDACP2060EXTERNALDEVICE)(pGsync->pExtDev); 621 622 rmStatus = gsyncFindFreeHandleLocation(pExt2060Temp, &iface); 623 if (rmStatus != NV_OK) 624 { 625 NV_PRINTF(LEVEL_ERROR, "Failed to free index for new GPU entry. \n"); 626 return NV_FALSE; 627 } 628 629 rmStatus = gsyncFindGpuHandleLocation(*ppExtdevs, pGpu->gpuId, &tempIface); 630 if (rmStatus != NV_OK) 631 { 632 NV_PRINTF(LEVEL_ERROR, "Couldn't find saved GPU entry, check extdevSaveI2cHandles. \n"); 633 return NV_FALSE; 634 } 635 636 pExt2060Temp->i2cHandles[iface].gpuId = pThis->i2cHandles[tempIface].gpuId; 637 pExt2060Temp->i2cHandles[iface].hClient = pThis->i2cHandles[tempIface].hClient; 638 pExt2060Temp->i2cHandles[iface].hDevice = pThis->i2cHandles[tempIface].hDevice; 639 pExt2060Temp->i2cHandles[iface].hSubdevice = pThis->i2cHandles[tempIface].hSubdevice; 640 pExt2060Temp->i2cHandles[iface].hSubscription = pThis->i2cHandles[tempIface].hSubscription; 641 642 pThis->ExternalDevice.pI->Destroy(pGpu, *ppExtdevs); 643 644 // Free our current pointer and replace it 645 portMemFree(*ppExtdevs); 646 *ppExtdevs = pGsync->pExtDev; 647 } 648 } 649 650 pThis = (PDACP2060EXTERNALDEVICE)*ppExtdevs; 651 652 if (uniqueId == 0x0) 653 { 654 // Use pGpu->gpuId as unique value. 655 uniqueId = pGpu->gpuId; 656 657 for (i = 0; i < 4; i++) 658 { 659 id = (NvU8)(uniqueId >> (i * 8)); 660 rmStatus = writeregu008_extdeviceTargeted(pGpu, *ppExtdevs, 661 NV_P2060_FPGA_ASGN_ID(i), 662 id); 663 if (rmStatus != NV_OK) 664 { 665 NV_PRINTF(LEVEL_ERROR, "failed to update P2060 device Id.\n"); 666 return NV_FALSE; 667 } 668 } 669 pThis->id = uniqueId; 670 } 671 672 rmStatus = GetP2060ConnectorIndexFromGpu(pGpu, pThis, &iface); 673 if (rmStatus != NV_OK) 674 { 675 NV_PRINTF(LEVEL_ERROR, "failed to find P2060 connector.\n"); 676 return NV_FALSE; 677 } 678 679 // 680 // Add 1 to index we got from status2 register read beacuse connector 681 // NV30F1_CTRL_GET_GSYNC_GPU_TOPOLOGY_ONE start with value 1. 682 // 683 connector = iface + 1; 684 685 // 686 // If adding a check before the gsyncAttachGpu call and returning before 687 // that please add the following code: 688 // pThis->gpuAttachMask &= ~NVBIT(pGpu->gpuInstance); 689 // (*ppExtdevs)->ReferenceCount--; 690 // before returning NV_FALSE so that the caller can destroy the 691 // ext device structure. The destroy funciton only decrements the ref count 692 // if the gpu has already been attached. 693 // 694 (*ppExtdevs)->ReferenceCount++; 695 pThis->gpuAttachMask |= NVBIT(pGpu->gpuInstance); 696 697 pThis->Iface[iface].GpuInfo.gpuId = pGpu->gpuId; 698 pThis->Iface[iface].GpuInfo.connected = NV_TRUE; 699 700 rmStatus = gsyncAttachGpu(*ppExtdevs, pGpu, connector, NULL, (*ppExtdevs)->deviceId); 701 702 if (rmStatus != NV_OK) 703 { 704 NV_PRINTF(LEVEL_ERROR, "failed to attach P2060 gsync to gpu.\n"); 705 return NV_FALSE; 706 } 707 708 if (pThis->ExternalDevice.deviceId == DAC_EXTERNAL_DEVICE_P2061) 709 { 710 pGpu->setProperty(pGpu, PDB_PROP_GPU_QSYNC_II_ATTACHED, NV_TRUE); 711 } 712 else 713 { 714 NV_ASSERT(pThis->ExternalDevice.deviceId == DAC_EXTERNAL_DEVICE_P2060); 715 pGpu->setProperty(pGpu, PDB_PROP_GPU_GSYNC_III_ATTACHED, NV_TRUE); 716 } 717 718 if (!pThis->isNonFramelockInterruptEnabled) 719 { 720 rmStatus = gsyncEnableNonFramelockInterrupt_P2060(pGpu, *ppExtdevs); 721 if (rmStatus != NV_OK) 722 { 723 NV_PRINTF(LEVEL_ERROR, 724 "Failed to enable non-framelock interrupts on gsync GPU.\n"); 725 return NV_FALSE; 726 } 727 pThis->isNonFramelockInterruptEnabled = NV_TRUE; 728 pThis->interruptEnabledInterface = iface; 729 } 730 731 return NV_TRUE; 732 } 733 734 /* 735 * Destroy the device P2060. 736 */ 737 void 738 extdevDestroy_P2060 739 ( 740 OBJGPU *pGpu, 741 PDACEXTERNALDEVICE pExternalDevice 742 ) 743 { 744 DACP2060EXTERNALDEVICE *pThis = (PDACP2060EXTERNALDEVICE)pExternalDevice; 745 RM_API *pRmApi = rmapiGetInterface(RMAPI_GPU_LOCK_INTERNAL); 746 KernelDisplay *pKernelDisplay = GPU_GET_KERNEL_DISPLAY(pGpu); 747 NvU32 iface, head; 748 NvU32 numHeads = kdispGetNumHeads(pKernelDisplay); 749 NvU8 ctrl2 = 0; 750 NV_STATUS rmStatus; 751 752 for (iface = 0; iface < NV_P2060_MAX_IFACES_PER_GSYNC; iface++) 753 { 754 if (pThis->Iface[iface].GpuInfo.gpuId == pGpu->gpuId) 755 { 756 pThis->gpuAttachMask &= ~NVBIT(pGpu->gpuInstance); 757 pExternalDevice->ReferenceCount--; 758 759 if (pThis->Iface[iface].GpuInfo.connected) 760 { 761 if (pExternalDevice->ReferenceCount == 0) 762 { 763 // clear id for this gsync device. 764 pThis->id = 0; 765 766 // reset the gsync hw 767 ctrl2 = FLD_SET_DRF_NUM(_P2060, _CONTROL2, _RESET, NV_TRUE, ctrl2); 768 writeregu008_extdeviceTargeted(pGpu, pExternalDevice, 769 NV_P2060_CONTROL2, ctrl2); 770 } 771 } 772 773 // Restore saved swap lockout window values that may not have 774 // been restored by disabling swap barriers. 775 if (pThis->Iface[iface].DsiFliplock.saved == NV_TRUE) 776 { 777 for (head = 0; head < numHeads; head++) 778 { 779 kdispRestoreOriginalLsrMinTime_HAL(pGpu, pKernelDisplay, head, 780 pThis->Iface[iface].DsiFliplock.OrigLsrMinTime[head]); 781 } 782 pThis->Iface[iface].DsiFliplock.saved = NV_FALSE; 783 } 784 785 gsyncRemoveGpu(pGpu); 786 787 pThis->Iface[iface].GpuInfo.gpuId = NV0000_CTRL_GPU_INVALID_ID; 788 pThis->Iface[iface].GpuInfo.connected = NV_FALSE; 789 790 pGpu->setProperty(pGpu, PDB_PROP_GPU_GSYNC_III_ATTACHED, NV_FALSE); 791 pGpu->setProperty(pGpu, PDB_PROP_GPU_QSYNC_II_ATTACHED, NV_FALSE); 792 793 rmStatus = gsyncFindGpuHandleLocation(pExternalDevice, pGpu->gpuId, &iface); 794 if (rmStatus != NV_OK) 795 { 796 NV_PRINTF(LEVEL_ERROR, "Couldn't find saved GPU entry, check saved i2chandles. \n"); 797 goto cleanup; 798 } 799 800 rmapiutilFreeClientAndDeviceHandles(pRmApi, 801 &pThis->i2cHandles[iface].hClient, 802 &pThis->i2cHandles[iface].hDevice, 803 &pThis->i2cHandles[iface].hSubdevice); 804 805 pThis->i2cHandles[iface].hClient = 0; 806 pThis->i2cHandles[iface].hDevice = 0; 807 pThis->i2cHandles[iface].hSubdevice = 0; 808 pThis->i2cHandles[iface].hSubscription = 0; 809 pThis->i2cHandles[iface].gpuId = 0; 810 811 break; 812 } 813 } 814 815 cleanup: 816 if (pExternalDevice->ReferenceCount == 0) 817 { 818 // And continue the chain running. 819 extdevDestroy_Base(pGpu, pExternalDevice); 820 } 821 } 822 823 /* 824 * Handles the loss/gain of sync and other interrupts. 825 */ 826 void 827 extdevService_P2060 828 ( 829 OBJGPU *pGpu, 830 PDACEXTERNALDEVICE pExtDev, 831 NvU8 lossRegStatus, 832 NvU8 gainRegStatus, 833 NvU8 miscRegStatus, 834 NvBool rmStatus 835 ) 836 { 837 OBJOS *pOS = GPU_GET_OS(pGpu); 838 EXTDEV_INTR_DATA intrData; 839 840 if (!rmStatus) 841 { 842 return; 843 } 844 845 intrData.lossRegStatus = lossRegStatus; 846 intrData.gainRegStatus = gainRegStatus; 847 intrData.miscRegStatus = miscRegStatus; 848 intrData.pExtDevice = pExtDev; 849 850 if (IS_GSP_CLIENT(pGpu)) 851 { 852 EXTDEV_INTR_DATA *workerThreadData = NULL; 853 854 workerThreadData = portMemAllocNonPaged(sizeof(EXTDEV_INTR_DATA)); 855 if (NULL != workerThreadData) 856 { 857 *workerThreadData = intrData; 858 } 859 else 860 { 861 NV_PRINTF(LEVEL_ERROR, "Memalloc failed\n"); 862 } 863 864 // Attempt to queue a work item. 865 if (NV_OK != pOS->osQueueWorkItemWithFlags(pGpu, 866 _extdevService, 867 (void *)workerThreadData, 868 OS_QUEUE_WORKITEM_FLAGS_LOCK_GPU_GROUP_SUBDEVICE_RW)) 869 { 870 portMemFree((void *)workerThreadData); 871 } 872 } 873 else 874 { 875 _extdevService(gpuGetInstance(pGpu), (void *)&intrData); 876 } 877 } 878 879 static void 880 _extdevService 881 ( 882 NvU32 gpuInstance, 883 void *workerThreadData 884 ) 885 { 886 OBJGPU *pGpu = gpumgrGetGpu(gpuInstance); 887 NV_STATUS rmStatus; 888 889 EXTDEV_INTR_DATA intrData = *(EXTDEV_INTR_DATA *)workerThreadData; 890 PDACP2060EXTERNALDEVICE pThis = (PDACP2060EXTERNALDEVICE)intrData.pExtDevice; 891 NvU32 iface, ifaceEvents[NV_P2060_MAX_IFACES_PER_GSYNC]; 892 893 rmStatus = gsyncUpdateGsyncStatusSnapshot_P2060(pGpu, intrData.pExtDevice); 894 if (rmStatus != NV_OK) 895 { 896 NV_PRINTF(LEVEL_ERROR, 897 "Couldn't raad the register status physical RMs.\n"); 898 return; 899 } 900 rmStatus = GetP2060GpuLocation(pGpu, pThis, &iface); 901 if (rmStatus != NV_OK) 902 { 903 NV_PRINTF(LEVEL_ERROR, 904 "Cannot get P2060 Gpu location for serving interrupt.\n"); 905 return; 906 } 907 908 ifaceEvents[iface] = 0x00; 909 910 if (intrData.lossRegStatus) //lost signal interrupts 911 { 912 if (DRF_VAL(_P2060, _STATUS4, _SYNC, (NvU32)intrData.lossRegStatus)) 913 { 914 ifaceEvents[iface] |= NVBIT(NV30F1_GSYNC_NOTIFIERS_SYNC_LOSS(iface)); 915 } 916 if (DRF_VAL(_P2060, _STATUS4, _STEREO, (NvU32)intrData.lossRegStatus)) 917 { 918 ifaceEvents[iface] |= NVBIT(NV30F1_GSYNC_NOTIFIERS_STEREO_LOSS(iface)); 919 } 920 if (DRF_VAL(_P2060, _STATUS4, _HS, (NvU32)intrData.lossRegStatus)) 921 { 922 ifaceEvents[iface] |= NVBIT(NV30F1_GSYNC_NOTIFIERS_HOUSE_LOSS); 923 } 924 if (DRF_VAL(_P2060, _STATUS4, _RJ45, (NvU32)intrData.lossRegStatus)) 925 { 926 ifaceEvents[iface] |= NVBIT(NV30F1_GSYNC_NOTIFIERS_RJ45_LOSS); 927 } 928 929 // 930 // Enable the watchdog again if we got any loss events. 931 // Otherise sync gain tracking and stereo sync won't work as desired. 932 // 933 if (ifaceEvents[iface]) 934 { 935 extdevScheduleWatchdog(pGpu, (PDACEXTERNALDEVICE)pThis); 936 if (!gsyncIsOnlyFrameLockMaster_P2060(pThis)) 937 { 938 pThis->watchdogCountDownValue = NV_P2060_WATCHDOG_COUNT_DOWN_VALUE; 939 } 940 } 941 942 if (ifaceEvents[iface] && (pThis->Iface[iface].lastEventNotified != ifaceEvents[iface])) 943 { 944 gsyncSignalServiceRequested(gsyncGetGsyncInstance(pGpu), ifaceEvents[iface], iface); 945 pThis->Iface[iface].lastEventNotified = ifaceEvents[iface]; 946 } 947 } 948 949 if (intrData.gainRegStatus) //Gain signal interrupts 950 { 951 if (DRF_VAL(_P2060, _STATUS4, _SYNC, (NvU32)intrData.gainRegStatus)) 952 { 953 ifaceEvents[iface] |= NVBIT(NV30F1_GSYNC_NOTIFIERS_SYNC_GAIN(iface)); 954 } 955 if (DRF_VAL(_P2060, _STATUS4, _STEREO, (NvU32)intrData.gainRegStatus)) 956 { 957 ifaceEvents[iface] |= NVBIT(NV30F1_GSYNC_NOTIFIERS_STEREO_GAIN(iface)); 958 } 959 if (DRF_VAL(_P2060, _STATUS4, _HS, (NvU32)intrData.gainRegStatus)) 960 { 961 ifaceEvents[iface] |= NVBIT(NV30F1_GSYNC_NOTIFIERS_HOUSE_GAIN); 962 } 963 if (DRF_VAL(_P2060, _STATUS4, _RJ45, (NvU32)intrData.gainRegStatus)) 964 { 965 ifaceEvents[iface] |= NVBIT(NV30F1_GSYNC_NOTIFIERS_RJ45_GAIN); 966 } 967 968 if (ifaceEvents[iface] && (pThis->Iface[iface].lastEventNotified != ifaceEvents[iface])) 969 { 970 gsyncSignalServiceRequested(gsyncGetGsyncInstance(pGpu), ifaceEvents[iface], iface); 971 pThis->Iface[iface].lastEventNotified = ifaceEvents[iface]; 972 } 973 } 974 975 if (intrData.miscRegStatus) //Other interrupts 976 { 977 if (FLD_TEST_DRF(_P2060, _STATUS4, _FRM_CNT_MATCH_INT, _PENDING, (NvU32)intrData.miscRegStatus)) 978 { 979 // 980 // To enable frameCountTimerService callback to verify the cached difference 1 second 981 // after the test signal is received. 982 // 983 pThis->FrameCountData.bReCheck = 1; 984 985 // 986 // Reset framecountData.Therefore whenever user queries after frame compare 987 // interrupt, gsync and gpu frame count register are read and difference is cached again. 988 // 989 // This will also disable frame compare match interrupt, which will be then enabled 990 // frame compare match interrupt in the next user query or in FrameCountTimerService. 991 // This is required to clear frmCmpInt bit of status1 register. A read to status1 992 // register should clear it, but it is possible that the read to status1 register by 993 // calling gsyncUpdateGsyncStatusSnapshot_P2060() function above may happen in the same 994 // frame and this would result interrupt to come back again setting frmCmpint bit. 995 // 996 rmStatus |= gsyncResetFrameCountData_P2060(pGpu, pThis); 997 998 if (rmStatus == NV_OK) 999 { 1000 // 1001 // Set enableFrmCmpMatchInt flag NV_TRUE and return. This indicates 1002 // that the frame compare match interrupt for slave needs to be 1003 // enabled, which is done in the next user query or in 1004 // FrameCountTimerService callback. 1005 // 1006 pThis->FrameCountData.enableFrmCmpMatchIntSlave = NV_TRUE; 1007 } 1008 } 1009 1010 if (FLD_TEST_DRF(_P2060, _STATUS4, _ERROR_INT, _PENDING, (NvU32)intrData.miscRegStatus)) 1011 { 1012 // Some error condition observed. Update snapshot 1013 rmStatus = gsyncUpdateGsyncStatusSnapshot_P2060(pGpu, intrData.pExtDevice); 1014 if (rmStatus != NV_OK) 1015 { 1016 return; 1017 } 1018 } 1019 } 1020 } 1021 1022 /* 1023 * waits for hardware to (re-)establish sync. 1024 * once sync obtains, the watchdog enables interrupt, de-sechedules 1025 * itself, and waits for an interrupt to go off before running again. 1026 */ 1027 NV_STATUS 1028 extdevWatchdog_P2060 1029 ( 1030 OBJGPU *pGpu, 1031 OBJTMR *pTmr, 1032 PDACEXTERNALDEVICE pExtDev 1033 ) 1034 { 1035 KernelDisplay *pKernelDisplay = GPU_GET_KERNEL_DISPLAY(pGpu); 1036 PDACP2060EXTERNALDEVICE pThis = (PDACP2060EXTERNALDEVICE)pExtDev; 1037 NvU32 iface, head; 1038 NvBool bStereoLocked; 1039 NV_STATUS rmStatus = NV_OK; 1040 NvBool bStereoEnabled[NV_P2060_MAX_IFACES_PER_GSYNC]; 1041 NvU32 numHeads = kdispGetNumHeads(pKernelDisplay); 1042 1043 if (pThis->watchdogCountDownValue) 1044 pThis->watchdogCountDownValue--; 1045 1046 // we now can trust our selection of GPU 1047 pGpu = GetP2060WatchdogGpu(pGpu, pThis); 1048 NV_ASSERT(pGpu); 1049 1050 // schedule the next callback. we can cancel, if it's not needed. 1051 extdevScheduleWatchdog(pGpu, (PDACEXTERNALDEVICE)pThis); 1052 1053 rmStatus = gsyncUpdateGsyncStatusSnapshot_P2060(pGpu, pExtDev); 1054 1055 if (!gsyncIsFrameLocked_P2060(pThis)) 1056 { 1057 gsyncCancelWatchdog_P2060(pThis); 1058 rmStatus = gsyncDisableFrameLockInterrupt_P2060((PDACEXTERNALDEVICE)pThis); 1059 return rmStatus; 1060 } 1061 1062 for (iface = 0; iface < NV_P2060_MAX_IFACES_PER_GSYNC; iface++) 1063 { 1064 OBJGPU *pTmpGpu = NULL; 1065 if (pThis->Iface[iface].GpuInfo.gpuId == NV0000_CTRL_GPU_INVALID_ID) 1066 { 1067 continue; 1068 } 1069 pTmpGpu = gpumgrGetGpuFromId(pThis->Iface[iface].GpuInfo.gpuId); 1070 1071 NV_ASSERT(pTmpGpu); 1072 1073 // figure out if stereo is enabled 1074 bStereoEnabled[iface] = gsyncIsStereoEnabled_p2060(pTmpGpu, pExtDev); 1075 1076 // loop over the heads of the current gpu on this interface 1077 for ( head = 0; head < numHeads; head++ ) 1078 { 1079 if (pThis->Iface[iface].Sync.Slaved[head] || 1080 pThis->Iface[iface].Sync.LocalSlave[head]) 1081 { 1082 bStereoLocked = FLD_TEST_DRF(_P2060, _STATUS, _STEREO, _LOCK, 1083 (NvU32)pThis->Snapshot[iface].Status1); 1084 1085 // check for sync and locks, noting that all heads share the status 1086 if ((pThis->Iface[iface].gainedSync) && 1087 (!bStereoEnabled[iface] || bStereoLocked)) 1088 { 1089 break; 1090 } 1091 else 1092 { 1093 return NV_ERR_GENERIC; // hope things are better, on next watchdog run 1094 } 1095 } 1096 } 1097 } 1098 1099 if ( NV_OK == rmStatus && pKernelDisplay->bExtdevIntrSupported 1100 && !pThis->watchdogCountDownValue) 1101 { 1102 NV_PRINTF(LEVEL_INFO, "P2060[%d] extdevCancelWatchdog.\n", iface); 1103 1104 // disable the watchdog, 1105 extdevCancelWatchdog(pGpu, (PDACEXTERNALDEVICE)pThis); 1106 1107 // enable the framelock interrupt, if either Master or Slaves are desired 1108 gsyncEnableFramelockInterrupt_P2060((PDACEXTERNALDEVICE)pThis); 1109 } 1110 1111 return NV_OK; 1112 } 1113 1114 static NV_STATUS 1115 gsyncApplyStereoPinAlwaysHiWar 1116 ( 1117 OBJGPU *pGpu, 1118 PDACEXTERNALDEVICE pExtDev 1119 ) 1120 { 1121 1122 return NV_OK; 1123 1124 } 1125 1126 static NV_STATUS 1127 gsyncUnApplyStereoPinAlwaysHiWar 1128 ( 1129 OBJGPU *pGpu 1130 ) 1131 { 1132 1133 return NV_OK; 1134 1135 } 1136 1137 // 1138 // gsyncReadUniversalFrameCount_P2060() 1139 // 1140 // When user queries for the first time or after 10 seconds, Gsync and Gpu 1141 // hardware framecount are read and then the difference between them is cached. 1142 // For rest of the instances whenever user queries for frame count, gpu 1143 // frame count is read, and software framecount is updated accordingly based 1144 // on previous cached values. 1145 // 1146 static NV_STATUS 1147 gsyncReadUniversalFrameCount_P2060 1148 ( 1149 OBJGPU *pGpu, 1150 PDACEXTERNALDEVICE pExtDev, 1151 NvU32 *pFrameCount 1152 ) 1153 { 1154 OBJGPU *pTmpGpu = NULL; 1155 KernelDisplay *pKernelDisplay = NULL; 1156 PDACP2060EXTERNALDEVICE pThis = (PDACP2060EXTERNALDEVICE) pExtDev; 1157 NV_STATUS rmStatus = NV_OK; 1158 NvU32 lineCount; 1159 NvU32 frameCount; 1160 NvS32 calculatedDiff; 1161 NvU64 currentTime = 0; 1162 NvU64 queryTimeDiff; 1163 OBJTMR *pTmpTmr = NULL; 1164 OBJTMR *pTmr = GPU_GET_TIMER(pGpu); 1165 1166 if (!(pThis->FrameCountData.iface == NV_P2060_MAX_IFACES_PER_GSYNC)) 1167 { 1168 // 1169 // pThis->FrameCountData.iface exists. 1170 // Thus deriving pTmpGpu from it, and to maintain consistency reading the time from it. 1171 // 1172 pTmpGpu = gpumgrGetGpuFromId(pThis->Iface[pThis->FrameCountData.iface].GpuInfo.gpuId); 1173 1174 if (pTmpGpu) 1175 { 1176 pTmpTmr = GPU_GET_TIMER(pTmpGpu); 1177 currentTime = tmrGetTime_HAL(pTmpGpu, pTmpTmr); 1178 } 1179 } 1180 1181 if (currentTime == 0) 1182 { 1183 // pTmpGpu doesn't exists, so getting the time from pGpu. 1184 currentTime = tmrGetTime_HAL(pGpu, pTmr); 1185 } 1186 1187 if (NV_P2060_STATUS_SYNC_LOSS_TRUE == DRF_VAL(_P2060, _STATUS, _SYNC_LOSS, GetP2060GpuSnapshot(pGpu,pThis))) 1188 { 1189 // don't increment the frame counter in case of sync loss 1190 *pFrameCount = pThis->FrameCountData.totalFrameCount; 1191 pThis->FrameCountData.lastFrameCounterQueryTime = currentTime; 1192 1193 return NV_OK; 1194 } 1195 1196 queryTimeDiff = currentTime - pThis->FrameCountData.lastFrameCounterQueryTime; 1197 1198 // 1199 // If user queries for the first time or after 10 secs then read gsync and 1200 // gpu frame count registers and update software frame count and cached 1201 //difference. Also enable the frmCmpMatchInt if not enabled. 1202 // 1203 if ((!pThis->FrameCountData.lastFrameCounterQueryTime) || 1204 (queryTimeDiff > 2 * NV_P2060_FRAME_COUNT_TIMER_INTERVAL)) 1205 { 1206 // 1207 // P2060 refreshrate is in 0.00001 Hz, so divide by 10000 to get Hz. 1208 // divide 1000000 by refreshRate to get the frame time in us. 1209 // 1210 pThis->FrameCountData.frameTime = 1000000 / (pThis->RefreshRate/10000); //in us 1211 1212 // 1213 // Enable FrameCountTimerService to verify FrameCountData.initialDifference. 1214 // 1215 pThis->FrameCountData.bReCheck = 1; 1216 1217 rmStatus = gsyncUpdateFrameCount_P2060(pThis, pGpu); 1218 *pFrameCount = pThis->FrameCountData.totalFrameCount; 1219 1220 // enable frame count match interrupt if not master 1221 if (!gsyncIsFrameLockMaster_P2060(pThis)) 1222 { 1223 NvU8 regCtrl3; 1224 1225 // set frame count match value 1 1226 rmStatus |= writeregu008_extdeviceTargeted(pGpu, (PDACEXTERNALDEVICE)pThis, 1227 (NvU8)NV_P2060_FRAME_CMPR_LOW, 0x1); 1228 rmStatus |= writeregu008_extdeviceTargeted(pGpu, (PDACEXTERNALDEVICE)pThis, 1229 (NvU8)NV_P2060_FRAME_CMPR_MID, 0x0); 1230 rmStatus |= writeregu008_extdeviceTargeted(pGpu, (PDACEXTERNALDEVICE)pThis, 1231 (NvU8)NV_P2060_FRAME_CMPR_HIGH, 0x0); 1232 1233 // 1234 // Enable frame count match interrupt for the first time. For rest of the 1235 // instances when, TEST_SIGNAL is received, interrupt is enable in 1236 // gsyncUpdateFrameCount_P2060() based on enableFrmCmpMatchIntSlave bit. 1237 // 1238 rmStatus |= readregu008_extdeviceTargeted(pGpu, (PDACEXTERNALDEVICE)pThis, 1239 NV_P2060_CONTROL3, ®Ctrl3); 1240 1241 if (rmStatus == NV_OK) 1242 { 1243 regCtrl3 |= DRF_DEF(_P2060, _CONTROL3, _INTERRUPT, _ON_FRAME_MATCH); 1244 rmStatus = writeregu008_extdeviceTargeted(pGpu, (PDACEXTERNALDEVICE)pThis, 1245 NV_P2060_CONTROL3, regCtrl3); 1246 } 1247 } 1248 1249 if (rmStatus != NV_OK) 1250 { 1251 rmStatus |= gsyncResetFrameCountData_P2060(pGpu, pThis); 1252 return rmStatus; 1253 } 1254 1255 pThis->FrameCountData.lastFrameCounterQueryTime = currentTime; 1256 } 1257 1258 // Update software framecount throught gpu frame count register. 1259 else 1260 { 1261 // 1262 // To avoid any inconsistency, linecount and framecount should always 1263 // be read from one specific Gpu head. Its value is stored in pThis->FrameCountData. 1264 // 1265 NV_ASSERT_OR_RETURN(pTmpGpu, NV_ERR_INVALID_DEVICE); 1266 1267 pKernelDisplay = GPU_GET_KERNEL_DISPLAY(pTmpGpu); 1268 1269 // Read the GPU frame count and line count 1270 rmStatus = kdispReadRgLineCountAndFrameCount_HAL(pTmpGpu, pKernelDisplay, 1271 pThis->FrameCountData.head, &lineCount, &frameCount); 1272 if (rmStatus != NV_OK) 1273 { 1274 NV_PRINTF(LEVEL_ERROR, "Failed to read RG_DPCA.\n"); 1275 return rmStatus; 1276 } 1277 1278 // 1279 // Check to ensure previousFrameCount != currentGpuFrmCnt. If this is not ensured, 1280 // it is possible to miss rollover condition. 1281 // 1282 if (pThis->FrameCountData.currentFrameCount != frameCount) 1283 { 1284 pThis->FrameCountData.previousFrameCount = pThis->FrameCountData.currentFrameCount; 1285 pThis->FrameCountData.currentFrameCount = frameCount; 1286 1287 // If rollback for gpu framecount has occured. 1288 if (pThis->FrameCountData.previousFrameCount > pThis->FrameCountData.currentFrameCount) 1289 { 1290 pThis->FrameCountData.numberOfRollbacks++; 1291 } 1292 } 1293 1294 calculatedDiff = pThis->FrameCountData.initialDifference + 1295 pThis->FrameCountData.numberOfRollbacks * (NV_P2060_MAX_GPU_FRAME_COUNT + 1); 1296 1297 pThis->FrameCountData.totalFrameCount = pThis->FrameCountData.currentFrameCount + 1298 calculatedDiff; 1299 1300 // 1301 // To keep sync between the sw framecount and gsync framecount. 1302 // 1303 // Gpu framecount increments after VTotal scanout lines whereas Gsync 1304 // increments after VActive scanout lines. Thus it is necessary to 1305 // mitigate this difference of 1 when linecount > VActive. 1306 // 1307 if (lineCount > pThis->FrameCountData.vActive) 1308 { 1309 pThis->FrameCountData.totalFrameCount++; 1310 } 1311 1312 *pFrameCount = pThis->FrameCountData.totalFrameCount; 1313 1314 pThis->FrameCountData.lastFrameCounterQueryTime = currentTime; 1315 } 1316 1317 // 1318 // Enable the frame compare match interrupt in master gsync, to detect if 1319 // rollover has occured. So that gsync and gpu frame count can be cached 1320 // again and difference between them is verified. 1321 // 1322 if ((!pThis->FrameCountData.isFrmCmpMatchIntMasterEnabled) && 1323 (pThis->FrameCountData.totalFrameCount > (NV_P2060_MAX_GSYNC_FRAME_COUNT - 1000))) 1324 { 1325 if (gsyncIsOnlyFrameLockMaster_P2060(pThis)) 1326 { 1327 NvU8 regCtrl3; 1328 1329 // enable frame count match interrupt 1330 rmStatus = readregu008_extdeviceTargeted(pGpu, (PDACEXTERNALDEVICE)pThis, NV_P2060_CONTROL3, ®Ctrl3); 1331 1332 regCtrl3 |= DRF_DEF(_P2060, _CONTROL3, _INTERRUPT, _ON_FRAME_MATCH); 1333 rmStatus |= writeregu008_extdeviceTargeted(pGpu, (PDACEXTERNALDEVICE)pThis, NV_P2060_CONTROL3, regCtrl3); 1334 1335 pThis->FrameCountData.isFrmCmpMatchIntMasterEnabled = NV_TRUE; 1336 1337 if (rmStatus != NV_OK) 1338 { 1339 rmStatus |= gsyncResetFrameCountData_P2060(pGpu, pThis); 1340 } 1341 } 1342 } 1343 return rmStatus; 1344 } 1345 1346 /* 1347 * Read Frame Rate register and calculate Framerate. 1348 */ 1349 static NV_STATUS 1350 gsyncReadFrameRate_P2060 1351 ( 1352 OBJGPU *pGpu, 1353 PDACEXTERNALDEVICE pExtDev, 1354 NvU32 *pFrameRate 1355 ) 1356 { 1357 NvU8 FrameCountLow, FrameCountMid, FrameCountHigh; 1358 NvU32 FrameCount; 1359 NV_STATUS rmStatus = NV_OK; 1360 1361 rmStatus |= readregu008_extdeviceTargeted(pGpu, pExtDev, (NvU8)NV_P2060_FRAMERATE_LOW, &FrameCountLow); 1362 rmStatus |= readregu008_extdeviceTargeted(pGpu, pExtDev, (NvU8)NV_P2060_FRAMERATE_MID, &FrameCountMid); 1363 rmStatus |= readregu008_extdeviceTargeted(pGpu, pExtDev, (NvU8)NV_P2060_FRAMERATE_HIGH, &FrameCountHigh); 1364 1365 if ( NV_OK == rmStatus ) 1366 { 1367 NvU32 divisor; 1368 1369 FrameCount = ( ( (((NvU32)FrameCountHigh) & DRF_MASK(NV_P2060_FRAMERATE_HIGH_VAL)) << 16 ) | 1370 ( (((NvU32)FrameCountMid) & DRF_MASK(NV_P2060_FRAMERATE_MID_VAL )) << 8 ) | 1371 ( (((NvU32)FrameCountLow) & DRF_MASK(NV_P2060_FRAMERATE_LOW_VAL )) ) ); 1372 1373 divisor = FrameCount + 2; // FPGA divider is 1 1374 *pFrameRate = FrameCount ? OVERFLOW_CAREFUL_MUL_DIV(160000000, 2048, divisor) : 0; 1375 *pFrameRate += 5; // take back one kadam, to honor the Extdev god, 1376 *pFrameRate -= *pFrameRate % 10; // whose GSync board this is... 1377 } 1378 return rmStatus; 1379 } 1380 1381 /* 1382 * Read House Sync Frame Rate register and calculate Framerate. 1383 */ 1384 static NV_STATUS 1385 gsyncReadHouseSyncFrameRate_P2060 1386 ( 1387 OBJGPU *pGpu, 1388 PDACEXTERNALDEVICE pExtDev, 1389 NvU32 *pFrameRate 1390 ) 1391 { 1392 NvU8 FrameCountLow, FrameCountMid, FrameCountHigh; 1393 NvU32 FrameCount; 1394 NV_STATUS rmStatus = NV_OK; 1395 1396 rmStatus |= readregu008_extdeviceTargeted(pGpu, pExtDev, (NvU8)NV_P2060_HS_FRAMERATE_LOW, &FrameCountLow); 1397 rmStatus |= readregu008_extdeviceTargeted(pGpu, pExtDev, (NvU8)NV_P2060_HS_FRAMERATE_MID, &FrameCountMid); 1398 rmStatus |= readregu008_extdeviceTargeted(pGpu, pExtDev, (NvU8)NV_P2060_HS_FRAMERATE_HIGH, &FrameCountHigh); 1399 1400 if ( NV_OK == rmStatus ) 1401 { 1402 NvU32 divisor; 1403 1404 FrameCount = ( ( (((NvU32)FrameCountHigh) & DRF_MASK(NV_P2060_HS_FRAMERATE_HIGH_VAL)) << 16 ) | 1405 ( (((NvU32)FrameCountMid) & DRF_MASK(NV_P2060_HS_FRAMERATE_MID_VAL )) << 8 ) | 1406 ( (((NvU32)FrameCountLow) & DRF_MASK(NV_P2060_HS_FRAMERATE_LOW_VAL )) ) ); 1407 1408 divisor = FrameCount + 2; // FPGA divider is 1 1409 *pFrameRate = FrameCount ? OVERFLOW_CAREFUL_MUL_DIV(160000000, 2048, divisor) : 0; 1410 *pFrameRate += 5; // take back one kadam, to honor the Extdev god, 1411 *pFrameRate -= *pFrameRate % 10; // whose GSync board this is... 1412 } 1413 return rmStatus; 1414 } 1415 1416 NV_STATUS 1417 gsyncOptimizeTimingParameters_P2060 1418 ( 1419 OBJGPU *pGpu, 1420 GSYNCTIMINGPARAMS *pParams 1421 ) 1422 { 1423 RM_API *pRmApi = GPU_GET_PHYSICAL_RMAPI(pGpu); 1424 NvU32 hClient = pGpu->hInternalClient; 1425 NvU32 hSubdevice = pGpu->hInternalSubdevice; 1426 NV_STATUS status = NV_OK; 1427 NV2080_CTRL_INTERNAL_GSYNC_OPTIMIZE_TIMING_PARAMETERS_PARAMS ctrlParams = {0}; 1428 1429 ctrlParams.timingParameters = *pParams; 1430 1431 status = pRmApi->Control(pRmApi, hClient, hSubdevice, 1432 NV2080_CTRL_CMD_INTERNAL_GSYNC_OPTIMIZE_TIMING_PARAMETERS, 1433 &ctrlParams, sizeof(ctrlParams)); 1434 1435 if (status != NV_OK) 1436 { 1437 NV_PRINTF(LEVEL_ERROR, "OptimizeTimingParameters control call has failed! \n"); 1438 } 1439 else 1440 { 1441 *pParams = ctrlParams.timingParameters; 1442 } 1443 1444 return status; 1445 } 1446 1447 /* 1448 * Program External Stereo Polarity to High side of master stereo 1449 */ 1450 static NV_STATUS 1451 gsyncProgramExtStereoPolarity_P2060 1452 ( 1453 OBJGPU *pGpu, 1454 PDACEXTERNALDEVICE pExternalDevice 1455 ) 1456 { 1457 NV_STATUS rmStatus = NV_OK; 1458 NvU8 ctrl4 = 0x00; 1459 1460 rmStatus = readregu008_extdeviceTargeted(pGpu, pExternalDevice, 1461 NV_P2060_CONTROL4, &ctrl4); 1462 if (rmStatus != NV_OK) 1463 { 1464 return rmStatus; 1465 } 1466 1467 // This bit controls stereo polarity relative to an external sync. 1468 ctrl4 = (NvU8) FLD_SET_DRF(_P2060, _CONTROL4, _EXT_STEREO_SYNC_POL, _HI, (NvU32)ctrl4); 1469 1470 rmStatus = writeregu008_extdeviceTargeted(pGpu, pExternalDevice, 1471 NV_P2060_CONTROL4, ctrl4); 1472 return rmStatus; 1473 } 1474 1475 NV_STATUS 1476 gsyncSetStereoLockMode_P2060 1477 ( 1478 OBJGPU *pGpu, 1479 PDACEXTERNALDEVICE pExtDev, 1480 NvU32 enable 1481 ) 1482 { 1483 NvU8 ctrl4; 1484 NV_STATUS rmStatus; 1485 1486 rmStatus = readregu008_extdeviceTargeted(pGpu, pExtDev, (NvU8)NV_P2060_CONTROL4, &ctrl4); 1487 1488 if (rmStatus != NV_OK) 1489 { 1490 return rmStatus; 1491 } 1492 1493 if (enable) 1494 { 1495 ctrl4 = FLD_SET_DRF(_P2060, _CONTROL4, _STEREO_LOCK_MODE, _ON, ctrl4); 1496 } 1497 else 1498 { 1499 ctrl4 = FLD_SET_DRF(_P2060, _CONTROL4, _STEREO_LOCK_MODE, _OFF, ctrl4); 1500 } 1501 1502 rmStatus = writeregu008_extdeviceTargeted(pGpu, pExtDev, NV_P2060_CONTROL4, ctrl4); 1503 1504 return rmStatus; 1505 } 1506 1507 NV_STATUS 1508 gsyncGetStereoLockMode_P2060 1509 ( 1510 OBJGPU *pGpu, 1511 PDACEXTERNALDEVICE pExtDev, 1512 NvU32 *enable 1513 ) 1514 { 1515 NvU8 ctrl4; 1516 NV_STATUS rmStatus; 1517 1518 rmStatus = readregu008_extdeviceTargeted(pGpu, pExtDev, (NvU8)NV_P2060_CONTROL4, &ctrl4); 1519 1520 if (NV_OK == rmStatus) 1521 { 1522 *enable = FLD_TEST_DRF(_P2060, _CONTROL4, _STEREO_LOCK_MODE, _ON, ctrl4); 1523 } 1524 1525 return rmStatus; 1526 } 1527 1528 NV_STATUS 1529 gsyncSetVideoMode_P2060 1530 ( 1531 OBJGPU *pGpu, 1532 PDACEXTERNALDEVICE pExtDev, 1533 GSYNCVIDEOMODE VideoMode 1534 ) 1535 { 1536 return NV_OK; 1537 } 1538 1539 NV_STATUS 1540 gsyncGetVideoMode_P2060 1541 ( 1542 OBJGPU *pGpu, 1543 PDACEXTERNALDEVICE pExtDev, 1544 GSYNCVIDEOMODE *pVideoMode 1545 ) 1546 { 1547 NvU8 videoMode; 1548 NV_STATUS rmStatus; 1549 PDACP2060EXTERNALDEVICE pThis = (PDACP2060EXTERNALDEVICE)pExtDev; 1550 1551 NV_ASSERT_OR_RETURN(pGpu, NV_ERR_GENERIC); 1552 1553 rmStatus = readregu008_extdeviceTargeted(pGpu, pExtDev, (NvU8)NV_P2060_STATUS2, &videoMode); 1554 1555 if ( NV_OK == rmStatus ) 1556 { 1557 *pVideoMode = DRF_VAL(_P2060, _STATUS2, _HS_DETECT, videoMode); 1558 if (*pVideoMode == 0x02) 1559 { 1560 // reported videoMode is composite. Convert it to RMAPI exported value. 1561 *pVideoMode = gsync_VideoMode_COMPOSITE; 1562 } 1563 } 1564 1565 // update p2060 object 1566 pThis->VideoMode = *pVideoMode; 1567 1568 return rmStatus; 1569 } 1570 1571 NV_STATUS 1572 gsyncSetEmitTestSignal_P2060 1573 ( 1574 OBJGPU *pGpu, 1575 PDACEXTERNALDEVICE pExtDev, 1576 NvU32 bEmitTestSignal 1577 ) 1578 { 1579 NvU8 ctrl; 1580 NV_STATUS rmStatus; 1581 PDACP2060EXTERNALDEVICE pThis = (PDACP2060EXTERNALDEVICE)pExtDev; 1582 1583 // update p2060 object 1584 pThis->EmitTestSignal = bEmitTestSignal; 1585 1586 if (!gsyncIsFrameLockMaster_P2060(pThis)) 1587 { 1588 return NV_ERR_INVALID_DEVICE; 1589 } 1590 1591 pGpu = GetP2060MasterableGpu(pGpu, (PDACP2060EXTERNALDEVICE)pExtDev); 1592 NV_ASSERT_OR_RETURN(pGpu, NV_ERR_GENERIC); 1593 1594 rmStatus = readregu008_extdeviceTargeted(pGpu, pExtDev, (NvU8)NV_P2060_CONTROL, &ctrl); 1595 1596 if ( bEmitTestSignal ) 1597 { 1598 ctrl = FLD_SET_DRF(_P2060, _CONTROL, _TEST_MODE, _ON, ctrl); 1599 } 1600 else 1601 { 1602 ctrl = FLD_SET_DRF(_P2060, _CONTROL, _TEST_MODE, _OFF, ctrl); 1603 1604 // 1605 // To enable frameCountTimerService callback which verifies 1606 // the cache difference 1 second after sending the test signal 1607 // 1608 pThis->FrameCountData.bReCheck = 1; 1609 1610 // 1611 // Reset framecountData.Therefore whenever user queries after TEST_MODE_OFF, 1612 // gsync and gpu frame count register are read and difference is cached again. 1613 // 1614 rmStatus |= gsyncResetFrameCountData_P2060(pGpu, pThis); 1615 } 1616 1617 rmStatus |= writeregu008_extdeviceTargeted(pGpu, pExtDev, NV_P2060_CONTROL, ctrl); 1618 1619 // 1620 // Add some OS delay between test mode transitions. This is also 1621 // necessary for proper propogation of test signal to other slaves. 1622 // 1623 { 1624 NvU32 refreshTime = 0; 1625 // 1626 // The test mode detection logic will return the previous value until the 1627 // next frame. Although only the master will only manipulate test mode, 1628 // we may transition to slave while test mode is still on due to this. 1629 // So delay for a couple of frames to make sure the value transitions 1630 // correctly. Fix for bug #82809, back in the day. 1631 // 1632 // P2060 refreshrate is in 0.00001 Hz, so divide by 10000 to get Hz. 1633 // 1634 if ((pThis->RefreshRate/10000) > 0) 1635 { 1636 refreshTime = 1000 / (pThis->RefreshRate/10000); 1637 } 1638 NV_ASSERT(refreshTime != 0); 1639 1640 // Only wait a maximum amount of time. 1641 refreshTime = NV_MIN(refreshTime, 35); 1642 osDelay(2*refreshTime /* ms */); 1643 } 1644 1645 return rmStatus; 1646 } 1647 1648 NV_STATUS 1649 gsyncGetEmitTestSignal_P2060 1650 ( 1651 OBJGPU *pGpu, 1652 PDACEXTERNALDEVICE pExtDev, 1653 NvU32 *pVal 1654 ) 1655 { 1656 NvU8 ctrl; 1657 NV_STATUS rmStatus; 1658 PDACP2060EXTERNALDEVICE pThis = (PDACP2060EXTERNALDEVICE)pExtDev; 1659 1660 rmStatus = readregu008_extdeviceTargeted(pGpu, pExtDev, (NvU8)NV_P2060_CONTROL, &ctrl); 1661 1662 if ( NV_OK == rmStatus ) 1663 { 1664 *pVal = FLD_TEST_DRF(_P2060, _CONTROL, _TEST_MODE, _ON, ctrl); 1665 } 1666 1667 // update p2060 object 1668 pThis->EmitTestSignal = *pVal; 1669 1670 return rmStatus; 1671 } 1672 1673 NV_STATUS 1674 gsyncSetInterlaceMode_P2060 1675 ( 1676 OBJGPU *pGpu, 1677 PDACEXTERNALDEVICE pExtDev, 1678 NvU32 InterlaceMode 1679 ) 1680 { 1681 NvU8 ctrl; 1682 NV_STATUS rmStatus; 1683 PDACP2060EXTERNALDEVICE pThis = (PDACP2060EXTERNALDEVICE)pExtDev; 1684 1685 // update p2060 object 1686 pThis->InterlaceMode = InterlaceMode; 1687 1688 pGpu = GetP2060MasterableGpu(pGpu, (PDACP2060EXTERNALDEVICE)pExtDev); 1689 NV_ASSERT_OR_RETURN(pGpu, NV_ERR_GENERIC); 1690 1691 rmStatus = readregu008_extdeviceTargeted(pGpu, pExtDev, (NvU8)NV_P2060_CONTROL, &ctrl); 1692 1693 if ( rmStatus == NV_OK ) 1694 { 1695 ctrl = FLD_SET_DRF_NUM(_P2060, _CONTROL, _INTERLACE_MODE, (NvU8)InterlaceMode, ctrl); 1696 rmStatus = writeregu008_extdeviceTargeted(pGpu, pExtDev, NV_P2060_CONTROL, ctrl); 1697 } 1698 1699 return rmStatus; 1700 } 1701 1702 NV_STATUS 1703 gsyncGetInterlaceMode_P2060 1704 ( 1705 OBJGPU *pGpu, 1706 PDACEXTERNALDEVICE pExtDev, 1707 NvU32 *pVal 1708 ) 1709 { 1710 NvU8 ctrl; 1711 NV_STATUS rmStatus; 1712 PDACP2060EXTERNALDEVICE pThis = (PDACP2060EXTERNALDEVICE)pExtDev; 1713 1714 pGpu = GetP2060MasterableGpu(pGpu, (PDACP2060EXTERNALDEVICE)pExtDev); 1715 NV_ASSERT_OR_RETURN(pGpu, NV_ERR_GENERIC); 1716 1717 rmStatus = readregu008_extdeviceTargeted(pGpu, pExtDev, (NvU8)NV_P2060_CONTROL, &ctrl); 1718 1719 if ( NV_OK == rmStatus ) 1720 { 1721 *pVal = FLD_TEST_DRF(_P2060, _CONTROL, _INTERLACE_MODE, _TRUE, ctrl); 1722 } 1723 1724 // update p2060 object 1725 pThis->InterlaceMode = *pVal; 1726 1727 return rmStatus; 1728 } 1729 1730 NV_STATUS 1731 gsyncSetUseHouse_P2060 1732 ( 1733 OBJGPU *pGpu, 1734 PDACEXTERNALDEVICE pExtDev, 1735 NvU32 UseHouseSync 1736 ) 1737 { 1738 NvU8 ctrl; 1739 NV_STATUS rmStatus = NV_OK; 1740 PDACP2060EXTERNALDEVICE pThis = (PDACP2060EXTERNALDEVICE)pExtDev; 1741 1742 // update p2060 object 1743 pThis->UseHouseSync = UseHouseSync; 1744 1745 pGpu = GetP2060MasterableGpu(pGpu, (PDACP2060EXTERNALDEVICE)pExtDev); 1746 NV_ASSERT_OR_RETURN(pGpu, NV_ERR_GENERIC); 1747 1748 rmStatus = readregu008_extdeviceTargeted(pGpu, pExtDev, NV_P2060_CONTROL, &ctrl); 1749 1750 if (NV_OK == rmStatus) 1751 { 1752 ctrl = FLD_SET_DRF_NUM(_P2060, _CONTROL, _SYNC_SELECT, (NvU8)UseHouseSync, ctrl); 1753 rmStatus = writeregu008_extdeviceTargeted(pGpu, pExtDev, NV_P2060_CONTROL, ctrl); 1754 } 1755 1756 return rmStatus; 1757 } 1758 1759 NV_STATUS 1760 gsyncGetUseHouse_P2060 1761 ( 1762 OBJGPU *pGpu, 1763 PDACEXTERNALDEVICE pExtDev, 1764 NvU32 *val 1765 ) 1766 { 1767 NvU8 ctrl; 1768 NV_STATUS rmStatus = NV_OK; 1769 PDACP2060EXTERNALDEVICE pThis = (PDACP2060EXTERNALDEVICE)pExtDev; 1770 1771 rmStatus = readregu008_extdeviceTargeted(pGpu, pExtDev, NV_P2060_CONTROL, &ctrl); 1772 1773 if (NV_OK == rmStatus) 1774 { 1775 *val = FLD_TEST_DRF(_P2060, _CONTROL, _SYNC_SELECT, _HOUSE, ctrl); 1776 1777 // update p2060 object 1778 pThis->UseHouseSync = *val; 1779 } 1780 1781 return rmStatus; 1782 } 1783 1784 NV_STATUS 1785 gsyncSetSyncPolarity_P2060 1786 ( 1787 OBJGPU *pGpu, 1788 PDACEXTERNALDEVICE pExtDev, 1789 GSYNCSYNCPOLARITY SyncPolarity 1790 ) 1791 { 1792 NvU8 ctrl; 1793 NV_STATUS rmStatus; 1794 PDACP2060EXTERNALDEVICE pThis = (PDACP2060EXTERNALDEVICE)pExtDev; 1795 GSYNCSYNCPOLARITY currentSyncPolarity; 1796 1797 // update p2060 object 1798 pThis->SyncPolarity = SyncPolarity; 1799 1800 pGpu = GetP2060MasterableGpu(pGpu, (PDACP2060EXTERNALDEVICE)pExtDev); 1801 NV_ASSERT_OR_RETURN(pGpu, NV_ERR_GENERIC); 1802 1803 rmStatus = readregu008_extdeviceTargeted(pGpu, pExtDev, (NvU8)NV_P2060_CONTROL, &ctrl); 1804 1805 if ( NV_OK == rmStatus ) 1806 { 1807 currentSyncPolarity = DRF_VAL(_P2060, _CONTROL, _SYNC_POLARITY, ctrl); 1808 1809 if (currentSyncPolarity != SyncPolarity) 1810 { 1811 NvU32 frameTime = 0; 1812 1813 ctrl = FLD_SET_DRF_NUM(_P2060, _CONTROL, _SYNC_POLARITY, (NvU8)SyncPolarity, ctrl); 1814 rmStatus = writeregu008_extdeviceTargeted(pGpu, pExtDev, NV_P2060_CONTROL, ctrl); 1815 1816 if ((pThis->RefreshRate/10000) > 0) 1817 { 1818 frameTime = 1000 / (pThis->RefreshRate/10000); 1819 } 1820 1821 // 1822 // Wait for max of 10 frames or 100 ms so that hardware can collect 1823 // the new house sync frame rate. 1824 // 1825 frameTime = NV_MAX(frameTime, 10); 1826 osDelay(10 * frameTime /* ms */); 1827 } 1828 } 1829 1830 return rmStatus; 1831 } 1832 1833 NV_STATUS 1834 gsyncGetSyncPolarity_P2060 1835 ( 1836 OBJGPU *pGpu, 1837 PDACEXTERNALDEVICE pExtDev, 1838 GSYNCSYNCPOLARITY *pSyncPolarity 1839 ) 1840 { 1841 NvU8 ctrl; 1842 NV_STATUS rmStatus; 1843 PDACP2060EXTERNALDEVICE pThis = (PDACP2060EXTERNALDEVICE)pExtDev; 1844 1845 rmStatus = readregu008_extdeviceTargeted(pGpu, pExtDev, (NvU8)NV_P2060_CONTROL, &ctrl); 1846 1847 if ( NV_OK == rmStatus ) 1848 { 1849 *pSyncPolarity = DRF_VAL(_P2060, _CONTROL, _SYNC_POLARITY, ctrl); 1850 } 1851 1852 // update p2060 object 1853 pThis->SyncPolarity = *pSyncPolarity; 1854 1855 return rmStatus; 1856 } 1857 1858 NV_STATUS 1859 gsyncSetNSync_P2060 1860 ( 1861 OBJGPU *pGpu, 1862 PDACEXTERNALDEVICE pExtDev, 1863 NvU32 NSync 1864 ) 1865 { 1866 NvU8 regNSync; 1867 NV_STATUS rmStatus; 1868 PDACP2060EXTERNALDEVICE pThis = (PDACP2060EXTERNALDEVICE)pExtDev; 1869 1870 // update p2060 object 1871 pThis->NSync = NSync; 1872 1873 rmStatus = readregu008_extdeviceTargeted(pGpu, pExtDev, (NvU8)NV_P2060_NSYNC, ®NSync); 1874 1875 if ( NV_OK == rmStatus ) 1876 { 1877 regNSync = FLD_SET_DRF_NUM(_P2060, _NSYNC, _FL, (NvU8)NSync, regNSync); 1878 rmStatus = writeregu008_extdeviceTargeted(pGpu, pExtDev, NV_P2060_NSYNC, regNSync); 1879 } 1880 1881 return rmStatus; 1882 } 1883 1884 NV_STATUS 1885 gsyncGetNSync_P2060 1886 ( 1887 OBJGPU *pGpu, 1888 PDACEXTERNALDEVICE pExtDev, 1889 NvU32 *pNSync 1890 ) 1891 { 1892 NvU8 regNSync; 1893 NV_STATUS rmStatus; 1894 PDACP2060EXTERNALDEVICE pThis = (PDACP2060EXTERNALDEVICE)pExtDev; 1895 1896 rmStatus = readregu008_extdeviceTargeted(pGpu, pExtDev, (NvU8)NV_P2060_NSYNC, ®NSync); 1897 1898 if ( NV_OK == rmStatus ) 1899 { 1900 *pNSync = DRF_VAL(_P2060, _NSYNC, _FL, regNSync); 1901 } 1902 1903 // update p2060 object 1904 pThis->NSync = *pNSync; 1905 1906 return rmStatus; 1907 } 1908 1909 NV_STATUS 1910 gsyncSetSyncSkew_P2060 1911 ( 1912 OBJGPU *pGpu, 1913 PDACEXTERNALDEVICE pExtDev, 1914 NvU32 SyncSkew 1915 ) 1916 { 1917 NvU8 SyncSkewLow, SyncSkewHigh; 1918 NV_STATUS rmStatus = NV_OK; 1919 PDACP2060EXTERNALDEVICE pThis = (PDACP2060EXTERNALDEVICE)pExtDev; 1920 1921 // update p2060 object 1922 pThis->SyncSkew = SyncSkew; 1923 1924 if (gsyncSupportsLargeSyncSkew_P2060(pExtDev)) 1925 { 1926 SyncSkewLow = (NvU8)((SyncSkew ) & DRF_MASK(NV_P2060_SYNC_SKEW_LOW_VAL )); 1927 SyncSkewHigh = (NvU8)((SyncSkew >> 8) & DRF_MASK(NV_P2060_SYNC_SKEW_HIGH_VAL)); 1928 } 1929 else 1930 { 1931 if ((SyncSkew != 0) && (SyncSkew != 1)) 1932 { 1933 return NV_ERR_NOT_SUPPORTED; 1934 } 1935 else 1936 { 1937 SyncSkewLow = (NvU8)SyncSkew; 1938 SyncSkewHigh = 0x00; 1939 } 1940 } 1941 1942 rmStatus |= writeregu008_extdeviceTargeted(pGpu, pExtDev, (NvU8)NV_P2060_SYNC_SKEW_LOW, SyncSkewLow); 1943 rmStatus |= writeregu008_extdeviceTargeted(pGpu, pExtDev, (NvU8)NV_P2060_SYNC_SKEW_HIGH, SyncSkewHigh); 1944 1945 return rmStatus; 1946 1947 } 1948 1949 NV_STATUS 1950 gsyncGetSyncSkew_P2060 1951 ( 1952 OBJGPU *pGpu, 1953 PDACEXTERNALDEVICE pExtDev, 1954 NvU32 *pSyncSkew 1955 ) 1956 { 1957 NvU8 SyncSkewLow, SyncSkewHigh; 1958 NV_STATUS rmStatus = NV_OK; 1959 PDACP2060EXTERNALDEVICE pThis = (PDACP2060EXTERNALDEVICE)pExtDev; 1960 1961 rmStatus |= readregu008_extdeviceTargeted(pGpu, pExtDev, (NvU8)NV_P2060_SYNC_SKEW_LOW, &SyncSkewLow); 1962 rmStatus |= readregu008_extdeviceTargeted(pGpu, pExtDev, (NvU8)NV_P2060_SYNC_SKEW_HIGH, &SyncSkewHigh); 1963 1964 if ( NV_OK == rmStatus ) 1965 { 1966 *pSyncSkew = 1967 ( ((((NvU32)SyncSkewHigh) & DRF_MASK(NV_P2060_SYNC_SKEW_HIGH_VAL)) << 8 ) | 1968 ((((NvU32)SyncSkewLow ) & DRF_MASK(NV_P2060_SYNC_SKEW_LOW_VAL )) ) ) ; 1969 } 1970 1971 // update p2060 object 1972 pThis->SyncSkew = *pSyncSkew; 1973 1974 return rmStatus; 1975 } 1976 1977 NV_STATUS 1978 gsyncSetSyncStartDelay_P2060 1979 ( 1980 OBJGPU *pGpu, 1981 PDACEXTERNALDEVICE pExtDev, 1982 NvU32 StartDelay 1983 ) 1984 { 1985 NvU8 StartDelayLow, StartDelayHigh; 1986 NV_STATUS rmStatus = NV_OK; 1987 PDACP2060EXTERNALDEVICE pThis = (PDACP2060EXTERNALDEVICE)pExtDev; 1988 1989 // update p2060 object 1990 pThis->SyncStartDelay = StartDelay; 1991 1992 StartDelayLow = (NvU8)((StartDelay ) & DRF_MASK(NV_P2060_START_DELAY_LOW_VAL )); 1993 StartDelayHigh= (NvU8)((StartDelay >> 8) & DRF_MASK(NV_P2060_START_DELAY_HIGH_VAL)); 1994 1995 rmStatus |= writeregu008_extdeviceTargeted(pGpu, pExtDev, (NvU8)NV_P2060_START_DELAY_LOW, StartDelayLow); 1996 rmStatus |= writeregu008_extdeviceTargeted(pGpu, pExtDev, (NvU8)NV_P2060_START_DELAY_HIGH, StartDelayHigh); 1997 1998 return rmStatus; 1999 } 2000 2001 NV_STATUS 2002 gsyncGetSyncStartDelay_P2060 2003 ( 2004 OBJGPU *pGpu, 2005 PDACEXTERNALDEVICE pExtDev, 2006 NvU32 *pStartDelay 2007 ) 2008 { 2009 NvU8 StartDelayLow, StartDelayHigh; 2010 NV_STATUS rmStatus = NV_OK; 2011 PDACP2060EXTERNALDEVICE pThis = (PDACP2060EXTERNALDEVICE)pExtDev; 2012 2013 rmStatus |= readregu008_extdeviceTargeted(pGpu, pExtDev, (NvU8)NV_P2060_START_DELAY_LOW, &StartDelayLow); 2014 rmStatus |= readregu008_extdeviceTargeted(pGpu, pExtDev, (NvU8)NV_P2060_START_DELAY_HIGH, &StartDelayHigh); 2015 2016 if ( NV_OK == rmStatus ) 2017 { 2018 *pStartDelay = 2019 ( ((((NvU32)StartDelayHigh) & DRF_MASK(NV_P2060_START_DELAY_HIGH_VAL)) << 8 ) | 2020 ((((NvU32)StartDelayLow ) & DRF_MASK(NV_P2060_START_DELAY_LOW_VAL )) ) ); 2021 } 2022 2023 // update p2060 object 2024 pThis->SyncStartDelay = *pStartDelay; 2025 2026 return rmStatus; 2027 } 2028 2029 /* 2030 * check if housesync is present or not. 2031 */ 2032 static NV_STATUS 2033 gsyncReadHouseSignalPresent_P2060 2034 ( 2035 OBJGPU *pGpu, 2036 PDACEXTERNALDEVICE pExtDev, 2037 NvBool bTestSyncLoss, 2038 NvU32 *pVal 2039 ) 2040 { 2041 PDACP2060EXTERNALDEVICE pThis = (PDACP2060EXTERNALDEVICE)pExtDev; 2042 NvU8 regStatus2; 2043 NvU32 regStatus = GetP2060GpuSnapshot(pGpu,pThis); 2044 NV_STATUS rmStatus = NV_OK; 2045 2046 NV_ASSERT_OR_RETURN(pGpu, NV_ERR_GENERIC); 2047 2048 if (bTestSyncLoss && FLD_TEST_DRF(_P2060, _STATUS, _SYNC_LOSS, _TRUE, (NvU32)regStatus)) 2049 { 2050 rmStatus |= gsyncUpdateGsyncStatusSnapshot_P2060(pGpu, pExtDev); 2051 2052 if ( NV_OK != rmStatus ) 2053 return rmStatus; 2054 2055 if (FLD_TEST_DRF(_P2060, _STATUS, _SYNC_LOSS, _TRUE, GetP2060GpuSnapshot(pGpu,pThis))) 2056 { 2057 *pVal = 0; // bTestSyncLoss and (SYNC_LOSS == NV_TRUE) 2058 } 2059 } 2060 else 2061 { 2062 rmStatus = readregu008_extdeviceTargeted(pGpu, (PDACEXTERNALDEVICE)pThis, 2063 (NvU8)NV_P2060_STATUS2, ®Status2); 2064 if ( NV_OK != rmStatus ) 2065 return rmStatus; 2066 2067 *pVal = !!(DRF_VAL(_P2060, _STATUS2, _HS_DETECT, (NvU32)regStatus2)); 2068 } 2069 2070 return rmStatus; 2071 } 2072 2073 /* 2074 * This function returns whether there is a sync source present. 2075 * 2076 * SYNC_LOSS bit in STATUS register is true by default, i.e when there 2077 * is no incoming sync source. This bit is unset when a stable sync 2078 * source is detected. 2079 * 2080 * Whenever framelock is enabled, NV_TRUE is returned only when the incoming 2081 * sync source is stable. Therefore it is sent based on the software state. 2082 * 2083 * When framelock is not enabled, return value totally depends on the value 2084 * of the gsync STATUS register. 2085 */ 2086 static NV_STATUS 2087 gsyncReadIsSyncDetected_P2060 2088 ( 2089 OBJGPU *pGpu, 2090 PDACEXTERNALDEVICE pExtDev, 2091 NvU32 *pVal 2092 ) 2093 { 2094 PDACP2060EXTERNALDEVICE pThis = (PDACP2060EXTERNALDEVICE)pExtDev; 2095 NV_STATUS rmStatus = NV_OK; 2096 NvU32 iface; 2097 2098 NV_ASSERT_OR_RETURN(pGpu, NV_ERR_GENERIC); 2099 2100 if (!gsyncIsFrameLocked_P2060(pThis)) 2101 { 2102 NvU8 regStatus; 2103 2104 // framelock is not enabled, read the NV_P2060_STATUS register to get the SYNC status 2105 rmStatus = readregu008_extdeviceTargeted(pGpu, (PDACEXTERNALDEVICE)pThis, (NvU8)NV_P2060_STATUS, ®Status); 2106 2107 if (rmStatus == NV_OK) 2108 { 2109 *pVal = (NV_P2060_STATUS_SYNC_LOSS_TRUE != DRF_VAL(_P2060, _STATUS, _SYNC_LOSS, regStatus)); 2110 } 2111 } 2112 else 2113 { 2114 rmStatus = GetP2060GpuLocation(pGpu, pThis, &iface); 2115 if (NV_OK != rmStatus) 2116 { 2117 return rmStatus; 2118 } 2119 2120 // 2121 // Sync gain should only be derived from our internal tracking variable. 2122 // The gsync status variables are reporting more transient data than desired. 2123 // 2124 *pVal = pThis->Iface[iface].gainedSync; 2125 } 2126 2127 return rmStatus; 2128 } 2129 2130 /* 2131 * Check if stereo is locked or not. 2132 * 2133 * stereo is locked means 2134 * - a framelock master signal is available as reference 2135 * - sync to this master signal has been gained 2136 * - master and local gpu both have either stereo enabled or disabled 2137 * - master and local stereo signal is in phase (in case it's enabled) 2138 */ 2139 static NV_STATUS 2140 gsyncReadStereoLocked_P2060 2141 ( 2142 OBJGPU *pGpu, 2143 PDACEXTERNALDEVICE pExtDev, 2144 NvU32 *pVal 2145 ) 2146 { 2147 PDACP2060EXTERNALDEVICE pThis = (PDACP2060EXTERNALDEVICE)pExtDev; 2148 NV_STATUS rmStatus = NV_ERR_GENERIC; 2149 2150 if (pVal) 2151 { 2152 NvU32 iface; 2153 2154 // Default return is stereo not locked. 2155 *pVal = 0; 2156 2157 // which gpu's interface are we talking to? 2158 rmStatus = GetP2060GpuLocation(pGpu, pThis, &iface); 2159 2160 if (NV_OK == rmStatus) 2161 { 2162 // stereo status reporting only makes sense if we've gained sync. 2163 if (pThis->Iface[iface].gainedSync) 2164 { 2165 NvU32 regStatus = GetP2060GpuSnapshot(pGpu,pThis); 2166 2167 if ((NV_P2060_STATUS_MSTR_STEREO_NOT_ACTIVE == 2168 DRF_VAL(_P2060, _STATUS, _MSTR_STEREO, regStatus)) && 2169 (NV_P2060_STATUS_GPU_STEREO_NOT_ACTIVE == 2170 DRF_VAL(_P2060, _STATUS, _GPU_STEREO, regStatus))) 2171 { 2172 // 2173 // If neither local nor master stereo is enabled 2174 // stereo is locked. 2175 // 2176 *pVal = 1; 2177 } 2178 else 2179 { 2180 // 2181 // If local or master stereo signals are present, 2182 // return back P358s stereo_lock reporting. 2183 // 2184 *pVal = (NV_P2060_STATUS_STEREO_LOCK == 2185 DRF_VAL(_P2060, _STATUS, _STEREO, regStatus)); 2186 } 2187 } 2188 } 2189 } 2190 2191 return rmStatus; 2192 } 2193 2194 /* 2195 * Check if VCXO is locked or not. 2196 */ 2197 static NV_STATUS 2198 gsyncReadVCXOLocked_P2060 2199 ( 2200 OBJGPU *pGpu, 2201 PDACEXTERNALDEVICE pExtDev, 2202 NvU32 *pVal 2203 ) 2204 { 2205 PDACP2060EXTERNALDEVICE pThis = (PDACP2060EXTERNALDEVICE)pExtDev; 2206 NV_STATUS rmStatus = NV_OK; 2207 NvU32 regStatus = GetP2060GpuSnapshot(pGpu,pThis); 2208 2209 // Status1 only needs to be read if the shapshot shows recent error or no vcxo lock 2210 if (!FLD_TEST_DRF(_P2060, _STATUS, _VCXO, _LOCK, regStatus)) 2211 { 2212 rmStatus = gsyncUpdateGsyncStatusSnapshot_P2060(pGpu, pExtDev); 2213 if ( NV_OK == rmStatus ) 2214 { 2215 *pVal = FLD_TEST_DRF(_P2060, _STATUS, _VCXO, _LOCK, GetP2060GpuSnapshot(pGpu,pThis)); 2216 } 2217 } 2218 else 2219 { 2220 *pVal = 1; //VCXO is locked. 2221 } 2222 2223 return rmStatus; 2224 } 2225 2226 /* 2227 * Check if timing is present or not. 2228 */ 2229 static NV_STATUS 2230 gsyncReadIsTiming_P2060 2231 ( 2232 OBJGPU *pGpu, 2233 PDACEXTERNALDEVICE pExtDev, 2234 NvU32 *pVal 2235 ) 2236 { 2237 PDACP2060EXTERNALDEVICE pThis = (PDACP2060EXTERNALDEVICE)pExtDev; 2238 NV_STATUS rmStatus = NV_OK; 2239 KernelDisplay *pKernelDisplay = GPU_GET_KERNEL_DISPLAY(pGpu); 2240 NvU32 numHeads = kdispGetNumHeads(pKernelDisplay); 2241 NvU32 bHouse, bLock = 0, bSync; 2242 NvU32 iface, head, tempIface, tempHead; 2243 2244 rmStatus = GetP2060GpuLocation(pGpu, pThis, &iface); 2245 if (NV_OK != rmStatus) 2246 { 2247 return rmStatus; 2248 } 2249 2250 // assume no, unless we find something below 2251 *pVal = (NvU32)NV_FALSE; 2252 2253 for (head = 0; head < numHeads; head++) 2254 { 2255 // check if we're slaved to another master head in the same system 2256 if (pThis->Iface[iface].Sync.LocalSlave[head]) 2257 { 2258 for (tempIface = 0; tempIface < NV_P2060_MAX_IFACES_PER_GSYNC; tempIface++) 2259 { 2260 for (tempHead = 0; tempHead < numHeads; tempHead++) 2261 { 2262 if (pThis->Iface[tempIface].Sync.Master[tempHead]) 2263 { 2264 // assume that if we're slaved to another local head 2265 // that we're in sync. there's no easy way to verify 2266 // this, short of trying to compare raster scanlines 2267 *pVal = (NvU32)NV_TRUE; 2268 } 2269 } 2270 } 2271 break; 2272 } 2273 2274 // check if we have a master, connected to a house sync 2275 if (pThis->Iface[iface].Sync.Master[head] && pThis->Iface[iface].Sync.Slaved[head]) 2276 { 2277 rmStatus |= gsyncReadHouseSignalPresent_P2060(pGpu, pExtDev, NV_TRUE, &bHouse); 2278 if ( NV_OK == rmStatus ) 2279 { 2280 *pVal = (NvU32)(bHouse); 2281 } 2282 break; 2283 } 2284 2285 // check if we have a master head, not connected to house sync 2286 if (pThis->Iface[iface].Sync.Master[head]) 2287 { 2288 // a master is by definition always in sync 2289 *pVal = (NvU32)NV_TRUE; 2290 break; 2291 } 2292 2293 if (pThis->Iface[iface].Sync.Slaved[head]) 2294 { 2295 rmStatus |= gsyncReadIsSyncDetected_P2060(pGpu, pExtDev, &bSync); 2296 rmStatus |= gsyncReadVCXOLocked_P2060(pGpu, pExtDev, &bLock); 2297 if ( NV_OK == rmStatus ) 2298 { 2299 *pVal = (NvU32)(bSync && bLock); 2300 } 2301 break; 2302 } 2303 } 2304 return rmStatus; 2305 } 2306 2307 2308 /* 2309 * Program P2060 Master for Framelock. 2310 */ 2311 static NV_STATUS 2312 gsyncProgramMaster_P2060 2313 ( 2314 OBJGPU *pGpu, 2315 PDACP2060EXTERNALDEVICE pThis, 2316 NvU32 Master, 2317 NvBool bRetainMaster, 2318 NvBool skipSwapBarrierWar 2319 ) 2320 { 2321 KernelDisplay *pKernelDisplay = GPU_GET_KERNEL_DISPLAY(pGpu); 2322 NvU32 DisplayIds[OBJ_MAX_HEADS]; 2323 NvU32 iface, head, index; 2324 NvU8 ctrl = 0; 2325 NvBool bTestModePresent; 2326 NvBool bHouseSelect, bEnableMaster = (0 != Master); 2327 NvBool bGPUAlreadyMaster; 2328 NvBool bQSyncAlreadyMaster; 2329 NV_STATUS rmStatus = NV_OK; 2330 NvU32 numHeads = kdispGetNumHeads(pKernelDisplay); 2331 2332 if ( Master && bRetainMaster) 2333 { 2334 for (iface = 0; iface < NV_P2060_MAX_IFACES_PER_GSYNC; iface++) 2335 { 2336 for ( head = 0; head < numHeads; head++ ) 2337 { 2338 if ( pThis->Iface[iface].Sync.Master[head] ) 2339 { 2340 pThis->Iface[iface].Sync.Master[head] = 0; 2341 pThis->Iface[iface].Sync.Slaved[head] = 0; 2342 pThis->Iface[iface].Sync.LocalSlave[head] = 0; 2343 } 2344 } 2345 } 2346 return rmStatus; 2347 } 2348 2349 // This utility fn returns display id's associated with each head. 2350 extdevGetBoundHeadsAndDisplayIds(pGpu, DisplayIds); 2351 2352 // which gpu's are we talking to? 2353 rmStatus = GetP2060GpuLocation(pGpu, pThis, &iface); 2354 if (NV_OK != rmStatus) 2355 { 2356 NV_PRINTF(LEVEL_ERROR, 2357 "Failed to get Gpu location. Can not program Master.\n"); 2358 return rmStatus; 2359 } 2360 2361 // no failure allowed! 2362 rmStatus = readregu008_extdeviceTargeted(pGpu, (PDACEXTERNALDEVICE)pThis, 2363 (NvU8)NV_P2060_CONTROL, &ctrl); 2364 if ((NV_OK != rmStatus)) 2365 { 2366 NV_PRINTF(LEVEL_ERROR, 2367 "Failed to read Ctrl data. Can not program Master.\n"); 2368 return rmStatus; 2369 } 2370 2371 // Check if TEST MODE present 2372 bTestModePresent = FLD_TEST_DRF(_P2060, _CONTROL, _TEST_MODE, _ON, (NvU32)ctrl); 2373 2374 // Check for House sync select as sync source 2375 bHouseSelect = FLD_TEST_DRF(_P2060, _CONTROL, _SYNC_SELECT, _HOUSE, (NvU32)ctrl); 2376 2377 rmStatus = GetP2060ConnectorIndexFromGpu(pGpu, pThis, &index); 2378 if (NV_OK != rmStatus) 2379 { 2380 NV_PRINTF(LEVEL_ERROR, 2381 "Failed to get connector index for Gpu. Can not program Master.\n"); 2382 return rmStatus; 2383 } 2384 // 2385 // For P2060, Already Mastership based on FPGA -> I_AM_MASTER + GPU -> TIMING SOURCE. 2386 // First check for display is already Master or not i.e. GPU is TS or not. 2387 // Then check for FPGA board is already Master or not. 2388 // 2389 bGPUAlreadyMaster = (DRF_VAL(_P2060, _CONTROL, _SYNC_SRC, (NvU32)ctrl) == index); 2390 bQSyncAlreadyMaster = FLD_TEST_DRF(_P2060, _CONTROL, _I_AM, _MASTER, (NvU32)ctrl); 2391 2392 // In case of Passthru mode, Qsync board can be shared across multiple VMs. 2393 // If Qsync board is already master, then only TS Gpu should be allowed to change it's mastership. 2394 // Bail out if non TS GPU tries to change it. 2395 if (IS_PASSTHRU(pGpu) && (bQSyncAlreadyMaster & !bGPUAlreadyMaster)) 2396 { 2397 return rmStatus; 2398 } 2399 2400 if (bQSyncAlreadyMaster != bEnableMaster) 2401 { 2402 if (pThis->ExternalDevice.deviceRev == DAC_EXTERNAL_DEVICE_REV_NONE) 2403 { 2404 NV_PRINTF(LEVEL_ERROR, 2405 "Failed to read NV_P2060_FPGA. Can not program Master.\n"); 2406 return rmStatus; 2407 } 2408 2409 if (bEnableMaster) 2410 { 2411 rmStatus = gsyncApplyStereoPinAlwaysHiWar(pGpu, (PDACEXTERNALDEVICE)pThis); 2412 2413 if (NV_OK != rmStatus) 2414 { 2415 NV_PRINTF(LEVEL_ERROR, 2416 "Failed to drive stereo output pin for bug3362661.\n"); 2417 } 2418 // 2419 // GPU will now be TS - Mark sync source for GPU on derived index. 2420 // This needs to be done first as only TS can write I_AM_MASTER bit. 2421 // 2422 ctrl = FLD_SET_DRF_NUM(_P2060, _CONTROL, _SYNC_SRC, (NvU8)index, ctrl); 2423 rmStatus |= writeregu008_extdeviceTargeted(pGpu, (PDACEXTERNALDEVICE) pThis, 2424 (NvU8)NV_P2060_CONTROL, ctrl); 2425 if (NV_OK != rmStatus) 2426 { 2427 NV_PRINTF(LEVEL_ERROR, 2428 "Failed to write SYNC_SRC. Can not program Master.\n"); 2429 return rmStatus; 2430 } 2431 } 2432 2433 if (bTestModePresent) 2434 { 2435 // Clear the TEST mode bit before handling enable/disable master. 2436 ctrl = FLD_SET_DRF(_P2060, _CONTROL, _TEST_MODE, _OFF, ctrl); 2437 2438 if (!bEnableMaster) 2439 { 2440 // 2441 // Clear the TEST mode bit before disabling master as TEST mode 2442 // can only be modified by the GPU TS under FPGA master mode. 2443 // 2444 rmStatus |= writeregu008_extdeviceTargeted(pGpu, (PDACEXTERNALDEVICE) pThis, 2445 (NvU8)NV_P2060_CONTROL, ctrl); 2446 osDelay(30); // Add delay of 30 ms as we are turning OFF TEST mode. 2447 } 2448 } 2449 2450 // Gsync/FPGA card will be master or not based on bEnableMaster. 2451 ctrl = FLD_SET_DRF_NUM(_P2060, _CONTROL, _I_AM, (NvU8)bEnableMaster, ctrl); 2452 rmStatus |= writeregu008_extdeviceTargeted(pGpu, (PDACEXTERNALDEVICE) pThis, 2453 (NvU8)NV_P2060_CONTROL, ctrl); 2454 if (NV_OK != rmStatus) 2455 { 2456 NV_PRINTF(LEVEL_ERROR, 2457 "Failed to write I_AM_MSTR. Can not program Master.\n"); 2458 return rmStatus; 2459 } 2460 2461 // 2462 // Now we have updated Master status of Gsync board, wait for some time. This will allow FPGA to 2463 // reflect state-change in other registers e.g portStat, Frame Rate etc. Refer Bug 1053022. 2464 // 2465 osDelay(200); 2466 2467 if (bEnableMaster) 2468 { 2469 // Remember the desired skipSwapBarrierWar setting for enable master calls. 2470 pThis->Iface[iface].skipSwapBarrierWar = skipSwapBarrierWar; 2471 } 2472 else 2473 { 2474 // Fetch the real skipSwapBarrierWar value from cache in case of an unsync call. 2475 skipSwapBarrierWar = pThis->Iface[iface].skipSwapBarrierWar; 2476 // And reset the cached value. 2477 pThis->Iface[iface].skipSwapBarrierWar = NV_FALSE; 2478 } 2479 2480 // 2481 // Fpga revisions <= 5 need to sw the swapbarrier on the framelock master 2482 // to drive the swap_rdy signal. This can be overridden by skipSwapBarrierWar. 2483 // 2484 if ((!skipSwapBarrierWar) && 2485 needsMasterBarrierWar(&pThis->ExternalDevice)) 2486 { 2487 // enable/disable SwapRdy for GPU during enable/disable of Framelock Master. 2488 rmStatus = gsyncUpdateSwapRdyConnectionForGpu_P2060(pGpu, pThis, bEnableMaster); 2489 if (NV_OK != rmStatus) 2490 { 2491 NV_PRINTF(LEVEL_ERROR, 2492 "Failed to update SwapRdyEnable. Can not program Master.\n"); 2493 return rmStatus; 2494 } 2495 } 2496 } 2497 2498 // now we're ready to let the software know about it. 2499 for ( head = 0; head < numHeads; head++ ) 2500 { 2501 // is this head the desired master, or are we are disabling mastership? 2502 // If mastership is currently disabled, don't touch cache as this could destroy slave values.0 2503 if ((Master & DisplayIds[head]) || (!bEnableMaster && bQSyncAlreadyMaster)) 2504 { 2505 pThis->Iface[iface].Sync.Master[head] = (bEnableMaster); 2506 pThis->Iface[iface].Sync.Slaved[head] = (bEnableMaster && bHouseSelect); 2507 2508 gsyncProgramFramelockEnable_P2060(pGpu, pThis, iface, bEnableMaster); 2509 } 2510 else 2511 { 2512 // we are setting a master, but it's not on this head, so just to be safe: 2513 pThis->Iface[iface].Sync.Master[head] = 0; 2514 } 2515 } 2516 2517 if (!bEnableMaster && !gsyncIsFrameLocked_P2060(pThis)) 2518 { 2519 // Disable Framelock interrupts as board is not framelocked now. 2520 gsyncDisableFrameLockInterrupt_P2060((PDACEXTERNALDEVICE)pThis); 2521 2522 rmStatus = gsyncUnApplyStereoPinAlwaysHiWar(pGpu); 2523 2524 if (NV_OK != rmStatus) 2525 { 2526 NV_PRINTF(LEVEL_ERROR, 2527 "Failed to drive stereo output pin for bug3362661.\n"); 2528 } 2529 } 2530 2531 if (!IsSLIEnabled(pGpu)) 2532 { 2533 NvU32 otherGpuId; 2534 OBJGPU *pOtherGpu; 2535 RM_API *pRmApi; 2536 NvU32 hClient; 2537 NvU32 hSubdevice; 2538 NvU32 Slaves, drOut, drIn; 2539 NvU32 tempIface; 2540 NV2080_CTRL_INTERNAL_GSYNC_SET_OR_RESTORE_RASTER_SYNC_PARAMS ctrlParams = {0}; 2541 2542 for (tempIface = 0; tempIface < NV_P2060_MAX_IFACES_PER_GSYNC; tempIface++) 2543 { 2544 if (tempIface == iface) 2545 { 2546 continue; 2547 } 2548 2549 otherGpuId = pThis->Iface[tempIface].GpuInfo.gpuId; 2550 if (otherGpuId == NV0000_CTRL_GPU_INVALID_ID) 2551 { 2552 continue; 2553 } 2554 2555 pOtherGpu = gpumgrGetGpuFromId(otherGpuId); 2556 NV_ASSERT(pOtherGpu); 2557 2558 if (gpumgrGetGpuLockAndDrPorts(pGpu, pOtherGpu, &drOut, &drIn) != NV_OK) 2559 { 2560 continue; 2561 } 2562 // 2563 // If this is the master gpu, we need to disable the raster sync 2564 // gpio on the other P2060 GPU that's connected to master over 2565 // Video bridge. Otherwise, if the video bridge is connected, 2566 // the raster sync signals from the two cards will interfere, 2567 // giving us an unreliable sync signal. 2568 // 2569 pRmApi = GPU_GET_PHYSICAL_RMAPI(pOtherGpu); 2570 hClient = pOtherGpu->hInternalClient; 2571 hSubdevice = pOtherGpu->hInternalSubdevice; 2572 2573 ctrlParams.bEnableMaster = bEnableMaster; 2574 ctrlParams.bRasterSyncGpioSaved = pThis->Iface[tempIface].RasterSyncGpio.saved; 2575 ctrlParams.bRasterSyncGpioDirection = pThis->Iface[tempIface].RasterSyncGpio.direction; 2576 2577 rmStatus = pRmApi->Control(pRmApi, hClient, hSubdevice, 2578 NV2080_CTRL_CMD_INTERNAL_GSYNC_SET_OR_RESTORE_RASTER_SYNC, 2579 &ctrlParams, sizeof(ctrlParams)); 2580 2581 if (rmStatus != NV_OK) 2582 { 2583 NV_PRINTF(LEVEL_ERROR, "Extdev control call to save/restore GPIO direction is failed!\n"); 2584 } 2585 else 2586 { 2587 if (bEnableMaster && !pThis->Iface[tempIface].RasterSyncGpio.saved) 2588 { 2589 pThis->Iface[tempIface].RasterSyncGpio.direction = ctrlParams.bRasterSyncGpioDirection; 2590 pThis->Iface[tempIface].RasterSyncGpio.saved = NV_TRUE; 2591 } 2592 else if (!bEnableMaster && pThis->Iface[tempIface].RasterSyncGpio.saved) 2593 { 2594 pThis->Iface[tempIface].RasterSyncGpio.saved = NV_FALSE; 2595 } 2596 } 2597 2598 Slaves = gsyncReadSlaves_P2060(pOtherGpu, pThis); 2599 if (Slaves) 2600 { 2601 rmStatus = gsyncProgramSlaves_P2060(pOtherGpu, pThis, Slaves); 2602 if (NV_OK != rmStatus) 2603 { 2604 NV_PRINTF(LEVEL_ERROR, 2605 "Failed to program SLI slaves. Can not program Master.\n"); 2606 return rmStatus; 2607 } 2608 } 2609 } 2610 } 2611 2612 // Reset the frame count data and also disable frame compare match interrupt. 2613 if (!bEnableMaster) 2614 { 2615 iface = pThis->FrameCountData.iface; 2616 head = pThis->FrameCountData.head; 2617 2618 if ((iface < NV_P2060_MAX_IFACES_PER_GSYNC) && (head < numHeads)) 2619 { 2620 rmStatus |= gsyncResetFrameCountData_P2060(pGpu, pThis); 2621 } 2622 } 2623 return rmStatus; 2624 } 2625 2626 /* 2627 * Read Framelock Master P2060. 2628 */ 2629 static NvU32 2630 gsyncReadMaster_P2060 2631 ( 2632 OBJGPU *pGpu, 2633 PDACP2060EXTERNALDEVICE pThis 2634 ) 2635 { 2636 KernelDisplay *pKernelDisplay = GPU_GET_KERNEL_DISPLAY(pGpu); 2637 NvU32 DisplayIds[OBJ_MAX_HEADS]; 2638 NvU32 iface, head; 2639 NvU32 Master = 0; 2640 NV_STATUS status; 2641 NvU32 numHeads = kdispGetNumHeads(pKernelDisplay); 2642 2643 extdevGetBoundHeadsAndDisplayIds(pGpu, DisplayIds); 2644 2645 status = GetP2060GpuLocation(pGpu, pThis, &iface); 2646 if (NV_OK != status) 2647 return 0; 2648 2649 for ( head = 0; head < numHeads; head++ ) 2650 { 2651 if (pThis->Iface[iface].Sync.Master[head]) 2652 { 2653 Master |= DisplayIds[head]; 2654 } 2655 } 2656 2657 // check hardware's opinion on the Master Gsync and Timing source GPU. 2658 if (gsyncIsP2060MasterBoard(pGpu, pThis) && 2659 GpuIsP2060Master(pGpu, pThis)) 2660 { 2661 if (Master) 2662 { 2663 return Master; 2664 } 2665 else 2666 { 2667 // HW is set to be master, but SW isn't treating it as master? 2668 // we must be on external sync, so no one display is associated... 2669 return ~0; 2670 } 2671 } 2672 else 2673 { 2674 // if HW says it's not the master, SW's opinion doesn't count. 2675 return 0; 2676 } 2677 } 2678 2679 /* 2680 * Program P2060 Slave for framelock. 2681 */ 2682 static NV_STATUS 2683 gsyncProgramSlaves_P2060 2684 ( 2685 OBJGPU *pGpu, 2686 PDACP2060EXTERNALDEVICE pThis, 2687 NvU32 Slaves 2688 ) 2689 { 2690 KernelDisplay *pKernelDisplay = GPU_GET_KERNEL_DISPLAY(pGpu); 2691 NvU32 DisplayIds[OBJ_MAX_HEADS]; 2692 NvU32 iface, head, index; 2693 NvU8 ctrl = 0, ctrl3 = 0; 2694 NvBool bCoupled, bHouseSelect, bLocalMaster, bEnableSlaves = (0 != Slaves); 2695 NV_STATUS rmStatus = NV_OK; 2696 NvU32 numHeads = kdispGetNumHeads(pKernelDisplay); 2697 2698 // This utility fn returns display id's associated with each head. 2699 extdevGetBoundHeadsAndDisplayIds(pGpu, DisplayIds); 2700 2701 // which gpu's are we talking to? 2702 rmStatus = GetP2060GpuLocation(pGpu, pThis, &iface); 2703 if (NV_OK != rmStatus) 2704 { 2705 NV_PRINTF(LEVEL_ERROR, 2706 "Failed to get Gpu location. Can not program Slave.\n"); 2707 return rmStatus; 2708 } 2709 2710 rmStatus = readregu008_extdeviceTargeted(pGpu, (PDACEXTERNALDEVICE)pThis, 2711 (NvU8)NV_P2060_CONTROL, &ctrl); 2712 if (NV_OK != rmStatus) 2713 { 2714 NV_PRINTF(LEVEL_ERROR, 2715 "Failed to read ctrl register. Can not program slave.\n"); 2716 return rmStatus; // ouch 2717 } 2718 2719 // Check for House sync select as sync source and FPGA board is master or not 2720 bHouseSelect = FLD_TEST_DRF(_P2060, _CONTROL, _SYNC_SELECT, _HOUSE, (NvU32)ctrl); 2721 bLocalMaster = FLD_TEST_DRF(_P2060, _CONTROL, _I_AM, _MASTER, (NvU32)ctrl); 2722 2723 if (bEnableSlaves || bLocalMaster) 2724 { 2725 rmStatus = gsyncApplyStereoPinAlwaysHiWar(pGpu, (PDACEXTERNALDEVICE)pThis); 2726 2727 if (NV_OK != rmStatus) 2728 { 2729 NV_PRINTF(LEVEL_ERROR, 2730 "Failed to drive stereo output pin for bug3362661.\n"); 2731 } 2732 } 2733 2734 if (bHouseSelect && bEnableSlaves && bLocalMaster) 2735 { 2736 rmStatus = readregu008_extdeviceTargeted(pGpu, (PDACEXTERNALDEVICE)pThis, 2737 (NvU8)NV_P2060_CONTROL3, &ctrl3); 2738 if (rmStatus != NV_OK) 2739 { 2740 NV_PRINTF(LEVEL_ERROR, 2741 "Failed to read ctrl3 register. Can not program slave.\n"); 2742 return rmStatus; 2743 } 2744 ctrl3 |= (NvU8) FLD_SET_DRF(_P2060, _CONTROL3, _RESYNC, _ON, (NvU32)ctrl3); 2745 writeregu008_extdeviceTargeted(pGpu, (PDACEXTERNALDEVICE)pThis, 2746 (NvU8)NV_P2060_CONTROL3, ctrl3); 2747 } 2748 2749 // 2750 // No need to check for every gpu connected to this gsync board. If gsync board 2751 // is not master/server, none of the gpu connected to it will have master head. 2752 // 2753 2754 if (bEnableSlaves && !bLocalMaster) 2755 { 2756 // 2757 // Sync source should be taken from GPU connected to Gsync board. 2758 // Get index of current GPU and make it sync source. 2759 // No idea is this safe or not. Adding TODO for future check. 2760 // 2761 rmStatus = GetP2060ConnectorIndexFromGpu(pGpu, pThis, &index); 2762 if (NV_OK != rmStatus) 2763 { 2764 NV_PRINTF(LEVEL_ERROR, 2765 "Failed to get connector index for Gpu. Can not program slave.\n"); 2766 return rmStatus; 2767 } 2768 2769 ctrl = FLD_SET_DRF_NUM(_P2060, _CONTROL, _SYNC_SRC, (NvU8)index, ctrl); 2770 2771 rmStatus = writeregu008_extdeviceTargeted(pGpu, (PDACEXTERNALDEVICE) pThis, 2772 (NvU8)NV_P2060_CONTROL, ctrl); 2773 if (NV_OK != rmStatus) 2774 { 2775 NV_PRINTF(LEVEL_ERROR, 2776 "Failed to write SYNC_SRC. Can not program slave.\n"); 2777 return rmStatus; 2778 } 2779 } 2780 2781 // 2782 // With House sync enabled the crashlocking still need some investigations. 2783 // So filter out Housesyced systems before doing local crashlocks. 2784 // 2785 if ((!bHouseSelect) && bEnableSlaves && bLocalMaster) 2786 { 2787 rmStatus = readregu008_extdeviceTargeted(pGpu, (PDACEXTERNALDEVICE)pThis, 2788 (NvU8)NV_P2060_CONTROL3, &ctrl3); 2789 if (rmStatus != NV_OK) 2790 { 2791 NV_PRINTF(LEVEL_ERROR, 2792 "Failed to read ctrl3 register. Can not program slave.\n"); 2793 return rmStatus; 2794 } 2795 ctrl3 |= (NvU8) FLD_SET_DRF(_P2060, _CONTROL3, _RESYNC, _ON, (NvU32)ctrl3); 2796 writeregu008_extdeviceTargeted(pGpu, (PDACEXTERNALDEVICE)pThis, 2797 (NvU8)NV_P2060_CONTROL3, ctrl3); 2798 } 2799 2800 // 2801 // If we on the same gpu as the framelock master, the P2060 will 2802 // not servo, so we must rely on the gpu to get our timing... 2803 // unless house sync is expected, in which case we get it back. 2804 // 2805 bCoupled = (!bLocalMaster) || (bHouseSelect); 2806 2807 // disable all existing slaves before enabling new slaves. 2808 if (bEnableSlaves) 2809 { 2810 for ( head = 0; head < numHeads; head++ ) 2811 { 2812 pThis->Iface[iface].Sync.Slaved[head] = 0; 2813 pThis->Iface[iface].Sync.LocalSlave[head] = 0; 2814 } 2815 } 2816 2817 for ( head = 0; head < numHeads; head++ ) 2818 { 2819 // is this head to be slaved, or are we freeing all slaves? 2820 if ((Slaves & DisplayIds[head]) || !bEnableSlaves) 2821 { 2822 pThis->Iface[iface].Sync.Slaved[head] = (bEnableSlaves && bCoupled); 2823 pThis->Iface[iface].Sync.LocalSlave[head] = (bEnableSlaves && !bCoupled); 2824 2825 gsyncProgramFramelockEnable_P2060(pGpu, pThis, iface, bEnableSlaves); 2826 } 2827 else 2828 { 2829 // we are setting a slave, but it's not on this head, so nothing needs doing. 2830 } 2831 } 2832 2833 if (!bEnableSlaves && !gsyncIsFrameLocked_P2060(pThis)) 2834 { 2835 // Disable Framelock interrupts as board is not framelocked now. 2836 gsyncDisableFrameLockInterrupt_P2060((PDACEXTERNALDEVICE)pThis); 2837 2838 rmStatus = gsyncUnApplyStereoPinAlwaysHiWar(pGpu); 2839 2840 if (NV_OK != rmStatus) 2841 { 2842 NV_PRINTF(LEVEL_ERROR, 2843 "Failed to drive stereo output pin for bug3362661.\n"); 2844 } 2845 } 2846 2847 // Reset FrameCountData and disable frame compare match interrupt. 2848 if (iface == pThis->FrameCountData.iface) 2849 { 2850 if (!(Slaves & DisplayIds[pThis->FrameCountData.head])) 2851 { 2852 if (pThis->Iface[iface].GpuInfo.gpuId != NV0000_CTRL_GPU_INVALID_ID) 2853 { 2854 rmStatus |= gsyncResetFrameCountData_P2060(pGpu, pThis); 2855 } 2856 } 2857 } 2858 return rmStatus; 2859 } 2860 2861 /* 2862 * Read P2060 slave for framelock. 2863 */ 2864 static NvU32 2865 gsyncReadSlaves_P2060 2866 ( 2867 OBJGPU *pGpu, 2868 PDACP2060EXTERNALDEVICE pThis 2869 ) 2870 { 2871 KernelDisplay *pKernelDisplay = GPU_GET_KERNEL_DISPLAY(pGpu); 2872 NvU32 DisplayIds[OBJ_MAX_HEADS]; 2873 NvU32 iface, head; 2874 NvU32 Slaves = 0; 2875 NV_STATUS status; 2876 NvU32 numHeads = kdispGetNumHeads(pKernelDisplay); 2877 2878 extdevGetBoundHeadsAndDisplayIds(pGpu, DisplayIds); 2879 2880 status = GetP2060GpuLocation(pGpu, pThis, &iface); 2881 if (NV_OK != status) 2882 return 0; 2883 2884 for ( head = 0; head < numHeads; head++ ) 2885 { 2886 if (!pThis->Iface[iface].Sync.Master[head] && 2887 (pThis->Iface[iface].Sync.Slaved[head] || pThis->Iface[iface].Sync.LocalSlave[head])) 2888 { 2889 Slaves |= DisplayIds[head]; 2890 } 2891 } 2892 return Slaves; 2893 } 2894 2895 static NV_STATUS 2896 gsyncProgramSwapBarrier_P2060 2897 ( 2898 OBJGPU *pGpu, 2899 PDACEXTERNALDEVICE pExtDev, 2900 NvBool bEnable 2901 ) 2902 { 2903 PDACP2060EXTERNALDEVICE pThis = (PDACP2060EXTERNALDEVICE) pExtDev; 2904 NvU32 iface; 2905 NvU8 ctrl2 = 0; 2906 NV_STATUS status = NV_OK; 2907 2908 status = GetP2060GpuLocation(pGpu, pThis, &iface); 2909 if (NV_OK != status) 2910 { 2911 if (!IsSLIEnabled(pGpu)) 2912 { 2913 // 2914 // If not in SLI, this function must only be called on GPUs connected 2915 // to the framelock board. 2916 // 2917 return status; 2918 } 2919 else 2920 { 2921 // 2922 // In SLI, we will try to add all GPUs in a topology to a swap 2923 // barrier, but not all of the GPUs actually have to be connected to 2924 // the framelock board, so we can return NV_OK to let the caller continue 2925 // on to the next GPU. 2926 // 2927 NV_PRINTF(LEVEL_INFO, 2928 "Ignoring GPU %u not connected to the framelock board.\n", 2929 gpumgrGetSubDeviceInstanceFromGpu(pGpu)); 2930 return NV_OK; 2931 } 2932 } 2933 2934 // Each connected GPU accesses it's own version of CONTROL2, on P2060 2935 if (GpuIsP2060Connected(pGpu, pThis)) 2936 { 2937 status = readregu008_extdeviceTargeted(pGpu, pExtDev, 2938 NV_P2060_CONTROL2, &ctrl2); 2939 if (status != NV_OK) 2940 { 2941 return status; 2942 } 2943 2944 if (pExtDev->deviceRev >= DAC_EXTERNAL_DEVICE_REV_MAX) 2945 { 2946 return NV_ERR_INVALID_STATE; 2947 } 2948 } 2949 2950 if (pThis->Iface[iface].SwapReadyRequested == bEnable) 2951 { 2952 // 2953 // The SwapReadyRequested boolean keeps tracks of the current 2954 // requested state for this GPU. Skip the WAR algorithm if it's 2955 // already taken this GPU's state into account. 2956 // 2957 return NV_OK; 2958 } 2959 2960 if (bEnable) // Enable Swap_rdy 2961 { 2962 ctrl2 = FLD_SET_DRF(_P2060, _CONTROL2, _SWAP_READY, _ENABLE, ctrl2); 2963 2964 if (pThis->tSwapRdyHiLsrMinTime == 0) 2965 { 2966 NvU32 data = 0; 2967 2968 // store Swap Lockout Window in pThis. 2969 pThis->tSwapRdyHiLsrMinTime = NV_REG_STR_TIME_SWAP_RDY_HI_MODIFY_LSR_MIN_TIME_DEFAULT; 2970 if (osReadRegistryDword(pGpu, 2971 NV_REG_STR_TIME_SWAP_RDY_HI_MODIFY_LSR_MIN_TIME, &data) == NV_OK) 2972 { 2973 pThis->tSwapRdyHiLsrMinTime = data; 2974 } 2975 } 2976 2977 NV_ASSERT(pThis->tSwapRdyHiLsrMinTime != 0); 2978 2979 if (pThis->Iface[iface].DsiFliplock.saved == NV_FALSE) 2980 { 2981 KernelDisplay *pKernelDisplay = GPU_GET_KERNEL_DISPLAY(pGpu); 2982 NvU32 numHeads = kdispGetNumHeads(pKernelDisplay); 2983 NvU32 head ; 2984 2985 for (head = 0; head < numHeads; head++) 2986 { 2987 NvU32 newLsrMinTime; 2988 if ((status = kdispComputeLsrMinTimeValue_HAL(pGpu, pKernelDisplay, head, 2989 pThis->tSwapRdyHiLsrMinTime, &newLsrMinTime)) == NV_OK) 2990 { 2991 NvU32 origLsrMinTime; 2992 kdispSetSwapBarrierLsrMinTime_HAL(pGpu, pKernelDisplay, head, &origLsrMinTime, 2993 newLsrMinTime); 2994 2995 pThis->Iface[iface].DsiFliplock.OrigLsrMinTime[head] = origLsrMinTime; 2996 } 2997 else 2998 { 2999 NV_PRINTF(LEVEL_ERROR, 3000 "Error occured while computing LSR_MIN_TIME for Swap Barrier\n"); 3001 NV_ASSERT(0); 3002 } 3003 } 3004 pThis->Iface[iface].DsiFliplock.saved = NV_TRUE; 3005 } 3006 3007 // The swapbarrier on master war is assumed to be fixed with fpga rev > 5. 3008 if ((!pThis->Iface[iface].skipSwapBarrierWar) && 3009 needsMasterBarrierWar(&pThis->ExternalDevice)) 3010 { 3011 if (gsyncIsP2060MasterBoard(pGpu, pThis) && GpuIsP2060Master(pGpu, pThis)) 3012 { 3013 // 3014 // Swap Rdy signal on Master + TS GPU will enabled or disabled during 3015 // Enable/Disable of Master i.e. gsyncProgramMaster_P2060 3016 // 3017 pThis->Iface[iface].SwapReadyRequested = bEnable; 3018 return NV_OK; 3019 } 3020 } 3021 3022 if (GpuIsConnectedToMasterViaBridge(pGpu, pThis) && 3023 (gpumgrGetGpuBridgeType() == SLI_BT_VIDLINK || isBoardWithNvlinkQsyncContention(pGpu))) 3024 { 3025 // 3026 // Do not enable swapRdy Connection of pGpu. pGpu will take swap Rdy signal 3027 // from Master + TS GPU via SLI (MIO) bridge 3028 // 3029 pThis->Iface[iface].SwapReadyRequested = bEnable; 3030 return status; //NV_OK 3031 } 3032 } 3033 else 3034 { 3035 ctrl2 = FLD_SET_DRF(_P2060, _CONTROL2, _SWAP_READY, _DISABLE, ctrl2); // Disable Swap_rdy 3036 3037 if (pThis->Iface[iface].DsiFliplock.saved == NV_TRUE) 3038 { 3039 KernelDisplay *pKernelDisplay = GPU_GET_KERNEL_DISPLAY(pGpu); 3040 NvU32 numHeads = kdispGetNumHeads(pKernelDisplay); 3041 NvU32 head ; 3042 3043 for (head = 0; head < numHeads; head++) 3044 { 3045 kdispRestoreOriginalLsrMinTime_HAL(pGpu, pKernelDisplay, head, 3046 pThis->Iface[iface].DsiFliplock.OrigLsrMinTime[head]); 3047 } 3048 pThis->Iface[iface].DsiFliplock.saved = NV_FALSE; 3049 } 3050 3051 // The swapbarrier on master war is assumed to be fixed with fpga rev > 5. 3052 if ((!pThis->Iface[iface].skipSwapBarrierWar) && 3053 needsMasterBarrierWar(&pThis->ExternalDevice)) 3054 { 3055 if (gsyncIsP2060MasterBoard(pGpu, pThis) && GpuIsP2060Master(pGpu, pThis)) 3056 { 3057 // 3058 // Swap Rdy signal on Master + TS GPU will enabled or disabled during 3059 // Enable/Disable of Master i.e. gsyncProgramMaster_P2060 3060 // 3061 pThis->Iface[iface].SwapReadyRequested = bEnable; 3062 return NV_OK; 3063 } 3064 } 3065 } 3066 3067 // Save the requested state for this GPU 3068 pThis->Iface[iface].SwapReadyRequested = bEnable; 3069 3070 // Each connected GPU accesses it's own version of CONTROL2, on P2060 3071 if (GpuIsP2060Connected(pGpu, pThis)) 3072 { 3073 status = writeregu008_extdeviceTargeted(pGpu, pExtDev, 3074 NV_P2060_CONTROL2, ctrl2); 3075 } 3076 3077 return status; 3078 } 3079 3080 3081 static NV_STATUS 3082 gsyncReadSwapBarrier_P2060 3083 ( 3084 OBJGPU *pGpu, 3085 PDACEXTERNALDEVICE pExtDev, 3086 NvBool *bEnable 3087 ) 3088 { 3089 PDACP2060EXTERNALDEVICE pThis = (PDACP2060EXTERNALDEVICE) pExtDev; 3090 NvU32 iface; 3091 NV_STATUS status = NV_OK; 3092 3093 status = GetP2060GpuLocation(pGpu, pThis, &iface); 3094 if (NV_OK != status) 3095 { 3096 if (!IsSLIEnabled(pGpu)) 3097 { 3098 // 3099 // If not in SLI, this function must only be called on GPUs connected 3100 // to the framelock board. 3101 // 3102 return status; 3103 } 3104 else 3105 { 3106 // 3107 // In SLI, we will try to read the swap barrier info from all GPUs in a 3108 // topology, but not all of the GPUs actually have to be connected to 3109 // the framelock board, so we can return NV_OK to let the caller continue 3110 // on to the next GPU. 3111 // 3112 NV_PRINTF(LEVEL_INFO, 3113 "Ignoring GPU %u not connected to the framelock board.\n", 3114 gpumgrGetSubDeviceInstanceFromGpu(pGpu)); 3115 return NV_OK; 3116 } 3117 } 3118 3119 if (gsyncIsP2060MasterBoard(pGpu, pThis) && GpuIsP2060Master(pGpu, pThis)) 3120 { 3121 // Read swapRdy of Master + TS GPU. 3122 *bEnable = pThis->Iface[iface].SwapReadyRequested; 3123 return status; //NV_OK 3124 } 3125 3126 if (GpuIsConnectedToMasterViaBridge(pGpu, pThis) && 3127 (gpumgrGetGpuBridgeType() == SLI_BT_VIDLINK || isBoardWithNvlinkQsyncContention(pGpu))) 3128 { 3129 // Read swapRdy of pGpu connected to Master + TS GPU via SLI (MIO) bridge. 3130 *bEnable = pThis->Iface[iface].SwapReadyRequested; 3131 return status; //NV_OK 3132 } 3133 3134 // Each connected GPU accesses it's own version of CONTROL2, on P2060 3135 if (GpuIsP2060Connected(pGpu, pThis)) 3136 { 3137 NvU8 ctrl2 = 0; 3138 status = readregu008_extdeviceTargeted(pGpu, 3139 pExtDev, NV_P2060_CONTROL2, &ctrl2); 3140 if (status != NV_OK) 3141 { 3142 return status; 3143 } 3144 *bEnable = (NV_P2060_CONTROL2_SWAP_READY_ENABLE == 3145 DRF_VAL(_P2060, _CONTROL2, _SWAP_READY, (NvU32)ctrl2)); 3146 } 3147 3148 return status; 3149 } 3150 3151 static NV_STATUS 3152 gsyncSetLsrMinTime 3153 ( 3154 OBJGPU *pSourceGpu, 3155 PDACEXTERNALDEVICE pExtDev, 3156 NvU32 enable 3157 ) 3158 { 3159 PDACP2060EXTERNALDEVICE pThis = (PDACP2060EXTERNALDEVICE)pExtDev; 3160 NV_STATUS rmStatus = NV_OK; 3161 NvU32 index; 3162 3163 // Get Mosaic Timing Source GPU Connector Index. 3164 if (NV_OK != GetP2060ConnectorIndexFromGpu(pSourceGpu, pThis, &index)) 3165 { 3166 return NV_ERR_GENERIC; 3167 } 3168 3169 if (enable) 3170 { 3171 // Set LSR_MIN_TIME 3172 if (pThis->tSwapRdyHiLsrMinTime == 0) 3173 { 3174 NvU32 data = 0; 3175 3176 // store Swap Lockout Window in pThis. 3177 pThis->tSwapRdyHiLsrMinTime = NV_REG_STR_TIME_SWAP_RDY_HI_MODIFY_LSR_MIN_TIME_DEFAULT; 3178 3179 if (osReadRegistryDword(pSourceGpu, 3180 NV_REG_STR_TIME_SWAP_RDY_HI_MODIFY_LSR_MIN_TIME, &data) == NV_OK) 3181 { 3182 pThis->tSwapRdyHiLsrMinTime = data; 3183 } 3184 } 3185 3186 if (pThis->Iface[index].DsiFliplock.saved == NV_FALSE) 3187 { 3188 KernelDisplay *pKernelDisplay = GPU_GET_KERNEL_DISPLAY(pSourceGpu); 3189 NvU32 numHeads = kdispGetNumHeads(pKernelDisplay); 3190 NvU32 head; 3191 3192 // Do we need to loop over numHeads? 3193 for (head = 0; head < numHeads; head++) 3194 { 3195 NvU32 newLsrMinTime; 3196 3197 if ((rmStatus = kdispComputeLsrMinTimeValue_HAL(pSourceGpu, pKernelDisplay, head, 3198 pThis->tSwapRdyHiLsrMinTime, &newLsrMinTime)) == NV_OK) 3199 { 3200 NvU32 origLsrMinTime; 3201 3202 kdispSetSwapBarrierLsrMinTime_HAL(pSourceGpu, pKernelDisplay, head, &origLsrMinTime, 3203 newLsrMinTime); 3204 3205 pThis->Iface[index].DsiFliplock.OrigLsrMinTime[head] = origLsrMinTime; 3206 } 3207 else 3208 { 3209 NV_PRINTF(LEVEL_ERROR, 3210 "Error occured while computing LSR_MIN_TIME for Swap Barrier\n"); 3211 NV_ASSERT(0); 3212 } 3213 } 3214 3215 pThis->Iface[index].DsiFliplock.saved = NV_TRUE; 3216 } 3217 } 3218 else 3219 { 3220 if (pThis->Iface[index].DsiFliplock.saved == NV_TRUE) 3221 { 3222 KernelDisplay *pKernelDisplay = GPU_GET_KERNEL_DISPLAY(pSourceGpu); 3223 NvU32 numHeads = kdispGetNumHeads(pKernelDisplay); 3224 NvU32 head; 3225 3226 for (head = 0; head < numHeads; head++) 3227 { 3228 kdispRestoreOriginalLsrMinTime_HAL(pSourceGpu, pKernelDisplay, head, 3229 pThis->Iface[index].DsiFliplock.OrigLsrMinTime[head]); 3230 } 3231 3232 pThis->Iface[index].DsiFliplock.saved = NV_FALSE; 3233 } 3234 } 3235 3236 return rmStatus; 3237 } 3238 3239 NV_STATUS 3240 gsyncSetMosaic_P2060 3241 ( 3242 OBJGPU *pSourceGpu, 3243 PDACEXTERNALDEVICE pExtDev, 3244 NV30F1_CTRL_GSYNC_SET_LOCAL_SYNC_PARAMS *pParams 3245 ) 3246 { 3247 PDACP2060EXTERNALDEVICE pThis = (PDACP2060EXTERNALDEVICE)pExtDev; 3248 NV_STATUS rmStatus = NV_OK; 3249 OBJGPU *pTempGpu = NULL; 3250 NvU8 mosaicReg, i; 3251 NvU32 mosaicGroup = pParams->mosaicGroupNumber; 3252 3253 if (mosaicGroup >= NV_P2060_MAX_MOSAIC_GROUPS) 3254 { 3255 NV_PRINTF(LEVEL_ERROR, 3256 "mosaicGroup equaling/extending NV_P2060_MAX_MOSAIC_GROUPS.\n"); 3257 return NV_ERR_INVALID_ARGUMENT; 3258 } 3259 3260 if (pParams->slaveGpuCount > NV_P2060_MAX_MOSAIC_SLAVES) 3261 { 3262 NV_PRINTF(LEVEL_ERROR, 3263 "mosaic slaveGpuCount extending NV_P2060_MAX_MOSAIC_SLAVES.\n"); 3264 return NV_ERR_INVALID_ARGUMENT; 3265 } 3266 3267 if (pParams->enableMosaic) { 3268 3269 NvU32 index; 3270 if (pThis->MosaicGroup[mosaicGroup].enabledMosaic) 3271 { 3272 // mosaic is already enabled for this group, 3273 // client should disable it first and re-query for this group. 3274 NV_PRINTF(LEVEL_ERROR, 3275 "trying to enable mosaicGroup which is already enabled.\n"); 3276 return NV_ERR_INVALID_ARGUMENT; 3277 } 3278 3279 // Get Mosaic Timing Source GPU Connector Index. 3280 if ( NV_OK != GetP2060ConnectorIndexFromGpu(pSourceGpu, pThis, &index)) 3281 { 3282 return NV_ERR_GENERIC; 3283 } 3284 3285 pThis->MosaicGroup[mosaicGroup].slaveGpuCount = pParams->slaveGpuCount; 3286 pThis->MosaicGroup[mosaicGroup].gpuTimingSource = pThis->Iface[index].GpuInfo.gpuId; 3287 3288 for (i = 0; i < pThis->MosaicGroup[mosaicGroup].slaveGpuCount; i++) 3289 { 3290 pThis->MosaicGroup[mosaicGroup].gpuTimingSlaves[i] = pParams->gpuTimingSlaves[i]; 3291 3292 pTempGpu = gpumgrGetGpuFromId(pParams->gpuTimingSlaves[i]); 3293 NV_ASSERT_OR_RETURN(pTempGpu, NV_ERR_GENERIC); 3294 3295 // Update register of mosaic timing slaves first 3296 mosaicReg = 0; 3297 mosaicReg = FLD_SET_DRF_NUM(_P2060, _MOSAIC_MODE, _TS, (NvU8)index, mosaicReg); 3298 mosaicReg = FLD_SET_DRF_NUM(_P2060, _MOSAIC_MODE, _GROUP, (NvU8)mosaicGroup, mosaicReg); 3299 mosaicReg = FLD_SET_DRF(_P2060, _MOSAIC_MODE, _ENABLE, _TRUE, mosaicReg); 3300 3301 rmStatus |= writeregu008_extdeviceTargeted(pTempGpu, 3302 (PDACEXTERNALDEVICE)pThis, NV_P2060_MOSAIC_MODE, mosaicReg); 3303 if (rmStatus != NV_OK) 3304 { 3305 NV_PRINTF(LEVEL_ERROR, 3306 "Failed to write P2060 mosaic slave register.\n"); 3307 return NV_ERR_GENERIC; 3308 } 3309 3310 // Set LSR_MIN_TIME 3311 gsyncSetLsrMinTime(pTempGpu, pExtDev, pParams->enableMosaic); 3312 } 3313 3314 gsyncSetLsrMinTime(pSourceGpu, pExtDev, pParams->enableMosaic); 3315 3316 // Update registers of mosaic timing source. 3317 mosaicReg = 0; 3318 mosaicReg = FLD_SET_DRF_NUM(_P2060, _MOSAIC_MODE, _TS, (NvU8)index, mosaicReg); 3319 mosaicReg = FLD_SET_DRF_NUM(_P2060, _MOSAIC_MODE, _GROUP, (NvU8)mosaicGroup, mosaicReg); 3320 mosaicReg = FLD_SET_DRF(_P2060, _MOSAIC_MODE, _ENABLE, _TRUE, mosaicReg); 3321 3322 rmStatus |= writeregu008_extdeviceTargeted(pSourceGpu, 3323 (PDACEXTERNALDEVICE)pThis, NV_P2060_MOSAIC_MODE, mosaicReg); 3324 if (rmStatus != NV_OK) 3325 { 3326 NV_PRINTF(LEVEL_ERROR, 3327 "Failed to write P2060 mosaic Source register.\n"); 3328 return NV_ERR_GENERIC; 3329 } 3330 3331 // Mark as Mosaic enabled for specified group 3332 pThis->MosaicGroup[mosaicGroup].enabledMosaic = NV_TRUE; 3333 } 3334 else 3335 { 3336 if (!pThis->MosaicGroup[mosaicGroup].enabledMosaic) 3337 { 3338 // mosaicgroup is not enabled, so can not disable 3339 NV_PRINTF(LEVEL_ERROR, 3340 "trying to disable mosaicGroup which is not enabled.\n"); 3341 return NV_ERR_INVALID_ARGUMENT; 3342 } 3343 3344 for (i = 0; i < pThis->MosaicGroup[mosaicGroup].slaveGpuCount; i++) 3345 { 3346 pTempGpu = gpumgrGetGpuFromId(pThis->MosaicGroup[mosaicGroup].gpuTimingSlaves[i]); 3347 NV_ASSERT_OR_RETURN(pTempGpu, NV_ERR_GENERIC); 3348 3349 rmStatus |= writeregu008_extdeviceTargeted(pTempGpu, 3350 (PDACEXTERNALDEVICE)pThis, NV_P2060_MOSAIC_MODE, 0x00); 3351 if (rmStatus != NV_OK) 3352 { 3353 NV_PRINTF(LEVEL_ERROR, 3354 "Failed to write P2060 mosaic slave register.\n"); 3355 return NV_ERR_GENERIC; 3356 } 3357 3358 // Reset LSR_MIN_TIME 3359 gsyncSetLsrMinTime(pTempGpu, pExtDev, pParams->enableMosaic); 3360 } 3361 3362 gsyncSetLsrMinTime(pSourceGpu, pExtDev, pParams->enableMosaic); 3363 3364 rmStatus |= writeregu008_extdeviceTargeted(pSourceGpu, 3365 (PDACEXTERNALDEVICE)pThis, NV_P2060_MOSAIC_MODE, 0x00); 3366 if (rmStatus != NV_OK) 3367 { 3368 NV_PRINTF(LEVEL_ERROR, 3369 "Failed to write P2060 mosaic Source register.\n"); 3370 return NV_ERR_GENERIC; 3371 } 3372 3373 // reset structure for specified group 3374 gsyncResetMosaicData_P2060(mosaicGroup, pThis); 3375 } 3376 3377 return rmStatus; 3378 } 3379 3380 #ifdef DEBUG 3381 /* 3382 * Helper function to printout the most relevant P2060_status 3383 * register informations in a human readable form. 3384 */ 3385 static void 3386 DbgPrintP2060StatusRegister(NvU32 DebugLevel, NvU32 regStatus) 3387 { 3388 if (DRF_VAL(_P2060, _STATUS, _SYNC_LOSS, regStatus)) 3389 NV_PRINTF_EX(NV_PRINTF_MODULE, DebugLevel, "SYNC_LOSS "); 3390 if (DRF_VAL(_P2060, _STATUS, _STEREO, regStatus)) 3391 NV_PRINTF_EX(NV_PRINTF_MODULE, DebugLevel, "STEREO_LOCK "); 3392 if (NV_P2060_STATUS_VCXO_LOCK == DRF_VAL(_P2060, _STATUS, _VCXO, regStatus)) 3393 NV_PRINTF_EX(NV_PRINTF_MODULE, DebugLevel, "VCXO_LOCK "); 3394 if (NV_P2060_STATUS_VCXO_NOLOCK_TOO_FAST == DRF_VAL(_P2060, _STATUS, _VCXO, regStatus)) 3395 NV_PRINTF_EX(NV_PRINTF_MODULE, DebugLevel, "VCXO_NOLOCK_TOO_FAST "); 3396 if (NV_P2060_STATUS_VCXO_NOLOCK_TOO_SLOW == DRF_VAL(_P2060, _STATUS, _VCXO, regStatus)) 3397 NV_PRINTF_EX(NV_PRINTF_MODULE, DebugLevel, "VCXO_NOLOCK_TOO_SLOW "); 3398 if (NV_P2060_STATUS_VCXO_NOT_SERVO == DRF_VAL(_P2060, _STATUS, _VCXO, regStatus)) 3399 NV_PRINTF_EX(NV_PRINTF_MODULE, DebugLevel, "VCXO_NOT_SERVO "); 3400 } 3401 #else 3402 #define DbgPrintP2060StatusRegister(DebugLevel, regStatus) 3403 #endif 3404 3405 static NV_STATUS 3406 gsyncGpuStereoHeadSync(OBJGPU *pGpu, NvU32 iface, PDACEXTERNALDEVICE pExtDev, NvU32 status1) 3407 { 3408 DACP2060EXTERNALDEVICE *pThis = (PDACP2060EXTERNALDEVICE)pExtDev; 3409 KernelDisplay *pKernelDisplay = GPU_GET_KERNEL_DISPLAY(pGpu); 3410 RM_API *pRmApi = GPU_GET_PHYSICAL_RMAPI(pGpu); 3411 NvU32 hClient = pGpu->hInternalClient; 3412 NvU32 hSubdevice = pGpu->hInternalSubdevice; 3413 NV_STATUS status = NV_OK; 3414 NvU32 numHeads = kdispGetNumHeads(pKernelDisplay); 3415 NvU32 headIdx; 3416 NV2080_CTRL_INTERNAL_GSYNC_SET_STREO_SYNC_PARAMS ctrlParams = {0}; 3417 3418 for (headIdx = 0; headIdx < numHeads; headIdx++) 3419 { 3420 ctrlParams.slave[headIdx] = pThis->Iface[iface].Sync.Slaved[headIdx]; 3421 ctrlParams.localSlave[headIdx] = pThis->Iface[iface].Sync.LocalSlave[headIdx]; 3422 ctrlParams.master[headIdx] = pThis->Iface[iface].Sync.Master[headIdx]; 3423 } 3424 3425 ctrlParams.regStatus = status1; 3426 status = pRmApi->Control(pRmApi, hClient, hSubdevice, 3427 NV2080_CTRL_CMD_INTERNAL_GSYNC_SET_STREO_SYNC, 3428 &ctrlParams, sizeof(ctrlParams)); 3429 3430 if (status != NV_OK) 3431 { 3432 NV_PRINTF(LEVEL_ERROR, "Stereo headsync failed\n"); 3433 } 3434 3435 return status; 3436 } 3437 3438 /* 3439 * Update the status register snapshot and 3440 * send loss/gain events to client if any. 3441 */ 3442 static NV_STATUS 3443 gsyncUpdateGsyncStatusSnapshot_P2060 3444 ( 3445 OBJGPU *pGpu, 3446 PDACEXTERNALDEVICE pExtDev 3447 ) 3448 { 3449 PDACP2060EXTERNALDEVICE pThis = (PDACP2060EXTERNALDEVICE)pExtDev; 3450 NvU32 iface; 3451 NvU8 regStatus = 0; 3452 NV_STATUS rmStatus = NV_OK; 3453 NvU32 ifaceEvents[NV_P2060_MAX_IFACES_PER_GSYNC]; 3454 3455 // Only read status variables if the board is framelocked at all. 3456 if (!gsyncIsFrameLocked_P2060(pThis)) 3457 { 3458 return rmStatus; 3459 } 3460 3461 for (iface = 0; iface < NV_P2060_MAX_IFACES_PER_GSYNC; iface++) 3462 { 3463 NvU32 diffStatus = 0x00; 3464 NvU32 oldStatus = 0x00; 3465 NvU32 newStatus = 0x00; 3466 ifaceEvents[iface] = 0x00; 3467 3468 // get status update for each interface 3469 if (pThis->Iface[iface].GpuInfo.gpuId != NV0000_CTRL_GPU_INVALID_ID) 3470 { 3471 int updateSnapshot = 1; 3472 int localMaster = 0; 3473 3474 // Take care of tracking state of connected gpu, not per incoming. 3475 OBJGPU *pIfaceGpu = gpumgrGetGpuFromId(pThis->Iface[iface].GpuInfo.gpuId); 3476 3477 NV_ASSERT(pIfaceGpu); 3478 3479 rmStatus = readregu008_extdeviceTargeted(pIfaceGpu, pExtDev, (NvU8)NV_P2060_STATUS, ®Status); 3480 if ( NV_OK != rmStatus ) 3481 { 3482 return NV_ERR_GENERIC; 3483 } 3484 3485 oldStatus = pThis->Snapshot[iface].Status1; 3486 newStatus = (NvU32)regStatus; 3487 3488 // Check for a local master which generates the sync so it's always synched. 3489 if ( (NV_P2060_STATUS_VCXO_NOT_SERVO == DRF_VAL(_P2060, _STATUS, _VCXO, newStatus)) && 3490 (NV_P2060_STATUS_SYNC_LOSS_FALSE == DRF_VAL(_P2060, _STATUS, _SYNC_LOSS, newStatus))) 3491 { 3492 localMaster = 1; 3493 if (!pThis->Iface[iface].gainedSync) 3494 { 3495 NV_PRINTF(LEVEL_INFO, 3496 "P2060[%d] is local master => GAINED SYNC\n", 3497 iface); 3498 pThis->Iface[iface].gainedSync = 1; 3499 } 3500 } 3501 else 3502 { 3503 // For slaves or masters driven by housesync we need to wait for a sync. 3504 3505 // 1st wait for syncgain before doing anything else. 3506 if ((!pThis->Iface[iface].gainedSync) && 3507 (NV_P2060_STATUS_VCXO_LOCK == DRF_VAL(_P2060, _STATUS, _VCXO, newStatus))) 3508 { 3509 OBJTMR *pTmr = GPU_GET_TIMER(pIfaceGpu); 3510 NvU64 timeDiff; 3511 NvU64 currentTime; 3512 3513 // get the current time 3514 currentTime = tmrGetTime_HAL(pIfaceGpu, pTmr); 3515 3516 // 3517 // Initialize waittime. 3518 // We're using a threshold of 10 seconds before we're accepting sync gain. 3519 // 3520 if (0 == pThis->Snapshot[iface].lastSyncCheckTime) 3521 { 3522 pThis->Snapshot[iface].lastSyncCheckTime = currentTime; 3523 } 3524 3525 // calculate the time difference from last change. 3526 timeDiff = ((currentTime - pThis->Snapshot[iface].lastSyncCheckTime) / 1000000); // time in ms 3527 3528 NV_PRINTF(LEVEL_INFO, 3529 "P2060[%d] snapshot timeDiff is %d ms\n", iface, 3530 (NvU32)timeDiff); 3531 3532 // 3533 // Update settings if we got no lock or if lock has settled long enough. 3534 // This is currently selected to 5 seconds by experiments with syncing 3535 // with stereo enabled. 3536 // 3537 if (timeDiff >= 5000) 3538 { 3539 NV_PRINTF(LEVEL_INFO, "P2060[%d] GAINED SYNC\n", 3540 iface); 3541 3542 pThis->Iface[iface].gainedSync = 1; 3543 3544 // We've gained sync, right time to also sync the stereo phase. 3545 if (FLD_TEST_DRF(_P2060, _STATUS, _GPU_STEREO, _ACTIVE, newStatus)) 3546 { 3547 gsyncGpuStereoHeadSync(pIfaceGpu, iface, pExtDev, newStatus); 3548 // Reset toggle time to wait some time before checking stereo sync again. 3549 pThis->Snapshot[iface].lastStereoToggleTime = 0; 3550 } 3551 } 3552 else 3553 { 3554 // 3555 // We haven't reached the settle down time for a sync, 3556 // so don't update the snapshot this time. 3557 // 3558 updateSnapshot = 0; 3559 } 3560 } 3561 } 3562 3563 // Take over new status and send events only if desired. 3564 if (updateSnapshot) 3565 { 3566 // 3567 // If we lost sync again reestablish syncwait mechanism. 3568 // Local master can't loose sync per definition. 3569 // 3570 if ((NV_P2060_STATUS_VCXO_LOCK != DRF_VAL(_P2060, _STATUS, _VCXO, newStatus)) && 3571 (!localMaster)) 3572 { 3573 pThis->Iface[iface].gainedSync = 0; 3574 pThis->Snapshot[iface].lastSyncCheckTime = 0; 3575 } 3576 3577 NV_PRINTF(LEVEL_INFO, "Update P2060[%d] settled from 0x%x ( ", 3578 iface, oldStatus); 3579 DbgPrintP2060StatusRegister(LEVEL_INFO, oldStatus); 3580 NV_PRINTF_EX(NV_PRINTF_MODULE, LEVEL_INFO, ") to 0x%x ( ", newStatus); 3581 DbgPrintP2060StatusRegister(LEVEL_INFO, newStatus); 3582 NV_PRINTF_EX(NV_PRINTF_MODULE, LEVEL_INFO, ")\n"); 3583 3584 diffStatus = (oldStatus ^ newStatus); 3585 3586 pThis->Snapshot[iface].Status1 = newStatus; 3587 } 3588 } 3589 else 3590 { 3591 continue; 3592 } 3593 3594 if ((DRF_VAL(_P2060, _STATUS, _VCXO, diffStatus)) || 3595 (DRF_VAL(_P2060, _STATUS, _SYNC_LOSS, diffStatus)) ) // diff state: sync or lock 3596 { 3597 if (FLD_TEST_DRF(_P2060, _STATUS, _SYNC_LOSS, _FALSE, newStatus) && 3598 (FLD_TEST_DRF(_P2060, _STATUS, _VCXO, _LOCK, newStatus) || 3599 FLD_TEST_DRF(_P2060, _STATUS, _VCXO, _NOT_SERVO, newStatus))) 3600 { 3601 ifaceEvents[iface] |= NVBIT(NV30F1_GSYNC_NOTIFIERS_SYNC_GAIN(iface)); 3602 } 3603 else 3604 { 3605 ifaceEvents[iface] |= NVBIT(NV30F1_GSYNC_NOTIFIERS_SYNC_LOSS(iface)); 3606 } 3607 } 3608 3609 // Only track stereo diff states when we are VCXO locked or NOT SERVO. 3610 if ((FLD_TEST_DRF(_P2060, _STATUS, _VCXO, _LOCK, newStatus) || 3611 FLD_TEST_DRF(_P2060, _STATUS, _VCXO, _NOT_SERVO, newStatus)) && 3612 DRF_VAL(_P2060, _STATUS, _STEREO, diffStatus)) // diff state: stereo 3613 { 3614 if (FLD_TEST_DRF(_P2060, _STATUS, _STEREO, _LOCK, newStatus)) 3615 { 3616 ifaceEvents[iface] |= NVBIT(NV30F1_GSYNC_NOTIFIERS_STEREO_GAIN(iface)); 3617 } 3618 else 3619 { 3620 ifaceEvents[iface] |= NVBIT(NV30F1_GSYNC_NOTIFIERS_STEREO_LOSS(iface)); 3621 } 3622 } 3623 } 3624 3625 for (iface = 0; iface < NV_P2060_MAX_IFACES_PER_GSYNC; iface++) 3626 { 3627 // Only check stereo phase if we've gained sync. 3628 if (pThis->Iface[iface].gainedSync) 3629 { 3630 // Only check and adjust stereo phase if stereo is enabled on this system. 3631 if (FLD_TEST_DRF(_P2060, _STATUS, _GPU_STEREO, _ACTIVE, pThis->Snapshot[iface].Status1)) 3632 { 3633 // 3634 // gsyncGpuStereoHeadSync() works without any gsync board interaction 3635 // with gpu register access only. In addition it will also sync heads 3636 // which are not driving the stereo pin and can't be monitored by the 3637 // gsync board. 3638 // So don't look at the gsync stereolock status as this doesn't cover 3639 // all heads. 3640 // Take care of tracking state of connected gpu, not per incoming. 3641 // 3642 OBJGPU *pIfaceGpu = gpumgrGetGpuFromId(pThis->Iface[iface].GpuInfo.gpuId); 3643 OBJTMR *pIfaceTmr; 3644 NvU32 timeDiff; 3645 NvU64 currentTime; 3646 3647 NV_ASSERT(pIfaceGpu); 3648 3649 pIfaceTmr = GPU_GET_TIMER(pIfaceGpu); 3650 3651 currentTime = tmrGetTime_HAL(pIfaceGpu, pIfaceTmr); // get the current time 3652 3653 if (pThis->Snapshot[iface].lastStereoToggleTime == 0) 3654 { 3655 pThis->Snapshot[iface].lastStereoToggleTime = currentTime; 3656 } 3657 timeDiff = (NvU32)((currentTime - pThis->Snapshot[iface].lastStereoToggleTime) / 1000000); // time in ms 3658 3659 // toggle stereo if it is not locked more than 5 sec. 3660 if (timeDiff >= 5000) 3661 { 3662 gsyncGpuStereoHeadSync(pIfaceGpu, iface, pExtDev, pThis->Snapshot[iface].Status1); 3663 pThis->Snapshot[iface].lastStereoToggleTime = currentTime; 3664 } 3665 3666 // Only report stereo loss if stereo is not in phase. 3667 if (!(FLD_TEST_DRF(_P2060, _STATUS, _STEREO, _LOCK, pThis->Snapshot[iface].Status1))) 3668 { 3669 ifaceEvents[iface] |= NVBIT(NV30F1_GSYNC_NOTIFIERS_STEREO_LOSS(iface)); // report loss this time. 3670 } 3671 } 3672 } 3673 } 3674 3675 for (iface = 0; iface < NV_P2060_MAX_IFACES_PER_GSYNC; iface++) 3676 { 3677 if (ifaceEvents[iface] && (pThis->Iface[iface].lastEventNotified != ifaceEvents[iface])) 3678 { 3679 NV_PRINTF(LEVEL_INFO, "Event P2060[%d]: 0x%x (", iface, 3680 ifaceEvents[iface]); 3681 gsyncDbgPrintGsyncEvents(LEVEL_INFO, ifaceEvents[iface], iface); 3682 NV_PRINTF_EX(NV_PRINTF_MODULE, LEVEL_INFO, ")\n"); 3683 3684 // notify clients that something has happened! 3685 gsyncSignalServiceRequested(gsyncGetGsyncInstance(pGpu), ifaceEvents[iface], iface); 3686 pThis->Iface[iface].lastEventNotified = ifaceEvents[iface]; 3687 } 3688 } 3689 3690 return NV_OK; 3691 } 3692 3693 3694 /* 3695 * Handle Get and Set queries related to signals. 3696 */ 3697 NV_STATUS 3698 gsyncRefSignal_P2060 3699 ( 3700 OBJGPU *pGpu, 3701 PDACEXTERNALDEVICE pExtDev, 3702 REFTYPE rType, 3703 GSYNCSYNCSIGNAL Signal, 3704 NvBool bRate, 3705 NvU32 *pPresence 3706 ) 3707 { 3708 NV_STATUS status = NV_OK; 3709 NvU32 rate; 3710 NvU32 value = 0; 3711 NvU32 bMaster; // Is this Gsync in Master mode 3712 PDACP2060EXTERNALDEVICE pThis = (PDACP2060EXTERNALDEVICE)pExtDev; 3713 3714 if (!bRate) 3715 { 3716 return NV_OK; 3717 } 3718 3719 // 3720 // Is any display on this P2060 a master, or are we using an ext 3721 // sync to be master. 3722 // 3723 bMaster = !!gsyncReadMaster_P2060(pGpu, pThis); 3724 3725 switch ( rType ) 3726 { 3727 case refFetchGet: 3728 if (gsync_Signal_RJ45_0 == Signal || gsync_Signal_RJ45_1 == Signal) 3729 { 3730 // Relevant only if this port is an input 3731 NvU32 port0Direction, expectedPort0Direction; 3732 NvU32 port1Direction, expectedPort1Direction; 3733 3734 status = gsyncReadFrameRate_P2060(pGpu, pExtDev, &rate); 3735 if (NV_OK != status) 3736 return status; 3737 3738 status = readregu008_extdeviceTargeted(pGpu, pExtDev, (NvU8)NV_P2060_STATUS2, (NvU8*)&value); 3739 if (NV_OK != status) 3740 return status; 3741 3742 port0Direction = DRF_VAL(_P2060, _STATUS2, _PORT0, value); 3743 port1Direction = DRF_VAL(_P2060, _STATUS2, _PORT1, value); 3744 3745 if (gsync_Signal_RJ45_0 == Signal) 3746 { 3747 expectedPort0Direction = NV_P2060_STATUS2_PORT0_INPUT; 3748 expectedPort1Direction = NV_P2060_STATUS2_PORT1_OUTPUT; 3749 } 3750 else 3751 { 3752 expectedPort0Direction = NV_P2060_STATUS2_PORT0_OUTPUT; 3753 expectedPort1Direction = NV_P2060_STATUS2_PORT1_INPUT; 3754 } 3755 if (port0Direction == expectedPort0Direction && port1Direction == expectedPort1Direction) 3756 { 3757 if (bMaster) 3758 { 3759 *pPresence = ~0; 3760 } 3761 else 3762 { 3763 *pPresence = rate; 3764 } 3765 } 3766 else 3767 { 3768 *pPresence = 0; 3769 } 3770 } 3771 else if (gsync_Signal_House == Signal) 3772 { 3773 status = gsyncReadHouseSignalPresent_P2060(pGpu, pExtDev, NV_FALSE, &value); 3774 3775 if (value && NV_OK == status) 3776 { 3777 status = gsyncReadHouseSyncFrameRate_P2060(pGpu, pExtDev, &rate); 3778 if (NV_OK != status) 3779 return status; 3780 3781 if (bMaster) 3782 { 3783 *pPresence = rate; 3784 } 3785 else 3786 { 3787 *pPresence = ~0; 3788 } 3789 } 3790 else 3791 { 3792 *pPresence = 0; 3793 } 3794 } 3795 else 3796 { 3797 return NV_ERR_GENERIC; 3798 } 3799 break; 3800 3801 case refRead: 3802 break; 3803 default: 3804 return NV_ERR_GENERIC; 3805 } 3806 3807 return status; 3808 } 3809 3810 /* 3811 * Handle Get and Set queries related to Master. 3812 */ 3813 NV_STATUS 3814 gsyncRefMaster_P2060 3815 ( 3816 OBJGPU *pGpu, 3817 PDACEXTERNALDEVICE pExtDev, 3818 REFTYPE rType, 3819 NvU32 *pDisplayMask, 3820 NvU32 *pRefresh, 3821 NvBool retainMaster, 3822 NvBool skipSwapBarrierWar 3823 ) 3824 { 3825 PDACP2060EXTERNALDEVICE pThis = (PDACP2060EXTERNALDEVICE)pExtDev; 3826 NvU32 Master = pThis->Master; 3827 NvU32 RefreshRate = pThis->RefreshRate; 3828 NV_STATUS status = NV_OK; 3829 3830 switch ( rType ) 3831 { 3832 case refSetCommit: 3833 if (!retainMaster) 3834 { 3835 Master = pThis->Master = *pDisplayMask; 3836 } 3837 RefreshRate = pThis->RefreshRate = *pRefresh; 3838 break; 3839 default: 3840 break; 3841 } 3842 3843 switch ( rType ) 3844 { 3845 case refSetCommit: 3846 // Only masterable gpus can be set to master, but either can be set to non-master. 3847 if (Master && (!gsyncGpuCanBeMaster_P2060(pGpu, (PDACEXTERNALDEVICE)pThis))) 3848 { 3849 NV_PRINTF(LEVEL_INFO, "P2060 GPU can not be Framelock Master.\n"); 3850 return NV_ERR_GENERIC; 3851 } 3852 3853 if (GpuIsMosaicTimingSlave(pGpu, pThis)) 3854 { 3855 NV_PRINTF(LEVEL_INFO, 3856 "P2060 GPU is mosaic timing slave. Can not set Framelock Master.\n"); 3857 return NV_ERR_GENERIC; 3858 } 3859 3860 status = gsyncProgramMaster_P2060(pGpu, pThis, Master, retainMaster, skipSwapBarrierWar); 3861 break; 3862 3863 case refFetchGet: 3864 case refRead: 3865 Master = gsyncReadMaster_P2060(pGpu, pThis); 3866 break; 3867 default: 3868 break; 3869 } 3870 3871 switch ( rType ) 3872 { 3873 case refFetchGet: 3874 pThis->Master = Master; 3875 /*NOBREAK*/ 3876 case refRead: 3877 *pDisplayMask = Master; 3878 *pRefresh = RefreshRate; 3879 break; 3880 3881 default: 3882 break; 3883 } 3884 3885 return status; 3886 } 3887 3888 /* 3889 * Handle Get and Set queries related to Slaves. 3890 */ 3891 NV_STATUS 3892 gsyncRefSlaves_P2060 3893 ( 3894 OBJGPU *pGpu, 3895 PDACEXTERNALDEVICE pExtDev, 3896 REFTYPE rType, 3897 NvU32 *pDisplayMasks, 3898 NvU32 *pRefresh 3899 ) 3900 { 3901 PDACP2060EXTERNALDEVICE pThis = (PDACP2060EXTERNALDEVICE)pExtDev; 3902 NV_STATUS status = NV_OK; 3903 NvU32 Slaves = pThis->Slaves; 3904 NvU32 RefreshRate = pThis->RefreshRate; 3905 3906 switch ( rType ) 3907 { 3908 case refSetCommit: 3909 pThis->Slaves = *pDisplayMasks; 3910 pThis->RefreshRate = *pRefresh; 3911 Slaves = pThis->Slaves; 3912 RefreshRate = pThis->RefreshRate; 3913 break; 3914 default: 3915 break; 3916 } 3917 3918 switch ( rType ) 3919 { 3920 case refSetCommit: 3921 status = gsyncProgramSlaves_P2060(pGpu, pThis, Slaves); 3922 break; 3923 3924 case refFetchGet: 3925 case refRead: 3926 Slaves = gsyncReadSlaves_P2060(pGpu, pThis); 3927 break; 3928 default: 3929 break; 3930 } 3931 3932 switch ( rType ) 3933 { 3934 case refFetchGet: 3935 pThis->Slaves = Slaves; 3936 /*NOBREAK*/ 3937 case refRead: 3938 *pDisplayMasks = Slaves; 3939 *pRefresh = RefreshRate; 3940 break; 3941 3942 default: 3943 break; 3944 } 3945 return status; 3946 } 3947 3948 /* 3949 * Handle Get queries related to CPL status. 3950 */ 3951 NV_STATUS 3952 gsyncGetCplStatus_P2060 3953 ( 3954 OBJGPU *pGpu, 3955 PDACEXTERNALDEVICE pExtDev, 3956 GSYNCSTATUS CplStatus, 3957 NvU32 *pVal 3958 ) 3959 { 3960 NV_STATUS status = NV_OK; 3961 NvU8 regStatus2; 3962 3963 *pVal = 0; // A little safety for those that do not check return codes 3964 3965 switch (CplStatus) 3966 { 3967 case gsync_Status_Refresh: 3968 // Read GSYNC Framerate value. 3969 status = gsyncReadFrameRate_P2060(pGpu, pExtDev, pVal); 3970 break; 3971 3972 case gsync_Status_HouseSyncIncoming: 3973 *pVal = 0; 3974 status = gsyncReadHouseSignalPresent_P2060(pGpu, pExtDev, NV_FALSE, pVal); 3975 if (NV_OK == status && *pVal) 3976 { 3977 // Read HS Framerate value. 3978 status = gsyncReadHouseSyncFrameRate_P2060(pGpu, pExtDev, pVal); 3979 } 3980 break; 3981 3982 case gsync_Status_bSyncReady: 3983 status = gsyncReadIsSyncDetected_P2060(pGpu, pExtDev, pVal); 3984 break; 3985 3986 case gsync_Status_bSwapReady: 3987 *pVal = 0; // counters should exist in P2060? 3988 break; 3989 3990 case gsync_Status_bTiming: 3991 status = gsyncReadIsTiming_P2060(pGpu, pExtDev, pVal); 3992 break; 3993 3994 case gsync_Status_bStereoSync: 3995 status = gsyncReadStereoLocked_P2060(pGpu, pExtDev, pVal); 3996 break; 3997 3998 case gsync_Status_bHouseSync: 3999 status = gsyncReadHouseSignalPresent_P2060(pGpu, pExtDev, NV_FALSE, pVal); 4000 break; 4001 4002 case gsync_Status_bPort0Input: 4003 status = readregu008_extdeviceTargeted(pGpu, pExtDev, (NvU8)NV_P2060_STATUS2, ®Status2); 4004 if ( NV_OK == status ) 4005 { 4006 *pVal = FLD_TEST_DRF(_P2060, _STATUS2, _PORT0, _INPUT, (NvU32)regStatus2); 4007 } 4008 break; 4009 4010 case gsync_Status_bPort1Input: 4011 status = readregu008_extdeviceTargeted(pGpu, pExtDev, (NvU8)NV_P2060_STATUS2, ®Status2); 4012 if ( NV_OK == status ) 4013 { 4014 *pVal = FLD_TEST_DRF(_P2060, _STATUS2, _PORT1, _INPUT, (NvU32)regStatus2); 4015 } 4016 break; 4017 4018 case gsync_Status_bPort0Ethernet: 4019 status = readregu008_extdeviceTargeted(pGpu, pExtDev, (NvU8)NV_P2060_STATUS2, ®Status2); 4020 if ( NV_OK == status ) 4021 { 4022 *pVal = FLD_TEST_DRF(_P2060, _STATUS2, _ETHER0_DETECTED, _TRUE, (NvU32)regStatus2); 4023 } 4024 break; 4025 4026 case gsync_Status_bPort1Ethernet: 4027 status = readregu008_extdeviceTargeted(pGpu, pExtDev, (NvU8)NV_P2060_STATUS2, ®Status2); 4028 if ( NV_OK == status ) 4029 { 4030 *pVal = FLD_TEST_DRF(_P2060, _STATUS2, _ETHER1_DETECTED, _TRUE, (NvU32)regStatus2); 4031 } 4032 break; 4033 4034 case gsync_Status_UniversalFrameCount: 4035 status = gsyncReadUniversalFrameCount_P2060(pGpu, pExtDev, pVal); 4036 break; 4037 4038 default: 4039 status = NV_ERR_GENERIC; 4040 } 4041 4042 return status; 4043 } 4044 4045 /* 4046 * Handle Get and Set queries related to Watchdog. 4047 */ 4048 NV_STATUS 4049 gsyncSetWatchdog_P2060 4050 ( 4051 OBJGPU *pGpu, 4052 PDACEXTERNALDEVICE pExtDev, 4053 NvU32 pVal 4054 ) 4055 { 4056 OBJGPU *pTempGpu = NULL; 4057 PDACP2060EXTERNALDEVICE pP2060 = (PDACP2060EXTERNALDEVICE)pExtDev; 4058 NV_STATUS status = NV_OK; 4059 4060 NV_ASSERT_OR_RETURN(pGpu && pP2060, NV_ERR_INVALID_DEVICE); 4061 4062 if (pVal) 4063 { 4064 gsyncCancelWatchdog_P2060(pP2060); 4065 pTempGpu = GetP2060WatchdogGpu(pGpu, pP2060); 4066 4067 extdevScheduleWatchdog(pTempGpu, (PDACEXTERNALDEVICE)pP2060); 4068 if (!gsyncIsOnlyFrameLockMaster_P2060(pP2060)) 4069 { 4070 pP2060->watchdogCountDownValue = NV_P2060_WATCHDOG_COUNT_DOWN_VALUE; 4071 } 4072 } 4073 4074 return status; 4075 } 4076 4077 /* 4078 * Handle Get and Set queries related to board revision. 4079 */ 4080 NV_STATUS 4081 gsyncGetRevision_P2060 4082 ( 4083 OBJGPU *pGpu, 4084 PDACEXTERNALDEVICE pExtDev, 4085 GSYNCCAPSPARAMS *pParams 4086 ) 4087 { 4088 OBJSYS *pSys = SYS_GET_INSTANCE(); 4089 NV_STATUS status = NV_OK; 4090 DAC_EXTERNAL_DEVICES deviceId = pExtDev->deviceId; 4091 DAC_EXTERNAL_DEVICE_REVS deviceRev = pExtDev->deviceRev; 4092 4093 if (!pGpu) 4094 { 4095 return NV_ERR_GENERIC; // something more descriptive, perhaps? 4096 } 4097 4098 portMemSet(pParams, 0, sizeof(*pParams)); 4099 4100 pParams->revId = (NvU32)pExtDev->revId; 4101 pParams->boardId = (NvU32)deviceId; 4102 pParams->revision = (NvU32)deviceRev; 4103 pParams->extendedRevision = (NvU32)pExtDev->deviceExRev; 4104 4105 if ((deviceRev != DAC_EXTERNAL_DEVICE_REV_NONE) && 4106 (deviceId == DAC_EXTERNAL_DEVICE_P2060 || 4107 deviceId == DAC_EXTERNAL_DEVICE_P2061)) 4108 { 4109 DACP2060EXTERNALDEVICE *p2060 = (DACP2060EXTERNALDEVICE *)pExtDev; 4110 4111 pParams->capFlags = NV30F1_CTRL_GSYNC_GET_CAPS_CAP_FLAGS_FREQ_ACCURACY_3DPS; 4112 4113 if (!pSys->getProperty(pSys, PDB_PROP_SYS_IS_QSYNC_FW_REVISION_CHECK_DISABLED)) 4114 { 4115 pParams->isFirmwareRevMismatch = isFirmwareRevMismatch(pGpu, deviceRev); 4116 } 4117 else 4118 { 4119 pParams->isFirmwareRevMismatch = NV_FALSE; 4120 } 4121 4122 pParams->maxSyncSkew = p2060->syncSkewMax; 4123 pParams->syncSkewResolution = p2060->syncSkewResolutionInNs; 4124 pParams->maxStartDelay = NV_P2060_START_DELAY_MAX_UNITS; 4125 pParams->startDelayResolution = NV_P2060_START_DELAY_RESOLUTION; 4126 pParams->maxSyncInterval = NV_P2060_SYNC_INTERVAL_MAX_UNITS; 4127 4128 // let client know which events we support 4129 pParams->capFlags |= NV30F1_CTRL_GSYNC_GET_CAPS_CAP_FLAGS_SYNC_LOCK_EVENT; 4130 pParams->capFlags |= NV30F1_CTRL_GSYNC_GET_CAPS_CAP_FLAGS_HOUSE_SYNC_EVENT; 4131 4132 // all connectors are capable of generating events 4133 pParams->capFlags |= NV30F1_CTRL_GSYNC_GET_CAPS_CAP_FLAGS_ALL_CONNECTOR_EVENT; 4134 4135 // clients can only request (i.e. not SET) for video mode at BNC connector. 4136 pParams->capFlags |= NV30F1_CTRL_GSYNC_GET_CAPS_CAP_FLAGS_ONLY_GET_VIDEO_MODE; 4137 4138 // Fpga revisions <= 5 need to have the swapbarrier set on framelock masters 4139 // to drive (pull up) the swap_rdy line of the whole framelock setup. 4140 // This is a behaviour with unwanted side effects which needs drivers wars 4141 // for certain configs. 4142 if (needsMasterBarrierWar(pExtDev)) 4143 { 4144 pParams->capFlags |= NV30F1_CTRL_GSYNC_GET_CAPS_CAP_FLAGS_NEED_MASTER_BARRIER_WAR; 4145 } 4146 4147 if (supportsMulDiv(pExtDev)) 4148 { 4149 pParams->capFlags |= NV30F1_CTRL_GSYNC_GET_CAPS_CAP_FLAGS_MULTIPLY_DIVIDE_SYNC; 4150 pParams->maxMulDivValue = (NV_P2060_MULTIPLIER_DIVIDER_VALUE_MINUS_ONE_MAX + 1); 4151 } 4152 } 4153 else 4154 { 4155 pParams->boardId = DAC_EXTERNAL_DEVICE_NONE; 4156 } 4157 4158 return status; 4159 } 4160 4161 /* 4162 * Handle Get and Set queries related to Swap barrier. 4163 */ 4164 NV_STATUS 4165 gsyncRefSwapBarrier_P2060 4166 ( 4167 OBJGPU *pGpu, 4168 PDACEXTERNALDEVICE pExtDev, 4169 REFTYPE rType, 4170 NvBool *bEnable 4171 ) 4172 { 4173 NV_STATUS status = NV_OK; 4174 4175 switch (rType) 4176 { 4177 case refSetCommit: 4178 status = gsyncProgramSwapBarrier_P2060(pGpu, pExtDev, *bEnable); 4179 break; 4180 case refFetchGet: 4181 case refRead: 4182 status = gsyncReadSwapBarrier_P2060(pGpu, pExtDev, bEnable); 4183 break; 4184 default: 4185 break; 4186 } 4187 4188 return status; 4189 } 4190 4191 /* 4192 * Configure GSYNC registers for pre-flash and post-flash operations. 4193 */ 4194 NV_STATUS 4195 gsyncConfigFlashGsync_P2060 4196 ( 4197 OBJGPU *pGpu, 4198 PDACEXTERNALDEVICE pExtDev, 4199 NvU32 preFlash 4200 ) 4201 { 4202 PDACP2060EXTERNALDEVICE pThis = (PDACP2060EXTERNALDEVICE) pExtDev; 4203 NvU32 iface; 4204 NV_STATUS rmStatus = NV_OK; 4205 4206 if (preFlash) 4207 { 4208 if (pThis->isNonFramelockInterruptEnabled == NV_FALSE) 4209 { 4210 // Non-Framelock interrupts are already disabled. 4211 return NV_OK; 4212 } 4213 4214 // Disable non-Framelock interrupts for given gpu 4215 for (iface = 0; iface < NV_P2060_MAX_IFACES_PER_GSYNC; iface++) 4216 { 4217 if (pThis->Iface[iface].GpuInfo.gpuId != NV0000_CTRL_GPU_INVALID_ID && 4218 pThis->interruptEnabledInterface == iface) 4219 { 4220 OBJGPU *pTmpGpu = gpumgrGetGpuFromId(pThis->Iface[iface].GpuInfo.gpuId); 4221 4222 NV_ASSERT(pTmpGpu); 4223 4224 rmStatus = gsyncDisableNonFramelockInterrupt_P2060(pTmpGpu, (PDACEXTERNALDEVICE)pThis); 4225 if (rmStatus != NV_OK) 4226 { 4227 NV_PRINTF(LEVEL_ERROR, 4228 "Failed to disable non-framelock interrupts on gsync GPU.\n"); 4229 return rmStatus; 4230 } 4231 break; 4232 } 4233 } 4234 pThis->isNonFramelockInterruptEnabled = NV_FALSE; 4235 } 4236 else 4237 { 4238 if (pThis->isNonFramelockInterruptEnabled == NV_FALSE) 4239 { 4240 // Enable non-Framelock interrupts for given gpu 4241 rmStatus = GetP2060ConnectorIndexFromGpu(pGpu, pThis, &iface); 4242 if (NV_OK != rmStatus) 4243 { 4244 NV_PRINTF(LEVEL_ERROR, 4245 "failed to find P2060 connector of the GPU.\n"); 4246 return rmStatus; 4247 } 4248 4249 rmStatus = gsyncEnableNonFramelockInterrupt_P2060(pGpu, (PDACEXTERNALDEVICE)pThis); 4250 if (NV_OK != rmStatus) 4251 { 4252 NV_PRINTF(LEVEL_ERROR, 4253 "Failed to enable non-framelock interrupts on gsync GPU.\n"); 4254 return rmStatus; 4255 } 4256 pThis->isNonFramelockInterruptEnabled = NV_TRUE; 4257 pThis->interruptEnabledInterface = iface; 4258 } 4259 4260 // Program External Stereo Sync Polarity for all attached gpus. 4261 for (iface = 0; iface < NV_P2060_MAX_IFACES_PER_GSYNC; iface++) 4262 { 4263 if (pThis->Iface[iface].GpuInfo.gpuId != NV0000_CTRL_GPU_INVALID_ID) 4264 { 4265 OBJGPU *pTmpGpu = gpumgrGetGpuFromId(pThis->Iface[iface].GpuInfo.gpuId); 4266 4267 NV_ASSERT(pTmpGpu); 4268 4269 rmStatus = gsyncProgramExtStereoPolarity_P2060(pTmpGpu, (PDACEXTERNALDEVICE)pThis); 4270 if (NV_OK != rmStatus) 4271 { 4272 NV_PRINTF(LEVEL_ERROR, 4273 "Failed to Program External Stereo Polarity for GPU.\n"); 4274 return rmStatus; 4275 } 4276 } 4277 } 4278 } 4279 return rmStatus; 4280 } 4281 4282 /* 4283 * Return snapshot of status1 register. 4284 */ 4285 static NvU32 4286 GetP2060GpuSnapshot 4287 ( 4288 OBJGPU *pGpu, 4289 PDACP2060EXTERNALDEVICE pThis 4290 ) 4291 { 4292 NvU32 iface; 4293 NV_STATUS status; 4294 4295 status = GetP2060GpuLocation(pGpu, pThis, &iface); 4296 if (NV_OK != status) 4297 return 0; 4298 4299 return pThis->Snapshot[iface].Status1; 4300 } 4301 4302 /* 4303 * Return NV_TRUE if pGpu is Timing Source else return NV_FALSE. 4304 */ 4305 static NvBool 4306 GpuIsP2060Master 4307 ( 4308 OBJGPU *pGpu, 4309 PDACP2060EXTERNALDEVICE pThis 4310 ) 4311 { 4312 NvU8 regControl; 4313 NvU32 index; 4314 NvBool bIsMasterGpu; 4315 NV_STATUS rmStatus; 4316 4317 if (!pGpu || !GpuIsP2060Connected(pGpu, pThis)) 4318 { 4319 return NV_FALSE; 4320 } 4321 4322 // Get the connector index and check if it is master 4323 if ( NV_OK != GetP2060ConnectorIndexFromGpu(pGpu, pThis, &index)) 4324 { 4325 return NV_FALSE; 4326 } 4327 4328 rmStatus = readregu008_extdeviceTargeted(pGpu, (PDACEXTERNALDEVICE)pThis, (NvU8)NV_P2060_CONTROL, ®Control); 4329 if (NV_OK != rmStatus) 4330 { 4331 return NV_FALSE; 4332 } 4333 4334 bIsMasterGpu = (DRF_VAL(_P2060, _CONTROL, _SYNC_SRC, (NvU32)regControl) == index); 4335 return bIsMasterGpu; 4336 } 4337 4338 /* 4339 * Return whether pGpu is connected to pThis or not. 4340 */ 4341 static NvBool 4342 GpuIsP2060Connected 4343 ( 4344 OBJGPU *pGpu, 4345 PDACP2060EXTERNALDEVICE pThis 4346 ) 4347 { 4348 NvU32 iface; 4349 4350 if (NV_OK == GetP2060GpuLocation(pGpu, pThis, &iface)) 4351 { 4352 return pThis->Iface[iface].GpuInfo.connected; 4353 } 4354 4355 return NV_FALSE; 4356 } 4357 4358 /* 4359 * Return Masterable(TS) Gpu for pthis. 4360 */ 4361 static OBJGPU* 4362 GetP2060MasterableGpu 4363 ( 4364 OBJGPU *pGpu, 4365 PDACP2060EXTERNALDEVICE pThis 4366 ) 4367 { 4368 OBJGPU *tempGpu; 4369 NvU32 iface; 4370 4371 for (iface = 0; iface < NV_P2060_MAX_IFACES_PER_GSYNC; iface++) 4372 { 4373 if (pThis->Iface[iface].GpuInfo.gpuId != NV0000_CTRL_GPU_INVALID_ID) 4374 { 4375 tempGpu = gpumgrGetGpuFromId(pThis->Iface[iface].GpuInfo.gpuId); 4376 4377 NV_ASSERT(tempGpu); 4378 4379 if (gsyncGpuCanBeMaster_P2060(tempGpu, (PDACEXTERNALDEVICE)pThis)) 4380 { 4381 return tempGpu; 4382 } 4383 } 4384 } 4385 4386 return NULL; 4387 } 4388 4389 /* 4390 * Return connector index for given pGpu. 4391 */ 4392 static NV_STATUS 4393 GetP2060ConnectorIndexFromGpu 4394 ( 4395 OBJGPU *pGpu, 4396 PDACP2060EXTERNALDEVICE pThis, 4397 NvU32 *index 4398 ) 4399 { 4400 NV_STATUS rmStatus = NV_OK; 4401 NvU8 regStatus2; 4402 4403 rmStatus = readregu008_extdeviceTargeted(pGpu, (PDACEXTERNALDEVICE)pThis, (NvU8)NV_P2060_STATUS2, ®Status2); 4404 if (NV_OK == rmStatus) 4405 { 4406 *index = DRF_VAL(_P2060, _STATUS2, _GPU_PORT, (NvU32)regStatus2); 4407 } 4408 4409 return rmStatus; 4410 } 4411 4412 /* 4413 * Return location of pGpu attached to P2060. 4414 */ 4415 static NV_STATUS 4416 GetP2060GpuLocation 4417 ( 4418 OBJGPU *pGpu, 4419 PDACP2060EXTERNALDEVICE pThis, 4420 NvU32 *iface 4421 ) 4422 { 4423 NvU32 tempIface; 4424 4425 for (tempIface = 0; tempIface < NV_P2060_MAX_IFACES_PER_GSYNC; tempIface++) 4426 { 4427 if (pThis->Iface[tempIface].GpuInfo.gpuId == pGpu->gpuId) 4428 { 4429 *iface = tempIface; 4430 4431 return NV_OK; 4432 } 4433 } 4434 4435 return NV_ERR_GENERIC; 4436 } 4437 4438 static void 4439 gsyncProgramFramelockEnable_P2060 4440 ( 4441 OBJGPU *pGpu, 4442 PDACP2060EXTERNALDEVICE pThis, 4443 NvU32 iface, 4444 NvBool bEnable 4445 ) 4446 { 4447 // 4448 // Key here is to force the status register snapshot 4449 // to unsynched and setting back the timeout for 4450 // syncgain. To ensure that the eventhandling won't 4451 // filter away any gain, send a syncloss event. 4452 // also track overall framelock state (on off) now. 4453 // 4454 NV_PRINTF(LEVEL_INFO, 4455 "P2060[%d]:%s snapshot reset to _SYNC_LOSS_TRUE _VCXO_NOT_SERVO _STEREO_NOLOCK\n", 4456 iface, bEnable ? "ON" : "OFF"); 4457 4458 pThis->Snapshot[iface].Status1 = 4459 DRF_DEF(_P2060, _STATUS, _SYNC_LOSS, _TRUE) | 4460 DRF_DEF(_P2060, _STATUS, _VCXO, _NOT_SERVO) | 4461 DRF_DEF(_P2060, _STATUS, _STEREO, _NOLOCK); 4462 4463 pThis->Snapshot[iface].lastStereoToggleTime = 0; 4464 4465 // Also reload delayed updates. 4466 pThis->Snapshot[iface].lastSyncCheckTime = 0; 4467 4468 // We will waiting for a syncgain. 4469 pThis->Iface[iface].gainedSync = 0; 4470 4471 if (bEnable) 4472 { 4473 gsyncSignalServiceRequested(gsyncGetGsyncInstance(pGpu), 4474 NVBIT(NV30F1_GSYNC_NOTIFIERS_SYNC_LOSS(iface)), iface); 4475 pThis->Iface[iface].lastEventNotified = 4476 NVBIT(NV30F1_GSYNC_NOTIFIERS_SYNC_LOSS(iface)); 4477 } 4478 } 4479 4480 static NvBool 4481 GpuIsMosaicTimingSlave 4482 ( 4483 OBJGPU *pGpu, 4484 PDACP2060EXTERNALDEVICE pThis 4485 ) 4486 { 4487 OBJGPU *pTempGpu = NULL; 4488 NvU8 i, j; 4489 4490 for (i = 0; i < NV_P2060_MAX_MOSAIC_GROUPS; i++) 4491 { 4492 if (pThis->MosaicGroup[i].enabledMosaic) 4493 { 4494 for (j = 0; j < NV_P2060_MAX_MOSAIC_SLAVES; j++) 4495 { 4496 pTempGpu = gpumgrGetGpuFromId(pThis->MosaicGroup[i].gpuTimingSlaves[j]); 4497 NV_ASSERT(pTempGpu); 4498 4499 if (pTempGpu == pGpu) 4500 { 4501 return NV_TRUE; 4502 } 4503 } 4504 } 4505 } 4506 return NV_FALSE; 4507 } 4508 4509 /* 4510 * Return NV_TRUE if pGpu can be master(TS) i.e. no other pGpu 4511 * attached to pThis is master. 4512 */ 4513 NvBool 4514 gsyncGpuCanBeMaster_P2060 4515 ( 4516 OBJGPU *pGpu, 4517 PDACEXTERNALDEVICE pExtDev 4518 ) 4519 { 4520 PDACP2060EXTERNALDEVICE pThis = (PDACP2060EXTERNALDEVICE)pExtDev; 4521 OBJGPU *pTempGpu; 4522 NvU32 iface, tempIface; 4523 NV_STATUS status; 4524 4525 // If FPGA board in not master, Any GPU attached to board can be master. 4526 if (!gsyncIsP2060MasterBoard(pGpu, pThis)) 4527 { 4528 return NV_TRUE; 4529 } 4530 4531 // Board is master, only TS GPU will be master. 4532 status = GetP2060GpuLocation(pGpu, pThis, &iface); 4533 if (NV_OK != status) 4534 { 4535 return NV_FALSE; 4536 } 4537 4538 for (tempIface = 0; tempIface < NV_P2060_MAX_IFACES_PER_GSYNC; tempIface++) 4539 { 4540 if (tempIface == iface) 4541 { 4542 continue; 4543 } 4544 4545 if (pThis->Iface[tempIface].GpuInfo.gpuId == NV0000_CTRL_GPU_INVALID_ID) 4546 { 4547 continue; 4548 } 4549 4550 pTempGpu = gpumgrGetGpuFromId(pThis->Iface[tempIface].GpuInfo.gpuId); 4551 4552 NV_ASSERT(pTempGpu); 4553 4554 if (GpuIsP2060Master(pTempGpu, pThis)) 4555 { 4556 return NV_FALSE; 4557 } 4558 } 4559 4560 return NV_TRUE; 4561 } 4562 4563 4564 static POBJGPU 4565 GetP2060Gpu 4566 ( 4567 OBJGPU *pGpu, 4568 PDACP2060EXTERNALDEVICE pThis 4569 ) 4570 { 4571 NvU32 iface; 4572 for (iface = 0; iface < NV_P2060_MAX_IFACES_PER_GSYNC; iface++) 4573 { 4574 if (pThis->Iface[iface].GpuInfo.gpuId != NV0000_CTRL_GPU_INVALID_ID) 4575 { 4576 OBJGPU *pTmpGpu = gpumgrGetGpuFromId(pThis->Iface[iface].GpuInfo.gpuId); 4577 4578 NV_ASSERT(pTmpGpu); 4579 4580 return pTmpGpu; 4581 } 4582 } 4583 return NULL; 4584 } 4585 4586 static OBJGPU* 4587 GetP2060WatchdogGpu 4588 ( 4589 OBJGPU *pGpu, 4590 PDACP2060EXTERNALDEVICE pThis 4591 ) 4592 { 4593 return GetP2060Gpu(pGpu, pThis); 4594 } 4595 4596 /* 4597 * Return NV_TRUE if either GPU stereo or MASTER stereo or 4598 * both are enabled else return NV_FALSE. 4599 */ 4600 static NvBool 4601 gsyncIsStereoEnabled_p2060 4602 ( 4603 OBJGPU *pGpu, 4604 PDACEXTERNALDEVICE pExtDev 4605 ) 4606 { 4607 NvU8 regStatus; 4608 NV_STATUS rmStatus; 4609 4610 rmStatus = readregu008_extdeviceTargeted(pGpu, pExtDev, (NvU8)NV_P2060_STATUS, ®Status); 4611 4612 if (rmStatus == NV_OK) 4613 { 4614 if (FLD_TEST_DRF(_P2060, _STATUS, _GPU_STEREO, _ACTIVE, regStatus) || 4615 FLD_TEST_DRF(_P2060, _STATUS, _MSTR_STEREO, _ACTIVE, regStatus)) 4616 { 4617 // stereo is enabled on the client or the server or both 4618 return NV_TRUE; 4619 } 4620 } 4621 return NV_FALSE; 4622 } 4623 4624 /* 4625 * Cancel the Watchdog for P2060. 4626 */ 4627 static void 4628 gsyncCancelWatchdog_P2060 4629 ( 4630 PDACP2060EXTERNALDEVICE pThis 4631 ) 4632 { 4633 NvU32 iface; 4634 OBJGPU *pTempGpu = NULL; 4635 4636 pThis->watchdogCountDownValue = 0; 4637 4638 // Cancel callbacks on all gpus 4639 for (iface = 0; iface < NV_P2060_MAX_IFACES_PER_GSYNC; iface++) 4640 { 4641 if (pThis->Iface[iface].GpuInfo.gpuId == NV0000_CTRL_GPU_INVALID_ID) 4642 continue; 4643 4644 pTempGpu = gpumgrGetGpuFromId(pThis->Iface[iface].GpuInfo.gpuId); 4645 NV_ASSERT(pTempGpu); 4646 4647 NV_PRINTF(LEVEL_INFO, "P2060[%d] extdevCancelWatchdog.\n", iface); 4648 4649 extdevCancelWatchdog(pTempGpu, (PDACEXTERNALDEVICE)pThis); 4650 } 4651 4652 return; 4653 } 4654 4655 /* 4656 * Enable FrameLock Interrupts for P2060. 4657 */ 4658 static NV_STATUS 4659 gsyncEnableFramelockInterrupt_P2060 4660 ( 4661 PDACEXTERNALDEVICE pExtDev 4662 ) 4663 { 4664 PDACP2060EXTERNALDEVICE pThis = (PDACP2060EXTERNALDEVICE) pExtDev; 4665 NvU8 regCtrl3; 4666 NvU32 iface; 4667 NV_STATUS status = NV_OK; 4668 4669 // Turn ON the interrupts 4670 for (iface = 0; iface < NV_P2060_MAX_IFACES_PER_GSYNC; iface++) 4671 { 4672 if (pThis->Iface[iface].GpuInfo.gpuId != NV0000_CTRL_GPU_INVALID_ID) 4673 { 4674 OBJGPU *pTmpGpu = gpumgrGetGpuFromId(pThis->Iface[iface].GpuInfo.gpuId); 4675 NV_ASSERT(pTmpGpu); 4676 4677 if (gsyncReadMaster_P2060(pTmpGpu, pThis) || gsyncReadSlaves_P2060(pTmpGpu, pThis)) 4678 { 4679 status = readregu008_extdeviceTargeted(pTmpGpu, 4680 (PDACEXTERNALDEVICE)pThis, NV_P2060_CONTROL3, ®Ctrl3); 4681 4682 if (gsyncIsStereoEnabled_p2060(pTmpGpu, pExtDev)) 4683 { 4684 regCtrl3 |= DRF_DEF(_P2060, _CONTROL3, _INTERRUPT, _ON_STEREO_CHG); 4685 } 4686 regCtrl3 |= DRF_DEF(_P2060, _CONTROL3, _INTERRUPT, _ON_SYNC_CHG); 4687 4688 status |= writeregu008_extdeviceTargeted(pTmpGpu, 4689 (PDACEXTERNALDEVICE)pThis, NV_P2060_CONTROL3, regCtrl3); 4690 4691 NV_PRINTF(LEVEL_INFO, "P2060[%d] enabled interrupt\n", iface); 4692 } 4693 } 4694 } 4695 return status; 4696 } 4697 4698 /* 4699 * Disable FrameLock Interrupts for P2060. 4700 */ 4701 static NV_STATUS 4702 gsyncDisableFrameLockInterrupt_P2060 4703 ( 4704 PDACEXTERNALDEVICE pExtDev 4705 ) 4706 { 4707 PDACP2060EXTERNALDEVICE pThis = (PDACP2060EXTERNALDEVICE) pExtDev; 4708 NvU8 regCtrl3; 4709 NvU32 iface; 4710 NV_STATUS status = NV_OK; 4711 4712 // Turn Off the interrupts 4713 for (iface = 0; iface < NV_P2060_MAX_IFACES_PER_GSYNC; iface++) 4714 { 4715 if (pThis->Iface[iface].GpuInfo.gpuId != NV0000_CTRL_GPU_INVALID_ID) 4716 { 4717 OBJGPU *pTmpGpu = gpumgrGetGpuFromId(pThis->Iface[iface].GpuInfo.gpuId); 4718 4719 NV_ASSERT(pTmpGpu); 4720 4721 status = readregu008_extdeviceTargeted(pTmpGpu, 4722 (PDACEXTERNALDEVICE)pThis, NV_P2060_CONTROL3, ®Ctrl3); 4723 4724 regCtrl3 &= ~DRF_DEF(_P2060, _CONTROL3, _INTERRUPT, _ON_STEREO_CHG); 4725 regCtrl3 &= ~DRF_DEF(_P2060, _CONTROL3, _INTERRUPT, _ON_SYNC_CHG); 4726 4727 status |= writeregu008_extdeviceTargeted(pTmpGpu, 4728 (PDACEXTERNALDEVICE)pThis, NV_P2060_CONTROL3, regCtrl3); 4729 4730 NV_PRINTF(LEVEL_INFO, "P2060[%d] disabled interrupt\n", iface); 4731 } 4732 } 4733 4734 return status; 4735 } 4736 4737 /* 4738 * Enable Non-FrameLock Interrupts for P2060. 4739 */ 4740 static NV_STATUS 4741 gsyncEnableNonFramelockInterrupt_P2060 4742 ( 4743 OBJGPU *pGpu, 4744 PDACEXTERNALDEVICE pExtDev 4745 ) 4746 { 4747 PDACP2060EXTERNALDEVICE pThis = (PDACP2060EXTERNALDEVICE) pExtDev; 4748 NvU8 regCtrl3 = 0x00; 4749 NV_STATUS rmStatus = NV_OK; 4750 4751 rmStatus = readregu008_extdeviceTargeted(pGpu, (PDACEXTERNALDEVICE)pThis, NV_P2060_CONTROL3, ®Ctrl3); 4752 4753 // Enable Non-Framelock interrupts on given gsync attached gpu. 4754 regCtrl3 |= DRF_DEF(_P2060, _CONTROL3, _INTERRUPT, _ON_HS_CHG); 4755 regCtrl3 |= DRF_DEF(_P2060, _CONTROL3, _INTERRUPT, _ON_RJ45_CHG); 4756 4757 rmStatus = writeregu008_extdeviceTargeted(pGpu,(PDACEXTERNALDEVICE)pThis, NV_P2060_CONTROL3, regCtrl3); 4758 4759 return rmStatus; 4760 } 4761 4762 /* 4763 * Disable Non-FrameLock Interrupts for P2060. 4764 */ 4765 static NV_STATUS 4766 gsyncDisableNonFramelockInterrupt_P2060 4767 ( 4768 OBJGPU *pGpu, 4769 PDACEXTERNALDEVICE pExtDev 4770 ) 4771 { 4772 PDACP2060EXTERNALDEVICE pThis = (PDACP2060EXTERNALDEVICE) pExtDev; 4773 NvU8 regCtrl3 = 0x00; 4774 NV_STATUS rmStatus = NV_OK; 4775 4776 rmStatus = readregu008_extdeviceTargeted(pGpu, (PDACEXTERNALDEVICE)pThis, NV_P2060_CONTROL3, ®Ctrl3); 4777 4778 // Disable Non-Framelock interrupts on given gsync attached gpu. 4779 regCtrl3 &= ~DRF_DEF(_P2060, _CONTROL3, _INTERRUPT, _ON_HS_CHG); 4780 regCtrl3 &= ~DRF_DEF(_P2060, _CONTROL3, _INTERRUPT, _ON_RJ45_CHG); 4781 4782 rmStatus = writeregu008_extdeviceTargeted(pGpu,(PDACEXTERNALDEVICE)pThis, NV_P2060_CONTROL3, regCtrl3); 4783 4784 return rmStatus; 4785 } 4786 4787 static void 4788 gsyncResetMosaicData_P2060 4789 ( 4790 NvU32 mosaicGroup, 4791 PDACP2060EXTERNALDEVICE pThis 4792 ) 4793 { 4794 NvU8 i; 4795 4796 if (!pThis) 4797 { 4798 return; 4799 } 4800 4801 pThis->MosaicGroup[mosaicGroup].gpuTimingSource = NV0000_CTRL_GPU_INVALID_ID; 4802 4803 for (i = 0; i < NV_P2060_MAX_MOSAIC_SLAVES; i++) 4804 { 4805 pThis->MosaicGroup[mosaicGroup].gpuTimingSlaves[i] = NV0000_CTRL_GPU_INVALID_ID; 4806 } 4807 4808 pThis->MosaicGroup[mosaicGroup].slaveGpuCount = 0; 4809 pThis->MosaicGroup[mosaicGroup].enabledMosaic = NV_FALSE; 4810 4811 } 4812 4813 /* 4814 * Enable/Disable SwapRdy Connection For GPU 4815 */ 4816 static NV_STATUS 4817 gsyncUpdateSwapRdyConnectionForGpu_P2060 4818 ( 4819 OBJGPU *pGpu, 4820 PDACP2060EXTERNALDEVICE pThis, 4821 NvBool bEnable 4822 ) 4823 { 4824 NV_STATUS rmStatus = NV_OK; 4825 NvU8 ctrl2 = 0x00; 4826 4827 rmStatus = readregu008_extdeviceTargeted(pGpu, (PDACEXTERNALDEVICE)pThis, 4828 NV_P2060_CONTROL2, &ctrl2); 4829 if (rmStatus != NV_OK) 4830 { 4831 return rmStatus; 4832 } 4833 4834 ctrl2 = FLD_SET_DRF_NUM(_P2060, _CONTROL2, _SWAP_READY, (NvU8)bEnable, ctrl2); 4835 4836 rmStatus = writeregu008_extdeviceTargeted(pGpu, (PDACEXTERNALDEVICE)pThis, 4837 NV_P2060_CONTROL2, ctrl2); 4838 4839 return rmStatus; 4840 } 4841 4842 /* 4843 * returns true if there is a framelock master on this P2060. 4844 * otherwise returns false. 4845 */ 4846 static NvBool 4847 gsyncIsFrameLockMaster_P2060 4848 ( 4849 PDACP2060EXTERNALDEVICE pThis 4850 ) 4851 { 4852 NvU32 iface; 4853 4854 for (iface = 0; iface < NV_P2060_MAX_IFACES_PER_GSYNC; iface++) 4855 { 4856 if (pThis->Iface[iface].GpuInfo.gpuId != NV0000_CTRL_GPU_INVALID_ID) 4857 { 4858 OBJGPU *pTmpGpu = gpumgrGetGpuFromId(pThis->Iface[iface].GpuInfo.gpuId); 4859 4860 NV_ASSERT(pTmpGpu); 4861 4862 if (gsyncReadMaster_P2060(pTmpGpu, pThis)) 4863 { 4864 return NV_TRUE; 4865 } 4866 } 4867 } 4868 4869 return NV_FALSE; 4870 } 4871 4872 /* 4873 * returns NV_TRUE if this gsync device is framelocked. 4874 */ 4875 static NvBool 4876 gsyncIsFrameLocked_P2060 4877 ( 4878 PDACP2060EXTERNALDEVICE pThis 4879 ) 4880 { 4881 NvU32 iface; 4882 4883 for (iface = 0; iface < NV_P2060_MAX_IFACES_PER_GSYNC; iface++) 4884 { 4885 if (pThis->Iface[iface].GpuInfo.gpuId != NV0000_CTRL_GPU_INVALID_ID) 4886 { 4887 OBJGPU *pTmpGpu = gpumgrGetGpuFromId(pThis->Iface[iface].GpuInfo.gpuId); 4888 NV_ASSERT(pTmpGpu); 4889 4890 if (gsyncReadMaster_P2060(pTmpGpu, pThis) || 4891 gsyncReadSlaves_P2060(pTmpGpu, pThis)) 4892 { 4893 return NV_TRUE; 4894 } 4895 } 4896 } 4897 4898 return NV_FALSE; 4899 } 4900 4901 /* 4902 * returns NV_TRUE if this gsync device is only framelock master. 4903 */ 4904 static NvBool 4905 gsyncIsOnlyFrameLockMaster_P2060 4906 ( 4907 PDACP2060EXTERNALDEVICE pThis 4908 ) 4909 { 4910 NvU32 iface, numHeads, head; 4911 KernelDisplay *pKernelDisplay; 4912 OBJGPU *pGpu; 4913 NvBool bIsMaster = NV_FALSE; 4914 4915 for (iface = 0; iface < NV_P2060_MAX_IFACES_PER_GSYNC; iface++) 4916 { 4917 if (pThis->Iface[iface].GpuInfo.gpuId != NV0000_CTRL_GPU_INVALID_ID) 4918 { 4919 pGpu = gpumgrGetGpuFromId(pThis->Iface[iface].GpuInfo.gpuId); 4920 NV_ASSERT_OR_RETURN(pGpu, NV_FALSE); 4921 4922 pKernelDisplay = GPU_GET_KERNEL_DISPLAY(pGpu); 4923 numHeads = kdispGetNumHeads(pKernelDisplay); 4924 4925 for (head = 0; head < numHeads; head++) 4926 { 4927 if (pThis->Iface[iface].Sync.Master[head]) 4928 bIsMaster = NV_TRUE; 4929 4930 if (pThis->Iface[iface].Sync.Slaved[head] || 4931 pThis->Iface[iface].Sync.LocalSlave[head]) 4932 { 4933 return NV_FALSE; 4934 } 4935 } 4936 } 4937 } 4938 4939 return bIsMaster; 4940 } 4941 4942 /* 4943 * return NV_TRUE if HW is OK with board as Framelock Master. 4944 */ 4945 static NvBool 4946 gsyncIsP2060MasterBoard 4947 ( 4948 OBJGPU *pGpu, 4949 PDACP2060EXTERNALDEVICE pThis 4950 ) 4951 { 4952 NvU8 ctrl; 4953 NvBool bIsMasterBoard; 4954 NV_STATUS rmStatus; 4955 4956 if (!pGpu || !GpuIsP2060Connected(pGpu, pThis)) 4957 { 4958 return NV_FALSE; 4959 } 4960 4961 rmStatus = readregu008_extdeviceTargeted(pGpu, (PDACEXTERNALDEVICE)pThis, (NvU8)NV_P2060_CONTROL, &ctrl); 4962 if (NV_OK != rmStatus) 4963 { 4964 return NV_FALSE; 4965 } 4966 4967 // Check HW opinion on Mastership of board. 4968 bIsMasterBoard = FLD_TEST_DRF(_P2060, _CONTROL, _I_AM, _MASTER, (NvU32)ctrl); 4969 4970 return bIsMasterBoard; 4971 } 4972 /* 4973 * return NV_TRUE if pGpu is connected to Master + TS GPU via SLI bridge 4974 */ 4975 static NvBool 4976 GpuIsConnectedToMasterViaBridge 4977 ( 4978 OBJGPU *pGpu, 4979 PDACP2060EXTERNALDEVICE pThis 4980 ) 4981 { 4982 OBJGPU *pOtherGpu = NULL; 4983 NvU32 gpuMask, gpuIndex, tempIface; 4984 NvU32 drOut, drIn; 4985 4986 gpumgrGetGpuAttachInfo(NULL, &gpuMask); 4987 gpuIndex = 0; 4988 while ((pOtherGpu = gpumgrGetNextGpu(gpuMask, &gpuIndex)) != NULL) 4989 { 4990 if ((pGpu == pOtherGpu) || gpumgrGetGpuLockAndDrPorts(pGpu, pOtherGpu, &drOut, &drIn) != NV_OK) 4991 { 4992 continue; 4993 } 4994 4995 if (GetP2060GpuLocation(pOtherGpu, pThis, &tempIface) == NV_OK) 4996 { 4997 if (gsyncIsP2060MasterBoard(pOtherGpu, pThis) && GpuIsP2060Master(pOtherGpu, pThis)) 4998 { 4999 // pGpu is connected to pOtherGpu via SLI bridge. 5000 // Both GPUs are connected to same P2060. 5001 return NV_TRUE; 5002 } 5003 } 5004 } 5005 return NV_FALSE; 5006 } 5007 5008 // 5009 // gsyncFrameCountTimerService_P2060() 5010 // 5011 // frame count timer callback service. 5012 // this function will read the actual gsync and gpu frame count value 5013 // and adjust the cached difference between them if required. 5014 // 5015 // this function is added to prevent any deviation of cached difference 5016 // between gpu and gsync hw frame count values from the actual. 5017 // As all the heads are framelocked, it is expected that cached 5018 // framecount value to be same on the master as well as slave 5019 // system. But during experiment, it is found that reading the hw gsync and 5020 // gpu frame count values immediately after the test signal is sent/received 5021 // may lead to inconsistent cached difference. Therefore the difference is 5022 // reverified after FRAME_COUNT_TIMER_INTERVAL period. 5023 // 5024 static 5025 NV_STATUS gsyncFrameCountTimerService_P2060 5026 ( 5027 OBJGPU *pGpu, 5028 OBJTMR *pTmr, 5029 void *pComponent 5030 ) 5031 { 5032 PDACP2060EXTERNALDEVICE pThis = NULL; 5033 NV_STATUS status; 5034 OBJGSYNC *pGsync = NULL; 5035 5036 pGsync = gsyncmgrGetGsync(pGpu); 5037 5038 NV_ASSERT_OR_RETURN((pGsync && pGsync->pExtDev), NV_ERR_INVALID_DEVICE); 5039 5040 pThis = (PDACP2060EXTERNALDEVICE)pGsync->pExtDev; 5041 5042 // disable the timer callback 5043 status = tmrCancelCallback(pTmr, (void *)&pThis->FrameCountData); 5044 5045 if (status != NV_OK) 5046 { 5047 return status; 5048 } 5049 5050 // 5051 // read the gsync and gpu frame count values.Cache the difference between them. 5052 // 5053 status = gsyncUpdateFrameCount_P2060(pThis, pGpu); 5054 5055 return status; 5056 } 5057 /* 5058 * Reset the FrameCount Data structure. 5059 */ 5060 // 5061 // gsyncResetFrameCountData_P2060() 5062 // 5063 // this function resets the FrameCountDate structure. 5064 // 5065 static NV_STATUS 5066 gsyncResetFrameCountData_P2060 5067 ( 5068 OBJGPU *pGpu, 5069 PDACP2060EXTERNALDEVICE pThis 5070 ) 5071 { 5072 5073 NvU8 regCtrl3; 5074 NV_STATUS rmStatus; 5075 5076 if (!pThis) 5077 { 5078 return NV_ERR_INVALID_ARGUMENT; 5079 } 5080 5081 pThis->FrameCountData.totalFrameCount = 0; 5082 pThis->FrameCountData.currentFrameCount = 0; 5083 pThis->FrameCountData.initialDifference = 0; 5084 pThis->FrameCountData.numberOfRollbacks = 0; 5085 pThis->FrameCountData.previousFrameCount = 0; 5086 pThis->FrameCountData.lastFrameCounterQueryTime = 0; 5087 pThis->FrameCountData.bReCheck = 0; 5088 pThis->FrameCountData.vActive = 0; 5089 pThis->FrameCountData.isFrmCmpMatchIntMasterEnabled = NV_FALSE; 5090 pThis->FrameCountData.enableFrmCmpMatchIntSlave = NV_FALSE; 5091 pThis->FrameCountData.head = NV_P2060_MAX_HEADS_PER_GPU; 5092 pThis->FrameCountData.iface = NV_P2060_MAX_IFACES_PER_GSYNC; 5093 5094 // disable frame count match interrupt 5095 rmStatus = readregu008_extdeviceTargeted(pGpu, (PDACEXTERNALDEVICE)pThis, 5096 NV_P2060_CONTROL3, ®Ctrl3); 5097 regCtrl3 &= ~DRF_DEF(_P2060, _CONTROL3, _INTERRUPT, _ON_FRAME_MATCH); 5098 rmStatus |= writeregu008_extdeviceTargeted(pGpu, (PDACEXTERNALDEVICE)pThis, 5099 NV_P2060_CONTROL3, regCtrl3); 5100 return rmStatus; 5101 } 5102 5103 // 5104 // gsyncUpdateFrameCount_P2060() 5105 // 5106 // For all heads in a framelocked state gpu framecount is equal.This also 5107 // implies for gsync frame count.i.e. gsync frame count = (gpu frame count + difference) 5108 // Therefore to reduce the i2c reads to access gsync frame count, 5109 // (gpu frame count + difference) can be returned. This is done by caching the 5110 // difference between the gpu and gsync framecount. 5111 // 5112 // FrameCountTimerService (1 second callback) is also enabled here to verify 5113 // the cache difference. 5114 // 5115 static NV_STATUS 5116 gsyncUpdateFrameCount_P2060 5117 ( 5118 PDACP2060EXTERNALDEVICE pThis, 5119 OBJGPU *pGpu 5120 ) 5121 { 5122 KernelDisplay *pKernelDisplay = GPU_GET_KERNEL_DISPLAY(pGpu); 5123 RM_API *pRmApi; 5124 NvU32 hClient; 5125 NvU32 hSubdevice; 5126 NvU8 FrameCountLow; 5127 NvU8 FrameCountMid; 5128 NvU8 FrameCountHigh; 5129 NvU8 regCtrl3; 5130 NvU32 rawGsyncFrameCount; 5131 NvU32 iface; 5132 NvU32 head = 0; 5133 NvU32 numHeads; 5134 NvU32 modGsyncFrameCount; 5135 NvU32 lineCount; 5136 NvU32 frameCount; 5137 RMTIMEOUT timeout; 5138 NvU32 safeRegionUpperLimit; 5139 NvU32 safeRegionLowerLimit; 5140 NV_STATUS rmStatus = NV_OK; 5141 NV2080_CTRL_INTERNAL_GSYNC_GET_VERTICAL_ACTIVE_LINES_PARAMS ctrlParams = {0}; 5142 5143 numHeads = kdispGetNumHeads(pKernelDisplay); 5144 5145 // get any framelocked head 5146 for (iface = 0; iface < NV_P2060_MAX_IFACES_PER_GSYNC; iface++) 5147 { 5148 if (pThis->Iface[iface].GpuInfo.gpuId == NV0000_CTRL_GPU_INVALID_ID) 5149 { 5150 continue; 5151 } 5152 5153 for (head = 0; head < numHeads; head++) 5154 { 5155 if (pThis->Iface[iface].Sync.Master[head] || 5156 pThis->Iface[iface].Sync.Slaved[head] || 5157 pThis->Iface[iface].Sync.LocalSlave[head]) 5158 { 5159 // Update pThis->FrameCountData with iface and head 5160 pThis->FrameCountData.iface = iface; 5161 pThis->FrameCountData.head = head; 5162 5163 // Get out of for loop 5164 iface = NV_P2060_MAX_IFACES_PER_GSYNC; 5165 break; 5166 } 5167 } 5168 } 5169 5170 if (head == numHeads) 5171 { 5172 return NV_ERR_GENERIC; 5173 } 5174 5175 pGpu = gpumgrGetGpuFromId(pThis->Iface[pThis->FrameCountData.iface].GpuInfo.gpuId); 5176 NV_ASSERT_OR_RETURN(pGpu, NV_ERR_INVALID_DEVICE); 5177 5178 pRmApi = GPU_GET_PHYSICAL_RMAPI(pGpu); 5179 hClient = pGpu->hInternalClient; 5180 hSubdevice = pGpu->hInternalSubdevice; 5181 5182 // Re-fetch pDisp as pGpu might have changed. 5183 pKernelDisplay = GPU_GET_KERNEL_DISPLAY(pGpu); 5184 NV_ASSERT_OR_RETURN(pKernelDisplay != NULL, NV_ERR_INVALID_DEVICE); 5185 NV_ASSERT_OR_RETURN(head < kdispGetNumHeads(pKernelDisplay), NV_ERR_INVALID_DEVICE); 5186 5187 ctrlParams.headIdx = head; 5188 5189 rmStatus = pRmApi->Control(pRmApi, hClient, hSubdevice, 5190 NV2080_CTRL_CMD_INTERNAL_GSYNC_GET_VERTICAL_ACTIVE_LINES, 5191 &ctrlParams, sizeof(ctrlParams)); 5192 5193 if (rmStatus != NV_OK) 5194 { 5195 return rmStatus; 5196 } 5197 5198 pThis->FrameCountData.vActive = ctrlParams.vActiveLines; 5199 5200 // 5201 // To read Gpu framecount, line count should be in between 5-70% of VVisible. 5202 // 5203 safeRegionUpperLimit = (pThis->FrameCountData.vActive * 7) / 10; 5204 safeRegionLowerLimit = pThis->FrameCountData.vActive / 20; 5205 5206 // Read the GPU frame count and line count 5207 rmStatus = kdispReadRgLineCountAndFrameCount_HAL(pGpu, pKernelDisplay, 5208 pThis->FrameCountData.head, &lineCount, &frameCount); 5209 if (rmStatus != NV_OK) 5210 { 5211 NV_PRINTF(LEVEL_ERROR, "Failed to read RG_DPCA.\n"); 5212 return rmStatus; 5213 } 5214 5215 // 5216 // Wait for a safe region i.e. 5-70 percent of the VActive. Then read the 5217 // gsync framecount. This is done to ensure that both gsync and gpu 5218 // registers are read in the safe zone otherwise there will be -/+ 1 5219 // frame inconsistency ( if read during the transition from frame N to 5220 // frame N + 1 i.e linecount > vActive) 5221 // 5222 if ((lineCount >= safeRegionUpperLimit) || (lineCount <= safeRegionLowerLimit)) 5223 { 5224 // 5225 // timeout of one frameTime(in nano seconds), to avoid going into an infinite 5226 // loop in case linecount is stuck to some value. 5227 // 5228 gpuSetTimeout(pGpu, (pThis->FrameCountData.frameTime * 1000), &timeout, 0); 5229 5230 // Read the linecount until we are in the safe region i.e taken as 5%-70% of VActive. 5231 while (((lineCount >= safeRegionUpperLimit) || (lineCount <= safeRegionLowerLimit)) && 5232 (gpuCheckTimeout(pGpu, &timeout) != NV_ERR_TIMEOUT)) 5233 { 5234 rmStatus = kdispReadRgLineCountAndFrameCount_HAL(pGpu, pKernelDisplay, 5235 pThis->FrameCountData.head, &lineCount, &frameCount); 5236 if (rmStatus != NV_OK) 5237 { 5238 NV_PRINTF(LEVEL_ERROR, "Failed to read RG_DPCA.\n"); 5239 return rmStatus; 5240 } 5241 } 5242 5243 if ((lineCount >= safeRegionUpperLimit) || (lineCount <= safeRegionLowerLimit)) 5244 { 5245 return NV_ERR_TIMEOUT; 5246 } 5247 } 5248 5249 rmStatus |= readregu008_extdeviceTargeted(pGpu, (PDACEXTERNALDEVICE) pThis, (NvU8)NV_P2060_FRAMECNTR_LOW, &FrameCountLow); 5250 rmStatus |= readregu008_extdeviceTargeted(pGpu, (PDACEXTERNALDEVICE) pThis, (NvU8)NV_P2060_FRAMECNTR_MID, &FrameCountMid); 5251 rmStatus |= readregu008_extdeviceTargeted(pGpu, (PDACEXTERNALDEVICE) pThis, (NvU8)NV_P2060_FRAMECNTR_HIGH, &FrameCountHigh); 5252 5253 if (rmStatus != NV_OK) 5254 { 5255 return rmStatus; 5256 } 5257 5258 rawGsyncFrameCount = ( 5259 ((((NvU32)FrameCountHigh) & DRF_MASK(NV_P2060_FRAMECNTR_HIGH_VAL))<< 16 ) | 5260 ((((NvU32)FrameCountMid) & DRF_MASK(NV_P2060_FRAMECNTR_MID_VAL)) << 8 ) | 5261 ((((NvU32)FrameCountLow) & DRF_MASK(NV_P2060_FRAMECNTR_LOW_VAL)))); 5262 5263 pThis->FrameCountData.currentFrameCount = frameCount; 5264 5265 // 5266 // Gsync frame count is 24 bit register whereas Gpu frame count register is 16 bit. 5267 // Therefore number of rollovers of Gpu frame count register is required. 5268 // Else gsync frame count and (gpu frame count + difference) can be off by (2^16*N). 5269 // where maximum value of N can be 256. << gsync frame count 2^24 = 256* 2^16. 5270 // 5271 pThis->FrameCountData.numberOfRollbacks = gsyncGetNumberOfGpuFrameCountRollbacks_P2060(rawGsyncFrameCount, 0, 256); 5272 modGsyncFrameCount = rawGsyncFrameCount - (pThis->FrameCountData.numberOfRollbacks * (NV_P2060_MAX_GPU_FRAME_COUNT + 1)); 5273 pThis->FrameCountData.initialDifference = modGsyncFrameCount - pThis->FrameCountData.currentFrameCount; 5274 pThis->FrameCountData.previousFrameCount = 0; 5275 5276 pThis->FrameCountData.totalFrameCount = pThis->FrameCountData.currentFrameCount + 5277 pThis->FrameCountData.initialDifference + 5278 pThis->FrameCountData.numberOfRollbacks * (NV_P2060_MAX_GPU_FRAME_COUNT + 1); 5279 5280 if (pThis->FrameCountData.enableFrmCmpMatchIntSlave) 5281 { 5282 pThis->FrameCountData.enableFrmCmpMatchIntSlave = NV_FALSE; 5283 5284 // enable frame count match interrupt 5285 rmStatus |= readregu008_extdeviceTargeted(pGpu, (PDACEXTERNALDEVICE)pThis, 5286 NV_P2060_CONTROL3, ®Ctrl3); 5287 5288 if (rmStatus == NV_OK) 5289 { 5290 regCtrl3 |= DRF_DEF(_P2060, _CONTROL3, _INTERRUPT, _ON_FRAME_MATCH); 5291 rmStatus = writeregu008_extdeviceTargeted(pGpu, (PDACEXTERNALDEVICE)pThis, 5292 NV_P2060_CONTROL3, regCtrl3); 5293 } 5294 } 5295 5296 // 5297 // Schedule 1 second timer callback, to verify initialDifference. 5298 // 5299 if (pThis->FrameCountData.bReCheck) 5300 { 5301 5302 NV_STATUS status = NV_OK; 5303 OBJTMR *pTmr = GPU_GET_TIMER(pGpu); 5304 5305 status = tmrScheduleCallbackRel( 5306 pTmr, 5307 gsyncFrameCountTimerService_P2060, 5308 (void *)&pThis->FrameCountData, 5309 (NV_P2060_FRAME_COUNT_TIMER_INTERVAL / 5), 5310 TMR_FLAG_RECUR, 5311 0); 5312 5313 if (status == NV_OK) 5314 { 5315 pThis->FrameCountData.bReCheck = 0; 5316 } 5317 5318 } 5319 return rmStatus; 5320 } 5321 5322 // 5323 // gsyncGetNumberOfGpuFrameCountRollbacks_P2060 5324 // 5325 // Get N where N is the maximum value for gsync framecount > N*(Gpu frame count) 5326 // 5327 static NvU32 5328 gsyncGetNumberOfGpuFrameCountRollbacks_P2060 5329 ( 5330 NvU32 FrameCount, 5331 NvU32 low, 5332 NvU32 high 5333 ) 5334 { 5335 NvU32 mid = (low + high) / 2; 5336 5337 if (FrameCount >= (high * NV_P2060_MAX_GPU_FRAME_COUNT)) 5338 { 5339 return high; 5340 } 5341 else if ((FrameCount >= (mid * NV_P2060_MAX_GPU_FRAME_COUNT)) && 5342 (FrameCount < ((mid+1) * NV_P2060_MAX_GPU_FRAME_COUNT))) 5343 { 5344 return mid; 5345 } 5346 else if ((FrameCount > (NV_P2060_MAX_GPU_FRAME_COUNT * low)) && (FrameCount < (mid * NV_P2060_MAX_GPU_FRAME_COUNT))) 5347 { 5348 return gsyncGetNumberOfGpuFrameCountRollbacks_P2060(FrameCount, low, mid); 5349 } 5350 else if ((FrameCount > (NV_P2060_MAX_GPU_FRAME_COUNT * mid)) && (FrameCount < (high * NV_P2060_MAX_GPU_FRAME_COUNT))) 5351 { 5352 return gsyncGetNumberOfGpuFrameCountRollbacks_P2060(FrameCount, mid+1, high); 5353 } 5354 else 5355 { 5356 return 0; 5357 } 5358 } 5359 5360 // Return NV_TRUE if the current Qsync revision supports large sync skew 5361 NvBool 5362 gsyncSupportsLargeSyncSkew_P2060 5363 ( 5364 DACEXTERNALDEVICE *pExtdev 5365 ) 5366 { 5367 if (pExtdev->deviceId == DAC_EXTERNAL_DEVICE_P2061) 5368 { 5369 // All p2061 revisions support sync skew > 1. 5370 return NV_TRUE; 5371 } 5372 else 5373 { 5374 // 5375 // P2060 FPGA (revision < 3) does not support SyncSkew more than 1 us(HW limitation). 5376 // If set to value more than 1 us, we observe screen flashing. Refer bug 1058215 5377 // 5378 NV_ASSERT(pExtdev->deviceId == DAC_EXTERNAL_DEVICE_P2060); 5379 return (pExtdev->deviceRev >= DAC_EXTERNAL_DEVICE_REV_3); 5380 } 5381 } 5382 5383 // Return NV_TRUE if the current Qsync revision needs the Swapbarrier WAR on master 5384 static NvBool 5385 needsMasterBarrierWar 5386 ( 5387 PDACEXTERNALDEVICE pExtdev 5388 ) 5389 { 5390 if (pExtdev->deviceId == DAC_EXTERNAL_DEVICE_P2061) 5391 { 5392 // All p2061 revisions do not need the WAR. 5393 return NV_FALSE; 5394 } 5395 else 5396 { 5397 // 5398 // P2060 Fpga (revision <= 5) needs to have the swapbarrier set on framelock masters 5399 // to drive (pull up) the swap_rdy line of the whole framelock setup. 5400 // This is a behaviour with unwanted side effects which needs drivers wars 5401 // for certain configs. 5402 // 5403 NV_ASSERT(pExtdev->deviceId == DAC_EXTERNAL_DEVICE_P2060); 5404 return (pExtdev->deviceRev <= DAC_EXTERNAL_DEVICE_REV_5); 5405 } 5406 } 5407 5408 // Return NV_TRUE if the Qsync revision is not compatible with GPU 5409 static NvBool 5410 isFirmwareRevMismatch 5411 ( 5412 OBJGPU *pGpu, 5413 DAC_EXTERNAL_DEVICE_REVS currentRev 5414 ) 5415 { 5416 if (IsKEPLER(pGpu)) 5417 { 5418 return ((currentRev < NV_P2060_MIN_REV) || 5419 (currentRev == DAC_EXTERNAL_DEVICE_REV_5) || 5420 (currentRev == DAC_EXTERNAL_DEVICE_REV_6)); 5421 } 5422 else if (IsMAXWELL(pGpu)) 5423 { 5424 return (currentRev < NV_P2060_MIN_REV); 5425 } 5426 else 5427 { 5428 return NV_FALSE; 5429 } 5430 } 5431 5432 /* 5433 * Nvlink and QSync can both transmit inter-GPU Display sync signals. 5434 * Contention in these signals is observed on some boards, if both Nvlink and 5435 * QSync are present between the boards. 5436 * 5437 * Returns TRUE if contention in transmission of sync signals possible on the 5438 * given GPU board if both mediums (QSync and Nvlink) are present between GPUs 5439 */ 5440 5441 static NvBool 5442 isBoardWithNvlinkQsyncContention 5443 ( 5444 OBJGPU *pGpu 5445 ) 5446 { 5447 NvU16 devIds[] = { 5448 0x2230, // Nvidia RTX A6000 (PG133 SKU 500) 5449 0x2231, // Nvidia RTX A5000 (PG132 SKU 500) 5450 0x2233 // Nvidia RTX A5500 (PG132 SKU 520) 5451 }; 5452 5453 NvU16 thisDevId = (NvU16)(((pGpu->idInfo.PCIDeviceID) >> 16) & 0x0000FFFF); 5454 NvU32 i; 5455 5456 for (i=0; i < (sizeof(devIds)/sizeof(devIds[0])); i++) 5457 { 5458 if (thisDevId == devIds[i]) 5459 { 5460 return NV_TRUE; 5461 } 5462 } 5463 5464 return NV_FALSE; 5465 } 5466 5467 // Return NV_TRUE if the current Qsync revision supports sync multiply/divide 5468 static NvBool 5469 supportsMulDiv 5470 ( 5471 DACEXTERNALDEVICE *pExtDev 5472 ) 5473 { 5474 // Supported only for 2061 boards with >= 2.4 5475 if (pExtDev->deviceId == DAC_EXTERNAL_DEVICE_P2061) 5476 { 5477 if ((pExtDev->deviceRev >= DAC_EXTERNAL_DEVICE_REV_3) || 5478 ((pExtDev->deviceRev == DAC_EXTERNAL_DEVICE_REV_2) && 5479 (pExtDev->deviceExRev >= 4))) 5480 { 5481 return NV_TRUE; 5482 } 5483 } 5484 return NV_FALSE; 5485 } 5486 5487 NV_STATUS 5488 gsyncGetMulDiv_P2060 5489 ( 5490 OBJGPU *pGpu, 5491 DACEXTERNALDEVICE *pExtDev, 5492 NV30F1_CTRL_GSYNC_MULTIPLY_DIVIDE_SETTINGS *pMulDivSettings 5493 ) 5494 { 5495 DACP2060EXTERNALDEVICE *pThis = (DACP2060EXTERNALDEVICE *)pExtDev; 5496 NvU8 reg; 5497 5498 NV_ASSERT_OR_RETURN(pMulDivSettings != NULL, NV_ERR_INVALID_ARGUMENT); 5499 NV_CHECK_OR_RETURN(LEVEL_INFO, supportsMulDiv(pExtDev), NV_ERR_NOT_SUPPORTED); 5500 5501 NV_CHECK_OK_OR_RETURN(LEVEL_INFO, 5502 readregu008_extdeviceTargeted(pGpu, pExtDev, NV_P2060_MULTIPLIER_DIVIDER, ®)); 5503 5504 pMulDivSettings->multiplyDivideValue = 5505 DRF_VAL(_P2060, _MULTIPLIER_DIVIDER, _VALUE_MINUS_ONE, reg) + 1; 5506 pMulDivSettings->multiplyDivideMode = 5507 FLD_TEST_DRF(_P2060, _MULTIPLIER_DIVIDER, _MODE, _DIVIDE, reg) ? 5508 NV30F1_CTRL_GSYNC_SET_CONTROL_MULTIPLY_DIVIDE_MODE_DIVIDE : 5509 NV30F1_CTRL_GSYNC_SET_CONTROL_MULTIPLY_DIVIDE_MODE_MULTIPLY; 5510 5511 // Cache this for debugging 5512 portMemCopy(&pThis->mulDivSettings, sizeof(pThis->mulDivSettings), 5513 pMulDivSettings, sizeof(*pMulDivSettings)); 5514 5515 return NV_OK; 5516 } 5517 5518 NV_STATUS 5519 gsyncSetMulDiv_P2060 5520 ( 5521 OBJGPU *pGpu, 5522 DACEXTERNALDEVICE *pExtDev, 5523 NV30F1_CTRL_GSYNC_MULTIPLY_DIVIDE_SETTINGS *pMulDivSettings 5524 ) 5525 { 5526 DACP2060EXTERNALDEVICE *pThis = (DACP2060EXTERNALDEVICE *)pExtDev; 5527 NvU8 reg; 5528 5529 NV_ASSERT_OR_RETURN(pMulDivSettings != NULL, NV_ERR_INVALID_ARGUMENT); 5530 NV_CHECK_OR_RETURN(LEVEL_INFO, supportsMulDiv(pExtDev), NV_ERR_NOT_SUPPORTED); 5531 pGpu = GetP2060MasterableGpu(pGpu, (DACP2060EXTERNALDEVICE *)pExtDev); 5532 NV_ASSERT_OR_RETURN(pGpu != NULL, NV_ERR_GENERIC); 5533 5534 // 5535 // Assume that there are no other fields inside NV_P2060_MULTIPLIER_DIVIDER 5536 // to necessitate a read-modify-write 5537 // 5538 reg = 0; 5539 5540 switch (pMulDivSettings->multiplyDivideMode) 5541 { 5542 case NV30F1_CTRL_GSYNC_SET_CONTROL_MULTIPLY_DIVIDE_MODE_MULTIPLY: 5543 reg = FLD_SET_DRF(_P2060, _MULTIPLIER_DIVIDER, _MODE, _MULTIPLY, reg); 5544 break; 5545 case NV30F1_CTRL_GSYNC_SET_CONTROL_MULTIPLY_DIVIDE_MODE_DIVIDE: 5546 reg = FLD_SET_DRF(_P2060, _MULTIPLIER_DIVIDER, _MODE, _DIVIDE, reg); 5547 break; 5548 default: 5549 return NV_ERR_INVALID_PARAMETER; 5550 } 5551 5552 // The register is a 3-bit value ranging from 0-7 representing the integers from 1-8, so check the input param 5553 if ((pMulDivSettings->multiplyDivideValue < 1) || 5554 (pMulDivSettings->multiplyDivideValue > (NV_P2060_MULTIPLIER_DIVIDER_VALUE_MINUS_ONE_MAX + 1))) 5555 return NV_ERR_INVALID_PARAMETER; 5556 // Subtract 1 while packing the register 5557 reg = FLD_SET_DRF_NUM(_P2060, _MULTIPLIER_DIVIDER, _VALUE_MINUS_ONE, 5558 pMulDivSettings->multiplyDivideValue - 1, reg); 5559 5560 NV_CHECK_OK_OR_RETURN(LEVEL_INFO, writeregu008_extdeviceTargeted(pGpu, pExtDev, NV_P2060_MULTIPLIER_DIVIDER, reg)); 5561 5562 // Cache this for debugging 5563 portMemCopy(&pThis->mulDivSettings, sizeof(pThis->mulDivSettings), 5564 pMulDivSettings, sizeof(*pMulDivSettings)); 5565 5566 return NV_OK; 5567 } 5568