1 /* 2 * SPDX-FileCopyrightText: Copyright (c) 2014 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 * SPDX-License-Identifier: MIT 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a 6 * copy of this software and associated documentation files (the "Software"), 7 * to deal in the Software without restriction, including without limitation 8 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 * and/or sell copies of the Software, and to permit persons to whom the 10 * Software is furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice shall be included in 13 * all copies or substantial portions of the Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 * DEALINGS IN THE SOFTWARE. 22 */ 23 24 #include "nvkms-framelock.h" 25 #include "nvkms-dpy.h" 26 #include "nvkms-utils.h" 27 #include "nvkms-evo.h" 28 #include "nvkms-rm.h" 29 #include "nvkms-rmapi.h" 30 31 #include "nvkms-private.h" /* nvSendDpyAttributeChangedEventEvo() */ 32 33 #include <class/cl30f1.h> 34 #include <ctrl/ctrl0000/ctrl0000gsync.h> /* NV0000_CTRL_CMD_GSYNC_GET_ATTACHED_IDS */ 35 #include <ctrl/ctrl30f1.h> 36 #include "nvos.h" 37 38 static NvBool FrameLockUseHouseSyncGetSupport(NVFrameLockEvoPtr pFrameLockEvo, 39 NvU32 *val); 40 static NvBool FrameLockSetPolarity( 41 NVFrameLockEvoPtr pFrameLockEvo, 42 enum NvKmsFrameLockAttributePolarityValue val); 43 static NvBool HouseSyncOutputModeUsable(const NVFrameLockEvoRec *pFrameLockEvo); 44 45 /*! 46 * Handle framelock sync gain/loss events triggered from resman. 47 * 48 * When RM sends an event notification that's handled by FrameLockEvent, 49 * that function schedules a timer to service that event notification. 50 * These timers are serviced out of order, though; we may receive a 51 * SYNC_LOSS event followed by a SYNC_GAIN event, but our scheduled 52 * callbacks may be called in the reverse order. 53 * 54 * Since we can't trust that events were serviced in order, this function 55 * responds to every sync gain or loss event by querying the actual 56 * sync status across all GPUs from RM and updating our cached sync status 57 * and notifying clients if necessary. 58 */ 59 static void 60 FrameLockHandleSyncEvent(void *dataPtr, NvU32 dataU32) 61 { 62 NVDispEvoPtr pDispEvo = dataPtr; 63 NVFrameLockEvoPtr pFrameLockEvo = pDispEvo->pFrameLockEvo; 64 NvU32 connectorIndex = pDispEvo->framelock.connectorIndex; 65 NvBool syncReadyCurrent = FALSE; 66 NV30F1_CTRL_GSYNC_GET_STATUS_SYNC_PARAMS statusParams = { 0 }; 67 68 statusParams.gpuId = nvGpuIdOfDispEvo(pDispEvo); 69 70 if (nvRmApiControl(nvEvoGlobal.clientHandle, 71 pFrameLockEvo->device, 72 NV30F1_CTRL_CMD_GSYNC_GET_STATUS_SYNC, 73 &statusParams, 74 sizeof(statusParams)) != NVOS_STATUS_SUCCESS) { 75 nvAssert(!"Failed to query gsync status after event"); 76 } else { 77 if (statusParams.bTiming && statusParams.bSyncReady) { 78 syncReadyCurrent = TRUE; 79 } 80 } 81 82 // Update syncReadyGpuMask for consistency with non-NVKMS path, although 83 // it is currently unused. 84 if (syncReadyCurrent) { 85 pFrameLockEvo->syncReadyGpuMask |= (1 << connectorIndex); 86 } else { 87 pFrameLockEvo->syncReadyGpuMask &= ~(1 << connectorIndex); 88 } 89 90 if (syncReadyCurrent != pFrameLockEvo->syncReadyLast) { 91 pFrameLockEvo->syncReadyLast = syncReadyCurrent; 92 nvSendFrameLockAttributeChangedEventEvo( 93 pFrameLockEvo, 94 NV_KMS_FRAMELOCK_ATTRIBUTE_SYNC_READY, 95 pFrameLockEvo->syncReadyLast); 96 } 97 } 98 99 /*! 100 * Receive framelock events from resman. 101 * 102 * This function is registered as a kernel callback function from 103 * resman. 104 * 105 * However, it is called with resman's context (resman locks held, etc). 106 * Schedule deferred work, so that we can process the event without resman's 107 * encumbrances. 108 */ 109 static void FrameLockEvent(void *arg, void *pEventDataVoid, 110 NvU32 hEvent, 111 NvU32 Data, NV_STATUS Status) 112 { 113 static nvkms_timer_proc_t *callbackTable[] = { 114 [NV30F1_GSYNC_NOTIFIERS_SYNC_LOSS(0)] = FrameLockHandleSyncEvent, 115 [NV30F1_GSYNC_NOTIFIERS_SYNC_LOSS(1)] = FrameLockHandleSyncEvent, 116 [NV30F1_GSYNC_NOTIFIERS_SYNC_LOSS(2)] = FrameLockHandleSyncEvent, 117 [NV30F1_GSYNC_NOTIFIERS_SYNC_LOSS(3)] = FrameLockHandleSyncEvent, 118 119 [NV30F1_GSYNC_NOTIFIERS_SYNC_GAIN(0)] = FrameLockHandleSyncEvent, 120 [NV30F1_GSYNC_NOTIFIERS_SYNC_GAIN(1)] = FrameLockHandleSyncEvent, 121 [NV30F1_GSYNC_NOTIFIERS_SYNC_GAIN(2)] = FrameLockHandleSyncEvent, 122 [NV30F1_GSYNC_NOTIFIERS_SYNC_GAIN(3)] = FrameLockHandleSyncEvent, 123 }; 124 125 const NvNotification *pNotifyData = pEventDataVoid; 126 NvU32 notifyIndex; 127 128 /* callbackTable[] assumes at most four connectors per gsync */ 129 ct_assert(NV30F1_GSYNC_CONNECTOR_COUNT == 4); 130 131 if (pNotifyData == NULL) { 132 nvAssert(!"Invalid pNotifyData from resman"); 133 return; 134 } 135 136 notifyIndex = pNotifyData->info32; 137 138 if ((notifyIndex >= ARRAY_LEN(callbackTable)) || 139 (callbackTable[notifyIndex] == NULL)) { 140 nvAssert(!"Invalid notifyIndex from resman"); 141 return; 142 } 143 144 (void) nvkms_alloc_timer_with_ref_ptr( 145 callbackTable[notifyIndex], /* callback */ 146 arg, /* argument (this is a ref_ptr to a pDispEvo) */ 147 0, /* unused */ 148 0); /* timeout (i.e., service as soon as possible) */ 149 } 150 151 /*! 152 * Free all events and handles allocated in FrameLockCreateEvents(). 153 */ 154 static void FrameLockDestroyEvents(NVDispEvoPtr pDispEvo) 155 { 156 NVFrameLockEvoPtr pFrameLockEvo = pDispEvo->pFrameLockEvo; 157 unsigned int i; 158 159 if (pFrameLockEvo == NULL) { 160 return; 161 } 162 163 for (i = 0; i < NV_FRAMELOCK_NUM_EVENTS; i++) { 164 if (pDispEvo->framelock.gsyncEvent[i].handle) { 165 nvRmApiFree(nvEvoGlobal.clientHandle, 166 pFrameLockEvo->device, 167 pDispEvo->framelock.gsyncEvent[i].handle); 168 nvFreeUnixRmHandle(&pDispEvo->pDevEvo->handleAllocator, 169 pDispEvo->framelock.gsyncEvent[i].handle); 170 pDispEvo->framelock.gsyncEvent[i].handle = 0; 171 } 172 } 173 } 174 175 /*! 176 * Allocate and configure all events and handles associated with them. 177 */ 178 static NvBool FrameLockCreateEvents(NVDispEvoPtr pDispEvo) 179 { 180 NVDevEvoPtr pDevEvo = pDispEvo->pDevEvo; 181 NVFrameLockEvoPtr pFrameLockEvo = pDispEvo->pFrameLockEvo; 182 const NvU32 connectorIndex = pDispEvo->framelock.connectorIndex; 183 unsigned int i; 184 185 if (pDispEvo->pFrameLockEvo == NULL) { 186 return TRUE; 187 } 188 189 nvAssert(connectorIndex < NV30F1_GSYNC_CONNECTOR_COUNT); 190 191 /* We should only get here on hardware that has per-connector events */ 192 nvAssert(!(pFrameLockEvo->caps & 193 NV30F1_CTRL_GSYNC_GET_CAPS_CAP_FLAGS_ONLY_PRIMARY_CONNECTOR_EVENT)); 194 195 for (i = 0; i < NV_FRAMELOCK_NUM_EVENTS; i++) { 196 NvU32 notifier; 197 NvBool ret; 198 199 switch (i) { 200 case NV_FRAMELOCK_SYNC_LOSS: 201 notifier = NV30F1_GSYNC_NOTIFIERS_SYNC_LOSS(connectorIndex); 202 break; 203 case NV_FRAMELOCK_SYNC_GAIN: 204 notifier = NV30F1_GSYNC_NOTIFIERS_SYNC_GAIN(connectorIndex); 205 break; 206 default: 207 nvAssert(!"Unknown gsync event index"); 208 continue; 209 } 210 211 pDispEvo->framelock.gsyncEvent[i].handle = 212 nvGenerateUnixRmHandle(&pDevEvo->handleAllocator); 213 214 ret = TRUE; 215 216 if (!nvRmRegisterCallback(pDevEvo, 217 &pDispEvo->framelock.gsyncEvent[i].callback, 218 pDispEvo->ref_ptr, 219 pFrameLockEvo->device, 220 pDispEvo->framelock.gsyncEvent[i].handle, 221 FrameLockEvent, 222 notifier)) { 223 ret = FALSE; 224 } 225 226 if (!ret) { 227 nvEvoLogDispDebug(pDispEvo, EVO_LOG_ERROR, 228 "Failed to register for framelock event %d", i); 229 nvFreeUnixRmHandle(&pDevEvo->handleAllocator, 230 pDispEvo->framelock.gsyncEvent[i].handle); 231 pDispEvo->framelock.gsyncEvent[i].handle = 0; 232 goto noEvents; 233 } 234 } 235 236 return TRUE; 237 238 noEvents: 239 240 nvEvoLogDisp(pDispEvo, EVO_LOG_WARN, 241 "Failed to register for framelock events"); 242 243 FrameLockDestroyEvents(pDispEvo); 244 245 return FALSE; 246 } 247 248 /*! 249 * Bind a pSubDev to a pFrameLock. 250 */ 251 static void BindGpuToFrameLock(NVDevEvoPtr pDevEvo, 252 const NvU32 gpuId, 253 NVFrameLockEvoPtr pFrameLockEvo, 254 NvU32 connectorIndex) 255 { 256 NVDispEvoPtr pDispEvo; 257 unsigned int dispIndex; 258 259 if (pFrameLockEvo->nGpuIds >= ARRAY_LEN(pFrameLockEvo->gpuIds)) { 260 return; 261 } 262 263 pFrameLockEvo->gpuIds[pFrameLockEvo->nGpuIds] = gpuId; 264 pFrameLockEvo->nGpuIds++; 265 266 /* 267 * If a disp exists for this subdevice, wire it up. 268 * Note that this should not happen for SLI non-display-owners. 269 */ 270 271 FOR_ALL_EVO_DISPLAYS(pDispEvo, dispIndex, pDevEvo) { 272 273 if (nvGpuIdOfDispEvo(pDispEvo) != gpuId) { 274 continue; 275 } 276 277 pDispEvo->pFrameLockEvo = pFrameLockEvo; 278 279 pDispEvo->framelock.connectorIndex = connectorIndex; 280 281 pFrameLockEvo->connectedGpuMask |= (1 << connectorIndex); 282 pFrameLockEvo->syncReadyGpuMask &= ~(1 << connectorIndex); 283 284 /* Set up stereo synchronization events */ 285 FrameLockCreateEvents(pDispEvo); 286 } 287 } 288 289 /*! 290 * Break the binding of pSubDev and pDisp to pFrameLock that we 291 * created in BindGpuToFrameLock(). 292 */ 293 static void UnbindGpuFromFrameLock(NVDevEvoPtr pDevEvo, 294 const NvU32 gpuId, 295 NVFrameLockEvoPtr pFrameLockEvo) 296 { 297 NVDispEvoPtr pDispEvo; 298 unsigned int dispIndex; 299 unsigned int gpu, j; 300 301 for (gpu = 0; gpu < pFrameLockEvo->nGpuIds; gpu++) { 302 if (pFrameLockEvo->gpuIds[gpu] == gpuId) { 303 break; 304 } 305 } 306 307 if (gpu == pFrameLockEvo->nGpuIds) { 308 return; 309 } 310 311 FOR_ALL_EVO_DISPLAYS(pDispEvo, dispIndex, pDevEvo) { 312 313 const NvU32 connectorIndex = pDispEvo->framelock.connectorIndex; 314 315 if (nvGpuIdOfDispEvo(pDispEvo) != gpuId) { 316 continue; 317 } 318 319 FrameLockDestroyEvents(pDispEvo); 320 321 pFrameLockEvo->connectedGpuMask &= ~(1 << connectorIndex); 322 pFrameLockEvo->syncReadyGpuMask &= ~(1 << connectorIndex); 323 324 pDispEvo->framelock.connectorIndex = 0; 325 326 pDispEvo->pFrameLockEvo = NULL; 327 } 328 329 for (j = gpu; j < (pFrameLockEvo->nGpuIds - 1); j++) { 330 pFrameLockEvo->gpuIds[j] = pFrameLockEvo->gpuIds[j+1]; 331 } 332 333 pFrameLockEvo->nGpuIds--; 334 } 335 336 /*! 337 * Find the NVFrameLockEvoPtr with the specified gsyncId. 338 */ 339 static NVFrameLockEvoPtr FindFrameLock(NvU32 gsyncId) 340 { 341 NVFrameLockEvoPtr pFrameLockEvo; 342 343 FOR_ALL_EVO_FRAMELOCKS(pFrameLockEvo) { 344 if (pFrameLockEvo->gsyncId == gsyncId) { 345 return pFrameLockEvo; 346 } 347 } 348 349 return NULL; 350 } 351 352 /*! 353 * Return whether the NVDevEvoPtr contains a GPU with the specified gpuId. 354 */ 355 static NvBool GpuIdInDevEvo(NVDevEvoPtr pDevEvo, NvU32 gpuId) 356 { 357 NvU32 sd; 358 359 for (sd = 0; sd < pDevEvo->numSubDevices; sd++) { 360 if (pDevEvo->pSubDevices[sd]->gpuId == gpuId) { 361 return TRUE; 362 } 363 } 364 365 return FALSE; 366 } 367 368 /*! 369 * Free the pFrameLock object. 370 */ 371 static void FreeFrameLockEvo(NVDevEvoPtr pDevEvo, 372 NVFrameLockEvoPtr pFrameLockEvo) 373 { 374 if (pFrameLockEvo == NULL) { 375 return; 376 } 377 378 if (pFrameLockEvo->device != 0) { 379 nvRmApiFree(nvEvoGlobal.clientHandle, 380 nvEvoGlobal.clientHandle, 381 pFrameLockEvo->device); 382 383 nvFreeUnixRmHandle(&pDevEvo->handleAllocator, 384 pFrameLockEvo->device); 385 pFrameLockEvo->device = 0; 386 } 387 388 nvAssert(pFrameLockEvo->nGpuIds == 0); 389 390 nvListDel(&pFrameLockEvo->frameLockListEntry); 391 392 nvFree(pFrameLockEvo); 393 } 394 395 /*! 396 * Allocate and initialize a new pFrameLock object. 397 */ 398 static NVFrameLockEvoPtr AllocFrameLockEvo(NVDevEvoPtr pDevEvo, 399 int instance, NvU32 gsyncId) 400 { 401 NV30F1_ALLOC_PARAMETERS gsyncAllocParams = { 0 }; 402 NV30F1_CTRL_GSYNC_GET_CAPS_PARAMS gsyncGetCapsParams = { 0 }; 403 NVFrameLockEvoPtr pFrameLockEvo; 404 405 nvAssert(FindFrameLock(gsyncId) == NULL); 406 407 pFrameLockEvo = nvCalloc(1, sizeof(NVFrameLockEvoRec)); 408 409 if (pFrameLockEvo == NULL) { 410 return NULL; 411 } 412 413 nvListInit(&pFrameLockEvo->frameLockListEntry); 414 415 pFrameLockEvo->device = nvGenerateUnixRmHandle(&pDevEvo->handleAllocator); 416 417 gsyncAllocParams.gsyncInstance = instance; 418 419 /* allocate a framelock object for the framelock device */ 420 if (nvRmApiAlloc(nvEvoGlobal.clientHandle, 421 nvEvoGlobal.clientHandle, 422 pFrameLockEvo->device, 423 NV30_GSYNC, 424 &gsyncAllocParams) != NVOS_STATUS_SUCCESS) { 425 pFrameLockEvo->device = 0; 426 goto fail; 427 } 428 429 /* Store unique frame lock device ID */ 430 pFrameLockEvo->gsyncId = gsyncId; 431 pFrameLockEvo->houseSyncUseable = 0; 432 pFrameLockEvo->nGpuIds = 0; 433 434 /* Initialize the state for the framelock board */ 435 pFrameLockEvo->polarity = NV_KMS_FRAMELOCK_ATTRIBUTE_POLARITY_FALLING_EDGE; 436 pFrameLockEvo->syncDelay = 0; 437 pFrameLockEvo->syncInterval = 0; 438 pFrameLockEvo->videoMode = 439 NV_KMS_FRAMELOCK_ATTRIBUTE_VIDEO_MODE_COMPOSITE_AUTO; 440 pFrameLockEvo->testMode = FALSE; 441 pFrameLockEvo->houseSyncMode = 442 NV_KMS_FRAMELOCK_ATTRIBUTE_HOUSE_SYNC_MODE_DISABLED; 443 pFrameLockEvo->mulDivValue = 1; 444 pFrameLockEvo->mulDivMode = NV_KMS_FRAMELOCK_ATTRIBUTE_MULTIPLY_DIVIDE_MODE_MULTIPLY; 445 446 /* Query the framelock revision information */ 447 if (nvRmApiControl(nvEvoGlobal.clientHandle, 448 pFrameLockEvo->device, 449 NV30F1_CTRL_CMD_GSYNC_GET_CAPS, 450 &gsyncGetCapsParams, 451 sizeof(gsyncGetCapsParams)) 452 != NVOS_STATUS_SUCCESS) { 453 goto fail; 454 } 455 456 /* Check if the Quadro Sync card has a firmware 457 * version compatible with the GPUs connected to it. 458 */ 459 pDevEvo->badFramelockFirmware = gsyncGetCapsParams.isFirmwareRevMismatch; 460 if (gsyncGetCapsParams.isFirmwareRevMismatch) { 461 nvEvoLogDev(pDevEvo, EVO_LOG_ERROR, "The firmware on this Quadro Sync " 462 "card is not compatible with the GPUs connected to it." 463 " Please visit " 464 "<https://www.nvidia.com/object/quadro-sync.html> " 465 "for instructions on installing the correct firmware."); 466 goto fail; 467 } 468 469 /* gsyncGetCapsParams.revId has the framelock board id in the high 4 bits 470 * and the FPGA revision in the low 4 bits. This is preserved here for 471 * legacy clients, but we expose the full board ID (e.g. 0x358, 0x2060, 472 * 0x2061) and firmware version individually, so clients can more easily 473 * distinguish P2061 ("Quadro Sync II") from P2060 and P358 474 * ("Quadro Sync"). 475 */ 476 477 pFrameLockEvo->fpgaIdAndRevision = gsyncGetCapsParams.revId; 478 pFrameLockEvo->boardId = gsyncGetCapsParams.boardId; 479 pFrameLockEvo->firmwareMajorVersion = gsyncGetCapsParams.revision; 480 pFrameLockEvo->firmwareMinorVersion = gsyncGetCapsParams.extendedRevision; 481 pFrameLockEvo->caps = gsyncGetCapsParams.capFlags; 482 pFrameLockEvo->maxSyncSkew = gsyncGetCapsParams.maxSyncSkew; 483 pFrameLockEvo->syncSkewResolution = gsyncGetCapsParams.syncSkewResolution; 484 pFrameLockEvo->maxSyncInterval = gsyncGetCapsParams.maxSyncInterval; 485 pFrameLockEvo->videoModeReadOnly = !!(gsyncGetCapsParams.capFlags & 486 NV30F1_CTRL_GSYNC_GET_CAPS_CAP_FLAGS_ONLY_GET_VIDEO_MODE); 487 pFrameLockEvo->mulDivSupported = !!(gsyncGetCapsParams.capFlags & 488 NV30F1_CTRL_GSYNC_GET_CAPS_CAP_FLAGS_MULTIPLY_DIVIDE_SYNC); 489 pFrameLockEvo->maxMulDivValue = gsyncGetCapsParams.maxMulDivValue; 490 491 /* Determine if house sync is selectable on this frame lock device */ 492 if (!FrameLockUseHouseSyncGetSupport(pFrameLockEvo, 493 &pFrameLockEvo->houseSyncUseable)) { 494 pFrameLockEvo->houseSyncUseable = FALSE; 495 } 496 497 pFrameLockEvo->houseSyncModeValidValues = 498 (1 << NV_KMS_FRAMELOCK_ATTRIBUTE_HOUSE_SYNC_MODE_DISABLED); 499 500 if (pFrameLockEvo->houseSyncUseable) { 501 pFrameLockEvo->houseSyncModeValidValues |= 502 (1 << NV_KMS_FRAMELOCK_ATTRIBUTE_HOUSE_SYNC_MODE_INPUT); 503 } 504 505 if (HouseSyncOutputModeUsable(pFrameLockEvo)) { 506 pFrameLockEvo->houseSyncModeValidValues |= 507 (1 << NV_KMS_FRAMELOCK_ATTRIBUTE_HOUSE_SYNC_MODE_OUTPUT); 508 } 509 510 /* Add frame lock device to global list. */ 511 nvListAppend(&pFrameLockEvo->frameLockListEntry, &nvEvoGlobal.frameLockList); 512 513 return pFrameLockEvo; 514 515 fail: 516 517 FreeFrameLockEvo(pDevEvo, pFrameLockEvo); 518 return NULL; 519 } 520 521 522 static void BindFrameLockToDevEvo(NVFrameLockEvoPtr pFrameLockEvo, 523 NVDevEvoPtr pDevEvo) 524 { 525 NV30F1_CTRL_GET_GSYNC_GPU_TOPOLOGY_PARAMS gsyncTopologyParams = { }; 526 int i; 527 528 /* find out which gpus are attached to which connectors */ 529 530 if (nvRmApiControl(nvEvoGlobal.clientHandle, 531 pFrameLockEvo->device, 532 NV30F1_CTRL_CMD_GET_GSYNC_GPU_TOPOLOGY, 533 &gsyncTopologyParams, 534 sizeof(gsyncTopologyParams)) 535 != NVOS_STATUS_SUCCESS) { 536 return; 537 } 538 539 /* Bind corresponding GPUs to the Frame Lock device */ 540 for (i = 0; i < ARRAY_LEN(gsyncTopologyParams.gpus); i++) { 541 542 NvU32 connectorIndex; 543 const NvU32 gpuId = gsyncTopologyParams.gpus[i].gpuId; 544 545 if (gpuId == NV30F1_CTRL_GPU_INVALID_ID) { 546 continue; 547 } 548 549 if (!GpuIdInDevEvo(pDevEvo, gpuId)) { 550 continue; 551 } 552 553 /* 554 * Connector type of _NONE means we sync through a proxy GPU, 555 * which we do not support. 556 */ 557 if (gsyncTopologyParams.gpus[i].connector == 558 NV30F1_CTRL_GET_GSYNC_GPU_TOPOLOGY_NONE) { 559 continue; 560 } 561 /* 562 * gsyncTopologyParams.gpus[i].connector is an enumerated 563 * type; convert it to a 0-based index 564 */ 565 nvAssert(gsyncTopologyParams.gpus[i].connector < 566 (NV30F1_CTRL_GET_GSYNC_GPU_TOPOLOGY_ONE + 567 NV30F1_GSYNC_CONNECTOR_COUNT)); 568 connectorIndex = gsyncTopologyParams.gpus[i].connector - 569 NV30F1_CTRL_GET_GSYNC_GPU_TOPOLOGY_ONE; 570 571 BindGpuToFrameLock(pDevEvo, gpuId, pFrameLockEvo, connectorIndex); 572 } 573 } 574 575 static void UnBindFrameLockFromDevEvo(NVFrameLockEvoPtr pFrameLockEvo, 576 NVDevEvoPtr pDevEvo) 577 { 578 int i; 579 580 /* 581 * Loop through GPUs from highest to lowest, because 582 * UnbindGpuFromFrameLock() may remove gpuIds[i]. 583 */ 584 for (i = pFrameLockEvo->nGpuIds - 1; i >= 0; i--) { 585 const NvU32 gpuId = pFrameLockEvo->gpuIds[i]; 586 587 if (!GpuIdInDevEvo(pDevEvo, gpuId)) { 588 continue; 589 } 590 591 UnbindGpuFromFrameLock(pDevEvo, gpuId, pFrameLockEvo); 592 } 593 } 594 595 596 /*! 597 * Find all of the available framelock devices. 598 * 599 * Framelock devices can only be recognized by resman after an RM 600 * client has attached a GPU that the framelock device is connected 601 * to. So, subsequent calls to this function may find additional 602 * framelock devices. 603 * 604 * Allocate framelock objects for all the newly found framelock devices. 605 */ 606 void nvAllocFrameLocksEvo(NVDevEvoPtr pDevEvo) 607 { 608 NV0000_CTRL_GSYNC_GET_ATTACHED_IDS_PARAMS attachedGsyncParams = { }; 609 int i; 610 611 if (nvRmApiControl(nvEvoGlobal.clientHandle, 612 nvEvoGlobal.clientHandle, 613 NV0000_CTRL_CMD_GSYNC_GET_ATTACHED_IDS, 614 &attachedGsyncParams, sizeof(attachedGsyncParams)) 615 != NVOS_STATUS_SUCCESS) { 616 return; 617 } 618 619 for (i = 0; i < ARRAY_LEN(attachedGsyncParams.gsyncIds); i++) { 620 621 NVFrameLockEvoPtr pFrameLockEvo; 622 623 if (attachedGsyncParams.gsyncIds[i] == NV0000_CTRL_GSYNC_INVALID_ID) { 624 continue; 625 } 626 627 pFrameLockEvo = FindFrameLock(attachedGsyncParams.gsyncIds[i]); 628 629 if (pFrameLockEvo == NULL) { 630 pFrameLockEvo = AllocFrameLockEvo(pDevEvo, i, 631 attachedGsyncParams.gsyncIds[i]); 632 } 633 634 if (pFrameLockEvo == NULL) { 635 continue; 636 } 637 638 BindFrameLockToDevEvo(pFrameLockEvo, pDevEvo); 639 } 640 } 641 642 /*! 643 * Free any framelock devices connected to any GPU on this pDevEvo. 644 */ 645 646 void nvFreeFrameLocksEvo(NVDevEvoPtr pDevEvo) 647 { 648 NVFrameLockEvoPtr pFrameLockEvo, pFrameLockEvoTmp; 649 650 /* Destroy the pFrameLockEvos */ 651 nvListForEachEntry_safe(pFrameLockEvo, pFrameLockEvoTmp, 652 &nvEvoGlobal.frameLockList, frameLockListEntry) { 653 654 UnBindFrameLockFromDevEvo(pFrameLockEvo, pDevEvo); 655 656 if (pFrameLockEvo->nGpuIds == 0) { 657 FreeFrameLockEvo(pDevEvo, pFrameLockEvo); 658 } 659 } 660 } 661 662 /*! 663 * Determine if this framelock device supports user selection of house 664 * sync. assign val appropriately. Returns TRUE if the attribute was 665 * successfully queried. 666 */ 667 static NvBool FrameLockUseHouseSyncGetSupport(NVFrameLockEvoPtr pFrameLockEvo, 668 NvU32 *val) 669 { 670 NV30F1_CTRL_GSYNC_GET_CONTROL_PARAMS_PARAMS 671 gsyncGetControlParamsParams = { 0 }; 672 NvU32 ret; 673 674 if (!val) return FALSE; 675 676 gsyncGetControlParamsParams.which = 677 NV30F1_CTRL_GSYNC_GET_CONTROL_SYNC_USE_HOUSE; 678 679 ret = nvRmApiControl(nvEvoGlobal.clientHandle, 680 pFrameLockEvo->device, 681 NV30F1_CTRL_CMD_GSYNC_GET_CONTROL_PARAMS, 682 &gsyncGetControlParamsParams, 683 sizeof(gsyncGetControlParamsParams)); 684 685 /* If we can query Use House Sync, then it is available */ 686 *val = (ret == NVOS_STATUS_SUCCESS) ? TRUE : FALSE; 687 688 return *val; 689 } 690 691 692 /*! 693 * Return whether or not this framelock device supports house sync mode. 694 * 695 * House sync mode is currently only available on P2061 (Quadro Sync II). 696 */ 697 static NvBool HouseSyncOutputModeUsable(const NVFrameLockEvoRec *pFrameLockEvo) 698 { 699 return (pFrameLockEvo->houseSyncUseable && 700 (pFrameLockEvo->boardId == 701 NV30F1_CTRL_GSYNC_GET_CAPS_BOARD_ID_P2061)); 702 } 703 704 705 /*! 706 * Enable or disable house sync output mode in the framelock board. 707 */ 708 static NvBool FrameLockSetHouseSyncOutputMode(NVFrameLockEvoPtr pFrameLockEvo, 709 NvBool enable) 710 { 711 NV30F1_CTRL_GSYNC_HOUSE_SYNC_MODE_PARAMS 712 gsyncSetHouseSyncModeParams = { 0 }; 713 NvU32 ret; 714 NvU8 houseSyncMode = enable ? NV30F1_CTRL_GSYNC_HOUSE_SYNC_MODE_OUTPUT : 715 NV30F1_CTRL_GSYNC_HOUSE_SYNC_MODE_INPUT; 716 717 nvAssert(HouseSyncOutputModeUsable(pFrameLockEvo)); 718 719 gsyncSetHouseSyncModeParams.houseSyncMode = houseSyncMode; 720 721 ret = nvRmApiControl(nvEvoGlobal.clientHandle, 722 pFrameLockEvo->device, 723 NV30F1_CTRL_CMD_GSYNC_SET_HOUSE_SYNC_MODE, 724 &gsyncSetHouseSyncModeParams, 725 sizeof(gsyncSetHouseSyncModeParams)); 726 727 return (ret == NVOS_STATUS_SUCCESS); 728 } 729 730 731 /*! 732 * Set the framelock to use the house sync if val is TRUE, otherwise 733 * set the framelock to use external sync. Returns FALSE if the 734 * assignment failed. 735 */ 736 NvBool nvFrameLockSetUseHouseSyncEvo(NVFrameLockEvoPtr pFrameLockEvo, NvU32 val) 737 { 738 NV30F1_CTRL_GSYNC_SET_CONTROL_PARAMS_PARAMS 739 gsyncSetControlParamsParams = { 0 }; 740 NvU32 ret; 741 NvBool houseSyncOutputMode = FALSE; 742 743 gsyncSetControlParamsParams.which = 744 NV30F1_CTRL_GSYNC_SET_CONTROL_SYNC_USE_HOUSE; 745 746 gsyncSetControlParamsParams.useHouseSync = val; 747 748 ret = nvRmApiControl(nvEvoGlobal.clientHandle, 749 pFrameLockEvo->device, 750 NV30F1_CTRL_CMD_GSYNC_SET_CONTROL_PARAMS, 751 &gsyncSetControlParamsParams, 752 sizeof(gsyncSetControlParamsParams)); 753 754 if (ret != NVOS_STATUS_SUCCESS) return FALSE; 755 756 if (HouseSyncOutputModeUsable(pFrameLockEvo)) { 757 758 NvS64 houseSyncInputPresent; 759 NvBool allowHouseSyncOutput = FALSE; 760 761 if (nvFrameLockGetStatusEvo(pFrameLockEvo, 762 NV_KMS_FRAMELOCK_ATTRIBUTE_HOUSE_STATUS, 763 &houseSyncInputPresent)) { 764 if (houseSyncInputPresent == 0) { 765 allowHouseSyncOutput = TRUE; 766 } 767 } 768 769 if (!val && allowHouseSyncOutput && 770 (pFrameLockEvo->houseSyncMode == 771 NV_KMS_FRAMELOCK_ATTRIBUTE_HOUSE_SYNC_MODE_OUTPUT)) { 772 773 houseSyncOutputMode = TRUE; 774 } 775 776 if (!FrameLockSetHouseSyncOutputMode(pFrameLockEvo, houseSyncOutputMode)) { 777 return FALSE; 778 } 779 } 780 781 /* 782 * House sync polarity is required to be rising edge if house sync is not 783 * in use. 784 * 785 * In addition, house sync polarity has no effect when house sync output 786 * mode is in use. 787 */ 788 if (val && !houseSyncOutputMode) { 789 return FrameLockSetPolarity(pFrameLockEvo, pFrameLockEvo->polarity); 790 } else { 791 return FrameLockSetPolarity(pFrameLockEvo, 792 NV_KMS_FRAMELOCK_ATTRIBUTE_POLARITY_RISING_EDGE); 793 } 794 } 795 796 /*! 797 * Set the polarity according to val; val is interpreted as an 798 * NV_KMS_FRAMELOCK_ATTRIBUTE_POLARITY value. Returns FALSE if the 799 * assignment failed. 800 */ 801 static NvBool FrameLockSetPolarity( 802 NVFrameLockEvoPtr pFrameLockEvo, 803 enum NvKmsFrameLockAttributePolarityValue val) 804 { 805 NV30F1_CTRL_GSYNC_SET_CONTROL_PARAMS_PARAMS 806 gsyncSetControlParamsParams = { 0 }; 807 NvU32 ret; 808 NvU32 polarity; 809 810 gsyncSetControlParamsParams.which = 811 NV30F1_CTRL_GSYNC_SET_CONTROL_SYNC_POLARITY; 812 813 switch (val) { 814 case NV_KMS_FRAMELOCK_ATTRIBUTE_POLARITY_RISING_EDGE: 815 polarity = NV30F1_CTRL_GSYNC_SET_CONTROL_SYNC_POLARITY_RISING_EDGE; 816 break; 817 818 case NV_KMS_FRAMELOCK_ATTRIBUTE_POLARITY_FALLING_EDGE: 819 polarity = NV30F1_CTRL_GSYNC_SET_CONTROL_SYNC_POLARITY_FALLING_EDGE; 820 break; 821 822 case NV_KMS_FRAMELOCK_ATTRIBUTE_POLARITY_BOTH_EDGES: 823 polarity = NV30F1_CTRL_GSYNC_SET_CONTROL_SYNC_POLARITY_BOTH_EDGES; 824 break; 825 826 default: 827 return FALSE; 828 } 829 830 gsyncSetControlParamsParams.syncPolarity = polarity; 831 832 ret = nvRmApiControl(nvEvoGlobal.clientHandle, 833 pFrameLockEvo->device, 834 NV30F1_CTRL_CMD_GSYNC_SET_CONTROL_PARAMS, 835 &gsyncSetControlParamsParams, 836 sizeof(gsyncSetControlParamsParams)); 837 838 if (ret != NVOS_STATUS_SUCCESS) return FALSE; 839 840 return TRUE; 841 } 842 843 /*! 844 * Set the sync delay to the value given in val. Returns FALSE if the 845 * assignment failed. Assigns pFrameLockEvo->syncDelay upon success. 846 */ 847 static NvBool FrameLockSetSyncDelay(NVFrameLockEvoPtr pFrameLockEvo, NvS64 val) 848 { 849 NV30F1_CTRL_GSYNC_SET_CONTROL_PARAMS_PARAMS 850 gsyncSetControlParamsParams = { 0 }; 851 NvU32 ret; 852 853 if (val > pFrameLockEvo->maxSyncSkew) return FALSE; 854 855 gsyncSetControlParamsParams.which = 856 NV30F1_CTRL_GSYNC_SET_CONTROL_SYNC_SKEW; 857 858 gsyncSetControlParamsParams.syncSkew = val; 859 860 ret = nvRmApiControl(nvEvoGlobal.clientHandle, 861 pFrameLockEvo->device, 862 NV30F1_CTRL_CMD_GSYNC_SET_CONTROL_PARAMS, 863 &gsyncSetControlParamsParams, 864 sizeof(gsyncSetControlParamsParams)); 865 866 if (ret != NVOS_STATUS_SUCCESS) return FALSE; 867 868 pFrameLockEvo->syncDelay = val; 869 870 return TRUE; 871 } 872 873 /*! 874 * Set the sync multiply/divide value given in val. Returns FALSE if the 875 * assignment failed. Assigns pFrameLockEvo->mulDivValue upon success. 876 */ 877 static NvBool SetFrameLockMulDivVal(NVFrameLockEvoPtr pFrameLockEvo, NvS64 val) 878 { 879 NV30F1_CTRL_GSYNC_SET_CONTROL_PARAMS_PARAMS 880 gsyncSetControlParamsParams = { 0 }; 881 NvU32 ret; 882 883 if (!pFrameLockEvo->mulDivSupported || 884 (val > pFrameLockEvo->maxMulDivValue)) { 885 return FALSE; 886 } 887 888 gsyncSetControlParamsParams.which = 889 NV30F1_CTRL_GSYNC_SET_CONTROL_SYNC_MULTIPLY_DIVIDE; 890 891 gsyncSetControlParamsParams.syncMulDiv.multiplyDivideValue = val; 892 gsyncSetControlParamsParams.syncMulDiv.multiplyDivideMode = pFrameLockEvo->mulDivMode; 893 894 ret = nvRmApiControl(nvEvoGlobal.clientHandle, 895 pFrameLockEvo->device, 896 NV30F1_CTRL_CMD_GSYNC_SET_CONTROL_PARAMS, 897 &gsyncSetControlParamsParams, 898 sizeof(gsyncSetControlParamsParams)); 899 900 if (ret != NVOS_STATUS_SUCCESS) return FALSE; 901 902 pFrameLockEvo->mulDivValue = val; 903 904 return TRUE; 905 } 906 907 /*! 908 * Set the sync multiply/divide mode given in val. Returns FALSE if the 909 * assignment failed. Assigns pFrameLockEvo->mulDivMode upon success. 910 */ 911 static NvBool SetFrameLockMulDivMode(NVFrameLockEvoPtr pFrameLockEvo, NvS64 val) 912 { 913 NV30F1_CTRL_GSYNC_SET_CONTROL_PARAMS_PARAMS 914 gsyncSetControlParamsParams = { 0 }; 915 NvU32 ret; 916 917 if (!pFrameLockEvo->mulDivSupported || 918 ((val != NV_KMS_FRAMELOCK_ATTRIBUTE_MULTIPLY_DIVIDE_MODE_MULTIPLY) && 919 (val != NV_KMS_FRAMELOCK_ATTRIBUTE_MULTIPLY_DIVIDE_MODE_DIVIDE))) { 920 return FALSE; 921 } 922 923 gsyncSetControlParamsParams.which = 924 NV30F1_CTRL_GSYNC_SET_CONTROL_SYNC_MULTIPLY_DIVIDE; 925 926 gsyncSetControlParamsParams.syncMulDiv.multiplyDivideValue = pFrameLockEvo->mulDivValue; 927 gsyncSetControlParamsParams.syncMulDiv.multiplyDivideMode = val; 928 929 ret = nvRmApiControl(nvEvoGlobal.clientHandle, 930 pFrameLockEvo->device, 931 NV30F1_CTRL_CMD_GSYNC_SET_CONTROL_PARAMS, 932 &gsyncSetControlParamsParams, 933 sizeof(gsyncSetControlParamsParams)); 934 935 if (ret != NVOS_STATUS_SUCCESS) return FALSE; 936 937 pFrameLockEvo->mulDivMode = val; 938 939 return TRUE; 940 } 941 /*! 942 * Set the sync interval to the value given in val. Returns FALSE if 943 * the assignment failed. Assigns pFrameLockEvo->syncInterval upon 944 * success. 945 */ 946 static NvBool FrameLockSetSyncInterval(NVFrameLockEvoPtr pFrameLockEvo, 947 NvS64 val) 948 { 949 NV30F1_CTRL_GSYNC_SET_CONTROL_PARAMS_PARAMS 950 gsyncSetControlParamsParams = { 0 }; 951 NvU32 ret; 952 953 gsyncSetControlParamsParams.which = 954 NV30F1_CTRL_GSYNC_SET_CONTROL_NSYNC; 955 956 gsyncSetControlParamsParams.nSync = val; 957 958 ret = nvRmApiControl(nvEvoGlobal.clientHandle, 959 pFrameLockEvo->device, 960 NV30F1_CTRL_CMD_GSYNC_SET_CONTROL_PARAMS, 961 &gsyncSetControlParamsParams, 962 sizeof(gsyncSetControlParamsParams)); 963 964 if (ret != NVOS_STATUS_SUCCESS) return FALSE; 965 966 pFrameLockEvo->syncInterval = val; 967 968 return TRUE; 969 } 970 971 /*! 972 * Query the status of the values that are acquired through the 973 * GET_STATUS_SYNC command, and assign the value to val. Returns 974 * FALSE if the query failed or if attr is not one of the currently 975 * handled attributes. 976 */ 977 static NvBool FrameLockGetStatusSync(const NVDispEvoRec *pDispEvo, NvS64 *val, 978 enum NvKmsDispAttribute nvKmsAttribute) 979 { 980 NV30F1_CTRL_GSYNC_GET_STATUS_SYNC_PARAMS gsyncGetStatusSyncParams = { 0 }; 981 NVFrameLockEvoPtr pFrameLockEvo = pDispEvo->pFrameLockEvo; 982 983 gsyncGetStatusSyncParams.gpuId = nvGpuIdOfDispEvo(pDispEvo); 984 985 if (nvRmApiControl(nvEvoGlobal.clientHandle, 986 pFrameLockEvo->device, 987 NV30F1_CTRL_CMD_GSYNC_GET_STATUS_SYNC, 988 &gsyncGetStatusSyncParams, 989 sizeof(gsyncGetStatusSyncParams)) 990 != NVOS_STATUS_SUCCESS) { 991 return FALSE; 992 } 993 994 switch (nvKmsAttribute) 995 { 996 997 case NV_KMS_DISP_ATTRIBUTE_FRAMELOCK_STEREO_SYNC: 998 *val = (gsyncGetStatusSyncParams.bTiming && 999 gsyncGetStatusSyncParams.bStereoSync && 1000 gsyncGetStatusSyncParams.bSyncReady); 1001 break; 1002 1003 case NV_KMS_DISP_ATTRIBUTE_FRAMELOCK_TIMING: 1004 *val = gsyncGetStatusSyncParams.bTiming ? TRUE : FALSE; 1005 break; 1006 1007 default: 1008 return FALSE; 1009 } 1010 1011 return TRUE; 1012 } 1013 1014 /*! 1015 * Return the sync rate. 1016 */ 1017 static NvS64 FrameLockInterpretSyncRate(const NVFrameLockEvoRec *pFrameLockEvo, 1018 NvS64 val) 1019 { 1020 /* Only show decimal places if they are accurate. The queried 1021 value provides 4 decimal places */ 1022 if (pFrameLockEvo->caps & 1023 NV30F1_CTRL_GSYNC_GET_CAPS_CAP_FLAGS_FREQ_ACCURACY_2DPS) { 1024 // only two are valid 1025 val -= (val % 100); 1026 } else if (pFrameLockEvo->caps & 1027 NV30F1_CTRL_GSYNC_GET_CAPS_CAP_FLAGS_FREQ_ACCURACY_3DPS) { 1028 // only three are valid 1029 val -= (val % 10); 1030 } else if (pFrameLockEvo->caps & 1031 NV30F1_CTRL_GSYNC_GET_CAPS_CAP_FLAGS_FREQ_ACCURACY_4DPS) { 1032 // all four are valid, nothing to do 1033 } 1034 return val; 1035 } 1036 1037 /*! 1038 * Query the status of one of the values that are acquired through the 1039 * GET_STATUS command, and assign the value to val. Returns FALSE if 1040 * the query failed or if attr is not one of the currently handled 1041 * attributes. 1042 */ 1043 NvBool nvFrameLockGetStatusEvo(const NVFrameLockEvoRec *pFrameLockEvo, 1044 enum NvKmsFrameLockAttribute attribute, 1045 NvS64 *val) 1046 { 1047 NV30F1_CTRL_GSYNC_GET_STATUS_PARAMS gsyncGetStatusParams = { 0 }; 1048 1049 switch (attribute) { 1050 1051 case NV_KMS_FRAMELOCK_ATTRIBUTE_PORT0_STATUS: 1052 gsyncGetStatusParams.which = NV30F1_CTRL_GSYNC_GET_STATUS_PORT0_INPUT; 1053 break; 1054 1055 case NV_KMS_FRAMELOCK_ATTRIBUTE_PORT1_STATUS: 1056 gsyncGetStatusParams.which = NV30F1_CTRL_GSYNC_GET_STATUS_PORT1_INPUT; 1057 break; 1058 1059 case NV_KMS_FRAMELOCK_ATTRIBUTE_HOUSE_STATUS: 1060 gsyncGetStatusParams.which = NV30F1_CTRL_GSYNC_GET_STATUS_HOUSE_SYNC; 1061 break; 1062 1063 case NV_KMS_FRAMELOCK_ATTRIBUTE_INCOMING_HOUSE_SYNC_RATE: 1064 gsyncGetStatusParams.which = 1065 NV30F1_CTRL_GSYNC_GET_STATUS_HOUSE_SYNC_INCOMING; 1066 break; 1067 1068 case NV_KMS_FRAMELOCK_ATTRIBUTE_SYNC_READY: 1069 gsyncGetStatusParams.which = NV30F1_CTRL_GSYNC_GET_STATUS_SYNC_READY; 1070 break; 1071 1072 case NV_KMS_FRAMELOCK_ATTRIBUTE_ETHERNET_DETECTED: 1073 gsyncGetStatusParams.which = 1074 NV30F1_CTRL_GSYNC_GET_STATUS_PORT0_ETHERNET | 1075 NV30F1_CTRL_GSYNC_GET_STATUS_PORT1_ETHERNET; 1076 break; 1077 1078 case NV_KMS_FRAMELOCK_ATTRIBUTE_SYNC_RATE: 1079 case NV_KMS_FRAMELOCK_ATTRIBUTE_SYNC_RATE_4: 1080 gsyncGetStatusParams.which = NV30F1_CTRL_GSYNC_GET_STATUS_REFRESH; 1081 break; 1082 1083 default: 1084 return FALSE; 1085 } 1086 1087 if (nvRmApiControl(nvEvoGlobal.clientHandle, 1088 pFrameLockEvo->device, 1089 NV30F1_CTRL_CMD_GSYNC_GET_STATUS, 1090 &gsyncGetStatusParams, 1091 sizeof(gsyncGetStatusParams)) 1092 != NVOS_STATUS_SUCCESS) { 1093 return FALSE; 1094 } 1095 1096 switch (attribute) { 1097 1098 case NV_KMS_FRAMELOCK_ATTRIBUTE_PORT0_STATUS: 1099 *val = gsyncGetStatusParams.bPort0Input ? 1100 NV_KMS_FRAMELOCK_ATTRIBUTE_PORT_STATUS_INPUT : 1101 NV_KMS_FRAMELOCK_ATTRIBUTE_PORT_STATUS_OUTPUT; 1102 break; 1103 1104 case NV_KMS_FRAMELOCK_ATTRIBUTE_PORT1_STATUS: 1105 *val = gsyncGetStatusParams.bPort1Input ? 1106 NV_KMS_FRAMELOCK_ATTRIBUTE_PORT_STATUS_INPUT : 1107 NV_KMS_FRAMELOCK_ATTRIBUTE_PORT_STATUS_OUTPUT; 1108 break; 1109 1110 case NV_KMS_FRAMELOCK_ATTRIBUTE_HOUSE_STATUS: 1111 *val = gsyncGetStatusParams.bHouseSync; 1112 break; 1113 1114 case NV_KMS_FRAMELOCK_ATTRIBUTE_SYNC_READY: 1115 *val = gsyncGetStatusParams.bSyncReady; 1116 break; 1117 1118 case NV_KMS_FRAMELOCK_ATTRIBUTE_ETHERNET_DETECTED: 1119 *val = 0x0; 1120 if (gsyncGetStatusParams.bPort0Ethernet) 1121 *val |= NV_KMS_FRAMELOCK_ATTRIBUTE_ETHERNET_DETECTED_PORT0; 1122 if (gsyncGetStatusParams.bPort1Ethernet) 1123 *val |= NV_KMS_FRAMELOCK_ATTRIBUTE_ETHERNET_DETECTED_PORT1; 1124 break; 1125 1126 case NV_KMS_FRAMELOCK_ATTRIBUTE_INCOMING_HOUSE_SYNC_RATE: 1127 *val = 1128 FrameLockInterpretSyncRate(pFrameLockEvo, 1129 gsyncGetStatusParams.houseSyncIncoming); 1130 break; 1131 1132 case NV_KMS_FRAMELOCK_ATTRIBUTE_SYNC_RATE: 1133 case NV_KMS_FRAMELOCK_ATTRIBUTE_SYNC_RATE_4: 1134 *val = FrameLockInterpretSyncRate(pFrameLockEvo, 1135 gsyncGetStatusParams.refresh); 1136 if (attribute == NV_KMS_FRAMELOCK_ATTRIBUTE_SYNC_RATE) { 1137 /* _STATUS_REFRESH is in Hz/10000, _SYNC_RATE is Hz/1000 */ 1138 *val /= 10; 1139 } 1140 break; 1141 1142 default: 1143 return FALSE; 1144 } 1145 1146 return TRUE; 1147 } 1148 1149 /*! 1150 * [en|dis]able syncing of the GPU to the FrameLock board for the 1151 * display mask associated with that gpu. val controls whether we are 1152 * enabling or disabling. 1153 */ 1154 static NvBool FrameLockSetEnable(NVDispEvoPtr pDispEvo, NvS64 val) 1155 { 1156 if (val) { 1157 1158 /* XXX NVKMS TODO: address the following: 1159 1160 In Xinerama a single app has a channel on each gpu. Before 1161 framelock is enabled the first time per X server, vblanks 1162 are not synchronized, so if a swap groupped app is started 1163 before framelock is enabled the channels get unstalled at 1164 different times, and it's likely that one display will be 1165 armed while the other is not. When framelock is enabled in 1166 this state, we'll deadlock because suddenly the armed display 1167 is waiting on the unarmed display to unstall, and the unarmed 1168 display cannot arm. Prevent this by idling all channels */ 1169 1170 return nvEnableFrameLockEvo(pDispEvo); 1171 } else { 1172 return nvDisableFrameLockEvo(pDispEvo); 1173 } 1174 } 1175 1176 static NvBool FrameLockSetWatchdog(NVFrameLockEvoPtr pFrameLockEvo, NvU32 val) 1177 { 1178 NV30F1_CTRL_GSYNC_SET_CONTROL_WATCHDOG_PARAMS 1179 gsyncSetControlWatchdogParams = { 0 }; 1180 NvU32 ret; 1181 1182 gsyncSetControlWatchdogParams.enable = val; 1183 1184 ret = nvRmApiControl(nvEvoGlobal.clientHandle, 1185 pFrameLockEvo->device, 1186 NV30F1_CTRL_CMD_GSYNC_SET_CONTROL_WATCHDOG, 1187 &gsyncSetControlWatchdogParams, 1188 sizeof(gsyncSetControlWatchdogParams)); 1189 1190 if (ret != NVOS_STATUS_SUCCESS) return FALSE; 1191 1192 return TRUE; 1193 } 1194 1195 1196 /*! 1197 * For the given display, determine if it can be set as a frame lock 1198 * server 1199 */ 1200 static NvBool FrameLockDpyCanBeServer(const NVDpyEvoRec *pDpyEvo) 1201 { 1202 NV30F1_CTRL_GSYNC_GET_CONTROL_SYNC_PARAMS gsyncGetControlSyncParams = { 0 }; 1203 NVDispEvoPtr pDispEvo = pDpyEvo->pDispEvo; 1204 NVFrameLockEvoPtr pFrameLockEvo = pDispEvo->pFrameLockEvo; 1205 const NvU32 head = nvGetPrimaryHwHead(pDispEvo, pDpyEvo->apiHead); 1206 const NVDispHeadStateEvoRec *pHeadState; 1207 NvU32 ret; 1208 1209 nvAssert(head != NV_INVALID_HEAD); 1210 nvAssert(pDispEvo); 1211 nvAssert(pDispEvo->pFrameLockEvo); 1212 1213 pHeadState = &pDispEvo->headState[head]; 1214 nvAssert(pHeadState->activeRmId); 1215 1216 /* If already a server, assume it can be a server. */ 1217 if (nvDpyIdsAreEqual(pDispEvo->framelock.server, pDpyEvo->id)) { 1218 return TRUE; 1219 } 1220 1221 gsyncGetControlSyncParams.gpuId = nvGpuIdOfDispEvo(pDispEvo); 1222 gsyncGetControlSyncParams.displays = pHeadState->activeRmId; 1223 1224 ret = nvRmApiControl(nvEvoGlobal.clientHandle, 1225 pFrameLockEvo->device, 1226 NV30F1_CTRL_CMD_GSYNC_GET_CONTROL_SYNC, 1227 &gsyncGetControlSyncParams, 1228 sizeof(gsyncGetControlSyncParams)); 1229 1230 if (ret != NVOS_STATUS_SUCCESS) { 1231 return FALSE; 1232 } 1233 1234 if (gsyncGetControlSyncParams.master && 1235 nvFrameLockServerPossibleEvo(pDpyEvo)) { 1236 return TRUE; 1237 } 1238 1239 return FALSE; 1240 } 1241 1242 1243 /*! 1244 * For the given display, determine if it can be set as a frame lock 1245 * client. 1246 */ 1247 static NvBool FrameLockDpyCanBeClient(const NVDpyEvoRec *pDpyEvo) 1248 { 1249 NVDispEvoPtr pDispEvo; 1250 1251 nvAssert(pDpyEvo->pDispEvo); 1252 nvAssert(pDpyEvo->pDispEvo->pFrameLockEvo); 1253 nvAssert(nvDpyEvoIsActive(pDpyEvo)); 1254 1255 pDispEvo = pDpyEvo->pDispEvo; 1256 1257 /* If already a client, assume it can be a client. */ 1258 if (nvDpyIdIsInDpyIdList(pDpyEvo->id, pDispEvo->framelock.clients)) { 1259 return TRUE; 1260 } 1261 1262 /* Otherwise, see if we can make it a client. */ 1263 return nvFrameLockClientPossibleEvo(pDpyEvo); 1264 } 1265 1266 1267 /*! 1268 * [en|dis]able test mode (based on the value of val). Returns FALSE 1269 * if changing the test mode failed. Assigns pFrameLockEvo->testMode 1270 * upon success. 1271 */ 1272 static NvBool FrameLockSetTestMode(NVFrameLockEvoPtr pFrameLockEvo, NvS64 val) 1273 { 1274 NV30F1_CTRL_GSYNC_SET_CONTROL_TESTING_PARAMS 1275 gsyncSetControlTestingParams = { 0 }; 1276 NvU32 ret; 1277 1278 gsyncSetControlTestingParams.bEmitTestSignal = (val == TRUE); 1279 1280 ret = nvRmApiControl(nvEvoGlobal.clientHandle, 1281 pFrameLockEvo->device, 1282 NV30F1_CTRL_CMD_GSYNC_SET_CONTROL_TESTING, 1283 &gsyncSetControlTestingParams, 1284 sizeof(gsyncSetControlTestingParams)); 1285 1286 if (ret != NVOS_STATUS_SUCCESS) return FALSE; 1287 1288 pFrameLockEvo->testMode = val; 1289 1290 return TRUE; 1291 } 1292 1293 1294 /*! 1295 * Set the video mode according to val; returns FALSE if the 1296 * assignment failed. Assigns pFrameLockEvo->videoMode upon success. 1297 */ 1298 static NvBool FrameLockSetVideoMode(NVFrameLockEvoPtr pFrameLockEvo, NvS64 val) 1299 { 1300 NV30F1_CTRL_GSYNC_SET_CONTROL_PARAMS_PARAMS 1301 gsyncSetControlParamsParams = { 0 }; 1302 NvU32 ret; 1303 1304 gsyncSetControlParamsParams.which = 1305 NV30F1_CTRL_GSYNC_SET_CONTROL_VIDEO_MODE; 1306 1307 switch (val) { 1308 1309 case NV_KMS_FRAMELOCK_ATTRIBUTE_VIDEO_MODE_COMPOSITE_AUTO: 1310 gsyncSetControlParamsParams.syncVideoMode = 1311 NV30F1_CTRL_GSYNC_SET_CONTROL_VIDEO_MODE_NONE; 1312 break; 1313 1314 case NV_KMS_FRAMELOCK_ATTRIBUTE_VIDEO_MODE_TTL: 1315 gsyncSetControlParamsParams.syncVideoMode = 1316 NV30F1_CTRL_GSYNC_SET_CONTROL_VIDEO_MODE_TTL; 1317 break; 1318 1319 case NV_KMS_FRAMELOCK_ATTRIBUTE_VIDEO_MODE_COMPOSITE_BI_LEVEL: 1320 gsyncSetControlParamsParams.syncVideoMode = 1321 NV30F1_CTRL_GSYNC_SET_CONTROL_VIDEO_MODE_NTSCPALSECAM; 1322 break; 1323 1324 case NV_KMS_FRAMELOCK_ATTRIBUTE_VIDEO_MODE_COMPOSITE_TRI_LEVEL: 1325 gsyncSetControlParamsParams.syncVideoMode = 1326 NV30F1_CTRL_GSYNC_SET_CONTROL_VIDEO_MODE_HDTV; 1327 break; 1328 1329 default: 1330 return FALSE; 1331 } 1332 1333 ret = nvRmApiControl(nvEvoGlobal.clientHandle, 1334 pFrameLockEvo->device, 1335 NV30F1_CTRL_CMD_GSYNC_SET_CONTROL_PARAMS, 1336 &gsyncSetControlParamsParams, 1337 sizeof(gsyncSetControlParamsParams)); 1338 1339 if (ret != NVOS_STATUS_SUCCESS) return FALSE; 1340 1341 pFrameLockEvo->videoMode = val; 1342 1343 return TRUE; 1344 } 1345 1346 1347 /*! 1348 * Enable or disable the swap ready connection through the gsync 1349 * connector. This should be called when we bind the swap barrier. 1350 */ 1351 static NvBool SetSwapBarrier(NVDispEvoPtr pDispEvo, NvS64 val) 1352 { 1353 NV30F1_CTRL_GSYNC_SET_CONTROL_SWAP_BARRIER_PARAMS 1354 gsyncSetSwapBarrierParams = { 0 }; 1355 NVFrameLockEvoPtr pFrameLockEvo = pDispEvo->pFrameLockEvo; 1356 NvU32 ret; 1357 NvBool enable = !!val; 1358 1359 if (!pFrameLockEvo) return FALSE; 1360 1361 nvSetSwapBarrierNotifyEvo(pDispEvo, enable, TRUE /* isPre */); 1362 1363 gsyncSetSwapBarrierParams.gpuId = nvGpuIdOfDispEvo(pDispEvo); 1364 gsyncSetSwapBarrierParams.enable = enable; 1365 1366 ret = nvRmApiControl(nvEvoGlobal.clientHandle, 1367 pFrameLockEvo->device, 1368 NV30F1_CTRL_CMD_GSYNC_SET_CONTROL_SWAP_BARRIER, 1369 &gsyncSetSwapBarrierParams, 1370 sizeof(gsyncSetSwapBarrierParams)); 1371 1372 nvSetSwapBarrierNotifyEvo(pDispEvo, enable, FALSE /* isPre */); 1373 1374 return (ret == NVOS_STATUS_SUCCESS); 1375 } 1376 1377 1378 /*! 1379 * Flush all of our known framelock SW state out to the HW, to make 1380 * sure both are in sync. This should be called any time we get the 1381 * HW back from outside control (e.g., starting X or coming back from 1382 * a VT switch). 1383 */ 1384 static NvBool ResetHardwareOneDisp(NVDispEvoPtr pDispEvo, NvS64 value) 1385 { 1386 NVFrameLockEvoPtr pFrameLockEvo = pDispEvo->pFrameLockEvo; 1387 NvU32 activeHeadsMask; 1388 NvBool ret = TRUE; 1389 1390 if (!pDispEvo->pFrameLockEvo || !value) { 1391 /* Nothing to do */ 1392 return TRUE; 1393 } 1394 1395 /* We should never get here when framelock is enabled */ 1396 if (pDispEvo->framelock.syncEnabled) { 1397 nvAssert(!"Attempted to reset framelock HW while framelock is enabled"); 1398 return FALSE; 1399 } 1400 1401 /* (Re-)set the HW state to match the SW state */ 1402 if (!nvFrameLockSetUseHouseSyncEvo(pFrameLockEvo, 1403 pFrameLockEvo->houseSyncArmed)) { 1404 ret = FALSE; 1405 } 1406 if (!FrameLockSetSyncDelay(pFrameLockEvo, pFrameLockEvo->syncDelay)) { 1407 ret = FALSE; 1408 } 1409 if (!FrameLockSetSyncInterval(pFrameLockEvo, pFrameLockEvo->syncInterval)) { 1410 ret = FALSE; 1411 } 1412 if (!FrameLockSetVideoMode(pFrameLockEvo, pFrameLockEvo->videoMode)) { 1413 ret = FALSE; 1414 } 1415 if (!FrameLockSetTestMode(pFrameLockEvo, pFrameLockEvo->testMode)) { 1416 ret = FALSE; 1417 } 1418 if (!SetFrameLockMulDivVal(pFrameLockEvo, pFrameLockEvo->mulDivValue)) { 1419 ret = FALSE; 1420 } 1421 if (!SetFrameLockMulDivMode(pFrameLockEvo, pFrameLockEvo->mulDivMode)) { 1422 ret = FALSE; 1423 } 1424 1425 /* Since (we think) sync is disabled, these should always be disabled */ 1426 if (!FrameLockSetWatchdog(pFrameLockEvo, FALSE)) { 1427 ret = FALSE; 1428 } 1429 if (!SetSwapBarrier(pDispEvo, FALSE)) { 1430 ret = FALSE; 1431 } 1432 1433 /* Disable both server and client lock for all heads */ 1434 activeHeadsMask = nvGetActiveHeadMask(pDispEvo); 1435 1436 if (!nvFramelockSetControlUnsyncEvo(pDispEvo, activeHeadsMask, TRUE)) { 1437 ret = FALSE; 1438 } 1439 if (!nvFramelockSetControlUnsyncEvo(pDispEvo, activeHeadsMask, FALSE)) { 1440 ret = FALSE; 1441 } 1442 1443 return ret; 1444 } 1445 1446 1447 /*! 1448 * Returns the allowable configurations for the given display device. 1449 * The device must be enabled to advertise server/client 1450 * configuration. 1451 */ 1452 static unsigned int FrameLockGetValidDpyConfig(const NVDpyEvoRec *pDpyEvo) 1453 { 1454 NVDispEvoPtr pDispEvo; 1455 unsigned int valid = 1456 (1 << (NV_KMS_DPY_ATTRIBUTE_FRAMELOCK_DISPLAY_CONFIG_DISABLED)); 1457 1458 if (!pDpyEvo || !nvDpyEvoIsActive(pDpyEvo)) { 1459 goto done; 1460 } 1461 1462 pDispEvo = pDpyEvo->pDispEvo; 1463 1464 if (!pDispEvo || !pDispEvo->pFrameLockEvo) { 1465 goto done; 1466 } 1467 1468 /* Check if display can be a server */ 1469 1470 if (FrameLockDpyCanBeServer(pDpyEvo)) { 1471 valid |= (1 << (NV_KMS_DPY_ATTRIBUTE_FRAMELOCK_DISPLAY_CONFIG_SERVER)); 1472 } 1473 1474 /* Check if display can be a client */ 1475 1476 if (FrameLockDpyCanBeClient(pDpyEvo)) { 1477 valid |= (1 << (NV_KMS_DPY_ATTRIBUTE_FRAMELOCK_DISPLAY_CONFIG_CLIENT)); 1478 } 1479 1480 done: 1481 1482 return valid; 1483 } 1484 1485 static NvBool GetFrameLock(NVDispEvoPtr pDispEvo, NvS64 *val) 1486 { 1487 *val = (pDispEvo->pFrameLockEvo) ? 1 : 0; 1488 return TRUE; 1489 } 1490 1491 static NvBool SetFrameLockPolarity(NVFrameLockEvoPtr pFrameLockEvo, NvS64 val) 1492 { 1493 if ((val != NV_KMS_FRAMELOCK_ATTRIBUTE_POLARITY_RISING_EDGE) && 1494 (val != NV_KMS_FRAMELOCK_ATTRIBUTE_POLARITY_FALLING_EDGE) && 1495 (val != NV_KMS_FRAMELOCK_ATTRIBUTE_POLARITY_BOTH_EDGES)) { 1496 return FALSE; 1497 } 1498 1499 pFrameLockEvo->polarity = val; 1500 1501 return TRUE; 1502 } 1503 1504 static NvBool GetFrameLockPolarity(const NVFrameLockEvoRec *pFrameLockEvo, 1505 enum NvKmsFrameLockAttribute attribute, 1506 NvS64 *val) 1507 { 1508 *val = pFrameLockEvo->polarity; 1509 1510 return TRUE; 1511 } 1512 1513 static NvBool GetFrameLockSyncDelay(const NVFrameLockEvoRec *pFrameLockEvo, 1514 enum NvKmsFrameLockAttribute attribute, 1515 NvS64 *val) 1516 { 1517 *val = pFrameLockEvo->syncDelay; 1518 1519 return TRUE; 1520 } 1521 1522 static NvBool GetFrameLockSyncDelayValidValues( 1523 const NVFrameLockEvoRec *pFrameLockEvo, 1524 struct NvKmsAttributeValidValuesCommonReply *pValidValues) 1525 { 1526 nvAssert(pValidValues->type == NV_KMS_ATTRIBUTE_TYPE_RANGE); 1527 1528 pValidValues->u.range.min = 0; 1529 pValidValues->u.range.max = pFrameLockEvo->maxSyncSkew; 1530 1531 return TRUE; 1532 } 1533 1534 static NvBool GetFrameLockMulDivVal(const NVFrameLockEvoRec *pFrameLockEvo, 1535 enum NvKmsFrameLockAttribute attribute, 1536 NvS64 *val) 1537 { 1538 if (!pFrameLockEvo->mulDivSupported) { 1539 return FALSE; 1540 } 1541 1542 *val = pFrameLockEvo->mulDivValue; 1543 1544 return TRUE; 1545 } 1546 1547 static NvBool GetFrameLockMulDivValValidValues( 1548 const NVFrameLockEvoRec *pFrameLockEvo, 1549 struct NvKmsAttributeValidValuesCommonReply *pValidValues) 1550 { 1551 nvAssert(pValidValues->type == NV_KMS_ATTRIBUTE_TYPE_RANGE); 1552 1553 if (!pFrameLockEvo->mulDivSupported) { 1554 return FALSE; 1555 } 1556 1557 pValidValues->u.range.min = 1; 1558 pValidValues->u.range.max = pFrameLockEvo->maxMulDivValue; 1559 1560 return TRUE; 1561 } 1562 1563 static NvBool GetFrameLockMulDivModeValidValues( 1564 const NVFrameLockEvoRec *pFrameLockEvo, 1565 struct NvKmsAttributeValidValuesCommonReply *pValidValues) 1566 { 1567 if (!pFrameLockEvo->mulDivSupported) { 1568 return FALSE; 1569 } 1570 1571 nvAssert(pValidValues->type == NV_KMS_ATTRIBUTE_TYPE_INTEGER); 1572 1573 return TRUE; 1574 } 1575 1576 static NvBool GetFrameLockMulDivMode(const NVFrameLockEvoRec *pFrameLockEvo, 1577 enum NvKmsFrameLockAttribute attribute, 1578 NvS64 *val) 1579 { 1580 if (!pFrameLockEvo->mulDivSupported) { 1581 return FALSE; 1582 } 1583 1584 *val = pFrameLockEvo->mulDivMode; 1585 1586 return TRUE; 1587 } 1588 1589 static NvBool SetHouseSyncMode(NVFrameLockEvoPtr pFrameLockEvo, NvS64 val) 1590 { 1591 if ((val < 0) || (val > 31)) { 1592 return FALSE; 1593 } 1594 1595 if ((pFrameLockEvo->houseSyncModeValidValues & NVBIT(val)) == 0) { 1596 return FALSE; 1597 } 1598 1599 pFrameLockEvo->houseSyncMode = val; 1600 1601 return TRUE; 1602 } 1603 1604 static NvBool GetHouseSyncMode(const NVFrameLockEvoRec *pFrameLockEvo, 1605 enum NvKmsFrameLockAttribute attribute, 1606 NvS64 *val) 1607 { 1608 if (!pFrameLockEvo->houseSyncUseable) return FALSE; 1609 1610 *val = pFrameLockEvo->houseSyncMode; 1611 1612 return TRUE; 1613 } 1614 1615 static NvBool GetHouseSyncModeValidValues( 1616 const NVFrameLockEvoRec *pFrameLockEvo, 1617 struct NvKmsAttributeValidValuesCommonReply *pValidValues) 1618 { 1619 if (!pFrameLockEvo->houseSyncUseable) { 1620 return FALSE; 1621 } 1622 1623 nvAssert(pValidValues->type == NV_KMS_ATTRIBUTE_TYPE_INTBITS); 1624 1625 pValidValues->u.bits.ints = pFrameLockEvo->houseSyncModeValidValues; 1626 1627 return TRUE; 1628 } 1629 1630 static NvBool GetFrameLockSyncInterval(const NVFrameLockEvoRec *pFrameLockEvo, 1631 enum NvKmsFrameLockAttribute attribute, 1632 NvS64 *val) 1633 { 1634 *val = pFrameLockEvo->syncInterval; 1635 1636 return TRUE; 1637 } 1638 1639 static NvBool GetFrameLockSyncIntervalValidValues( 1640 const NVFrameLockEvoRec *pFrameLockEvo, 1641 struct NvKmsAttributeValidValuesCommonReply *pValidValues) 1642 { 1643 nvAssert(pValidValues->type == NV_KMS_ATTRIBUTE_TYPE_RANGE); 1644 1645 pValidValues->u.range.min = 0; 1646 pValidValues->u.range.max = pFrameLockEvo->maxSyncInterval; 1647 1648 return TRUE; 1649 } 1650 1651 static NvBool SetFrameLockSync(NVDispEvoRec *pDispEvo, NvS64 val) 1652 { 1653 NvBool a, b; 1654 1655 if (!pDispEvo->pFrameLockEvo) return FALSE; 1656 1657 /* If we are already enabled or already disabled, we're done. */ 1658 if (val == pDispEvo->framelock.syncEnabled) return TRUE; 1659 1660 /* Something must be set to enable/disable */ 1661 if (nvDpyIdIsInvalid(pDispEvo->framelock.server) && 1662 nvDpyIdListIsEmpty(pDispEvo->framelock.clients)) return FALSE; 1663 1664 /* If we're disabling and test mode is currently enabled, disable it */ 1665 if (!val && 1666 !nvDpyIdIsInvalid(pDispEvo->framelock.server) && 1667 pDispEvo->pFrameLockEvo->testMode) { 1668 1669 FrameLockSetTestMode(pDispEvo->pFrameLockEvo, FALSE); 1670 } 1671 1672 /* 1673 * It is important to set syncEnabled before calling FrameLockSetEnable. 1674 * FrameLockSetEnable may call into GLS which may call back into the 1675 * driver to query if framelock is enabled, which checks this field. 1676 */ 1677 pDispEvo->framelock.syncEnabled = val; 1678 1679 a = FrameLockSetEnable(pDispEvo, val); 1680 b = FrameLockSetWatchdog(pDispEvo->pFrameLockEvo, val); 1681 1682 /* 1683 * Since RM doesn't send a SYNC_READY event on sync disable through nvctrl, 1684 * send it here. 1685 */ 1686 if (!val && a && b) { 1687 nvSendFrameLockAttributeChangedEventEvo( 1688 pDispEvo->pFrameLockEvo, 1689 NV_KMS_FRAMELOCK_ATTRIBUTE_SYNC_READY, 1690 FALSE); 1691 pDispEvo->pFrameLockEvo->syncReadyLast = val; 1692 } 1693 1694 return (a && b); 1695 } 1696 1697 static NvBool GetFrameLockSync(NVDispEvoPtr pDispEvo, NvS64 *val) 1698 { 1699 if (!pDispEvo->pFrameLockEvo) return FALSE; 1700 1701 /* return the cached state */ 1702 1703 *val = ((pDispEvo->framelock.currentServerHead != NV_INVALID_HEAD) || 1704 (pDispEvo->framelock.currentClientHeadsMask != 0x0)); 1705 1706 return TRUE; 1707 } 1708 1709 static NvBool GetFrameLockSyncReady(const NVFrameLockEvoRec *pFrameLockEvo, 1710 enum NvKmsFrameLockAttribute attribute, 1711 NvS64 *val) 1712 { 1713 /* return the cached state */ 1714 1715 *val = pFrameLockEvo->syncReadyLast; 1716 1717 return TRUE; 1718 } 1719 1720 static NvBool GetFrameLockStereoSync(NVDispEvoPtr pDispEvo, NvS64 *val) 1721 { 1722 if (!pDispEvo->pFrameLockEvo) return FALSE; 1723 1724 return FrameLockGetStatusSync(pDispEvo, val, 1725 NV_KMS_DISP_ATTRIBUTE_FRAMELOCK_STEREO_SYNC); 1726 } 1727 1728 static NvBool GetFrameLockTiming(NVDispEvoPtr pDispEvo, NvS64 *val) 1729 { 1730 if (!pDispEvo->pFrameLockEvo) return FALSE; 1731 1732 return FrameLockGetStatusSync(pDispEvo, val, 1733 NV_KMS_DISP_ATTRIBUTE_FRAMELOCK_TIMING); 1734 } 1735 1736 static NvBool SetFrameLockTestSignal(NVDispEvoRec *pDispEvo, NvS64 val) 1737 { 1738 if (!pDispEvo->pFrameLockEvo) return FALSE; 1739 1740 /* The test signal can only be emitted if the GPU is the server 1741 * and framelock is enabled. 1742 */ 1743 1744 if (!nvDpyIdIsInvalid(pDispEvo->framelock.server) && 1745 pDispEvo->framelock.syncEnabled) { 1746 return FrameLockSetTestMode(pDispEvo->pFrameLockEvo, val); 1747 } 1748 1749 return FALSE; 1750 } 1751 1752 static NvBool GetFrameLockTestSignal(NVDispEvoPtr pDispEvo, NvS64 *val) 1753 { 1754 if (!pDispEvo->pFrameLockEvo || 1755 nvDpyIdIsInvalid(pDispEvo->framelock.server)) { 1756 return FALSE; 1757 } 1758 1759 *val = pDispEvo->pFrameLockEvo->testMode; 1760 1761 return TRUE; 1762 } 1763 1764 static NvBool SetFrameLockVideoMode(NVFrameLockEvoPtr pFrameLockEvo, NvS64 val) 1765 { 1766 if (pFrameLockEvo->videoModeReadOnly) { 1767 return FALSE; 1768 } 1769 1770 return FrameLockSetVideoMode(pFrameLockEvo, val); 1771 } 1772 1773 static NvBool GetFrameLockVideoMode(const NVFrameLockEvoRec *pFrameLockEvo, 1774 enum NvKmsFrameLockAttribute attribute, 1775 NvS64 *val) 1776 { 1777 *val = pFrameLockEvo->videoMode; 1778 1779 return TRUE; 1780 } 1781 1782 static NvBool GetFrameLockVideoModeValidValues( 1783 const NVFrameLockEvoRec *pFrameLockEvo, 1784 struct NvKmsAttributeValidValuesCommonReply *pValidValues) 1785 { 1786 nvAssert(pValidValues->type == NV_KMS_ATTRIBUTE_TYPE_RANGE); 1787 1788 pValidValues->u.range.min = 1789 NV_KMS_FRAMELOCK_ATTRIBUTE_VIDEO_MODE_COMPOSITE_AUTO; 1790 pValidValues->u.range.max = 1791 NV_KMS_FRAMELOCK_ATTRIBUTE_VIDEO_MODE_COMPOSITE_TRI_LEVEL; 1792 1793 if (pFrameLockEvo->videoModeReadOnly) { 1794 pValidValues->writable = FALSE; 1795 } 1796 1797 return TRUE; 1798 } 1799 1800 static NvBool GetFrameLockFpgaRevision(const NVFrameLockEvoRec *pFrameLockEvo, 1801 enum NvKmsFrameLockAttribute attribute, 1802 NvS64 *val) 1803 { 1804 *val = pFrameLockEvo->fpgaIdAndRevision; 1805 1806 return TRUE; 1807 } 1808 1809 static NvBool GetFrameLockFirmwareMajorVersion( 1810 const NVFrameLockEvoRec *pFrameLockEvo, 1811 enum NvKmsFrameLockAttribute attribute, 1812 NvS64 *val) 1813 { 1814 *val = pFrameLockEvo->firmwareMajorVersion; 1815 1816 return TRUE; 1817 } 1818 1819 static NvBool GetFrameLockFirmwareMinorVersion( 1820 const NVFrameLockEvoRec *pFrameLockEvo, 1821 enum NvKmsFrameLockAttribute attribute, 1822 NvS64 *val) 1823 { 1824 *val = pFrameLockEvo->firmwareMinorVersion; 1825 1826 return TRUE; 1827 } 1828 1829 static NvBool GetFrameLockBoardId(const NVFrameLockEvoRec *pFrameLockEvo, 1830 enum NvKmsFrameLockAttribute attribute, 1831 NvS64 *val) 1832 { 1833 *val = pFrameLockEvo->boardId; 1834 1835 return TRUE; 1836 } 1837 1838 static NvBool GetFrameLockFpgaRevisionUnsupported( 1839 NVDispEvoPtr pDispEvo, 1840 NvS64 *val) 1841 { 1842 NVDevEvoPtr pDevEvo = pDispEvo->pDevEvo; 1843 *val = pDevEvo->badFramelockFirmware; 1844 1845 return TRUE; 1846 } 1847 1848 static NvBool GetFrameLockSyncDelayResolution( 1849 const NVFrameLockEvoRec *pFrameLockEvo, 1850 enum NvKmsFrameLockAttribute attribute, 1851 NvS64 *val) 1852 { 1853 *val = pFrameLockEvo->syncSkewResolution; 1854 1855 return TRUE; 1856 } 1857 1858 NvBool nvSetFrameLockDisplayConfigEvo(NVDpyEvoRec *pDpyEvo, NvS64 val) 1859 { 1860 NVDispEvoPtr pDispEvo = pDpyEvo->pDispEvo; 1861 unsigned int valid; 1862 NvBool removeFromClients = FALSE; 1863 NvBool removeFromServer = FALSE; 1864 1865 if (!pDispEvo || !pDispEvo->pFrameLockEvo) { 1866 return FALSE; 1867 } 1868 1869 /* Only set the config when framelock is disabled */ 1870 1871 if (pDispEvo->framelock.syncEnabled) { 1872 return FALSE; 1873 } 1874 1875 valid = FrameLockGetValidDpyConfig(pDpyEvo); 1876 1877 /* Display device cannot be set as such */ 1878 if (!((1<<val) & valid)) { 1879 return FALSE; 1880 } 1881 1882 switch (val) { 1883 case NV_KMS_DPY_ATTRIBUTE_FRAMELOCK_DISPLAY_CONFIG_SERVER: 1884 /* alert other dpy it is being disabled as server */ 1885 if (!nvDpyIdIsInvalid(pDispEvo->framelock.server) && 1886 !nvDpyIdsAreEqual(pDispEvo->framelock.server, pDpyEvo->id)) { 1887 NVDpyEvoPtr pOtherDpyEvo; 1888 1889 pOtherDpyEvo = 1890 nvGetDpyEvoFromDispEvo(pDispEvo, pDispEvo->framelock.server); 1891 if (pOtherDpyEvo) { 1892 nvSendDpyAttributeChangedEventEvo( 1893 pOtherDpyEvo, 1894 NV_KMS_DPY_ATTRIBUTE_FRAMELOCK_DISPLAY_CONFIG, 1895 NV_KMS_DPY_ATTRIBUTE_FRAMELOCK_DISPLAY_CONFIG_DISABLED); 1896 } 1897 } 1898 pDispEvo->framelock.server = pDpyEvo->id; 1899 removeFromClients = TRUE; 1900 break; 1901 1902 case NV_KMS_DPY_ATTRIBUTE_FRAMELOCK_DISPLAY_CONFIG_CLIENT: 1903 pDispEvo->framelock.clients = 1904 nvAddDpyIdToDpyIdList(pDpyEvo->id, pDispEvo->framelock.clients); 1905 removeFromServer = TRUE; 1906 break; 1907 1908 case NV_KMS_DPY_ATTRIBUTE_FRAMELOCK_DISPLAY_CONFIG_DISABLED: 1909 removeFromClients = TRUE; 1910 removeFromServer = TRUE; 1911 break; 1912 1913 default: 1914 return FALSE; 1915 } 1916 1917 if (removeFromClients) { 1918 if (nvDpyIdIsInDpyIdList(pDpyEvo->id, pDispEvo->framelock.clients)) { 1919 pDispEvo->framelock.clients = 1920 nvDpyIdListMinusDpyId(pDispEvo->framelock.clients, pDpyEvo->id); 1921 } 1922 } 1923 1924 if (removeFromServer) { 1925 if (nvDpyIdsAreEqual(pDispEvo->framelock.server, pDpyEvo->id)) { 1926 pDispEvo->framelock.server = nvInvalidDpyId(); 1927 } 1928 } 1929 1930 return TRUE; 1931 } 1932 1933 NvBool nvGetFrameLockDisplayConfigEvo(const NVDpyEvoRec *pDpyEvo, NvS64 *val) 1934 { 1935 NVDispEvoPtr pDispEvo = pDpyEvo->pDispEvo; 1936 1937 if (!pDispEvo || !pDispEvo->pFrameLockEvo) { 1938 return FALSE; 1939 } 1940 1941 if (nvDpyIdsAreEqual(pDispEvo->framelock.server, pDpyEvo->id)) { 1942 *val = NV_KMS_DPY_ATTRIBUTE_FRAMELOCK_DISPLAY_CONFIG_SERVER; 1943 } else if (nvDpyIdIsInDpyIdList(pDpyEvo->id, pDispEvo->framelock.clients)) { 1944 *val = NV_KMS_DPY_ATTRIBUTE_FRAMELOCK_DISPLAY_CONFIG_CLIENT; 1945 } else { 1946 *val = NV_KMS_DPY_ATTRIBUTE_FRAMELOCK_DISPLAY_CONFIG_DISABLED; 1947 } 1948 1949 return TRUE; 1950 } 1951 1952 NvBool nvGetFrameLockDisplayConfigValidValuesEvo( 1953 const NVDpyEvoRec *pDpyEvo, 1954 struct NvKmsAttributeValidValuesCommonReply *pValidValues) 1955 { 1956 if (pDpyEvo->pDispEvo->pFrameLockEvo == NULL) { 1957 return FALSE; 1958 } 1959 1960 nvAssert(pValidValues->type == NV_KMS_ATTRIBUTE_TYPE_INTBITS); 1961 1962 pValidValues->u.bits.ints = FrameLockGetValidDpyConfig(pDpyEvo); 1963 1964 return TRUE; 1965 } 1966 1967 static const struct { 1968 NvBool (*set)(NVDispEvoPtr pDispEvo, NvS64 value); 1969 NvBool (*get)(NVDispEvoPtr pDispEvo, NvS64 *pValue); 1970 enum NvKmsAttributeType type; 1971 } DispAttributesDispatchTable[] = { 1972 [NV_KMS_DISP_ATTRIBUTE_FRAMELOCK] = { 1973 .set = NULL, 1974 .get = GetFrameLock, 1975 .type = NV_KMS_ATTRIBUTE_TYPE_BOOLEAN, 1976 }, 1977 [NV_KMS_DISP_ATTRIBUTE_FRAMELOCK_SYNC] = { 1978 .set = SetFrameLockSync, 1979 .get = GetFrameLockSync, 1980 .type = NV_KMS_ATTRIBUTE_TYPE_BOOLEAN, 1981 }, 1982 [NV_KMS_DISP_ATTRIBUTE_GPU_FRAMELOCK_FPGA_REVISION_UNSUPPORTED] = { 1983 .set = NULL, 1984 .get = GetFrameLockFpgaRevisionUnsupported, 1985 .type = NV_KMS_ATTRIBUTE_TYPE_BOOLEAN, 1986 }, 1987 [NV_KMS_DISP_ATTRIBUTE_FRAMELOCK_STEREO_SYNC] = { 1988 .set = NULL, 1989 .get = GetFrameLockStereoSync, 1990 .type = NV_KMS_ATTRIBUTE_TYPE_BOOLEAN, 1991 }, 1992 [NV_KMS_DISP_ATTRIBUTE_FRAMELOCK_TIMING] = { 1993 .set = NULL, 1994 .get = GetFrameLockTiming, 1995 .type = NV_KMS_ATTRIBUTE_TYPE_BOOLEAN, 1996 }, 1997 [NV_KMS_DISP_ATTRIBUTE_FRAMELOCK_TEST_SIGNAL] = { 1998 .set = SetFrameLockTestSignal, 1999 .get = GetFrameLockTestSignal, 2000 .type = NV_KMS_ATTRIBUTE_TYPE_BOOLEAN, 2001 }, 2002 [NV_KMS_DISP_ATTRIBUTE_FRAMELOCK_RESET] = { 2003 .set = ResetHardwareOneDisp, 2004 .get = NULL, 2005 .type = NV_KMS_ATTRIBUTE_TYPE_BOOLEAN, 2006 }, 2007 [NV_KMS_DISP_ATTRIBUTE_FRAMELOCK_SET_SWAP_BARRIER] = { 2008 .set = SetSwapBarrier, 2009 .get = NULL, 2010 .type = NV_KMS_ATTRIBUTE_TYPE_BOOLEAN, 2011 }, 2012 [NV_KMS_DISP_ATTRIBUTE_ALLOW_FLIPLOCK] = { 2013 .set = nvAllowFlipLockEvo, 2014 .get = NULL, 2015 .type = NV_KMS_ATTRIBUTE_TYPE_BOOLEAN, 2016 }, 2017 [NV_KMS_DISP_ATTRIBUTE_QUERY_DP_AUX_LOG] = { 2018 .set = NULL, 2019 .get = nvRmQueryDpAuxLog, 2020 .type = NV_KMS_ATTRIBUTE_TYPE_BOOLEAN, 2021 }, 2022 }; 2023 2024 2025 /*! 2026 * Set pParams->attribute to pParams->value on the given disp. 2027 */ 2028 NvBool nvSetDispAttributeEvo(NVDispEvoPtr pDispEvo, 2029 struct NvKmsSetDispAttributeParams *pParams) 2030 { 2031 NvU32 index = pParams->request.attribute; 2032 2033 if (index >= ARRAY_LEN(DispAttributesDispatchTable)) { 2034 return FALSE; 2035 } 2036 2037 if (DispAttributesDispatchTable[index].set == NULL) { 2038 return FALSE; 2039 } 2040 2041 return DispAttributesDispatchTable[index].set(pDispEvo, 2042 pParams->request.value); 2043 } 2044 2045 2046 /*! 2047 * Get the value of pParams->attribute on the given disp. 2048 */ 2049 NvBool nvGetDispAttributeEvo(NVDispEvoPtr pDispEvo, 2050 struct NvKmsGetDispAttributeParams *pParams) 2051 { 2052 NvU32 index = pParams->request.attribute; 2053 2054 if (index >= ARRAY_LEN(DispAttributesDispatchTable)) { 2055 return FALSE; 2056 } 2057 2058 if (DispAttributesDispatchTable[index].get == NULL) { 2059 return FALSE; 2060 } 2061 2062 return DispAttributesDispatchTable[index].get(pDispEvo, 2063 &pParams->reply.value); 2064 } 2065 2066 2067 /*! 2068 * Get the valid values of pParams->attribute on the given disp. 2069 */ 2070 NvBool nvGetDispAttributeValidValuesEvo( 2071 const NVDispEvoRec *pDispEvo, 2072 struct NvKmsGetDispAttributeValidValuesParams *pParams) 2073 { 2074 struct NvKmsAttributeValidValuesCommonReply *pReply = 2075 &pParams->reply.common; 2076 NvU32 index = pParams->request.attribute; 2077 2078 if (index >= ARRAY_LEN(DispAttributesDispatchTable)) { 2079 return FALSE; 2080 } 2081 2082 /* 2083 * FRAMELOCK and GPU_FRAMELOCK_FPGA_REVISION_UNSUPPORTED 2084 * can be queried without a pFrameLockEvo; all other 2085 * attributes require a pFrameLockEvo. 2086 */ 2087 if (((pParams->request.attribute != NV_KMS_DISP_ATTRIBUTE_FRAMELOCK) && 2088 (pParams->request.attribute != 2089 NV_KMS_DISP_ATTRIBUTE_GPU_FRAMELOCK_FPGA_REVISION_UNSUPPORTED)) && 2090 (pDispEvo->pFrameLockEvo == NULL)) { 2091 return FALSE; 2092 } 2093 2094 nvkms_memset(pReply, 0, sizeof(*pReply)); 2095 2096 pReply->readable = (DispAttributesDispatchTable[index].get != NULL); 2097 pReply->writable = (DispAttributesDispatchTable[index].set != NULL); 2098 2099 pReply->type = DispAttributesDispatchTable[index].type; 2100 2101 return TRUE; 2102 } 2103 2104 2105 static const struct { 2106 NvBool (*set)(NVFrameLockEvoPtr pFrameLockEvo, NvS64 value); 2107 NvBool (*get)(const NVFrameLockEvoRec *pFrameLockEvo, 2108 enum NvKmsFrameLockAttribute attribute, NvS64 *pValue); 2109 NvBool (*getValidValues)( 2110 const NVFrameLockEvoRec *pFrameLockEvo, 2111 struct NvKmsAttributeValidValuesCommonReply *pValidValues); 2112 enum NvKmsAttributeType type; 2113 } FrameLockAttributesDispatchTable[] = { 2114 [NV_KMS_FRAMELOCK_ATTRIBUTE_POLARITY] = { 2115 .set = SetFrameLockPolarity, 2116 .get = GetFrameLockPolarity, 2117 .getValidValues = NULL, 2118 .type = NV_KMS_ATTRIBUTE_TYPE_BITMASK, 2119 }, 2120 [NV_KMS_FRAMELOCK_ATTRIBUTE_SYNC_DELAY] = { 2121 .set = FrameLockSetSyncDelay, 2122 .get = GetFrameLockSyncDelay, 2123 .getValidValues = GetFrameLockSyncDelayValidValues, 2124 .type = NV_KMS_ATTRIBUTE_TYPE_RANGE, 2125 }, 2126 [NV_KMS_FRAMELOCK_ATTRIBUTE_HOUSE_SYNC_MODE] = { 2127 .set = SetHouseSyncMode, 2128 .get = GetHouseSyncMode, 2129 .getValidValues = GetHouseSyncModeValidValues, 2130 .type = NV_KMS_ATTRIBUTE_TYPE_INTBITS, 2131 }, 2132 [NV_KMS_FRAMELOCK_ATTRIBUTE_SYNC_INTERVAL] = { 2133 .set = FrameLockSetSyncInterval, 2134 .get = GetFrameLockSyncInterval, 2135 .getValidValues = GetFrameLockSyncIntervalValidValues, 2136 .type = NV_KMS_ATTRIBUTE_TYPE_RANGE, 2137 }, 2138 [NV_KMS_FRAMELOCK_ATTRIBUTE_SYNC_READY] = { 2139 .set = NULL, 2140 .get = GetFrameLockSyncReady, 2141 .getValidValues = NULL, 2142 .type = NV_KMS_ATTRIBUTE_TYPE_BOOLEAN, 2143 }, 2144 [NV_KMS_FRAMELOCK_ATTRIBUTE_VIDEO_MODE] = { 2145 .set = SetFrameLockVideoMode, 2146 .get = GetFrameLockVideoMode, 2147 .getValidValues = GetFrameLockVideoModeValidValues, 2148 .type = NV_KMS_ATTRIBUTE_TYPE_RANGE, 2149 }, 2150 [NV_KMS_FRAMELOCK_ATTRIBUTE_FPGA_REVISION] = { 2151 .set = NULL, 2152 .get = GetFrameLockFpgaRevision, 2153 .getValidValues = NULL, 2154 .type = NV_KMS_ATTRIBUTE_TYPE_INTEGER, 2155 }, 2156 [NV_KMS_FRAMELOCK_ATTRIBUTE_FIRMWARE_MAJOR_VERSION] = { 2157 .set = NULL, 2158 .get = GetFrameLockFirmwareMajorVersion, 2159 .getValidValues = NULL, 2160 .type = NV_KMS_ATTRIBUTE_TYPE_INTEGER, 2161 }, 2162 [NV_KMS_FRAMELOCK_ATTRIBUTE_FIRMWARE_MINOR_VERSION] = { 2163 .set = NULL, 2164 .get = GetFrameLockFirmwareMinorVersion, 2165 .getValidValues = NULL, 2166 .type = NV_KMS_ATTRIBUTE_TYPE_INTEGER, 2167 }, 2168 [NV_KMS_FRAMELOCK_ATTRIBUTE_BOARD_ID] = { 2169 .set = NULL, 2170 .get = GetFrameLockBoardId, 2171 .getValidValues = NULL, 2172 .type = NV_KMS_ATTRIBUTE_TYPE_INTEGER, 2173 }, 2174 [NV_KMS_FRAMELOCK_ATTRIBUTE_SYNC_DELAY_RESOLUTION] = { 2175 .set = NULL, 2176 .get = GetFrameLockSyncDelayResolution, 2177 .getValidValues = NULL, 2178 .type = NV_KMS_ATTRIBUTE_TYPE_INTEGER, 2179 }, 2180 [NV_KMS_FRAMELOCK_ATTRIBUTE_PORT0_STATUS] = { 2181 .set = NULL, 2182 .get = nvFrameLockGetStatusEvo, 2183 .getValidValues = NULL, 2184 .type = NV_KMS_ATTRIBUTE_TYPE_BOOLEAN, 2185 }, 2186 [NV_KMS_FRAMELOCK_ATTRIBUTE_PORT1_STATUS] = { 2187 .set = NULL, 2188 .get = nvFrameLockGetStatusEvo, 2189 .getValidValues = NULL, 2190 .type = NV_KMS_ATTRIBUTE_TYPE_BOOLEAN, 2191 }, 2192 [NV_KMS_FRAMELOCK_ATTRIBUTE_HOUSE_STATUS] = { 2193 .set = NULL, 2194 .get = nvFrameLockGetStatusEvo, 2195 .getValidValues = NULL, 2196 .type = NV_KMS_ATTRIBUTE_TYPE_BOOLEAN, 2197 }, 2198 [NV_KMS_FRAMELOCK_ATTRIBUTE_ETHERNET_DETECTED] = { 2199 .set = NULL, 2200 .get = nvFrameLockGetStatusEvo, 2201 .getValidValues = NULL, 2202 .type = NV_KMS_ATTRIBUTE_TYPE_BITMASK, 2203 }, 2204 [NV_KMS_FRAMELOCK_ATTRIBUTE_SYNC_RATE] = { 2205 .set = NULL, 2206 .get = nvFrameLockGetStatusEvo, 2207 .getValidValues = NULL, 2208 .type = NV_KMS_ATTRIBUTE_TYPE_INTEGER, 2209 }, 2210 [NV_KMS_FRAMELOCK_ATTRIBUTE_SYNC_RATE_4] = { 2211 .set = NULL, 2212 .get = nvFrameLockGetStatusEvo, 2213 .getValidValues = NULL, 2214 .type = NV_KMS_ATTRIBUTE_TYPE_INTEGER, 2215 }, 2216 [NV_KMS_FRAMELOCK_ATTRIBUTE_INCOMING_HOUSE_SYNC_RATE] = { 2217 .set = NULL, 2218 .get = nvFrameLockGetStatusEvo, 2219 .getValidValues = NULL, 2220 .type = NV_KMS_ATTRIBUTE_TYPE_INTEGER, 2221 }, 2222 [NV_KMS_FRAMELOCK_ATTRIBUTE_MULTIPLY_DIVIDE_VALUE] = { 2223 .set = SetFrameLockMulDivVal, 2224 .get = GetFrameLockMulDivVal, 2225 .getValidValues = GetFrameLockMulDivValValidValues, 2226 .type = NV_KMS_ATTRIBUTE_TYPE_RANGE, 2227 }, 2228 [NV_KMS_FRAMELOCK_ATTRIBUTE_MULTIPLY_DIVIDE_MODE] = { 2229 .set = SetFrameLockMulDivMode, 2230 .get = GetFrameLockMulDivMode, 2231 .getValidValues = GetFrameLockMulDivModeValidValues, 2232 .type = NV_KMS_ATTRIBUTE_TYPE_INTEGER, 2233 }, 2234 }; 2235 2236 NvBool nvSetFrameLockAttributeEvo( 2237 NVFrameLockEvoRec *pFrameLockEvo, 2238 const struct NvKmsSetFrameLockAttributeParams *pParams) 2239 { 2240 NvU32 index = pParams->request.attribute; 2241 2242 if (index >= ARRAY_LEN(FrameLockAttributesDispatchTable)) { 2243 return FALSE; 2244 } 2245 2246 if (FrameLockAttributesDispatchTable[index].set == NULL) { 2247 return FALSE; 2248 } 2249 2250 if ((FrameLockAttributesDispatchTable[index].type == 2251 NV_KMS_ATTRIBUTE_TYPE_BOOLEAN) && 2252 (pParams->request.value != TRUE) && 2253 (pParams->request.value != FALSE)) { 2254 return FALSE; 2255 } 2256 2257 return FrameLockAttributesDispatchTable[index].set(pFrameLockEvo, 2258 pParams->request.value); 2259 } 2260 2261 NvBool nvGetFrameLockAttributeEvo( 2262 const NVFrameLockEvoRec *pFrameLockEvo, 2263 struct NvKmsGetFrameLockAttributeParams *pParams) 2264 { 2265 NvU32 index = pParams->request.attribute; 2266 2267 if (index >= ARRAY_LEN(FrameLockAttributesDispatchTable)) { 2268 return FALSE; 2269 } 2270 2271 if (FrameLockAttributesDispatchTable[index].get == NULL) { 2272 return FALSE; 2273 } 2274 2275 return FrameLockAttributesDispatchTable[index].get(pFrameLockEvo, 2276 pParams->request.attribute, 2277 &pParams->reply.value); 2278 } 2279 2280 NvBool nvGetFrameLockAttributeValidValuesEvo( 2281 const NVFrameLockEvoRec *pFrameLockEvo, 2282 struct NvKmsGetFrameLockAttributeValidValuesParams *pParams) 2283 { 2284 struct NvKmsAttributeValidValuesCommonReply *pReply = 2285 &pParams->reply.common; 2286 NvU32 index = pParams->request.attribute; 2287 2288 if (index >= ARRAY_LEN(FrameLockAttributesDispatchTable)) { 2289 return FALSE; 2290 } 2291 2292 nvkms_memset(pReply, 0, sizeof(*pReply)); 2293 2294 pReply->readable = (FrameLockAttributesDispatchTable[index].get != NULL); 2295 pReply->writable = (FrameLockAttributesDispatchTable[index].set != NULL); 2296 2297 pReply->type = FrameLockAttributesDispatchTable[index].type; 2298 2299 /* 2300 * The getValidValues function provides two important things: 2301 * - If type==Range, then assigns reply::u::range. 2302 * - If the attribute is not currently available, returns FALSE. 2303 * If the getValidValues function is NULL, assume the attribute is 2304 * available. The type must not be something requires assigning 2305 * to reply::u. 2306 */ 2307 if (FrameLockAttributesDispatchTable[index].getValidValues == NULL) { 2308 nvAssert(pReply->type != NV_KMS_ATTRIBUTE_TYPE_RANGE); 2309 return TRUE; 2310 } 2311 2312 return FrameLockAttributesDispatchTable[index].getValidValues( 2313 pFrameLockEvo, pReply); 2314 } 2315 2316 NvU32 nvGetFramelockServerHead(const NVDispEvoRec *pDispEvo) 2317 { 2318 const NVDpyEvoRec *pDpyEvo = 2319 nvGetDpyEvoFromDispEvo(pDispEvo, pDispEvo->framelock.server); 2320 return (pDpyEvo != NULL) ? nvGetPrimaryHwHead(pDispEvo, pDpyEvo->apiHead) : 2321 NV_INVALID_HEAD; 2322 } 2323 2324 NvU32 nvGetFramelockClientHeadsMask(const NVDispEvoRec *pDispEvo) 2325 { 2326 NvU32 headsMask = 0x0; 2327 const NVDpyEvoRec *pServerDpyEvo, *pClientDpyEvo; 2328 2329 pServerDpyEvo = nvGetDpyEvoFromDispEvo(pDispEvo, 2330 pDispEvo->framelock.server); 2331 if ((pServerDpyEvo != NULL) && 2332 (pServerDpyEvo->apiHead != NV_INVALID_HEAD)) { 2333 const NVDispApiHeadStateEvoRec *pApiHeadState = 2334 &pDispEvo->apiHeadState[pServerDpyEvo->apiHead]; 2335 NvU32 primaryHead = nvGetPrimaryHwHead(pDispEvo, 2336 pServerDpyEvo->apiHead); 2337 2338 nvAssert(primaryHead != NV_INVALID_HEAD); 2339 2340 /* 2341 * The secondary hardware-head of the server dpy are client of the 2342 * primary head. 2343 */ 2344 headsMask |= pApiHeadState->hwHeadsMask; 2345 headsMask &= ~NVBIT(primaryHead); 2346 } 2347 2348 FOR_ALL_EVO_DPYS(pClientDpyEvo, pDispEvo->framelock.clients, pDispEvo) { 2349 if (pClientDpyEvo->apiHead == NV_INVALID_HEAD) { 2350 continue; 2351 } 2352 const NVDispApiHeadStateEvoRec *pApiHeadState = 2353 &pDispEvo->apiHeadState[pClientDpyEvo->apiHead]; 2354 headsMask |= pApiHeadState->hwHeadsMask; 2355 } 2356 2357 return headsMask; 2358 } 2359 2360 void nvUpdateGLSFramelock(const NVDispEvoRec *pDispEvo, const NvU32 head, 2361 const NvBool enable, const NvBool server) 2362 { 2363 NVDpyEvoRec *pDpyEvo; 2364 NvS64 value = enable | (server << 1); 2365 2366 /* 2367 * XXX[2Heads1OR] Optimize this loop in follow on code change when 2368 * apiHead -> pDpyEvo mapping will get implemented. 2369 */ 2370 FOR_ALL_EVO_DPYS(pDpyEvo, pDispEvo->validDisplays, pDispEvo) { 2371 /* 2372 * XXX[2Heads1OR] Framelock is currently not supported with 2373 * 2Heads1OR, the api head is expected to be mapped onto a single 2374 * hardware head which is the primary hardware head. 2375 */ 2376 if ((pDpyEvo->apiHead == NV_INVALID_HEAD) || 2377 (nvGetPrimaryHwHead(pDispEvo, pDpyEvo->apiHead) != head)) { 2378 continue; 2379 } 2380 2381 nvSendDpyAttributeChangedEventEvo(pDpyEvo, 2382 NV_KMS_DPY_ATTRIBUTE_UPDATE_GLS_FRAMELOCK, 2383 value); 2384 } 2385 } 2386