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