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