1758b4ee8SAndy Ritger /*
2eb5c7665SAndy Ritger  * SPDX-FileCopyrightText: Copyright (c) 1993-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3758b4ee8SAndy Ritger  * SPDX-License-Identifier: MIT
4758b4ee8SAndy Ritger  *
5758b4ee8SAndy Ritger  * Permission is hereby granted, free of charge, to any person obtaining a
6758b4ee8SAndy Ritger  * copy of this software and associated documentation files (the "Software"),
7758b4ee8SAndy Ritger  * to deal in the Software without restriction, including without limitation
8758b4ee8SAndy Ritger  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9758b4ee8SAndy Ritger  * and/or sell copies of the Software, and to permit persons to whom the
10758b4ee8SAndy Ritger  * Software is furnished to do so, subject to the following conditions:
11758b4ee8SAndy Ritger  *
12758b4ee8SAndy Ritger  * The above copyright notice and this permission notice shall be included in
13758b4ee8SAndy Ritger  * all copies or substantial portions of the Software.
14758b4ee8SAndy Ritger  *
15758b4ee8SAndy Ritger  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16758b4ee8SAndy Ritger  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17758b4ee8SAndy Ritger  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18758b4ee8SAndy Ritger  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19758b4ee8SAndy Ritger  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20758b4ee8SAndy Ritger  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21758b4ee8SAndy Ritger  * DEALINGS IN THE SOFTWARE.
22758b4ee8SAndy Ritger  */
23758b4ee8SAndy Ritger 
24758b4ee8SAndy Ritger #include "nvrm_registry.h"
25758b4ee8SAndy Ritger #include "objtmr.h"
26758b4ee8SAndy Ritger #include "gpu/external_device/gsync.h"
27758b4ee8SAndy Ritger #include "dev_p2060.h"
28758b4ee8SAndy Ritger #include "gpu/external_device/dac_p2060.h"
29758b4ee8SAndy Ritger #include "gpu_mgr/gpu_mgr.h"
30758b4ee8SAndy Ritger #include "gpu/disp/kern_disp.h"
31758b4ee8SAndy Ritger #include "rmapi/rmapi_utils.h"
32758b4ee8SAndy Ritger #include "class/cl402c.h" // NV40_I2C
33758b4ee8SAndy Ritger #include "kernel/gpu/i2c/i2c_api.h"
34*91676d66SBernhard Stoeckner #include "platform/sli/sli.h"
35758b4ee8SAndy Ritger /*
36758b4ee8SAndy Ritger  * statics
37758b4ee8SAndy Ritger  */
38758b4ee8SAndy Ritger 
39758b4ee8SAndy Ritger static NvBool     GpuIsP2060Master   (OBJGPU *, PDACP2060EXTERNALDEVICE);
40758b4ee8SAndy Ritger static NvBool     GpuIsP2060Connected(OBJGPU *, PDACP2060EXTERNALDEVICE);
41758b4ee8SAndy Ritger static NvBool     GpuIsMosaicTimingSlave(OBJGPU *, PDACP2060EXTERNALDEVICE);
42758b4ee8SAndy Ritger static NvBool     GpuIsConnectedToMasterViaBridge(OBJGPU *, PDACP2060EXTERNALDEVICE);
43758b4ee8SAndy Ritger 
44758b4ee8SAndy Ritger static OBJGPU*    GetP2060MasterableGpu (OBJGPU *, PDACP2060EXTERNALDEVICE);
45758b4ee8SAndy Ritger static OBJGPU*    GetP2060WatchdogGpu   (OBJGPU *, PDACP2060EXTERNALDEVICE);
46758b4ee8SAndy Ritger 
47758b4ee8SAndy Ritger static NV_STATUS  GetP2060GpuLocation   (OBJGPU *, PDACP2060EXTERNALDEVICE, NvU32*);
48758b4ee8SAndy Ritger static NV_STATUS  GetP2060ConnectorIndexFromGpu (OBJGPU *, PDACP2060EXTERNALDEVICE, NvU32*);
49758b4ee8SAndy Ritger static NvU32      GetP2060GpuSnapshot   (OBJGPU *, PDACP2060EXTERNALDEVICE);
50758b4ee8SAndy Ritger 
51758b4ee8SAndy Ritger static void       gsyncProgramFramelockEnable_P2060(OBJGPU *, PDACP2060EXTERNALDEVICE, NvU32, NvBool);
52758b4ee8SAndy Ritger static NvBool     gsyncIsStereoEnabled_p2060 (OBJGPU *, PDACEXTERNALDEVICE);
53758b4ee8SAndy Ritger static NV_STATUS  gsyncProgramExtStereoPolarity_P2060 (OBJGPU *, PDACEXTERNALDEVICE);
54758b4ee8SAndy Ritger 
55758b4ee8SAndy Ritger static NV_STATUS  gsyncProgramSlaves_P2060(OBJGPU *, PDACP2060EXTERNALDEVICE, NvU32);
56758b4ee8SAndy Ritger static NvU32      gsyncReadSlaves_P2060(OBJGPU *, PDACP2060EXTERNALDEVICE);
57758b4ee8SAndy Ritger static NV_STATUS  gsyncProgramMaster_P2060(OBJGPU *, PDACP2060EXTERNALDEVICE, NvU32, NvBool, NvBool);
58758b4ee8SAndy Ritger static NvU32      gsyncReadMaster_P2060(OBJGPU *, PDACP2060EXTERNALDEVICE);
59758b4ee8SAndy Ritger 
60758b4ee8SAndy Ritger static NV_STATUS  gsyncUpdateGsyncStatusSnapshot_P2060(OBJGPU *, PDACEXTERNALDEVICE);
61758b4ee8SAndy Ritger 
62758b4ee8SAndy Ritger static void       gsyncCancelWatchdog_P2060(PDACP2060EXTERNALDEVICE);
63758b4ee8SAndy Ritger static NV_STATUS  gsyncDisableFrameLockInterrupt_P2060(PDACEXTERNALDEVICE);
64758b4ee8SAndy Ritger static NV_STATUS  gsyncEnableFramelockInterrupt_P2060(PDACEXTERNALDEVICE);
65758b4ee8SAndy Ritger static NV_STATUS  gsyncDisableNonFramelockInterrupt_P2060(OBJGPU *, PDACEXTERNALDEVICE);
66758b4ee8SAndy Ritger static NV_STATUS  gsyncEnableNonFramelockInterrupt_P2060(OBJGPU *, PDACEXTERNALDEVICE);
67758b4ee8SAndy Ritger static void       gsyncResetMosaicData_P2060(NvU32, PDACP2060EXTERNALDEVICE);
68758b4ee8SAndy Ritger static NV_STATUS  gsyncUpdateSwapRdyConnectionForGpu_P2060(OBJGPU *, PDACP2060EXTERNALDEVICE, NvBool);
69758b4ee8SAndy Ritger 
70758b4ee8SAndy Ritger static NvBool     gsyncIsFrameLocked_P2060(PDACP2060EXTERNALDEVICE);
71758b4ee8SAndy Ritger static NvBool     gsyncIsOnlyFrameLockMaster_P2060(PDACP2060EXTERNALDEVICE);
72758b4ee8SAndy Ritger static NvBool     gsyncIsFrameLockMaster_P2060(PDACP2060EXTERNALDEVICE);
73758b4ee8SAndy Ritger static NvBool     gsyncIsP2060MasterBoard(OBJGPU *, PDACP2060EXTERNALDEVICE);
74758b4ee8SAndy Ritger 
75758b4ee8SAndy Ritger static NV_STATUS  gsyncSetLsrMinTime(OBJGPU *, PDACEXTERNALDEVICE, NvU32);
76758b4ee8SAndy Ritger 
77758b4ee8SAndy Ritger static NV_STATUS  gsyncUpdateFrameCount_P2060(PDACP2060EXTERNALDEVICE, OBJGPU *);
78758b4ee8SAndy Ritger static NvU32      gsyncGetNumberOfGpuFrameCountRollbacks_P2060(NvU32, NvU32, NvU32);
79758b4ee8SAndy Ritger static NV_STATUS  gsyncFrameCountTimerService_P2060(OBJGPU *, OBJTMR *, void *);
80758b4ee8SAndy Ritger static NV_STATUS  gsyncResetFrameCountData_P2060(OBJGPU *, PDACP2060EXTERNALDEVICE);
81758b4ee8SAndy Ritger 
82758b4ee8SAndy Ritger static NV_STATUS  gsyncGpuStereoHeadSync(OBJGPU *, NvU32, PDACEXTERNALDEVICE, NvU32);
834397463eSAndy Ritger static NvBool     supportsMulDiv(DACEXTERNALDEVICE *);
84758b4ee8SAndy Ritger static NvBool     needsMasterBarrierWar(PDACEXTERNALDEVICE);
85758b4ee8SAndy Ritger static NvBool     isFirmwareRevMismatch(OBJGPU *, DAC_EXTERNAL_DEVICE_REVS);
86758b4ee8SAndy Ritger 
874397463eSAndy Ritger static NvBool     isBoardWithNvlinkQsyncContention(OBJGPU *);
88758b4ee8SAndy Ritger static void       _extdevService(NvU32 , void *);
89758b4ee8SAndy Ritger 
90758b4ee8SAndy Ritger NvBool
extdevGetDevice_P2060(OBJGPU * pGpu,PDACEXTERNALDEVICE pExternalDevice)91758b4ee8SAndy Ritger extdevGetDevice_P2060
92758b4ee8SAndy Ritger (
93758b4ee8SAndy Ritger     OBJGPU *pGpu,
94758b4ee8SAndy Ritger     PDACEXTERNALDEVICE pExternalDevice
95758b4ee8SAndy Ritger )
96758b4ee8SAndy Ritger {
97758b4ee8SAndy Ritger     NvU8 revId;
98758b4ee8SAndy Ritger     NvU8 data;
99758b4ee8SAndy Ritger     DAC_EXTERNAL_DEVICES externalDeviceId;
100758b4ee8SAndy Ritger     DAC_EXTERNAL_DEVICE_REVS externalDeviceRev;
101758b4ee8SAndy Ritger     NV_STATUS status;
102758b4ee8SAndy Ritger 
103758b4ee8SAndy Ritger     if (!RMCFG_FEATURE_EXTDEV_GSYNC_P2060 ||
104758b4ee8SAndy Ritger         IS_EMULATION(pGpu) || IS_SIMULATION(pGpu))
105758b4ee8SAndy Ritger     {
106758b4ee8SAndy Ritger         return NV_FALSE;
107758b4ee8SAndy Ritger     }
108758b4ee8SAndy Ritger 
109758b4ee8SAndy Ritger     // Read the FPGA revision register
110758b4ee8SAndy Ritger     status = readregu008_extdevice(pGpu, pExternalDevice, (NvU8)NV_P2060_FPGA, &data);
111758b4ee8SAndy Ritger     if (status != NV_OK)
112758b4ee8SAndy Ritger     {
113758b4ee8SAndy Ritger         return NV_FALSE;
114758b4ee8SAndy Ritger     }
115758b4ee8SAndy Ritger     revId = data;
116758b4ee8SAndy Ritger 
117758b4ee8SAndy Ritger     // Decode the register value into device ID
118758b4ee8SAndy Ritger     if (DRF_VAL(_P2060, _FPGA, _ID, data) == NV_P2060_FPGA_ID_5)
119758b4ee8SAndy Ritger     {
120758b4ee8SAndy Ritger         externalDeviceId = DAC_EXTERNAL_DEVICE_P2060;
121758b4ee8SAndy Ritger     }
122758b4ee8SAndy Ritger     else if (DRF_VAL(_P2061, _FPGA, _ID, data) == NV_P2061_FPGA_ID_4)
123758b4ee8SAndy Ritger     {
124758b4ee8SAndy Ritger         externalDeviceId = DAC_EXTERNAL_DEVICE_P2061;
125758b4ee8SAndy Ritger     }
126758b4ee8SAndy Ritger     else
127758b4ee8SAndy Ritger     {
128758b4ee8SAndy Ritger         return NV_FALSE;
129758b4ee8SAndy Ritger     }
130758b4ee8SAndy Ritger 
131758b4ee8SAndy Ritger     // Decode the register value into device revision (major revision)
132758b4ee8SAndy Ritger     externalDeviceRev = DRF_VAL(_P2060, _FPGA, _REV, data);
133758b4ee8SAndy Ritger 
134758b4ee8SAndy Ritger     // Read device extended revision (minor revision)
135758b4ee8SAndy Ritger     status = readregu008_extdevice(pGpu, pExternalDevice, (NvU8)NV_P2060_FPGA_EXREV, &data);
136758b4ee8SAndy Ritger     if (status != NV_OK)
137758b4ee8SAndy Ritger     {
138758b4ee8SAndy Ritger         return NV_FALSE;
139758b4ee8SAndy Ritger     }
140758b4ee8SAndy Ritger 
141758b4ee8SAndy Ritger     // Caching revId, device ID, device revision, and device extended revision
142758b4ee8SAndy Ritger     pExternalDevice->revId = revId;
143758b4ee8SAndy Ritger     pExternalDevice->deviceId = externalDeviceId;
144758b4ee8SAndy Ritger     pExternalDevice->deviceRev = externalDeviceRev;
145758b4ee8SAndy Ritger     pExternalDevice->deviceExRev = data;
146758b4ee8SAndy Ritger 
147758b4ee8SAndy Ritger     return NV_TRUE;
148758b4ee8SAndy Ritger }
149758b4ee8SAndy Ritger 
150758b4ee8SAndy Ritger /*
151758b4ee8SAndy Ritger  * Return Extdev with setting of the data structures and
152758b4ee8SAndy Ritger  * function pointers for P2060.
153758b4ee8SAndy Ritger  */
154758b4ee8SAndy Ritger PDACEXTERNALDEVICE
extdevConstruct_P2060(OBJGPU * pGpu,PDACEXTERNALDEVICE pExternalDevice)155758b4ee8SAndy Ritger extdevConstruct_P2060
156758b4ee8SAndy Ritger (
157758b4ee8SAndy Ritger     OBJGPU             *pGpu,
158758b4ee8SAndy Ritger     PDACEXTERNALDEVICE  pExternalDevice
159758b4ee8SAndy Ritger )
160758b4ee8SAndy Ritger {
161758b4ee8SAndy Ritger     DACP2060EXTERNALDEVICE *pThis = (PDACP2060EXTERNALDEVICE)pExternalDevice;
162758b4ee8SAndy Ritger     KernelDisplay          *pKernelDisplay = GPU_GET_KERNEL_DISPLAY(pGpu);
163758b4ee8SAndy Ritger     NvU32 iface, head, i;
164758b4ee8SAndy Ritger     NvU32 numHeads = kdispGetNumHeads(pKernelDisplay);
165758b4ee8SAndy Ritger 
166758b4ee8SAndy Ritger     if ( !extdevConstruct_Base(pGpu, pExternalDevice) )
167758b4ee8SAndy Ritger     {
168758b4ee8SAndy Ritger         return 0;
169758b4ee8SAndy Ritger     }
170758b4ee8SAndy Ritger 
171758b4ee8SAndy Ritger     // Setup interfaces
172758b4ee8SAndy Ritger     pThis->ExternalDevice.pI->Destroy = extdevDestroy_P2060;
173758b4ee8SAndy Ritger     pThis->ExternalDevice.pI->Attach  = gsyncAttachExternalDevice_P2060;
174758b4ee8SAndy Ritger 
175758b4ee8SAndy Ritger     pThis->ExternalDevice.pI->GetDevice             = extdevGetDevice_P2060;
176758b4ee8SAndy Ritger     pThis->ExternalDevice.pI->Init                  = extdevInit_P2060;
177758b4ee8SAndy Ritger 
178758b4ee8SAndy Ritger     pThis->ExternalDevice.pI->Service               = extdevService_P2060;
179758b4ee8SAndy Ritger     pThis->ExternalDevice.pI->Watchdog              = extdevWatchdog_P2060;
180758b4ee8SAndy Ritger     pThis->ExternalDevice.pI->setI2cHandles         = extdevSaveI2cHandles_P2060;
181758b4ee8SAndy Ritger 
182758b4ee8SAndy Ritger 
183758b4ee8SAndy Ritger     // Init data members
184758b4ee8SAndy Ritger     pThis->ExternalDevice.I2CAddr     = 0x20;
185758b4ee8SAndy Ritger     pThis->ExternalDevice.I2CPort     = pGpu->i2cPortForExtdev;
186758b4ee8SAndy Ritger     pThis->ExternalDevice.MaxGpus     = NV_P2060_MAX_IFACES_PER_GSYNC * NV_P2060_MAX_GPUS_PER_IFACE;
187758b4ee8SAndy Ritger 
188758b4ee8SAndy Ritger     pThis->gpuAttachMask = 0;
189758b4ee8SAndy Ritger     pThis->id = 0;
190758b4ee8SAndy Ritger     pThis->watchdogCountDownValue = 0;
191758b4ee8SAndy Ritger     pThis->isNonFramelockInterruptEnabled = NV_FALSE;
192758b4ee8SAndy Ritger     pThis->interruptEnabledInterface = 0;
193758b4ee8SAndy Ritger     pThis->tSwapRdyHi = 0;
194758b4ee8SAndy Ritger     pThis->tSwapRdyHiLsrMinTime = 0;
195758b4ee8SAndy Ritger 
196758b4ee8SAndy Ritger     //init FrameCountData
197758b4ee8SAndy Ritger     pThis->FrameCountData.totalFrameCount               = 0;
198758b4ee8SAndy Ritger     pThis->FrameCountData.currentFrameCount             = 0;
199758b4ee8SAndy Ritger     pThis->FrameCountData.initialDifference             = 0;
200758b4ee8SAndy Ritger     pThis->FrameCountData.numberOfRollbacks             = 0;
201758b4ee8SAndy Ritger     pThis->FrameCountData.previousFrameCount            = 0;
202758b4ee8SAndy Ritger     pThis->FrameCountData.lastFrameCounterQueryTime     = 0;
203758b4ee8SAndy Ritger     pThis->FrameCountData.bReCheck                      = 0;
204758b4ee8SAndy Ritger     pThis->FrameCountData.vActive                       = 0;
205758b4ee8SAndy Ritger     pThis->FrameCountData.isFrmCmpMatchIntMasterEnabled = NV_FALSE;
206758b4ee8SAndy Ritger     pThis->FrameCountData.enableFrmCmpMatchIntSlave     = NV_FALSE;
207758b4ee8SAndy Ritger     pThis->FrameCountData.head                          = NV_P2060_MAX_HEADS_PER_GPU;
208758b4ee8SAndy Ritger     pThis->FrameCountData.iface                         = NV_P2060_MAX_IFACES_PER_GSYNC;
209758b4ee8SAndy Ritger 
210758b4ee8SAndy Ritger     for (iface = 0; iface < NV_P2060_MAX_IFACES_PER_GSYNC; iface++)
211758b4ee8SAndy Ritger     {
212758b4ee8SAndy Ritger         pThis->Iface[iface].GpuInfo.gpuId     = NV0000_CTRL_GPU_INVALID_ID;
213758b4ee8SAndy Ritger         pThis->Iface[iface].GpuInfo.connected = NV_FALSE;
214758b4ee8SAndy Ritger 
215758b4ee8SAndy Ritger         pThis->Iface[iface].RasterSyncGpio.saved   = NV_FALSE;
216758b4ee8SAndy Ritger         pThis->Iface[iface].DsiFliplock.saved      = NV_FALSE;
217758b4ee8SAndy Ritger 
218758b4ee8SAndy Ritger         for (head = 0; head < numHeads; head++)
219758b4ee8SAndy Ritger         {
220758b4ee8SAndy Ritger             pThis->Iface[iface].Sync.Master[head]     = 0;
221758b4ee8SAndy Ritger             pThis->Iface[iface].Sync.Slaved[head]     = 0;
222758b4ee8SAndy Ritger             pThis->Iface[iface].Sync.LocalSlave[head] = 0;
223758b4ee8SAndy Ritger         }
224758b4ee8SAndy Ritger 
225758b4ee8SAndy Ritger         pThis->Iface[iface].lastEventNotified = 0;
226758b4ee8SAndy Ritger         pThis->Iface[iface].gainedSync        = 0;
227758b4ee8SAndy Ritger 
228758b4ee8SAndy Ritger         pThis->i2cHandles[iface].hClient       = 0;
229758b4ee8SAndy Ritger         pThis->i2cHandles[iface].hDevice       = 0;
230758b4ee8SAndy Ritger         pThis->i2cHandles[iface].hSubdevice    = 0;
231758b4ee8SAndy Ritger         pThis->i2cHandles[iface].hSubscription = 0;
232758b4ee8SAndy Ritger         pThis->i2cHandles[iface].gpuId         = 0;
233758b4ee8SAndy Ritger     }
234758b4ee8SAndy Ritger 
235758b4ee8SAndy Ritger     //init MosaicData
236758b4ee8SAndy Ritger     for (i = 0; i < NV_P2060_MAX_MOSAIC_GROUPS; i++)
237758b4ee8SAndy Ritger     {
238758b4ee8SAndy Ritger         gsyncResetMosaicData_P2060(i, pThis);
239758b4ee8SAndy Ritger     }
240758b4ee8SAndy Ritger 
241758b4ee8SAndy Ritger     return pExternalDevice;
242758b4ee8SAndy Ritger }
243758b4ee8SAndy Ritger 
244758b4ee8SAndy Ritger /*
245758b4ee8SAndy Ritger  * setup device registers
246758b4ee8SAndy Ritger  */
247758b4ee8SAndy Ritger static void
_externalDeviceInit_P2060(OBJGPU * pGpu,NvBool bExtDevFound)248758b4ee8SAndy Ritger _externalDeviceInit_P2060
249758b4ee8SAndy Ritger (
250758b4ee8SAndy Ritger     OBJGPU            *pGpu,
251758b4ee8SAndy Ritger     NvBool             bExtDevFound
252758b4ee8SAndy Ritger )
253758b4ee8SAndy Ritger {
254758b4ee8SAndy Ritger     KernelDisplay *pKernelDisplay = GPU_GET_KERNEL_DISPLAY(pGpu);
255758b4ee8SAndy Ritger     RM_API   *pRmApi      = GPU_GET_PHYSICAL_RMAPI(pGpu);
256758b4ee8SAndy Ritger     NvU32     hClient     = pGpu->hInternalClient;
257758b4ee8SAndy Ritger     NvU32     hSubdevice  = pGpu->hInternalSubdevice;
258758b4ee8SAndy Ritger     NV_STATUS status      = NV_OK;
259758b4ee8SAndy Ritger     NV2080_CTRL_INTERNAL_GSYNC_ATTACH_AND_INIT_PARAMS ctrlParams = {0};
260758b4ee8SAndy Ritger 
261758b4ee8SAndy Ritger     ctrlParams.bExtDevFound = bExtDevFound;
262758b4ee8SAndy Ritger 
263758b4ee8SAndy Ritger     status = pRmApi->Control(pRmApi, hClient, hSubdevice,
264758b4ee8SAndy Ritger                              NV2080_CTRL_CMD_INTERNAL_GSYNC_ATTACH_AND_INIT,
265758b4ee8SAndy Ritger                              &ctrlParams, sizeof(ctrlParams));
266758b4ee8SAndy Ritger 
267758b4ee8SAndy Ritger     if (status != NV_OK)
268758b4ee8SAndy Ritger     {
269758b4ee8SAndy Ritger         NV_PRINTF(LEVEL_ERROR, "Extdev GPIO interrupt enable failed\n");
270758b4ee8SAndy Ritger     }
271758b4ee8SAndy Ritger     else
272758b4ee8SAndy Ritger     {
273758b4ee8SAndy Ritger         pKernelDisplay->bExtdevIntrSupported = NV_TRUE;
274758b4ee8SAndy Ritger     }
275758b4ee8SAndy Ritger 
276758b4ee8SAndy Ritger     return;
277758b4ee8SAndy Ritger }
278758b4ee8SAndy Ritger 
279758b4ee8SAndy Ritger NV_STATUS
gsyncFindGpuHandleLocation(DACEXTERNALDEVICE * pExternalDevice,NvU32 gpuId,NvU32 * iface)280758b4ee8SAndy Ritger gsyncFindGpuHandleLocation
281758b4ee8SAndy Ritger (
282758b4ee8SAndy Ritger     DACEXTERNALDEVICE      *pExternalDevice,
283758b4ee8SAndy Ritger     NvU32                   gpuId,
284758b4ee8SAndy Ritger     NvU32                  *iface
285758b4ee8SAndy Ritger )
286758b4ee8SAndy Ritger {
287758b4ee8SAndy Ritger     DACP2060EXTERNALDEVICE *pThis = (PDACP2060EXTERNALDEVICE)pExternalDevice;
288758b4ee8SAndy Ritger     NvU32 tempIface;
289758b4ee8SAndy Ritger     NV_STATUS rmStatus = NV_ERR_GENERIC;
290758b4ee8SAndy Ritger 
291758b4ee8SAndy Ritger     for (tempIface = 0; tempIface < NV_P2060_MAX_IFACES_PER_GSYNC; tempIface++)
292758b4ee8SAndy Ritger     {
293758b4ee8SAndy Ritger         if (pThis->i2cHandles[tempIface].gpuId == gpuId)
294758b4ee8SAndy Ritger         {
295758b4ee8SAndy Ritger             *iface = tempIface;
296758b4ee8SAndy Ritger             rmStatus = NV_OK;
297758b4ee8SAndy Ritger         }
298758b4ee8SAndy Ritger     }
299758b4ee8SAndy Ritger 
300758b4ee8SAndy Ritger     return rmStatus;
301758b4ee8SAndy Ritger }
302758b4ee8SAndy Ritger 
303758b4ee8SAndy Ritger static NV_STATUS
gsyncFindFreeHandleLocation(DACP2060EXTERNALDEVICE * pThis,NvU32 * iface)304758b4ee8SAndy Ritger gsyncFindFreeHandleLocation
305758b4ee8SAndy Ritger (
306758b4ee8SAndy Ritger     DACP2060EXTERNALDEVICE *pThis,
307758b4ee8SAndy Ritger     NvU32                  *iface
308758b4ee8SAndy Ritger )
309758b4ee8SAndy Ritger {
310758b4ee8SAndy Ritger     NvU32 tempIface;
311758b4ee8SAndy Ritger     NV_STATUS rmStatus = NV_ERR_GENERIC;
312758b4ee8SAndy Ritger 
313758b4ee8SAndy Ritger     for (tempIface = 0; tempIface < NV_P2060_MAX_IFACES_PER_GSYNC; tempIface++)
314758b4ee8SAndy Ritger     {
315758b4ee8SAndy Ritger         if (pThis->i2cHandles[tempIface].gpuId == 0)
316758b4ee8SAndy Ritger         {
317758b4ee8SAndy Ritger             *iface = tempIface;
318758b4ee8SAndy Ritger             rmStatus = NV_OK;
319758b4ee8SAndy Ritger         }
320758b4ee8SAndy Ritger     }
321758b4ee8SAndy Ritger 
322758b4ee8SAndy Ritger     return rmStatus;
323758b4ee8SAndy Ritger }
324758b4ee8SAndy Ritger 
325758b4ee8SAndy Ritger NvBool
extdevSaveI2cHandles_P2060(OBJGPU * pGpu,DACEXTERNALDEVICE * pExternalDevice)326758b4ee8SAndy Ritger extdevSaveI2cHandles_P2060
327758b4ee8SAndy Ritger (
328758b4ee8SAndy Ritger     OBJGPU             *pGpu,
329758b4ee8SAndy Ritger     DACEXTERNALDEVICE  *pExternalDevice
330758b4ee8SAndy Ritger )
331758b4ee8SAndy Ritger {
332758b4ee8SAndy Ritger     DACP2060EXTERNALDEVICE *pThis = (PDACP2060EXTERNALDEVICE)pExternalDevice;
333758b4ee8SAndy Ritger     RM_API                 *pRmApi = rmapiGetInterface(RMAPI_GPU_LOCK_INTERNAL);
334758b4ee8SAndy Ritger     NvHandle                hClient;
335758b4ee8SAndy Ritger     NvHandle                hDevice;
336758b4ee8SAndy Ritger     NvHandle                hSubdevice;
337758b4ee8SAndy Ritger     NvHandle                hSubscription = NV01_NULL_OBJECT;
338758b4ee8SAndy Ritger     NvU32                   iface;
339758b4ee8SAndy Ritger     NV_STATUS               rmStatus;
340758b4ee8SAndy Ritger 
341758b4ee8SAndy Ritger     rmStatus = gsyncFindFreeHandleLocation(pThis, &iface);
342758b4ee8SAndy Ritger     if (rmStatus != NV_OK)
343758b4ee8SAndy Ritger     {
344758b4ee8SAndy Ritger         NV_PRINTF(LEVEL_ERROR, "Maximum number of GPUs have been attached\n");
345758b4ee8SAndy Ritger         return NV_FALSE;
346758b4ee8SAndy Ritger     }
347758b4ee8SAndy Ritger 
348758b4ee8SAndy Ritger     rmStatus = rmapiutilAllocClientAndDeviceHandles(pRmApi,
349758b4ee8SAndy Ritger                                                     pGpu, &hClient, &hDevice, &hSubdevice);
350758b4ee8SAndy Ritger     NV_ASSERT_OR_RETURN(rmStatus == NV_OK, NV_FALSE);
351758b4ee8SAndy Ritger 
352758b4ee8SAndy Ritger     rmStatus = pRmApi->Alloc(pRmApi, hClient, hSubdevice,
353eb5c7665SAndy Ritger                             &hSubscription, NV40_I2C, NULL, 0);
354758b4ee8SAndy Ritger 
355758b4ee8SAndy Ritger     NV_ASSERT_OR_RETURN(rmStatus == NV_OK, NV_FALSE);
356758b4ee8SAndy Ritger 
357758b4ee8SAndy Ritger     pThis->i2cHandles[iface].hClient       = hClient;
358758b4ee8SAndy Ritger     pThis->i2cHandles[iface].hDevice       = hDevice;
359758b4ee8SAndy Ritger     pThis->i2cHandles[iface].hSubdevice    = hSubdevice;
360758b4ee8SAndy Ritger     pThis->i2cHandles[iface].hSubscription = hSubscription;
361758b4ee8SAndy Ritger     pThis->i2cHandles[iface].gpuId         = pGpu->gpuId;
362758b4ee8SAndy Ritger 
363758b4ee8SAndy Ritger     return NV_TRUE;
364758b4ee8SAndy Ritger }
365758b4ee8SAndy Ritger 
366758b4ee8SAndy Ritger NV_STATUS
i2c_extdeviceHelper(OBJGPU * pGpu,DACEXTERNALDEVICE * pExternalDevice,NvU32 i2cPort,NvU8 SubAdr,NvU8 * pData,NvBool write)367758b4ee8SAndy Ritger i2c_extdeviceHelper
368758b4ee8SAndy Ritger (
369758b4ee8SAndy Ritger     OBJGPU            *pGpu,
370758b4ee8SAndy Ritger     DACEXTERNALDEVICE *pExternalDevice,
371758b4ee8SAndy Ritger     NvU32              i2cPort,
372758b4ee8SAndy Ritger     NvU8               SubAdr,
373758b4ee8SAndy Ritger     NvU8              *pData,
374758b4ee8SAndy Ritger     NvBool             write
375758b4ee8SAndy Ritger )
376758b4ee8SAndy Ritger {
377758b4ee8SAndy Ritger     RM_API                 *pRmApi  = rmapiGetInterface(RMAPI_GPU_LOCK_INTERNAL);
378758b4ee8SAndy Ritger     DACP2060EXTERNALDEVICE *pThis   = (PDACP2060EXTERNALDEVICE)pExternalDevice;
379758b4ee8SAndy Ritger     NV_STATUS               status  = NV_ERR_GENERIC;
380758b4ee8SAndy Ritger     NvU32                   iface;
381758b4ee8SAndy Ritger     NV402C_CTRL_I2C_TRANSACTION_PARAMS *pParams;
382758b4ee8SAndy Ritger 
383758b4ee8SAndy Ritger     pParams = portMemAllocNonPaged(sizeof(*pParams));
384758b4ee8SAndy Ritger     if (pParams == NULL)
385758b4ee8SAndy Ritger     {
386758b4ee8SAndy Ritger         return NV_ERR_NO_MEMORY;
387758b4ee8SAndy Ritger     }
388758b4ee8SAndy Ritger 
389758b4ee8SAndy Ritger     status = gsyncFindGpuHandleLocation(pExternalDevice, pGpu->gpuId, &iface);
390758b4ee8SAndy Ritger     if (status != NV_OK)
391758b4ee8SAndy Ritger     {
392758b4ee8SAndy Ritger         NV_PRINTF(LEVEL_ERROR, "Couldn't find saved GPU entry, check saved i2chandles. \n");
393758b4ee8SAndy Ritger         return status;
394758b4ee8SAndy Ritger     }
395758b4ee8SAndy Ritger 
396758b4ee8SAndy Ritger     portMemSet(pParams, 0, sizeof(*pParams));
397758b4ee8SAndy Ritger 
398758b4ee8SAndy Ritger     pParams->portId        = (NvU8)i2cPort;
399758b4ee8SAndy Ritger     pParams->transType     = NV402C_CTRL_I2C_TRANSACTION_TYPE_SMBUS_BYTE_RW;
400758b4ee8SAndy Ritger     pParams->deviceAddress = (NvU16)pExternalDevice->I2CAddr;
401758b4ee8SAndy Ritger 
402758b4ee8SAndy Ritger     pParams->transData.smbusByteData.bWrite = write;
403758b4ee8SAndy Ritger     pParams->transData.smbusByteData.registerAddress = SubAdr;
404758b4ee8SAndy Ritger     if (write)
405758b4ee8SAndy Ritger     {
406758b4ee8SAndy Ritger         pParams->transData.smbusByteData.message = *pData;
407758b4ee8SAndy Ritger     }
408758b4ee8SAndy Ritger 
409758b4ee8SAndy Ritger     status = pRmApi->Control(pRmApi, pThis->i2cHandles[iface].hClient,
410758b4ee8SAndy Ritger                              pThis->i2cHandles[iface].hSubscription,
411758b4ee8SAndy Ritger                              NV402C_CTRL_CMD_I2C_TRANSACTION,
412758b4ee8SAndy Ritger                              pParams, sizeof(*pParams));
413758b4ee8SAndy Ritger 
414758b4ee8SAndy Ritger     if (!write)
415758b4ee8SAndy Ritger     {
416758b4ee8SAndy Ritger         *pData = pParams->transData.smbusByteData.message;
417758b4ee8SAndy Ritger     }
418758b4ee8SAndy Ritger 
419758b4ee8SAndy Ritger     portMemFree(pParams);
420758b4ee8SAndy Ritger 
421758b4ee8SAndy Ritger     return status;
422758b4ee8SAndy Ritger }
423758b4ee8SAndy Ritger 
424758b4ee8SAndy Ritger /*
425758b4ee8SAndy Ritger  * Initialize P2060 for all GPUs in loop.
426758b4ee8SAndy Ritger  */
427758b4ee8SAndy Ritger NvBool
extdevInit_P2060(OBJGPU * pGpu,PDACEXTERNALDEVICE pExternalDevice)428758b4ee8SAndy Ritger extdevInit_P2060
429758b4ee8SAndy Ritger (
430758b4ee8SAndy Ritger     OBJGPU  *pGpu,
431758b4ee8SAndy Ritger     PDACEXTERNALDEVICE pExternalDevice
432758b4ee8SAndy Ritger )
433758b4ee8SAndy Ritger {
434758b4ee8SAndy Ritger     OBJGPU  *pGpuTemp;
435758b4ee8SAndy Ritger     OBJSYS  *pSys = SYS_GET_INSTANCE();
436758b4ee8SAndy Ritger     OBJGSYNC *pGsyncTemp = NULL;
437758b4ee8SAndy Ritger     NvU32 gpuAttachCnt, gpuAttachMask, gpuInstance;
438758b4ee8SAndy Ritger     NvU32 data;
439758b4ee8SAndy Ritger 
440758b4ee8SAndy Ritger     if (!GpuIsP2060Connected(pGpu, (PDACP2060EXTERNALDEVICE)pExternalDevice))
441758b4ee8SAndy Ritger     {
442758b4ee8SAndy Ritger         return NV_FALSE;
443758b4ee8SAndy Ritger     }
444758b4ee8SAndy Ritger 
445758b4ee8SAndy Ritger     if (NV_OK != gsyncProgramExtStereoPolarity_P2060(pGpu, pExternalDevice))
446758b4ee8SAndy Ritger     {
447758b4ee8SAndy Ritger         return NV_FALSE;
448758b4ee8SAndy Ritger     }
449758b4ee8SAndy Ritger 
450758b4ee8SAndy Ritger     // Check regkeys
451758b4ee8SAndy Ritger     if (NV_OK == osReadRegistryDword(pGpu, NV_REG_STR_RM_QSYNC_FW_REV_CHECK, &data))
452758b4ee8SAndy Ritger     {
453758b4ee8SAndy Ritger         if (NV_REG_STR_RM_QSYNC_FW_REV_CHECK_DISABLE == data)
454758b4ee8SAndy Ritger         {
455758b4ee8SAndy Ritger             pSys->setProperty(pSys, PDB_PROP_SYS_IS_QSYNC_FW_REVISION_CHECK_DISABLED, NV_TRUE);
456758b4ee8SAndy Ritger         }
457758b4ee8SAndy Ritger     }
458758b4ee8SAndy Ritger 
459758b4ee8SAndy Ritger     // Initialize SyncPolarity to FALLING_EDGE. Refer Bug 1035880
460758b4ee8SAndy Ritger     if (NV_OK != gsyncSetSyncPolarity_P2060(pGpu, pExternalDevice, gsync_SyncPolarity_FallingEdge))
461758b4ee8SAndy Ritger     {
462758b4ee8SAndy Ritger         return NV_FALSE;
463758b4ee8SAndy Ritger     }
464758b4ee8SAndy Ritger 
465758b4ee8SAndy Ritger     // get count of all other gpus in the system
466758b4ee8SAndy Ritger     gpumgrGetGpuAttachInfo(&gpuAttachCnt, &gpuAttachMask);
467758b4ee8SAndy Ritger 
468758b4ee8SAndy Ritger     // loop over
469758b4ee8SAndy Ritger     gpuInstance = 0;
470758b4ee8SAndy Ritger     while ((pGpuTemp = gpumgrGetNextGpu(gpuAttachMask, &gpuInstance)) != NULL)
471758b4ee8SAndy Ritger     {
472758b4ee8SAndy Ritger         pGsyncTemp = gsyncmgrGetGsync(pGpuTemp);
473758b4ee8SAndy Ritger 
474758b4ee8SAndy Ritger         if (!pGsyncTemp || !pGsyncTemp->pExtDev)
475758b4ee8SAndy Ritger             continue;
476758b4ee8SAndy Ritger 
477758b4ee8SAndy Ritger         _externalDeviceInit_P2060(pGpuTemp, (pGpu == pGpuTemp));
478758b4ee8SAndy Ritger     }
479758b4ee8SAndy Ritger 
480758b4ee8SAndy Ritger     return NV_TRUE;
481758b4ee8SAndy Ritger }
482758b4ee8SAndy Ritger 
483758b4ee8SAndy Ritger static NV_STATUS
gsyncReadBoardId_P2060(OBJGPU * pGpu,PDACEXTERNALDEVICE pExternalDevice,NvU32 * uniqueId)484758b4ee8SAndy Ritger gsyncReadBoardId_P2060
485758b4ee8SAndy Ritger (
486758b4ee8SAndy Ritger     OBJGPU             *pGpu,
487758b4ee8SAndy Ritger     PDACEXTERNALDEVICE  pExternalDevice,
488758b4ee8SAndy Ritger     NvU32              *uniqueId
489758b4ee8SAndy Ritger )
490758b4ee8SAndy Ritger {
491758b4ee8SAndy Ritger     NvU8  i, id = 0;
492758b4ee8SAndy Ritger     NV_STATUS rmStatus = NV_OK;
493758b4ee8SAndy Ritger 
494758b4ee8SAndy Ritger     *uniqueId = 0;
495758b4ee8SAndy Ritger     for (i = 0; i < 4; i++)
496758b4ee8SAndy Ritger     {
497758b4ee8SAndy Ritger         rmStatus = readregu008_extdeviceTargeted(pGpu, pExternalDevice,
498758b4ee8SAndy Ritger                                   NV_P2060_FPGA_ASGN_ID(i), &id);
499758b4ee8SAndy Ritger         if (rmStatus != NV_OK)
500758b4ee8SAndy Ritger         {
501758b4ee8SAndy Ritger             return rmStatus;
502758b4ee8SAndy Ritger         }
503758b4ee8SAndy Ritger         *uniqueId |= id << (i * 8);
504758b4ee8SAndy Ritger     }
505758b4ee8SAndy Ritger     return NV_OK;
506758b4ee8SAndy Ritger }
507758b4ee8SAndy Ritger 
508758b4ee8SAndy Ritger /*
509758b4ee8SAndy Ritger  * Attach P2060 to GPU on correct connector index.
510758b4ee8SAndy Ritger  */
511758b4ee8SAndy Ritger NvBool
gsyncAttachExternalDevice_P2060(OBJGPU * pGpu,PDACEXTERNALDEVICE * ppExtdevs)512758b4ee8SAndy Ritger gsyncAttachExternalDevice_P2060
513758b4ee8SAndy Ritger (
514758b4ee8SAndy Ritger     OBJGPU             *pGpu,
515758b4ee8SAndy Ritger     PDACEXTERNALDEVICE *ppExtdevs
516758b4ee8SAndy Ritger )
517758b4ee8SAndy Ritger {
518758b4ee8SAndy Ritger     OBJSYS *pSys = SYS_GET_INSTANCE();
519758b4ee8SAndy Ritger     OBJGSYNCMGR *pGsyncMgr = SYS_GET_GSYNCMGR(pSys);
520758b4ee8SAndy Ritger     OBJGSYNC *pGsync = NULL;
521758b4ee8SAndy Ritger     OBJGPU   *pOtherGpu = NULL;
522758b4ee8SAndy Ritger     DACP2060EXTERNALDEVICE *pThis, *pExt2060Temp;
523758b4ee8SAndy Ritger     NvU8  i, id = 0, regCtrl2 = 0;
524758b4ee8SAndy Ritger     NvU32 iface, connector, uniqueId = 0, pOtherGpuId = 0, bSkipResetForVM = 0, index = 0;
525758b4ee8SAndy Ritger     NvU32 tempIface;
526758b4ee8SAndy Ritger     NvBool bExtDevFound = NV_FALSE;
527758b4ee8SAndy Ritger     NV_STATUS rmStatus = NV_OK;
528758b4ee8SAndy Ritger     NvU8 ctrl = 0;
529758b4ee8SAndy Ritger 
530758b4ee8SAndy Ritger     rmStatus = gsyncReadBoardId_P2060(pGpu, *ppExtdevs, &uniqueId);
531758b4ee8SAndy Ritger     if (rmStatus != NV_OK)
532758b4ee8SAndy Ritger     {
533758b4ee8SAndy Ritger         NV_PRINTF(LEVEL_ERROR, "failed to read P2060 device Id.\n");
534758b4ee8SAndy Ritger         return NV_FALSE;
535758b4ee8SAndy Ritger     }
536758b4ee8SAndy Ritger 
537758b4ee8SAndy Ritger     if (uniqueId != 0x0)
538758b4ee8SAndy Ritger     {
539758b4ee8SAndy Ritger         // HW says another GPU has been here first. Confirm this from SW.
540758b4ee8SAndy Ritger         for (i = 0; i < NV30F1_MAX_GSYNCS; i++)
541758b4ee8SAndy Ritger         {
542758b4ee8SAndy Ritger             if (pGsyncMgr->gsyncTable[i].gpuCount)
543758b4ee8SAndy Ritger             {
544758b4ee8SAndy Ritger                 pGsync = &pGsyncMgr->gsyncTable[i];
545758b4ee8SAndy Ritger                 if (pGsync->pExtDev)
546758b4ee8SAndy Ritger                 {
547758b4ee8SAndy Ritger                     pThis  = (PDACP2060EXTERNALDEVICE) pGsync->pExtDev;
548758b4ee8SAndy Ritger                     if (pThis->id == uniqueId)
549758b4ee8SAndy Ritger                     {
550758b4ee8SAndy Ritger                         pOtherGpuId = pGsync->gpus[0].gpuId;
551758b4ee8SAndy Ritger                         bExtDevFound = NV_TRUE;
552758b4ee8SAndy Ritger                     }
553758b4ee8SAndy Ritger                 }
554758b4ee8SAndy Ritger             }
555758b4ee8SAndy Ritger 
556758b4ee8SAndy Ritger             if (bExtDevFound)
557758b4ee8SAndy Ritger             {
558758b4ee8SAndy Ritger                 break;
559758b4ee8SAndy Ritger             }
560758b4ee8SAndy Ritger         }
561758b4ee8SAndy Ritger 
562758b4ee8SAndy Ritger         if (!bExtDevFound)
563758b4ee8SAndy Ritger         {
564758b4ee8SAndy Ritger             if ((IS_PASSTHRU(pGpu)))
565758b4ee8SAndy Ritger             {
566758b4ee8SAndy Ritger                 // look for master board
567758b4ee8SAndy Ritger                 rmStatus = readregu008_extdeviceTargeted(pGpu, *ppExtdevs,
568758b4ee8SAndy Ritger                                                             (NvU8)NV_P2060_CONTROL, &ctrl);
569758b4ee8SAndy Ritger                 if (rmStatus != NV_OK)
570758b4ee8SAndy Ritger                 {
571758b4ee8SAndy Ritger                     NV_PRINTF(LEVEL_ERROR, "Failed to read Ctrl data.\n");
572758b4ee8SAndy Ritger                     return NV_FALSE;
573758b4ee8SAndy Ritger                 }
574758b4ee8SAndy Ritger 
575758b4ee8SAndy Ritger                 pThis = (PDACP2060EXTERNALDEVICE)*ppExtdevs;
576758b4ee8SAndy Ritger                 bSkipResetForVM = FLD_TEST_DRF(_P2060, _CONTROL, _I_AM, _MASTER, (NvU32)ctrl);
577758b4ee8SAndy Ritger                 rmStatus = GetP2060ConnectorIndexFromGpu(pGpu, pThis, &index);
578758b4ee8SAndy Ritger 
579758b4ee8SAndy Ritger                 if (rmStatus != NV_OK)
580758b4ee8SAndy Ritger                 {
581758b4ee8SAndy Ritger                     NV_PRINTF(LEVEL_ERROR, "Failed to get connector index for Gpu.\n");
582758b4ee8SAndy Ritger                     return NV_FALSE;
583758b4ee8SAndy Ritger                 }
584758b4ee8SAndy Ritger 
585758b4ee8SAndy Ritger                 // Look for SYNC source gpu.
586758b4ee8SAndy Ritger                 bSkipResetForVM = bSkipResetForVM && !(DRF_VAL(_P2060, _CONTROL, _SYNC_SRC, (NvU32)ctrl) == index);
587758b4ee8SAndy Ritger             }
588758b4ee8SAndy Ritger 
589758b4ee8SAndy Ritger             if (!bSkipResetForVM)
590758b4ee8SAndy Ritger             {
591758b4ee8SAndy Ritger                 // ExtDev is not preset in pGsyncMgr. Issue RESET to P2060 HW.
592758b4ee8SAndy Ritger                 regCtrl2 = FLD_SET_DRF_NUM(_P2060, _CONTROL2, _RESET, NV_TRUE, regCtrl2);
593758b4ee8SAndy Ritger                 writeregu008_extdeviceTargeted(pGpu, *ppExtdevs,
594758b4ee8SAndy Ritger                     NV_P2060_CONTROL2, regCtrl2);
595758b4ee8SAndy Ritger 
596758b4ee8SAndy Ritger                 osDelay(5); // Add delay of 5ms before I2C read as board is in reset phase.
597758b4ee8SAndy Ritger 
598758b4ee8SAndy Ritger                 rmStatus = gsyncReadBoardId_P2060(pGpu, *ppExtdevs, &uniqueId);
599758b4ee8SAndy Ritger                 if ((rmStatus != NV_OK) || (uniqueId != 0))
600758b4ee8SAndy Ritger                 {
601758b4ee8SAndy Ritger                     NV_PRINTF(LEVEL_ERROR,
602758b4ee8SAndy Ritger                         "failed to read P2060 device Id after reset.\n");
603758b4ee8SAndy Ritger                     return NV_FALSE;
604758b4ee8SAndy Ritger                 }
605758b4ee8SAndy Ritger             }
606758b4ee8SAndy Ritger         }
607758b4ee8SAndy Ritger         else
608758b4ee8SAndy Ritger         {
609758b4ee8SAndy Ritger             pOtherGpu = gpumgrGetGpuFromId(pOtherGpuId);
610758b4ee8SAndy Ritger             pGsync    = gsyncmgrGetGsync(pOtherGpu);
611758b4ee8SAndy Ritger 
612758b4ee8SAndy Ritger             if (!pGsync || !pGsync->pExtDev)
613758b4ee8SAndy Ritger             {
614758b4ee8SAndy Ritger                 NV_ASSERT(0);
615758b4ee8SAndy Ritger                 return NV_FALSE;
616758b4ee8SAndy Ritger             }
617758b4ee8SAndy Ritger 
618758b4ee8SAndy Ritger             NV_ASSERT(pGsync->pExtDev != *ppExtdevs);
619758b4ee8SAndy Ritger 
620758b4ee8SAndy Ritger             pThis = (PDACP2060EXTERNALDEVICE)*ppExtdevs;
621758b4ee8SAndy Ritger             pExt2060Temp = (PDACP2060EXTERNALDEVICE)(pGsync->pExtDev);
622758b4ee8SAndy Ritger 
623758b4ee8SAndy Ritger             rmStatus = gsyncFindFreeHandleLocation(pExt2060Temp, &iface);
624758b4ee8SAndy Ritger             if (rmStatus != NV_OK)
625758b4ee8SAndy Ritger             {
626758b4ee8SAndy Ritger                 NV_PRINTF(LEVEL_ERROR, "Failed to free index for new GPU entry. \n");
627758b4ee8SAndy Ritger                 return NV_FALSE;
628758b4ee8SAndy Ritger             }
629758b4ee8SAndy Ritger 
630758b4ee8SAndy Ritger             rmStatus = gsyncFindGpuHandleLocation(*ppExtdevs, pGpu->gpuId, &tempIface);
631758b4ee8SAndy Ritger             if (rmStatus != NV_OK)
632758b4ee8SAndy Ritger             {
633758b4ee8SAndy Ritger                 NV_PRINTF(LEVEL_ERROR, "Couldn't find saved GPU entry, check extdevSaveI2cHandles. \n");
634758b4ee8SAndy Ritger                 return NV_FALSE;
635758b4ee8SAndy Ritger             }
636758b4ee8SAndy Ritger 
637758b4ee8SAndy Ritger             pExt2060Temp->i2cHandles[iface].gpuId         = pThis->i2cHandles[tempIface].gpuId;
638758b4ee8SAndy Ritger             pExt2060Temp->i2cHandles[iface].hClient       = pThis->i2cHandles[tempIface].hClient;
639758b4ee8SAndy Ritger             pExt2060Temp->i2cHandles[iface].hDevice       = pThis->i2cHandles[tempIface].hDevice;
640758b4ee8SAndy Ritger             pExt2060Temp->i2cHandles[iface].hSubdevice    = pThis->i2cHandles[tempIface].hSubdevice;
641758b4ee8SAndy Ritger             pExt2060Temp->i2cHandles[iface].hSubscription = pThis->i2cHandles[tempIface].hSubscription;
642758b4ee8SAndy Ritger 
643758b4ee8SAndy Ritger             pThis->ExternalDevice.pI->Destroy(pGpu, *ppExtdevs);
644758b4ee8SAndy Ritger 
645758b4ee8SAndy Ritger             // Free our current pointer and replace it
646758b4ee8SAndy Ritger             portMemFree(*ppExtdevs);
647758b4ee8SAndy Ritger             *ppExtdevs = pGsync->pExtDev;
648758b4ee8SAndy Ritger         }
649758b4ee8SAndy Ritger     }
650758b4ee8SAndy Ritger 
651758b4ee8SAndy Ritger     pThis = (PDACP2060EXTERNALDEVICE)*ppExtdevs;
652758b4ee8SAndy Ritger 
653758b4ee8SAndy Ritger     if (uniqueId == 0x0)
654758b4ee8SAndy Ritger     {
655758b4ee8SAndy Ritger         // Use pGpu->gpuId as unique value.
656758b4ee8SAndy Ritger         uniqueId = pGpu->gpuId;
657758b4ee8SAndy Ritger 
658758b4ee8SAndy Ritger         for (i = 0; i < 4; i++)
659758b4ee8SAndy Ritger         {
660758b4ee8SAndy Ritger             id = (NvU8)(uniqueId >> (i * 8));
661758b4ee8SAndy Ritger             rmStatus = writeregu008_extdeviceTargeted(pGpu, *ppExtdevs,
662758b4ee8SAndy Ritger                                                       NV_P2060_FPGA_ASGN_ID(i),
663758b4ee8SAndy Ritger                                                       id);
664758b4ee8SAndy Ritger             if (rmStatus != NV_OK)
665758b4ee8SAndy Ritger             {
666758b4ee8SAndy Ritger                 NV_PRINTF(LEVEL_ERROR, "failed to update P2060 device Id.\n");
667758b4ee8SAndy Ritger                 return NV_FALSE;
668758b4ee8SAndy Ritger             }
669758b4ee8SAndy Ritger         }
670758b4ee8SAndy Ritger         pThis->id = uniqueId;
671758b4ee8SAndy Ritger     }
672758b4ee8SAndy Ritger 
673758b4ee8SAndy Ritger     rmStatus = GetP2060ConnectorIndexFromGpu(pGpu, pThis, &iface);
674758b4ee8SAndy Ritger     if (rmStatus != NV_OK)
675758b4ee8SAndy Ritger     {
676758b4ee8SAndy Ritger         NV_PRINTF(LEVEL_ERROR, "failed to find P2060 connector.\n");
677758b4ee8SAndy Ritger         return NV_FALSE;
678758b4ee8SAndy Ritger     }
679758b4ee8SAndy Ritger 
680758b4ee8SAndy Ritger     //
681758b4ee8SAndy Ritger     // Add 1 to index we got from status2 register read beacuse connector
682758b4ee8SAndy Ritger     // NV30F1_CTRL_GET_GSYNC_GPU_TOPOLOGY_ONE start with value 1.
683758b4ee8SAndy Ritger     //
684758b4ee8SAndy Ritger     connector = iface + 1;
685758b4ee8SAndy Ritger 
686758b4ee8SAndy Ritger     //
687758b4ee8SAndy Ritger     // If adding a check before the gsyncAttachGpu call and returning before
688758b4ee8SAndy Ritger     // that please add the following code:
689758b4ee8SAndy Ritger     // pThis->gpuAttachMask &= ~NVBIT(pGpu->gpuInstance);
690758b4ee8SAndy Ritger     //    (*ppExtdevs)->ReferenceCount--;
691758b4ee8SAndy Ritger     // before returning NV_FALSE so that the caller can destroy the
692758b4ee8SAndy Ritger     // ext device structure. The destroy funciton only decrements the ref count
693758b4ee8SAndy Ritger     // if the gpu has already been attached.
694758b4ee8SAndy Ritger     //
695758b4ee8SAndy Ritger     (*ppExtdevs)->ReferenceCount++;
696758b4ee8SAndy Ritger     pThis->gpuAttachMask |= NVBIT(pGpu->gpuInstance);
697758b4ee8SAndy Ritger 
698758b4ee8SAndy Ritger     pThis->Iface[iface].GpuInfo.gpuId = pGpu->gpuId;
699758b4ee8SAndy Ritger     pThis->Iface[iface].GpuInfo.connected = NV_TRUE;
700758b4ee8SAndy Ritger 
701758b4ee8SAndy Ritger     rmStatus = gsyncAttachGpu(*ppExtdevs, pGpu, connector, NULL, (*ppExtdevs)->deviceId);
702758b4ee8SAndy Ritger 
703758b4ee8SAndy Ritger     if (rmStatus != NV_OK)
704758b4ee8SAndy Ritger     {
705758b4ee8SAndy Ritger         NV_PRINTF(LEVEL_ERROR, "failed to attach P2060 gsync to gpu.\n");
706758b4ee8SAndy Ritger         return NV_FALSE;
707758b4ee8SAndy Ritger     }
708758b4ee8SAndy Ritger 
709758b4ee8SAndy Ritger     if (pThis->ExternalDevice.deviceId == DAC_EXTERNAL_DEVICE_P2061)
710758b4ee8SAndy Ritger     {
711758b4ee8SAndy Ritger         pGpu->setProperty(pGpu, PDB_PROP_GPU_QSYNC_II_ATTACHED, NV_TRUE);
712758b4ee8SAndy Ritger     }
713758b4ee8SAndy Ritger     else
714758b4ee8SAndy Ritger     {
715758b4ee8SAndy Ritger         NV_ASSERT(pThis->ExternalDevice.deviceId == DAC_EXTERNAL_DEVICE_P2060);
716758b4ee8SAndy Ritger         pGpu->setProperty(pGpu, PDB_PROP_GPU_GSYNC_III_ATTACHED, NV_TRUE);
717758b4ee8SAndy Ritger     }
718758b4ee8SAndy Ritger 
719758b4ee8SAndy Ritger     if (!pThis->isNonFramelockInterruptEnabled)
720758b4ee8SAndy Ritger     {
721758b4ee8SAndy Ritger         rmStatus = gsyncEnableNonFramelockInterrupt_P2060(pGpu, *ppExtdevs);
722758b4ee8SAndy Ritger         if (rmStatus != NV_OK)
723758b4ee8SAndy Ritger         {
724758b4ee8SAndy Ritger             NV_PRINTF(LEVEL_ERROR,
725758b4ee8SAndy Ritger                       "Failed to enable non-framelock interrupts on gsync GPU.\n");
726758b4ee8SAndy Ritger             return NV_FALSE;
727758b4ee8SAndy Ritger         }
728758b4ee8SAndy Ritger         pThis->isNonFramelockInterruptEnabled = NV_TRUE;
729758b4ee8SAndy Ritger         pThis->interruptEnabledInterface = iface;
730758b4ee8SAndy Ritger     }
731758b4ee8SAndy Ritger 
732758b4ee8SAndy Ritger     return NV_TRUE;
733758b4ee8SAndy Ritger }
734758b4ee8SAndy Ritger 
735758b4ee8SAndy Ritger /*
736758b4ee8SAndy Ritger  * Destroy the device P2060.
737758b4ee8SAndy Ritger  */
738758b4ee8SAndy Ritger void
extdevDestroy_P2060(OBJGPU * pGpu,PDACEXTERNALDEVICE pExternalDevice)739758b4ee8SAndy Ritger extdevDestroy_P2060
740758b4ee8SAndy Ritger (
741758b4ee8SAndy Ritger     OBJGPU *pGpu,
742758b4ee8SAndy Ritger     PDACEXTERNALDEVICE pExternalDevice
743758b4ee8SAndy Ritger )
744758b4ee8SAndy Ritger {
745758b4ee8SAndy Ritger     DACP2060EXTERNALDEVICE *pThis = (PDACP2060EXTERNALDEVICE)pExternalDevice;
746758b4ee8SAndy Ritger     RM_API   *pRmApi = rmapiGetInterface(RMAPI_GPU_LOCK_INTERNAL);
747758b4ee8SAndy Ritger     KernelDisplay *pKernelDisplay = GPU_GET_KERNEL_DISPLAY(pGpu);
748758b4ee8SAndy Ritger     NvU32 iface, head;
749758b4ee8SAndy Ritger     NvU32 numHeads = kdispGetNumHeads(pKernelDisplay);
750758b4ee8SAndy Ritger     NvU8 ctrl2 = 0;
751758b4ee8SAndy Ritger     NV_STATUS rmStatus;
752758b4ee8SAndy Ritger 
753758b4ee8SAndy Ritger     for (iface = 0; iface < NV_P2060_MAX_IFACES_PER_GSYNC; iface++)
754758b4ee8SAndy Ritger     {
755758b4ee8SAndy Ritger         if (pThis->Iface[iface].GpuInfo.gpuId == pGpu->gpuId)
756758b4ee8SAndy Ritger         {
757758b4ee8SAndy Ritger             pThis->gpuAttachMask &= ~NVBIT(pGpu->gpuInstance);
758758b4ee8SAndy Ritger             pExternalDevice->ReferenceCount--;
759758b4ee8SAndy Ritger 
760758b4ee8SAndy Ritger             if (pThis->Iface[iface].GpuInfo.connected)
761758b4ee8SAndy Ritger             {
762758b4ee8SAndy Ritger                 if (pExternalDevice->ReferenceCount == 0)
763758b4ee8SAndy Ritger                 {
764758b4ee8SAndy Ritger                     // clear id for this gsync device.
765758b4ee8SAndy Ritger                     pThis->id = 0;
766758b4ee8SAndy Ritger 
767758b4ee8SAndy Ritger                     // reset the gsync hw
768758b4ee8SAndy Ritger                     ctrl2 = FLD_SET_DRF_NUM(_P2060, _CONTROL2, _RESET, NV_TRUE, ctrl2);
769758b4ee8SAndy Ritger                     writeregu008_extdeviceTargeted(pGpu, pExternalDevice,
770758b4ee8SAndy Ritger                                                    NV_P2060_CONTROL2, ctrl2);
771758b4ee8SAndy Ritger                 }
772758b4ee8SAndy Ritger             }
773758b4ee8SAndy Ritger 
774758b4ee8SAndy Ritger             // Restore saved swap lockout window values that may not have
775758b4ee8SAndy Ritger             // been restored by disabling swap barriers.
776758b4ee8SAndy Ritger             if (pThis->Iface[iface].DsiFliplock.saved == NV_TRUE)
777758b4ee8SAndy Ritger             {
778758b4ee8SAndy Ritger                 for (head = 0; head < numHeads; head++)
779758b4ee8SAndy Ritger                 {
780758b4ee8SAndy Ritger                     kdispRestoreOriginalLsrMinTime_HAL(pGpu, pKernelDisplay, head,
781758b4ee8SAndy Ritger                     pThis->Iface[iface].DsiFliplock.OrigLsrMinTime[head]);
782758b4ee8SAndy Ritger                 }
783758b4ee8SAndy Ritger                 pThis->Iface[iface].DsiFliplock.saved = NV_FALSE;
784758b4ee8SAndy Ritger             }
785758b4ee8SAndy Ritger 
786758b4ee8SAndy Ritger             gsyncRemoveGpu(pGpu);
787758b4ee8SAndy Ritger 
788758b4ee8SAndy Ritger             pThis->Iface[iface].GpuInfo.gpuId = NV0000_CTRL_GPU_INVALID_ID;
789758b4ee8SAndy Ritger             pThis->Iface[iface].GpuInfo.connected = NV_FALSE;
790758b4ee8SAndy Ritger 
791758b4ee8SAndy Ritger             pGpu->setProperty(pGpu, PDB_PROP_GPU_GSYNC_III_ATTACHED, NV_FALSE);
792758b4ee8SAndy Ritger             pGpu->setProperty(pGpu, PDB_PROP_GPU_QSYNC_II_ATTACHED, NV_FALSE);
793758b4ee8SAndy Ritger 
794758b4ee8SAndy Ritger             rmStatus = gsyncFindGpuHandleLocation(pExternalDevice, pGpu->gpuId, &iface);
795758b4ee8SAndy Ritger             if (rmStatus != NV_OK)
796758b4ee8SAndy Ritger             {
797758b4ee8SAndy Ritger                 NV_PRINTF(LEVEL_ERROR, "Couldn't find saved GPU entry, check saved i2chandles. \n");
798758b4ee8SAndy Ritger                 goto cleanup;
799758b4ee8SAndy Ritger             }
800758b4ee8SAndy Ritger 
801758b4ee8SAndy Ritger             rmapiutilFreeClientAndDeviceHandles(pRmApi,
802758b4ee8SAndy Ritger                                                 &pThis->i2cHandles[iface].hClient,
803758b4ee8SAndy Ritger                                                 &pThis->i2cHandles[iface].hDevice,
804758b4ee8SAndy Ritger                                                 &pThis->i2cHandles[iface].hSubdevice);
805758b4ee8SAndy Ritger 
806758b4ee8SAndy Ritger             pThis->i2cHandles[iface].hClient   = 0;
807758b4ee8SAndy Ritger             pThis->i2cHandles[iface].hDevice   = 0;
808758b4ee8SAndy Ritger             pThis->i2cHandles[iface].hSubdevice    = 0;
809758b4ee8SAndy Ritger             pThis->i2cHandles[iface].hSubscription = 0;
810758b4ee8SAndy Ritger             pThis->i2cHandles[iface].gpuId   = 0;
811758b4ee8SAndy Ritger 
812758b4ee8SAndy Ritger             break;
813758b4ee8SAndy Ritger         }
814758b4ee8SAndy Ritger     }
815758b4ee8SAndy Ritger 
816758b4ee8SAndy Ritger cleanup:
817758b4ee8SAndy Ritger     if (pExternalDevice->ReferenceCount == 0)
818758b4ee8SAndy Ritger     {
819758b4ee8SAndy Ritger        // And continue the chain running.
820758b4ee8SAndy Ritger        extdevDestroy_Base(pGpu, pExternalDevice);
821758b4ee8SAndy Ritger     }
822758b4ee8SAndy Ritger }
823758b4ee8SAndy Ritger 
824758b4ee8SAndy Ritger /*
825758b4ee8SAndy Ritger  * Handles the loss/gain of sync and other interrupts.
826758b4ee8SAndy Ritger  */
827758b4ee8SAndy Ritger void
extdevService_P2060(OBJGPU * pGpu,PDACEXTERNALDEVICE pExtDev,NvU8 lossRegStatus,NvU8 gainRegStatus,NvU8 miscRegStatus,NvBool rmStatus)828758b4ee8SAndy Ritger extdevService_P2060
829758b4ee8SAndy Ritger (
830758b4ee8SAndy Ritger     OBJGPU            *pGpu,
831758b4ee8SAndy Ritger     PDACEXTERNALDEVICE pExtDev,
832758b4ee8SAndy Ritger     NvU8               lossRegStatus,
833758b4ee8SAndy Ritger     NvU8               gainRegStatus,
834758b4ee8SAndy Ritger     NvU8               miscRegStatus,
835758b4ee8SAndy Ritger     NvBool             rmStatus
836758b4ee8SAndy Ritger )
837758b4ee8SAndy Ritger {
838758b4ee8SAndy Ritger     EXTDEV_INTR_DATA intrData;
839758b4ee8SAndy Ritger 
840758b4ee8SAndy Ritger     if (!rmStatus)
841758b4ee8SAndy Ritger     {
842758b4ee8SAndy Ritger         return;
843758b4ee8SAndy Ritger     }
844758b4ee8SAndy Ritger 
845758b4ee8SAndy Ritger     intrData.lossRegStatus = lossRegStatus;
846758b4ee8SAndy Ritger     intrData.gainRegStatus = gainRegStatus;
847758b4ee8SAndy Ritger     intrData.miscRegStatus = miscRegStatus;
848758b4ee8SAndy Ritger     intrData.pExtDevice    = pExtDev;
849758b4ee8SAndy Ritger 
850758b4ee8SAndy Ritger     if (IS_GSP_CLIENT(pGpu))
851758b4ee8SAndy Ritger     {
852758b4ee8SAndy Ritger         EXTDEV_INTR_DATA *workerThreadData = NULL;
853758b4ee8SAndy Ritger 
854758b4ee8SAndy Ritger         workerThreadData = portMemAllocNonPaged(sizeof(EXTDEV_INTR_DATA));
855758b4ee8SAndy Ritger         if (NULL != workerThreadData)
856758b4ee8SAndy Ritger         {
857758b4ee8SAndy Ritger             *workerThreadData = intrData;
858758b4ee8SAndy Ritger         }
859758b4ee8SAndy Ritger         else
860758b4ee8SAndy Ritger         {
861758b4ee8SAndy Ritger             NV_PRINTF(LEVEL_ERROR, "Memalloc failed\n");
862758b4ee8SAndy Ritger         }
863758b4ee8SAndy Ritger 
864758b4ee8SAndy Ritger         // Attempt to queue a work item.
865b5bf85a8SAndy Ritger         if (NV_OK != osQueueWorkItemWithFlags(pGpu,
866758b4ee8SAndy Ritger                                               _extdevService,
867758b4ee8SAndy Ritger                                               (void *)workerThreadData,
868758b4ee8SAndy Ritger                                               OS_QUEUE_WORKITEM_FLAGS_LOCK_GPU_GROUP_SUBDEVICE_RW))
869758b4ee8SAndy Ritger         {
870758b4ee8SAndy Ritger             portMemFree((void *)workerThreadData);
871758b4ee8SAndy Ritger         }
872758b4ee8SAndy Ritger     }
873758b4ee8SAndy Ritger     else
874758b4ee8SAndy Ritger     {
875758b4ee8SAndy Ritger         _extdevService(gpuGetInstance(pGpu), (void *)&intrData);
876758b4ee8SAndy Ritger     }
877758b4ee8SAndy Ritger }
878758b4ee8SAndy Ritger 
879758b4ee8SAndy Ritger static void
_extdevService(NvU32 gpuInstance,void * workerThreadData)880758b4ee8SAndy Ritger _extdevService
881758b4ee8SAndy Ritger (
882758b4ee8SAndy Ritger     NvU32 gpuInstance,
883758b4ee8SAndy Ritger     void *workerThreadData
884758b4ee8SAndy Ritger )
885758b4ee8SAndy Ritger {
886758b4ee8SAndy Ritger     OBJGPU *pGpu = gpumgrGetGpu(gpuInstance);
887758b4ee8SAndy Ritger     NV_STATUS rmStatus;
888758b4ee8SAndy Ritger 
889758b4ee8SAndy Ritger     EXTDEV_INTR_DATA intrData = *(EXTDEV_INTR_DATA *)workerThreadData;
890758b4ee8SAndy Ritger     PDACP2060EXTERNALDEVICE pThis = (PDACP2060EXTERNALDEVICE)intrData.pExtDevice;
891758b4ee8SAndy Ritger     NvU32 iface, ifaceEvents[NV_P2060_MAX_IFACES_PER_GSYNC];
892758b4ee8SAndy Ritger 
893758b4ee8SAndy Ritger     rmStatus = gsyncUpdateGsyncStatusSnapshot_P2060(pGpu, intrData.pExtDevice);
894758b4ee8SAndy Ritger     if (rmStatus != NV_OK)
895758b4ee8SAndy Ritger     {
896758b4ee8SAndy Ritger         NV_PRINTF(LEVEL_ERROR,
897758b4ee8SAndy Ritger                   "Couldn't raad the register status physical RMs.\n");
898758b4ee8SAndy Ritger         return;
899758b4ee8SAndy Ritger     }
900758b4ee8SAndy Ritger     rmStatus = GetP2060GpuLocation(pGpu, pThis, &iface);
901758b4ee8SAndy Ritger     if (rmStatus != NV_OK)
902758b4ee8SAndy Ritger     {
903758b4ee8SAndy Ritger         NV_PRINTF(LEVEL_ERROR,
904758b4ee8SAndy Ritger                   "Cannot get P2060 Gpu location for serving interrupt.\n");
905758b4ee8SAndy Ritger         return;
906758b4ee8SAndy Ritger     }
907758b4ee8SAndy Ritger 
908758b4ee8SAndy Ritger     ifaceEvents[iface] = 0x00;
909758b4ee8SAndy Ritger 
910758b4ee8SAndy Ritger     if (intrData.lossRegStatus) //lost signal interrupts
911758b4ee8SAndy Ritger     {
912758b4ee8SAndy Ritger         if (DRF_VAL(_P2060, _STATUS4, _SYNC, (NvU32)intrData.lossRegStatus))
913758b4ee8SAndy Ritger         {
914758b4ee8SAndy Ritger             ifaceEvents[iface] |= NVBIT(NV30F1_GSYNC_NOTIFIERS_SYNC_LOSS(iface));
915758b4ee8SAndy Ritger         }
916758b4ee8SAndy Ritger         if (DRF_VAL(_P2060, _STATUS4, _STEREO, (NvU32)intrData.lossRegStatus))
917758b4ee8SAndy Ritger         {
918758b4ee8SAndy Ritger             ifaceEvents[iface] |= NVBIT(NV30F1_GSYNC_NOTIFIERS_STEREO_LOSS(iface));
919758b4ee8SAndy Ritger         }
920758b4ee8SAndy Ritger         if (DRF_VAL(_P2060, _STATUS4, _HS, (NvU32)intrData.lossRegStatus))
921758b4ee8SAndy Ritger         {
922758b4ee8SAndy Ritger             ifaceEvents[iface] |= NVBIT(NV30F1_GSYNC_NOTIFIERS_HOUSE_LOSS);
923758b4ee8SAndy Ritger         }
924758b4ee8SAndy Ritger         if (DRF_VAL(_P2060, _STATUS4, _RJ45, (NvU32)intrData.lossRegStatus))
925758b4ee8SAndy Ritger         {
926758b4ee8SAndy Ritger             ifaceEvents[iface] |= NVBIT(NV30F1_GSYNC_NOTIFIERS_RJ45_LOSS);
927758b4ee8SAndy Ritger         }
928758b4ee8SAndy Ritger 
929758b4ee8SAndy Ritger         //
930758b4ee8SAndy Ritger         // Enable the watchdog again if we got any loss events.
931758b4ee8SAndy Ritger         // Otherise sync gain tracking and stereo sync won't work as desired.
932758b4ee8SAndy Ritger         //
933758b4ee8SAndy Ritger         if (ifaceEvents[iface])
934758b4ee8SAndy Ritger         {
935758b4ee8SAndy Ritger             extdevScheduleWatchdog(pGpu, (PDACEXTERNALDEVICE)pThis);
936758b4ee8SAndy Ritger             if (!gsyncIsOnlyFrameLockMaster_P2060(pThis))
937758b4ee8SAndy Ritger             {
938758b4ee8SAndy Ritger                 pThis->watchdogCountDownValue = NV_P2060_WATCHDOG_COUNT_DOWN_VALUE;
939758b4ee8SAndy Ritger             }
940758b4ee8SAndy Ritger         }
941758b4ee8SAndy Ritger 
942758b4ee8SAndy Ritger         if (ifaceEvents[iface] && (pThis->Iface[iface].lastEventNotified != ifaceEvents[iface]))
943758b4ee8SAndy Ritger         {
944758b4ee8SAndy Ritger              gsyncSignalServiceRequested(gsyncGetGsyncInstance(pGpu), ifaceEvents[iface], iface);
945758b4ee8SAndy Ritger              pThis->Iface[iface].lastEventNotified = ifaceEvents[iface];
946758b4ee8SAndy Ritger         }
947758b4ee8SAndy Ritger     }
948758b4ee8SAndy Ritger 
949758b4ee8SAndy Ritger     if (intrData.gainRegStatus) //Gain signal interrupts
950758b4ee8SAndy Ritger     {
951758b4ee8SAndy Ritger         if (DRF_VAL(_P2060, _STATUS4, _SYNC, (NvU32)intrData.gainRegStatus))
952758b4ee8SAndy Ritger         {
953758b4ee8SAndy Ritger             ifaceEvents[iface] |= NVBIT(NV30F1_GSYNC_NOTIFIERS_SYNC_GAIN(iface));
954758b4ee8SAndy Ritger         }
955758b4ee8SAndy Ritger         if (DRF_VAL(_P2060, _STATUS4, _STEREO, (NvU32)intrData.gainRegStatus))
956758b4ee8SAndy Ritger         {
957758b4ee8SAndy Ritger             ifaceEvents[iface] |= NVBIT(NV30F1_GSYNC_NOTIFIERS_STEREO_GAIN(iface));
958758b4ee8SAndy Ritger         }
959758b4ee8SAndy Ritger         if (DRF_VAL(_P2060, _STATUS4, _HS, (NvU32)intrData.gainRegStatus))
960758b4ee8SAndy Ritger         {
961758b4ee8SAndy Ritger             ifaceEvents[iface] |= NVBIT(NV30F1_GSYNC_NOTIFIERS_HOUSE_GAIN);
962758b4ee8SAndy Ritger         }
963758b4ee8SAndy Ritger         if (DRF_VAL(_P2060, _STATUS4, _RJ45, (NvU32)intrData.gainRegStatus))
964758b4ee8SAndy Ritger         {
965758b4ee8SAndy Ritger             ifaceEvents[iface] |= NVBIT(NV30F1_GSYNC_NOTIFIERS_RJ45_GAIN);
966758b4ee8SAndy Ritger         }
967758b4ee8SAndy Ritger 
968758b4ee8SAndy Ritger         if (ifaceEvents[iface] && (pThis->Iface[iface].lastEventNotified != ifaceEvents[iface]))
969758b4ee8SAndy Ritger         {
970758b4ee8SAndy Ritger             gsyncSignalServiceRequested(gsyncGetGsyncInstance(pGpu), ifaceEvents[iface], iface);
971758b4ee8SAndy Ritger             pThis->Iface[iface].lastEventNotified = ifaceEvents[iface];
972758b4ee8SAndy Ritger         }
973758b4ee8SAndy Ritger     }
974758b4ee8SAndy Ritger 
975758b4ee8SAndy Ritger     if (intrData.miscRegStatus) //Other interrupts
976758b4ee8SAndy Ritger     {
977758b4ee8SAndy Ritger         if (FLD_TEST_DRF(_P2060, _STATUS4, _FRM_CNT_MATCH_INT, _PENDING, (NvU32)intrData.miscRegStatus))
978758b4ee8SAndy Ritger         {
979758b4ee8SAndy Ritger             //
980758b4ee8SAndy Ritger             // To enable frameCountTimerService callback to verify the cached difference 1 second
981758b4ee8SAndy Ritger             // after the test signal is received.
982758b4ee8SAndy Ritger             //
983758b4ee8SAndy Ritger             pThis->FrameCountData.bReCheck = 1;
984758b4ee8SAndy Ritger 
985758b4ee8SAndy Ritger             //
986758b4ee8SAndy Ritger             // Reset framecountData.Therefore whenever user queries after frame compare
987758b4ee8SAndy Ritger             // interrupt, gsync and gpu frame count register are read and difference is cached again.
988758b4ee8SAndy Ritger             //
989758b4ee8SAndy Ritger             // This will also disable frame compare match interrupt, which will be then enabled
990758b4ee8SAndy Ritger             // frame compare match interrupt in the next user query or in FrameCountTimerService.
991758b4ee8SAndy Ritger             // This is required to clear frmCmpInt bit of status1 register. A read to status1
992758b4ee8SAndy Ritger             // register should clear it, but it is possible that the read to status1 register by
993758b4ee8SAndy Ritger             // calling  gsyncUpdateGsyncStatusSnapshot_P2060() function above may happen in the same
994758b4ee8SAndy Ritger             // frame and this would result interrupt to come back again setting frmCmpint bit.
995758b4ee8SAndy Ritger             //
996758b4ee8SAndy Ritger             rmStatus |= gsyncResetFrameCountData_P2060(pGpu, pThis);
997758b4ee8SAndy Ritger 
998758b4ee8SAndy Ritger             if (rmStatus == NV_OK)
999758b4ee8SAndy Ritger             {
1000758b4ee8SAndy Ritger                 //
1001758b4ee8SAndy Ritger                 // Set enableFrmCmpMatchInt flag NV_TRUE and return. This indicates
1002758b4ee8SAndy Ritger                 // that the frame compare match interrupt for slave needs to be
1003758b4ee8SAndy Ritger                 // enabled, which is done in the next user query or in
1004758b4ee8SAndy Ritger                 // FrameCountTimerService callback.
1005758b4ee8SAndy Ritger                 //
1006758b4ee8SAndy Ritger                 pThis->FrameCountData.enableFrmCmpMatchIntSlave = NV_TRUE;
1007758b4ee8SAndy Ritger             }
1008758b4ee8SAndy Ritger         }
1009758b4ee8SAndy Ritger 
1010758b4ee8SAndy Ritger         if (FLD_TEST_DRF(_P2060, _STATUS4, _ERROR_INT, _PENDING, (NvU32)intrData.miscRegStatus))
1011758b4ee8SAndy Ritger         {
1012758b4ee8SAndy Ritger             // Some error condition observed. Update snapshot
1013758b4ee8SAndy Ritger             rmStatus  = gsyncUpdateGsyncStatusSnapshot_P2060(pGpu, intrData.pExtDevice);
1014758b4ee8SAndy Ritger             if (rmStatus != NV_OK)
1015758b4ee8SAndy Ritger             {
1016758b4ee8SAndy Ritger                 return;
1017758b4ee8SAndy Ritger             }
1018758b4ee8SAndy Ritger         }
1019758b4ee8SAndy Ritger     }
1020758b4ee8SAndy Ritger }
1021758b4ee8SAndy Ritger 
1022758b4ee8SAndy Ritger /*
1023758b4ee8SAndy Ritger  * waits for hardware to (re-)establish sync.
1024758b4ee8SAndy Ritger  * once sync obtains, the watchdog enables interrupt, de-sechedules
1025758b4ee8SAndy Ritger  * itself, and waits for an interrupt to go off before running again.
1026758b4ee8SAndy Ritger  */
1027758b4ee8SAndy Ritger NV_STATUS
extdevWatchdog_P2060(OBJGPU * pGpu,OBJTMR * pTmr,PDACEXTERNALDEVICE pExtDev)1028758b4ee8SAndy Ritger extdevWatchdog_P2060
1029758b4ee8SAndy Ritger (
1030758b4ee8SAndy Ritger     OBJGPU            *pGpu,
1031758b4ee8SAndy Ritger     OBJTMR            *pTmr,
1032758b4ee8SAndy Ritger     PDACEXTERNALDEVICE pExtDev
1033758b4ee8SAndy Ritger )
1034758b4ee8SAndy Ritger {
1035758b4ee8SAndy Ritger     KernelDisplay *pKernelDisplay = GPU_GET_KERNEL_DISPLAY(pGpu);
1036758b4ee8SAndy Ritger     PDACP2060EXTERNALDEVICE pThis = (PDACP2060EXTERNALDEVICE)pExtDev;
1037758b4ee8SAndy Ritger     NvU32 iface, head;
1038758b4ee8SAndy Ritger     NvBool bStereoLocked;
1039758b4ee8SAndy Ritger     NV_STATUS rmStatus = NV_OK;
1040758b4ee8SAndy Ritger     NvBool bStereoEnabled[NV_P2060_MAX_IFACES_PER_GSYNC];
1041758b4ee8SAndy Ritger     NvU32 numHeads = kdispGetNumHeads(pKernelDisplay);
1042758b4ee8SAndy Ritger 
1043758b4ee8SAndy Ritger     if (pThis->watchdogCountDownValue)
1044758b4ee8SAndy Ritger         pThis->watchdogCountDownValue--;
1045758b4ee8SAndy Ritger 
1046758b4ee8SAndy Ritger     // we now can trust our selection of GPU
1047758b4ee8SAndy Ritger     pGpu = GetP2060WatchdogGpu(pGpu, pThis);
1048758b4ee8SAndy Ritger     NV_ASSERT(pGpu);
1049758b4ee8SAndy Ritger 
1050758b4ee8SAndy Ritger     // schedule the next callback.  we can cancel, if it's not needed.
1051758b4ee8SAndy Ritger     extdevScheduleWatchdog(pGpu, (PDACEXTERNALDEVICE)pThis);
1052758b4ee8SAndy Ritger 
1053758b4ee8SAndy Ritger     rmStatus = gsyncUpdateGsyncStatusSnapshot_P2060(pGpu, pExtDev);
1054758b4ee8SAndy Ritger 
1055758b4ee8SAndy Ritger     if (!gsyncIsFrameLocked_P2060(pThis))
1056758b4ee8SAndy Ritger     {
1057758b4ee8SAndy Ritger         gsyncCancelWatchdog_P2060(pThis);
1058758b4ee8SAndy Ritger         rmStatus = gsyncDisableFrameLockInterrupt_P2060((PDACEXTERNALDEVICE)pThis);
1059758b4ee8SAndy Ritger         return rmStatus;
1060758b4ee8SAndy Ritger     }
1061758b4ee8SAndy Ritger 
1062758b4ee8SAndy Ritger     for (iface = 0; iface < NV_P2060_MAX_IFACES_PER_GSYNC; iface++)
1063758b4ee8SAndy Ritger     {
1064758b4ee8SAndy Ritger         OBJGPU *pTmpGpu = NULL;
1065758b4ee8SAndy Ritger         if (pThis->Iface[iface].GpuInfo.gpuId == NV0000_CTRL_GPU_INVALID_ID)
1066758b4ee8SAndy Ritger         {
1067758b4ee8SAndy Ritger             continue;
1068758b4ee8SAndy Ritger         }
1069758b4ee8SAndy Ritger         pTmpGpu = gpumgrGetGpuFromId(pThis->Iface[iface].GpuInfo.gpuId);
1070758b4ee8SAndy Ritger 
1071758b4ee8SAndy Ritger         NV_ASSERT(pTmpGpu);
1072758b4ee8SAndy Ritger 
1073758b4ee8SAndy Ritger         // figure out if stereo is enabled
1074758b4ee8SAndy Ritger         bStereoEnabled[iface] = gsyncIsStereoEnabled_p2060(pTmpGpu, pExtDev);
1075758b4ee8SAndy Ritger 
1076758b4ee8SAndy Ritger         // loop over the heads of the current gpu on this interface
1077758b4ee8SAndy Ritger         for ( head = 0; head < numHeads; head++ )
1078758b4ee8SAndy Ritger         {
1079758b4ee8SAndy Ritger             if (pThis->Iface[iface].Sync.Slaved[head] ||
1080758b4ee8SAndy Ritger                 pThis->Iface[iface].Sync.LocalSlave[head])
1081758b4ee8SAndy Ritger             {
1082758b4ee8SAndy Ritger                 bStereoLocked  = FLD_TEST_DRF(_P2060, _STATUS, _STEREO, _LOCK,
1083758b4ee8SAndy Ritger                                              (NvU32)pThis->Snapshot[iface].Status1);
1084758b4ee8SAndy Ritger 
1085758b4ee8SAndy Ritger                  // check for sync and locks, noting that all heads share the status
1086758b4ee8SAndy Ritger                  if ((pThis->Iface[iface].gainedSync) &&
1087758b4ee8SAndy Ritger                      (!bStereoEnabled[iface] || bStereoLocked))
1088758b4ee8SAndy Ritger                  {
1089758b4ee8SAndy Ritger                       break;
1090758b4ee8SAndy Ritger                  }
1091758b4ee8SAndy Ritger                  else
1092758b4ee8SAndy Ritger                  {
1093758b4ee8SAndy Ritger                      return NV_ERR_GENERIC; // hope things are better, on next watchdog run
1094758b4ee8SAndy Ritger                  }
1095758b4ee8SAndy Ritger             }
1096758b4ee8SAndy Ritger         }
1097758b4ee8SAndy Ritger     }
1098758b4ee8SAndy Ritger 
1099758b4ee8SAndy Ritger     if ( NV_OK == rmStatus && pKernelDisplay->bExtdevIntrSupported
1100758b4ee8SAndy Ritger          && !pThis->watchdogCountDownValue)
1101758b4ee8SAndy Ritger     {
1102758b4ee8SAndy Ritger         NV_PRINTF(LEVEL_INFO, "P2060[%d] extdevCancelWatchdog.\n", iface);
1103758b4ee8SAndy Ritger 
1104758b4ee8SAndy Ritger         // disable the watchdog,
1105758b4ee8SAndy Ritger         extdevCancelWatchdog(pGpu, (PDACEXTERNALDEVICE)pThis);
1106758b4ee8SAndy Ritger 
1107758b4ee8SAndy Ritger         // enable the framelock interrupt, if either Master or Slaves are desired
1108758b4ee8SAndy Ritger         gsyncEnableFramelockInterrupt_P2060((PDACEXTERNALDEVICE)pThis);
1109758b4ee8SAndy Ritger     }
1110758b4ee8SAndy Ritger 
1111758b4ee8SAndy Ritger     return NV_OK;
1112758b4ee8SAndy Ritger }
1113758b4ee8SAndy Ritger 
1114758b4ee8SAndy Ritger static NV_STATUS
gsyncApplyStereoPinAlwaysHiWar(OBJGPU * pGpu,PDACEXTERNALDEVICE pExtDev)1115758b4ee8SAndy Ritger gsyncApplyStereoPinAlwaysHiWar
1116758b4ee8SAndy Ritger (
11174397463eSAndy Ritger     OBJGPU            *pGpu,
1118758b4ee8SAndy Ritger     PDACEXTERNALDEVICE pExtDev
1119758b4ee8SAndy Ritger )
1120758b4ee8SAndy Ritger {
1121758b4ee8SAndy Ritger 
1122758b4ee8SAndy Ritger     return NV_OK;
1123758b4ee8SAndy Ritger 
1124758b4ee8SAndy Ritger }
1125758b4ee8SAndy Ritger 
1126758b4ee8SAndy Ritger static NV_STATUS
gsyncUnApplyStereoPinAlwaysHiWar(OBJGPU * pGpu)1127758b4ee8SAndy Ritger gsyncUnApplyStereoPinAlwaysHiWar
1128758b4ee8SAndy Ritger (
11294397463eSAndy Ritger     OBJGPU *pGpu
1130758b4ee8SAndy Ritger )
1131758b4ee8SAndy Ritger {
1132758b4ee8SAndy Ritger 
1133758b4ee8SAndy Ritger     return NV_OK;
1134758b4ee8SAndy Ritger 
1135758b4ee8SAndy Ritger }
1136758b4ee8SAndy Ritger 
1137758b4ee8SAndy Ritger //
1138758b4ee8SAndy Ritger // gsyncReadUniversalFrameCount_P2060()
1139758b4ee8SAndy Ritger //
1140758b4ee8SAndy Ritger // When user queries for the first time or after 10 seconds, Gsync and Gpu
1141758b4ee8SAndy Ritger // hardware framecount are read and then the difference between them is cached.
1142758b4ee8SAndy Ritger // For rest of the instances whenever user queries for frame count, gpu
1143758b4ee8SAndy Ritger // frame count is read, and software framecount is updated accordingly based
1144758b4ee8SAndy Ritger // on previous cached values.
1145758b4ee8SAndy Ritger //
1146758b4ee8SAndy Ritger static NV_STATUS
gsyncReadUniversalFrameCount_P2060(OBJGPU * pGpu,PDACEXTERNALDEVICE pExtDev,NvU32 * pFrameCount)1147758b4ee8SAndy Ritger gsyncReadUniversalFrameCount_P2060
1148758b4ee8SAndy Ritger (
1149758b4ee8SAndy Ritger     OBJGPU *pGpu,
1150758b4ee8SAndy Ritger     PDACEXTERNALDEVICE pExtDev,
1151758b4ee8SAndy Ritger     NvU32 *pFrameCount
1152758b4ee8SAndy Ritger )
1153758b4ee8SAndy Ritger {
1154758b4ee8SAndy Ritger     OBJGPU   *pTmpGpu = NULL;
1155758b4ee8SAndy Ritger     KernelDisplay *pKernelDisplay = NULL;
1156758b4ee8SAndy Ritger     PDACP2060EXTERNALDEVICE pThis = (PDACP2060EXTERNALDEVICE) pExtDev;
1157758b4ee8SAndy Ritger     NV_STATUS rmStatus = NV_OK;
1158758b4ee8SAndy Ritger     NvU32 lineCount;
1159758b4ee8SAndy Ritger     NvU32 frameCount;
1160758b4ee8SAndy Ritger     NvS32 calculatedDiff;
1161758b4ee8SAndy Ritger     NvU64 currentTime = 0;
1162758b4ee8SAndy Ritger     NvU64 queryTimeDiff;
1163758b4ee8SAndy Ritger     OBJTMR *pTmpTmr = NULL;
1164758b4ee8SAndy Ritger     OBJTMR *pTmr = GPU_GET_TIMER(pGpu);
1165758b4ee8SAndy Ritger 
1166758b4ee8SAndy Ritger     if (!(pThis->FrameCountData.iface == NV_P2060_MAX_IFACES_PER_GSYNC))
1167758b4ee8SAndy Ritger     {
1168758b4ee8SAndy Ritger         //
1169758b4ee8SAndy Ritger         // pThis->FrameCountData.iface exists.
1170758b4ee8SAndy Ritger         // Thus deriving pTmpGpu from it, and to maintain consistency reading the time from it.
1171758b4ee8SAndy Ritger         //
1172758b4ee8SAndy Ritger         pTmpGpu = gpumgrGetGpuFromId(pThis->Iface[pThis->FrameCountData.iface].GpuInfo.gpuId);
1173758b4ee8SAndy Ritger 
1174758b4ee8SAndy Ritger         if (pTmpGpu)
1175758b4ee8SAndy Ritger         {
1176758b4ee8SAndy Ritger             pTmpTmr = GPU_GET_TIMER(pTmpGpu);
1177758b4ee8SAndy Ritger             currentTime = tmrGetTime_HAL(pTmpGpu, pTmpTmr);
1178758b4ee8SAndy Ritger         }
1179758b4ee8SAndy Ritger     }
1180758b4ee8SAndy Ritger 
1181758b4ee8SAndy Ritger     if (currentTime == 0)
1182758b4ee8SAndy Ritger     {
1183758b4ee8SAndy Ritger         // pTmpGpu doesn't exists, so getting the time from pGpu.
1184758b4ee8SAndy Ritger         currentTime = tmrGetTime_HAL(pGpu, pTmr);
1185758b4ee8SAndy Ritger     }
1186758b4ee8SAndy Ritger 
1187758b4ee8SAndy Ritger     if (NV_P2060_STATUS_SYNC_LOSS_TRUE == DRF_VAL(_P2060, _STATUS, _SYNC_LOSS, GetP2060GpuSnapshot(pGpu,pThis)))
1188758b4ee8SAndy Ritger     {
1189758b4ee8SAndy Ritger         // don't increment the frame counter in case of sync loss
1190758b4ee8SAndy Ritger         *pFrameCount = pThis->FrameCountData.totalFrameCount;
1191758b4ee8SAndy Ritger         pThis->FrameCountData.lastFrameCounterQueryTime = currentTime;
1192758b4ee8SAndy Ritger 
1193758b4ee8SAndy Ritger         return NV_OK;
1194758b4ee8SAndy Ritger     }
1195758b4ee8SAndy Ritger 
1196758b4ee8SAndy Ritger     queryTimeDiff = currentTime - pThis->FrameCountData.lastFrameCounterQueryTime;
1197758b4ee8SAndy Ritger 
1198758b4ee8SAndy Ritger     //
1199758b4ee8SAndy Ritger     // If user queries for the first time or after 10 secs then read gsync and
1200758b4ee8SAndy Ritger     // gpu frame count registers and update software frame count and cached
1201758b4ee8SAndy Ritger     //difference. Also enable the frmCmpMatchInt if not enabled.
1202758b4ee8SAndy Ritger     //
1203758b4ee8SAndy Ritger     if ((!pThis->FrameCountData.lastFrameCounterQueryTime) ||
1204758b4ee8SAndy Ritger        (queryTimeDiff > 2 * NV_P2060_FRAME_COUNT_TIMER_INTERVAL))
1205758b4ee8SAndy Ritger     {
1206758b4ee8SAndy Ritger         //
1207758b4ee8SAndy Ritger         // P2060 refreshrate is in 0.00001 Hz, so divide by 10000 to get Hz.
1208758b4ee8SAndy Ritger         // divide 1000000 by refreshRate to get the frame time in us.
1209758b4ee8SAndy Ritger         //
1210758b4ee8SAndy Ritger         pThis->FrameCountData.frameTime = 1000000 / (pThis->RefreshRate/10000); //in us
1211758b4ee8SAndy Ritger 
1212758b4ee8SAndy Ritger         //
1213758b4ee8SAndy Ritger         // Enable FrameCountTimerService to verify FrameCountData.initialDifference.
1214758b4ee8SAndy Ritger         //
1215758b4ee8SAndy Ritger         pThis->FrameCountData.bReCheck = 1;
1216758b4ee8SAndy Ritger 
1217758b4ee8SAndy Ritger         rmStatus = gsyncUpdateFrameCount_P2060(pThis, pGpu);
1218758b4ee8SAndy Ritger         *pFrameCount = pThis->FrameCountData.totalFrameCount;
1219758b4ee8SAndy Ritger 
1220758b4ee8SAndy Ritger         // enable frame count match interrupt if not master
1221758b4ee8SAndy Ritger         if (!gsyncIsFrameLockMaster_P2060(pThis))
1222758b4ee8SAndy Ritger         {
1223758b4ee8SAndy Ritger             NvU8 regCtrl3;
1224758b4ee8SAndy Ritger 
1225758b4ee8SAndy Ritger             // set frame count match value 1
1226758b4ee8SAndy Ritger             rmStatus |= writeregu008_extdeviceTargeted(pGpu, (PDACEXTERNALDEVICE)pThis,
1227758b4ee8SAndy Ritger                                                       (NvU8)NV_P2060_FRAME_CMPR_LOW,  0x1);
1228758b4ee8SAndy Ritger             rmStatus |= writeregu008_extdeviceTargeted(pGpu, (PDACEXTERNALDEVICE)pThis,
1229758b4ee8SAndy Ritger                                                       (NvU8)NV_P2060_FRAME_CMPR_MID,  0x0);
1230758b4ee8SAndy Ritger             rmStatus |= writeregu008_extdeviceTargeted(pGpu, (PDACEXTERNALDEVICE)pThis,
1231758b4ee8SAndy Ritger                                                       (NvU8)NV_P2060_FRAME_CMPR_HIGH,  0x0);
1232758b4ee8SAndy Ritger 
1233758b4ee8SAndy Ritger             //
1234758b4ee8SAndy Ritger             // Enable frame count match interrupt for the first time. For rest of the
1235758b4ee8SAndy Ritger             // instances when, TEST_SIGNAL is received, interrupt is enable in
1236758b4ee8SAndy Ritger             // gsyncUpdateFrameCount_P2060() based on enableFrmCmpMatchIntSlave bit.
1237758b4ee8SAndy Ritger             //
1238758b4ee8SAndy Ritger             rmStatus |= readregu008_extdeviceTargeted(pGpu, (PDACEXTERNALDEVICE)pThis,
1239758b4ee8SAndy Ritger                                                       NV_P2060_CONTROL3,  &regCtrl3);
1240758b4ee8SAndy Ritger 
1241758b4ee8SAndy Ritger             if (rmStatus == NV_OK)
1242758b4ee8SAndy Ritger             {
1243758b4ee8SAndy Ritger                 regCtrl3 |= DRF_DEF(_P2060, _CONTROL3, _INTERRUPT, _ON_FRAME_MATCH);
1244758b4ee8SAndy Ritger                 rmStatus = writeregu008_extdeviceTargeted(pGpu, (PDACEXTERNALDEVICE)pThis,
1245758b4ee8SAndy Ritger                                                           NV_P2060_CONTROL3, regCtrl3);
1246758b4ee8SAndy Ritger             }
1247758b4ee8SAndy Ritger         }
1248758b4ee8SAndy Ritger 
1249758b4ee8SAndy Ritger         if (rmStatus != NV_OK)
1250758b4ee8SAndy Ritger         {
1251758b4ee8SAndy Ritger             rmStatus |= gsyncResetFrameCountData_P2060(pGpu, pThis);
1252758b4ee8SAndy Ritger             return rmStatus;
1253758b4ee8SAndy Ritger         }
1254758b4ee8SAndy Ritger 
1255758b4ee8SAndy Ritger         pThis->FrameCountData.lastFrameCounterQueryTime = currentTime;
1256758b4ee8SAndy Ritger     }
1257758b4ee8SAndy Ritger 
1258758b4ee8SAndy Ritger     // Update software framecount throught gpu frame count register.
1259758b4ee8SAndy Ritger     else
1260758b4ee8SAndy Ritger     {
1261758b4ee8SAndy Ritger         //
1262758b4ee8SAndy Ritger         // To avoid any inconsistency, linecount and framecount should always
1263758b4ee8SAndy Ritger         // be read from one specific Gpu head. Its value is stored in pThis->FrameCountData.
1264758b4ee8SAndy Ritger         //
1265758b4ee8SAndy Ritger         NV_ASSERT_OR_RETURN(pTmpGpu, NV_ERR_INVALID_DEVICE);
1266758b4ee8SAndy Ritger 
1267758b4ee8SAndy Ritger         pKernelDisplay = GPU_GET_KERNEL_DISPLAY(pTmpGpu);
1268758b4ee8SAndy Ritger 
1269758b4ee8SAndy Ritger         // Read the GPU frame count and line count
1270758b4ee8SAndy Ritger         rmStatus = kdispReadRgLineCountAndFrameCount_HAL(pTmpGpu, pKernelDisplay,
1271758b4ee8SAndy Ritger                        pThis->FrameCountData.head, &lineCount, &frameCount);
1272758b4ee8SAndy Ritger         if (rmStatus != NV_OK)
1273758b4ee8SAndy Ritger         {
1274758b4ee8SAndy Ritger             NV_PRINTF(LEVEL_ERROR, "Failed to read RG_DPCA.\n");
1275758b4ee8SAndy Ritger             return rmStatus;
1276758b4ee8SAndy Ritger         }
1277758b4ee8SAndy Ritger 
1278758b4ee8SAndy Ritger         //
1279758b4ee8SAndy Ritger         // Check to ensure previousFrameCount != currentGpuFrmCnt. If this is not ensured,
1280758b4ee8SAndy Ritger         // it is possible to miss rollover condition.
1281758b4ee8SAndy Ritger         //
1282758b4ee8SAndy Ritger         if (pThis->FrameCountData.currentFrameCount != frameCount)
1283758b4ee8SAndy Ritger         {
1284758b4ee8SAndy Ritger             pThis->FrameCountData.previousFrameCount = pThis->FrameCountData.currentFrameCount;
1285758b4ee8SAndy Ritger             pThis->FrameCountData.currentFrameCount  = frameCount;
1286758b4ee8SAndy Ritger 
1287758b4ee8SAndy Ritger             // If rollback for gpu framecount has occured.
1288758b4ee8SAndy Ritger             if (pThis->FrameCountData.previousFrameCount > pThis->FrameCountData.currentFrameCount)
1289758b4ee8SAndy Ritger             {
1290758b4ee8SAndy Ritger                 pThis->FrameCountData.numberOfRollbacks++;
1291758b4ee8SAndy Ritger             }
1292758b4ee8SAndy Ritger         }
1293758b4ee8SAndy Ritger 
1294758b4ee8SAndy Ritger         calculatedDiff = pThis->FrameCountData.initialDifference +
1295758b4ee8SAndy Ritger                          pThis->FrameCountData.numberOfRollbacks * (NV_P2060_MAX_GPU_FRAME_COUNT + 1);
1296758b4ee8SAndy Ritger 
1297758b4ee8SAndy Ritger         pThis->FrameCountData.totalFrameCount = pThis->FrameCountData.currentFrameCount +
1298758b4ee8SAndy Ritger                                                 calculatedDiff;
1299758b4ee8SAndy Ritger 
1300758b4ee8SAndy Ritger         //
1301758b4ee8SAndy Ritger         // To keep sync between the sw framecount and gsync framecount.
1302758b4ee8SAndy Ritger         //
1303758b4ee8SAndy Ritger         // Gpu framecount increments after VTotal scanout lines  whereas Gsync
1304758b4ee8SAndy Ritger         // increments after VActive scanout lines. Thus it is necessary to
1305758b4ee8SAndy Ritger         // mitigate this difference of 1 when linecount > VActive.
1306758b4ee8SAndy Ritger         //
1307758b4ee8SAndy Ritger         if (lineCount > pThis->FrameCountData.vActive)
1308758b4ee8SAndy Ritger         {
1309758b4ee8SAndy Ritger             pThis->FrameCountData.totalFrameCount++;
1310758b4ee8SAndy Ritger         }
1311758b4ee8SAndy Ritger 
1312758b4ee8SAndy Ritger         *pFrameCount = pThis->FrameCountData.totalFrameCount;
1313758b4ee8SAndy Ritger 
1314758b4ee8SAndy Ritger         pThis->FrameCountData.lastFrameCounterQueryTime = currentTime;
1315758b4ee8SAndy Ritger     }
1316758b4ee8SAndy Ritger 
1317758b4ee8SAndy Ritger     //
1318758b4ee8SAndy Ritger     // Enable the frame compare match interrupt in master gsync, to detect if
1319758b4ee8SAndy Ritger     // rollover has occured. So that gsync and gpu frame count can be cached
1320758b4ee8SAndy Ritger     // again and difference between them is verified.
1321758b4ee8SAndy Ritger     //
1322758b4ee8SAndy Ritger     if ((!pThis->FrameCountData.isFrmCmpMatchIntMasterEnabled) &&
1323758b4ee8SAndy Ritger         (pThis->FrameCountData.totalFrameCount > (NV_P2060_MAX_GSYNC_FRAME_COUNT - 1000)))
1324758b4ee8SAndy Ritger     {
1325758b4ee8SAndy Ritger         if (gsyncIsOnlyFrameLockMaster_P2060(pThis))
1326758b4ee8SAndy Ritger         {
1327758b4ee8SAndy Ritger             NvU8 regCtrl3;
1328758b4ee8SAndy Ritger 
1329758b4ee8SAndy Ritger             // enable frame count match interrupt
1330758b4ee8SAndy Ritger             rmStatus = readregu008_extdeviceTargeted(pGpu, (PDACEXTERNALDEVICE)pThis, NV_P2060_CONTROL3,  &regCtrl3);
1331758b4ee8SAndy Ritger 
1332758b4ee8SAndy Ritger             regCtrl3 |= DRF_DEF(_P2060, _CONTROL3, _INTERRUPT, _ON_FRAME_MATCH);
1333758b4ee8SAndy Ritger             rmStatus |= writeregu008_extdeviceTargeted(pGpu, (PDACEXTERNALDEVICE)pThis, NV_P2060_CONTROL3, regCtrl3);
1334758b4ee8SAndy Ritger 
1335758b4ee8SAndy Ritger             pThis->FrameCountData.isFrmCmpMatchIntMasterEnabled = NV_TRUE;
1336758b4ee8SAndy Ritger 
1337758b4ee8SAndy Ritger             if (rmStatus != NV_OK)
1338758b4ee8SAndy Ritger             {
1339758b4ee8SAndy Ritger                 rmStatus |= gsyncResetFrameCountData_P2060(pGpu, pThis);
1340758b4ee8SAndy Ritger             }
1341758b4ee8SAndy Ritger         }
1342758b4ee8SAndy Ritger     }
1343758b4ee8SAndy Ritger     return rmStatus;
1344758b4ee8SAndy Ritger }
1345758b4ee8SAndy Ritger 
1346758b4ee8SAndy Ritger /*
1347758b4ee8SAndy Ritger  * Read Frame Rate register and calculate Framerate.
1348758b4ee8SAndy Ritger  */
1349758b4ee8SAndy Ritger static NV_STATUS
gsyncReadFrameRate_P2060(OBJGPU * pGpu,PDACEXTERNALDEVICE pExtDev,NvU32 * pFrameRate)1350758b4ee8SAndy Ritger gsyncReadFrameRate_P2060
1351758b4ee8SAndy Ritger (
1352758b4ee8SAndy Ritger     OBJGPU *pGpu,
1353758b4ee8SAndy Ritger     PDACEXTERNALDEVICE pExtDev,
1354758b4ee8SAndy Ritger     NvU32 *pFrameRate
1355758b4ee8SAndy Ritger )
1356758b4ee8SAndy Ritger {
1357758b4ee8SAndy Ritger     NvU8  FrameCountLow, FrameCountMid, FrameCountHigh;
1358758b4ee8SAndy Ritger     NvU32 FrameCount;
1359758b4ee8SAndy Ritger     NV_STATUS rmStatus = NV_OK;
1360758b4ee8SAndy Ritger 
1361758b4ee8SAndy Ritger     rmStatus |= readregu008_extdeviceTargeted(pGpu, pExtDev, (NvU8)NV_P2060_FRAMERATE_LOW,  &FrameCountLow);
1362758b4ee8SAndy Ritger     rmStatus |= readregu008_extdeviceTargeted(pGpu, pExtDev, (NvU8)NV_P2060_FRAMERATE_MID,  &FrameCountMid);
1363758b4ee8SAndy Ritger     rmStatus |= readregu008_extdeviceTargeted(pGpu, pExtDev, (NvU8)NV_P2060_FRAMERATE_HIGH, &FrameCountHigh);
1364758b4ee8SAndy Ritger 
1365758b4ee8SAndy Ritger     if ( NV_OK == rmStatus )
1366758b4ee8SAndy Ritger     {
1367758b4ee8SAndy Ritger         NvU32 divisor;
1368758b4ee8SAndy Ritger 
1369758b4ee8SAndy Ritger         FrameCount = ( ( (((NvU32)FrameCountHigh) & DRF_MASK(NV_P2060_FRAMERATE_HIGH_VAL)) << 16 )  |
1370758b4ee8SAndy Ritger                        ( (((NvU32)FrameCountMid)  & DRF_MASK(NV_P2060_FRAMERATE_MID_VAL )) <<  8 )  |
1371758b4ee8SAndy Ritger                        ( (((NvU32)FrameCountLow)  & DRF_MASK(NV_P2060_FRAMERATE_LOW_VAL ))       )  );
1372758b4ee8SAndy Ritger 
1373758b4ee8SAndy Ritger         divisor     = FrameCount + 2; // FPGA divider is 1
1374758b4ee8SAndy Ritger         *pFrameRate = FrameCount ? OVERFLOW_CAREFUL_MUL_DIV(160000000, 2048, divisor) : 0;
1375758b4ee8SAndy Ritger         *pFrameRate += 5; // take back one kadam, to honor the Extdev god,
1376758b4ee8SAndy Ritger         *pFrameRate -= *pFrameRate % 10;  // whose GSync board this is...
1377758b4ee8SAndy Ritger     }
1378758b4ee8SAndy Ritger     return rmStatus;
1379758b4ee8SAndy Ritger }
1380758b4ee8SAndy Ritger 
1381758b4ee8SAndy Ritger /*
1382758b4ee8SAndy Ritger  * Read House Sync Frame Rate register and calculate Framerate.
1383758b4ee8SAndy Ritger  */
1384758b4ee8SAndy Ritger static NV_STATUS
gsyncReadHouseSyncFrameRate_P2060(OBJGPU * pGpu,PDACEXTERNALDEVICE pExtDev,NvU32 * pFrameRate)1385758b4ee8SAndy Ritger gsyncReadHouseSyncFrameRate_P2060
1386758b4ee8SAndy Ritger (
1387758b4ee8SAndy Ritger     OBJGPU *pGpu,
1388758b4ee8SAndy Ritger     PDACEXTERNALDEVICE pExtDev,
1389758b4ee8SAndy Ritger     NvU32 *pFrameRate
1390758b4ee8SAndy Ritger )
1391758b4ee8SAndy Ritger {
1392758b4ee8SAndy Ritger     NvU8  FrameCountLow, FrameCountMid, FrameCountHigh;
1393758b4ee8SAndy Ritger     NvU32 FrameCount;
1394758b4ee8SAndy Ritger     NV_STATUS rmStatus = NV_OK;
1395758b4ee8SAndy Ritger 
1396758b4ee8SAndy Ritger     rmStatus |= readregu008_extdeviceTargeted(pGpu, pExtDev, (NvU8)NV_P2060_HS_FRAMERATE_LOW,  &FrameCountLow);
1397758b4ee8SAndy Ritger     rmStatus |= readregu008_extdeviceTargeted(pGpu, pExtDev, (NvU8)NV_P2060_HS_FRAMERATE_MID,  &FrameCountMid);
1398758b4ee8SAndy Ritger     rmStatus |= readregu008_extdeviceTargeted(pGpu, pExtDev, (NvU8)NV_P2060_HS_FRAMERATE_HIGH, &FrameCountHigh);
1399758b4ee8SAndy Ritger 
1400758b4ee8SAndy Ritger     if ( NV_OK == rmStatus )
1401758b4ee8SAndy Ritger     {
1402758b4ee8SAndy Ritger         NvU32 divisor;
1403758b4ee8SAndy Ritger 
1404758b4ee8SAndy Ritger         FrameCount = ( ( (((NvU32)FrameCountHigh) & DRF_MASK(NV_P2060_HS_FRAMERATE_HIGH_VAL)) << 16 )  |
1405758b4ee8SAndy Ritger                        ( (((NvU32)FrameCountMid)  & DRF_MASK(NV_P2060_HS_FRAMERATE_MID_VAL )) <<  8 )  |
1406758b4ee8SAndy Ritger                        ( (((NvU32)FrameCountLow)  & DRF_MASK(NV_P2060_HS_FRAMERATE_LOW_VAL ))       )  );
1407758b4ee8SAndy Ritger 
1408758b4ee8SAndy Ritger         divisor     = FrameCount + 2; // FPGA divider is 1
1409758b4ee8SAndy Ritger         *pFrameRate = FrameCount ? OVERFLOW_CAREFUL_MUL_DIV(160000000, 2048, divisor) : 0;
1410758b4ee8SAndy Ritger         *pFrameRate += 5; // take back one kadam, to honor the Extdev god,
1411758b4ee8SAndy Ritger         *pFrameRate -= *pFrameRate % 10;  // whose GSync board this is...
1412758b4ee8SAndy Ritger     }
1413758b4ee8SAndy Ritger     return rmStatus;
1414758b4ee8SAndy Ritger }
1415758b4ee8SAndy Ritger 
1416758b4ee8SAndy Ritger NV_STATUS
gsyncOptimizeTimingParameters_P2060(OBJGPU * pGpu,GSYNCTIMINGPARAMS * pParams)1417758b4ee8SAndy Ritger gsyncOptimizeTimingParameters_P2060
1418758b4ee8SAndy Ritger (
1419758b4ee8SAndy Ritger     OBJGPU            *pGpu,
1420758b4ee8SAndy Ritger     GSYNCTIMINGPARAMS *pParams
1421758b4ee8SAndy Ritger )
1422758b4ee8SAndy Ritger {
1423758b4ee8SAndy Ritger     RM_API   *pRmApi      = GPU_GET_PHYSICAL_RMAPI(pGpu);
1424758b4ee8SAndy Ritger     NvU32     hClient     = pGpu->hInternalClient;
1425758b4ee8SAndy Ritger     NvU32     hSubdevice  = pGpu->hInternalSubdevice;
1426758b4ee8SAndy Ritger     NV_STATUS status      = NV_OK;
1427758b4ee8SAndy Ritger     NV2080_CTRL_INTERNAL_GSYNC_OPTIMIZE_TIMING_PARAMETERS_PARAMS ctrlParams = {0};
1428758b4ee8SAndy Ritger 
1429758b4ee8SAndy Ritger     ctrlParams.timingParameters = *pParams;
1430758b4ee8SAndy Ritger 
1431758b4ee8SAndy Ritger     status = pRmApi->Control(pRmApi, hClient, hSubdevice,
1432758b4ee8SAndy Ritger                              NV2080_CTRL_CMD_INTERNAL_GSYNC_OPTIMIZE_TIMING_PARAMETERS,
1433758b4ee8SAndy Ritger                              &ctrlParams, sizeof(ctrlParams));
1434758b4ee8SAndy Ritger 
1435758b4ee8SAndy Ritger     if (status != NV_OK)
1436758b4ee8SAndy Ritger     {
1437758b4ee8SAndy Ritger         NV_PRINTF(LEVEL_ERROR, "OptimizeTimingParameters control call has failed! \n");
1438758b4ee8SAndy Ritger     }
1439758b4ee8SAndy Ritger     else
1440758b4ee8SAndy Ritger     {
1441758b4ee8SAndy Ritger         *pParams = ctrlParams.timingParameters;
1442758b4ee8SAndy Ritger     }
1443758b4ee8SAndy Ritger 
1444758b4ee8SAndy Ritger     return status;
1445758b4ee8SAndy Ritger }
1446758b4ee8SAndy Ritger 
1447758b4ee8SAndy Ritger /*
1448758b4ee8SAndy Ritger  * Program External Stereo Polarity to High side of master stereo
1449758b4ee8SAndy Ritger  */
1450758b4ee8SAndy Ritger static NV_STATUS
gsyncProgramExtStereoPolarity_P2060(OBJGPU * pGpu,PDACEXTERNALDEVICE pExternalDevice)1451758b4ee8SAndy Ritger gsyncProgramExtStereoPolarity_P2060
1452758b4ee8SAndy Ritger (
1453758b4ee8SAndy Ritger     OBJGPU  *pGpu,
1454758b4ee8SAndy Ritger     PDACEXTERNALDEVICE pExternalDevice
1455758b4ee8SAndy Ritger )
1456758b4ee8SAndy Ritger {
1457758b4ee8SAndy Ritger     NV_STATUS rmStatus = NV_OK;
1458758b4ee8SAndy Ritger     NvU8  ctrl4 = 0x00;
1459758b4ee8SAndy Ritger 
1460758b4ee8SAndy Ritger     rmStatus = readregu008_extdeviceTargeted(pGpu, pExternalDevice,
1461758b4ee8SAndy Ritger                                              NV_P2060_CONTROL4, &ctrl4);
1462758b4ee8SAndy Ritger     if (rmStatus != NV_OK)
1463758b4ee8SAndy Ritger     {
1464758b4ee8SAndy Ritger         return rmStatus;
1465758b4ee8SAndy Ritger     }
1466758b4ee8SAndy Ritger 
1467758b4ee8SAndy Ritger     // This bit controls stereo polarity relative to an external sync.
1468758b4ee8SAndy Ritger     ctrl4 = (NvU8) FLD_SET_DRF(_P2060, _CONTROL4, _EXT_STEREO_SYNC_POL, _HI, (NvU32)ctrl4);
1469758b4ee8SAndy Ritger 
1470758b4ee8SAndy Ritger     rmStatus = writeregu008_extdeviceTargeted(pGpu, pExternalDevice,
1471758b4ee8SAndy Ritger                                              NV_P2060_CONTROL4, ctrl4);
1472758b4ee8SAndy Ritger     return rmStatus;
1473758b4ee8SAndy Ritger }
1474758b4ee8SAndy Ritger 
1475758b4ee8SAndy Ritger NV_STATUS
gsyncSetStereoLockMode_P2060(OBJGPU * pGpu,PDACEXTERNALDEVICE pExtDev,NvU32 enable)1476758b4ee8SAndy Ritger gsyncSetStereoLockMode_P2060
1477758b4ee8SAndy Ritger (
1478758b4ee8SAndy Ritger     OBJGPU            *pGpu,
1479758b4ee8SAndy Ritger     PDACEXTERNALDEVICE pExtDev,
1480758b4ee8SAndy Ritger     NvU32              enable
1481758b4ee8SAndy Ritger )
1482758b4ee8SAndy Ritger {
1483758b4ee8SAndy Ritger     NvU8 ctrl4;
1484758b4ee8SAndy Ritger     NV_STATUS rmStatus;
1485758b4ee8SAndy Ritger 
1486758b4ee8SAndy Ritger     rmStatus = readregu008_extdeviceTargeted(pGpu, pExtDev, (NvU8)NV_P2060_CONTROL4, &ctrl4);
1487758b4ee8SAndy Ritger 
1488758b4ee8SAndy Ritger     if (rmStatus != NV_OK)
1489758b4ee8SAndy Ritger     {
1490758b4ee8SAndy Ritger          return rmStatus;
1491758b4ee8SAndy Ritger     }
1492758b4ee8SAndy Ritger 
1493758b4ee8SAndy Ritger     if (enable)
1494758b4ee8SAndy Ritger     {
1495758b4ee8SAndy Ritger         ctrl4 = FLD_SET_DRF(_P2060, _CONTROL4, _STEREO_LOCK_MODE, _ON, ctrl4);
1496758b4ee8SAndy Ritger     }
1497758b4ee8SAndy Ritger     else
1498758b4ee8SAndy Ritger     {
1499758b4ee8SAndy Ritger         ctrl4 = FLD_SET_DRF(_P2060, _CONTROL4, _STEREO_LOCK_MODE, _OFF, ctrl4);
1500758b4ee8SAndy Ritger     }
1501758b4ee8SAndy Ritger 
1502758b4ee8SAndy Ritger     rmStatus = writeregu008_extdeviceTargeted(pGpu, pExtDev, NV_P2060_CONTROL4, ctrl4);
1503758b4ee8SAndy Ritger 
1504758b4ee8SAndy Ritger     return rmStatus;
1505758b4ee8SAndy Ritger }
1506758b4ee8SAndy Ritger 
1507758b4ee8SAndy Ritger NV_STATUS
gsyncGetStereoLockMode_P2060(OBJGPU * pGpu,PDACEXTERNALDEVICE pExtDev,NvU32 * enable)1508758b4ee8SAndy Ritger gsyncGetStereoLockMode_P2060
1509758b4ee8SAndy Ritger (
1510758b4ee8SAndy Ritger     OBJGPU            *pGpu,
1511758b4ee8SAndy Ritger     PDACEXTERNALDEVICE pExtDev,
1512758b4ee8SAndy Ritger     NvU32              *enable
1513758b4ee8SAndy Ritger )
1514758b4ee8SAndy Ritger {
1515758b4ee8SAndy Ritger     NvU8 ctrl4;
1516758b4ee8SAndy Ritger     NV_STATUS rmStatus;
1517758b4ee8SAndy Ritger 
1518758b4ee8SAndy Ritger     rmStatus = readregu008_extdeviceTargeted(pGpu, pExtDev, (NvU8)NV_P2060_CONTROL4, &ctrl4);
1519758b4ee8SAndy Ritger 
1520758b4ee8SAndy Ritger     if (NV_OK == rmStatus)
1521758b4ee8SAndy Ritger     {
1522758b4ee8SAndy Ritger         *enable = FLD_TEST_DRF(_P2060, _CONTROL4, _STEREO_LOCK_MODE, _ON, ctrl4);
1523758b4ee8SAndy Ritger     }
1524758b4ee8SAndy Ritger 
1525758b4ee8SAndy Ritger     return rmStatus;
1526758b4ee8SAndy Ritger }
1527758b4ee8SAndy Ritger 
1528758b4ee8SAndy Ritger NV_STATUS
gsyncSetVideoMode_P2060(OBJGPU * pGpu,PDACEXTERNALDEVICE pExtDev,GSYNCVIDEOMODE VideoMode)1529758b4ee8SAndy Ritger gsyncSetVideoMode_P2060
1530758b4ee8SAndy Ritger (
1531758b4ee8SAndy Ritger     OBJGPU *pGpu,
1532758b4ee8SAndy Ritger     PDACEXTERNALDEVICE pExtDev,
1533758b4ee8SAndy Ritger     GSYNCVIDEOMODE VideoMode
1534758b4ee8SAndy Ritger )
1535758b4ee8SAndy Ritger {
1536758b4ee8SAndy Ritger     return NV_OK;
1537758b4ee8SAndy Ritger }
1538758b4ee8SAndy Ritger 
1539758b4ee8SAndy Ritger NV_STATUS
gsyncGetVideoMode_P2060(OBJGPU * pGpu,PDACEXTERNALDEVICE pExtDev,GSYNCVIDEOMODE * pVideoMode)1540758b4ee8SAndy Ritger gsyncGetVideoMode_P2060
1541758b4ee8SAndy Ritger (
1542758b4ee8SAndy Ritger     OBJGPU *pGpu,
1543758b4ee8SAndy Ritger     PDACEXTERNALDEVICE pExtDev,
1544758b4ee8SAndy Ritger     GSYNCVIDEOMODE *pVideoMode
1545758b4ee8SAndy Ritger )
1546758b4ee8SAndy Ritger {
1547758b4ee8SAndy Ritger     NvU8 videoMode;
1548758b4ee8SAndy Ritger     NV_STATUS rmStatus;
1549758b4ee8SAndy Ritger     PDACP2060EXTERNALDEVICE pThis = (PDACP2060EXTERNALDEVICE)pExtDev;
1550758b4ee8SAndy Ritger 
1551758b4ee8SAndy Ritger     NV_ASSERT_OR_RETURN(pGpu, NV_ERR_GENERIC);
1552758b4ee8SAndy Ritger 
1553758b4ee8SAndy Ritger     rmStatus = readregu008_extdeviceTargeted(pGpu, pExtDev, (NvU8)NV_P2060_STATUS2, &videoMode);
1554758b4ee8SAndy Ritger 
1555758b4ee8SAndy Ritger     if ( NV_OK == rmStatus )
1556758b4ee8SAndy Ritger     {
1557758b4ee8SAndy Ritger         *pVideoMode = DRF_VAL(_P2060, _STATUS2, _HS_DETECT, videoMode);
1558758b4ee8SAndy Ritger         if (*pVideoMode == 0x02)
1559758b4ee8SAndy Ritger         {
1560758b4ee8SAndy Ritger             // reported videoMode is composite. Convert it to RMAPI exported value.
1561758b4ee8SAndy Ritger             *pVideoMode = gsync_VideoMode_COMPOSITE;
1562758b4ee8SAndy Ritger         }
1563758b4ee8SAndy Ritger     }
1564758b4ee8SAndy Ritger 
1565758b4ee8SAndy Ritger     // update p2060 object
1566758b4ee8SAndy Ritger     pThis->VideoMode = *pVideoMode;
1567758b4ee8SAndy Ritger 
1568758b4ee8SAndy Ritger     return rmStatus;
1569758b4ee8SAndy Ritger }
1570758b4ee8SAndy Ritger 
1571758b4ee8SAndy Ritger NV_STATUS
gsyncSetEmitTestSignal_P2060(OBJGPU * pGpu,PDACEXTERNALDEVICE pExtDev,NvU32 bEmitTestSignal)1572758b4ee8SAndy Ritger gsyncSetEmitTestSignal_P2060
1573758b4ee8SAndy Ritger (
1574758b4ee8SAndy Ritger     OBJGPU *pGpu,
1575758b4ee8SAndy Ritger     PDACEXTERNALDEVICE pExtDev,
1576758b4ee8SAndy Ritger     NvU32 bEmitTestSignal
1577758b4ee8SAndy Ritger )
1578758b4ee8SAndy Ritger {
1579758b4ee8SAndy Ritger     NvU8 ctrl;
1580758b4ee8SAndy Ritger     NV_STATUS rmStatus;
1581758b4ee8SAndy Ritger     PDACP2060EXTERNALDEVICE pThis = (PDACP2060EXTERNALDEVICE)pExtDev;
1582758b4ee8SAndy Ritger 
1583758b4ee8SAndy Ritger     // update p2060 object
1584758b4ee8SAndy Ritger     pThis->EmitTestSignal = bEmitTestSignal;
1585758b4ee8SAndy Ritger 
1586758b4ee8SAndy Ritger     if (!gsyncIsFrameLockMaster_P2060(pThis))
1587758b4ee8SAndy Ritger     {
1588758b4ee8SAndy Ritger         return NV_ERR_INVALID_DEVICE;
1589758b4ee8SAndy Ritger     }
1590758b4ee8SAndy Ritger 
1591758b4ee8SAndy Ritger     pGpu = GetP2060MasterableGpu(pGpu, (PDACP2060EXTERNALDEVICE)pExtDev);
1592758b4ee8SAndy Ritger     NV_ASSERT_OR_RETURN(pGpu, NV_ERR_GENERIC);
1593758b4ee8SAndy Ritger 
1594758b4ee8SAndy Ritger     rmStatus = readregu008_extdeviceTargeted(pGpu, pExtDev, (NvU8)NV_P2060_CONTROL, &ctrl);
1595758b4ee8SAndy Ritger 
1596758b4ee8SAndy Ritger     if ( bEmitTestSignal )
1597758b4ee8SAndy Ritger     {
1598758b4ee8SAndy Ritger         ctrl = FLD_SET_DRF(_P2060, _CONTROL, _TEST_MODE,  _ON, ctrl);
1599758b4ee8SAndy Ritger     }
1600758b4ee8SAndy Ritger     else
1601758b4ee8SAndy Ritger     {
1602758b4ee8SAndy Ritger         ctrl = FLD_SET_DRF(_P2060, _CONTROL, _TEST_MODE, _OFF, ctrl);
1603758b4ee8SAndy Ritger 
1604758b4ee8SAndy Ritger         //
1605758b4ee8SAndy Ritger         // To enable frameCountTimerService callback which verifies
1606758b4ee8SAndy Ritger         // the cache difference 1 second after sending the test signal
1607758b4ee8SAndy Ritger         //
1608758b4ee8SAndy Ritger         pThis->FrameCountData.bReCheck = 1;
1609758b4ee8SAndy Ritger 
1610758b4ee8SAndy Ritger         //
1611758b4ee8SAndy Ritger         // Reset framecountData.Therefore whenever user queries after TEST_MODE_OFF,
1612758b4ee8SAndy Ritger         // gsync and gpu frame count register are read and difference is cached again.
1613758b4ee8SAndy Ritger         //
1614758b4ee8SAndy Ritger         rmStatus |= gsyncResetFrameCountData_P2060(pGpu, pThis);
1615758b4ee8SAndy Ritger     }
1616758b4ee8SAndy Ritger 
1617758b4ee8SAndy Ritger     rmStatus |= writeregu008_extdeviceTargeted(pGpu, pExtDev, NV_P2060_CONTROL, ctrl);
1618758b4ee8SAndy Ritger 
1619758b4ee8SAndy Ritger     //
1620758b4ee8SAndy Ritger     // Add some OS delay between test mode transitions. This is also
1621758b4ee8SAndy Ritger     // necessary for proper propogation of test signal to other slaves.
1622758b4ee8SAndy Ritger     //
1623758b4ee8SAndy Ritger     {
1624758b4ee8SAndy Ritger         NvU32 refreshTime = 0;
1625758b4ee8SAndy Ritger         //
1626758b4ee8SAndy Ritger         // The test mode detection logic will return the previous value until the
1627758b4ee8SAndy Ritger         // next frame.  Although only the master will only manipulate test mode,
1628758b4ee8SAndy Ritger         // we may transition to slave while test mode is still on due to this.
1629758b4ee8SAndy Ritger         // So delay for a couple of frames to make sure the value transitions
1630758b4ee8SAndy Ritger         // correctly. Fix for bug #82809, back in the day.
1631758b4ee8SAndy Ritger         //
1632758b4ee8SAndy Ritger         // P2060 refreshrate is in 0.00001 Hz, so divide by 10000 to get Hz.
1633758b4ee8SAndy Ritger         //
1634758b4ee8SAndy Ritger         if ((pThis->RefreshRate/10000) > 0)
1635758b4ee8SAndy Ritger         {
1636758b4ee8SAndy Ritger             refreshTime = 1000 / (pThis->RefreshRate/10000);
1637758b4ee8SAndy Ritger         }
1638758b4ee8SAndy Ritger         NV_ASSERT(refreshTime != 0);
1639758b4ee8SAndy Ritger 
1640758b4ee8SAndy Ritger         // Only wait a maximum amount of time.
1641758b4ee8SAndy Ritger         refreshTime = NV_MIN(refreshTime, 35);
1642758b4ee8SAndy Ritger         osDelay(2*refreshTime /* ms */);
1643758b4ee8SAndy Ritger     }
1644758b4ee8SAndy Ritger 
1645758b4ee8SAndy Ritger     return rmStatus;
1646758b4ee8SAndy Ritger }
1647758b4ee8SAndy Ritger 
1648758b4ee8SAndy Ritger NV_STATUS
gsyncGetEmitTestSignal_P2060(OBJGPU * pGpu,PDACEXTERNALDEVICE pExtDev,NvU32 * pVal)1649758b4ee8SAndy Ritger gsyncGetEmitTestSignal_P2060
1650758b4ee8SAndy Ritger (
1651758b4ee8SAndy Ritger  OBJGPU *pGpu,
1652758b4ee8SAndy Ritger  PDACEXTERNALDEVICE pExtDev,
1653758b4ee8SAndy Ritger  NvU32 *pVal
1654758b4ee8SAndy Ritger )
1655758b4ee8SAndy Ritger {
1656758b4ee8SAndy Ritger     NvU8 ctrl;
1657758b4ee8SAndy Ritger     NV_STATUS rmStatus;
1658758b4ee8SAndy Ritger     PDACP2060EXTERNALDEVICE pThis = (PDACP2060EXTERNALDEVICE)pExtDev;
1659758b4ee8SAndy Ritger 
1660758b4ee8SAndy Ritger     rmStatus = readregu008_extdeviceTargeted(pGpu, pExtDev, (NvU8)NV_P2060_CONTROL, &ctrl);
1661758b4ee8SAndy Ritger 
1662758b4ee8SAndy Ritger     if ( NV_OK == rmStatus )
1663758b4ee8SAndy Ritger     {
1664758b4ee8SAndy Ritger         *pVal = FLD_TEST_DRF(_P2060, _CONTROL, _TEST_MODE, _ON, ctrl);
1665758b4ee8SAndy Ritger     }
1666758b4ee8SAndy Ritger 
1667758b4ee8SAndy Ritger     // update p2060 object
1668758b4ee8SAndy Ritger     pThis->EmitTestSignal = *pVal;
1669758b4ee8SAndy Ritger 
1670758b4ee8SAndy Ritger     return rmStatus;
1671758b4ee8SAndy Ritger }
1672758b4ee8SAndy Ritger 
1673758b4ee8SAndy Ritger NV_STATUS
gsyncSetInterlaceMode_P2060(OBJGPU * pGpu,PDACEXTERNALDEVICE pExtDev,NvU32 InterlaceMode)1674758b4ee8SAndy Ritger gsyncSetInterlaceMode_P2060
1675758b4ee8SAndy Ritger (
1676758b4ee8SAndy Ritger     OBJGPU *pGpu,
1677758b4ee8SAndy Ritger     PDACEXTERNALDEVICE pExtDev,
1678758b4ee8SAndy Ritger     NvU32 InterlaceMode
1679758b4ee8SAndy Ritger )
1680758b4ee8SAndy Ritger {
1681758b4ee8SAndy Ritger     NvU8 ctrl;
1682758b4ee8SAndy Ritger     NV_STATUS rmStatus;
1683758b4ee8SAndy Ritger     PDACP2060EXTERNALDEVICE pThis = (PDACP2060EXTERNALDEVICE)pExtDev;
1684758b4ee8SAndy Ritger 
1685758b4ee8SAndy Ritger     // update p2060 object
1686758b4ee8SAndy Ritger     pThis->InterlaceMode = InterlaceMode;
1687758b4ee8SAndy Ritger 
1688758b4ee8SAndy Ritger     pGpu = GetP2060MasterableGpu(pGpu, (PDACP2060EXTERNALDEVICE)pExtDev);
1689758b4ee8SAndy Ritger     NV_ASSERT_OR_RETURN(pGpu, NV_ERR_GENERIC);
1690758b4ee8SAndy Ritger 
1691758b4ee8SAndy Ritger     rmStatus = readregu008_extdeviceTargeted(pGpu, pExtDev, (NvU8)NV_P2060_CONTROL, &ctrl);
1692758b4ee8SAndy Ritger 
1693758b4ee8SAndy Ritger     if ( rmStatus == NV_OK )
1694758b4ee8SAndy Ritger     {
1695758b4ee8SAndy Ritger         ctrl = FLD_SET_DRF_NUM(_P2060, _CONTROL, _INTERLACE_MODE, (NvU8)InterlaceMode, ctrl);
1696758b4ee8SAndy Ritger         rmStatus = writeregu008_extdeviceTargeted(pGpu, pExtDev, NV_P2060_CONTROL, ctrl);
1697758b4ee8SAndy Ritger     }
1698758b4ee8SAndy Ritger 
1699758b4ee8SAndy Ritger     return rmStatus;
1700758b4ee8SAndy Ritger }
1701758b4ee8SAndy Ritger 
1702758b4ee8SAndy Ritger NV_STATUS
gsyncGetInterlaceMode_P2060(OBJGPU * pGpu,PDACEXTERNALDEVICE pExtDev,NvU32 * pVal)1703758b4ee8SAndy Ritger gsyncGetInterlaceMode_P2060
1704758b4ee8SAndy Ritger (
1705758b4ee8SAndy Ritger     OBJGPU *pGpu,
1706758b4ee8SAndy Ritger     PDACEXTERNALDEVICE pExtDev,
1707758b4ee8SAndy Ritger     NvU32 *pVal
1708758b4ee8SAndy Ritger )
1709758b4ee8SAndy Ritger {
1710758b4ee8SAndy Ritger     NvU8 ctrl;
1711758b4ee8SAndy Ritger     NV_STATUS rmStatus;
1712758b4ee8SAndy Ritger     PDACP2060EXTERNALDEVICE pThis = (PDACP2060EXTERNALDEVICE)pExtDev;
1713758b4ee8SAndy Ritger 
1714758b4ee8SAndy Ritger     pGpu = GetP2060MasterableGpu(pGpu, (PDACP2060EXTERNALDEVICE)pExtDev);
1715758b4ee8SAndy Ritger     NV_ASSERT_OR_RETURN(pGpu, NV_ERR_GENERIC);
1716758b4ee8SAndy Ritger 
1717758b4ee8SAndy Ritger     rmStatus = readregu008_extdeviceTargeted(pGpu, pExtDev, (NvU8)NV_P2060_CONTROL, &ctrl);
1718758b4ee8SAndy Ritger 
1719758b4ee8SAndy Ritger     if ( NV_OK == rmStatus )
1720758b4ee8SAndy Ritger     {
1721758b4ee8SAndy Ritger         *pVal = FLD_TEST_DRF(_P2060, _CONTROL, _INTERLACE_MODE, _TRUE, ctrl);
1722758b4ee8SAndy Ritger     }
1723758b4ee8SAndy Ritger 
1724758b4ee8SAndy Ritger     // update p2060 object
1725758b4ee8SAndy Ritger     pThis->InterlaceMode = *pVal;
1726758b4ee8SAndy Ritger 
1727758b4ee8SAndy Ritger     return rmStatus;
1728758b4ee8SAndy Ritger }
1729758b4ee8SAndy Ritger 
1730758b4ee8SAndy Ritger NV_STATUS
gsyncSetUseHouse_P2060(OBJGPU * pGpu,PDACEXTERNALDEVICE pExtDev,NvU32 UseHouseSync)1731758b4ee8SAndy Ritger gsyncSetUseHouse_P2060
1732758b4ee8SAndy Ritger (
1733758b4ee8SAndy Ritger     OBJGPU *pGpu,
1734758b4ee8SAndy Ritger     PDACEXTERNALDEVICE pExtDev,
1735758b4ee8SAndy Ritger     NvU32 UseHouseSync
1736758b4ee8SAndy Ritger )
1737758b4ee8SAndy Ritger {
1738758b4ee8SAndy Ritger     NvU8 ctrl;
1739758b4ee8SAndy Ritger     NV_STATUS rmStatus = NV_OK;
1740758b4ee8SAndy Ritger     PDACP2060EXTERNALDEVICE pThis = (PDACP2060EXTERNALDEVICE)pExtDev;
1741758b4ee8SAndy Ritger 
1742758b4ee8SAndy Ritger     // update p2060 object
1743758b4ee8SAndy Ritger     pThis->UseHouseSync = UseHouseSync;
1744758b4ee8SAndy Ritger 
1745758b4ee8SAndy Ritger     pGpu = GetP2060MasterableGpu(pGpu, (PDACP2060EXTERNALDEVICE)pExtDev);
1746758b4ee8SAndy Ritger     NV_ASSERT_OR_RETURN(pGpu, NV_ERR_GENERIC);
1747758b4ee8SAndy Ritger 
1748758b4ee8SAndy Ritger     rmStatus = readregu008_extdeviceTargeted(pGpu, pExtDev, NV_P2060_CONTROL, &ctrl);
1749758b4ee8SAndy Ritger 
1750758b4ee8SAndy Ritger     if (NV_OK == rmStatus)
1751758b4ee8SAndy Ritger     {
1752758b4ee8SAndy Ritger         ctrl = FLD_SET_DRF_NUM(_P2060, _CONTROL, _SYNC_SELECT, (NvU8)UseHouseSync, ctrl);
1753758b4ee8SAndy Ritger         rmStatus = writeregu008_extdeviceTargeted(pGpu, pExtDev, NV_P2060_CONTROL, ctrl);
1754758b4ee8SAndy Ritger     }
1755758b4ee8SAndy Ritger 
1756758b4ee8SAndy Ritger     return rmStatus;
1757758b4ee8SAndy Ritger }
1758758b4ee8SAndy Ritger 
1759758b4ee8SAndy Ritger NV_STATUS
gsyncGetUseHouse_P2060(OBJGPU * pGpu,PDACEXTERNALDEVICE pExtDev,NvU32 * val)1760758b4ee8SAndy Ritger gsyncGetUseHouse_P2060
1761758b4ee8SAndy Ritger (
1762758b4ee8SAndy Ritger     OBJGPU *pGpu,
1763758b4ee8SAndy Ritger     PDACEXTERNALDEVICE pExtDev,
1764758b4ee8SAndy Ritger     NvU32 *val
1765758b4ee8SAndy Ritger )
1766758b4ee8SAndy Ritger {
1767758b4ee8SAndy Ritger     NvU8 ctrl;
1768758b4ee8SAndy Ritger     NV_STATUS rmStatus = NV_OK;
1769758b4ee8SAndy Ritger     PDACP2060EXTERNALDEVICE pThis = (PDACP2060EXTERNALDEVICE)pExtDev;
1770758b4ee8SAndy Ritger 
1771758b4ee8SAndy Ritger     rmStatus = readregu008_extdeviceTargeted(pGpu, pExtDev, NV_P2060_CONTROL, &ctrl);
1772758b4ee8SAndy Ritger 
1773758b4ee8SAndy Ritger     if (NV_OK == rmStatus)
1774758b4ee8SAndy Ritger     {
1775758b4ee8SAndy Ritger         *val = FLD_TEST_DRF(_P2060, _CONTROL, _SYNC_SELECT, _HOUSE, ctrl);
1776758b4ee8SAndy Ritger 
1777758b4ee8SAndy Ritger         // update p2060 object
1778758b4ee8SAndy Ritger         pThis->UseHouseSync = *val;
1779758b4ee8SAndy Ritger     }
1780758b4ee8SAndy Ritger 
1781758b4ee8SAndy Ritger     return rmStatus;
1782758b4ee8SAndy Ritger }
1783758b4ee8SAndy Ritger 
1784758b4ee8SAndy Ritger NV_STATUS
gsyncSetSyncPolarity_P2060(OBJGPU * pGpu,PDACEXTERNALDEVICE pExtDev,GSYNCSYNCPOLARITY SyncPolarity)1785758b4ee8SAndy Ritger gsyncSetSyncPolarity_P2060
1786758b4ee8SAndy Ritger (
1787758b4ee8SAndy Ritger     OBJGPU *pGpu,
1788758b4ee8SAndy Ritger     PDACEXTERNALDEVICE pExtDev,
1789758b4ee8SAndy Ritger     GSYNCSYNCPOLARITY SyncPolarity
1790758b4ee8SAndy Ritger )
1791758b4ee8SAndy Ritger {
1792758b4ee8SAndy Ritger     NvU8 ctrl;
1793758b4ee8SAndy Ritger     NV_STATUS rmStatus;
1794758b4ee8SAndy Ritger     PDACP2060EXTERNALDEVICE pThis = (PDACP2060EXTERNALDEVICE)pExtDev;
1795758b4ee8SAndy Ritger     GSYNCSYNCPOLARITY currentSyncPolarity;
1796758b4ee8SAndy Ritger 
1797758b4ee8SAndy Ritger     // update p2060 object
1798758b4ee8SAndy Ritger     pThis->SyncPolarity = SyncPolarity;
1799758b4ee8SAndy Ritger 
1800758b4ee8SAndy Ritger     pGpu = GetP2060MasterableGpu(pGpu, (PDACP2060EXTERNALDEVICE)pExtDev);
1801758b4ee8SAndy Ritger     NV_ASSERT_OR_RETURN(pGpu, NV_ERR_GENERIC);
1802758b4ee8SAndy Ritger 
1803758b4ee8SAndy Ritger     rmStatus = readregu008_extdeviceTargeted(pGpu, pExtDev, (NvU8)NV_P2060_CONTROL, &ctrl);
1804758b4ee8SAndy Ritger 
1805758b4ee8SAndy Ritger     if ( NV_OK == rmStatus )
1806758b4ee8SAndy Ritger     {
1807758b4ee8SAndy Ritger         currentSyncPolarity = DRF_VAL(_P2060, _CONTROL, _SYNC_POLARITY, ctrl);
1808758b4ee8SAndy Ritger 
1809758b4ee8SAndy Ritger         if (currentSyncPolarity != SyncPolarity)
1810758b4ee8SAndy Ritger         {
1811758b4ee8SAndy Ritger             NvU32 frameTime = 0;
1812758b4ee8SAndy Ritger 
1813758b4ee8SAndy Ritger             ctrl = FLD_SET_DRF_NUM(_P2060, _CONTROL, _SYNC_POLARITY, (NvU8)SyncPolarity, ctrl);
1814758b4ee8SAndy Ritger             rmStatus = writeregu008_extdeviceTargeted(pGpu, pExtDev, NV_P2060_CONTROL, ctrl);
1815758b4ee8SAndy Ritger 
1816758b4ee8SAndy Ritger             if ((pThis->RefreshRate/10000) > 0)
1817758b4ee8SAndy Ritger             {
1818758b4ee8SAndy Ritger                 frameTime = 1000 / (pThis->RefreshRate/10000);
1819758b4ee8SAndy Ritger             }
1820758b4ee8SAndy Ritger 
1821758b4ee8SAndy Ritger             //
1822758b4ee8SAndy Ritger             // Wait for max of 10 frames or 100 ms so that hardware can collect
1823758b4ee8SAndy Ritger             // the new house sync frame rate.
1824758b4ee8SAndy Ritger             //
1825758b4ee8SAndy Ritger             frameTime = NV_MAX(frameTime, 10);
1826758b4ee8SAndy Ritger             osDelay(10 * frameTime /* ms */);
1827758b4ee8SAndy Ritger         }
1828758b4ee8SAndy Ritger     }
1829758b4ee8SAndy Ritger 
1830758b4ee8SAndy Ritger     return rmStatus;
1831758b4ee8SAndy Ritger }
1832758b4ee8SAndy Ritger 
1833758b4ee8SAndy Ritger NV_STATUS
gsyncGetSyncPolarity_P2060(OBJGPU * pGpu,PDACEXTERNALDEVICE pExtDev,GSYNCSYNCPOLARITY * pSyncPolarity)1834758b4ee8SAndy Ritger gsyncGetSyncPolarity_P2060
1835758b4ee8SAndy Ritger (
1836758b4ee8SAndy Ritger     OBJGPU *pGpu,
1837758b4ee8SAndy Ritger     PDACEXTERNALDEVICE pExtDev,
1838758b4ee8SAndy Ritger     GSYNCSYNCPOLARITY *pSyncPolarity
1839758b4ee8SAndy Ritger )
1840758b4ee8SAndy Ritger {
1841758b4ee8SAndy Ritger     NvU8 ctrl;
1842758b4ee8SAndy Ritger     NV_STATUS rmStatus;
1843758b4ee8SAndy Ritger     PDACP2060EXTERNALDEVICE pThis = (PDACP2060EXTERNALDEVICE)pExtDev;
1844758b4ee8SAndy Ritger 
1845758b4ee8SAndy Ritger     rmStatus = readregu008_extdeviceTargeted(pGpu, pExtDev, (NvU8)NV_P2060_CONTROL, &ctrl);
1846758b4ee8SAndy Ritger 
1847758b4ee8SAndy Ritger     if ( NV_OK == rmStatus )
1848758b4ee8SAndy Ritger     {
1849758b4ee8SAndy Ritger         *pSyncPolarity = DRF_VAL(_P2060, _CONTROL, _SYNC_POLARITY, ctrl);
1850758b4ee8SAndy Ritger     }
1851758b4ee8SAndy Ritger 
1852758b4ee8SAndy Ritger     // update p2060 object
1853758b4ee8SAndy Ritger     pThis->SyncPolarity = *pSyncPolarity;
1854758b4ee8SAndy Ritger 
1855758b4ee8SAndy Ritger     return rmStatus;
1856758b4ee8SAndy Ritger }
1857758b4ee8SAndy Ritger 
1858758b4ee8SAndy Ritger NV_STATUS
gsyncSetNSync_P2060(OBJGPU * pGpu,PDACEXTERNALDEVICE pExtDev,NvU32 NSync)1859758b4ee8SAndy Ritger gsyncSetNSync_P2060
1860758b4ee8SAndy Ritger (
1861758b4ee8SAndy Ritger     OBJGPU *pGpu,
1862758b4ee8SAndy Ritger     PDACEXTERNALDEVICE pExtDev,
1863758b4ee8SAndy Ritger     NvU32 NSync
1864758b4ee8SAndy Ritger )
1865758b4ee8SAndy Ritger {
1866758b4ee8SAndy Ritger     NvU8 regNSync;
1867758b4ee8SAndy Ritger     NV_STATUS rmStatus;
1868758b4ee8SAndy Ritger     PDACP2060EXTERNALDEVICE pThis = (PDACP2060EXTERNALDEVICE)pExtDev;
1869758b4ee8SAndy Ritger 
1870758b4ee8SAndy Ritger     // update p2060 object
1871758b4ee8SAndy Ritger     pThis->NSync = NSync;
1872758b4ee8SAndy Ritger 
1873758b4ee8SAndy Ritger     rmStatus = readregu008_extdeviceTargeted(pGpu, pExtDev, (NvU8)NV_P2060_NSYNC, &regNSync);
1874758b4ee8SAndy Ritger 
1875758b4ee8SAndy Ritger     if ( NV_OK == rmStatus )
1876758b4ee8SAndy Ritger     {
1877758b4ee8SAndy Ritger         regNSync = FLD_SET_DRF_NUM(_P2060, _NSYNC, _FL, (NvU8)NSync, regNSync);
1878758b4ee8SAndy Ritger         rmStatus = writeregu008_extdeviceTargeted(pGpu, pExtDev, NV_P2060_NSYNC, regNSync);
1879758b4ee8SAndy Ritger     }
1880758b4ee8SAndy Ritger 
1881758b4ee8SAndy Ritger     return rmStatus;
1882758b4ee8SAndy Ritger }
1883758b4ee8SAndy Ritger 
1884758b4ee8SAndy Ritger NV_STATUS
gsyncGetNSync_P2060(OBJGPU * pGpu,PDACEXTERNALDEVICE pExtDev,NvU32 * pNSync)1885758b4ee8SAndy Ritger gsyncGetNSync_P2060
1886758b4ee8SAndy Ritger (
1887758b4ee8SAndy Ritger     OBJGPU *pGpu,
1888758b4ee8SAndy Ritger     PDACEXTERNALDEVICE pExtDev,
1889758b4ee8SAndy Ritger     NvU32 *pNSync
1890758b4ee8SAndy Ritger )
1891758b4ee8SAndy Ritger {
1892758b4ee8SAndy Ritger     NvU8 regNSync;
1893758b4ee8SAndy Ritger     NV_STATUS rmStatus;
1894758b4ee8SAndy Ritger     PDACP2060EXTERNALDEVICE pThis = (PDACP2060EXTERNALDEVICE)pExtDev;
1895758b4ee8SAndy Ritger 
1896758b4ee8SAndy Ritger     rmStatus = readregu008_extdeviceTargeted(pGpu, pExtDev, (NvU8)NV_P2060_NSYNC, &regNSync);
1897758b4ee8SAndy Ritger 
1898758b4ee8SAndy Ritger     if ( NV_OK == rmStatus )
1899758b4ee8SAndy Ritger     {
1900758b4ee8SAndy Ritger         *pNSync = DRF_VAL(_P2060, _NSYNC, _FL, regNSync);
1901758b4ee8SAndy Ritger     }
1902758b4ee8SAndy Ritger 
1903758b4ee8SAndy Ritger     // update p2060 object
1904758b4ee8SAndy Ritger     pThis->NSync = *pNSync;
1905758b4ee8SAndy Ritger 
1906758b4ee8SAndy Ritger     return rmStatus;
1907758b4ee8SAndy Ritger }
1908758b4ee8SAndy Ritger 
1909758b4ee8SAndy Ritger NV_STATUS
gsyncSetSyncSkew_P2060(OBJGPU * pGpu,PDACEXTERNALDEVICE pExtDev,NvU32 SyncSkew)1910758b4ee8SAndy Ritger gsyncSetSyncSkew_P2060
1911758b4ee8SAndy Ritger (
1912758b4ee8SAndy Ritger     OBJGPU *pGpu,
1913758b4ee8SAndy Ritger     PDACEXTERNALDEVICE pExtDev,
1914758b4ee8SAndy Ritger     NvU32 SyncSkew
1915758b4ee8SAndy Ritger )
1916758b4ee8SAndy Ritger {
1917758b4ee8SAndy Ritger     NvU8 SyncSkewLow, SyncSkewHigh;
1918758b4ee8SAndy Ritger     NV_STATUS rmStatus = NV_OK;
1919758b4ee8SAndy Ritger     PDACP2060EXTERNALDEVICE pThis = (PDACP2060EXTERNALDEVICE)pExtDev;
1920758b4ee8SAndy Ritger 
1921758b4ee8SAndy Ritger     // update p2060 object
1922758b4ee8SAndy Ritger     pThis->SyncSkew = SyncSkew;
1923758b4ee8SAndy Ritger 
1924e598191eSAndy Ritger     if (gsyncSupportsLargeSyncSkew_P2060(pExtDev))
1925758b4ee8SAndy Ritger     {
1926758b4ee8SAndy Ritger         SyncSkewLow  = (NvU8)((SyncSkew     ) & DRF_MASK(NV_P2060_SYNC_SKEW_LOW_VAL ));
1927758b4ee8SAndy Ritger         SyncSkewHigh = (NvU8)((SyncSkew >> 8) & DRF_MASK(NV_P2060_SYNC_SKEW_HIGH_VAL));
1928758b4ee8SAndy Ritger     }
1929758b4ee8SAndy Ritger     else
1930758b4ee8SAndy Ritger     {
1931758b4ee8SAndy Ritger         if ((SyncSkew != 0) && (SyncSkew != 1))
1932758b4ee8SAndy Ritger         {
1933758b4ee8SAndy Ritger             return NV_ERR_NOT_SUPPORTED;
1934758b4ee8SAndy Ritger         }
1935758b4ee8SAndy Ritger         else
1936758b4ee8SAndy Ritger         {
1937758b4ee8SAndy Ritger             SyncSkewLow  = (NvU8)SyncSkew;
1938758b4ee8SAndy Ritger             SyncSkewHigh = 0x00;
1939758b4ee8SAndy Ritger        }
1940758b4ee8SAndy Ritger     }
1941758b4ee8SAndy Ritger 
1942758b4ee8SAndy Ritger     rmStatus |= writeregu008_extdeviceTargeted(pGpu, pExtDev, (NvU8)NV_P2060_SYNC_SKEW_LOW, SyncSkewLow);
1943758b4ee8SAndy Ritger     rmStatus |= writeregu008_extdeviceTargeted(pGpu, pExtDev, (NvU8)NV_P2060_SYNC_SKEW_HIGH, SyncSkewHigh);
1944758b4ee8SAndy Ritger 
1945758b4ee8SAndy Ritger     return rmStatus;
1946758b4ee8SAndy Ritger 
1947758b4ee8SAndy Ritger }
1948758b4ee8SAndy Ritger 
1949758b4ee8SAndy Ritger NV_STATUS
gsyncGetSyncSkew_P2060(OBJGPU * pGpu,PDACEXTERNALDEVICE pExtDev,NvU32 * pSyncSkew)1950758b4ee8SAndy Ritger gsyncGetSyncSkew_P2060
1951758b4ee8SAndy Ritger (
1952758b4ee8SAndy Ritger     OBJGPU *pGpu,
1953758b4ee8SAndy Ritger     PDACEXTERNALDEVICE pExtDev,
1954758b4ee8SAndy Ritger     NvU32 *pSyncSkew
1955758b4ee8SAndy Ritger )
1956758b4ee8SAndy Ritger {
1957758b4ee8SAndy Ritger     NvU8 SyncSkewLow, SyncSkewHigh;
1958758b4ee8SAndy Ritger     NV_STATUS rmStatus = NV_OK;
1959758b4ee8SAndy Ritger     PDACP2060EXTERNALDEVICE pThis = (PDACP2060EXTERNALDEVICE)pExtDev;
1960758b4ee8SAndy Ritger 
1961758b4ee8SAndy Ritger     rmStatus |= readregu008_extdeviceTargeted(pGpu, pExtDev, (NvU8)NV_P2060_SYNC_SKEW_LOW,  &SyncSkewLow);
1962758b4ee8SAndy Ritger     rmStatus |= readregu008_extdeviceTargeted(pGpu, pExtDev, (NvU8)NV_P2060_SYNC_SKEW_HIGH, &SyncSkewHigh);
1963758b4ee8SAndy Ritger 
1964758b4ee8SAndy Ritger     if ( NV_OK == rmStatus )
1965758b4ee8SAndy Ritger     {
1966758b4ee8SAndy Ritger         *pSyncSkew =
1967758b4ee8SAndy Ritger             ( ((((NvU32)SyncSkewHigh) & DRF_MASK(NV_P2060_SYNC_SKEW_HIGH_VAL)) << 8 ) |
1968758b4ee8SAndy Ritger               ((((NvU32)SyncSkewLow ) & DRF_MASK(NV_P2060_SYNC_SKEW_LOW_VAL ))      ) ) ;
1969758b4ee8SAndy Ritger     }
1970758b4ee8SAndy Ritger 
1971758b4ee8SAndy Ritger     // update p2060 object
1972758b4ee8SAndy Ritger     pThis->SyncSkew = *pSyncSkew;
1973758b4ee8SAndy Ritger 
1974758b4ee8SAndy Ritger     return rmStatus;
1975758b4ee8SAndy Ritger }
1976758b4ee8SAndy Ritger 
1977758b4ee8SAndy Ritger NV_STATUS
gsyncSetSyncStartDelay_P2060(OBJGPU * pGpu,PDACEXTERNALDEVICE pExtDev,NvU32 StartDelay)1978758b4ee8SAndy Ritger gsyncSetSyncStartDelay_P2060
1979758b4ee8SAndy Ritger (
1980758b4ee8SAndy Ritger     OBJGPU *pGpu,
1981758b4ee8SAndy Ritger     PDACEXTERNALDEVICE pExtDev,
1982758b4ee8SAndy Ritger     NvU32 StartDelay
1983758b4ee8SAndy Ritger )
1984758b4ee8SAndy Ritger {
1985758b4ee8SAndy Ritger     NvU8 StartDelayLow, StartDelayHigh;
1986758b4ee8SAndy Ritger     NV_STATUS rmStatus = NV_OK;
1987758b4ee8SAndy Ritger     PDACP2060EXTERNALDEVICE pThis = (PDACP2060EXTERNALDEVICE)pExtDev;
1988758b4ee8SAndy Ritger 
1989758b4ee8SAndy Ritger     // update p2060 object
1990758b4ee8SAndy Ritger     pThis->SyncStartDelay = StartDelay;
1991758b4ee8SAndy Ritger 
1992758b4ee8SAndy Ritger     StartDelayLow = (NvU8)((StartDelay     ) & DRF_MASK(NV_P2060_START_DELAY_LOW_VAL ));
1993758b4ee8SAndy Ritger     StartDelayHigh= (NvU8)((StartDelay >> 8) & DRF_MASK(NV_P2060_START_DELAY_HIGH_VAL));
1994758b4ee8SAndy Ritger 
1995758b4ee8SAndy Ritger     rmStatus |= writeregu008_extdeviceTargeted(pGpu, pExtDev, (NvU8)NV_P2060_START_DELAY_LOW, StartDelayLow);
1996758b4ee8SAndy Ritger     rmStatus |= writeregu008_extdeviceTargeted(pGpu, pExtDev, (NvU8)NV_P2060_START_DELAY_HIGH, StartDelayHigh);
1997758b4ee8SAndy Ritger 
1998758b4ee8SAndy Ritger     return rmStatus;
1999758b4ee8SAndy Ritger }
2000758b4ee8SAndy Ritger 
2001758b4ee8SAndy Ritger NV_STATUS
gsyncGetSyncStartDelay_P2060(OBJGPU * pGpu,PDACEXTERNALDEVICE pExtDev,NvU32 * pStartDelay)2002758b4ee8SAndy Ritger gsyncGetSyncStartDelay_P2060
2003758b4ee8SAndy Ritger (
2004758b4ee8SAndy Ritger     OBJGPU *pGpu,
2005758b4ee8SAndy Ritger     PDACEXTERNALDEVICE pExtDev,
2006758b4ee8SAndy Ritger     NvU32 *pStartDelay
2007758b4ee8SAndy Ritger )
2008758b4ee8SAndy Ritger {
2009758b4ee8SAndy Ritger     NvU8 StartDelayLow, StartDelayHigh;
2010758b4ee8SAndy Ritger     NV_STATUS rmStatus = NV_OK;
2011758b4ee8SAndy Ritger     PDACP2060EXTERNALDEVICE pThis = (PDACP2060EXTERNALDEVICE)pExtDev;
2012758b4ee8SAndy Ritger 
2013758b4ee8SAndy Ritger     rmStatus |= readregu008_extdeviceTargeted(pGpu, pExtDev, (NvU8)NV_P2060_START_DELAY_LOW, &StartDelayLow);
2014758b4ee8SAndy Ritger     rmStatus |= readregu008_extdeviceTargeted(pGpu, pExtDev, (NvU8)NV_P2060_START_DELAY_HIGH, &StartDelayHigh);
2015758b4ee8SAndy Ritger 
2016758b4ee8SAndy Ritger     if ( NV_OK == rmStatus )
2017758b4ee8SAndy Ritger     {
2018758b4ee8SAndy Ritger         *pStartDelay =
2019758b4ee8SAndy Ritger             ( ((((NvU32)StartDelayHigh) & DRF_MASK(NV_P2060_START_DELAY_HIGH_VAL)) << 8 ) |
2020758b4ee8SAndy Ritger               ((((NvU32)StartDelayLow ) & DRF_MASK(NV_P2060_START_DELAY_LOW_VAL ))      ) );
2021758b4ee8SAndy Ritger     }
2022758b4ee8SAndy Ritger 
2023758b4ee8SAndy Ritger     // update p2060 object
2024758b4ee8SAndy Ritger     pThis->SyncStartDelay = *pStartDelay;
2025758b4ee8SAndy Ritger 
2026758b4ee8SAndy Ritger     return rmStatus;
2027758b4ee8SAndy Ritger }
2028758b4ee8SAndy Ritger 
2029758b4ee8SAndy Ritger /*
2030758b4ee8SAndy Ritger  * check if housesync is present or not.
2031758b4ee8SAndy Ritger  */
2032758b4ee8SAndy Ritger static NV_STATUS
gsyncReadHouseSignalPresent_P2060(OBJGPU * pGpu,PDACEXTERNALDEVICE pExtDev,NvBool bTestSyncLoss,NvU32 * pVal)2033758b4ee8SAndy Ritger gsyncReadHouseSignalPresent_P2060
2034758b4ee8SAndy Ritger (
2035758b4ee8SAndy Ritger     OBJGPU *pGpu,
2036758b4ee8SAndy Ritger     PDACEXTERNALDEVICE pExtDev,
2037758b4ee8SAndy Ritger     NvBool bTestSyncLoss,
2038758b4ee8SAndy Ritger     NvU32 *pVal
2039758b4ee8SAndy Ritger )
2040758b4ee8SAndy Ritger {
2041758b4ee8SAndy Ritger     PDACP2060EXTERNALDEVICE pThis = (PDACP2060EXTERNALDEVICE)pExtDev;
2042758b4ee8SAndy Ritger     NvU8 regStatus2;
2043758b4ee8SAndy Ritger     NvU32 regStatus = GetP2060GpuSnapshot(pGpu,pThis);
2044758b4ee8SAndy Ritger     NV_STATUS rmStatus = NV_OK;
2045758b4ee8SAndy Ritger 
2046758b4ee8SAndy Ritger     NV_ASSERT_OR_RETURN(pGpu, NV_ERR_GENERIC);
2047758b4ee8SAndy Ritger 
2048758b4ee8SAndy Ritger     if (bTestSyncLoss && FLD_TEST_DRF(_P2060, _STATUS, _SYNC_LOSS, _TRUE, (NvU32)regStatus))
2049758b4ee8SAndy Ritger     {
2050758b4ee8SAndy Ritger         rmStatus |= gsyncUpdateGsyncStatusSnapshot_P2060(pGpu, pExtDev);
2051758b4ee8SAndy Ritger 
2052758b4ee8SAndy Ritger         if ( NV_OK != rmStatus )
2053758b4ee8SAndy Ritger             return rmStatus;
2054758b4ee8SAndy Ritger 
2055758b4ee8SAndy Ritger         if (FLD_TEST_DRF(_P2060, _STATUS, _SYNC_LOSS, _TRUE, GetP2060GpuSnapshot(pGpu,pThis)))
2056758b4ee8SAndy Ritger         {
2057758b4ee8SAndy Ritger             *pVal = 0; // bTestSyncLoss and (SYNC_LOSS == NV_TRUE)
2058758b4ee8SAndy Ritger         }
2059758b4ee8SAndy Ritger     }
2060758b4ee8SAndy Ritger     else
2061758b4ee8SAndy Ritger     {
2062758b4ee8SAndy Ritger         rmStatus = readregu008_extdeviceTargeted(pGpu, (PDACEXTERNALDEVICE)pThis,
2063758b4ee8SAndy Ritger                                                  (NvU8)NV_P2060_STATUS2, &regStatus2);
2064758b4ee8SAndy Ritger         if ( NV_OK != rmStatus )
2065758b4ee8SAndy Ritger             return rmStatus;
2066758b4ee8SAndy Ritger 
2067758b4ee8SAndy Ritger         *pVal = !!(DRF_VAL(_P2060, _STATUS2, _HS_DETECT, (NvU32)regStatus2));
2068758b4ee8SAndy Ritger     }
2069758b4ee8SAndy Ritger 
2070758b4ee8SAndy Ritger     return rmStatus;
2071758b4ee8SAndy Ritger }
2072758b4ee8SAndy Ritger 
2073758b4ee8SAndy Ritger /*
2074758b4ee8SAndy Ritger  * This function returns whether there is a sync source present.
2075758b4ee8SAndy Ritger  *
2076eb5c7665SAndy Ritger  * If framelock is not enabled, the only sync source possible is an external signal.
2077758b4ee8SAndy Ritger  *
2078eb5c7665SAndy Ritger  * If framelock is enabled, a local master may be providing the sync signal, or
2079eb5c7665SAndy Ritger  * housesync may be providing a signal via a local master, or we may need to
2080eb5c7665SAndy Ritger  * poll for an external signal.
2081758b4ee8SAndy Ritger  */
2082758b4ee8SAndy Ritger static NV_STATUS
gsyncReadIsSyncDetected_P2060(OBJGPU * pGpu,PDACEXTERNALDEVICE pExtDev,NvU32 * pVal)2083758b4ee8SAndy Ritger gsyncReadIsSyncDetected_P2060
2084758b4ee8SAndy Ritger (
2085758b4ee8SAndy Ritger     OBJGPU *pGpu,
2086758b4ee8SAndy Ritger     PDACEXTERNALDEVICE pExtDev,
2087758b4ee8SAndy Ritger     NvU32 *pVal
2088758b4ee8SAndy Ritger )
2089758b4ee8SAndy Ritger {
2090758b4ee8SAndy Ritger     PDACP2060EXTERNALDEVICE pThis = (PDACP2060EXTERNALDEVICE)pExtDev;
2091eb5c7665SAndy Ritger     KernelDisplay *pKernelDisplay = GPU_GET_KERNEL_DISPLAY(pGpu);
2092eb5c7665SAndy Ritger     NvU32 numHeads = kdispGetNumHeads(pKernelDisplay);
2093eb5c7665SAndy Ritger 
2094eb5c7665SAndy Ritger     // Assume we are not synced, unless we match one of the cases below
2095eb5c7665SAndy Ritger     *pVal = NV_FALSE;
2096758b4ee8SAndy Ritger 
2097758b4ee8SAndy Ritger     NV_ASSERT_OR_RETURN(pGpu, NV_ERR_GENERIC);
2098758b4ee8SAndy Ritger 
2099758b4ee8SAndy Ritger     if (!gsyncIsFrameLocked_P2060(pThis))
2100758b4ee8SAndy Ritger     {
2101758b4ee8SAndy Ritger         NvU8 regStatus;
2102758b4ee8SAndy Ritger 
2103eb5c7665SAndy Ritger         //
2104eb5c7665SAndy Ritger         // Framelock is not enabled; read the NV_P2060_STATUS register to get
2105eb5c7665SAndy Ritger         // the external sync status
2106eb5c7665SAndy Ritger         //
2107eb5c7665SAndy Ritger         NV_ASSERT_OK_OR_RETURN(
2108eb5c7665SAndy Ritger             readregu008_extdeviceTargeted(pGpu, pExtDev, (NvU8)NV_P2060_STATUS, &regStatus));
2109eb5c7665SAndy Ritger         *pVal = FLD_TEST_DRF(_P2060, _STATUS, _SYNC_LOSS, _FALSE, regStatus);
2110758b4ee8SAndy Ritger     }
2111758b4ee8SAndy Ritger     else
2112758b4ee8SAndy Ritger     {
2113eb5c7665SAndy Ritger         NvU32 iface, head, tempIface, tempHead;
2114eb5c7665SAndy Ritger 
2115eb5c7665SAndy Ritger         NV_ASSERT_OK_OR_RETURN(GetP2060GpuLocation(pGpu, pThis, &iface));
2116eb5c7665SAndy Ritger 
2117eb5c7665SAndy Ritger 
2118eb5c7665SAndy Ritger         for (head = 0; head < numHeads; head++)
2119758b4ee8SAndy Ritger         {
2120eb5c7665SAndy Ritger             // Check if we're slaved to another master head in the same system
2121eb5c7665SAndy Ritger             if (pThis->Iface[iface].Sync.LocalSlave[head])
2122eb5c7665SAndy Ritger             {
2123eb5c7665SAndy Ritger                 for (tempIface = 0; tempIface < NV_P2060_MAX_IFACES_PER_GSYNC; tempIface++)
2124eb5c7665SAndy Ritger                 {
2125eb5c7665SAndy Ritger                     for (tempHead = 0; tempHead < numHeads; tempHead++)
2126eb5c7665SAndy Ritger                     {
2127eb5c7665SAndy Ritger                         if (pThis->Iface[tempIface].Sync.Master[tempHead])
2128eb5c7665SAndy Ritger                         {
2129eb5c7665SAndy Ritger                             //
2130eb5c7665SAndy Ritger                             // If we're slaved to another local head, we are
2131eb5c7665SAndy Ritger                             // receiving a sync signal from it. (But if it uses
2132eb5c7665SAndy Ritger                             // housesync, then it must also be receiving housesync.)
2133eb5c7665SAndy Ritger                             //
2134eb5c7665SAndy Ritger                             if (!pThis->Iface[tempIface].Sync.Slaved[tempHead])
2135eb5c7665SAndy Ritger                             {
2136eb5c7665SAndy Ritger                                 *pVal = NV_TRUE;
2137eb5c7665SAndy Ritger                             }
2138eb5c7665SAndy Ritger                             else
2139eb5c7665SAndy Ritger                             {
2140eb5c7665SAndy Ritger                                 NV_ASSERT_OK_OR_RETURN(
2141eb5c7665SAndy Ritger                                     gsyncReadHouseSignalPresent_P2060(pGpu, pExtDev,
2142eb5c7665SAndy Ritger                                                                       NV_TRUE, pVal));
2143eb5c7665SAndy Ritger                             }
2144eb5c7665SAndy Ritger                         }
2145eb5c7665SAndy Ritger                     }
2146eb5c7665SAndy Ritger                 }
2147eb5c7665SAndy Ritger                 break;
2148758b4ee8SAndy Ritger             }
2149758b4ee8SAndy Ritger 
2150eb5c7665SAndy Ritger             if (pThis->Iface[iface].Sync.Master[head])
2151eb5c7665SAndy Ritger             {
2152758b4ee8SAndy Ritger                 //
2153eb5c7665SAndy Ritger                 // A master head with no house signal has its own sync signal.
2154eb5c7665SAndy Ritger                 // A master head with house signal has a sync signal if the
2155eb5c7665SAndy Ritger                 // house signal is present.
2156758b4ee8SAndy Ritger                 //
2157eb5c7665SAndy Ritger                 if (pThis->Iface[iface].Sync.Slaved[head])
2158eb5c7665SAndy Ritger                 {
2159eb5c7665SAndy Ritger                     NV_ASSERT_OK_OR_RETURN(
2160eb5c7665SAndy Ritger                         gsyncReadHouseSignalPresent_P2060(pGpu, pExtDev, NV_TRUE, pVal));
2161eb5c7665SAndy Ritger                     break;
2162eb5c7665SAndy Ritger                 }
2163eb5c7665SAndy Ritger                 else
2164eb5c7665SAndy Ritger                 {
2165eb5c7665SAndy Ritger                     *pVal = NV_TRUE;
2166eb5c7665SAndy Ritger                     break;
2167eb5c7665SAndy Ritger                 }
2168758b4ee8SAndy Ritger             }
2169758b4ee8SAndy Ritger 
2170eb5c7665SAndy Ritger             if (pThis->Iface[iface].Sync.Slaved[head])
2171eb5c7665SAndy Ritger             {
2172eb5c7665SAndy Ritger                 NvU8 regStatus;
2173eb5c7665SAndy Ritger 
2174eb5c7665SAndy Ritger                 //
2175eb5c7665SAndy Ritger                 // A slaved head with external master signal must poll
2176eb5c7665SAndy Ritger                 // NV_P2060_STATUS_SYNC_LOSS for sync status.
2177eb5c7665SAndy Ritger                 //
2178eb5c7665SAndy Ritger                 NV_ASSERT_OK_OR_RETURN(
2179eb5c7665SAndy Ritger                     readregu008_extdeviceTargeted(pGpu, pExtDev, (NvU8)NV_P2060_STATUS, &regStatus));
2180eb5c7665SAndy Ritger                 *pVal = FLD_TEST_DRF(_P2060, _STATUS, _SYNC_LOSS, _FALSE, regStatus);
2181eb5c7665SAndy Ritger                 break;
2182eb5c7665SAndy Ritger             }
2183eb5c7665SAndy Ritger         }
2184eb5c7665SAndy Ritger     }
2185eb5c7665SAndy Ritger 
2186eb5c7665SAndy Ritger     return NV_OK;
2187758b4ee8SAndy Ritger }
2188758b4ee8SAndy Ritger 
2189758b4ee8SAndy Ritger /*
2190758b4ee8SAndy Ritger  * Check if stereo is locked or not.
2191758b4ee8SAndy Ritger  *
2192758b4ee8SAndy Ritger  * stereo is locked means
2193758b4ee8SAndy Ritger  * - a framelock master signal is available as reference
2194758b4ee8SAndy Ritger  * - sync to this master signal has been gained
2195758b4ee8SAndy Ritger  * - master and local gpu both have either stereo enabled or disabled
2196758b4ee8SAndy Ritger  * - master and local stereo signal is in phase (in case it's enabled)
2197758b4ee8SAndy Ritger  */
2198758b4ee8SAndy Ritger static NV_STATUS
gsyncReadStereoLocked_P2060(OBJGPU * pGpu,PDACEXTERNALDEVICE pExtDev,NvU32 * pVal)2199758b4ee8SAndy Ritger gsyncReadStereoLocked_P2060
2200758b4ee8SAndy Ritger (
2201758b4ee8SAndy Ritger     OBJGPU *pGpu,
2202758b4ee8SAndy Ritger     PDACEXTERNALDEVICE pExtDev,
2203758b4ee8SAndy Ritger     NvU32 *pVal
2204758b4ee8SAndy Ritger )
2205758b4ee8SAndy Ritger {
2206758b4ee8SAndy Ritger     PDACP2060EXTERNALDEVICE pThis = (PDACP2060EXTERNALDEVICE)pExtDev;
2207758b4ee8SAndy Ritger     NV_STATUS rmStatus = NV_ERR_GENERIC;
2208758b4ee8SAndy Ritger 
2209758b4ee8SAndy Ritger     if (pVal)
2210758b4ee8SAndy Ritger     {
2211758b4ee8SAndy Ritger         NvU32 iface;
2212758b4ee8SAndy Ritger 
2213758b4ee8SAndy Ritger         // Default return is stereo not locked.
2214758b4ee8SAndy Ritger         *pVal = 0;
2215758b4ee8SAndy Ritger 
2216758b4ee8SAndy Ritger         // which gpu's interface are we talking to?
2217758b4ee8SAndy Ritger         rmStatus = GetP2060GpuLocation(pGpu, pThis, &iface);
2218758b4ee8SAndy Ritger 
2219758b4ee8SAndy Ritger         if (NV_OK == rmStatus)
2220758b4ee8SAndy Ritger         {
2221758b4ee8SAndy Ritger             // stereo status reporting only makes sense if we've gained sync.
2222758b4ee8SAndy Ritger             if (pThis->Iface[iface].gainedSync)
2223758b4ee8SAndy Ritger             {
2224758b4ee8SAndy Ritger                 NvU32 regStatus = GetP2060GpuSnapshot(pGpu,pThis);
2225758b4ee8SAndy Ritger 
2226758b4ee8SAndy Ritger                 if ((NV_P2060_STATUS_MSTR_STEREO_NOT_ACTIVE ==
2227758b4ee8SAndy Ritger                     DRF_VAL(_P2060, _STATUS, _MSTR_STEREO, regStatus)) &&
2228758b4ee8SAndy Ritger                     (NV_P2060_STATUS_GPU_STEREO_NOT_ACTIVE ==
2229758b4ee8SAndy Ritger                     DRF_VAL(_P2060, _STATUS, _GPU_STEREO, regStatus)))
2230758b4ee8SAndy Ritger                 {
2231758b4ee8SAndy Ritger                     //
2232758b4ee8SAndy Ritger                     // If neither local nor master stereo is enabled
2233758b4ee8SAndy Ritger                     // stereo is locked.
2234758b4ee8SAndy Ritger                     //
2235758b4ee8SAndy Ritger                     *pVal = 1;
2236758b4ee8SAndy Ritger                 }
2237758b4ee8SAndy Ritger                 else
2238758b4ee8SAndy Ritger                 {
2239758b4ee8SAndy Ritger                     //
2240758b4ee8SAndy Ritger                     // If local or master stereo signals are present,
2241758b4ee8SAndy Ritger                     // return back P358s stereo_lock reporting.
2242758b4ee8SAndy Ritger                     //
2243758b4ee8SAndy Ritger                     *pVal = (NV_P2060_STATUS_STEREO_LOCK ==
2244758b4ee8SAndy Ritger                         DRF_VAL(_P2060, _STATUS, _STEREO, regStatus));
2245758b4ee8SAndy Ritger                 }
2246758b4ee8SAndy Ritger             }
2247758b4ee8SAndy Ritger         }
2248758b4ee8SAndy Ritger     }
2249758b4ee8SAndy Ritger 
2250758b4ee8SAndy Ritger     return rmStatus;
2251758b4ee8SAndy Ritger }
2252758b4ee8SAndy Ritger 
2253eb5c7665SAndy Ritger //
2254eb5c7665SAndy Ritger // Check if we are in sync, i.e. we supply the master sync signal or are servoed
2255eb5c7665SAndy Ritger // to the master sync signal. The servo should be stable for about 5 seconds if
2256eb5c7665SAndy Ritger // the signal is external (i.e. use the gainedSync value which already maintains
2257eb5c7665SAndy Ritger // this.)
2258eb5c7665SAndy Ritger //
2259758b4ee8SAndy Ritger static NV_STATUS
gsyncReadIsTiming_P2060(OBJGPU * pGpu,PDACEXTERNALDEVICE pExtDev,NvU32 * pVal)2260758b4ee8SAndy Ritger gsyncReadIsTiming_P2060
2261758b4ee8SAndy Ritger (
2262758b4ee8SAndy Ritger     OBJGPU *pGpu,
2263758b4ee8SAndy Ritger     PDACEXTERNALDEVICE pExtDev,
2264758b4ee8SAndy Ritger     NvU32 *pVal
2265758b4ee8SAndy Ritger )
2266758b4ee8SAndy Ritger {
2267758b4ee8SAndy Ritger     PDACP2060EXTERNALDEVICE pThis = (PDACP2060EXTERNALDEVICE)pExtDev;
2268eb5c7665SAndy Ritger     NvU32 iface;
2269758b4ee8SAndy Ritger 
2270eb5c7665SAndy Ritger     *pVal = NV_FALSE;
2271758b4ee8SAndy Ritger 
2272eb5c7665SAndy Ritger     NV_ASSERT_OK_OR_RETURN(GetP2060GpuLocation(pGpu, pThis, &iface));
2273758b4ee8SAndy Ritger 
2274eb5c7665SAndy Ritger     *pVal = pThis->Iface[iface].gainedSync;
2275758b4ee8SAndy Ritger 
2276eb5c7665SAndy Ritger     return NV_OK;
2277758b4ee8SAndy Ritger }
2278758b4ee8SAndy Ritger 
2279758b4ee8SAndy Ritger 
2280758b4ee8SAndy Ritger /*
2281758b4ee8SAndy Ritger  * Program P2060 Master for Framelock.
2282758b4ee8SAndy Ritger  */
2283758b4ee8SAndy Ritger static NV_STATUS
gsyncProgramMaster_P2060(OBJGPU * pGpu,PDACP2060EXTERNALDEVICE pThis,NvU32 Master,NvBool bRetainMaster,NvBool skipSwapBarrierWar)2284758b4ee8SAndy Ritger gsyncProgramMaster_P2060
2285758b4ee8SAndy Ritger (
2286758b4ee8SAndy Ritger     OBJGPU *pGpu,
2287758b4ee8SAndy Ritger     PDACP2060EXTERNALDEVICE pThis,
2288758b4ee8SAndy Ritger     NvU32 Master,
2289758b4ee8SAndy Ritger     NvBool bRetainMaster,
2290758b4ee8SAndy Ritger     NvBool skipSwapBarrierWar
2291758b4ee8SAndy Ritger )
2292758b4ee8SAndy Ritger {
2293758b4ee8SAndy Ritger     KernelDisplay  *pKernelDisplay = GPU_GET_KERNEL_DISPLAY(pGpu);
2294758b4ee8SAndy Ritger     NvU32       DisplayIds[OBJ_MAX_HEADS];
2295758b4ee8SAndy Ritger     NvU32       iface, head, index;
2296758b4ee8SAndy Ritger     NvU8        ctrl = 0;
2297758b4ee8SAndy Ritger     NvBool      bTestModePresent;
2298758b4ee8SAndy Ritger     NvBool      bHouseSelect, bEnableMaster = (0 != Master);
2299758b4ee8SAndy Ritger     NvBool      bGPUAlreadyMaster;
2300758b4ee8SAndy Ritger     NvBool      bQSyncAlreadyMaster;
2301758b4ee8SAndy Ritger     NV_STATUS   rmStatus = NV_OK;
2302758b4ee8SAndy Ritger     NvU32 numHeads = kdispGetNumHeads(pKernelDisplay);
2303758b4ee8SAndy Ritger 
2304758b4ee8SAndy Ritger     if ( Master && bRetainMaster)
2305758b4ee8SAndy Ritger     {
2306758b4ee8SAndy Ritger         for (iface = 0; iface < NV_P2060_MAX_IFACES_PER_GSYNC; iface++)
2307758b4ee8SAndy Ritger         {
2308758b4ee8SAndy Ritger             for ( head = 0; head < numHeads; head++ )
2309758b4ee8SAndy Ritger             {
2310758b4ee8SAndy Ritger                 if ( pThis->Iface[iface].Sync.Master[head] )
2311758b4ee8SAndy Ritger                 {
2312758b4ee8SAndy Ritger                     pThis->Iface[iface].Sync.Master[head] = 0;
2313758b4ee8SAndy Ritger                     pThis->Iface[iface].Sync.Slaved[head] = 0;
2314758b4ee8SAndy Ritger                     pThis->Iface[iface].Sync.LocalSlave[head] = 0;
2315758b4ee8SAndy Ritger                 }
2316758b4ee8SAndy Ritger             }
2317758b4ee8SAndy Ritger         }
2318758b4ee8SAndy Ritger         return rmStatus;
2319758b4ee8SAndy Ritger     }
2320758b4ee8SAndy Ritger 
2321758b4ee8SAndy Ritger     // This utility fn returns display id's associated with each head.
2322758b4ee8SAndy Ritger     extdevGetBoundHeadsAndDisplayIds(pGpu, DisplayIds);
2323758b4ee8SAndy Ritger 
2324758b4ee8SAndy Ritger     // which gpu's are we talking to?
2325758b4ee8SAndy Ritger     rmStatus = GetP2060GpuLocation(pGpu, pThis, &iface);
2326758b4ee8SAndy Ritger     if (NV_OK != rmStatus)
2327758b4ee8SAndy Ritger     {
2328758b4ee8SAndy Ritger         NV_PRINTF(LEVEL_ERROR,
2329758b4ee8SAndy Ritger                   "Failed to get Gpu location. Can not program Master.\n");
2330758b4ee8SAndy Ritger         return rmStatus;
2331758b4ee8SAndy Ritger     }
2332758b4ee8SAndy Ritger 
2333758b4ee8SAndy Ritger     // no failure allowed!
2334758b4ee8SAndy Ritger     rmStatus = readregu008_extdeviceTargeted(pGpu, (PDACEXTERNALDEVICE)pThis,
2335758b4ee8SAndy Ritger                                             (NvU8)NV_P2060_CONTROL, &ctrl);
2336758b4ee8SAndy Ritger     if ((NV_OK != rmStatus))
2337758b4ee8SAndy Ritger     {
2338758b4ee8SAndy Ritger         NV_PRINTF(LEVEL_ERROR,
2339758b4ee8SAndy Ritger                   "Failed to read Ctrl data. Can not program Master.\n");
2340758b4ee8SAndy Ritger         return rmStatus;
2341758b4ee8SAndy Ritger     }
2342758b4ee8SAndy Ritger 
2343758b4ee8SAndy Ritger     // Check if TEST MODE present
2344758b4ee8SAndy Ritger     bTestModePresent = FLD_TEST_DRF(_P2060, _CONTROL, _TEST_MODE, _ON, (NvU32)ctrl);
2345758b4ee8SAndy Ritger 
2346758b4ee8SAndy Ritger     // Check for House sync select as sync source
2347758b4ee8SAndy Ritger     bHouseSelect = FLD_TEST_DRF(_P2060, _CONTROL, _SYNC_SELECT, _HOUSE, (NvU32)ctrl);
2348758b4ee8SAndy Ritger 
2349758b4ee8SAndy Ritger     rmStatus = GetP2060ConnectorIndexFromGpu(pGpu, pThis, &index);
2350758b4ee8SAndy Ritger     if (NV_OK != rmStatus)
2351758b4ee8SAndy Ritger     {
2352758b4ee8SAndy Ritger         NV_PRINTF(LEVEL_ERROR,
2353758b4ee8SAndy Ritger                   "Failed to get connector index for Gpu. Can not program Master.\n");
2354758b4ee8SAndy Ritger         return rmStatus;
2355758b4ee8SAndy Ritger     }
2356758b4ee8SAndy Ritger     //
2357758b4ee8SAndy Ritger     // For P2060, Already Mastership based on FPGA -> I_AM_MASTER + GPU -> TIMING SOURCE.
2358758b4ee8SAndy Ritger     // First check for display is already Master or not i.e. GPU is TS or not.
2359758b4ee8SAndy Ritger     // Then check for FPGA board is already Master or not.
2360758b4ee8SAndy Ritger     //
2361758b4ee8SAndy Ritger     bGPUAlreadyMaster = (DRF_VAL(_P2060, _CONTROL, _SYNC_SRC, (NvU32)ctrl) == index);
2362758b4ee8SAndy Ritger     bQSyncAlreadyMaster = FLD_TEST_DRF(_P2060, _CONTROL, _I_AM, _MASTER, (NvU32)ctrl);
2363758b4ee8SAndy Ritger 
2364758b4ee8SAndy Ritger     // In case of Passthru mode, Qsync board can be shared across multiple VMs.
2365758b4ee8SAndy Ritger     // If Qsync board is already master, then only TS Gpu should be allowed to change it's mastership.
2366758b4ee8SAndy Ritger     // Bail out if non TS GPU tries to change it.
2367758b4ee8SAndy Ritger     if (IS_PASSTHRU(pGpu) && (bQSyncAlreadyMaster & !bGPUAlreadyMaster))
2368758b4ee8SAndy Ritger     {
2369758b4ee8SAndy Ritger         return rmStatus;
2370758b4ee8SAndy Ritger     }
2371758b4ee8SAndy Ritger 
2372758b4ee8SAndy Ritger     if (bQSyncAlreadyMaster != bEnableMaster)
2373758b4ee8SAndy Ritger     {
2374758b4ee8SAndy Ritger         if (pThis->ExternalDevice.deviceRev == DAC_EXTERNAL_DEVICE_REV_NONE)
2375758b4ee8SAndy Ritger         {
2376758b4ee8SAndy Ritger             NV_PRINTF(LEVEL_ERROR,
2377758b4ee8SAndy Ritger                       "Failed to read NV_P2060_FPGA. Can not program Master.\n");
2378758b4ee8SAndy Ritger             return rmStatus;
2379758b4ee8SAndy Ritger         }
2380758b4ee8SAndy Ritger 
2381758b4ee8SAndy Ritger         if (bEnableMaster)
2382758b4ee8SAndy Ritger         {
2383758b4ee8SAndy Ritger             rmStatus = gsyncApplyStereoPinAlwaysHiWar(pGpu, (PDACEXTERNALDEVICE)pThis);
2384758b4ee8SAndy Ritger 
2385758b4ee8SAndy Ritger             if (NV_OK != rmStatus)
2386758b4ee8SAndy Ritger             {
2387758b4ee8SAndy Ritger                 NV_PRINTF(LEVEL_ERROR,
2388758b4ee8SAndy Ritger                           "Failed to drive stereo output pin for bug3362661.\n");
2389758b4ee8SAndy Ritger             }
2390758b4ee8SAndy Ritger             //
2391758b4ee8SAndy Ritger             // GPU will now be TS - Mark sync source for GPU on derived index.
2392758b4ee8SAndy Ritger             // This needs to be done first as only TS can write I_AM_MASTER bit.
2393758b4ee8SAndy Ritger             //
2394758b4ee8SAndy Ritger             ctrl = FLD_SET_DRF_NUM(_P2060, _CONTROL, _SYNC_SRC, (NvU8)index, ctrl);
2395758b4ee8SAndy Ritger             rmStatus |= writeregu008_extdeviceTargeted(pGpu, (PDACEXTERNALDEVICE) pThis,
2396758b4ee8SAndy Ritger                                                       (NvU8)NV_P2060_CONTROL, ctrl);
2397758b4ee8SAndy Ritger             if (NV_OK != rmStatus)
2398758b4ee8SAndy Ritger             {
2399758b4ee8SAndy Ritger                 NV_PRINTF(LEVEL_ERROR,
2400758b4ee8SAndy Ritger                           "Failed to write SYNC_SRC. Can not program Master.\n");
2401758b4ee8SAndy Ritger                 return rmStatus;
2402758b4ee8SAndy Ritger             }
2403758b4ee8SAndy Ritger         }
2404758b4ee8SAndy Ritger 
2405758b4ee8SAndy Ritger         if (bTestModePresent)
2406758b4ee8SAndy Ritger         {
2407758b4ee8SAndy Ritger             // Clear the TEST mode bit before handling enable/disable master.
2408758b4ee8SAndy Ritger             ctrl = FLD_SET_DRF(_P2060, _CONTROL, _TEST_MODE, _OFF, ctrl);
2409758b4ee8SAndy Ritger 
2410758b4ee8SAndy Ritger             if (!bEnableMaster)
2411758b4ee8SAndy Ritger             {
2412758b4ee8SAndy Ritger                 //
2413758b4ee8SAndy Ritger                 // Clear the TEST mode bit before disabling master as TEST mode
2414758b4ee8SAndy Ritger                 // can only be modified by the GPU TS under FPGA master mode.
2415758b4ee8SAndy Ritger                 //
2416758b4ee8SAndy Ritger                 rmStatus |= writeregu008_extdeviceTargeted(pGpu, (PDACEXTERNALDEVICE) pThis,
2417758b4ee8SAndy Ritger                                                         (NvU8)NV_P2060_CONTROL, ctrl);
2418758b4ee8SAndy Ritger                 osDelay(30); // Add delay of 30 ms as we are turning OFF TEST mode.
2419758b4ee8SAndy Ritger             }
2420758b4ee8SAndy Ritger         }
2421758b4ee8SAndy Ritger 
2422758b4ee8SAndy Ritger         // Gsync/FPGA card will be master or not based on bEnableMaster.
2423758b4ee8SAndy Ritger         ctrl = FLD_SET_DRF_NUM(_P2060, _CONTROL, _I_AM, (NvU8)bEnableMaster, ctrl);
2424758b4ee8SAndy Ritger         rmStatus |= writeregu008_extdeviceTargeted(pGpu, (PDACEXTERNALDEVICE) pThis,
2425758b4ee8SAndy Ritger                                                   (NvU8)NV_P2060_CONTROL, ctrl);
2426758b4ee8SAndy Ritger         if (NV_OK != rmStatus)
2427758b4ee8SAndy Ritger         {
2428758b4ee8SAndy Ritger             NV_PRINTF(LEVEL_ERROR,
2429758b4ee8SAndy Ritger                       "Failed to write I_AM_MSTR. Can not program Master.\n");
2430758b4ee8SAndy Ritger             return rmStatus;
2431758b4ee8SAndy Ritger         }
2432758b4ee8SAndy Ritger 
2433758b4ee8SAndy Ritger         //
2434758b4ee8SAndy Ritger         // Now we have updated Master status of Gsync board, wait for some time. This will allow FPGA to
2435758b4ee8SAndy Ritger         // reflect state-change in other registers e.g portStat, Frame Rate etc. Refer Bug 1053022.
2436758b4ee8SAndy Ritger         //
2437758b4ee8SAndy Ritger         osDelay(200);
2438758b4ee8SAndy Ritger 
2439758b4ee8SAndy Ritger         if (bEnableMaster)
2440758b4ee8SAndy Ritger         {
2441758b4ee8SAndy Ritger             // Remember the desired skipSwapBarrierWar setting for enable master calls.
2442758b4ee8SAndy Ritger             pThis->Iface[iface].skipSwapBarrierWar = skipSwapBarrierWar;
2443758b4ee8SAndy Ritger         }
2444758b4ee8SAndy Ritger         else
2445758b4ee8SAndy Ritger         {
2446758b4ee8SAndy Ritger             // Fetch the real skipSwapBarrierWar value from cache in case of an unsync call.
2447758b4ee8SAndy Ritger             skipSwapBarrierWar = pThis->Iface[iface].skipSwapBarrierWar;
2448758b4ee8SAndy Ritger             // And reset the cached value.
2449758b4ee8SAndy Ritger             pThis->Iface[iface].skipSwapBarrierWar = NV_FALSE;
2450758b4ee8SAndy Ritger         }
2451758b4ee8SAndy Ritger 
2452758b4ee8SAndy Ritger         //
2453758b4ee8SAndy Ritger         // Fpga revisions <= 5 need to sw the swapbarrier on the framelock master
2454758b4ee8SAndy Ritger         // to drive the swap_rdy signal. This can be overridden by skipSwapBarrierWar.
2455758b4ee8SAndy Ritger         //
2456758b4ee8SAndy Ritger         if ((!skipSwapBarrierWar) &&
2457758b4ee8SAndy Ritger             needsMasterBarrierWar(&pThis->ExternalDevice))
2458758b4ee8SAndy Ritger         {
2459758b4ee8SAndy Ritger             // enable/disable SwapRdy for GPU during enable/disable of Framelock Master.
2460758b4ee8SAndy Ritger             rmStatus = gsyncUpdateSwapRdyConnectionForGpu_P2060(pGpu, pThis, bEnableMaster);
2461758b4ee8SAndy Ritger             if (NV_OK != rmStatus)
2462758b4ee8SAndy Ritger             {
2463758b4ee8SAndy Ritger                 NV_PRINTF(LEVEL_ERROR,
2464758b4ee8SAndy Ritger                           "Failed to update SwapRdyEnable. Can not program Master.\n");
2465758b4ee8SAndy Ritger                 return rmStatus;
2466758b4ee8SAndy Ritger             }
2467758b4ee8SAndy Ritger         }
2468758b4ee8SAndy Ritger     }
2469758b4ee8SAndy Ritger 
2470758b4ee8SAndy Ritger     // now we're ready to let the software know about it.
2471758b4ee8SAndy Ritger     for ( head = 0; head < numHeads; head++ )
2472758b4ee8SAndy Ritger     {
2473758b4ee8SAndy Ritger         // is this head the desired master, or are we are disabling mastership?
2474758b4ee8SAndy Ritger         // If mastership is currently disabled, don't touch cache as this could destroy slave values.0
2475758b4ee8SAndy Ritger         if ((Master & DisplayIds[head]) || (!bEnableMaster && bQSyncAlreadyMaster))
2476758b4ee8SAndy Ritger         {
2477758b4ee8SAndy Ritger             pThis->Iface[iface].Sync.Master[head] = (bEnableMaster);
2478758b4ee8SAndy Ritger             pThis->Iface[iface].Sync.Slaved[head] = (bEnableMaster && bHouseSelect);
2479758b4ee8SAndy Ritger 
2480758b4ee8SAndy Ritger             gsyncProgramFramelockEnable_P2060(pGpu, pThis, iface, bEnableMaster);
2481758b4ee8SAndy Ritger         }
2482758b4ee8SAndy Ritger          else
2483758b4ee8SAndy Ritger         {
2484758b4ee8SAndy Ritger             // we are setting a master, but it's not on this head, so just to be safe:
2485758b4ee8SAndy Ritger             pThis->Iface[iface].Sync.Master[head] = 0;
2486758b4ee8SAndy Ritger         }
2487758b4ee8SAndy Ritger     }
2488758b4ee8SAndy Ritger 
2489758b4ee8SAndy Ritger     if (!bEnableMaster && !gsyncIsFrameLocked_P2060(pThis))
2490758b4ee8SAndy Ritger     {
2491758b4ee8SAndy Ritger         // Disable Framelock interrupts as board is not framelocked now.
2492758b4ee8SAndy Ritger         gsyncDisableFrameLockInterrupt_P2060((PDACEXTERNALDEVICE)pThis);
2493758b4ee8SAndy Ritger 
2494758b4ee8SAndy Ritger         rmStatus = gsyncUnApplyStereoPinAlwaysHiWar(pGpu);
2495758b4ee8SAndy Ritger 
2496758b4ee8SAndy Ritger         if (NV_OK != rmStatus)
2497758b4ee8SAndy Ritger         {
2498758b4ee8SAndy Ritger             NV_PRINTF(LEVEL_ERROR,
2499758b4ee8SAndy Ritger                       "Failed to drive stereo output pin for bug3362661.\n");
2500758b4ee8SAndy Ritger         }
2501758b4ee8SAndy Ritger     }
2502758b4ee8SAndy Ritger 
2503758b4ee8SAndy Ritger     if (!IsSLIEnabled(pGpu))
2504758b4ee8SAndy Ritger     {
2505758b4ee8SAndy Ritger         NvU32 otherGpuId;
2506758b4ee8SAndy Ritger         OBJGPU   *pOtherGpu;
2507758b4ee8SAndy Ritger         RM_API   *pRmApi;
2508758b4ee8SAndy Ritger         NvU32     hClient;
2509758b4ee8SAndy Ritger         NvU32     hSubdevice;
2510758b4ee8SAndy Ritger         NvU32 Slaves, drOut, drIn;
2511758b4ee8SAndy Ritger         NvU32 tempIface;
2512758b4ee8SAndy Ritger         NV2080_CTRL_INTERNAL_GSYNC_SET_OR_RESTORE_RASTER_SYNC_PARAMS ctrlParams = {0};
2513758b4ee8SAndy Ritger 
2514758b4ee8SAndy Ritger         for (tempIface = 0; tempIface < NV_P2060_MAX_IFACES_PER_GSYNC; tempIface++)
2515758b4ee8SAndy Ritger         {
2516758b4ee8SAndy Ritger             if (tempIface == iface)
2517758b4ee8SAndy Ritger             {
2518758b4ee8SAndy Ritger                 continue;
2519758b4ee8SAndy Ritger             }
2520758b4ee8SAndy Ritger 
2521758b4ee8SAndy Ritger             otherGpuId = pThis->Iface[tempIface].GpuInfo.gpuId;
2522758b4ee8SAndy Ritger             if (otherGpuId == NV0000_CTRL_GPU_INVALID_ID)
2523758b4ee8SAndy Ritger             {
2524758b4ee8SAndy Ritger                 continue;
2525758b4ee8SAndy Ritger             }
2526758b4ee8SAndy Ritger 
2527758b4ee8SAndy Ritger             pOtherGpu = gpumgrGetGpuFromId(otherGpuId);
2528758b4ee8SAndy Ritger             NV_ASSERT(pOtherGpu);
2529758b4ee8SAndy Ritger 
2530758b4ee8SAndy Ritger             if (gpumgrGetGpuLockAndDrPorts(pGpu, pOtherGpu, &drOut, &drIn) != NV_OK)
2531758b4ee8SAndy Ritger             {
2532758b4ee8SAndy Ritger                 continue;
2533758b4ee8SAndy Ritger             }
2534758b4ee8SAndy Ritger             //
2535758b4ee8SAndy Ritger             // If this is the master gpu, we need to disable the raster sync
2536758b4ee8SAndy Ritger             // gpio on the other P2060 GPU that's connected to master over
2537758b4ee8SAndy Ritger             // Video bridge. Otherwise, if the video bridge is connected,
2538758b4ee8SAndy Ritger             // the raster sync signals from the two cards will interfere,
2539758b4ee8SAndy Ritger             // giving us an unreliable sync signal.
2540758b4ee8SAndy Ritger             //
2541758b4ee8SAndy Ritger             pRmApi      = GPU_GET_PHYSICAL_RMAPI(pOtherGpu);
2542758b4ee8SAndy Ritger             hClient     = pOtherGpu->hInternalClient;
2543758b4ee8SAndy Ritger             hSubdevice  = pOtherGpu->hInternalSubdevice;
2544758b4ee8SAndy Ritger 
2545758b4ee8SAndy Ritger             ctrlParams.bEnableMaster = bEnableMaster;
2546758b4ee8SAndy Ritger             ctrlParams.bRasterSyncGpioSaved = pThis->Iface[tempIface].RasterSyncGpio.saved;
2547758b4ee8SAndy Ritger             ctrlParams.bRasterSyncGpioDirection = pThis->Iface[tempIface].RasterSyncGpio.direction;
2548758b4ee8SAndy Ritger 
2549758b4ee8SAndy Ritger             rmStatus = pRmApi->Control(pRmApi, hClient, hSubdevice,
2550758b4ee8SAndy Ritger                                        NV2080_CTRL_CMD_INTERNAL_GSYNC_SET_OR_RESTORE_RASTER_SYNC,
2551758b4ee8SAndy Ritger                                        &ctrlParams, sizeof(ctrlParams));
2552758b4ee8SAndy Ritger 
2553758b4ee8SAndy Ritger             if (rmStatus != NV_OK)
2554758b4ee8SAndy Ritger             {
2555758b4ee8SAndy Ritger                 NV_PRINTF(LEVEL_ERROR, "Extdev control call to save/restore GPIO direction is failed!\n");
2556758b4ee8SAndy Ritger             }
2557758b4ee8SAndy Ritger             else
2558758b4ee8SAndy Ritger             {
2559758b4ee8SAndy Ritger                 if (bEnableMaster && !pThis->Iface[tempIface].RasterSyncGpio.saved)
2560758b4ee8SAndy Ritger                 {
2561758b4ee8SAndy Ritger                     pThis->Iface[tempIface].RasterSyncGpio.direction = ctrlParams.bRasterSyncGpioDirection;
2562758b4ee8SAndy Ritger                     pThis->Iface[tempIface].RasterSyncGpio.saved = NV_TRUE;
2563758b4ee8SAndy Ritger                 }
2564758b4ee8SAndy Ritger                 else if (!bEnableMaster && pThis->Iface[tempIface].RasterSyncGpio.saved)
2565758b4ee8SAndy Ritger                 {
2566758b4ee8SAndy Ritger                      pThis->Iface[tempIface].RasterSyncGpio.saved = NV_FALSE;
2567758b4ee8SAndy Ritger                  }
2568758b4ee8SAndy Ritger             }
2569758b4ee8SAndy Ritger 
2570758b4ee8SAndy Ritger             Slaves = gsyncReadSlaves_P2060(pOtherGpu, pThis);
2571758b4ee8SAndy Ritger             if (Slaves)
2572758b4ee8SAndy Ritger             {
2573758b4ee8SAndy Ritger                 rmStatus = gsyncProgramSlaves_P2060(pOtherGpu, pThis, Slaves);
2574758b4ee8SAndy Ritger                 if (NV_OK != rmStatus)
2575758b4ee8SAndy Ritger                 {
2576758b4ee8SAndy Ritger                     NV_PRINTF(LEVEL_ERROR,
2577758b4ee8SAndy Ritger                               "Failed to program SLI slaves. Can not program Master.\n");
2578758b4ee8SAndy Ritger                     return rmStatus;
2579758b4ee8SAndy Ritger                 }
2580758b4ee8SAndy Ritger             }
2581758b4ee8SAndy Ritger         }
2582758b4ee8SAndy Ritger     }
2583758b4ee8SAndy Ritger 
2584758b4ee8SAndy Ritger     // Reset the frame count data and also disable frame compare match interrupt.
2585758b4ee8SAndy Ritger     if (!bEnableMaster)
2586758b4ee8SAndy Ritger     {
2587758b4ee8SAndy Ritger         iface = pThis->FrameCountData.iface;
2588758b4ee8SAndy Ritger         head  = pThis->FrameCountData.head;
2589758b4ee8SAndy Ritger 
2590758b4ee8SAndy Ritger         if ((iface < NV_P2060_MAX_IFACES_PER_GSYNC) && (head  < numHeads))
2591758b4ee8SAndy Ritger         {
2592758b4ee8SAndy Ritger             rmStatus |= gsyncResetFrameCountData_P2060(pGpu, pThis);
2593758b4ee8SAndy Ritger         }
2594758b4ee8SAndy Ritger     }
2595758b4ee8SAndy Ritger     return rmStatus;
2596758b4ee8SAndy Ritger }
2597758b4ee8SAndy Ritger 
2598758b4ee8SAndy Ritger /*
2599758b4ee8SAndy Ritger  * Read Framelock Master P2060.
2600758b4ee8SAndy Ritger  */
2601758b4ee8SAndy Ritger static NvU32
gsyncReadMaster_P2060(OBJGPU * pGpu,PDACP2060EXTERNALDEVICE pThis)2602758b4ee8SAndy Ritger gsyncReadMaster_P2060
2603758b4ee8SAndy Ritger (
2604758b4ee8SAndy Ritger     OBJGPU *pGpu,
2605758b4ee8SAndy Ritger     PDACP2060EXTERNALDEVICE pThis
2606758b4ee8SAndy Ritger )
2607758b4ee8SAndy Ritger {
2608758b4ee8SAndy Ritger     KernelDisplay  *pKernelDisplay = GPU_GET_KERNEL_DISPLAY(pGpu);
2609758b4ee8SAndy Ritger     NvU32       DisplayIds[OBJ_MAX_HEADS];
2610758b4ee8SAndy Ritger     NvU32       iface, head;
2611758b4ee8SAndy Ritger     NvU32       Master = 0;
2612758b4ee8SAndy Ritger     NV_STATUS   status;
2613758b4ee8SAndy Ritger     NvU32 numHeads = kdispGetNumHeads(pKernelDisplay);
2614758b4ee8SAndy Ritger 
2615758b4ee8SAndy Ritger     extdevGetBoundHeadsAndDisplayIds(pGpu, DisplayIds);
2616758b4ee8SAndy Ritger 
2617758b4ee8SAndy Ritger     status = GetP2060GpuLocation(pGpu, pThis, &iface);
2618758b4ee8SAndy Ritger     if (NV_OK != status)
2619758b4ee8SAndy Ritger         return 0;
2620758b4ee8SAndy Ritger 
2621758b4ee8SAndy Ritger     for ( head = 0; head < numHeads; head++ )
2622758b4ee8SAndy Ritger     {
2623758b4ee8SAndy Ritger         if (pThis->Iface[iface].Sync.Master[head])
2624758b4ee8SAndy Ritger         {
2625758b4ee8SAndy Ritger             Master |= DisplayIds[head];
2626758b4ee8SAndy Ritger         }
2627758b4ee8SAndy Ritger     }
2628758b4ee8SAndy Ritger 
2629758b4ee8SAndy Ritger     // check hardware's opinion on the Master Gsync and Timing source GPU.
2630758b4ee8SAndy Ritger     if (gsyncIsP2060MasterBoard(pGpu, pThis) &&
2631758b4ee8SAndy Ritger         GpuIsP2060Master(pGpu, pThis))
2632758b4ee8SAndy Ritger     {
2633758b4ee8SAndy Ritger         if (Master)
2634758b4ee8SAndy Ritger         {
2635758b4ee8SAndy Ritger             return Master;
2636758b4ee8SAndy Ritger         }
2637758b4ee8SAndy Ritger         else
2638758b4ee8SAndy Ritger         {
2639758b4ee8SAndy Ritger             // HW is set to be master, but SW isn't treating it as master?
2640758b4ee8SAndy Ritger             // we must be on external sync, so no one display is associated...
2641758b4ee8SAndy Ritger             return ~0;
2642758b4ee8SAndy Ritger         }
2643758b4ee8SAndy Ritger     }
2644758b4ee8SAndy Ritger     else
2645758b4ee8SAndy Ritger     {
2646758b4ee8SAndy Ritger         // if HW says it's not the master, SW's opinion doesn't count.
2647758b4ee8SAndy Ritger         return 0;
2648758b4ee8SAndy Ritger     }
2649758b4ee8SAndy Ritger }
2650758b4ee8SAndy Ritger 
2651758b4ee8SAndy Ritger /*
2652758b4ee8SAndy Ritger  * Program P2060 Slave for framelock.
2653758b4ee8SAndy Ritger  */
2654758b4ee8SAndy Ritger static NV_STATUS
gsyncProgramSlaves_P2060(OBJGPU * pGpu,PDACP2060EXTERNALDEVICE pThis,NvU32 Slaves)2655758b4ee8SAndy Ritger gsyncProgramSlaves_P2060
2656758b4ee8SAndy Ritger (
2657758b4ee8SAndy Ritger     OBJGPU *pGpu,
2658758b4ee8SAndy Ritger     PDACP2060EXTERNALDEVICE pThis,
2659758b4ee8SAndy Ritger     NvU32 Slaves
2660758b4ee8SAndy Ritger )
2661758b4ee8SAndy Ritger {
2662758b4ee8SAndy Ritger     KernelDisplay  *pKernelDisplay = GPU_GET_KERNEL_DISPLAY(pGpu);
2663758b4ee8SAndy Ritger     NvU32       DisplayIds[OBJ_MAX_HEADS];
2664758b4ee8SAndy Ritger     NvU32       iface, head, index;
2665758b4ee8SAndy Ritger     NvU8        ctrl = 0, ctrl3 = 0;
2666758b4ee8SAndy Ritger     NvBool      bCoupled, bHouseSelect, bLocalMaster, bEnableSlaves = (0 != Slaves);
2667758b4ee8SAndy Ritger     NV_STATUS   rmStatus = NV_OK;
2668758b4ee8SAndy Ritger     NvU32 numHeads = kdispGetNumHeads(pKernelDisplay);
2669758b4ee8SAndy Ritger 
2670758b4ee8SAndy Ritger     // This utility fn returns display id's associated with each head.
2671758b4ee8SAndy Ritger     extdevGetBoundHeadsAndDisplayIds(pGpu, DisplayIds);
2672758b4ee8SAndy Ritger 
2673758b4ee8SAndy Ritger     // which gpu's are we talking to?
2674758b4ee8SAndy Ritger     rmStatus = GetP2060GpuLocation(pGpu, pThis, &iface);
2675758b4ee8SAndy Ritger     if (NV_OK != rmStatus)
2676758b4ee8SAndy Ritger     {
2677758b4ee8SAndy Ritger         NV_PRINTF(LEVEL_ERROR,
2678758b4ee8SAndy Ritger                   "Failed to get Gpu location. Can not program Slave.\n");
2679758b4ee8SAndy Ritger         return rmStatus;
2680758b4ee8SAndy Ritger     }
2681758b4ee8SAndy Ritger 
2682758b4ee8SAndy Ritger     rmStatus = readregu008_extdeviceTargeted(pGpu, (PDACEXTERNALDEVICE)pThis,
2683758b4ee8SAndy Ritger                                             (NvU8)NV_P2060_CONTROL, &ctrl);
2684758b4ee8SAndy Ritger     if (NV_OK != rmStatus)
2685758b4ee8SAndy Ritger     {
2686758b4ee8SAndy Ritger         NV_PRINTF(LEVEL_ERROR,
2687758b4ee8SAndy Ritger                   "Failed to read ctrl register. Can not program slave.\n");
2688758b4ee8SAndy Ritger         return rmStatus; // ouch
2689758b4ee8SAndy Ritger     }
2690758b4ee8SAndy Ritger 
2691758b4ee8SAndy Ritger     // Check for House sync select as sync source and FPGA board is master or not
2692758b4ee8SAndy Ritger     bHouseSelect = FLD_TEST_DRF(_P2060, _CONTROL, _SYNC_SELECT, _HOUSE,  (NvU32)ctrl);
2693758b4ee8SAndy Ritger     bLocalMaster = FLD_TEST_DRF(_P2060, _CONTROL, _I_AM,        _MASTER, (NvU32)ctrl);
2694758b4ee8SAndy Ritger 
2695758b4ee8SAndy Ritger     if (bEnableSlaves || bLocalMaster)
2696758b4ee8SAndy Ritger     {
2697758b4ee8SAndy Ritger         rmStatus = gsyncApplyStereoPinAlwaysHiWar(pGpu, (PDACEXTERNALDEVICE)pThis);
2698758b4ee8SAndy Ritger 
2699758b4ee8SAndy Ritger         if (NV_OK != rmStatus)
2700758b4ee8SAndy Ritger         {
2701758b4ee8SAndy Ritger             NV_PRINTF(LEVEL_ERROR,
2702758b4ee8SAndy Ritger                       "Failed to drive stereo output pin for bug3362661.\n");
2703758b4ee8SAndy Ritger         }
2704758b4ee8SAndy Ritger     }
2705758b4ee8SAndy Ritger 
2706758b4ee8SAndy Ritger     if (bHouseSelect && bEnableSlaves && bLocalMaster)
2707758b4ee8SAndy Ritger     {
2708758b4ee8SAndy Ritger         rmStatus = readregu008_extdeviceTargeted(pGpu, (PDACEXTERNALDEVICE)pThis,
2709758b4ee8SAndy Ritger                                                 (NvU8)NV_P2060_CONTROL3, &ctrl3);
2710758b4ee8SAndy Ritger         if (rmStatus != NV_OK)
2711758b4ee8SAndy Ritger         {
2712758b4ee8SAndy Ritger             NV_PRINTF(LEVEL_ERROR,
2713758b4ee8SAndy Ritger                       "Failed to read ctrl3 register. Can not program slave.\n");
2714758b4ee8SAndy Ritger             return rmStatus;
2715758b4ee8SAndy Ritger         }
2716758b4ee8SAndy Ritger         ctrl3 |= (NvU8) FLD_SET_DRF(_P2060, _CONTROL3, _RESYNC, _ON, (NvU32)ctrl3);
2717758b4ee8SAndy Ritger         writeregu008_extdeviceTargeted(pGpu, (PDACEXTERNALDEVICE)pThis,
2718758b4ee8SAndy Ritger                                       (NvU8)NV_P2060_CONTROL3, ctrl3);
2719758b4ee8SAndy Ritger     }
2720758b4ee8SAndy Ritger 
2721758b4ee8SAndy Ritger     //
2722758b4ee8SAndy Ritger     // No need to check for every gpu connected to this gsync board. If gsync board
2723758b4ee8SAndy Ritger     // is not master/server, none of the gpu connected to it will have master head.
2724758b4ee8SAndy Ritger     //
2725758b4ee8SAndy Ritger 
2726758b4ee8SAndy Ritger     if (bEnableSlaves && !bLocalMaster)
2727758b4ee8SAndy Ritger     {
2728758b4ee8SAndy Ritger        //
2729758b4ee8SAndy Ritger        // Sync source should be taken from GPU connected to Gsync board.
2730758b4ee8SAndy Ritger        // Get index of current GPU and make it sync source.
2731758b4ee8SAndy Ritger        // No idea is this safe or not. Adding TODO for future check.
2732758b4ee8SAndy Ritger        //
2733758b4ee8SAndy Ritger        rmStatus = GetP2060ConnectorIndexFromGpu(pGpu, pThis, &index);
2734758b4ee8SAndy Ritger        if (NV_OK != rmStatus)
2735758b4ee8SAndy Ritger        {
2736758b4ee8SAndy Ritger            NV_PRINTF(LEVEL_ERROR,
2737758b4ee8SAndy Ritger                      "Failed to get connector index for Gpu. Can not program slave.\n");
2738758b4ee8SAndy Ritger            return rmStatus;
2739758b4ee8SAndy Ritger        }
2740758b4ee8SAndy Ritger 
2741758b4ee8SAndy Ritger        ctrl = FLD_SET_DRF_NUM(_P2060, _CONTROL, _SYNC_SRC, (NvU8)index, ctrl);
2742758b4ee8SAndy Ritger 
2743758b4ee8SAndy Ritger        rmStatus = writeregu008_extdeviceTargeted(pGpu, (PDACEXTERNALDEVICE) pThis,
2744758b4ee8SAndy Ritger                                                 (NvU8)NV_P2060_CONTROL, ctrl);
2745758b4ee8SAndy Ritger        if (NV_OK != rmStatus)
2746758b4ee8SAndy Ritger        {
2747758b4ee8SAndy Ritger            NV_PRINTF(LEVEL_ERROR,
2748758b4ee8SAndy Ritger                      "Failed to write SYNC_SRC. Can not program slave.\n");
2749758b4ee8SAndy Ritger            return rmStatus;
2750758b4ee8SAndy Ritger        }
2751758b4ee8SAndy Ritger     }
2752758b4ee8SAndy Ritger 
2753758b4ee8SAndy Ritger     //
2754758b4ee8SAndy Ritger     // With House sync enabled the crashlocking still need some investigations.
2755758b4ee8SAndy Ritger     // So filter out Housesyced systems before doing local crashlocks.
2756758b4ee8SAndy Ritger     //
2757758b4ee8SAndy Ritger     if ((!bHouseSelect) && bEnableSlaves && bLocalMaster)
2758758b4ee8SAndy Ritger     {
2759758b4ee8SAndy Ritger         rmStatus = readregu008_extdeviceTargeted(pGpu, (PDACEXTERNALDEVICE)pThis,
2760758b4ee8SAndy Ritger                                                 (NvU8)NV_P2060_CONTROL3, &ctrl3);
2761758b4ee8SAndy Ritger         if (rmStatus != NV_OK)
2762758b4ee8SAndy Ritger         {
2763758b4ee8SAndy Ritger             NV_PRINTF(LEVEL_ERROR,
2764758b4ee8SAndy Ritger                       "Failed to read ctrl3 register. Can not program slave.\n");
2765758b4ee8SAndy Ritger             return rmStatus;
2766758b4ee8SAndy Ritger         }
2767758b4ee8SAndy Ritger         ctrl3 |= (NvU8) FLD_SET_DRF(_P2060, _CONTROL3, _RESYNC, _ON, (NvU32)ctrl3);
2768758b4ee8SAndy Ritger         writeregu008_extdeviceTargeted(pGpu, (PDACEXTERNALDEVICE)pThis,
2769758b4ee8SAndy Ritger                                        (NvU8)NV_P2060_CONTROL3, ctrl3);
2770758b4ee8SAndy Ritger     }
2771758b4ee8SAndy Ritger 
2772758b4ee8SAndy Ritger     //
2773758b4ee8SAndy Ritger     // If we on the same gpu as the framelock master, the P2060 will
2774758b4ee8SAndy Ritger     // not servo, so we must rely on the gpu to get our timing...
2775758b4ee8SAndy Ritger     // unless house sync is expected, in which case we get it back.
2776758b4ee8SAndy Ritger     //
2777758b4ee8SAndy Ritger     bCoupled = (!bLocalMaster) || (bHouseSelect);
2778758b4ee8SAndy Ritger 
2779758b4ee8SAndy Ritger     // disable all existing slaves before enabling new slaves.
2780758b4ee8SAndy Ritger     if (bEnableSlaves)
2781758b4ee8SAndy Ritger     {
2782758b4ee8SAndy Ritger         for ( head = 0; head < numHeads; head++ )
2783758b4ee8SAndy Ritger         {
2784758b4ee8SAndy Ritger             pThis->Iface[iface].Sync.Slaved[head] =     0;
2785758b4ee8SAndy Ritger             pThis->Iface[iface].Sync.LocalSlave[head] = 0;
2786758b4ee8SAndy Ritger         }
2787758b4ee8SAndy Ritger     }
2788758b4ee8SAndy Ritger 
2789758b4ee8SAndy Ritger     for ( head = 0; head < numHeads; head++ )
2790758b4ee8SAndy Ritger     {
2791758b4ee8SAndy Ritger         // is this head to be slaved, or are we freeing all slaves?
2792758b4ee8SAndy Ritger         if ((Slaves & DisplayIds[head]) || !bEnableSlaves)
2793758b4ee8SAndy Ritger         {
2794758b4ee8SAndy Ritger             pThis->Iface[iface].Sync.Slaved[head] =     (bEnableSlaves &&  bCoupled);
2795758b4ee8SAndy Ritger             pThis->Iface[iface].Sync.LocalSlave[head] = (bEnableSlaves && !bCoupled);
2796758b4ee8SAndy Ritger 
2797758b4ee8SAndy Ritger             gsyncProgramFramelockEnable_P2060(pGpu, pThis, iface, bEnableSlaves);
2798758b4ee8SAndy Ritger         }
2799758b4ee8SAndy Ritger         else
2800758b4ee8SAndy Ritger         {
2801758b4ee8SAndy Ritger             // we are setting a slave, but it's not on this head, so nothing needs doing.
2802758b4ee8SAndy Ritger         }
2803758b4ee8SAndy Ritger     }
2804758b4ee8SAndy Ritger 
2805758b4ee8SAndy Ritger     if (!bEnableSlaves && !gsyncIsFrameLocked_P2060(pThis))
2806758b4ee8SAndy Ritger     {
2807758b4ee8SAndy Ritger         // Disable Framelock interrupts as board is not framelocked now.
2808758b4ee8SAndy Ritger         gsyncDisableFrameLockInterrupt_P2060((PDACEXTERNALDEVICE)pThis);
2809758b4ee8SAndy Ritger 
2810758b4ee8SAndy Ritger         rmStatus = gsyncUnApplyStereoPinAlwaysHiWar(pGpu);
2811758b4ee8SAndy Ritger 
2812758b4ee8SAndy Ritger         if (NV_OK != rmStatus)
2813758b4ee8SAndy Ritger         {
2814758b4ee8SAndy Ritger             NV_PRINTF(LEVEL_ERROR,
2815758b4ee8SAndy Ritger                       "Failed to drive stereo output pin for bug3362661.\n");
2816758b4ee8SAndy Ritger         }
2817758b4ee8SAndy Ritger     }
2818758b4ee8SAndy Ritger 
2819758b4ee8SAndy Ritger     // Reset FrameCountData and disable frame compare match interrupt.
2820758b4ee8SAndy Ritger     if (iface == pThis->FrameCountData.iface)
2821758b4ee8SAndy Ritger     {
2822758b4ee8SAndy Ritger         if (!(Slaves & DisplayIds[pThis->FrameCountData.head]))
2823758b4ee8SAndy Ritger         {
2824758b4ee8SAndy Ritger             if (pThis->Iface[iface].GpuInfo.gpuId != NV0000_CTRL_GPU_INVALID_ID)
2825758b4ee8SAndy Ritger             {
2826758b4ee8SAndy Ritger                 rmStatus |= gsyncResetFrameCountData_P2060(pGpu, pThis);
2827758b4ee8SAndy Ritger             }
2828758b4ee8SAndy Ritger         }
2829758b4ee8SAndy Ritger     }
2830758b4ee8SAndy Ritger     return rmStatus;
2831758b4ee8SAndy Ritger }
2832758b4ee8SAndy Ritger 
2833758b4ee8SAndy Ritger /*
2834758b4ee8SAndy Ritger  * Read P2060 slave for framelock.
2835758b4ee8SAndy Ritger  */
2836758b4ee8SAndy Ritger static NvU32
gsyncReadSlaves_P2060(OBJGPU * pGpu,PDACP2060EXTERNALDEVICE pThis)2837758b4ee8SAndy Ritger gsyncReadSlaves_P2060
2838758b4ee8SAndy Ritger (
2839758b4ee8SAndy Ritger     OBJGPU *pGpu,
2840758b4ee8SAndy Ritger     PDACP2060EXTERNALDEVICE pThis
2841758b4ee8SAndy Ritger )
2842758b4ee8SAndy Ritger {
2843758b4ee8SAndy Ritger     KernelDisplay  *pKernelDisplay = GPU_GET_KERNEL_DISPLAY(pGpu);
2844758b4ee8SAndy Ritger     NvU32       DisplayIds[OBJ_MAX_HEADS];
2845758b4ee8SAndy Ritger     NvU32       iface, head;
2846758b4ee8SAndy Ritger     NvU32       Slaves = 0;
2847758b4ee8SAndy Ritger     NV_STATUS   status;
2848758b4ee8SAndy Ritger     NvU32 numHeads = kdispGetNumHeads(pKernelDisplay);
2849758b4ee8SAndy Ritger 
2850758b4ee8SAndy Ritger     extdevGetBoundHeadsAndDisplayIds(pGpu, DisplayIds);
2851758b4ee8SAndy Ritger 
2852758b4ee8SAndy Ritger     status = GetP2060GpuLocation(pGpu, pThis, &iface);
2853758b4ee8SAndy Ritger     if (NV_OK != status)
2854758b4ee8SAndy Ritger         return 0;
2855758b4ee8SAndy Ritger 
2856758b4ee8SAndy Ritger     for ( head = 0; head < numHeads; head++ )
2857758b4ee8SAndy Ritger     {
2858758b4ee8SAndy Ritger         if (!pThis->Iface[iface].Sync.Master[head] &&
2859758b4ee8SAndy Ritger             (pThis->Iface[iface].Sync.Slaved[head] || pThis->Iface[iface].Sync.LocalSlave[head]))
2860758b4ee8SAndy Ritger         {
2861758b4ee8SAndy Ritger             Slaves |= DisplayIds[head];
2862758b4ee8SAndy Ritger         }
2863758b4ee8SAndy Ritger     }
2864758b4ee8SAndy Ritger     return Slaves;
2865758b4ee8SAndy Ritger }
2866758b4ee8SAndy Ritger 
2867758b4ee8SAndy Ritger static NV_STATUS
gsyncProgramSwapBarrier_P2060(OBJGPU * pGpu,PDACEXTERNALDEVICE pExtDev,NvBool bEnable)2868758b4ee8SAndy Ritger gsyncProgramSwapBarrier_P2060
2869758b4ee8SAndy Ritger (
2870758b4ee8SAndy Ritger     OBJGPU              *pGpu,
2871758b4ee8SAndy Ritger     PDACEXTERNALDEVICE   pExtDev,
2872758b4ee8SAndy Ritger     NvBool               bEnable
2873758b4ee8SAndy Ritger )
2874758b4ee8SAndy Ritger {
2875758b4ee8SAndy Ritger     PDACP2060EXTERNALDEVICE pThis = (PDACP2060EXTERNALDEVICE) pExtDev;
2876758b4ee8SAndy Ritger     NvU32          iface;
2877758b4ee8SAndy Ritger     NvU8           ctrl2 = 0;
2878758b4ee8SAndy Ritger     NV_STATUS      status = NV_OK;
2879758b4ee8SAndy Ritger 
2880758b4ee8SAndy Ritger     status = GetP2060GpuLocation(pGpu, pThis, &iface);
2881758b4ee8SAndy Ritger     if (NV_OK != status)
2882758b4ee8SAndy Ritger     {
2883758b4ee8SAndy Ritger        if (!IsSLIEnabled(pGpu))
2884758b4ee8SAndy Ritger        {
2885758b4ee8SAndy Ritger            //
2886758b4ee8SAndy Ritger            // If not in SLI, this function must only be called on GPUs connected
2887758b4ee8SAndy Ritger            // to the framelock board.
2888758b4ee8SAndy Ritger            //
2889758b4ee8SAndy Ritger            return status;
2890758b4ee8SAndy Ritger        }
2891758b4ee8SAndy Ritger        else
2892758b4ee8SAndy Ritger        {
2893758b4ee8SAndy Ritger            //
2894758b4ee8SAndy Ritger            // In SLI, we will try to add all GPUs in a topology to a swap
2895758b4ee8SAndy Ritger            // barrier, but not all of the GPUs actually have to be connected to
2896758b4ee8SAndy Ritger            // the framelock board, so we can return NV_OK to let the caller continue
2897758b4ee8SAndy Ritger            // on to the next GPU.
2898758b4ee8SAndy Ritger            //
2899758b4ee8SAndy Ritger            NV_PRINTF(LEVEL_INFO,
2900758b4ee8SAndy Ritger                      "Ignoring GPU %u not connected to the framelock board.\n",
2901758b4ee8SAndy Ritger                      gpumgrGetSubDeviceInstanceFromGpu(pGpu));
2902758b4ee8SAndy Ritger            return NV_OK;
2903758b4ee8SAndy Ritger        }
2904758b4ee8SAndy Ritger     }
2905758b4ee8SAndy Ritger 
2906758b4ee8SAndy Ritger     // Each connected GPU accesses it's own version of CONTROL2, on P2060
2907758b4ee8SAndy Ritger     if (GpuIsP2060Connected(pGpu, pThis))
2908758b4ee8SAndy Ritger     {
2909758b4ee8SAndy Ritger         status = readregu008_extdeviceTargeted(pGpu, pExtDev,
2910758b4ee8SAndy Ritger                                      NV_P2060_CONTROL2, &ctrl2);
2911758b4ee8SAndy Ritger         if (status != NV_OK)
2912758b4ee8SAndy Ritger         {
2913758b4ee8SAndy Ritger             return status;
2914758b4ee8SAndy Ritger         }
2915758b4ee8SAndy Ritger 
2916758b4ee8SAndy Ritger         if (pExtDev->deviceRev >= DAC_EXTERNAL_DEVICE_REV_MAX)
2917758b4ee8SAndy Ritger         {
2918758b4ee8SAndy Ritger             return NV_ERR_INVALID_STATE;
2919758b4ee8SAndy Ritger         }
2920758b4ee8SAndy Ritger     }
2921758b4ee8SAndy Ritger 
2922758b4ee8SAndy Ritger     if (pThis->Iface[iface].SwapReadyRequested == bEnable)
2923758b4ee8SAndy Ritger     {
2924758b4ee8SAndy Ritger        //
2925758b4ee8SAndy Ritger        // The SwapReadyRequested boolean keeps tracks of the current
2926758b4ee8SAndy Ritger        // requested state for this GPU. Skip the WAR algorithm if it's
2927758b4ee8SAndy Ritger        // already taken this GPU's state into account.
2928758b4ee8SAndy Ritger        //
2929758b4ee8SAndy Ritger        return NV_OK;
2930758b4ee8SAndy Ritger     }
2931758b4ee8SAndy Ritger 
2932758b4ee8SAndy Ritger     if (bEnable)  // Enable Swap_rdy
2933758b4ee8SAndy Ritger     {
2934758b4ee8SAndy Ritger         ctrl2 = FLD_SET_DRF(_P2060, _CONTROL2, _SWAP_READY, _ENABLE, ctrl2);
2935758b4ee8SAndy Ritger 
2936758b4ee8SAndy Ritger         if (pThis->tSwapRdyHiLsrMinTime == 0)
2937758b4ee8SAndy Ritger         {
2938758b4ee8SAndy Ritger             NvU32 data = 0;
2939758b4ee8SAndy Ritger 
2940758b4ee8SAndy Ritger             // store Swap Lockout Window in pThis.
2941758b4ee8SAndy Ritger             pThis->tSwapRdyHiLsrMinTime = NV_REG_STR_TIME_SWAP_RDY_HI_MODIFY_LSR_MIN_TIME_DEFAULT;
2942758b4ee8SAndy Ritger             if (osReadRegistryDword(pGpu,
2943758b4ee8SAndy Ritger              NV_REG_STR_TIME_SWAP_RDY_HI_MODIFY_LSR_MIN_TIME, &data) == NV_OK)
2944758b4ee8SAndy Ritger             {
2945758b4ee8SAndy Ritger                 pThis->tSwapRdyHiLsrMinTime = data;
2946758b4ee8SAndy Ritger             }
2947758b4ee8SAndy Ritger         }
2948758b4ee8SAndy Ritger 
2949758b4ee8SAndy Ritger         NV_ASSERT(pThis->tSwapRdyHiLsrMinTime != 0);
2950758b4ee8SAndy Ritger 
2951758b4ee8SAndy Ritger         if (pThis->Iface[iface].DsiFliplock.saved == NV_FALSE)
2952758b4ee8SAndy Ritger         {
2953758b4ee8SAndy Ritger             KernelDisplay *pKernelDisplay = GPU_GET_KERNEL_DISPLAY(pGpu);
2954758b4ee8SAndy Ritger             NvU32          numHeads = kdispGetNumHeads(pKernelDisplay);
2955758b4ee8SAndy Ritger             NvU32          head ;
2956758b4ee8SAndy Ritger 
2957758b4ee8SAndy Ritger             for (head = 0; head < numHeads; head++)
2958758b4ee8SAndy Ritger             {
2959758b4ee8SAndy Ritger                 NvU32 newLsrMinTime;
2960758b4ee8SAndy Ritger                 if ((status = kdispComputeLsrMinTimeValue_HAL(pGpu, pKernelDisplay, head,
2961758b4ee8SAndy Ritger                              pThis->tSwapRdyHiLsrMinTime, &newLsrMinTime)) == NV_OK)
2962758b4ee8SAndy Ritger                 {
2963758b4ee8SAndy Ritger                     NvU32 origLsrMinTime;
2964758b4ee8SAndy Ritger                     kdispSetSwapBarrierLsrMinTime_HAL(pGpu, pKernelDisplay, head, &origLsrMinTime,
2965758b4ee8SAndy Ritger                                       newLsrMinTime);
2966758b4ee8SAndy Ritger 
2967758b4ee8SAndy Ritger                     pThis->Iface[iface].DsiFliplock.OrigLsrMinTime[head] = origLsrMinTime;
2968758b4ee8SAndy Ritger                 }
2969758b4ee8SAndy Ritger                 else
2970758b4ee8SAndy Ritger                 {
2971758b4ee8SAndy Ritger                     NV_PRINTF(LEVEL_ERROR,
2972758b4ee8SAndy Ritger                               "Error occured while computing LSR_MIN_TIME for Swap Barrier\n");
2973758b4ee8SAndy Ritger                     NV_ASSERT(0);
2974758b4ee8SAndy Ritger                 }
2975758b4ee8SAndy Ritger             }
2976758b4ee8SAndy Ritger             pThis->Iface[iface].DsiFliplock.saved = NV_TRUE;
2977758b4ee8SAndy Ritger         }
2978758b4ee8SAndy Ritger 
2979758b4ee8SAndy Ritger         // The swapbarrier on master war is assumed to be fixed with fpga rev > 5.
2980758b4ee8SAndy Ritger         if ((!pThis->Iface[iface].skipSwapBarrierWar) &&
2981758b4ee8SAndy Ritger              needsMasterBarrierWar(&pThis->ExternalDevice))
2982758b4ee8SAndy Ritger         {
2983758b4ee8SAndy Ritger             if (gsyncIsP2060MasterBoard(pGpu, pThis) && GpuIsP2060Master(pGpu, pThis))
2984758b4ee8SAndy Ritger             {
2985758b4ee8SAndy Ritger                 //
2986758b4ee8SAndy Ritger                 // Swap Rdy signal on Master + TS GPU will enabled or disabled during
2987758b4ee8SAndy Ritger                 // Enable/Disable of Master i.e. gsyncProgramMaster_P2060
2988758b4ee8SAndy Ritger                 //
2989758b4ee8SAndy Ritger                 pThis->Iface[iface].SwapReadyRequested = bEnable;
2990758b4ee8SAndy Ritger                 return NV_OK;
2991758b4ee8SAndy Ritger             }
2992758b4ee8SAndy Ritger         }
2993758b4ee8SAndy Ritger 
2994758b4ee8SAndy Ritger         if (GpuIsConnectedToMasterViaBridge(pGpu, pThis) &&
2995758b4ee8SAndy Ritger            (gpumgrGetGpuBridgeType() == SLI_BT_VIDLINK || isBoardWithNvlinkQsyncContention(pGpu)))
2996758b4ee8SAndy Ritger         {
2997758b4ee8SAndy Ritger             //
2998758b4ee8SAndy Ritger             // Do not enable swapRdy Connection of pGpu. pGpu will take swap Rdy signal
2999758b4ee8SAndy Ritger             // from Master + TS GPU via SLI (MIO) bridge
3000758b4ee8SAndy Ritger             //
3001758b4ee8SAndy Ritger             pThis->Iface[iface].SwapReadyRequested = bEnable;
3002758b4ee8SAndy Ritger             return status; //NV_OK
3003758b4ee8SAndy Ritger         }
3004758b4ee8SAndy Ritger     }
3005758b4ee8SAndy Ritger     else
3006758b4ee8SAndy Ritger     {
3007758b4ee8SAndy Ritger         ctrl2 = FLD_SET_DRF(_P2060, _CONTROL2, _SWAP_READY, _DISABLE, ctrl2); // Disable Swap_rdy
3008758b4ee8SAndy Ritger 
3009758b4ee8SAndy Ritger         if (pThis->Iface[iface].DsiFliplock.saved == NV_TRUE)
3010758b4ee8SAndy Ritger         {
3011758b4ee8SAndy Ritger             KernelDisplay *pKernelDisplay = GPU_GET_KERNEL_DISPLAY(pGpu);
3012758b4ee8SAndy Ritger             NvU32          numHeads = kdispGetNumHeads(pKernelDisplay);
3013758b4ee8SAndy Ritger             NvU32          head ;
3014758b4ee8SAndy Ritger 
3015758b4ee8SAndy Ritger             for (head = 0; head < numHeads; head++)
3016758b4ee8SAndy Ritger             {
3017758b4ee8SAndy Ritger                 kdispRestoreOriginalLsrMinTime_HAL(pGpu, pKernelDisplay, head,
3018758b4ee8SAndy Ritger                 pThis->Iface[iface].DsiFliplock.OrigLsrMinTime[head]);
3019758b4ee8SAndy Ritger             }
3020758b4ee8SAndy Ritger             pThis->Iface[iface].DsiFliplock.saved = NV_FALSE;
3021758b4ee8SAndy Ritger         }
3022758b4ee8SAndy Ritger 
3023758b4ee8SAndy Ritger         // The swapbarrier on master war is assumed to be fixed with fpga rev > 5.
3024758b4ee8SAndy Ritger         if ((!pThis->Iface[iface].skipSwapBarrierWar) &&
3025758b4ee8SAndy Ritger              needsMasterBarrierWar(&pThis->ExternalDevice))
3026758b4ee8SAndy Ritger         {
3027758b4ee8SAndy Ritger             if (gsyncIsP2060MasterBoard(pGpu, pThis) && GpuIsP2060Master(pGpu, pThis))
3028758b4ee8SAndy Ritger             {
3029758b4ee8SAndy Ritger                 //
3030758b4ee8SAndy Ritger                 // Swap Rdy signal on Master + TS GPU will enabled or disabled during
3031758b4ee8SAndy Ritger                 // Enable/Disable of Master i.e. gsyncProgramMaster_P2060
3032758b4ee8SAndy Ritger                 //
3033758b4ee8SAndy Ritger                 pThis->Iface[iface].SwapReadyRequested = bEnable;
3034758b4ee8SAndy Ritger                 return NV_OK;
3035758b4ee8SAndy Ritger             }
3036758b4ee8SAndy Ritger         }
3037758b4ee8SAndy Ritger     }
3038758b4ee8SAndy Ritger 
3039758b4ee8SAndy Ritger     // Save the requested state for this GPU
3040758b4ee8SAndy Ritger     pThis->Iface[iface].SwapReadyRequested = bEnable;
3041758b4ee8SAndy Ritger 
3042758b4ee8SAndy Ritger     // Each connected GPU accesses it's own version of CONTROL2, on P2060
3043758b4ee8SAndy Ritger     if (GpuIsP2060Connected(pGpu, pThis))
3044758b4ee8SAndy Ritger     {
3045758b4ee8SAndy Ritger         status = writeregu008_extdeviceTargeted(pGpu, pExtDev,
3046758b4ee8SAndy Ritger                                                 NV_P2060_CONTROL2, ctrl2);
3047758b4ee8SAndy Ritger     }
3048758b4ee8SAndy Ritger 
3049758b4ee8SAndy Ritger     return status;
3050758b4ee8SAndy Ritger }
3051758b4ee8SAndy Ritger 
3052758b4ee8SAndy Ritger 
3053758b4ee8SAndy Ritger static NV_STATUS
gsyncReadSwapBarrier_P2060(OBJGPU * pGpu,PDACEXTERNALDEVICE pExtDev,NvBool * bEnable)3054758b4ee8SAndy Ritger gsyncReadSwapBarrier_P2060
3055758b4ee8SAndy Ritger (
3056758b4ee8SAndy Ritger     OBJGPU             *pGpu,
3057758b4ee8SAndy Ritger     PDACEXTERNALDEVICE  pExtDev,
3058758b4ee8SAndy Ritger     NvBool             *bEnable
3059758b4ee8SAndy Ritger )
3060758b4ee8SAndy Ritger {
3061758b4ee8SAndy Ritger     PDACP2060EXTERNALDEVICE pThis = (PDACP2060EXTERNALDEVICE) pExtDev;
3062758b4ee8SAndy Ritger     NvU32 iface;
3063758b4ee8SAndy Ritger     NV_STATUS status = NV_OK;
3064758b4ee8SAndy Ritger 
3065758b4ee8SAndy Ritger     status = GetP2060GpuLocation(pGpu, pThis, &iface);
3066758b4ee8SAndy Ritger     if (NV_OK != status)
3067758b4ee8SAndy Ritger     {
3068758b4ee8SAndy Ritger        if (!IsSLIEnabled(pGpu))
3069758b4ee8SAndy Ritger        {
3070758b4ee8SAndy Ritger            //
3071758b4ee8SAndy Ritger            // If not in SLI, this function must only be called on GPUs connected
3072758b4ee8SAndy Ritger            // to the framelock board.
3073758b4ee8SAndy Ritger            //
3074758b4ee8SAndy Ritger            return status;
3075758b4ee8SAndy Ritger        }
3076758b4ee8SAndy Ritger        else
3077758b4ee8SAndy Ritger        {
3078758b4ee8SAndy Ritger            //
3079758b4ee8SAndy Ritger            // In SLI, we will try to read the swap barrier info from all GPUs in a
3080758b4ee8SAndy Ritger            // topology, but not all of the GPUs actually have to be connected to
3081758b4ee8SAndy Ritger            // the framelock board, so we can return NV_OK to let the caller continue
3082758b4ee8SAndy Ritger            // on to the next GPU.
3083758b4ee8SAndy Ritger            //
3084758b4ee8SAndy Ritger            NV_PRINTF(LEVEL_INFO,
3085758b4ee8SAndy Ritger                      "Ignoring GPU %u not connected to the framelock board.\n",
3086758b4ee8SAndy Ritger                      gpumgrGetSubDeviceInstanceFromGpu(pGpu));
3087758b4ee8SAndy Ritger            return NV_OK;
3088758b4ee8SAndy Ritger        }
3089758b4ee8SAndy Ritger     }
3090758b4ee8SAndy Ritger 
3091758b4ee8SAndy Ritger     if (gsyncIsP2060MasterBoard(pGpu, pThis) && GpuIsP2060Master(pGpu, pThis))
3092758b4ee8SAndy Ritger     {
3093758b4ee8SAndy Ritger         // Read swapRdy of Master + TS GPU.
3094758b4ee8SAndy Ritger         *bEnable = pThis->Iface[iface].SwapReadyRequested;
3095758b4ee8SAndy Ritger         return status; //NV_OK
3096758b4ee8SAndy Ritger     }
3097758b4ee8SAndy Ritger 
3098758b4ee8SAndy Ritger     if (GpuIsConnectedToMasterViaBridge(pGpu, pThis) &&
3099758b4ee8SAndy Ritger        (gpumgrGetGpuBridgeType() == SLI_BT_VIDLINK || isBoardWithNvlinkQsyncContention(pGpu)))
3100758b4ee8SAndy Ritger     {
3101758b4ee8SAndy Ritger         // Read swapRdy of pGpu connected to Master + TS GPU via SLI (MIO) bridge.
3102758b4ee8SAndy Ritger         *bEnable = pThis->Iface[iface].SwapReadyRequested;
3103758b4ee8SAndy Ritger         return status; //NV_OK
3104758b4ee8SAndy Ritger     }
3105758b4ee8SAndy Ritger 
3106758b4ee8SAndy Ritger     // Each connected GPU accesses it's own version of CONTROL2, on P2060
3107758b4ee8SAndy Ritger     if (GpuIsP2060Connected(pGpu, pThis))
3108758b4ee8SAndy Ritger     {
3109758b4ee8SAndy Ritger         NvU8 ctrl2 = 0;
3110758b4ee8SAndy Ritger         status = readregu008_extdeviceTargeted(pGpu,
3111758b4ee8SAndy Ritger                        pExtDev, NV_P2060_CONTROL2, &ctrl2);
3112758b4ee8SAndy Ritger         if (status != NV_OK)
3113758b4ee8SAndy Ritger         {
3114758b4ee8SAndy Ritger             return status;
3115758b4ee8SAndy Ritger         }
3116758b4ee8SAndy Ritger         *bEnable = (NV_P2060_CONTROL2_SWAP_READY_ENABLE ==
3117758b4ee8SAndy Ritger                        DRF_VAL(_P2060, _CONTROL2, _SWAP_READY, (NvU32)ctrl2));
3118758b4ee8SAndy Ritger     }
3119758b4ee8SAndy Ritger 
3120758b4ee8SAndy Ritger     return status;
3121758b4ee8SAndy Ritger }
3122758b4ee8SAndy Ritger 
3123758b4ee8SAndy Ritger static NV_STATUS
gsyncSetLsrMinTime(OBJGPU * pSourceGpu,PDACEXTERNALDEVICE pExtDev,NvU32 enable)3124758b4ee8SAndy Ritger gsyncSetLsrMinTime
3125758b4ee8SAndy Ritger (
3126758b4ee8SAndy Ritger     OBJGPU                                   *pSourceGpu,
3127758b4ee8SAndy Ritger     PDACEXTERNALDEVICE                        pExtDev,
3128758b4ee8SAndy Ritger     NvU32                                     enable
3129758b4ee8SAndy Ritger )
3130758b4ee8SAndy Ritger {
3131758b4ee8SAndy Ritger     PDACP2060EXTERNALDEVICE pThis    = (PDACP2060EXTERNALDEVICE)pExtDev;
3132758b4ee8SAndy Ritger     NV_STATUS               rmStatus = NV_OK;
3133758b4ee8SAndy Ritger     NvU32                   index;
3134758b4ee8SAndy Ritger 
3135758b4ee8SAndy Ritger     // Get Mosaic Timing Source GPU Connector Index.
3136758b4ee8SAndy Ritger     if (NV_OK != GetP2060ConnectorIndexFromGpu(pSourceGpu, pThis, &index))
3137758b4ee8SAndy Ritger     {
3138758b4ee8SAndy Ritger         return NV_ERR_GENERIC;
3139758b4ee8SAndy Ritger     }
3140758b4ee8SAndy Ritger 
3141758b4ee8SAndy Ritger     if (enable)
3142758b4ee8SAndy Ritger     {
3143758b4ee8SAndy Ritger         // Set LSR_MIN_TIME
3144758b4ee8SAndy Ritger         if (pThis->tSwapRdyHiLsrMinTime == 0)
3145758b4ee8SAndy Ritger         {
3146758b4ee8SAndy Ritger             NvU32 data = 0;
3147758b4ee8SAndy Ritger 
3148758b4ee8SAndy Ritger             // store Swap Lockout Window in pThis.
3149758b4ee8SAndy Ritger             pThis->tSwapRdyHiLsrMinTime = NV_REG_STR_TIME_SWAP_RDY_HI_MODIFY_LSR_MIN_TIME_DEFAULT;
3150758b4ee8SAndy Ritger 
3151758b4ee8SAndy Ritger             if (osReadRegistryDword(pSourceGpu,
3152758b4ee8SAndy Ritger                     NV_REG_STR_TIME_SWAP_RDY_HI_MODIFY_LSR_MIN_TIME, &data) == NV_OK)
3153758b4ee8SAndy Ritger             {
3154758b4ee8SAndy Ritger                 pThis->tSwapRdyHiLsrMinTime = data;
3155758b4ee8SAndy Ritger             }
3156758b4ee8SAndy Ritger         }
3157758b4ee8SAndy Ritger 
3158758b4ee8SAndy Ritger         if (pThis->Iface[index].DsiFliplock.saved == NV_FALSE)
3159758b4ee8SAndy Ritger         {
3160758b4ee8SAndy Ritger             KernelDisplay  *pKernelDisplay = GPU_GET_KERNEL_DISPLAY(pSourceGpu);
3161758b4ee8SAndy Ritger             NvU32           numHeads = kdispGetNumHeads(pKernelDisplay);
3162758b4ee8SAndy Ritger             NvU32           head;
3163758b4ee8SAndy Ritger 
3164758b4ee8SAndy Ritger             // Do we need to loop over numHeads?
3165758b4ee8SAndy Ritger             for (head = 0; head < numHeads; head++)
3166758b4ee8SAndy Ritger             {
3167758b4ee8SAndy Ritger                 NvU32 newLsrMinTime;
3168758b4ee8SAndy Ritger 
3169758b4ee8SAndy Ritger                 if ((rmStatus = kdispComputeLsrMinTimeValue_HAL(pSourceGpu, pKernelDisplay, head,
3170758b4ee8SAndy Ritger                                     pThis->tSwapRdyHiLsrMinTime, &newLsrMinTime)) == NV_OK)
3171758b4ee8SAndy Ritger                 {
3172758b4ee8SAndy Ritger                     NvU32 origLsrMinTime;
3173758b4ee8SAndy Ritger 
3174758b4ee8SAndy Ritger                     kdispSetSwapBarrierLsrMinTime_HAL(pSourceGpu, pKernelDisplay, head, &origLsrMinTime,
3175758b4ee8SAndy Ritger                         newLsrMinTime);
3176758b4ee8SAndy Ritger 
3177758b4ee8SAndy Ritger                     pThis->Iface[index].DsiFliplock.OrigLsrMinTime[head] = origLsrMinTime;
3178758b4ee8SAndy Ritger                 }
3179758b4ee8SAndy Ritger                 else
3180758b4ee8SAndy Ritger                 {
3181758b4ee8SAndy Ritger                     NV_PRINTF(LEVEL_ERROR,
3182758b4ee8SAndy Ritger                               "Error occured while computing LSR_MIN_TIME for Swap Barrier\n");
3183758b4ee8SAndy Ritger                     NV_ASSERT(0);
3184758b4ee8SAndy Ritger                 }
3185758b4ee8SAndy Ritger             }
3186758b4ee8SAndy Ritger 
3187758b4ee8SAndy Ritger             pThis->Iface[index].DsiFliplock.saved = NV_TRUE;
3188758b4ee8SAndy Ritger         }
3189758b4ee8SAndy Ritger     }
3190758b4ee8SAndy Ritger     else
3191758b4ee8SAndy Ritger     {
3192758b4ee8SAndy Ritger         if (pThis->Iface[index].DsiFliplock.saved == NV_TRUE)
3193758b4ee8SAndy Ritger         {
3194758b4ee8SAndy Ritger             KernelDisplay  *pKernelDisplay = GPU_GET_KERNEL_DISPLAY(pSourceGpu);
3195758b4ee8SAndy Ritger             NvU32           numHeads = kdispGetNumHeads(pKernelDisplay);
3196758b4ee8SAndy Ritger             NvU32           head;
3197758b4ee8SAndy Ritger 
3198758b4ee8SAndy Ritger             for (head = 0; head < numHeads; head++)
3199758b4ee8SAndy Ritger             {
3200758b4ee8SAndy Ritger                 kdispRestoreOriginalLsrMinTime_HAL(pSourceGpu, pKernelDisplay, head,
3201758b4ee8SAndy Ritger                     pThis->Iface[index].DsiFliplock.OrigLsrMinTime[head]);
3202758b4ee8SAndy Ritger             }
3203758b4ee8SAndy Ritger 
3204758b4ee8SAndy Ritger             pThis->Iface[index].DsiFliplock.saved = NV_FALSE;
3205758b4ee8SAndy Ritger         }
3206758b4ee8SAndy Ritger     }
3207758b4ee8SAndy Ritger 
3208758b4ee8SAndy Ritger     return rmStatus;
3209758b4ee8SAndy Ritger }
3210758b4ee8SAndy Ritger 
3211758b4ee8SAndy Ritger NV_STATUS
gsyncSetMosaic_P2060(OBJGPU * pSourceGpu,PDACEXTERNALDEVICE pExtDev,NV30F1_CTRL_GSYNC_SET_LOCAL_SYNC_PARAMS * pParams)3212758b4ee8SAndy Ritger gsyncSetMosaic_P2060
3213758b4ee8SAndy Ritger (
3214758b4ee8SAndy Ritger     OBJGPU                                   *pSourceGpu,
3215758b4ee8SAndy Ritger     PDACEXTERNALDEVICE                        pExtDev,
3216758b4ee8SAndy Ritger     NV30F1_CTRL_GSYNC_SET_LOCAL_SYNC_PARAMS *pParams
3217758b4ee8SAndy Ritger )
3218758b4ee8SAndy Ritger {
3219758b4ee8SAndy Ritger     PDACP2060EXTERNALDEVICE pThis = (PDACP2060EXTERNALDEVICE)pExtDev;
3220758b4ee8SAndy Ritger     NV_STATUS rmStatus = NV_OK;
3221758b4ee8SAndy Ritger     OBJGPU *pTempGpu = NULL;
3222b5bf85a8SAndy Ritger     NvU8 mosaicReg;
3223b5bf85a8SAndy Ritger     NvU32 i;
3224758b4ee8SAndy Ritger     NvU32 mosaicGroup = pParams->mosaicGroupNumber;
3225758b4ee8SAndy Ritger 
3226758b4ee8SAndy Ritger     if (mosaicGroup >= NV_P2060_MAX_MOSAIC_GROUPS)
3227758b4ee8SAndy Ritger     {
3228758b4ee8SAndy Ritger         NV_PRINTF(LEVEL_ERROR,
3229758b4ee8SAndy Ritger                   "mosaicGroup equaling/extending NV_P2060_MAX_MOSAIC_GROUPS.\n");
3230758b4ee8SAndy Ritger         return NV_ERR_INVALID_ARGUMENT;
3231758b4ee8SAndy Ritger     }
3232758b4ee8SAndy Ritger 
3233758b4ee8SAndy Ritger     if (pParams->slaveGpuCount > NV_P2060_MAX_MOSAIC_SLAVES)
3234758b4ee8SAndy Ritger     {
3235758b4ee8SAndy Ritger         NV_PRINTF(LEVEL_ERROR,
3236758b4ee8SAndy Ritger                   "mosaic slaveGpuCount extending NV_P2060_MAX_MOSAIC_SLAVES.\n");
3237758b4ee8SAndy Ritger         return NV_ERR_INVALID_ARGUMENT;
3238758b4ee8SAndy Ritger     }
3239758b4ee8SAndy Ritger 
3240758b4ee8SAndy Ritger     if (pParams->enableMosaic) {
3241758b4ee8SAndy Ritger 
3242758b4ee8SAndy Ritger         NvU32 index;
3243758b4ee8SAndy Ritger         if (pThis->MosaicGroup[mosaicGroup].enabledMosaic)
3244758b4ee8SAndy Ritger         {
3245758b4ee8SAndy Ritger             // mosaic is already enabled for this group,
3246758b4ee8SAndy Ritger             // client should disable it first and re-query for this group.
3247758b4ee8SAndy Ritger             NV_PRINTF(LEVEL_ERROR,
3248758b4ee8SAndy Ritger                       "trying to enable mosaicGroup which is already enabled.\n");
3249758b4ee8SAndy Ritger             return NV_ERR_INVALID_ARGUMENT;
3250758b4ee8SAndy Ritger         }
3251758b4ee8SAndy Ritger 
3252758b4ee8SAndy Ritger         // Get Mosaic Timing Source GPU Connector Index.
3253758b4ee8SAndy Ritger         if ( NV_OK != GetP2060ConnectorIndexFromGpu(pSourceGpu, pThis, &index))
3254758b4ee8SAndy Ritger         {
3255758b4ee8SAndy Ritger              return NV_ERR_GENERIC;
3256758b4ee8SAndy Ritger         }
3257758b4ee8SAndy Ritger 
3258758b4ee8SAndy Ritger         pThis->MosaicGroup[mosaicGroup].slaveGpuCount   = pParams->slaveGpuCount;
3259758b4ee8SAndy Ritger         pThis->MosaicGroup[mosaicGroup].gpuTimingSource = pThis->Iface[index].GpuInfo.gpuId;
3260758b4ee8SAndy Ritger 
3261758b4ee8SAndy Ritger         for (i = 0; i < pThis->MosaicGroup[mosaicGroup].slaveGpuCount; i++)
3262758b4ee8SAndy Ritger         {
3263758b4ee8SAndy Ritger            pThis->MosaicGroup[mosaicGroup].gpuTimingSlaves[i] = pParams->gpuTimingSlaves[i];
3264758b4ee8SAndy Ritger 
3265758b4ee8SAndy Ritger            pTempGpu = gpumgrGetGpuFromId(pParams->gpuTimingSlaves[i]);
3266758b4ee8SAndy Ritger            NV_ASSERT_OR_RETURN(pTempGpu, NV_ERR_GENERIC);
3267758b4ee8SAndy Ritger 
3268758b4ee8SAndy Ritger            // Update register of mosaic timing slaves first
3269758b4ee8SAndy Ritger            mosaicReg = 0;
3270758b4ee8SAndy Ritger            mosaicReg = FLD_SET_DRF_NUM(_P2060, _MOSAIC_MODE, _TS,    (NvU8)index, mosaicReg);
3271758b4ee8SAndy Ritger            mosaicReg = FLD_SET_DRF_NUM(_P2060, _MOSAIC_MODE, _GROUP, (NvU8)mosaicGroup, mosaicReg);
3272758b4ee8SAndy Ritger            mosaicReg = FLD_SET_DRF(_P2060, _MOSAIC_MODE, _ENABLE, _TRUE, mosaicReg);
3273758b4ee8SAndy Ritger 
3274758b4ee8SAndy Ritger            rmStatus |= writeregu008_extdeviceTargeted(pTempGpu,
3275758b4ee8SAndy Ritger                           (PDACEXTERNALDEVICE)pThis, NV_P2060_MOSAIC_MODE, mosaicReg);
3276758b4ee8SAndy Ritger            if (rmStatus != NV_OK)
3277758b4ee8SAndy Ritger            {
3278758b4ee8SAndy Ritger                NV_PRINTF(LEVEL_ERROR,
3279758b4ee8SAndy Ritger                          "Failed to write P2060 mosaic slave register.\n");
3280758b4ee8SAndy Ritger                return NV_ERR_GENERIC;
3281758b4ee8SAndy Ritger            }
3282758b4ee8SAndy Ritger 
3283758b4ee8SAndy Ritger            // Set LSR_MIN_TIME
3284758b4ee8SAndy Ritger            gsyncSetLsrMinTime(pTempGpu, pExtDev, pParams->enableMosaic);
3285758b4ee8SAndy Ritger         }
3286758b4ee8SAndy Ritger 
3287758b4ee8SAndy Ritger         gsyncSetLsrMinTime(pSourceGpu, pExtDev, pParams->enableMosaic);
3288758b4ee8SAndy Ritger 
3289758b4ee8SAndy Ritger         // Update registers of mosaic timing source.
3290758b4ee8SAndy Ritger         mosaicReg = 0;
3291758b4ee8SAndy Ritger         mosaicReg = FLD_SET_DRF_NUM(_P2060, _MOSAIC_MODE, _TS,    (NvU8)index, mosaicReg);
3292758b4ee8SAndy Ritger         mosaicReg = FLD_SET_DRF_NUM(_P2060, _MOSAIC_MODE, _GROUP, (NvU8)mosaicGroup, mosaicReg);
3293758b4ee8SAndy Ritger         mosaicReg = FLD_SET_DRF(_P2060, _MOSAIC_MODE, _ENABLE, _TRUE, mosaicReg);
3294758b4ee8SAndy Ritger 
3295758b4ee8SAndy Ritger         rmStatus |= writeregu008_extdeviceTargeted(pSourceGpu,
3296758b4ee8SAndy Ritger                           (PDACEXTERNALDEVICE)pThis, NV_P2060_MOSAIC_MODE, mosaicReg);
3297758b4ee8SAndy Ritger         if (rmStatus != NV_OK)
3298758b4ee8SAndy Ritger         {
3299758b4ee8SAndy Ritger             NV_PRINTF(LEVEL_ERROR,
3300758b4ee8SAndy Ritger                       "Failed to write P2060 mosaic Source register.\n");
3301758b4ee8SAndy Ritger             return NV_ERR_GENERIC;
3302758b4ee8SAndy Ritger         }
3303758b4ee8SAndy Ritger 
3304758b4ee8SAndy Ritger         // Mark as Mosaic enabled for specified group
3305758b4ee8SAndy Ritger         pThis->MosaicGroup[mosaicGroup].enabledMosaic = NV_TRUE;
3306758b4ee8SAndy Ritger     }
3307758b4ee8SAndy Ritger     else
3308758b4ee8SAndy Ritger     {
3309758b4ee8SAndy Ritger         if (!pThis->MosaicGroup[mosaicGroup].enabledMosaic)
3310758b4ee8SAndy Ritger         {
3311758b4ee8SAndy Ritger             // mosaicgroup is not enabled, so can not disable
3312758b4ee8SAndy Ritger             NV_PRINTF(LEVEL_ERROR,
3313758b4ee8SAndy Ritger                       "trying to disable mosaicGroup which is not enabled.\n");
3314758b4ee8SAndy Ritger             return NV_ERR_INVALID_ARGUMENT;
3315758b4ee8SAndy Ritger         }
3316758b4ee8SAndy Ritger 
3317758b4ee8SAndy Ritger         for (i = 0; i < pThis->MosaicGroup[mosaicGroup].slaveGpuCount; i++)
3318758b4ee8SAndy Ritger         {
3319758b4ee8SAndy Ritger             pTempGpu = gpumgrGetGpuFromId(pThis->MosaicGroup[mosaicGroup].gpuTimingSlaves[i]);
3320758b4ee8SAndy Ritger             NV_ASSERT_OR_RETURN(pTempGpu, NV_ERR_GENERIC);
3321758b4ee8SAndy Ritger 
3322758b4ee8SAndy Ritger             rmStatus |= writeregu008_extdeviceTargeted(pTempGpu,
3323758b4ee8SAndy Ritger                           (PDACEXTERNALDEVICE)pThis, NV_P2060_MOSAIC_MODE, 0x00);
3324758b4ee8SAndy Ritger             if (rmStatus != NV_OK)
3325758b4ee8SAndy Ritger             {
3326758b4ee8SAndy Ritger                NV_PRINTF(LEVEL_ERROR,
3327758b4ee8SAndy Ritger                          "Failed to write P2060 mosaic slave register.\n");
3328758b4ee8SAndy Ritger                return NV_ERR_GENERIC;
3329758b4ee8SAndy Ritger             }
3330758b4ee8SAndy Ritger 
3331758b4ee8SAndy Ritger             // Reset LSR_MIN_TIME
3332758b4ee8SAndy Ritger             gsyncSetLsrMinTime(pTempGpu, pExtDev, pParams->enableMosaic);
3333758b4ee8SAndy Ritger         }
3334758b4ee8SAndy Ritger 
3335758b4ee8SAndy Ritger         gsyncSetLsrMinTime(pSourceGpu, pExtDev, pParams->enableMosaic);
3336758b4ee8SAndy Ritger 
3337758b4ee8SAndy Ritger         rmStatus |= writeregu008_extdeviceTargeted(pSourceGpu,
3338758b4ee8SAndy Ritger                           (PDACEXTERNALDEVICE)pThis, NV_P2060_MOSAIC_MODE, 0x00);
3339758b4ee8SAndy Ritger         if (rmStatus != NV_OK)
3340758b4ee8SAndy Ritger         {
3341758b4ee8SAndy Ritger              NV_PRINTF(LEVEL_ERROR,
3342758b4ee8SAndy Ritger                        "Failed to write P2060 mosaic Source register.\n");
3343758b4ee8SAndy Ritger              return NV_ERR_GENERIC;
3344758b4ee8SAndy Ritger         }
3345758b4ee8SAndy Ritger 
3346758b4ee8SAndy Ritger         // reset structure for specified group
3347758b4ee8SAndy Ritger         gsyncResetMosaicData_P2060(mosaicGroup, pThis);
3348758b4ee8SAndy Ritger     }
3349758b4ee8SAndy Ritger 
3350758b4ee8SAndy Ritger     return rmStatus;
3351758b4ee8SAndy Ritger }
3352758b4ee8SAndy Ritger 
3353758b4ee8SAndy Ritger #ifdef DEBUG
3354758b4ee8SAndy Ritger /*
3355758b4ee8SAndy Ritger  * Helper function to printout the most relevant P2060_status
3356758b4ee8SAndy Ritger  * register informations in a human readable form.
3357758b4ee8SAndy Ritger  */
3358758b4ee8SAndy Ritger static void
DbgPrintP2060StatusRegister(NvU32 regStatus)3359b5bf85a8SAndy Ritger DbgPrintP2060StatusRegister(NvU32 regStatus)
3360758b4ee8SAndy Ritger {
3361758b4ee8SAndy Ritger     if (DRF_VAL(_P2060, _STATUS, _SYNC_LOSS, regStatus))
3362b5bf85a8SAndy Ritger         NV_PRINTF_EX(NV_PRINTF_MODULE, LEVEL_INFO, "SYNC_LOSS ");
3363758b4ee8SAndy Ritger     if (DRF_VAL(_P2060, _STATUS, _STEREO, regStatus))
3364b5bf85a8SAndy Ritger         NV_PRINTF_EX(NV_PRINTF_MODULE, LEVEL_INFO, "STEREO_LOCK ");
3365758b4ee8SAndy Ritger     if (NV_P2060_STATUS_VCXO_LOCK == DRF_VAL(_P2060, _STATUS, _VCXO, regStatus))
3366b5bf85a8SAndy Ritger         NV_PRINTF_EX(NV_PRINTF_MODULE, LEVEL_INFO, "VCXO_LOCK ");
3367758b4ee8SAndy Ritger     if (NV_P2060_STATUS_VCXO_NOLOCK_TOO_FAST == DRF_VAL(_P2060, _STATUS, _VCXO, regStatus))
3368b5bf85a8SAndy Ritger         NV_PRINTF_EX(NV_PRINTF_MODULE, LEVEL_INFO, "VCXO_NOLOCK_TOO_FAST ");
3369758b4ee8SAndy Ritger     if (NV_P2060_STATUS_VCXO_NOLOCK_TOO_SLOW == DRF_VAL(_P2060, _STATUS, _VCXO, regStatus))
3370b5bf85a8SAndy Ritger         NV_PRINTF_EX(NV_PRINTF_MODULE, LEVEL_INFO, "VCXO_NOLOCK_TOO_SLOW ");
3371758b4ee8SAndy Ritger     if (NV_P2060_STATUS_VCXO_NOT_SERVO == DRF_VAL(_P2060, _STATUS, _VCXO, regStatus))
3372b5bf85a8SAndy Ritger         NV_PRINTF_EX(NV_PRINTF_MODULE, LEVEL_INFO, "VCXO_NOT_SERVO ");
3373758b4ee8SAndy Ritger }
3374758b4ee8SAndy Ritger #else
3375b5bf85a8SAndy Ritger #define DbgPrintP2060StatusRegister(regStatus)
3376758b4ee8SAndy Ritger #endif
3377758b4ee8SAndy Ritger 
3378758b4ee8SAndy Ritger static NV_STATUS
gsyncGpuStereoHeadSync(OBJGPU * pGpu,NvU32 iface,PDACEXTERNALDEVICE pExtDev,NvU32 status1)3379758b4ee8SAndy Ritger gsyncGpuStereoHeadSync(OBJGPU *pGpu, NvU32 iface, PDACEXTERNALDEVICE pExtDev, NvU32 status1)
3380758b4ee8SAndy Ritger {
3381758b4ee8SAndy Ritger     DACP2060EXTERNALDEVICE *pThis = (PDACP2060EXTERNALDEVICE)pExtDev;
3382758b4ee8SAndy Ritger     KernelDisplay *pKernelDisplay = GPU_GET_KERNEL_DISPLAY(pGpu);
3383758b4ee8SAndy Ritger     RM_API   *pRmApi      = GPU_GET_PHYSICAL_RMAPI(pGpu);
3384758b4ee8SAndy Ritger     NvU32     hClient     = pGpu->hInternalClient;
3385758b4ee8SAndy Ritger     NvU32     hSubdevice  = pGpu->hInternalSubdevice;
3386758b4ee8SAndy Ritger     NV_STATUS status      = NV_OK;
3387758b4ee8SAndy Ritger     NvU32     numHeads    = kdispGetNumHeads(pKernelDisplay);
3388758b4ee8SAndy Ritger     NvU32     headIdx;
3389758b4ee8SAndy Ritger     NV2080_CTRL_INTERNAL_GSYNC_SET_STREO_SYNC_PARAMS ctrlParams = {0};
3390758b4ee8SAndy Ritger 
3391758b4ee8SAndy Ritger     for (headIdx = 0; headIdx < numHeads; headIdx++)
3392758b4ee8SAndy Ritger     {
3393758b4ee8SAndy Ritger         ctrlParams.slave[headIdx]      = pThis->Iface[iface].Sync.Slaved[headIdx];
3394758b4ee8SAndy Ritger         ctrlParams.localSlave[headIdx] = pThis->Iface[iface].Sync.LocalSlave[headIdx];
3395758b4ee8SAndy Ritger         ctrlParams.master[headIdx]     = pThis->Iface[iface].Sync.Master[headIdx];
3396758b4ee8SAndy Ritger     }
3397758b4ee8SAndy Ritger 
3398758b4ee8SAndy Ritger     ctrlParams.regStatus = status1;
3399758b4ee8SAndy Ritger     status = pRmApi->Control(pRmApi, hClient, hSubdevice,
3400758b4ee8SAndy Ritger                              NV2080_CTRL_CMD_INTERNAL_GSYNC_SET_STREO_SYNC,
3401758b4ee8SAndy Ritger                              &ctrlParams, sizeof(ctrlParams));
3402758b4ee8SAndy Ritger 
3403758b4ee8SAndy Ritger     if (status != NV_OK)
3404758b4ee8SAndy Ritger     {
3405758b4ee8SAndy Ritger         NV_PRINTF(LEVEL_ERROR, "Stereo headsync failed\n");
3406758b4ee8SAndy Ritger     }
3407758b4ee8SAndy Ritger 
3408758b4ee8SAndy Ritger     return status;
3409758b4ee8SAndy Ritger }
3410758b4ee8SAndy Ritger 
3411758b4ee8SAndy Ritger /*
3412758b4ee8SAndy Ritger  * Update the status register snapshot and
3413758b4ee8SAndy Ritger  * send loss/gain events to client if any.
3414758b4ee8SAndy Ritger  */
3415758b4ee8SAndy Ritger static NV_STATUS
gsyncUpdateGsyncStatusSnapshot_P2060(OBJGPU * pGpu,PDACEXTERNALDEVICE pExtDev)3416758b4ee8SAndy Ritger gsyncUpdateGsyncStatusSnapshot_P2060
3417758b4ee8SAndy Ritger (
3418758b4ee8SAndy Ritger     OBJGPU *pGpu,
3419758b4ee8SAndy Ritger     PDACEXTERNALDEVICE pExtDev
3420758b4ee8SAndy Ritger )
3421758b4ee8SAndy Ritger {
3422758b4ee8SAndy Ritger     PDACP2060EXTERNALDEVICE pThis = (PDACP2060EXTERNALDEVICE)pExtDev;
3423758b4ee8SAndy Ritger     NvU32 iface;
3424758b4ee8SAndy Ritger     NvU8 regStatus = 0;
3425758b4ee8SAndy Ritger     NV_STATUS rmStatus = NV_OK;
3426758b4ee8SAndy Ritger     NvU32 ifaceEvents[NV_P2060_MAX_IFACES_PER_GSYNC];
3427758b4ee8SAndy Ritger 
3428758b4ee8SAndy Ritger     // Only read status variables if the board is framelocked at all.
3429758b4ee8SAndy Ritger     if (!gsyncIsFrameLocked_P2060(pThis))
3430758b4ee8SAndy Ritger     {
3431758b4ee8SAndy Ritger         return rmStatus;
3432758b4ee8SAndy Ritger     }
3433758b4ee8SAndy Ritger 
3434758b4ee8SAndy Ritger     for (iface = 0; iface < NV_P2060_MAX_IFACES_PER_GSYNC; iface++)
3435758b4ee8SAndy Ritger     {
3436758b4ee8SAndy Ritger         NvU32 diffStatus = 0x00;
3437758b4ee8SAndy Ritger         NvU32 oldStatus  = 0x00;
3438758b4ee8SAndy Ritger         NvU32 newStatus  = 0x00;
3439758b4ee8SAndy Ritger         ifaceEvents[iface] = 0x00;
3440758b4ee8SAndy Ritger 
3441758b4ee8SAndy Ritger         // get status update for each interface
3442758b4ee8SAndy Ritger         if (pThis->Iface[iface].GpuInfo.gpuId != NV0000_CTRL_GPU_INVALID_ID)
3443758b4ee8SAndy Ritger         {
3444758b4ee8SAndy Ritger             int updateSnapshot = 1;
3445758b4ee8SAndy Ritger             int localMaster = 0;
3446758b4ee8SAndy Ritger 
3447758b4ee8SAndy Ritger             // Take care of tracking state of connected gpu, not per incoming.
3448758b4ee8SAndy Ritger             OBJGPU *pIfaceGpu = gpumgrGetGpuFromId(pThis->Iface[iface].GpuInfo.gpuId);
3449758b4ee8SAndy Ritger 
3450758b4ee8SAndy Ritger             NV_ASSERT(pIfaceGpu);
3451758b4ee8SAndy Ritger 
3452758b4ee8SAndy Ritger             rmStatus  = readregu008_extdeviceTargeted(pIfaceGpu, pExtDev, (NvU8)NV_P2060_STATUS, &regStatus);
3453758b4ee8SAndy Ritger             if ( NV_OK != rmStatus )
3454758b4ee8SAndy Ritger             {
3455758b4ee8SAndy Ritger                 return NV_ERR_GENERIC;
3456758b4ee8SAndy Ritger             }
3457758b4ee8SAndy Ritger 
3458758b4ee8SAndy Ritger             oldStatus = pThis->Snapshot[iface].Status1;
3459758b4ee8SAndy Ritger             newStatus = (NvU32)regStatus;
3460758b4ee8SAndy Ritger 
3461758b4ee8SAndy Ritger             // Check for a local master which generates the sync so it's always synched.
3462758b4ee8SAndy Ritger             if ( (NV_P2060_STATUS_VCXO_NOT_SERVO  == DRF_VAL(_P2060, _STATUS, _VCXO,      newStatus)) &&
3463758b4ee8SAndy Ritger                  (NV_P2060_STATUS_SYNC_LOSS_FALSE == DRF_VAL(_P2060, _STATUS, _SYNC_LOSS, newStatus)))
3464758b4ee8SAndy Ritger             {
3465758b4ee8SAndy Ritger                 localMaster = 1;
3466758b4ee8SAndy Ritger                 if (!pThis->Iface[iface].gainedSync)
3467758b4ee8SAndy Ritger                 {
3468758b4ee8SAndy Ritger                     NV_PRINTF(LEVEL_INFO,
3469758b4ee8SAndy Ritger                               "P2060[%d] is local master => GAINED SYNC\n",
3470758b4ee8SAndy Ritger                               iface);
3471758b4ee8SAndy Ritger                     pThis->Iface[iface].gainedSync = 1;
3472758b4ee8SAndy Ritger                 }
3473758b4ee8SAndy Ritger             }
3474758b4ee8SAndy Ritger             else
3475758b4ee8SAndy Ritger             {
3476758b4ee8SAndy Ritger                 // For slaves or masters driven by housesync we need to wait for a sync.
3477758b4ee8SAndy Ritger 
3478758b4ee8SAndy Ritger                 // 1st wait for syncgain before doing anything else.
3479758b4ee8SAndy Ritger                 if ((!pThis->Iface[iface].gainedSync) &&
3480758b4ee8SAndy Ritger                     (NV_P2060_STATUS_VCXO_LOCK == DRF_VAL(_P2060, _STATUS, _VCXO, newStatus)))
3481758b4ee8SAndy Ritger                 {
3482758b4ee8SAndy Ritger                     OBJTMR *pTmr = GPU_GET_TIMER(pIfaceGpu);
3483758b4ee8SAndy Ritger                     NvU64 timeDiff;
3484758b4ee8SAndy Ritger                     NvU64 currentTime;
3485758b4ee8SAndy Ritger 
3486758b4ee8SAndy Ritger                     // get the current time
3487758b4ee8SAndy Ritger                     currentTime = tmrGetTime_HAL(pIfaceGpu, pTmr);
3488758b4ee8SAndy Ritger 
3489758b4ee8SAndy Ritger                     //
3490758b4ee8SAndy Ritger                     // Initialize waittime.
3491758b4ee8SAndy Ritger                     // We're using a threshold of 10 seconds before we're accepting sync gain.
3492758b4ee8SAndy Ritger                     //
3493758b4ee8SAndy Ritger                     if (0 == pThis->Snapshot[iface].lastSyncCheckTime)
3494758b4ee8SAndy Ritger                     {
3495758b4ee8SAndy Ritger                         pThis->Snapshot[iface].lastSyncCheckTime = currentTime;
3496758b4ee8SAndy Ritger                     }
3497758b4ee8SAndy Ritger 
3498758b4ee8SAndy Ritger                     // calculate the time difference from last change.
3499758b4ee8SAndy Ritger                     timeDiff = ((currentTime - pThis->Snapshot[iface].lastSyncCheckTime) / 1000000); // time in ms
3500758b4ee8SAndy Ritger 
3501758b4ee8SAndy Ritger                     NV_PRINTF(LEVEL_INFO,
3502758b4ee8SAndy Ritger                               "P2060[%d] snapshot timeDiff is %d ms\n", iface,
3503758b4ee8SAndy Ritger                               (NvU32)timeDiff);
3504758b4ee8SAndy Ritger 
3505758b4ee8SAndy Ritger                     //
3506758b4ee8SAndy Ritger                     // Update settings if we got no lock or if lock has settled long enough.
3507758b4ee8SAndy Ritger                     // This is currently selected to 5 seconds by experiments with syncing
3508758b4ee8SAndy Ritger                     // with stereo enabled.
3509758b4ee8SAndy Ritger                     //
3510758b4ee8SAndy Ritger                     if (timeDiff >= 5000)
3511758b4ee8SAndy Ritger                     {
3512758b4ee8SAndy Ritger                         NV_PRINTF(LEVEL_INFO, "P2060[%d] GAINED SYNC\n",
3513758b4ee8SAndy Ritger                                   iface);
3514758b4ee8SAndy Ritger 
3515758b4ee8SAndy Ritger                         pThis->Iface[iface].gainedSync = 1;
3516758b4ee8SAndy Ritger 
3517758b4ee8SAndy Ritger                         // We've gained sync, right time to also sync the stereo phase.
3518758b4ee8SAndy Ritger                         if (FLD_TEST_DRF(_P2060, _STATUS, _GPU_STEREO, _ACTIVE, newStatus))
3519758b4ee8SAndy Ritger                         {
3520758b4ee8SAndy Ritger                             gsyncGpuStereoHeadSync(pIfaceGpu, iface, pExtDev, newStatus);
3521758b4ee8SAndy Ritger                             // Reset toggle time to wait some time before checking stereo sync again.
3522758b4ee8SAndy Ritger                             pThis->Snapshot[iface].lastStereoToggleTime = 0;
3523758b4ee8SAndy Ritger                         }
3524758b4ee8SAndy Ritger                     }
3525758b4ee8SAndy Ritger                     else
3526758b4ee8SAndy Ritger                     {
3527758b4ee8SAndy Ritger                         //
3528758b4ee8SAndy Ritger                         // We haven't reached the settle down time for a sync,
3529758b4ee8SAndy Ritger                         // so don't update the snapshot this time.
3530758b4ee8SAndy Ritger                         //
3531758b4ee8SAndy Ritger                         updateSnapshot = 0;
3532758b4ee8SAndy Ritger                     }
3533758b4ee8SAndy Ritger                 }
3534758b4ee8SAndy Ritger             }
3535758b4ee8SAndy Ritger 
3536758b4ee8SAndy Ritger             // Take over new status and send events only if desired.
3537758b4ee8SAndy Ritger             if (updateSnapshot)
3538758b4ee8SAndy Ritger             {
3539758b4ee8SAndy Ritger                 //
3540758b4ee8SAndy Ritger                 // If we lost sync again reestablish syncwait mechanism.
3541758b4ee8SAndy Ritger                 // Local master can't loose sync per definition.
3542758b4ee8SAndy Ritger                 //
3543758b4ee8SAndy Ritger                 if ((NV_P2060_STATUS_VCXO_LOCK != DRF_VAL(_P2060, _STATUS, _VCXO, newStatus)) &&
3544758b4ee8SAndy Ritger                     (!localMaster))
3545758b4ee8SAndy Ritger                 {
3546758b4ee8SAndy Ritger                     pThis->Iface[iface].gainedSync = 0;
3547758b4ee8SAndy Ritger                     pThis->Snapshot[iface].lastSyncCheckTime = 0;
3548758b4ee8SAndy Ritger                 }
3549758b4ee8SAndy Ritger 
3550758b4ee8SAndy Ritger                 NV_PRINTF(LEVEL_INFO, "Update P2060[%d] settled from 0x%x ( ",
3551758b4ee8SAndy Ritger                           iface, oldStatus);
3552b5bf85a8SAndy Ritger                 DbgPrintP2060StatusRegister(oldStatus);
3553758b4ee8SAndy Ritger                 NV_PRINTF_EX(NV_PRINTF_MODULE, LEVEL_INFO, ") to 0x%x ( ", newStatus);
3554b5bf85a8SAndy Ritger                 DbgPrintP2060StatusRegister(newStatus);
3555758b4ee8SAndy Ritger                 NV_PRINTF_EX(NV_PRINTF_MODULE, LEVEL_INFO, ")\n");
3556758b4ee8SAndy Ritger 
3557758b4ee8SAndy Ritger                 diffStatus = (oldStatus ^ newStatus);
3558758b4ee8SAndy Ritger 
3559758b4ee8SAndy Ritger                 pThis->Snapshot[iface].Status1 = newStatus;
3560758b4ee8SAndy Ritger             }
3561758b4ee8SAndy Ritger         }
3562758b4ee8SAndy Ritger         else
3563758b4ee8SAndy Ritger         {
3564758b4ee8SAndy Ritger             continue;
3565758b4ee8SAndy Ritger         }
3566758b4ee8SAndy Ritger 
3567758b4ee8SAndy Ritger         if ((DRF_VAL(_P2060, _STATUS, _VCXO,      diffStatus)) ||
3568758b4ee8SAndy Ritger             (DRF_VAL(_P2060, _STATUS, _SYNC_LOSS, diffStatus)) ) // diff state: sync or lock
3569758b4ee8SAndy Ritger         {
3570758b4ee8SAndy Ritger             if (FLD_TEST_DRF(_P2060, _STATUS, _SYNC_LOSS, _FALSE, newStatus) &&
3571758b4ee8SAndy Ritger                 (FLD_TEST_DRF(_P2060, _STATUS, _VCXO,      _LOCK, newStatus) ||
3572758b4ee8SAndy Ritger                  FLD_TEST_DRF(_P2060, _STATUS, _VCXO, _NOT_SERVO, newStatus)))
3573758b4ee8SAndy Ritger             {
3574758b4ee8SAndy Ritger                 ifaceEvents[iface] |= NVBIT(NV30F1_GSYNC_NOTIFIERS_SYNC_GAIN(iface));
3575758b4ee8SAndy Ritger             }
3576758b4ee8SAndy Ritger             else
3577758b4ee8SAndy Ritger             {
3578758b4ee8SAndy Ritger                 ifaceEvents[iface] |= NVBIT(NV30F1_GSYNC_NOTIFIERS_SYNC_LOSS(iface));
3579758b4ee8SAndy Ritger             }
3580758b4ee8SAndy Ritger         }
3581758b4ee8SAndy Ritger 
3582758b4ee8SAndy Ritger         // Only track stereo diff states when we are VCXO locked or NOT SERVO.
3583758b4ee8SAndy Ritger         if ((FLD_TEST_DRF(_P2060, _STATUS, _VCXO, _LOCK, newStatus) ||
3584758b4ee8SAndy Ritger              FLD_TEST_DRF(_P2060, _STATUS, _VCXO, _NOT_SERVO, newStatus)) &&
3585758b4ee8SAndy Ritger              DRF_VAL(_P2060, _STATUS, _STEREO, diffStatus)) // diff state: stereo
3586758b4ee8SAndy Ritger         {
3587758b4ee8SAndy Ritger             if (FLD_TEST_DRF(_P2060, _STATUS, _STEREO, _LOCK, newStatus))
3588758b4ee8SAndy Ritger             {
3589758b4ee8SAndy Ritger                 ifaceEvents[iface] |= NVBIT(NV30F1_GSYNC_NOTIFIERS_STEREO_GAIN(iface));
3590758b4ee8SAndy Ritger             }
3591758b4ee8SAndy Ritger             else
3592758b4ee8SAndy Ritger             {
3593758b4ee8SAndy Ritger                 ifaceEvents[iface] |= NVBIT(NV30F1_GSYNC_NOTIFIERS_STEREO_LOSS(iface));
3594758b4ee8SAndy Ritger             }
3595758b4ee8SAndy Ritger         }
3596758b4ee8SAndy Ritger     }
3597758b4ee8SAndy Ritger 
3598758b4ee8SAndy Ritger     for (iface = 0; iface < NV_P2060_MAX_IFACES_PER_GSYNC; iface++)
3599758b4ee8SAndy Ritger     {
3600758b4ee8SAndy Ritger         // Only check stereo phase if we've gained sync.
3601758b4ee8SAndy Ritger         if (pThis->Iface[iface].gainedSync)
3602758b4ee8SAndy Ritger         {
3603758b4ee8SAndy Ritger             // Only check and adjust stereo phase if stereo is enabled on this system.
3604758b4ee8SAndy Ritger             if (FLD_TEST_DRF(_P2060, _STATUS, _GPU_STEREO, _ACTIVE, pThis->Snapshot[iface].Status1))
3605758b4ee8SAndy Ritger             {
3606758b4ee8SAndy Ritger                 //
3607758b4ee8SAndy Ritger                 // gsyncGpuStereoHeadSync() works without any gsync board interaction
3608758b4ee8SAndy Ritger                 // with gpu register access only. In addition it will also sync heads
3609758b4ee8SAndy Ritger                 // which are not driving the stereo pin and can't be monitored by the
3610758b4ee8SAndy Ritger                 // gsync board.
3611758b4ee8SAndy Ritger                 // So don't look at the gsync stereolock status as this doesn't cover
3612758b4ee8SAndy Ritger                 // all heads.
3613758b4ee8SAndy Ritger                 // Take care of tracking state of connected gpu, not per incoming.
3614758b4ee8SAndy Ritger                 //
3615758b4ee8SAndy Ritger                 OBJGPU *pIfaceGpu = gpumgrGetGpuFromId(pThis->Iface[iface].GpuInfo.gpuId);
3616758b4ee8SAndy Ritger                 OBJTMR *pIfaceTmr;
3617758b4ee8SAndy Ritger                 NvU32 timeDiff;
3618758b4ee8SAndy Ritger                 NvU64 currentTime;
3619758b4ee8SAndy Ritger 
3620758b4ee8SAndy Ritger                 NV_ASSERT(pIfaceGpu);
3621758b4ee8SAndy Ritger 
3622758b4ee8SAndy Ritger                 pIfaceTmr = GPU_GET_TIMER(pIfaceGpu);
3623758b4ee8SAndy Ritger 
3624758b4ee8SAndy Ritger                 currentTime = tmrGetTime_HAL(pIfaceGpu, pIfaceTmr);  // get the current time
3625758b4ee8SAndy Ritger 
3626758b4ee8SAndy Ritger                 if (pThis->Snapshot[iface].lastStereoToggleTime == 0)
3627758b4ee8SAndy Ritger                 {
3628758b4ee8SAndy Ritger                     pThis->Snapshot[iface].lastStereoToggleTime = currentTime;
3629758b4ee8SAndy Ritger                 }
3630758b4ee8SAndy Ritger                 timeDiff = (NvU32)((currentTime - pThis->Snapshot[iface].lastStereoToggleTime) / 1000000); // time in ms
3631758b4ee8SAndy Ritger 
3632758b4ee8SAndy Ritger                 // toggle stereo if it is not locked more than 5 sec.
3633758b4ee8SAndy Ritger                 if (timeDiff >= 5000)
3634758b4ee8SAndy Ritger                 {
3635758b4ee8SAndy Ritger                     gsyncGpuStereoHeadSync(pIfaceGpu, iface, pExtDev, pThis->Snapshot[iface].Status1);
3636758b4ee8SAndy Ritger                     pThis->Snapshot[iface].lastStereoToggleTime = currentTime;
3637758b4ee8SAndy Ritger                 }
3638758b4ee8SAndy Ritger 
3639758b4ee8SAndy Ritger                 // Only report stereo loss if stereo is not in phase.
3640758b4ee8SAndy Ritger                 if (!(FLD_TEST_DRF(_P2060, _STATUS, _STEREO, _LOCK, pThis->Snapshot[iface].Status1)))
3641758b4ee8SAndy Ritger                 {
3642758b4ee8SAndy Ritger                     ifaceEvents[iface] |= NVBIT(NV30F1_GSYNC_NOTIFIERS_STEREO_LOSS(iface)); // report loss this time.
3643758b4ee8SAndy Ritger                 }
3644758b4ee8SAndy Ritger             }
3645758b4ee8SAndy Ritger         }
3646758b4ee8SAndy Ritger     }
3647758b4ee8SAndy Ritger 
3648758b4ee8SAndy Ritger     for (iface = 0; iface < NV_P2060_MAX_IFACES_PER_GSYNC; iface++)
3649758b4ee8SAndy Ritger     {
3650758b4ee8SAndy Ritger         if (ifaceEvents[iface] && (pThis->Iface[iface].lastEventNotified != ifaceEvents[iface]))
3651758b4ee8SAndy Ritger         {
3652758b4ee8SAndy Ritger             NV_PRINTF(LEVEL_INFO, "Event P2060[%d]: 0x%x (", iface,
3653758b4ee8SAndy Ritger                       ifaceEvents[iface]);
3654b5bf85a8SAndy Ritger             gsyncDbgPrintGsyncEvents(ifaceEvents[iface], iface);
3655758b4ee8SAndy Ritger             NV_PRINTF_EX(NV_PRINTF_MODULE, LEVEL_INFO, ")\n");
3656758b4ee8SAndy Ritger 
3657758b4ee8SAndy Ritger             // notify clients that something has happened!
3658758b4ee8SAndy Ritger             gsyncSignalServiceRequested(gsyncGetGsyncInstance(pGpu), ifaceEvents[iface], iface);
3659758b4ee8SAndy Ritger             pThis->Iface[iface].lastEventNotified = ifaceEvents[iface];
3660758b4ee8SAndy Ritger         }
3661758b4ee8SAndy Ritger     }
3662758b4ee8SAndy Ritger 
3663758b4ee8SAndy Ritger     return NV_OK;
3664758b4ee8SAndy Ritger }
3665758b4ee8SAndy Ritger 
3666758b4ee8SAndy Ritger 
3667758b4ee8SAndy Ritger /*
3668758b4ee8SAndy Ritger  * Handle Get and Set queries related to signals.
3669758b4ee8SAndy Ritger  */
3670758b4ee8SAndy Ritger NV_STATUS
gsyncRefSignal_P2060(OBJGPU * pGpu,PDACEXTERNALDEVICE pExtDev,REFTYPE rType,GSYNCSYNCSIGNAL Signal,NvBool bRate,NvU32 * pPresence)3671758b4ee8SAndy Ritger gsyncRefSignal_P2060
3672758b4ee8SAndy Ritger (
3673758b4ee8SAndy Ritger     OBJGPU            *pGpu,
3674758b4ee8SAndy Ritger     PDACEXTERNALDEVICE pExtDev,
3675758b4ee8SAndy Ritger     REFTYPE            rType,
3676758b4ee8SAndy Ritger     GSYNCSYNCSIGNAL    Signal,
3677758b4ee8SAndy Ritger     NvBool             bRate,
3678758b4ee8SAndy Ritger     NvU32              *pPresence
3679758b4ee8SAndy Ritger )
3680758b4ee8SAndy Ritger {
3681758b4ee8SAndy Ritger     NV_STATUS status = NV_OK;
3682758b4ee8SAndy Ritger     NvU32 rate;
3683758b4ee8SAndy Ritger     NvU32 value = 0;
3684758b4ee8SAndy Ritger     NvU32 bMaster; // Is this Gsync in Master mode
3685758b4ee8SAndy Ritger     PDACP2060EXTERNALDEVICE pThis = (PDACP2060EXTERNALDEVICE)pExtDev;
3686758b4ee8SAndy Ritger 
3687758b4ee8SAndy Ritger     if (!bRate)
3688758b4ee8SAndy Ritger     {
3689758b4ee8SAndy Ritger         return NV_OK;
3690758b4ee8SAndy Ritger     }
3691758b4ee8SAndy Ritger 
3692758b4ee8SAndy Ritger     //
3693758b4ee8SAndy Ritger     // Is any display on this P2060 a master, or are we using an ext
3694758b4ee8SAndy Ritger     // sync to be master.
3695758b4ee8SAndy Ritger     //
3696758b4ee8SAndy Ritger     bMaster = !!gsyncReadMaster_P2060(pGpu, pThis);
3697758b4ee8SAndy Ritger 
3698758b4ee8SAndy Ritger     switch ( rType )
3699758b4ee8SAndy Ritger     {
3700758b4ee8SAndy Ritger     case refFetchGet:
3701758b4ee8SAndy Ritger          if (gsync_Signal_RJ45_0 == Signal || gsync_Signal_RJ45_1 == Signal)
3702758b4ee8SAndy Ritger          {
3703758b4ee8SAndy Ritger              // Relevant only if this port is an input
3704758b4ee8SAndy Ritger              NvU32 port0Direction, expectedPort0Direction;
3705758b4ee8SAndy Ritger              NvU32 port1Direction, expectedPort1Direction;
3706758b4ee8SAndy Ritger 
3707758b4ee8SAndy Ritger              status = gsyncReadFrameRate_P2060(pGpu, pExtDev, &rate);
3708758b4ee8SAndy Ritger              if (NV_OK != status)
3709758b4ee8SAndy Ritger                  return status;
3710758b4ee8SAndy Ritger 
3711758b4ee8SAndy Ritger              status  = readregu008_extdeviceTargeted(pGpu, pExtDev, (NvU8)NV_P2060_STATUS2, (NvU8*)&value);
3712758b4ee8SAndy Ritger              if (NV_OK != status)
3713758b4ee8SAndy Ritger                  return status;
3714758b4ee8SAndy Ritger 
3715758b4ee8SAndy Ritger              port0Direction = DRF_VAL(_P2060, _STATUS2, _PORT0, value);
3716758b4ee8SAndy Ritger              port1Direction = DRF_VAL(_P2060, _STATUS2, _PORT1, value);
3717758b4ee8SAndy Ritger 
3718758b4ee8SAndy Ritger              if (gsync_Signal_RJ45_0 == Signal)
3719758b4ee8SAndy Ritger              {
3720758b4ee8SAndy Ritger                  expectedPort0Direction = NV_P2060_STATUS2_PORT0_INPUT;
3721758b4ee8SAndy Ritger                  expectedPort1Direction = NV_P2060_STATUS2_PORT1_OUTPUT;
3722758b4ee8SAndy Ritger              }
3723758b4ee8SAndy Ritger              else
3724758b4ee8SAndy Ritger              {
3725758b4ee8SAndy Ritger                  expectedPort0Direction = NV_P2060_STATUS2_PORT0_OUTPUT;
3726758b4ee8SAndy Ritger                  expectedPort1Direction = NV_P2060_STATUS2_PORT1_INPUT;
3727758b4ee8SAndy Ritger              }
3728758b4ee8SAndy Ritger              if (port0Direction == expectedPort0Direction && port1Direction == expectedPort1Direction)
3729758b4ee8SAndy Ritger              {
3730758b4ee8SAndy Ritger                  if (bMaster)
3731758b4ee8SAndy Ritger                  {
3732758b4ee8SAndy Ritger                      *pPresence = ~0;
3733758b4ee8SAndy Ritger                  }
3734758b4ee8SAndy Ritger                  else
3735758b4ee8SAndy Ritger                  {
3736758b4ee8SAndy Ritger                      *pPresence = rate;
3737758b4ee8SAndy Ritger                  }
3738758b4ee8SAndy Ritger              }
3739758b4ee8SAndy Ritger              else
3740758b4ee8SAndy Ritger              {
3741758b4ee8SAndy Ritger                 *pPresence = 0;
3742758b4ee8SAndy Ritger              }
3743758b4ee8SAndy Ritger          }
3744758b4ee8SAndy Ritger          else if (gsync_Signal_House == Signal)
3745758b4ee8SAndy Ritger          {
3746758b4ee8SAndy Ritger              status = gsyncReadHouseSignalPresent_P2060(pGpu, pExtDev, NV_FALSE, &value);
3747758b4ee8SAndy Ritger 
3748758b4ee8SAndy Ritger              if (value && NV_OK == status)
3749758b4ee8SAndy Ritger              {
3750758b4ee8SAndy Ritger                  status = gsyncReadHouseSyncFrameRate_P2060(pGpu, pExtDev, &rate);
3751758b4ee8SAndy Ritger                  if (NV_OK != status)
3752758b4ee8SAndy Ritger                      return status;
3753758b4ee8SAndy Ritger 
3754758b4ee8SAndy Ritger                  if (bMaster)
3755758b4ee8SAndy Ritger                  {
3756758b4ee8SAndy Ritger                     *pPresence = rate;
3757758b4ee8SAndy Ritger                  }
3758758b4ee8SAndy Ritger                  else
3759758b4ee8SAndy Ritger                  {
3760758b4ee8SAndy Ritger                     *pPresence = ~0;
3761758b4ee8SAndy Ritger                  }
3762758b4ee8SAndy Ritger              }
3763758b4ee8SAndy Ritger              else
3764758b4ee8SAndy Ritger              {
3765758b4ee8SAndy Ritger                  *pPresence = 0;
3766758b4ee8SAndy Ritger              }
3767758b4ee8SAndy Ritger          }
3768758b4ee8SAndy Ritger          else
3769758b4ee8SAndy Ritger          {
3770758b4ee8SAndy Ritger              return NV_ERR_GENERIC;
3771758b4ee8SAndy Ritger          }
3772758b4ee8SAndy Ritger          break;
3773758b4ee8SAndy Ritger 
3774758b4ee8SAndy Ritger     case refRead:
3775758b4ee8SAndy Ritger          break;
3776758b4ee8SAndy Ritger     default:
3777758b4ee8SAndy Ritger          return NV_ERR_GENERIC;
3778758b4ee8SAndy Ritger     }
3779758b4ee8SAndy Ritger 
3780758b4ee8SAndy Ritger     return status;
3781758b4ee8SAndy Ritger }
3782758b4ee8SAndy Ritger 
3783758b4ee8SAndy Ritger /*
3784758b4ee8SAndy Ritger  * Handle Get and Set queries related to Master.
3785758b4ee8SAndy Ritger  */
3786758b4ee8SAndy Ritger NV_STATUS
gsyncRefMaster_P2060(OBJGPU * pGpu,PDACEXTERNALDEVICE pExtDev,REFTYPE rType,NvU32 * pDisplayMask,NvU32 * pRefresh,NvBool retainMaster,NvBool skipSwapBarrierWar)3787758b4ee8SAndy Ritger gsyncRefMaster_P2060
3788758b4ee8SAndy Ritger (
3789758b4ee8SAndy Ritger     OBJGPU *pGpu,
3790758b4ee8SAndy Ritger     PDACEXTERNALDEVICE pExtDev,
3791758b4ee8SAndy Ritger     REFTYPE rType,
3792758b4ee8SAndy Ritger     NvU32 *pDisplayMask,
3793758b4ee8SAndy Ritger     NvU32 *pRefresh,
3794758b4ee8SAndy Ritger     NvBool retainMaster,
3795758b4ee8SAndy Ritger     NvBool skipSwapBarrierWar
3796758b4ee8SAndy Ritger )
3797758b4ee8SAndy Ritger {
3798758b4ee8SAndy Ritger     PDACP2060EXTERNALDEVICE pThis = (PDACP2060EXTERNALDEVICE)pExtDev;
3799758b4ee8SAndy Ritger     NvU32 Master = pThis->Master;
3800758b4ee8SAndy Ritger     NvU32 RefreshRate = pThis->RefreshRate;
3801758b4ee8SAndy Ritger     NV_STATUS status = NV_OK;
3802758b4ee8SAndy Ritger 
3803758b4ee8SAndy Ritger     switch ( rType )
3804758b4ee8SAndy Ritger     {
3805758b4ee8SAndy Ritger     case refSetCommit:
3806758b4ee8SAndy Ritger         if (!retainMaster)
3807758b4ee8SAndy Ritger         {
3808758b4ee8SAndy Ritger             Master = pThis->Master = *pDisplayMask;
3809758b4ee8SAndy Ritger         }
3810758b4ee8SAndy Ritger         RefreshRate = pThis->RefreshRate = *pRefresh;
3811758b4ee8SAndy Ritger         break;
3812758b4ee8SAndy Ritger     default:
3813758b4ee8SAndy Ritger         break;
3814758b4ee8SAndy Ritger     }
3815758b4ee8SAndy Ritger 
3816758b4ee8SAndy Ritger     switch ( rType )
3817758b4ee8SAndy Ritger     {
3818758b4ee8SAndy Ritger     case refSetCommit:
3819758b4ee8SAndy Ritger         // Only masterable gpus can be set to master, but either can be set to non-master.
3820758b4ee8SAndy Ritger         if (Master && (!gsyncGpuCanBeMaster_P2060(pGpu, (PDACEXTERNALDEVICE)pThis)))
3821758b4ee8SAndy Ritger         {
3822758b4ee8SAndy Ritger             NV_PRINTF(LEVEL_INFO, "P2060 GPU can not be Framelock Master.\n");
3823758b4ee8SAndy Ritger             return NV_ERR_GENERIC;
3824758b4ee8SAndy Ritger         }
3825758b4ee8SAndy Ritger 
3826758b4ee8SAndy Ritger         if (GpuIsMosaicTimingSlave(pGpu, pThis))
3827758b4ee8SAndy Ritger         {
3828758b4ee8SAndy Ritger             NV_PRINTF(LEVEL_INFO,
3829758b4ee8SAndy Ritger                       "P2060 GPU is mosaic timing slave. Can not set Framelock Master.\n");
3830758b4ee8SAndy Ritger             return NV_ERR_GENERIC;
3831758b4ee8SAndy Ritger         }
3832758b4ee8SAndy Ritger 
3833758b4ee8SAndy Ritger         status = gsyncProgramMaster_P2060(pGpu, pThis, Master, retainMaster, skipSwapBarrierWar);
3834758b4ee8SAndy Ritger         break;
3835758b4ee8SAndy Ritger 
3836758b4ee8SAndy Ritger     case refFetchGet:
3837758b4ee8SAndy Ritger     case refRead:
3838758b4ee8SAndy Ritger         Master = gsyncReadMaster_P2060(pGpu, pThis);
3839758b4ee8SAndy Ritger         break;
3840758b4ee8SAndy Ritger     default:
3841758b4ee8SAndy Ritger         break;
3842758b4ee8SAndy Ritger     }
3843758b4ee8SAndy Ritger 
3844758b4ee8SAndy Ritger     switch ( rType )
3845758b4ee8SAndy Ritger     {
3846758b4ee8SAndy Ritger     case refFetchGet:
3847758b4ee8SAndy Ritger         pThis->Master = Master;
3848758b4ee8SAndy Ritger         /*NOBREAK*/
3849758b4ee8SAndy Ritger     case refRead:
3850758b4ee8SAndy Ritger         *pDisplayMask = Master;
3851758b4ee8SAndy Ritger         *pRefresh = RefreshRate;
3852758b4ee8SAndy Ritger         break;
3853758b4ee8SAndy Ritger 
3854758b4ee8SAndy Ritger     default:
3855758b4ee8SAndy Ritger         break;
3856758b4ee8SAndy Ritger     }
3857758b4ee8SAndy Ritger 
3858758b4ee8SAndy Ritger     return status;
3859758b4ee8SAndy Ritger }
3860758b4ee8SAndy Ritger 
3861758b4ee8SAndy Ritger /*
3862758b4ee8SAndy Ritger  * Handle Get and Set queries related to Slaves.
3863758b4ee8SAndy Ritger  */
3864758b4ee8SAndy Ritger NV_STATUS
gsyncRefSlaves_P2060(OBJGPU * pGpu,PDACEXTERNALDEVICE pExtDev,REFTYPE rType,NvU32 * pDisplayMasks,NvU32 * pRefresh)3865758b4ee8SAndy Ritger gsyncRefSlaves_P2060
3866758b4ee8SAndy Ritger (
3867758b4ee8SAndy Ritger     OBJGPU *pGpu,
3868758b4ee8SAndy Ritger     PDACEXTERNALDEVICE pExtDev,
3869758b4ee8SAndy Ritger     REFTYPE rType,
3870758b4ee8SAndy Ritger     NvU32 *pDisplayMasks,
3871758b4ee8SAndy Ritger     NvU32 *pRefresh
3872758b4ee8SAndy Ritger )
3873758b4ee8SAndy Ritger {
3874758b4ee8SAndy Ritger     PDACP2060EXTERNALDEVICE pThis = (PDACP2060EXTERNALDEVICE)pExtDev;
3875758b4ee8SAndy Ritger     NV_STATUS status = NV_OK;
3876758b4ee8SAndy Ritger     NvU32 Slaves = pThis->Slaves;
3877758b4ee8SAndy Ritger     NvU32 RefreshRate = pThis->RefreshRate;
3878758b4ee8SAndy Ritger 
3879758b4ee8SAndy Ritger     switch ( rType )
3880758b4ee8SAndy Ritger     {
3881758b4ee8SAndy Ritger     case refSetCommit:
3882758b4ee8SAndy Ritger         pThis->Slaves = *pDisplayMasks;
3883758b4ee8SAndy Ritger         pThis->RefreshRate = *pRefresh;
3884758b4ee8SAndy Ritger         Slaves = pThis->Slaves;
3885758b4ee8SAndy Ritger         RefreshRate = pThis->RefreshRate;
3886758b4ee8SAndy Ritger         break;
3887758b4ee8SAndy Ritger     default:
3888758b4ee8SAndy Ritger         break;
3889758b4ee8SAndy Ritger     }
3890758b4ee8SAndy Ritger 
3891758b4ee8SAndy Ritger     switch ( rType )
3892758b4ee8SAndy Ritger     {
3893758b4ee8SAndy Ritger     case refSetCommit:
3894758b4ee8SAndy Ritger         status = gsyncProgramSlaves_P2060(pGpu, pThis, Slaves);
3895758b4ee8SAndy Ritger         break;
3896758b4ee8SAndy Ritger 
3897758b4ee8SAndy Ritger     case refFetchGet:
3898758b4ee8SAndy Ritger     case refRead:
3899758b4ee8SAndy Ritger         Slaves = gsyncReadSlaves_P2060(pGpu, pThis);
3900758b4ee8SAndy Ritger         break;
3901758b4ee8SAndy Ritger     default:
3902758b4ee8SAndy Ritger         break;
3903758b4ee8SAndy Ritger     }
3904758b4ee8SAndy Ritger 
3905758b4ee8SAndy Ritger     switch ( rType )
3906758b4ee8SAndy Ritger     {
3907758b4ee8SAndy Ritger     case refFetchGet:
3908758b4ee8SAndy Ritger         pThis->Slaves = Slaves;
3909758b4ee8SAndy Ritger         /*NOBREAK*/
3910758b4ee8SAndy Ritger     case refRead:
3911758b4ee8SAndy Ritger         *pDisplayMasks = Slaves;
3912758b4ee8SAndy Ritger         *pRefresh = RefreshRate;
3913758b4ee8SAndy Ritger         break;
3914758b4ee8SAndy Ritger 
3915758b4ee8SAndy Ritger     default:
3916758b4ee8SAndy Ritger         break;
3917758b4ee8SAndy Ritger     }
3918758b4ee8SAndy Ritger     return status;
3919758b4ee8SAndy Ritger }
3920758b4ee8SAndy Ritger 
3921758b4ee8SAndy Ritger /*
3922758b4ee8SAndy Ritger  * Handle Get queries related to CPL status.
3923758b4ee8SAndy Ritger  */
3924758b4ee8SAndy Ritger NV_STATUS
gsyncGetCplStatus_P2060(OBJGPU * pGpu,PDACEXTERNALDEVICE pExtDev,GSYNCSTATUS CplStatus,NvU32 * pVal)3925758b4ee8SAndy Ritger gsyncGetCplStatus_P2060
3926758b4ee8SAndy Ritger (
3927758b4ee8SAndy Ritger     OBJGPU *pGpu,
3928758b4ee8SAndy Ritger     PDACEXTERNALDEVICE pExtDev,
3929758b4ee8SAndy Ritger     GSYNCSTATUS CplStatus,
3930758b4ee8SAndy Ritger     NvU32 *pVal
3931758b4ee8SAndy Ritger )
3932758b4ee8SAndy Ritger {
3933758b4ee8SAndy Ritger     NV_STATUS status = NV_OK;
3934758b4ee8SAndy Ritger     NvU8  regStatus2;
3935758b4ee8SAndy Ritger 
3936758b4ee8SAndy Ritger     *pVal = 0; // A little safety for those that do not check return codes
3937758b4ee8SAndy Ritger 
3938758b4ee8SAndy Ritger     switch (CplStatus)
3939758b4ee8SAndy Ritger     {
3940758b4ee8SAndy Ritger         case gsync_Status_Refresh:
3941758b4ee8SAndy Ritger             // Read GSYNC Framerate value.
3942758b4ee8SAndy Ritger             status = gsyncReadFrameRate_P2060(pGpu, pExtDev, pVal);
3943758b4ee8SAndy Ritger             break;
3944758b4ee8SAndy Ritger 
3945758b4ee8SAndy Ritger         case gsync_Status_HouseSyncIncoming:
3946758b4ee8SAndy Ritger             *pVal = 0;
3947758b4ee8SAndy Ritger             status = gsyncReadHouseSignalPresent_P2060(pGpu, pExtDev, NV_FALSE, pVal);
3948758b4ee8SAndy Ritger             if (NV_OK == status &&  *pVal)
3949758b4ee8SAndy Ritger             {
3950758b4ee8SAndy Ritger                 // Read HS Framerate value.
3951758b4ee8SAndy Ritger                 status = gsyncReadHouseSyncFrameRate_P2060(pGpu, pExtDev, pVal);
3952758b4ee8SAndy Ritger             }
3953758b4ee8SAndy Ritger             break;
3954758b4ee8SAndy Ritger 
3955758b4ee8SAndy Ritger         case gsync_Status_bSyncReady:
3956758b4ee8SAndy Ritger             status = gsyncReadIsSyncDetected_P2060(pGpu, pExtDev, pVal);
3957758b4ee8SAndy Ritger             break;
3958758b4ee8SAndy Ritger 
3959758b4ee8SAndy Ritger         case gsync_Status_bSwapReady:
3960758b4ee8SAndy Ritger             *pVal = 0; // counters should exist in P2060?
3961758b4ee8SAndy Ritger             break;
3962758b4ee8SAndy Ritger 
3963758b4ee8SAndy Ritger         case gsync_Status_bTiming:
3964758b4ee8SAndy Ritger             status = gsyncReadIsTiming_P2060(pGpu, pExtDev, pVal);
3965758b4ee8SAndy Ritger             break;
3966758b4ee8SAndy Ritger 
3967758b4ee8SAndy Ritger         case gsync_Status_bStereoSync:
3968758b4ee8SAndy Ritger             status = gsyncReadStereoLocked_P2060(pGpu, pExtDev, pVal);
3969758b4ee8SAndy Ritger             break;
3970758b4ee8SAndy Ritger 
3971758b4ee8SAndy Ritger         case gsync_Status_bHouseSync:
3972758b4ee8SAndy Ritger             status = gsyncReadHouseSignalPresent_P2060(pGpu, pExtDev, NV_FALSE, pVal);
3973758b4ee8SAndy Ritger             break;
3974758b4ee8SAndy Ritger 
3975758b4ee8SAndy Ritger         case gsync_Status_bPort0Input:
3976758b4ee8SAndy Ritger             status = readregu008_extdeviceTargeted(pGpu, pExtDev, (NvU8)NV_P2060_STATUS2, &regStatus2);
3977758b4ee8SAndy Ritger             if ( NV_OK == status )
3978758b4ee8SAndy Ritger             {
3979758b4ee8SAndy Ritger                 *pVal = FLD_TEST_DRF(_P2060, _STATUS2, _PORT0, _INPUT, (NvU32)regStatus2);
3980758b4ee8SAndy Ritger             }
3981758b4ee8SAndy Ritger             break;
3982758b4ee8SAndy Ritger 
3983758b4ee8SAndy Ritger         case gsync_Status_bPort1Input:
3984758b4ee8SAndy Ritger             status = readregu008_extdeviceTargeted(pGpu, pExtDev, (NvU8)NV_P2060_STATUS2, &regStatus2);
3985758b4ee8SAndy Ritger             if ( NV_OK == status )
3986758b4ee8SAndy Ritger             {
3987758b4ee8SAndy Ritger                 *pVal = FLD_TEST_DRF(_P2060, _STATUS2, _PORT1, _INPUT, (NvU32)regStatus2);
3988758b4ee8SAndy Ritger             }
3989758b4ee8SAndy Ritger             break;
3990758b4ee8SAndy Ritger 
3991758b4ee8SAndy Ritger         case gsync_Status_bPort0Ethernet:
3992758b4ee8SAndy Ritger             status = readregu008_extdeviceTargeted(pGpu, pExtDev, (NvU8)NV_P2060_STATUS2, &regStatus2);
3993758b4ee8SAndy Ritger             if ( NV_OK == status )
3994758b4ee8SAndy Ritger             {
3995758b4ee8SAndy Ritger                 *pVal = FLD_TEST_DRF(_P2060, _STATUS2, _ETHER0_DETECTED, _TRUE, (NvU32)regStatus2);
3996758b4ee8SAndy Ritger             }
3997758b4ee8SAndy Ritger             break;
3998758b4ee8SAndy Ritger 
3999758b4ee8SAndy Ritger         case gsync_Status_bPort1Ethernet:
4000758b4ee8SAndy Ritger             status = readregu008_extdeviceTargeted(pGpu, pExtDev, (NvU8)NV_P2060_STATUS2, &regStatus2);
4001758b4ee8SAndy Ritger             if ( NV_OK == status )
4002758b4ee8SAndy Ritger             {
4003758b4ee8SAndy Ritger                 *pVal = FLD_TEST_DRF(_P2060, _STATUS2, _ETHER1_DETECTED, _TRUE, (NvU32)regStatus2);
4004758b4ee8SAndy Ritger             }
4005758b4ee8SAndy Ritger             break;
4006758b4ee8SAndy Ritger 
4007758b4ee8SAndy Ritger         case gsync_Status_UniversalFrameCount:
4008758b4ee8SAndy Ritger             status = gsyncReadUniversalFrameCount_P2060(pGpu, pExtDev, pVal);
4009758b4ee8SAndy Ritger             break;
4010758b4ee8SAndy Ritger 
4011758b4ee8SAndy Ritger         default:
4012758b4ee8SAndy Ritger             status = NV_ERR_GENERIC;
4013758b4ee8SAndy Ritger     }
4014758b4ee8SAndy Ritger 
4015758b4ee8SAndy Ritger     return status;
4016758b4ee8SAndy Ritger }
4017758b4ee8SAndy Ritger 
4018758b4ee8SAndy Ritger /*
4019758b4ee8SAndy Ritger  * Handle Get and Set queries related to Watchdog.
4020758b4ee8SAndy Ritger  */
4021758b4ee8SAndy Ritger NV_STATUS
gsyncSetWatchdog_P2060(OBJGPU * pGpu,PDACEXTERNALDEVICE pExtDev,NvU32 pVal)4022758b4ee8SAndy Ritger gsyncSetWatchdog_P2060
4023758b4ee8SAndy Ritger (
4024758b4ee8SAndy Ritger     OBJGPU *pGpu,
4025758b4ee8SAndy Ritger     PDACEXTERNALDEVICE pExtDev,
4026758b4ee8SAndy Ritger     NvU32 pVal
4027758b4ee8SAndy Ritger )
4028758b4ee8SAndy Ritger {
4029758b4ee8SAndy Ritger     OBJGPU *pTempGpu = NULL;
4030758b4ee8SAndy Ritger     PDACP2060EXTERNALDEVICE pP2060 = (PDACP2060EXTERNALDEVICE)pExtDev;
4031758b4ee8SAndy Ritger     NV_STATUS status = NV_OK;
4032758b4ee8SAndy Ritger 
4033758b4ee8SAndy Ritger     NV_ASSERT_OR_RETURN(pGpu && pP2060, NV_ERR_INVALID_DEVICE);
4034758b4ee8SAndy Ritger 
4035758b4ee8SAndy Ritger     if (pVal)
4036758b4ee8SAndy Ritger     {
4037758b4ee8SAndy Ritger         gsyncCancelWatchdog_P2060(pP2060);
4038758b4ee8SAndy Ritger         pTempGpu = GetP2060WatchdogGpu(pGpu, pP2060);
4039758b4ee8SAndy Ritger 
4040758b4ee8SAndy Ritger         extdevScheduleWatchdog(pTempGpu, (PDACEXTERNALDEVICE)pP2060);
4041758b4ee8SAndy Ritger         if (!gsyncIsOnlyFrameLockMaster_P2060(pP2060))
4042758b4ee8SAndy Ritger         {
4043758b4ee8SAndy Ritger             pP2060->watchdogCountDownValue = NV_P2060_WATCHDOG_COUNT_DOWN_VALUE;
4044758b4ee8SAndy Ritger         }
4045758b4ee8SAndy Ritger     }
4046758b4ee8SAndy Ritger 
4047758b4ee8SAndy Ritger     return status;
4048758b4ee8SAndy Ritger }
4049758b4ee8SAndy Ritger 
4050758b4ee8SAndy Ritger /*
4051758b4ee8SAndy Ritger  * Handle Get and Set queries related to board revision.
4052758b4ee8SAndy Ritger  */
4053758b4ee8SAndy Ritger NV_STATUS
gsyncGetRevision_P2060(OBJGPU * pGpu,PDACEXTERNALDEVICE pExtDev,GSYNCCAPSPARAMS * pParams)4054758b4ee8SAndy Ritger gsyncGetRevision_P2060
4055758b4ee8SAndy Ritger (
4056758b4ee8SAndy Ritger     OBJGPU *pGpu,
4057758b4ee8SAndy Ritger     PDACEXTERNALDEVICE pExtDev,
4058758b4ee8SAndy Ritger     GSYNCCAPSPARAMS *pParams
4059758b4ee8SAndy Ritger )
4060758b4ee8SAndy Ritger {
4061758b4ee8SAndy Ritger     OBJSYS  *pSys = SYS_GET_INSTANCE();
4062758b4ee8SAndy Ritger     NV_STATUS status = NV_OK;
4063758b4ee8SAndy Ritger     DAC_EXTERNAL_DEVICES deviceId = pExtDev->deviceId;
4064758b4ee8SAndy Ritger     DAC_EXTERNAL_DEVICE_REVS deviceRev = pExtDev->deviceRev;
4065758b4ee8SAndy Ritger 
4066758b4ee8SAndy Ritger     if (!pGpu)
4067758b4ee8SAndy Ritger     {
4068758b4ee8SAndy Ritger         return NV_ERR_GENERIC; // something more descriptive, perhaps?
4069758b4ee8SAndy Ritger     }
4070758b4ee8SAndy Ritger 
40714397463eSAndy Ritger     portMemSet(pParams, 0, sizeof(*pParams));
40724397463eSAndy Ritger 
4073758b4ee8SAndy Ritger     pParams->revId = (NvU32)pExtDev->revId;
4074758b4ee8SAndy Ritger     pParams->boardId = (NvU32)deviceId;
4075758b4ee8SAndy Ritger     pParams->revision = (NvU32)deviceRev;
4076758b4ee8SAndy Ritger     pParams->extendedRevision = (NvU32)pExtDev->deviceExRev;
4077758b4ee8SAndy Ritger 
4078758b4ee8SAndy Ritger     if ((deviceRev != DAC_EXTERNAL_DEVICE_REV_NONE) &&
4079758b4ee8SAndy Ritger         (deviceId == DAC_EXTERNAL_DEVICE_P2060 ||
4080758b4ee8SAndy Ritger          deviceId == DAC_EXTERNAL_DEVICE_P2061))
4081758b4ee8SAndy Ritger     {
4082e598191eSAndy Ritger         DACP2060EXTERNALDEVICE *p2060 = (DACP2060EXTERNALDEVICE *)pExtDev;
4083e598191eSAndy Ritger 
4084758b4ee8SAndy Ritger         pParams->capFlags = NV30F1_CTRL_GSYNC_GET_CAPS_CAP_FLAGS_FREQ_ACCURACY_3DPS;
4085758b4ee8SAndy Ritger 
4086758b4ee8SAndy Ritger         if (!pSys->getProperty(pSys, PDB_PROP_SYS_IS_QSYNC_FW_REVISION_CHECK_DISABLED))
4087758b4ee8SAndy Ritger         {
4088758b4ee8SAndy Ritger             pParams->isFirmwareRevMismatch = isFirmwareRevMismatch(pGpu, deviceRev);
4089758b4ee8SAndy Ritger         }
4090758b4ee8SAndy Ritger         else
4091758b4ee8SAndy Ritger         {
4092758b4ee8SAndy Ritger             pParams->isFirmwareRevMismatch = NV_FALSE;
4093758b4ee8SAndy Ritger         }
4094758b4ee8SAndy Ritger 
4095e598191eSAndy Ritger         pParams->maxSyncSkew          = p2060->syncSkewMax;
4096e598191eSAndy Ritger         pParams->syncSkewResolution   = p2060->syncSkewResolutionInNs;
4097758b4ee8SAndy Ritger         pParams->maxStartDelay        = NV_P2060_START_DELAY_MAX_UNITS;
4098758b4ee8SAndy Ritger         pParams->startDelayResolution = NV_P2060_START_DELAY_RESOLUTION;
4099758b4ee8SAndy Ritger         pParams->maxSyncInterval      = NV_P2060_SYNC_INTERVAL_MAX_UNITS;
4100758b4ee8SAndy Ritger 
4101758b4ee8SAndy Ritger         // let client know which events we support
4102758b4ee8SAndy Ritger         pParams->capFlags |= NV30F1_CTRL_GSYNC_GET_CAPS_CAP_FLAGS_SYNC_LOCK_EVENT;
4103758b4ee8SAndy Ritger         pParams->capFlags |= NV30F1_CTRL_GSYNC_GET_CAPS_CAP_FLAGS_HOUSE_SYNC_EVENT;
4104758b4ee8SAndy Ritger 
4105758b4ee8SAndy Ritger         // all connectors are capable of generating events
4106758b4ee8SAndy Ritger         pParams->capFlags |= NV30F1_CTRL_GSYNC_GET_CAPS_CAP_FLAGS_ALL_CONNECTOR_EVENT;
4107758b4ee8SAndy Ritger 
4108758b4ee8SAndy Ritger         // clients can only request (i.e. not SET) for video mode at BNC connector.
4109758b4ee8SAndy Ritger         pParams->capFlags |= NV30F1_CTRL_GSYNC_GET_CAPS_CAP_FLAGS_ONLY_GET_VIDEO_MODE;
4110758b4ee8SAndy Ritger 
4111758b4ee8SAndy Ritger         // Fpga revisions <= 5 need to have the swapbarrier set on framelock masters
4112758b4ee8SAndy Ritger         // to drive (pull up) the swap_rdy line of the whole framelock setup.
4113758b4ee8SAndy Ritger         // This is a behaviour with unwanted side effects which needs drivers wars
4114758b4ee8SAndy Ritger         // for certain configs.
4115758b4ee8SAndy Ritger         if (needsMasterBarrierWar(pExtDev))
4116758b4ee8SAndy Ritger         {
4117758b4ee8SAndy Ritger             pParams->capFlags |= NV30F1_CTRL_GSYNC_GET_CAPS_CAP_FLAGS_NEED_MASTER_BARRIER_WAR;
4118758b4ee8SAndy Ritger         }
41194397463eSAndy Ritger 
41204397463eSAndy Ritger         if (supportsMulDiv(pExtDev))
41214397463eSAndy Ritger         {
41224397463eSAndy Ritger             pParams->capFlags |= NV30F1_CTRL_GSYNC_GET_CAPS_CAP_FLAGS_MULTIPLY_DIVIDE_SYNC;
41234397463eSAndy Ritger             pParams->maxMulDivValue = (NV_P2060_MULTIPLIER_DIVIDER_VALUE_MINUS_ONE_MAX + 1);
41244397463eSAndy Ritger         }
4125758b4ee8SAndy Ritger     }
4126758b4ee8SAndy Ritger     else
4127758b4ee8SAndy Ritger     {
4128758b4ee8SAndy Ritger         pParams->boardId = DAC_EXTERNAL_DEVICE_NONE;
4129758b4ee8SAndy Ritger     }
4130758b4ee8SAndy Ritger 
4131758b4ee8SAndy Ritger     return status;
4132758b4ee8SAndy Ritger }
4133758b4ee8SAndy Ritger 
4134758b4ee8SAndy Ritger /*
4135758b4ee8SAndy Ritger  * Handle Get and Set queries related to Swap barrier.
4136758b4ee8SAndy Ritger  */
4137758b4ee8SAndy Ritger NV_STATUS
gsyncRefSwapBarrier_P2060(OBJGPU * pGpu,PDACEXTERNALDEVICE pExtDev,REFTYPE rType,NvBool * bEnable)4138758b4ee8SAndy Ritger gsyncRefSwapBarrier_P2060
4139758b4ee8SAndy Ritger (
4140758b4ee8SAndy Ritger     OBJGPU              *pGpu,
4141758b4ee8SAndy Ritger     PDACEXTERNALDEVICE   pExtDev,
4142758b4ee8SAndy Ritger     REFTYPE              rType,
4143758b4ee8SAndy Ritger     NvBool               *bEnable
4144758b4ee8SAndy Ritger )
4145758b4ee8SAndy Ritger {
4146758b4ee8SAndy Ritger     NV_STATUS status = NV_OK;
4147758b4ee8SAndy Ritger 
4148758b4ee8SAndy Ritger     switch (rType)
4149758b4ee8SAndy Ritger     {
4150758b4ee8SAndy Ritger         case refSetCommit:
4151758b4ee8SAndy Ritger             status = gsyncProgramSwapBarrier_P2060(pGpu, pExtDev, *bEnable);
4152758b4ee8SAndy Ritger             break;
4153758b4ee8SAndy Ritger         case refFetchGet:
4154758b4ee8SAndy Ritger         case refRead:
4155758b4ee8SAndy Ritger             status = gsyncReadSwapBarrier_P2060(pGpu, pExtDev, bEnable);
4156758b4ee8SAndy Ritger             break;
4157758b4ee8SAndy Ritger         default:
4158758b4ee8SAndy Ritger             break;
4159758b4ee8SAndy Ritger     }
4160758b4ee8SAndy Ritger 
4161758b4ee8SAndy Ritger     return status;
4162758b4ee8SAndy Ritger }
4163758b4ee8SAndy Ritger 
4164758b4ee8SAndy Ritger /*
4165758b4ee8SAndy Ritger  * Configure GSYNC registers for pre-flash and post-flash operations.
4166758b4ee8SAndy Ritger  */
4167758b4ee8SAndy Ritger NV_STATUS
gsyncConfigFlashGsync_P2060(OBJGPU * pGpu,PDACEXTERNALDEVICE pExtDev,NvU32 preFlash)4168758b4ee8SAndy Ritger gsyncConfigFlashGsync_P2060
4169758b4ee8SAndy Ritger (
4170758b4ee8SAndy Ritger     OBJGPU                *pGpu,
4171758b4ee8SAndy Ritger     PDACEXTERNALDEVICE     pExtDev,
4172758b4ee8SAndy Ritger     NvU32                  preFlash
4173758b4ee8SAndy Ritger )
4174758b4ee8SAndy Ritger {
4175758b4ee8SAndy Ritger     PDACP2060EXTERNALDEVICE pThis = (PDACP2060EXTERNALDEVICE) pExtDev;
4176758b4ee8SAndy Ritger     NvU32 iface;
4177758b4ee8SAndy Ritger     NV_STATUS rmStatus = NV_OK;
4178758b4ee8SAndy Ritger 
4179758b4ee8SAndy Ritger     if (preFlash)
4180758b4ee8SAndy Ritger     {
4181758b4ee8SAndy Ritger         if (pThis->isNonFramelockInterruptEnabled == NV_FALSE)
4182758b4ee8SAndy Ritger         {
4183758b4ee8SAndy Ritger             // Non-Framelock interrupts are already disabled.
4184758b4ee8SAndy Ritger             return NV_OK;
4185758b4ee8SAndy Ritger         }
4186758b4ee8SAndy Ritger 
4187758b4ee8SAndy Ritger         // Disable non-Framelock interrupts for given gpu
4188758b4ee8SAndy Ritger         for (iface = 0; iface < NV_P2060_MAX_IFACES_PER_GSYNC; iface++)
4189758b4ee8SAndy Ritger         {
4190758b4ee8SAndy Ritger             if (pThis->Iface[iface].GpuInfo.gpuId != NV0000_CTRL_GPU_INVALID_ID &&
4191758b4ee8SAndy Ritger                 pThis->interruptEnabledInterface == iface)
4192758b4ee8SAndy Ritger             {
4193758b4ee8SAndy Ritger                 OBJGPU *pTmpGpu = gpumgrGetGpuFromId(pThis->Iface[iface].GpuInfo.gpuId);
4194758b4ee8SAndy Ritger 
4195758b4ee8SAndy Ritger                 NV_ASSERT(pTmpGpu);
4196758b4ee8SAndy Ritger 
4197758b4ee8SAndy Ritger                 rmStatus = gsyncDisableNonFramelockInterrupt_P2060(pTmpGpu, (PDACEXTERNALDEVICE)pThis);
4198758b4ee8SAndy Ritger                 if (rmStatus != NV_OK)
4199758b4ee8SAndy Ritger                 {
4200758b4ee8SAndy Ritger                     NV_PRINTF(LEVEL_ERROR,
4201758b4ee8SAndy Ritger                               "Failed to disable non-framelock interrupts on gsync GPU.\n");
4202758b4ee8SAndy Ritger                     return rmStatus;
4203758b4ee8SAndy Ritger                 }
4204758b4ee8SAndy Ritger                 break;
4205758b4ee8SAndy Ritger             }
4206758b4ee8SAndy Ritger         }
4207758b4ee8SAndy Ritger         pThis->isNonFramelockInterruptEnabled = NV_FALSE;
4208758b4ee8SAndy Ritger     }
4209758b4ee8SAndy Ritger     else
4210758b4ee8SAndy Ritger     {
4211758b4ee8SAndy Ritger         if (pThis->isNonFramelockInterruptEnabled == NV_FALSE)
4212758b4ee8SAndy Ritger         {
4213758b4ee8SAndy Ritger             // Enable non-Framelock interrupts for given gpu
4214758b4ee8SAndy Ritger             rmStatus = GetP2060ConnectorIndexFromGpu(pGpu, pThis, &iface);
4215758b4ee8SAndy Ritger             if (NV_OK != rmStatus)
4216758b4ee8SAndy Ritger             {
4217758b4ee8SAndy Ritger                 NV_PRINTF(LEVEL_ERROR,
4218758b4ee8SAndy Ritger                           "failed to find P2060 connector of the GPU.\n");
4219758b4ee8SAndy Ritger                 return rmStatus;
4220758b4ee8SAndy Ritger             }
4221758b4ee8SAndy Ritger 
4222758b4ee8SAndy Ritger             rmStatus = gsyncEnableNonFramelockInterrupt_P2060(pGpu, (PDACEXTERNALDEVICE)pThis);
4223758b4ee8SAndy Ritger             if (NV_OK != rmStatus)
4224758b4ee8SAndy Ritger             {
4225758b4ee8SAndy Ritger                 NV_PRINTF(LEVEL_ERROR,
4226758b4ee8SAndy Ritger                           "Failed to enable non-framelock interrupts on gsync GPU.\n");
4227758b4ee8SAndy Ritger                 return rmStatus;
4228758b4ee8SAndy Ritger             }
4229758b4ee8SAndy Ritger             pThis->isNonFramelockInterruptEnabled = NV_TRUE;
4230758b4ee8SAndy Ritger             pThis->interruptEnabledInterface = iface;
4231758b4ee8SAndy Ritger         }
4232758b4ee8SAndy Ritger 
4233758b4ee8SAndy Ritger         // Program External Stereo Sync Polarity for all attached gpus.
4234758b4ee8SAndy Ritger         for (iface = 0; iface < NV_P2060_MAX_IFACES_PER_GSYNC; iface++)
4235758b4ee8SAndy Ritger         {
4236758b4ee8SAndy Ritger             if (pThis->Iface[iface].GpuInfo.gpuId != NV0000_CTRL_GPU_INVALID_ID)
4237758b4ee8SAndy Ritger             {
4238758b4ee8SAndy Ritger                 OBJGPU *pTmpGpu = gpumgrGetGpuFromId(pThis->Iface[iface].GpuInfo.gpuId);
4239758b4ee8SAndy Ritger 
4240758b4ee8SAndy Ritger                 NV_ASSERT(pTmpGpu);
4241758b4ee8SAndy Ritger 
4242758b4ee8SAndy Ritger                 rmStatus = gsyncProgramExtStereoPolarity_P2060(pTmpGpu, (PDACEXTERNALDEVICE)pThis);
4243758b4ee8SAndy Ritger                 if (NV_OK != rmStatus)
4244758b4ee8SAndy Ritger                 {
4245758b4ee8SAndy Ritger                     NV_PRINTF(LEVEL_ERROR,
4246758b4ee8SAndy Ritger                               "Failed to Program External Stereo Polarity for GPU.\n");
4247758b4ee8SAndy Ritger                     return rmStatus;
4248758b4ee8SAndy Ritger                 }
4249758b4ee8SAndy Ritger             }
4250758b4ee8SAndy Ritger         }
4251758b4ee8SAndy Ritger     }
4252758b4ee8SAndy Ritger     return rmStatus;
4253758b4ee8SAndy Ritger }
4254758b4ee8SAndy Ritger 
4255758b4ee8SAndy Ritger /*
4256758b4ee8SAndy Ritger  * Return snapshot of status1 register.
4257758b4ee8SAndy Ritger  */
4258758b4ee8SAndy Ritger static NvU32
GetP2060GpuSnapshot(OBJGPU * pGpu,PDACP2060EXTERNALDEVICE pThis)4259758b4ee8SAndy Ritger GetP2060GpuSnapshot
4260758b4ee8SAndy Ritger (
4261758b4ee8SAndy Ritger     OBJGPU *pGpu,
4262758b4ee8SAndy Ritger     PDACP2060EXTERNALDEVICE pThis
4263758b4ee8SAndy Ritger )
4264758b4ee8SAndy Ritger {
4265758b4ee8SAndy Ritger     NvU32 iface;
4266758b4ee8SAndy Ritger     NV_STATUS status;
4267758b4ee8SAndy Ritger 
4268758b4ee8SAndy Ritger     status = GetP2060GpuLocation(pGpu, pThis, &iface);
4269758b4ee8SAndy Ritger     if (NV_OK != status)
4270758b4ee8SAndy Ritger         return 0;
4271758b4ee8SAndy Ritger 
4272758b4ee8SAndy Ritger     return pThis->Snapshot[iface].Status1;
4273758b4ee8SAndy Ritger }
4274758b4ee8SAndy Ritger 
4275758b4ee8SAndy Ritger /*
4276758b4ee8SAndy Ritger  * Return NV_TRUE if pGpu is Timing Source else return NV_FALSE.
4277758b4ee8SAndy Ritger  */
4278758b4ee8SAndy Ritger static NvBool
GpuIsP2060Master(OBJGPU * pGpu,PDACP2060EXTERNALDEVICE pThis)4279758b4ee8SAndy Ritger GpuIsP2060Master
4280758b4ee8SAndy Ritger (
4281758b4ee8SAndy Ritger     OBJGPU *pGpu,
4282758b4ee8SAndy Ritger     PDACP2060EXTERNALDEVICE pThis
4283758b4ee8SAndy Ritger )
4284758b4ee8SAndy Ritger {
4285758b4ee8SAndy Ritger     NvU8 regControl;
4286758b4ee8SAndy Ritger     NvU32 index;
4287758b4ee8SAndy Ritger     NvBool bIsMasterGpu;
4288758b4ee8SAndy Ritger     NV_STATUS rmStatus;
4289758b4ee8SAndy Ritger 
4290758b4ee8SAndy Ritger     if (!pGpu || !GpuIsP2060Connected(pGpu, pThis))
4291758b4ee8SAndy Ritger     {
4292758b4ee8SAndy Ritger         return NV_FALSE;
4293758b4ee8SAndy Ritger     }
4294758b4ee8SAndy Ritger 
4295758b4ee8SAndy Ritger     // Get the connector index and check if it is master
4296758b4ee8SAndy Ritger     if ( NV_OK != GetP2060ConnectorIndexFromGpu(pGpu, pThis, &index))
4297758b4ee8SAndy Ritger     {
4298758b4ee8SAndy Ritger         return NV_FALSE;
4299758b4ee8SAndy Ritger     }
4300758b4ee8SAndy Ritger 
4301758b4ee8SAndy Ritger     rmStatus = readregu008_extdeviceTargeted(pGpu, (PDACEXTERNALDEVICE)pThis, (NvU8)NV_P2060_CONTROL, &regControl);
4302758b4ee8SAndy Ritger     if (NV_OK != rmStatus)
4303758b4ee8SAndy Ritger     {
4304758b4ee8SAndy Ritger         return NV_FALSE;
4305758b4ee8SAndy Ritger     }
4306758b4ee8SAndy Ritger 
4307758b4ee8SAndy Ritger     bIsMasterGpu = (DRF_VAL(_P2060, _CONTROL, _SYNC_SRC, (NvU32)regControl) == index);
4308758b4ee8SAndy Ritger     return bIsMasterGpu;
4309758b4ee8SAndy Ritger }
4310758b4ee8SAndy Ritger 
4311758b4ee8SAndy Ritger /*
4312758b4ee8SAndy Ritger  * Return whether pGpu is connected to pThis or not.
4313758b4ee8SAndy Ritger  */
4314758b4ee8SAndy Ritger static NvBool
GpuIsP2060Connected(OBJGPU * pGpu,PDACP2060EXTERNALDEVICE pThis)4315758b4ee8SAndy Ritger GpuIsP2060Connected
4316758b4ee8SAndy Ritger (
4317758b4ee8SAndy Ritger     OBJGPU *pGpu,
4318758b4ee8SAndy Ritger     PDACP2060EXTERNALDEVICE pThis
4319758b4ee8SAndy Ritger )
4320758b4ee8SAndy Ritger {
4321758b4ee8SAndy Ritger     NvU32 iface;
4322758b4ee8SAndy Ritger 
4323758b4ee8SAndy Ritger     if (NV_OK == GetP2060GpuLocation(pGpu, pThis, &iface))
4324758b4ee8SAndy Ritger     {
4325758b4ee8SAndy Ritger         return pThis->Iface[iface].GpuInfo.connected;
4326758b4ee8SAndy Ritger     }
4327758b4ee8SAndy Ritger 
4328758b4ee8SAndy Ritger     return NV_FALSE;
4329758b4ee8SAndy Ritger }
4330758b4ee8SAndy Ritger 
4331758b4ee8SAndy Ritger /*
4332758b4ee8SAndy Ritger  * Return Masterable(TS) Gpu for pthis.
4333758b4ee8SAndy Ritger  */
4334758b4ee8SAndy Ritger static OBJGPU*
GetP2060MasterableGpu(OBJGPU * pGpu,PDACP2060EXTERNALDEVICE pThis)4335758b4ee8SAndy Ritger GetP2060MasterableGpu
4336758b4ee8SAndy Ritger (
4337758b4ee8SAndy Ritger     OBJGPU *pGpu,
4338758b4ee8SAndy Ritger     PDACP2060EXTERNALDEVICE pThis
4339758b4ee8SAndy Ritger )
4340758b4ee8SAndy Ritger {
4341758b4ee8SAndy Ritger     OBJGPU *tempGpu;
4342758b4ee8SAndy Ritger     NvU32 iface;
4343758b4ee8SAndy Ritger 
4344758b4ee8SAndy Ritger     for (iface = 0; iface < NV_P2060_MAX_IFACES_PER_GSYNC; iface++)
4345758b4ee8SAndy Ritger     {
4346758b4ee8SAndy Ritger         if (pThis->Iface[iface].GpuInfo.gpuId != NV0000_CTRL_GPU_INVALID_ID)
4347758b4ee8SAndy Ritger         {
4348758b4ee8SAndy Ritger             tempGpu = gpumgrGetGpuFromId(pThis->Iface[iface].GpuInfo.gpuId);
4349758b4ee8SAndy Ritger 
4350758b4ee8SAndy Ritger             NV_ASSERT(tempGpu);
4351758b4ee8SAndy Ritger 
4352758b4ee8SAndy Ritger             if (gsyncGpuCanBeMaster_P2060(tempGpu, (PDACEXTERNALDEVICE)pThis))
4353758b4ee8SAndy Ritger             {
4354758b4ee8SAndy Ritger                 return tempGpu;
4355758b4ee8SAndy Ritger             }
4356758b4ee8SAndy Ritger         }
4357758b4ee8SAndy Ritger     }
4358758b4ee8SAndy Ritger 
4359758b4ee8SAndy Ritger     return NULL;
4360758b4ee8SAndy Ritger }
4361758b4ee8SAndy Ritger 
4362758b4ee8SAndy Ritger /*
4363758b4ee8SAndy Ritger  * Return connector index for given pGpu.
4364758b4ee8SAndy Ritger  */
4365758b4ee8SAndy Ritger static NV_STATUS
GetP2060ConnectorIndexFromGpu(OBJGPU * pGpu,PDACP2060EXTERNALDEVICE pThis,NvU32 * index)4366758b4ee8SAndy Ritger GetP2060ConnectorIndexFromGpu
4367758b4ee8SAndy Ritger (
4368758b4ee8SAndy Ritger     OBJGPU *pGpu,
4369758b4ee8SAndy Ritger     PDACP2060EXTERNALDEVICE pThis,
4370758b4ee8SAndy Ritger     NvU32 *index
4371758b4ee8SAndy Ritger )
4372758b4ee8SAndy Ritger {
4373758b4ee8SAndy Ritger     NV_STATUS rmStatus = NV_OK;
4374758b4ee8SAndy Ritger     NvU8 regStatus2;
4375758b4ee8SAndy Ritger 
4376758b4ee8SAndy Ritger     rmStatus  = readregu008_extdeviceTargeted(pGpu, (PDACEXTERNALDEVICE)pThis, (NvU8)NV_P2060_STATUS2, &regStatus2);
4377758b4ee8SAndy Ritger     if (NV_OK == rmStatus)
4378758b4ee8SAndy Ritger     {
4379758b4ee8SAndy Ritger         *index = DRF_VAL(_P2060, _STATUS2, _GPU_PORT, (NvU32)regStatus2);
4380758b4ee8SAndy Ritger     }
4381758b4ee8SAndy Ritger 
4382758b4ee8SAndy Ritger     return rmStatus;
4383758b4ee8SAndy Ritger }
4384758b4ee8SAndy Ritger 
4385758b4ee8SAndy Ritger /*
4386758b4ee8SAndy Ritger  * Return location of pGpu attached to P2060.
4387758b4ee8SAndy Ritger  */
4388758b4ee8SAndy Ritger static NV_STATUS
GetP2060GpuLocation(OBJGPU * pGpu,PDACP2060EXTERNALDEVICE pThis,NvU32 * iface)4389758b4ee8SAndy Ritger GetP2060GpuLocation
4390758b4ee8SAndy Ritger (
4391758b4ee8SAndy Ritger     OBJGPU *pGpu,
4392758b4ee8SAndy Ritger     PDACP2060EXTERNALDEVICE pThis,
4393758b4ee8SAndy Ritger     NvU32 *iface
4394758b4ee8SAndy Ritger )
4395758b4ee8SAndy Ritger {
4396758b4ee8SAndy Ritger     NvU32 tempIface;
4397758b4ee8SAndy Ritger 
4398758b4ee8SAndy Ritger     for (tempIface = 0; tempIface < NV_P2060_MAX_IFACES_PER_GSYNC; tempIface++)
4399758b4ee8SAndy Ritger     {
4400758b4ee8SAndy Ritger         if (pThis->Iface[tempIface].GpuInfo.gpuId == pGpu->gpuId)
4401758b4ee8SAndy Ritger         {
4402758b4ee8SAndy Ritger             *iface = tempIface;
4403758b4ee8SAndy Ritger 
4404758b4ee8SAndy Ritger             return NV_OK;
4405758b4ee8SAndy Ritger         }
4406758b4ee8SAndy Ritger     }
4407758b4ee8SAndy Ritger 
4408758b4ee8SAndy Ritger     return NV_ERR_GENERIC;
4409758b4ee8SAndy Ritger }
4410758b4ee8SAndy Ritger 
4411758b4ee8SAndy Ritger static void
gsyncProgramFramelockEnable_P2060(OBJGPU * pGpu,PDACP2060EXTERNALDEVICE pThis,NvU32 iface,NvBool bEnable)4412758b4ee8SAndy Ritger gsyncProgramFramelockEnable_P2060
4413758b4ee8SAndy Ritger (
4414758b4ee8SAndy Ritger     OBJGPU                 *pGpu,
4415758b4ee8SAndy Ritger     PDACP2060EXTERNALDEVICE pThis,
4416758b4ee8SAndy Ritger     NvU32                   iface,
4417758b4ee8SAndy Ritger     NvBool                  bEnable
4418758b4ee8SAndy Ritger )
4419758b4ee8SAndy Ritger {
4420758b4ee8SAndy Ritger     //
4421758b4ee8SAndy Ritger     // Key here is to force the status register snapshot
4422758b4ee8SAndy Ritger     // to unsynched and setting back the timeout for
4423758b4ee8SAndy Ritger     // syncgain. To ensure that the eventhandling won't
4424758b4ee8SAndy Ritger     // filter away any gain, send a syncloss event.
4425758b4ee8SAndy Ritger     // also track overall framelock state (on off) now.
4426758b4ee8SAndy Ritger     //
4427758b4ee8SAndy Ritger     NV_PRINTF(LEVEL_INFO,
4428758b4ee8SAndy Ritger               "P2060[%d]:%s snapshot reset to _SYNC_LOSS_TRUE _VCXO_NOT_SERVO _STEREO_NOLOCK\n",
4429758b4ee8SAndy Ritger               iface, bEnable ? "ON" : "OFF");
4430758b4ee8SAndy Ritger 
4431758b4ee8SAndy Ritger     pThis->Snapshot[iface].Status1 =
4432758b4ee8SAndy Ritger         DRF_DEF(_P2060, _STATUS, _SYNC_LOSS, _TRUE) |
4433758b4ee8SAndy Ritger         DRF_DEF(_P2060, _STATUS, _VCXO, _NOT_SERVO) |
4434758b4ee8SAndy Ritger         DRF_DEF(_P2060, _STATUS, _STEREO, _NOLOCK);
4435758b4ee8SAndy Ritger 
4436758b4ee8SAndy Ritger     pThis->Snapshot[iface].lastStereoToggleTime = 0;
4437758b4ee8SAndy Ritger 
4438758b4ee8SAndy Ritger     // Also reload delayed updates.
4439758b4ee8SAndy Ritger     pThis->Snapshot[iface].lastSyncCheckTime = 0;
4440758b4ee8SAndy Ritger 
4441758b4ee8SAndy Ritger     // We will waiting for a syncgain.
4442758b4ee8SAndy Ritger     pThis->Iface[iface].gainedSync = 0;
4443758b4ee8SAndy Ritger 
4444758b4ee8SAndy Ritger     if (bEnable)
4445758b4ee8SAndy Ritger     {
4446758b4ee8SAndy Ritger         gsyncSignalServiceRequested(gsyncGetGsyncInstance(pGpu),
4447758b4ee8SAndy Ritger             NVBIT(NV30F1_GSYNC_NOTIFIERS_SYNC_LOSS(iface)), iface);
4448758b4ee8SAndy Ritger         pThis->Iface[iface].lastEventNotified =
4449758b4ee8SAndy Ritger             NVBIT(NV30F1_GSYNC_NOTIFIERS_SYNC_LOSS(iface));
4450758b4ee8SAndy Ritger     }
4451758b4ee8SAndy Ritger }
4452758b4ee8SAndy Ritger 
4453758b4ee8SAndy Ritger static NvBool
GpuIsMosaicTimingSlave(OBJGPU * pGpu,PDACP2060EXTERNALDEVICE pThis)4454758b4ee8SAndy Ritger GpuIsMosaicTimingSlave
4455758b4ee8SAndy Ritger (
4456758b4ee8SAndy Ritger     OBJGPU *pGpu,
4457758b4ee8SAndy Ritger     PDACP2060EXTERNALDEVICE pThis
4458758b4ee8SAndy Ritger )
4459758b4ee8SAndy Ritger {
4460758b4ee8SAndy Ritger     OBJGPU *pTempGpu = NULL;
4461758b4ee8SAndy Ritger     NvU8 i, j;
4462758b4ee8SAndy Ritger 
4463758b4ee8SAndy Ritger     for (i = 0; i < NV_P2060_MAX_MOSAIC_GROUPS; i++)
4464758b4ee8SAndy Ritger     {
4465758b4ee8SAndy Ritger         if (pThis->MosaicGroup[i].enabledMosaic)
4466758b4ee8SAndy Ritger         {
4467758b4ee8SAndy Ritger              for (j = 0; j < NV_P2060_MAX_MOSAIC_SLAVES; j++)
4468758b4ee8SAndy Ritger              {
4469758b4ee8SAndy Ritger                   pTempGpu = gpumgrGetGpuFromId(pThis->MosaicGroup[i].gpuTimingSlaves[j]);
4470758b4ee8SAndy Ritger                   NV_ASSERT(pTempGpu);
4471758b4ee8SAndy Ritger 
4472758b4ee8SAndy Ritger                   if (pTempGpu == pGpu)
4473758b4ee8SAndy Ritger                   {
4474758b4ee8SAndy Ritger                       return NV_TRUE;
4475758b4ee8SAndy Ritger                   }
4476758b4ee8SAndy Ritger              }
4477758b4ee8SAndy Ritger         }
4478758b4ee8SAndy Ritger     }
4479758b4ee8SAndy Ritger     return NV_FALSE;
4480758b4ee8SAndy Ritger }
4481758b4ee8SAndy Ritger 
4482758b4ee8SAndy Ritger /*
4483758b4ee8SAndy Ritger  * Return NV_TRUE if pGpu can be master(TS) i.e. no other pGpu
4484758b4ee8SAndy Ritger  * attached to pThis is master.
4485758b4ee8SAndy Ritger  */
4486758b4ee8SAndy Ritger NvBool
gsyncGpuCanBeMaster_P2060(OBJGPU * pGpu,PDACEXTERNALDEVICE pExtDev)4487758b4ee8SAndy Ritger gsyncGpuCanBeMaster_P2060
4488758b4ee8SAndy Ritger (
4489758b4ee8SAndy Ritger     OBJGPU *pGpu,
4490758b4ee8SAndy Ritger     PDACEXTERNALDEVICE pExtDev
4491758b4ee8SAndy Ritger )
4492758b4ee8SAndy Ritger {
4493758b4ee8SAndy Ritger     PDACP2060EXTERNALDEVICE pThis = (PDACP2060EXTERNALDEVICE)pExtDev;
4494758b4ee8SAndy Ritger     OBJGPU *pTempGpu;
4495758b4ee8SAndy Ritger     NvU32 iface, tempIface;
4496758b4ee8SAndy Ritger     NV_STATUS status;
4497758b4ee8SAndy Ritger 
4498758b4ee8SAndy Ritger     // If FPGA board in not master, Any GPU attached to board can be master.
4499758b4ee8SAndy Ritger     if (!gsyncIsP2060MasterBoard(pGpu, pThis))
4500758b4ee8SAndy Ritger     {
4501758b4ee8SAndy Ritger         return NV_TRUE;
4502758b4ee8SAndy Ritger     }
4503758b4ee8SAndy Ritger 
4504758b4ee8SAndy Ritger     // Board is master, only TS GPU will be master.
4505758b4ee8SAndy Ritger     status = GetP2060GpuLocation(pGpu, pThis, &iface);
4506758b4ee8SAndy Ritger     if (NV_OK != status)
4507758b4ee8SAndy Ritger     {
4508758b4ee8SAndy Ritger         return NV_FALSE;
4509758b4ee8SAndy Ritger     }
4510758b4ee8SAndy Ritger 
4511758b4ee8SAndy Ritger     for (tempIface = 0; tempIface < NV_P2060_MAX_IFACES_PER_GSYNC; tempIface++)
4512758b4ee8SAndy Ritger     {
4513758b4ee8SAndy Ritger         if (tempIface == iface)
4514758b4ee8SAndy Ritger         {
4515758b4ee8SAndy Ritger             continue;
4516758b4ee8SAndy Ritger         }
4517758b4ee8SAndy Ritger 
4518758b4ee8SAndy Ritger         if (pThis->Iface[tempIface].GpuInfo.gpuId == NV0000_CTRL_GPU_INVALID_ID)
4519758b4ee8SAndy Ritger         {
4520758b4ee8SAndy Ritger             continue;
4521758b4ee8SAndy Ritger         }
4522758b4ee8SAndy Ritger 
4523758b4ee8SAndy Ritger         pTempGpu = gpumgrGetGpuFromId(pThis->Iface[tempIface].GpuInfo.gpuId);
4524758b4ee8SAndy Ritger 
4525758b4ee8SAndy Ritger         NV_ASSERT(pTempGpu);
4526758b4ee8SAndy Ritger 
4527758b4ee8SAndy Ritger         if (GpuIsP2060Master(pTempGpu, pThis))
4528758b4ee8SAndy Ritger         {
4529758b4ee8SAndy Ritger             return NV_FALSE;
4530758b4ee8SAndy Ritger         }
4531758b4ee8SAndy Ritger     }
4532758b4ee8SAndy Ritger 
4533758b4ee8SAndy Ritger     return NV_TRUE;
4534758b4ee8SAndy Ritger }
4535758b4ee8SAndy Ritger 
4536758b4ee8SAndy Ritger 
4537758b4ee8SAndy Ritger static POBJGPU
GetP2060Gpu(OBJGPU * pGpu,PDACP2060EXTERNALDEVICE pThis)4538758b4ee8SAndy Ritger GetP2060Gpu
4539758b4ee8SAndy Ritger (
4540758b4ee8SAndy Ritger     OBJGPU *pGpu,
4541758b4ee8SAndy Ritger     PDACP2060EXTERNALDEVICE pThis
4542758b4ee8SAndy Ritger )
4543758b4ee8SAndy Ritger {
4544758b4ee8SAndy Ritger     NvU32 iface;
4545758b4ee8SAndy Ritger     for (iface = 0; iface < NV_P2060_MAX_IFACES_PER_GSYNC; iface++)
4546758b4ee8SAndy Ritger     {
4547758b4ee8SAndy Ritger         if (pThis->Iface[iface].GpuInfo.gpuId != NV0000_CTRL_GPU_INVALID_ID)
4548758b4ee8SAndy Ritger         {
4549758b4ee8SAndy Ritger             OBJGPU *pTmpGpu = gpumgrGetGpuFromId(pThis->Iface[iface].GpuInfo.gpuId);
4550758b4ee8SAndy Ritger 
4551758b4ee8SAndy Ritger             NV_ASSERT(pTmpGpu);
4552758b4ee8SAndy Ritger 
4553758b4ee8SAndy Ritger             return pTmpGpu;
4554758b4ee8SAndy Ritger         }
4555758b4ee8SAndy Ritger     }
4556758b4ee8SAndy Ritger     return NULL;
4557758b4ee8SAndy Ritger }
4558758b4ee8SAndy Ritger 
4559758b4ee8SAndy Ritger static OBJGPU*
GetP2060WatchdogGpu(OBJGPU * pGpu,PDACP2060EXTERNALDEVICE pThis)4560758b4ee8SAndy Ritger GetP2060WatchdogGpu
4561758b4ee8SAndy Ritger (
4562758b4ee8SAndy Ritger     OBJGPU *pGpu,
4563758b4ee8SAndy Ritger     PDACP2060EXTERNALDEVICE pThis
4564758b4ee8SAndy Ritger )
4565758b4ee8SAndy Ritger {
4566758b4ee8SAndy Ritger    return GetP2060Gpu(pGpu, pThis);
4567758b4ee8SAndy Ritger }
4568758b4ee8SAndy Ritger 
4569758b4ee8SAndy Ritger /*
4570758b4ee8SAndy Ritger  * Return NV_TRUE if either GPU stereo or MASTER stereo or
4571758b4ee8SAndy Ritger  * both are enabled else return NV_FALSE.
4572758b4ee8SAndy Ritger  */
4573758b4ee8SAndy Ritger static NvBool
gsyncIsStereoEnabled_p2060(OBJGPU * pGpu,PDACEXTERNALDEVICE pExtDev)4574758b4ee8SAndy Ritger gsyncIsStereoEnabled_p2060
4575758b4ee8SAndy Ritger (
4576758b4ee8SAndy Ritger     OBJGPU            *pGpu,
4577758b4ee8SAndy Ritger     PDACEXTERNALDEVICE pExtDev
4578758b4ee8SAndy Ritger )
4579758b4ee8SAndy Ritger {
4580758b4ee8SAndy Ritger     NvU8 regStatus;
4581758b4ee8SAndy Ritger     NV_STATUS rmStatus;
4582758b4ee8SAndy Ritger 
4583758b4ee8SAndy Ritger     rmStatus  = readregu008_extdeviceTargeted(pGpu, pExtDev, (NvU8)NV_P2060_STATUS,  &regStatus);
4584758b4ee8SAndy Ritger 
4585758b4ee8SAndy Ritger     if (rmStatus == NV_OK)
4586758b4ee8SAndy Ritger     {
4587758b4ee8SAndy Ritger         if (FLD_TEST_DRF(_P2060, _STATUS, _GPU_STEREO, _ACTIVE, regStatus) ||
4588758b4ee8SAndy Ritger             FLD_TEST_DRF(_P2060, _STATUS, _MSTR_STEREO, _ACTIVE, regStatus))
4589758b4ee8SAndy Ritger         {
4590758b4ee8SAndy Ritger             // stereo is enabled on the client or the server or both
4591758b4ee8SAndy Ritger             return NV_TRUE;
4592758b4ee8SAndy Ritger         }
4593758b4ee8SAndy Ritger     }
4594758b4ee8SAndy Ritger     return NV_FALSE;
4595758b4ee8SAndy Ritger }
4596758b4ee8SAndy Ritger 
4597758b4ee8SAndy Ritger /*
4598758b4ee8SAndy Ritger  * Cancel the Watchdog for P2060.
4599758b4ee8SAndy Ritger  */
4600758b4ee8SAndy Ritger static void
gsyncCancelWatchdog_P2060(PDACP2060EXTERNALDEVICE pThis)4601758b4ee8SAndy Ritger gsyncCancelWatchdog_P2060
4602758b4ee8SAndy Ritger (
4603758b4ee8SAndy Ritger     PDACP2060EXTERNALDEVICE pThis
4604758b4ee8SAndy Ritger )
4605758b4ee8SAndy Ritger {
4606758b4ee8SAndy Ritger     NvU32 iface;
4607758b4ee8SAndy Ritger     OBJGPU *pTempGpu = NULL;
4608758b4ee8SAndy Ritger 
4609758b4ee8SAndy Ritger     pThis->watchdogCountDownValue = 0;
4610758b4ee8SAndy Ritger 
4611758b4ee8SAndy Ritger     // Cancel callbacks on all gpus
4612758b4ee8SAndy Ritger     for (iface = 0; iface < NV_P2060_MAX_IFACES_PER_GSYNC; iface++)
4613758b4ee8SAndy Ritger     {
4614758b4ee8SAndy Ritger         if (pThis->Iface[iface].GpuInfo.gpuId == NV0000_CTRL_GPU_INVALID_ID)
4615758b4ee8SAndy Ritger             continue;
4616758b4ee8SAndy Ritger 
4617758b4ee8SAndy Ritger         pTempGpu = gpumgrGetGpuFromId(pThis->Iface[iface].GpuInfo.gpuId);
4618758b4ee8SAndy Ritger         NV_ASSERT(pTempGpu);
4619758b4ee8SAndy Ritger 
4620758b4ee8SAndy Ritger         NV_PRINTF(LEVEL_INFO, "P2060[%d] extdevCancelWatchdog.\n", iface);
4621758b4ee8SAndy Ritger 
4622758b4ee8SAndy Ritger         extdevCancelWatchdog(pTempGpu, (PDACEXTERNALDEVICE)pThis);
4623758b4ee8SAndy Ritger     }
4624758b4ee8SAndy Ritger 
4625758b4ee8SAndy Ritger     return;
4626758b4ee8SAndy Ritger }
4627758b4ee8SAndy Ritger 
4628758b4ee8SAndy Ritger /*
4629758b4ee8SAndy Ritger  * Enable FrameLock Interrupts for P2060.
4630758b4ee8SAndy Ritger  */
4631758b4ee8SAndy Ritger static NV_STATUS
gsyncEnableFramelockInterrupt_P2060(PDACEXTERNALDEVICE pExtDev)4632758b4ee8SAndy Ritger gsyncEnableFramelockInterrupt_P2060
4633758b4ee8SAndy Ritger (
4634758b4ee8SAndy Ritger     PDACEXTERNALDEVICE pExtDev
4635758b4ee8SAndy Ritger )
4636758b4ee8SAndy Ritger {
4637758b4ee8SAndy Ritger     PDACP2060EXTERNALDEVICE pThis = (PDACP2060EXTERNALDEVICE) pExtDev;
4638758b4ee8SAndy Ritger     NvU8  regCtrl3;
4639758b4ee8SAndy Ritger     NvU32 iface;
4640758b4ee8SAndy Ritger     NV_STATUS status = NV_OK;
4641758b4ee8SAndy Ritger 
4642758b4ee8SAndy Ritger     // Turn ON the interrupts
4643758b4ee8SAndy Ritger     for (iface = 0; iface < NV_P2060_MAX_IFACES_PER_GSYNC; iface++)
4644758b4ee8SAndy Ritger     {
4645758b4ee8SAndy Ritger         if (pThis->Iface[iface].GpuInfo.gpuId != NV0000_CTRL_GPU_INVALID_ID)
4646758b4ee8SAndy Ritger         {
4647758b4ee8SAndy Ritger             OBJGPU *pTmpGpu = gpumgrGetGpuFromId(pThis->Iface[iface].GpuInfo.gpuId);
4648758b4ee8SAndy Ritger             NV_ASSERT(pTmpGpu);
4649758b4ee8SAndy Ritger 
4650758b4ee8SAndy Ritger             if (gsyncReadMaster_P2060(pTmpGpu, pThis) || gsyncReadSlaves_P2060(pTmpGpu, pThis))
4651758b4ee8SAndy Ritger             {
4652758b4ee8SAndy Ritger                 status = readregu008_extdeviceTargeted(pTmpGpu,
4653758b4ee8SAndy Ritger                          (PDACEXTERNALDEVICE)pThis, NV_P2060_CONTROL3,  &regCtrl3);
4654758b4ee8SAndy Ritger 
4655758b4ee8SAndy Ritger                 if (gsyncIsStereoEnabled_p2060(pTmpGpu, pExtDev))
4656758b4ee8SAndy Ritger                 {
4657758b4ee8SAndy Ritger                       regCtrl3 |= DRF_DEF(_P2060, _CONTROL3, _INTERRUPT, _ON_STEREO_CHG);
4658758b4ee8SAndy Ritger                 }
4659758b4ee8SAndy Ritger                 regCtrl3 |= DRF_DEF(_P2060, _CONTROL3, _INTERRUPT, _ON_SYNC_CHG);
4660758b4ee8SAndy Ritger 
4661758b4ee8SAndy Ritger                 status |= writeregu008_extdeviceTargeted(pTmpGpu,
4662758b4ee8SAndy Ritger                           (PDACEXTERNALDEVICE)pThis, NV_P2060_CONTROL3, regCtrl3);
4663758b4ee8SAndy Ritger 
4664758b4ee8SAndy Ritger                 NV_PRINTF(LEVEL_INFO, "P2060[%d] enabled interrupt\n", iface);
4665758b4ee8SAndy Ritger             }
4666758b4ee8SAndy Ritger         }
4667758b4ee8SAndy Ritger     }
4668758b4ee8SAndy Ritger     return status;
4669758b4ee8SAndy Ritger }
4670758b4ee8SAndy Ritger 
4671758b4ee8SAndy Ritger /*
4672758b4ee8SAndy Ritger  * Disable FrameLock Interrupts for P2060.
4673758b4ee8SAndy Ritger  */
4674758b4ee8SAndy Ritger static NV_STATUS
gsyncDisableFrameLockInterrupt_P2060(PDACEXTERNALDEVICE pExtDev)4675758b4ee8SAndy Ritger gsyncDisableFrameLockInterrupt_P2060
4676758b4ee8SAndy Ritger (
4677758b4ee8SAndy Ritger     PDACEXTERNALDEVICE pExtDev
4678758b4ee8SAndy Ritger )
4679758b4ee8SAndy Ritger {
4680758b4ee8SAndy Ritger     PDACP2060EXTERNALDEVICE pThis = (PDACP2060EXTERNALDEVICE) pExtDev;
4681758b4ee8SAndy Ritger     NvU8  regCtrl3;
4682758b4ee8SAndy Ritger     NvU32 iface;
4683758b4ee8SAndy Ritger     NV_STATUS status = NV_OK;
4684758b4ee8SAndy Ritger 
4685758b4ee8SAndy Ritger     // Turn Off the interrupts
4686758b4ee8SAndy Ritger     for (iface = 0; iface < NV_P2060_MAX_IFACES_PER_GSYNC; iface++)
4687758b4ee8SAndy Ritger     {
4688758b4ee8SAndy Ritger         if (pThis->Iface[iface].GpuInfo.gpuId != NV0000_CTRL_GPU_INVALID_ID)
4689758b4ee8SAndy Ritger         {
4690758b4ee8SAndy Ritger             OBJGPU *pTmpGpu = gpumgrGetGpuFromId(pThis->Iface[iface].GpuInfo.gpuId);
4691758b4ee8SAndy Ritger 
4692758b4ee8SAndy Ritger             NV_ASSERT(pTmpGpu);
4693758b4ee8SAndy Ritger 
4694758b4ee8SAndy Ritger             status = readregu008_extdeviceTargeted(pTmpGpu,
4695758b4ee8SAndy Ritger                        (PDACEXTERNALDEVICE)pThis, NV_P2060_CONTROL3, &regCtrl3);
4696758b4ee8SAndy Ritger 
4697758b4ee8SAndy Ritger             regCtrl3 &= ~DRF_DEF(_P2060, _CONTROL3, _INTERRUPT, _ON_STEREO_CHG);
4698758b4ee8SAndy Ritger             regCtrl3 &= ~DRF_DEF(_P2060, _CONTROL3, _INTERRUPT, _ON_SYNC_CHG);
4699758b4ee8SAndy Ritger 
4700758b4ee8SAndy Ritger             status |= writeregu008_extdeviceTargeted(pTmpGpu,
4701758b4ee8SAndy Ritger                       (PDACEXTERNALDEVICE)pThis, NV_P2060_CONTROL3, regCtrl3);
4702758b4ee8SAndy Ritger 
4703758b4ee8SAndy Ritger             NV_PRINTF(LEVEL_INFO, "P2060[%d] disabled interrupt\n", iface);
4704758b4ee8SAndy Ritger         }
4705758b4ee8SAndy Ritger     }
4706758b4ee8SAndy Ritger 
4707758b4ee8SAndy Ritger     return status;
4708758b4ee8SAndy Ritger }
4709758b4ee8SAndy Ritger 
4710758b4ee8SAndy Ritger /*
4711758b4ee8SAndy Ritger  * Enable Non-FrameLock Interrupts for P2060.
4712758b4ee8SAndy Ritger  */
4713758b4ee8SAndy Ritger static NV_STATUS
gsyncEnableNonFramelockInterrupt_P2060(OBJGPU * pGpu,PDACEXTERNALDEVICE pExtDev)4714758b4ee8SAndy Ritger gsyncEnableNonFramelockInterrupt_P2060
4715758b4ee8SAndy Ritger (
4716758b4ee8SAndy Ritger     OBJGPU            *pGpu,
4717758b4ee8SAndy Ritger     PDACEXTERNALDEVICE pExtDev
4718758b4ee8SAndy Ritger )
4719758b4ee8SAndy Ritger {
4720758b4ee8SAndy Ritger     PDACP2060EXTERNALDEVICE pThis = (PDACP2060EXTERNALDEVICE) pExtDev;
4721758b4ee8SAndy Ritger     NvU8  regCtrl3 = 0x00;
4722758b4ee8SAndy Ritger     NV_STATUS rmStatus = NV_OK;
4723758b4ee8SAndy Ritger 
4724758b4ee8SAndy Ritger     rmStatus = readregu008_extdeviceTargeted(pGpu, (PDACEXTERNALDEVICE)pThis, NV_P2060_CONTROL3, &regCtrl3);
4725758b4ee8SAndy Ritger 
4726758b4ee8SAndy Ritger     // Enable Non-Framelock interrupts on given gsync attached gpu.
4727758b4ee8SAndy Ritger     regCtrl3 |= DRF_DEF(_P2060, _CONTROL3, _INTERRUPT, _ON_HS_CHG);
4728758b4ee8SAndy Ritger     regCtrl3 |= DRF_DEF(_P2060, _CONTROL3, _INTERRUPT, _ON_RJ45_CHG);
4729758b4ee8SAndy Ritger 
4730758b4ee8SAndy Ritger     rmStatus = writeregu008_extdeviceTargeted(pGpu,(PDACEXTERNALDEVICE)pThis, NV_P2060_CONTROL3, regCtrl3);
4731758b4ee8SAndy Ritger 
4732758b4ee8SAndy Ritger     return rmStatus;
4733758b4ee8SAndy Ritger }
4734758b4ee8SAndy Ritger 
4735758b4ee8SAndy Ritger /*
4736758b4ee8SAndy Ritger  * Disable Non-FrameLock Interrupts for P2060.
4737758b4ee8SAndy Ritger  */
4738758b4ee8SAndy Ritger static NV_STATUS
gsyncDisableNonFramelockInterrupt_P2060(OBJGPU * pGpu,PDACEXTERNALDEVICE pExtDev)4739758b4ee8SAndy Ritger gsyncDisableNonFramelockInterrupt_P2060
4740758b4ee8SAndy Ritger (
4741758b4ee8SAndy Ritger     OBJGPU            *pGpu,
4742758b4ee8SAndy Ritger     PDACEXTERNALDEVICE pExtDev
4743758b4ee8SAndy Ritger )
4744758b4ee8SAndy Ritger {
4745758b4ee8SAndy Ritger     PDACP2060EXTERNALDEVICE pThis = (PDACP2060EXTERNALDEVICE) pExtDev;
4746758b4ee8SAndy Ritger     NvU8  regCtrl3 = 0x00;
4747758b4ee8SAndy Ritger     NV_STATUS rmStatus = NV_OK;
4748758b4ee8SAndy Ritger 
4749758b4ee8SAndy Ritger     rmStatus = readregu008_extdeviceTargeted(pGpu, (PDACEXTERNALDEVICE)pThis, NV_P2060_CONTROL3, &regCtrl3);
4750758b4ee8SAndy Ritger 
4751758b4ee8SAndy Ritger     // Disable Non-Framelock interrupts on given gsync attached gpu.
4752758b4ee8SAndy Ritger     regCtrl3 &= ~DRF_DEF(_P2060, _CONTROL3, _INTERRUPT, _ON_HS_CHG);
4753758b4ee8SAndy Ritger     regCtrl3 &= ~DRF_DEF(_P2060, _CONTROL3, _INTERRUPT, _ON_RJ45_CHG);
4754758b4ee8SAndy Ritger 
4755758b4ee8SAndy Ritger     rmStatus = writeregu008_extdeviceTargeted(pGpu,(PDACEXTERNALDEVICE)pThis, NV_P2060_CONTROL3, regCtrl3);
4756758b4ee8SAndy Ritger 
4757758b4ee8SAndy Ritger     return rmStatus;
4758758b4ee8SAndy Ritger }
4759758b4ee8SAndy Ritger 
4760758b4ee8SAndy Ritger static void
gsyncResetMosaicData_P2060(NvU32 mosaicGroup,PDACP2060EXTERNALDEVICE pThis)4761758b4ee8SAndy Ritger gsyncResetMosaicData_P2060
4762758b4ee8SAndy Ritger (
4763758b4ee8SAndy Ritger     NvU32 mosaicGroup,
4764758b4ee8SAndy Ritger     PDACP2060EXTERNALDEVICE pThis
4765758b4ee8SAndy Ritger )
4766758b4ee8SAndy Ritger {
4767758b4ee8SAndy Ritger    NvU8 i;
4768758b4ee8SAndy Ritger 
4769758b4ee8SAndy Ritger    if (!pThis)
4770758b4ee8SAndy Ritger    {
4771758b4ee8SAndy Ritger         return;
4772758b4ee8SAndy Ritger    }
4773758b4ee8SAndy Ritger 
4774758b4ee8SAndy Ritger    pThis->MosaicGroup[mosaicGroup].gpuTimingSource = NV0000_CTRL_GPU_INVALID_ID;
4775758b4ee8SAndy Ritger 
4776758b4ee8SAndy Ritger    for (i = 0; i < NV_P2060_MAX_MOSAIC_SLAVES; i++)
4777758b4ee8SAndy Ritger    {
4778758b4ee8SAndy Ritger       pThis->MosaicGroup[mosaicGroup].gpuTimingSlaves[i] = NV0000_CTRL_GPU_INVALID_ID;
4779758b4ee8SAndy Ritger    }
4780758b4ee8SAndy Ritger 
4781758b4ee8SAndy Ritger    pThis->MosaicGroup[mosaicGroup].slaveGpuCount = 0;
4782758b4ee8SAndy Ritger    pThis->MosaicGroup[mosaicGroup].enabledMosaic = NV_FALSE;
4783758b4ee8SAndy Ritger 
4784758b4ee8SAndy Ritger }
4785758b4ee8SAndy Ritger 
4786758b4ee8SAndy Ritger /*
4787758b4ee8SAndy Ritger  * Enable/Disable SwapRdy Connection For GPU
4788758b4ee8SAndy Ritger  */
4789758b4ee8SAndy Ritger static NV_STATUS
gsyncUpdateSwapRdyConnectionForGpu_P2060(OBJGPU * pGpu,PDACP2060EXTERNALDEVICE pThis,NvBool bEnable)4790758b4ee8SAndy Ritger gsyncUpdateSwapRdyConnectionForGpu_P2060
4791758b4ee8SAndy Ritger (
4792758b4ee8SAndy Ritger     OBJGPU *pGpu,
4793758b4ee8SAndy Ritger     PDACP2060EXTERNALDEVICE pThis,
4794758b4ee8SAndy Ritger     NvBool bEnable
4795758b4ee8SAndy Ritger )
4796758b4ee8SAndy Ritger {
4797758b4ee8SAndy Ritger     NV_STATUS rmStatus = NV_OK;
4798758b4ee8SAndy Ritger     NvU8 ctrl2 = 0x00;
4799758b4ee8SAndy Ritger 
4800758b4ee8SAndy Ritger     rmStatus = readregu008_extdeviceTargeted(pGpu, (PDACEXTERNALDEVICE)pThis,
4801758b4ee8SAndy Ritger                                              NV_P2060_CONTROL2, &ctrl2);
4802758b4ee8SAndy Ritger     if (rmStatus != NV_OK)
4803758b4ee8SAndy Ritger     {
4804758b4ee8SAndy Ritger         return rmStatus;
4805758b4ee8SAndy Ritger     }
4806758b4ee8SAndy Ritger 
4807758b4ee8SAndy Ritger     ctrl2 = FLD_SET_DRF_NUM(_P2060, _CONTROL2, _SWAP_READY, (NvU8)bEnable, ctrl2);
4808758b4ee8SAndy Ritger 
4809758b4ee8SAndy Ritger     rmStatus = writeregu008_extdeviceTargeted(pGpu, (PDACEXTERNALDEVICE)pThis,
4810758b4ee8SAndy Ritger                                              NV_P2060_CONTROL2, ctrl2);
4811758b4ee8SAndy Ritger 
4812758b4ee8SAndy Ritger     return rmStatus;
4813758b4ee8SAndy Ritger }
4814758b4ee8SAndy Ritger 
4815758b4ee8SAndy Ritger /*
4816758b4ee8SAndy Ritger  * returns true if there is a framelock master on this P2060.
4817758b4ee8SAndy Ritger  * otherwise returns false.
4818758b4ee8SAndy Ritger  */
4819758b4ee8SAndy Ritger static NvBool
gsyncIsFrameLockMaster_P2060(PDACP2060EXTERNALDEVICE pThis)4820758b4ee8SAndy Ritger gsyncIsFrameLockMaster_P2060
4821758b4ee8SAndy Ritger (
4822758b4ee8SAndy Ritger     PDACP2060EXTERNALDEVICE pThis
4823758b4ee8SAndy Ritger )
4824758b4ee8SAndy Ritger {
4825758b4ee8SAndy Ritger     NvU32 iface;
4826758b4ee8SAndy Ritger 
4827758b4ee8SAndy Ritger     for (iface = 0; iface < NV_P2060_MAX_IFACES_PER_GSYNC; iface++)
4828758b4ee8SAndy Ritger     {
4829758b4ee8SAndy Ritger         if (pThis->Iface[iface].GpuInfo.gpuId != NV0000_CTRL_GPU_INVALID_ID)
4830758b4ee8SAndy Ritger         {
4831758b4ee8SAndy Ritger             OBJGPU *pTmpGpu = gpumgrGetGpuFromId(pThis->Iface[iface].GpuInfo.gpuId);
4832758b4ee8SAndy Ritger 
4833758b4ee8SAndy Ritger             NV_ASSERT(pTmpGpu);
4834758b4ee8SAndy Ritger 
4835758b4ee8SAndy Ritger             if (gsyncReadMaster_P2060(pTmpGpu, pThis))
4836758b4ee8SAndy Ritger             {
4837758b4ee8SAndy Ritger                 return NV_TRUE;
4838758b4ee8SAndy Ritger             }
4839758b4ee8SAndy Ritger         }
4840758b4ee8SAndy Ritger     }
4841758b4ee8SAndy Ritger 
4842758b4ee8SAndy Ritger     return NV_FALSE;
4843758b4ee8SAndy Ritger }
4844758b4ee8SAndy Ritger 
4845758b4ee8SAndy Ritger /*
4846758b4ee8SAndy Ritger  * returns NV_TRUE if this gsync device is framelocked.
4847758b4ee8SAndy Ritger  */
4848758b4ee8SAndy Ritger static NvBool
gsyncIsFrameLocked_P2060(PDACP2060EXTERNALDEVICE pThis)4849758b4ee8SAndy Ritger gsyncIsFrameLocked_P2060
4850758b4ee8SAndy Ritger (
4851758b4ee8SAndy Ritger     PDACP2060EXTERNALDEVICE pThis
4852758b4ee8SAndy Ritger )
4853758b4ee8SAndy Ritger {
4854758b4ee8SAndy Ritger     NvU32 iface;
4855758b4ee8SAndy Ritger 
4856758b4ee8SAndy Ritger     for (iface = 0; iface < NV_P2060_MAX_IFACES_PER_GSYNC; iface++)
4857758b4ee8SAndy Ritger     {
4858758b4ee8SAndy Ritger         if (pThis->Iface[iface].GpuInfo.gpuId != NV0000_CTRL_GPU_INVALID_ID)
4859758b4ee8SAndy Ritger         {
4860758b4ee8SAndy Ritger             OBJGPU *pTmpGpu = gpumgrGetGpuFromId(pThis->Iface[iface].GpuInfo.gpuId);
4861758b4ee8SAndy Ritger             NV_ASSERT(pTmpGpu);
4862758b4ee8SAndy Ritger 
4863758b4ee8SAndy Ritger             if (gsyncReadMaster_P2060(pTmpGpu, pThis) ||
4864758b4ee8SAndy Ritger                 gsyncReadSlaves_P2060(pTmpGpu, pThis))
4865758b4ee8SAndy Ritger             {
4866758b4ee8SAndy Ritger                 return NV_TRUE;
4867758b4ee8SAndy Ritger             }
4868758b4ee8SAndy Ritger         }
4869758b4ee8SAndy Ritger     }
4870758b4ee8SAndy Ritger 
4871758b4ee8SAndy Ritger     return NV_FALSE;
4872758b4ee8SAndy Ritger }
4873758b4ee8SAndy Ritger 
4874758b4ee8SAndy Ritger /*
4875758b4ee8SAndy Ritger  * returns NV_TRUE if this gsync device is only framelock master.
4876758b4ee8SAndy Ritger  */
4877758b4ee8SAndy Ritger static NvBool
gsyncIsOnlyFrameLockMaster_P2060(PDACP2060EXTERNALDEVICE pThis)4878758b4ee8SAndy Ritger gsyncIsOnlyFrameLockMaster_P2060
4879758b4ee8SAndy Ritger (
4880758b4ee8SAndy Ritger     PDACP2060EXTERNALDEVICE pThis
4881758b4ee8SAndy Ritger )
4882758b4ee8SAndy Ritger {
4883758b4ee8SAndy Ritger     NvU32 iface, numHeads, head;
4884758b4ee8SAndy Ritger     KernelDisplay  *pKernelDisplay;
4885758b4ee8SAndy Ritger     OBJGPU  *pGpu;
4886758b4ee8SAndy Ritger     NvBool bIsMaster = NV_FALSE;
4887758b4ee8SAndy Ritger 
4888758b4ee8SAndy Ritger     for (iface = 0; iface < NV_P2060_MAX_IFACES_PER_GSYNC; iface++)
4889758b4ee8SAndy Ritger     {
4890758b4ee8SAndy Ritger         if (pThis->Iface[iface].GpuInfo.gpuId != NV0000_CTRL_GPU_INVALID_ID)
4891758b4ee8SAndy Ritger         {
4892758b4ee8SAndy Ritger             pGpu  = gpumgrGetGpuFromId(pThis->Iface[iface].GpuInfo.gpuId);
4893758b4ee8SAndy Ritger             NV_ASSERT_OR_RETURN(pGpu, NV_FALSE);
4894758b4ee8SAndy Ritger 
4895758b4ee8SAndy Ritger             pKernelDisplay = GPU_GET_KERNEL_DISPLAY(pGpu);
4896758b4ee8SAndy Ritger             numHeads = kdispGetNumHeads(pKernelDisplay);
4897758b4ee8SAndy Ritger 
4898758b4ee8SAndy Ritger             for (head = 0; head < numHeads; head++)
4899758b4ee8SAndy Ritger             {
4900758b4ee8SAndy Ritger                 if (pThis->Iface[iface].Sync.Master[head])
4901758b4ee8SAndy Ritger                     bIsMaster = NV_TRUE;
4902758b4ee8SAndy Ritger 
4903758b4ee8SAndy Ritger                 if (pThis->Iface[iface].Sync.Slaved[head] ||
4904758b4ee8SAndy Ritger                     pThis->Iface[iface].Sync.LocalSlave[head])
4905758b4ee8SAndy Ritger                 {
4906758b4ee8SAndy Ritger                     return NV_FALSE;
4907758b4ee8SAndy Ritger                 }
4908758b4ee8SAndy Ritger             }
4909758b4ee8SAndy Ritger         }
4910758b4ee8SAndy Ritger     }
4911758b4ee8SAndy Ritger 
4912758b4ee8SAndy Ritger     return bIsMaster;
4913758b4ee8SAndy Ritger }
4914758b4ee8SAndy Ritger 
4915758b4ee8SAndy Ritger /*
4916758b4ee8SAndy Ritger  * return NV_TRUE if HW is OK with board as Framelock Master.
4917758b4ee8SAndy Ritger  */
4918758b4ee8SAndy Ritger static NvBool
gsyncIsP2060MasterBoard(OBJGPU * pGpu,PDACP2060EXTERNALDEVICE pThis)4919758b4ee8SAndy Ritger gsyncIsP2060MasterBoard
4920758b4ee8SAndy Ritger (
4921758b4ee8SAndy Ritger     OBJGPU *pGpu,
4922758b4ee8SAndy Ritger     PDACP2060EXTERNALDEVICE pThis
4923758b4ee8SAndy Ritger )
4924758b4ee8SAndy Ritger {
4925758b4ee8SAndy Ritger     NvU8 ctrl;
4926758b4ee8SAndy Ritger     NvBool bIsMasterBoard;
4927758b4ee8SAndy Ritger     NV_STATUS rmStatus;
4928758b4ee8SAndy Ritger 
4929758b4ee8SAndy Ritger     if (!pGpu || !GpuIsP2060Connected(pGpu, pThis))
4930758b4ee8SAndy Ritger     {
4931758b4ee8SAndy Ritger         return NV_FALSE;
4932758b4ee8SAndy Ritger     }
4933758b4ee8SAndy Ritger 
4934758b4ee8SAndy Ritger     rmStatus = readregu008_extdeviceTargeted(pGpu, (PDACEXTERNALDEVICE)pThis, (NvU8)NV_P2060_CONTROL, &ctrl);
4935758b4ee8SAndy Ritger     if (NV_OK != rmStatus)
4936758b4ee8SAndy Ritger     {
4937758b4ee8SAndy Ritger         return NV_FALSE;
4938758b4ee8SAndy Ritger     }
4939758b4ee8SAndy Ritger 
4940758b4ee8SAndy Ritger     // Check HW opinion on Mastership of board.
4941758b4ee8SAndy Ritger     bIsMasterBoard = FLD_TEST_DRF(_P2060, _CONTROL, _I_AM, _MASTER, (NvU32)ctrl);
4942758b4ee8SAndy Ritger 
4943758b4ee8SAndy Ritger     return bIsMasterBoard;
4944758b4ee8SAndy Ritger }
4945758b4ee8SAndy Ritger /*
4946758b4ee8SAndy Ritger  * return NV_TRUE if pGpu is connected to Master + TS GPU via SLI bridge
4947758b4ee8SAndy Ritger  */
4948758b4ee8SAndy Ritger static NvBool
GpuIsConnectedToMasterViaBridge(OBJGPU * pGpu,PDACP2060EXTERNALDEVICE pThis)4949758b4ee8SAndy Ritger GpuIsConnectedToMasterViaBridge
4950758b4ee8SAndy Ritger (
4951758b4ee8SAndy Ritger     OBJGPU *pGpu,
4952758b4ee8SAndy Ritger     PDACP2060EXTERNALDEVICE pThis
4953758b4ee8SAndy Ritger )
4954758b4ee8SAndy Ritger {
4955758b4ee8SAndy Ritger     OBJGPU *pOtherGpu = NULL;
4956758b4ee8SAndy Ritger     NvU32 gpuMask, gpuIndex, tempIface;
4957758b4ee8SAndy Ritger     NvU32 drOut, drIn;
4958758b4ee8SAndy Ritger 
4959758b4ee8SAndy Ritger     gpumgrGetGpuAttachInfo(NULL, &gpuMask);
4960758b4ee8SAndy Ritger     gpuIndex = 0;
4961758b4ee8SAndy Ritger     while ((pOtherGpu = gpumgrGetNextGpu(gpuMask, &gpuIndex)) != NULL)
4962758b4ee8SAndy Ritger     {
4963758b4ee8SAndy Ritger         if ((pGpu == pOtherGpu) || gpumgrGetGpuLockAndDrPorts(pGpu, pOtherGpu, &drOut, &drIn) != NV_OK)
4964758b4ee8SAndy Ritger         {
4965758b4ee8SAndy Ritger             continue;
4966758b4ee8SAndy Ritger         }
4967758b4ee8SAndy Ritger 
4968758b4ee8SAndy Ritger         if (GetP2060GpuLocation(pOtherGpu, pThis, &tempIface) == NV_OK)
4969758b4ee8SAndy Ritger         {
4970758b4ee8SAndy Ritger             if (gsyncIsP2060MasterBoard(pOtherGpu, pThis) && GpuIsP2060Master(pOtherGpu, pThis))
4971758b4ee8SAndy Ritger             {
4972758b4ee8SAndy Ritger                 // pGpu is connected to pOtherGpu via SLI bridge.
4973758b4ee8SAndy Ritger                 // Both GPUs are connected to same P2060.
4974758b4ee8SAndy Ritger                 return NV_TRUE;
4975758b4ee8SAndy Ritger             }
4976758b4ee8SAndy Ritger         }
4977758b4ee8SAndy Ritger     }
4978758b4ee8SAndy Ritger     return NV_FALSE;
4979758b4ee8SAndy Ritger }
4980758b4ee8SAndy Ritger 
4981758b4ee8SAndy Ritger //
4982758b4ee8SAndy Ritger // gsyncFrameCountTimerService_P2060()
4983758b4ee8SAndy Ritger //
4984758b4ee8SAndy Ritger // frame count timer callback service.
4985758b4ee8SAndy Ritger // this function will read the actual gsync and gpu frame count value
4986758b4ee8SAndy Ritger // and adjust the cached difference between them if required.
4987758b4ee8SAndy Ritger //
4988758b4ee8SAndy Ritger // this function is added to prevent any deviation of cached difference
4989758b4ee8SAndy Ritger // between gpu and gsync hw frame count values from the actual.
4990758b4ee8SAndy Ritger // As all the heads are framelocked, it is expected that cached
4991758b4ee8SAndy Ritger // framecount value to be same on the master as well as slave
4992758b4ee8SAndy Ritger // system. But during experiment, it is found that reading the hw gsync and
4993758b4ee8SAndy Ritger // gpu frame count values immediately after the test signal is sent/received
4994758b4ee8SAndy Ritger // may lead to inconsistent cached difference. Therefore the difference is
4995758b4ee8SAndy Ritger // reverified after FRAME_COUNT_TIMER_INTERVAL period.
4996758b4ee8SAndy Ritger //
4997758b4ee8SAndy Ritger static
gsyncFrameCountTimerService_P2060(OBJGPU * pGpu,OBJTMR * pTmr,void * pComponent)4998758b4ee8SAndy Ritger NV_STATUS gsyncFrameCountTimerService_P2060
4999758b4ee8SAndy Ritger (
5000758b4ee8SAndy Ritger     OBJGPU *pGpu,
5001758b4ee8SAndy Ritger     OBJTMR *pTmr,
5002758b4ee8SAndy Ritger     void *pComponent
5003758b4ee8SAndy Ritger )
5004758b4ee8SAndy Ritger {
5005758b4ee8SAndy Ritger     PDACP2060EXTERNALDEVICE pThis = NULL;
5006758b4ee8SAndy Ritger     NV_STATUS status;
5007758b4ee8SAndy Ritger     OBJGSYNC *pGsync = NULL;
5008758b4ee8SAndy Ritger 
5009758b4ee8SAndy Ritger     pGsync = gsyncmgrGetGsync(pGpu);
5010758b4ee8SAndy Ritger 
5011758b4ee8SAndy Ritger     NV_ASSERT_OR_RETURN((pGsync && pGsync->pExtDev), NV_ERR_INVALID_DEVICE);
5012758b4ee8SAndy Ritger 
5013758b4ee8SAndy Ritger     pThis = (PDACP2060EXTERNALDEVICE)pGsync->pExtDev;
5014758b4ee8SAndy Ritger 
5015758b4ee8SAndy Ritger     // disable the timer callback
5016758b4ee8SAndy Ritger     status = tmrCancelCallback(pTmr, (void *)&pThis->FrameCountData);
5017758b4ee8SAndy Ritger 
5018758b4ee8SAndy Ritger     if (status != NV_OK)
5019758b4ee8SAndy Ritger     {
5020758b4ee8SAndy Ritger         return status;
5021758b4ee8SAndy Ritger     }
5022758b4ee8SAndy Ritger 
5023758b4ee8SAndy Ritger     //
5024758b4ee8SAndy Ritger     // read the gsync and gpu frame count values.Cache the difference between them.
5025758b4ee8SAndy Ritger     //
5026758b4ee8SAndy Ritger     status = gsyncUpdateFrameCount_P2060(pThis, pGpu);
5027758b4ee8SAndy Ritger 
5028758b4ee8SAndy Ritger     return status;
5029758b4ee8SAndy Ritger }
5030758b4ee8SAndy Ritger /*
5031758b4ee8SAndy Ritger  * Reset the FrameCount Data structure.
5032758b4ee8SAndy Ritger  */
5033758b4ee8SAndy Ritger //
5034758b4ee8SAndy Ritger // gsyncResetFrameCountData_P2060()
5035758b4ee8SAndy Ritger //
5036758b4ee8SAndy Ritger // this function resets the FrameCountDate structure.
5037758b4ee8SAndy Ritger //
5038758b4ee8SAndy Ritger static NV_STATUS
gsyncResetFrameCountData_P2060(OBJGPU * pGpu,PDACP2060EXTERNALDEVICE pThis)5039758b4ee8SAndy Ritger gsyncResetFrameCountData_P2060
5040758b4ee8SAndy Ritger (
5041758b4ee8SAndy Ritger     OBJGPU *pGpu,
5042758b4ee8SAndy Ritger     PDACP2060EXTERNALDEVICE pThis
5043758b4ee8SAndy Ritger )
5044758b4ee8SAndy Ritger {
5045758b4ee8SAndy Ritger 
5046758b4ee8SAndy Ritger     NvU8 regCtrl3;
5047758b4ee8SAndy Ritger     NV_STATUS rmStatus;
5048758b4ee8SAndy Ritger 
5049758b4ee8SAndy Ritger     if (!pThis)
5050758b4ee8SAndy Ritger     {
5051758b4ee8SAndy Ritger         return NV_ERR_INVALID_ARGUMENT;
5052758b4ee8SAndy Ritger     }
5053758b4ee8SAndy Ritger 
5054758b4ee8SAndy Ritger     pThis->FrameCountData.totalFrameCount               = 0;
5055758b4ee8SAndy Ritger     pThis->FrameCountData.currentFrameCount             = 0;
5056758b4ee8SAndy Ritger     pThis->FrameCountData.initialDifference             = 0;
5057758b4ee8SAndy Ritger     pThis->FrameCountData.numberOfRollbacks             = 0;
5058758b4ee8SAndy Ritger     pThis->FrameCountData.previousFrameCount            = 0;
5059758b4ee8SAndy Ritger     pThis->FrameCountData.lastFrameCounterQueryTime     = 0;
5060758b4ee8SAndy Ritger     pThis->FrameCountData.bReCheck                      = 0;
5061758b4ee8SAndy Ritger     pThis->FrameCountData.vActive                       = 0;
5062758b4ee8SAndy Ritger     pThis->FrameCountData.isFrmCmpMatchIntMasterEnabled = NV_FALSE;
5063758b4ee8SAndy Ritger     pThis->FrameCountData.enableFrmCmpMatchIntSlave     = NV_FALSE;
5064758b4ee8SAndy Ritger     pThis->FrameCountData.head                          = NV_P2060_MAX_HEADS_PER_GPU;
5065758b4ee8SAndy Ritger     pThis->FrameCountData.iface                         = NV_P2060_MAX_IFACES_PER_GSYNC;
5066758b4ee8SAndy Ritger 
5067758b4ee8SAndy Ritger     // disable frame count match interrupt
5068758b4ee8SAndy Ritger     rmStatus = readregu008_extdeviceTargeted(pGpu, (PDACEXTERNALDEVICE)pThis,
5069758b4ee8SAndy Ritger                                              NV_P2060_CONTROL3, &regCtrl3);
5070758b4ee8SAndy Ritger     regCtrl3 &= ~DRF_DEF(_P2060, _CONTROL3, _INTERRUPT, _ON_FRAME_MATCH);
5071758b4ee8SAndy Ritger     rmStatus |= writeregu008_extdeviceTargeted(pGpu, (PDACEXTERNALDEVICE)pThis,
5072758b4ee8SAndy Ritger                                                NV_P2060_CONTROL3, regCtrl3);
5073758b4ee8SAndy Ritger     return rmStatus;
5074758b4ee8SAndy Ritger }
5075758b4ee8SAndy Ritger 
5076758b4ee8SAndy Ritger //
5077758b4ee8SAndy Ritger // gsyncUpdateFrameCount_P2060()
5078758b4ee8SAndy Ritger //
5079758b4ee8SAndy Ritger // For all heads in a framelocked state gpu framecount is equal.This also
5080758b4ee8SAndy Ritger // implies for gsync frame count.i.e. gsync frame count = (gpu frame count + difference)
5081758b4ee8SAndy Ritger // Therefore to reduce the i2c reads to access gsync frame count,
5082758b4ee8SAndy Ritger // (gpu frame count + difference) can be returned. This is done by caching the
5083758b4ee8SAndy Ritger // difference between the gpu and gsync framecount.
5084758b4ee8SAndy Ritger //
5085758b4ee8SAndy Ritger // FrameCountTimerService (1 second callback) is also enabled here to verify
5086758b4ee8SAndy Ritger // the cache difference.
5087758b4ee8SAndy Ritger //
5088758b4ee8SAndy Ritger static NV_STATUS
gsyncUpdateFrameCount_P2060(PDACP2060EXTERNALDEVICE pThis,OBJGPU * pGpu)5089758b4ee8SAndy Ritger gsyncUpdateFrameCount_P2060
5090758b4ee8SAndy Ritger (
5091758b4ee8SAndy Ritger     PDACP2060EXTERNALDEVICE pThis,
5092758b4ee8SAndy Ritger     OBJGPU *pGpu
5093758b4ee8SAndy Ritger )
5094758b4ee8SAndy Ritger {
5095758b4ee8SAndy Ritger     KernelDisplay *pKernelDisplay = GPU_GET_KERNEL_DISPLAY(pGpu);
5096758b4ee8SAndy Ritger     RM_API *pRmApi;
5097758b4ee8SAndy Ritger     NvU32 hClient;
5098758b4ee8SAndy Ritger     NvU32 hSubdevice;
5099758b4ee8SAndy Ritger     NvU8  FrameCountLow;
5100758b4ee8SAndy Ritger     NvU8  FrameCountMid;
5101758b4ee8SAndy Ritger     NvU8  FrameCountHigh;
5102758b4ee8SAndy Ritger     NvU8  regCtrl3;
5103758b4ee8SAndy Ritger     NvU32 rawGsyncFrameCount;
5104758b4ee8SAndy Ritger     NvU32 iface;
5105758b4ee8SAndy Ritger     NvU32 head = 0;
5106758b4ee8SAndy Ritger     NvU32 numHeads;
5107758b4ee8SAndy Ritger     NvU32 modGsyncFrameCount;
5108758b4ee8SAndy Ritger     NvU32 lineCount;
5109758b4ee8SAndy Ritger     NvU32 frameCount;
5110758b4ee8SAndy Ritger     RMTIMEOUT timeout;
5111758b4ee8SAndy Ritger     NvU32 safeRegionUpperLimit;
5112758b4ee8SAndy Ritger     NvU32 safeRegionLowerLimit;
5113758b4ee8SAndy Ritger     NV_STATUS rmStatus = NV_OK;
5114758b4ee8SAndy Ritger     NV2080_CTRL_INTERNAL_GSYNC_GET_VERTICAL_ACTIVE_LINES_PARAMS ctrlParams = {0};
5115758b4ee8SAndy Ritger 
5116758b4ee8SAndy Ritger     numHeads = kdispGetNumHeads(pKernelDisplay);
5117758b4ee8SAndy Ritger 
5118758b4ee8SAndy Ritger     // get any framelocked head
5119758b4ee8SAndy Ritger     for (iface = 0; iface < NV_P2060_MAX_IFACES_PER_GSYNC; iface++)
5120758b4ee8SAndy Ritger     {
5121758b4ee8SAndy Ritger         if (pThis->Iface[iface].GpuInfo.gpuId == NV0000_CTRL_GPU_INVALID_ID)
5122758b4ee8SAndy Ritger         {
5123758b4ee8SAndy Ritger             continue;
5124758b4ee8SAndy Ritger         }
5125758b4ee8SAndy Ritger 
5126758b4ee8SAndy Ritger         for (head = 0; head < numHeads; head++)
5127758b4ee8SAndy Ritger         {
5128758b4ee8SAndy Ritger             if (pThis->Iface[iface].Sync.Master[head] ||
5129758b4ee8SAndy Ritger                 pThis->Iface[iface].Sync.Slaved[head] ||
5130758b4ee8SAndy Ritger                 pThis->Iface[iface].Sync.LocalSlave[head])
5131758b4ee8SAndy Ritger             {
5132758b4ee8SAndy Ritger                 // Update pThis->FrameCountData with iface and head
5133758b4ee8SAndy Ritger                 pThis->FrameCountData.iface = iface;
5134758b4ee8SAndy Ritger                 pThis->FrameCountData.head  = head;
5135758b4ee8SAndy Ritger 
5136758b4ee8SAndy Ritger                 // Get out of for loop
5137758b4ee8SAndy Ritger                 iface = NV_P2060_MAX_IFACES_PER_GSYNC;
5138758b4ee8SAndy Ritger                 break;
5139758b4ee8SAndy Ritger             }
5140758b4ee8SAndy Ritger         }
5141758b4ee8SAndy Ritger     }
5142758b4ee8SAndy Ritger 
5143758b4ee8SAndy Ritger     if (head == numHeads)
5144758b4ee8SAndy Ritger     {
5145758b4ee8SAndy Ritger         return NV_ERR_GENERIC;
5146758b4ee8SAndy Ritger     }
5147758b4ee8SAndy Ritger 
5148758b4ee8SAndy Ritger     pGpu = gpumgrGetGpuFromId(pThis->Iface[pThis->FrameCountData.iface].GpuInfo.gpuId);
5149758b4ee8SAndy Ritger     NV_ASSERT_OR_RETURN(pGpu, NV_ERR_INVALID_DEVICE);
5150758b4ee8SAndy Ritger 
5151758b4ee8SAndy Ritger     pRmApi     = GPU_GET_PHYSICAL_RMAPI(pGpu);
5152758b4ee8SAndy Ritger     hClient    = pGpu->hInternalClient;
5153758b4ee8SAndy Ritger     hSubdevice = pGpu->hInternalSubdevice;
5154758b4ee8SAndy Ritger 
5155758b4ee8SAndy Ritger     // Re-fetch pDisp as pGpu might have changed.
5156758b4ee8SAndy Ritger     pKernelDisplay = GPU_GET_KERNEL_DISPLAY(pGpu);
5157758b4ee8SAndy Ritger     NV_ASSERT_OR_RETURN(pKernelDisplay != NULL, NV_ERR_INVALID_DEVICE);
5158758b4ee8SAndy Ritger     NV_ASSERT_OR_RETURN(head < kdispGetNumHeads(pKernelDisplay), NV_ERR_INVALID_DEVICE);
5159758b4ee8SAndy Ritger 
5160758b4ee8SAndy Ritger     ctrlParams.headIdx = head;
5161758b4ee8SAndy Ritger 
5162758b4ee8SAndy Ritger     rmStatus = pRmApi->Control(pRmApi, hClient, hSubdevice,
5163758b4ee8SAndy Ritger                                NV2080_CTRL_CMD_INTERNAL_GSYNC_GET_VERTICAL_ACTIVE_LINES,
5164758b4ee8SAndy Ritger                                &ctrlParams, sizeof(ctrlParams));
5165758b4ee8SAndy Ritger 
5166758b4ee8SAndy Ritger     if (rmStatus != NV_OK)
5167758b4ee8SAndy Ritger     {
5168758b4ee8SAndy Ritger         return rmStatus;
5169758b4ee8SAndy Ritger     }
5170758b4ee8SAndy Ritger 
5171758b4ee8SAndy Ritger     pThis->FrameCountData.vActive = ctrlParams.vActiveLines;
5172758b4ee8SAndy Ritger 
5173758b4ee8SAndy Ritger     //
5174758b4ee8SAndy Ritger     // To read Gpu framecount, line count should be in between 5-70% of VVisible.
5175758b4ee8SAndy Ritger     //
5176758b4ee8SAndy Ritger     safeRegionUpperLimit = (pThis->FrameCountData.vActive * 7) / 10;
5177758b4ee8SAndy Ritger     safeRegionLowerLimit = pThis->FrameCountData.vActive / 20;
5178758b4ee8SAndy Ritger 
5179758b4ee8SAndy Ritger     // Read the GPU frame count and line count
5180758b4ee8SAndy Ritger     rmStatus = kdispReadRgLineCountAndFrameCount_HAL(pGpu, pKernelDisplay,
5181758b4ee8SAndy Ritger                    pThis->FrameCountData.head, &lineCount, &frameCount);
5182758b4ee8SAndy Ritger     if (rmStatus != NV_OK)
5183758b4ee8SAndy Ritger     {
5184758b4ee8SAndy Ritger         NV_PRINTF(LEVEL_ERROR, "Failed to read RG_DPCA.\n");
5185758b4ee8SAndy Ritger         return rmStatus;
5186758b4ee8SAndy Ritger     }
5187758b4ee8SAndy Ritger 
5188758b4ee8SAndy Ritger     //
5189758b4ee8SAndy Ritger     // Wait for a safe region i.e. 5-70 percent of the VActive. Then read the
5190758b4ee8SAndy Ritger     // gsync framecount. This is done to ensure that both gsync and gpu
5191758b4ee8SAndy Ritger     // registers are read in the safe zone otherwise there will be -/+ 1
5192758b4ee8SAndy Ritger     // frame inconsistency ( if read during the transition from frame N to
5193758b4ee8SAndy Ritger     // frame N + 1 i.e linecount > vActive)
5194758b4ee8SAndy Ritger     //
5195758b4ee8SAndy Ritger     if ((lineCount >= safeRegionUpperLimit) || (lineCount <= safeRegionLowerLimit))
5196758b4ee8SAndy Ritger     {
5197758b4ee8SAndy Ritger         //
5198758b4ee8SAndy Ritger         // timeout of one frameTime(in nano seconds), to avoid going into an infinite
5199758b4ee8SAndy Ritger         // loop in case linecount is stuck to some value.
5200758b4ee8SAndy Ritger         //
5201758b4ee8SAndy Ritger         gpuSetTimeout(pGpu, (pThis->FrameCountData.frameTime * 1000), &timeout, 0);
5202758b4ee8SAndy Ritger 
5203758b4ee8SAndy Ritger         // Read the linecount until we are in the safe region i.e taken as 5%-70% of VActive.
5204758b4ee8SAndy Ritger         while (((lineCount >= safeRegionUpperLimit) || (lineCount <= safeRegionLowerLimit)) &&
5205758b4ee8SAndy Ritger                 (gpuCheckTimeout(pGpu, &timeout) != NV_ERR_TIMEOUT))
5206758b4ee8SAndy Ritger         {
5207758b4ee8SAndy Ritger             rmStatus = kdispReadRgLineCountAndFrameCount_HAL(pGpu, pKernelDisplay,
5208758b4ee8SAndy Ritger                            pThis->FrameCountData.head, &lineCount, &frameCount);
5209758b4ee8SAndy Ritger             if (rmStatus != NV_OK)
5210758b4ee8SAndy Ritger             {
5211758b4ee8SAndy Ritger                 NV_PRINTF(LEVEL_ERROR, "Failed to read RG_DPCA.\n");
5212758b4ee8SAndy Ritger                 return rmStatus;
5213758b4ee8SAndy Ritger             }
5214758b4ee8SAndy Ritger         }
5215758b4ee8SAndy Ritger 
5216758b4ee8SAndy Ritger         if ((lineCount >= safeRegionUpperLimit) || (lineCount <= safeRegionLowerLimit))
5217758b4ee8SAndy Ritger         {
5218758b4ee8SAndy Ritger             return NV_ERR_TIMEOUT;
5219758b4ee8SAndy Ritger         }
5220758b4ee8SAndy Ritger     }
5221758b4ee8SAndy Ritger 
5222758b4ee8SAndy Ritger     rmStatus |= readregu008_extdeviceTargeted(pGpu, (PDACEXTERNALDEVICE) pThis, (NvU8)NV_P2060_FRAMECNTR_LOW,  &FrameCountLow);
5223758b4ee8SAndy Ritger     rmStatus |= readregu008_extdeviceTargeted(pGpu, (PDACEXTERNALDEVICE) pThis, (NvU8)NV_P2060_FRAMECNTR_MID,  &FrameCountMid);
5224758b4ee8SAndy Ritger     rmStatus |= readregu008_extdeviceTargeted(pGpu, (PDACEXTERNALDEVICE) pThis, (NvU8)NV_P2060_FRAMECNTR_HIGH, &FrameCountHigh);
5225758b4ee8SAndy Ritger 
5226758b4ee8SAndy Ritger     if (rmStatus != NV_OK)
5227758b4ee8SAndy Ritger     {
5228758b4ee8SAndy Ritger         return rmStatus;
5229758b4ee8SAndy Ritger     }
5230758b4ee8SAndy Ritger 
5231758b4ee8SAndy Ritger      rawGsyncFrameCount = (
5232758b4ee8SAndy Ritger                           ((((NvU32)FrameCountHigh)    & DRF_MASK(NV_P2060_FRAMECNTR_HIGH_VAL))<< 16 ) |
5233758b4ee8SAndy Ritger                           ((((NvU32)FrameCountMid)     & DRF_MASK(NV_P2060_FRAMECNTR_MID_VAL)) << 8 )  |
5234758b4ee8SAndy Ritger                           ((((NvU32)FrameCountLow)     & DRF_MASK(NV_P2060_FRAMECNTR_LOW_VAL))));
5235758b4ee8SAndy Ritger 
5236758b4ee8SAndy Ritger     pThis->FrameCountData.currentFrameCount = frameCount;
5237758b4ee8SAndy Ritger 
5238758b4ee8SAndy Ritger     //
5239758b4ee8SAndy Ritger     // Gsync frame count is 24 bit register whereas Gpu frame count register is 16 bit.
5240758b4ee8SAndy Ritger     // Therefore number of rollovers of Gpu frame count register is required.
5241758b4ee8SAndy Ritger     // Else gsync frame count and (gpu frame count + difference) can be off by (2^16*N).
5242758b4ee8SAndy Ritger     // where maximum value of N can be 256. << gsync frame count 2^24 = 256* 2^16.
5243758b4ee8SAndy Ritger     //
5244758b4ee8SAndy Ritger     pThis->FrameCountData.numberOfRollbacks  = gsyncGetNumberOfGpuFrameCountRollbacks_P2060(rawGsyncFrameCount, 0, 256);
5245758b4ee8SAndy Ritger     modGsyncFrameCount                       = rawGsyncFrameCount - (pThis->FrameCountData.numberOfRollbacks * (NV_P2060_MAX_GPU_FRAME_COUNT + 1));
5246758b4ee8SAndy Ritger     pThis->FrameCountData.initialDifference  = modGsyncFrameCount - pThis->FrameCountData.currentFrameCount;
5247758b4ee8SAndy Ritger     pThis->FrameCountData.previousFrameCount = 0;
5248758b4ee8SAndy Ritger 
5249758b4ee8SAndy Ritger     pThis->FrameCountData.totalFrameCount  =  pThis->FrameCountData.currentFrameCount +
5250758b4ee8SAndy Ritger                                               pThis->FrameCountData.initialDifference +
5251758b4ee8SAndy Ritger                                               pThis->FrameCountData.numberOfRollbacks * (NV_P2060_MAX_GPU_FRAME_COUNT + 1);
5252758b4ee8SAndy Ritger 
5253758b4ee8SAndy Ritger     if (pThis->FrameCountData.enableFrmCmpMatchIntSlave)
5254758b4ee8SAndy Ritger     {
5255758b4ee8SAndy Ritger         pThis->FrameCountData.enableFrmCmpMatchIntSlave = NV_FALSE;
5256758b4ee8SAndy Ritger 
5257758b4ee8SAndy Ritger         // enable frame count match interrupt
5258758b4ee8SAndy Ritger         rmStatus |= readregu008_extdeviceTargeted(pGpu, (PDACEXTERNALDEVICE)pThis,
5259758b4ee8SAndy Ritger                                                   NV_P2060_CONTROL3,  &regCtrl3);
5260758b4ee8SAndy Ritger 
5261758b4ee8SAndy Ritger         if (rmStatus == NV_OK)
5262758b4ee8SAndy Ritger         {
5263758b4ee8SAndy Ritger             regCtrl3 |= DRF_DEF(_P2060, _CONTROL3, _INTERRUPT, _ON_FRAME_MATCH);
5264758b4ee8SAndy Ritger             rmStatus = writeregu008_extdeviceTargeted(pGpu, (PDACEXTERNALDEVICE)pThis,
5265758b4ee8SAndy Ritger                                                       NV_P2060_CONTROL3, regCtrl3);
5266758b4ee8SAndy Ritger         }
5267758b4ee8SAndy Ritger     }
5268758b4ee8SAndy Ritger 
5269758b4ee8SAndy Ritger     //
5270758b4ee8SAndy Ritger     // Schedule 1 second timer callback, to verify initialDifference.
5271758b4ee8SAndy Ritger     //
5272758b4ee8SAndy Ritger     if (pThis->FrameCountData.bReCheck)
5273758b4ee8SAndy Ritger     {
5274758b4ee8SAndy Ritger 
5275758b4ee8SAndy Ritger         NV_STATUS status = NV_OK;
5276758b4ee8SAndy Ritger         OBJTMR *pTmr  = GPU_GET_TIMER(pGpu);
5277758b4ee8SAndy Ritger 
5278758b4ee8SAndy Ritger         status = tmrScheduleCallbackRel(
5279758b4ee8SAndy Ritger                  pTmr,
5280758b4ee8SAndy Ritger                  gsyncFrameCountTimerService_P2060,
5281758b4ee8SAndy Ritger                  (void *)&pThis->FrameCountData,
5282758b4ee8SAndy Ritger                  (NV_P2060_FRAME_COUNT_TIMER_INTERVAL / 5),
5283758b4ee8SAndy Ritger                  TMR_FLAG_RECUR,
5284758b4ee8SAndy Ritger                  0);
5285758b4ee8SAndy Ritger 
5286758b4ee8SAndy Ritger         if (status == NV_OK)
5287758b4ee8SAndy Ritger         {
5288758b4ee8SAndy Ritger             pThis->FrameCountData.bReCheck = 0;
5289758b4ee8SAndy Ritger         }
5290758b4ee8SAndy Ritger 
5291758b4ee8SAndy Ritger     }
5292758b4ee8SAndy Ritger     return rmStatus;
5293758b4ee8SAndy Ritger }
5294758b4ee8SAndy Ritger 
5295758b4ee8SAndy Ritger //
5296758b4ee8SAndy Ritger // gsyncGetNumberOfGpuFrameCountRollbacks_P2060
5297758b4ee8SAndy Ritger //
5298758b4ee8SAndy Ritger // Get N where N is the maximum value for gsync framecount > N*(Gpu frame count)
5299758b4ee8SAndy Ritger //
5300758b4ee8SAndy Ritger static NvU32
gsyncGetNumberOfGpuFrameCountRollbacks_P2060(NvU32 FrameCount,NvU32 low,NvU32 high)5301758b4ee8SAndy Ritger gsyncGetNumberOfGpuFrameCountRollbacks_P2060
5302758b4ee8SAndy Ritger (
5303758b4ee8SAndy Ritger     NvU32 FrameCount,
5304758b4ee8SAndy Ritger     NvU32 low,
5305758b4ee8SAndy Ritger     NvU32 high
5306758b4ee8SAndy Ritger )
5307758b4ee8SAndy Ritger {
5308758b4ee8SAndy Ritger     NvU32 mid = (low + high) / 2;
5309758b4ee8SAndy Ritger 
5310758b4ee8SAndy Ritger     if (FrameCount >= (high * NV_P2060_MAX_GPU_FRAME_COUNT))
5311758b4ee8SAndy Ritger     {
5312758b4ee8SAndy Ritger         return high;
5313758b4ee8SAndy Ritger     }
5314758b4ee8SAndy Ritger     else if ((FrameCount >= (mid * NV_P2060_MAX_GPU_FRAME_COUNT)) &&
5315758b4ee8SAndy Ritger              (FrameCount < ((mid+1) * NV_P2060_MAX_GPU_FRAME_COUNT)))
5316758b4ee8SAndy Ritger     {
5317758b4ee8SAndy Ritger         return mid;
5318758b4ee8SAndy Ritger     }
5319758b4ee8SAndy Ritger     else if ((FrameCount > (NV_P2060_MAX_GPU_FRAME_COUNT * low)) && (FrameCount < (mid * NV_P2060_MAX_GPU_FRAME_COUNT)))
5320758b4ee8SAndy Ritger     {
5321758b4ee8SAndy Ritger         return gsyncGetNumberOfGpuFrameCountRollbacks_P2060(FrameCount, low, mid);
5322758b4ee8SAndy Ritger     }
5323758b4ee8SAndy Ritger     else if ((FrameCount > (NV_P2060_MAX_GPU_FRAME_COUNT * mid)) && (FrameCount < (high * NV_P2060_MAX_GPU_FRAME_COUNT)))
5324758b4ee8SAndy Ritger     {
5325758b4ee8SAndy Ritger         return gsyncGetNumberOfGpuFrameCountRollbacks_P2060(FrameCount, mid+1, high);
5326758b4ee8SAndy Ritger     }
5327758b4ee8SAndy Ritger     else
5328758b4ee8SAndy Ritger     {
5329758b4ee8SAndy Ritger         return 0;
5330758b4ee8SAndy Ritger     }
5331758b4ee8SAndy Ritger }
5332758b4ee8SAndy Ritger 
5333758b4ee8SAndy Ritger // Return NV_TRUE if the current Qsync revision supports large sync skew
5334e598191eSAndy Ritger NvBool
gsyncSupportsLargeSyncSkew_P2060(DACEXTERNALDEVICE * pExtdev)5335e598191eSAndy Ritger gsyncSupportsLargeSyncSkew_P2060
5336758b4ee8SAndy Ritger (
5337e598191eSAndy Ritger     DACEXTERNALDEVICE *pExtdev
5338758b4ee8SAndy Ritger )
5339758b4ee8SAndy Ritger {
5340758b4ee8SAndy Ritger     if (pExtdev->deviceId == DAC_EXTERNAL_DEVICE_P2061)
5341758b4ee8SAndy Ritger     {
5342758b4ee8SAndy Ritger         // All p2061 revisions support sync skew > 1.
5343758b4ee8SAndy Ritger         return NV_TRUE;
5344758b4ee8SAndy Ritger     }
5345758b4ee8SAndy Ritger     else
5346758b4ee8SAndy Ritger     {
5347758b4ee8SAndy Ritger         //
5348758b4ee8SAndy Ritger         // P2060 FPGA (revision < 3) does not support SyncSkew more than 1 us(HW limitation).
5349758b4ee8SAndy Ritger         // If set to value more than 1 us, we observe screen flashing. Refer bug 1058215
5350758b4ee8SAndy Ritger         //
5351758b4ee8SAndy Ritger         NV_ASSERT(pExtdev->deviceId == DAC_EXTERNAL_DEVICE_P2060);
5352758b4ee8SAndy Ritger         return (pExtdev->deviceRev >= DAC_EXTERNAL_DEVICE_REV_3);
5353758b4ee8SAndy Ritger     }
5354758b4ee8SAndy Ritger }
5355758b4ee8SAndy Ritger 
5356758b4ee8SAndy Ritger // Return NV_TRUE if the current Qsync revision needs the Swapbarrier WAR on master
5357758b4ee8SAndy Ritger static NvBool
needsMasterBarrierWar(PDACEXTERNALDEVICE pExtdev)5358758b4ee8SAndy Ritger needsMasterBarrierWar
5359758b4ee8SAndy Ritger (
5360758b4ee8SAndy Ritger     PDACEXTERNALDEVICE pExtdev
5361758b4ee8SAndy Ritger )
5362758b4ee8SAndy Ritger {
5363758b4ee8SAndy Ritger     if (pExtdev->deviceId == DAC_EXTERNAL_DEVICE_P2061)
5364758b4ee8SAndy Ritger     {
5365758b4ee8SAndy Ritger         // All p2061 revisions do not need the WAR.
5366758b4ee8SAndy Ritger         return NV_FALSE;
5367758b4ee8SAndy Ritger     }
5368758b4ee8SAndy Ritger     else
5369758b4ee8SAndy Ritger     {
5370758b4ee8SAndy Ritger         //
5371758b4ee8SAndy Ritger         // P2060 Fpga (revision <= 5) needs to have the swapbarrier set on framelock masters
5372758b4ee8SAndy Ritger         // to drive (pull up) the swap_rdy line of the whole framelock setup.
5373758b4ee8SAndy Ritger         // This is a behaviour with unwanted side effects which needs drivers wars
5374758b4ee8SAndy Ritger         // for certain configs.
5375758b4ee8SAndy Ritger         //
5376758b4ee8SAndy Ritger         NV_ASSERT(pExtdev->deviceId == DAC_EXTERNAL_DEVICE_P2060);
5377758b4ee8SAndy Ritger         return (pExtdev->deviceRev <= DAC_EXTERNAL_DEVICE_REV_5);
5378758b4ee8SAndy Ritger     }
5379758b4ee8SAndy Ritger }
5380758b4ee8SAndy Ritger 
5381758b4ee8SAndy Ritger // Return NV_TRUE if the Qsync revision is not compatible with GPU
5382758b4ee8SAndy Ritger static NvBool
isFirmwareRevMismatch(OBJGPU * pGpu,DAC_EXTERNAL_DEVICE_REVS currentRev)5383758b4ee8SAndy Ritger isFirmwareRevMismatch
5384758b4ee8SAndy Ritger (
5385758b4ee8SAndy Ritger     OBJGPU *pGpu,
5386758b4ee8SAndy Ritger     DAC_EXTERNAL_DEVICE_REVS currentRev
5387758b4ee8SAndy Ritger )
5388758b4ee8SAndy Ritger {
5389*91676d66SBernhard Stoeckner     if (IsMAXWELL(pGpu))
5390758b4ee8SAndy Ritger     {
5391758b4ee8SAndy Ritger         return (currentRev < NV_P2060_MIN_REV);
5392758b4ee8SAndy Ritger     }
5393758b4ee8SAndy Ritger     else
5394758b4ee8SAndy Ritger     {
5395758b4ee8SAndy Ritger         return NV_FALSE;
5396758b4ee8SAndy Ritger     }
5397758b4ee8SAndy Ritger }
5398758b4ee8SAndy Ritger 
5399758b4ee8SAndy Ritger /*
5400758b4ee8SAndy Ritger  * Nvlink and QSync can both transmit inter-GPU Display sync signals.
5401758b4ee8SAndy Ritger  * Contention in these signals is observed on some boards, if both Nvlink and
5402758b4ee8SAndy Ritger  * QSync are present between the boards.
5403758b4ee8SAndy Ritger  *
5404758b4ee8SAndy Ritger  * Returns TRUE if contention in transmission of sync signals possible on the
5405758b4ee8SAndy Ritger  * given GPU board if both mediums (QSync and Nvlink) are present between GPUs
5406758b4ee8SAndy Ritger  */
5407758b4ee8SAndy Ritger 
5408758b4ee8SAndy Ritger static NvBool
isBoardWithNvlinkQsyncContention(OBJGPU * pGpu)5409758b4ee8SAndy Ritger isBoardWithNvlinkQsyncContention
5410758b4ee8SAndy Ritger (
54114397463eSAndy Ritger     OBJGPU *pGpu
5412758b4ee8SAndy Ritger )
5413758b4ee8SAndy Ritger {
5414758b4ee8SAndy Ritger     NvU16 devIds[] = {
5415758b4ee8SAndy Ritger         0x2230,     // Nvidia RTX A6000 (PG133 SKU 500)
5416758b4ee8SAndy Ritger         0x2231,     // Nvidia RTX A5000 (PG132 SKU 500)
5417758b4ee8SAndy Ritger         0x2233      // Nvidia RTX A5500 (PG132 SKU 520)
5418758b4ee8SAndy Ritger     };
5419758b4ee8SAndy Ritger 
5420758b4ee8SAndy Ritger     NvU16 thisDevId = (NvU16)(((pGpu->idInfo.PCIDeviceID) >> 16) & 0x0000FFFF);
5421758b4ee8SAndy Ritger     NvU32 i;
5422758b4ee8SAndy Ritger 
5423758b4ee8SAndy Ritger     for (i=0; i < (sizeof(devIds)/sizeof(devIds[0])); i++)
5424758b4ee8SAndy Ritger     {
5425758b4ee8SAndy Ritger         if (thisDevId == devIds[i])
5426758b4ee8SAndy Ritger         {
5427758b4ee8SAndy Ritger             return NV_TRUE;
5428758b4ee8SAndy Ritger         }
5429758b4ee8SAndy Ritger     }
5430758b4ee8SAndy Ritger 
5431758b4ee8SAndy Ritger     return NV_FALSE;
5432758b4ee8SAndy Ritger }
54334397463eSAndy Ritger 
54344397463eSAndy Ritger // Return NV_TRUE if the current Qsync revision supports sync multiply/divide
54354397463eSAndy Ritger static NvBool
supportsMulDiv(DACEXTERNALDEVICE * pExtDev)54364397463eSAndy Ritger supportsMulDiv
54374397463eSAndy Ritger (
54384397463eSAndy Ritger     DACEXTERNALDEVICE *pExtDev
54394397463eSAndy Ritger )
54404397463eSAndy Ritger {
54414397463eSAndy Ritger     // Supported only for 2061 boards with >= 2.4
54424397463eSAndy Ritger     if (pExtDev->deviceId == DAC_EXTERNAL_DEVICE_P2061)
54434397463eSAndy Ritger     {
54444397463eSAndy Ritger         if ((pExtDev->deviceRev >= DAC_EXTERNAL_DEVICE_REV_3) ||
54454397463eSAndy Ritger             ((pExtDev->deviceRev == DAC_EXTERNAL_DEVICE_REV_2) &&
54464397463eSAndy Ritger              (pExtDev->deviceExRev >= 4)))
54474397463eSAndy Ritger         {
54484397463eSAndy Ritger             return NV_TRUE;
54494397463eSAndy Ritger         }
54504397463eSAndy Ritger     }
54514397463eSAndy Ritger     return NV_FALSE;
54524397463eSAndy Ritger }
54534397463eSAndy Ritger 
54544397463eSAndy Ritger NV_STATUS
gsyncGetMulDiv_P2060(OBJGPU * pGpu,DACEXTERNALDEVICE * pExtDev,NV30F1_CTRL_GSYNC_MULTIPLY_DIVIDE_SETTINGS * pMulDivSettings)54554397463eSAndy Ritger gsyncGetMulDiv_P2060
54564397463eSAndy Ritger (
54574397463eSAndy Ritger     OBJGPU *pGpu,
54584397463eSAndy Ritger     DACEXTERNALDEVICE *pExtDev,
54594397463eSAndy Ritger     NV30F1_CTRL_GSYNC_MULTIPLY_DIVIDE_SETTINGS *pMulDivSettings
54604397463eSAndy Ritger )
54614397463eSAndy Ritger {
54624397463eSAndy Ritger     DACP2060EXTERNALDEVICE *pThis = (DACP2060EXTERNALDEVICE *)pExtDev;
54634397463eSAndy Ritger     NvU8 reg;
54644397463eSAndy Ritger 
54654397463eSAndy Ritger     NV_ASSERT_OR_RETURN(pMulDivSettings != NULL, NV_ERR_INVALID_ARGUMENT);
54664397463eSAndy Ritger     NV_CHECK_OR_RETURN(LEVEL_INFO, supportsMulDiv(pExtDev), NV_ERR_NOT_SUPPORTED);
54674397463eSAndy Ritger 
54684397463eSAndy Ritger     NV_CHECK_OK_OR_RETURN(LEVEL_INFO,
54694397463eSAndy Ritger         readregu008_extdeviceTargeted(pGpu, pExtDev, NV_P2060_MULTIPLIER_DIVIDER, &reg));
54704397463eSAndy Ritger 
54714397463eSAndy Ritger     pMulDivSettings->multiplyDivideValue =
54724397463eSAndy Ritger         DRF_VAL(_P2060, _MULTIPLIER_DIVIDER, _VALUE_MINUS_ONE, reg) + 1;
54734397463eSAndy Ritger     pMulDivSettings->multiplyDivideMode =
54744397463eSAndy Ritger         FLD_TEST_DRF(_P2060, _MULTIPLIER_DIVIDER, _MODE, _DIVIDE, reg) ?
54754397463eSAndy Ritger             NV30F1_CTRL_GSYNC_SET_CONTROL_MULTIPLY_DIVIDE_MODE_DIVIDE :
54764397463eSAndy Ritger             NV30F1_CTRL_GSYNC_SET_CONTROL_MULTIPLY_DIVIDE_MODE_MULTIPLY;
54774397463eSAndy Ritger 
54784397463eSAndy Ritger     // Cache this for debugging
54794397463eSAndy Ritger     portMemCopy(&pThis->mulDivSettings, sizeof(pThis->mulDivSettings),
54804397463eSAndy Ritger                 pMulDivSettings, sizeof(*pMulDivSettings));
54814397463eSAndy Ritger 
54824397463eSAndy Ritger     return NV_OK;
54834397463eSAndy Ritger }
54844397463eSAndy Ritger 
54854397463eSAndy Ritger NV_STATUS
gsyncSetMulDiv_P2060(OBJGPU * pGpu,DACEXTERNALDEVICE * pExtDev,NV30F1_CTRL_GSYNC_MULTIPLY_DIVIDE_SETTINGS * pMulDivSettings)54864397463eSAndy Ritger gsyncSetMulDiv_P2060
54874397463eSAndy Ritger (
54884397463eSAndy Ritger     OBJGPU *pGpu,
54894397463eSAndy Ritger     DACEXTERNALDEVICE *pExtDev,
54904397463eSAndy Ritger     NV30F1_CTRL_GSYNC_MULTIPLY_DIVIDE_SETTINGS *pMulDivSettings
54914397463eSAndy Ritger )
54924397463eSAndy Ritger {
54934397463eSAndy Ritger     DACP2060EXTERNALDEVICE *pThis = (DACP2060EXTERNALDEVICE *)pExtDev;
54944397463eSAndy Ritger     NvU8 reg;
54954397463eSAndy Ritger 
54964397463eSAndy Ritger     NV_ASSERT_OR_RETURN(pMulDivSettings != NULL, NV_ERR_INVALID_ARGUMENT);
54974397463eSAndy Ritger     NV_CHECK_OR_RETURN(LEVEL_INFO, supportsMulDiv(pExtDev), NV_ERR_NOT_SUPPORTED);
54984397463eSAndy Ritger     pGpu = GetP2060MasterableGpu(pGpu, (DACP2060EXTERNALDEVICE *)pExtDev);
54994397463eSAndy Ritger     NV_ASSERT_OR_RETURN(pGpu != NULL, NV_ERR_GENERIC);
55004397463eSAndy Ritger 
55014397463eSAndy Ritger     //
55024397463eSAndy Ritger     // Assume that there are no other fields inside NV_P2060_MULTIPLIER_DIVIDER
55034397463eSAndy Ritger     // to necessitate a read-modify-write
55044397463eSAndy Ritger     //
55054397463eSAndy Ritger     reg = 0;
55064397463eSAndy Ritger 
55074397463eSAndy Ritger     switch (pMulDivSettings->multiplyDivideMode)
55084397463eSAndy Ritger     {
55094397463eSAndy Ritger         case NV30F1_CTRL_GSYNC_SET_CONTROL_MULTIPLY_DIVIDE_MODE_MULTIPLY:
55104397463eSAndy Ritger             reg = FLD_SET_DRF(_P2060, _MULTIPLIER_DIVIDER, _MODE, _MULTIPLY, reg);
55114397463eSAndy Ritger             break;
55124397463eSAndy Ritger         case NV30F1_CTRL_GSYNC_SET_CONTROL_MULTIPLY_DIVIDE_MODE_DIVIDE:
55134397463eSAndy Ritger             reg = FLD_SET_DRF(_P2060, _MULTIPLIER_DIVIDER, _MODE, _DIVIDE, reg);
55144397463eSAndy Ritger             break;
55154397463eSAndy Ritger         default:
55164397463eSAndy Ritger             return NV_ERR_INVALID_PARAMETER;
55174397463eSAndy Ritger     }
55184397463eSAndy Ritger 
55194397463eSAndy Ritger     // The register is a 3-bit value ranging from 0-7 representing the integers from 1-8, so check the input param
55204397463eSAndy Ritger     if ((pMulDivSettings->multiplyDivideValue < 1) ||
55214397463eSAndy Ritger         (pMulDivSettings->multiplyDivideValue > (NV_P2060_MULTIPLIER_DIVIDER_VALUE_MINUS_ONE_MAX + 1)))
55224397463eSAndy Ritger         return NV_ERR_INVALID_PARAMETER;
55234397463eSAndy Ritger     // Subtract 1 while packing the register
55244397463eSAndy Ritger     reg = FLD_SET_DRF_NUM(_P2060, _MULTIPLIER_DIVIDER, _VALUE_MINUS_ONE,
55254397463eSAndy Ritger                           pMulDivSettings->multiplyDivideValue - 1, reg);
55264397463eSAndy Ritger 
55274397463eSAndy Ritger     NV_CHECK_OK_OR_RETURN(LEVEL_INFO, writeregu008_extdeviceTargeted(pGpu, pExtDev, NV_P2060_MULTIPLIER_DIVIDER, reg));
55284397463eSAndy Ritger 
55294397463eSAndy Ritger     // Cache this for debugging
55304397463eSAndy Ritger     portMemCopy(&pThis->mulDivSettings, sizeof(pThis->mulDivSettings),
55314397463eSAndy Ritger                 pMulDivSettings, sizeof(*pMulDivSettings));
55324397463eSAndy Ritger 
55334397463eSAndy Ritger     return NV_OK;
55344397463eSAndy Ritger }
5535