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,  &regCtrl3);
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,  &regCtrl3);
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, &regNSync);
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, &regNSync);
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, &regStatus2);
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, &regStatus));
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, &regStatus));
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, &regStatus);
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, &regStatus2);
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, &regStatus2);
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, &regStatus2);
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, &regStatus2);
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, &regControl);
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, &regStatus2);
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,  &regStatus);
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,  &regCtrl3);
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, &regCtrl3);
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, &regCtrl3);
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, &regCtrl3);
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, &regCtrl3);
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,  &regCtrl3);
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, &reg));
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