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