1 /* 2 * SPDX-FileCopyrightText: Copyright (c) 1993-2015 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 /* this source file contains routines for setting and moving the cursor. 25 * NV50 specific */ 26 27 #include "nvkms-cursor.h" 28 #include "nvkms-types.h" 29 #include "nvkms-dma.h" 30 #include "nvkms-utils.h" 31 #include "nvkms-rm.h" 32 #include "nvkms-evo.h" 33 #include "nvkms-vrr.h" 34 #include "nvkms-surface.h" 35 #include "nvkms-flip.h" 36 37 #include "nvkms-rmapi.h" 38 39 #include <class/cl917a.h> /* sizeof(GK104DispCursorControlPio) */ 40 41 #include <nvos.h> /* NV50VAIO_CHANNELPIO_ALLOCATION_PARAMETERS */ 42 43 /*! 44 * Get the NVSurfaceEvoPtrs described by NvKmsSetCursorImageCommonParams. 45 * 46 * Look up the surfaces described by NvKmsSetCursorImageCommonParams, 47 * and check that the surfaces are valid for use by cursor on the 48 * given pDevEvo. 49 * 50 * \param[in] pDevEvo The device on which the cursor image will be set. 51 * \param[in] pParams The parameter structure indicating the surfaces. 52 * \param[out] pSurfaceEvo The array of surfaces to be assigned. 53 * 54 * \return If the parameters are valid, return TRUE and assign 55 * pSurfaceEvo. Otherwise, return FALSE. 56 */ 57 NvBool nvGetCursorImageSurfaces( 58 const NVDevEvoRec *pDevEvo, 59 const NVEvoApiHandlesRec *pOpenDevSurfaceHandles, 60 const struct NvKmsSetCursorImageCommonParams *pParams, 61 NVSurfaceEvoPtr pSurfaceEvos[NVKMS_MAX_EYES]) 62 { 63 NvU32 eye; 64 65 nvkms_memset(pSurfaceEvos, 0, sizeof(NVSurfaceEvoRec *) * NVKMS_MAX_EYES); 66 67 /* XXX NVKMS TODO: add support for stereo cursor */ 68 nvAssert(pParams->surfaceHandle[NVKMS_RIGHT] == 0); 69 70 for (eye = 0; eye < ARRAY_LEN(pParams->surfaceHandle); eye++) { 71 if (pParams->surfaceHandle[eye] != 0) { 72 NVSurfaceEvoPtr pSurfaceEvo = NULL; 73 pSurfaceEvo = 74 nvEvoGetSurfaceFromHandle(pDevEvo, 75 pOpenDevSurfaceHandles, 76 pParams->surfaceHandle[eye], 77 TRUE /* isUsedByCursorChannel */, 78 FALSE /* isUsedByLayerChannel */); 79 if ((pSurfaceEvo == NULL) || 80 (pSurfaceEvo->isoType != NVKMS_MEMORY_ISO)) { 81 return FALSE; 82 } 83 84 pSurfaceEvos[eye] = pSurfaceEvo; 85 } 86 } 87 88 return TRUE; 89 } 90 91 static void 92 SetCursorImageOneHead(NVDispEvoPtr pDispEvo, 93 const NvU32 head, 94 NVSurfaceEvoRec *pSurfaceEvoNew, 95 const struct NvKmsCompositionParams *pCursorCompParams, 96 NVEvoUpdateState *pUpdateState) 97 { 98 NVDevEvoPtr pDevEvo = pDispEvo->pDevEvo; 99 const NvU32 sd = pDispEvo->displayOwner; 100 NvBool changed = FALSE; 101 102 NVSurfaceEvoPtr pSurfaceEvoOld = 103 pDevEvo->gpus[sd].headState[head].cursor.pSurfaceEvo; 104 105 if (pSurfaceEvoNew != NULL && 106 nvkms_memcmp(pCursorCompParams, 107 &pDevEvo->gpus[sd].headState[head].cursor.cursorCompParams, 108 sizeof(*pCursorCompParams)) != 0) { 109 pDevEvo->gpus[sd].headState[head].cursor.cursorCompParams = 110 *pCursorCompParams; 111 changed = TRUE; 112 } 113 114 if (pSurfaceEvoNew != pSurfaceEvoOld) { 115 116 if (pSurfaceEvoNew != NULL) { 117 nvEvoIncrementSurfaceRefCnts(pSurfaceEvoNew); 118 } 119 120 if (pSurfaceEvoOld) { 121 nvEvoDecrementSurfaceRefCnts(pSurfaceEvoOld); 122 } 123 124 pDevEvo->gpus[sd].headState[head].cursor.pSurfaceEvo = pSurfaceEvoNew; 125 changed = TRUE; 126 } 127 128 if (changed) { 129 nvPushEvoSubDevMaskDisp(pDispEvo); 130 pDevEvo->hal->SetCursorImage( 131 pDevEvo, 132 head, 133 pDevEvo->gpus[sd].headState[head].cursor.pSurfaceEvo, 134 pUpdateState, 135 &pDevEvo->gpus[sd].headState[head].cursor.cursorCompParams); 136 nvPopEvoSubDevMask(pDevEvo); 137 } 138 } 139 140 static void 141 SetCursorImage(NVDispEvoPtr pDispEvo, 142 const NvU32 apiHead, 143 NVSurfaceEvoRec *pSurfaceEvoNew, 144 const struct NvKmsCompositionParams *pCursorCompParams) 145 { 146 NVDevEvoRec *pDevEvo = pDispEvo->pDevEvo; 147 const NVDispApiHeadStateEvoRec *pApiHeadState = 148 &pDispEvo->apiHeadState[apiHead]; 149 NvU32 head; 150 NVEvoUpdateState updateState = { }; 151 NvBool changed = FALSE; 152 153 FOR_EACH_EVO_HW_HEAD_IN_MASK(pApiHeadState->hwHeadsMask, head) { 154 SetCursorImageOneHead(pDispEvo, 155 head, 156 pSurfaceEvoNew, 157 pCursorCompParams, 158 &updateState); 159 } 160 161 if (!nvIsUpdateStateEmpty(pDevEvo, &updateState)) { 162 nvEvoUpdateAndKickOff(pDispEvo, FALSE, &updateState, 163 TRUE /* releaseElv */); 164 changed = TRUE; 165 } 166 167 /* 168 * Unconditionally trigger an unstall: even if the cursor image or 169 * composition didn't change, clients setting the cursor image would expect 170 * a VRR unstall. Also, if the cursor changed from an image to no image 171 * (i.e., hiding the cursor), that should trigger a VRR unstall, too. 172 */ 173 nvTriggerVrrUnstallSetCursorImage(pDispEvo, changed); 174 } 175 176 static NvBool 177 FlipCursorImage(NVDispEvoPtr pDispEvo, 178 const struct NvKmsPerOpenDev *pOpenDevice, 179 NvU32 apiHead, 180 const struct NvKmsSetCursorImageCommonParams *pImageParams) 181 { 182 const NvU32 sd = pDispEvo->displayOwner; 183 NvBool ret; 184 struct NvKmsFlipRequestOneHead *pFlipHead = 185 nvCalloc(1, sizeof(*pFlipHead)); 186 187 if (pFlipHead == NULL) { 188 return FALSE; 189 } 190 191 pFlipHead->sd = sd; 192 pFlipHead->head = apiHead; 193 pFlipHead->flip.cursor.image = *pImageParams; 194 pFlipHead->flip.cursor.imageSpecified = TRUE; 195 196 ret = nvFlipEvo(pDispEvo->pDevEvo, 197 pOpenDevice, 198 pFlipHead, 199 1 /* numFlipHeads */, 200 TRUE /* commit */, 201 FALSE /* allowVrr */, 202 NULL /* pReply */, 203 FALSE /* skipUpdate */, 204 FALSE /* allowFlipLock */); 205 206 nvFree(pFlipHead); 207 208 return ret; 209 } 210 211 NvBool nvSetCursorImage( 212 NVDispEvoPtr pDispEvo, 213 const struct NvKmsPerOpenDev *pOpenDevice, 214 const NVEvoApiHandlesRec *pOpenDevSurfaceHandles, 215 NvU32 apiHead, 216 const struct NvKmsSetCursorImageCommonParams *pParams) 217 { 218 NVDevEvoPtr pDevEvo = pDispEvo->pDevEvo; 219 NVSurfaceEvoPtr pSurfaceEvos[NVKMS_MAX_EYES]; 220 NVSurfaceEvoPtr pSurfaceEvoNew; 221 NvBool flipCursorImage = FALSE; 222 223 if (!nvGetCursorImageSurfaces(pDevEvo, pOpenDevSurfaceHandles, 224 pParams, pSurfaceEvos)) { 225 return FALSE; 226 } 227 228 pSurfaceEvoNew = pSurfaceEvos[NVKMS_LEFT]; 229 230 /* 231 * Use flip to apply or remove workaround for hardware bug 2052012 232 */ 233 if (NV5070_CTRL_SYSTEM_GET_CAP( 234 pDevEvo->capsBits, 235 NV5070_CTRL_SYSTEM_CAPS_BUG_2052012_GLITCHY_MCLK_SWITCH)) { 236 const NvU32 sd = pDispEvo->displayOwner; 237 const NVDispApiHeadStateEvoRec *pApiHeadState = 238 &pDispEvo->apiHeadState[apiHead]; 239 NvU32 head; 240 241 FOR_EACH_EVO_HW_HEAD_IN_MASK(pApiHeadState->hwHeadsMask, head) { 242 NVSurfaceEvoPtr pSurfaceEvoOld = 243 pDevEvo->gpus[sd].headState[head].cursor.pSurfaceEvo; 244 245 if ((pSurfaceEvoOld != pSurfaceEvoNew) && 246 (pSurfaceEvoOld == NULL || pSurfaceEvoNew == NULL)) { 247 flipCursorImage = TRUE; 248 break; 249 } 250 } 251 } 252 253 if (flipCursorImage) { 254 return FlipCursorImage(pDispEvo, 255 pOpenDevice, apiHead, pParams); 256 } 257 258 SetCursorImage(pDispEvo, 259 apiHead, 260 pSurfaceEvoNew, 261 &pParams->cursorCompParams); 262 263 return TRUE; 264 } 265 266 void nvEvoMoveCursorInternal(NVDispEvoPtr pDispEvo, 267 NvU32 head, NvS16 x, NvS16 y) 268 { 269 NVDevEvoPtr pDevEvo = pDispEvo->pDevEvo; 270 const NvU32 sd = pDispEvo->displayOwner; 271 NVEvoSubDevPtr pEvoSubDev = &pDevEvo->gpus[sd]; 272 273 pDevEvo->cursorHal->MoveCursor(pDevEvo, sd, head, x, y); 274 275 /* If the cursor is visible, trigger VRR unstall to display the 276 * cursor at the new postion */ 277 if (pEvoSubDev->headState[head].cursor.pSurfaceEvo) { 278 nvTriggerVrrUnstallMoveCursor(pDispEvo); 279 } 280 } 281 282 void nvMoveCursor(NVDispEvoPtr pDispEvo, const NvU32 apiHead, 283 const struct NvKmsMoveCursorCommonParams *pParams) 284 { 285 NVDevEvoPtr pDevEvo = pDispEvo->pDevEvo; 286 const NVDispApiHeadStateEvoRec *pApiHeadState = 287 &pDispEvo->apiHeadState[apiHead]; 288 NvU16 hwViewportInWidth; 289 NvU32 head, headCount; 290 291 /* XXX NVKMS TODO: validate x,y against current viewport in? */ 292 293 nvAssert(apiHead != NV_INVALID_HEAD); 294 295 headCount = 0; 296 FOR_EACH_EVO_HW_HEAD_IN_MASK(pApiHeadState->hwHeadsMask, head) { 297 const NVDispHeadStateEvoRec *pHeadState = &pDispEvo->headState[head]; 298 const NVHwModeTimingsEvo *pTimings = &pHeadState->timings; 299 const NvU32 sd = pDispEvo->displayOwner; 300 301 if (headCount == 0) { 302 hwViewportInWidth = pTimings->viewPort.in.width; 303 } else { 304 nvAssert(hwViewportInWidth == pTimings->viewPort.in.width); 305 } 306 307 pDevEvo->gpus[sd].headState[head].cursor.x = 308 pParams->x - (hwViewportInWidth * pHeadState->tilePosition); 309 pDevEvo->gpus[sd].headState[head].cursor.y = pParams->y; 310 311 nvEvoMoveCursorInternal(pDispEvo, 312 head, 313 pDevEvo->gpus[sd].headState[head].cursor.x, 314 pDevEvo->gpus[sd].headState[head].cursor.y); 315 316 headCount++; 317 } 318 } 319 320 // Allocate and map cursor position PIO channels 321 NvBool nvAllocCursorEvo(NVDevEvoPtr pDevEvo) 322 { 323 NvU32 head; 324 325 for (head = 0; head < pDevEvo->numHeads; head++) { 326 NV50VAIO_CHANNELPIO_ALLOCATION_PARAMETERS PioChannelAllocParams = { 0 }; 327 NVDispEvoPtr pDispEvo; 328 NvU32 sd; 329 330 PioChannelAllocParams.channelInstance = head; 331 // No notifiers in cursor channel 332 PioChannelAllocParams.hObjectNotify = 0; 333 pDevEvo->cursorHandle[head] = 334 nvGenerateUnixRmHandle(&pDevEvo->handleAllocator); 335 336 if (nvRmApiAlloc( 337 nvEvoGlobal.clientHandle, 338 pDevEvo->displayHandle, 339 pDevEvo->cursorHandle[head], 340 pDevEvo->cursorHal->klass, 341 &PioChannelAllocParams) != NVOS_STATUS_SUCCESS) { 342 nvEvoLogDevDebug(pDevEvo, EVO_LOG_ERROR, 343 "Failed to allocate CURSOR PIO for head %d", 344 head); 345 nvFreeCursorEvo(pDevEvo); 346 return FALSE; 347 } 348 349 FOR_ALL_EVO_DISPLAYS(pDispEvo, sd, pDevEvo) { 350 NVEvoSubDevPtr pEvoSubDev = &pDevEvo->gpus[sd]; 351 void *pPioDisplayChannel; 352 NvU32 status; 353 354 status = nvRmApiMapMemory( 355 nvEvoGlobal.clientHandle, 356 pDevEvo->pSubDevices[sd]->handle, 357 pDevEvo->cursorHandle[head], 358 0, 359 sizeof(GK104DispCursorControlPio), 360 &pPioDisplayChannel, 361 0); 362 if (status != NVOS_STATUS_SUCCESS) { 363 nvEvoLogDispDebug(pDispEvo, EVO_LOG_ERROR, 364 "Failed to map CURSOR PIO for head %d", 365 head); 366 nvFreeCursorEvo(pDevEvo); 367 return FALSE; 368 } 369 pEvoSubDev->cursorPio[head] = pPioDisplayChannel; 370 } 371 } 372 373 return TRUE; 374 } 375 376 // Free and unmap Cursor PIO Channels 377 void nvFreeCursorEvo(NVDevEvoPtr pDevEvo) 378 { 379 NvU32 head; 380 381 for (head = 0; head < pDevEvo->numHeads; head++) { 382 NVDispEvoPtr pDispEvo; 383 NvU32 sd; 384 NvU32 status; 385 386 if (pDevEvo->cursorHandle[head] == 0) { 387 continue; 388 } 389 390 FOR_ALL_EVO_DISPLAYS(pDispEvo, sd, pDevEvo) { 391 NVEvoSubDevPtr pEvoSubDev = &pDevEvo->gpus[sd]; 392 NvU32 status; 393 394 if (pEvoSubDev->cursorPio[head] == NULL) { 395 continue; 396 } 397 398 status = nvRmApiUnmapMemory( 399 nvEvoGlobal.clientHandle, 400 pDevEvo->pSubDevices[sd]->handle, 401 pDevEvo->cursorHandle[head], 402 pEvoSubDev->cursorPio[head], 403 0); 404 405 if (status != NVOS_STATUS_SUCCESS) { 406 nvEvoLogDispDebug(pDispEvo, EVO_LOG_ERROR, 407 "Failed to unmap cursor channel memory"); 408 } 409 pEvoSubDev->cursorPio[head] = NULL; 410 } 411 412 status = nvRmApiFree( 413 nvEvoGlobal.clientHandle, 414 pDevEvo->displayHandle, 415 pDevEvo->cursorHandle[head]); 416 417 if (status != NVOS_STATUS_SUCCESS) { 418 nvEvoLogDevDebug(pDevEvo, EVO_LOG_ERROR, 419 "Failed to tear down Cursor channel"); 420 } 421 nvFreeUnixRmHandle(&pDevEvo->handleAllocator, 422 pDevEvo->cursorHandle[head]); 423 424 pDevEvo->cursorHandle[head] = 0; 425 } 426 } 427 428 extern NVEvoCursorHAL nvEvoCursor91; 429 extern NVEvoCursorHAL nvEvoCursorC3; 430 extern NVEvoCursorHAL nvEvoCursorC5; 431 extern NVEvoCursorHAL nvEvoCursorC6; 432 433 enum NvKmsAllocDeviceStatus nvInitDispHalCursorEvo(NVDevEvoPtr pDevEvo) 434 { 435 static const NVEvoCursorHALPtr cursorTable[] = { 436 &nvEvoCursor91, 437 &nvEvoCursorC3, 438 &nvEvoCursorC5, 439 &nvEvoCursorC6, 440 }; 441 442 int i; 443 444 for (i = 0; i < ARRAY_LEN(cursorTable); i++) { 445 if (nvRmEvoClassListCheck(pDevEvo, cursorTable[i]->klass)) { 446 447 pDevEvo->cursorHal = cursorTable[i]; 448 449 return NVKMS_ALLOC_DEVICE_STATUS_SUCCESS; 450 } 451 } 452 453 return NVKMS_ALLOC_DEVICE_STATUS_NO_HARDWARE_AVAILABLE; 454 } 455