1 /*
2 * SPDX-FileCopyrightText: Copyright (c) 2010-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3 * SPDX-License-Identifier: MIT
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
22 */
23
24 /*
25 * This file contains implementations of the EVO HAL methods for display class
26 * 3.x (also known as "nvdisplay").
27 */
28
29 #include "nvkms-dma.h"
30 #include "nvkms-types.h"
31 #include "nvkms-rmapi.h"
32 #include "nvkms-surface.h"
33 #include "nvkms-softfloat.h"
34 #include "nvkms-evo.h"
35 #include "nvkms-evo1.h"
36 #include "nvkms-evo3.h"
37 #include "nvkms-prealloc.h"
38 #include "nv-float.h"
39 #include "nvkms-dpy.h"
40 #include "nvkms-vrr.h"
41 #include "nvkms-ctxdma.h"
42
43 #include <nvmisc.h>
44
45 #include <class/clc372sw.h> // NVC372_DISPLAY_SW
46 #include <class/clc373.h> // NVC373_DISP_CAPABILITIES
47 #include <class/clc37b.h> // NVC37B_WINDOW_IMM_CHANNEL_DMA
48 #include <class/clc37d.h> // NVC37D_CORE_CHANNEL_DMA
49 #include <class/clc37dcrcnotif.h> // NVC37D_NOTIFIER_CRC
50 #include <class/clc37dswspare.h> // NVC37D_HEAD_SET_SW_SPARE_*
51 #include <class/clc37e.h> // NVC37E_WINDOW_CHANNEL_DMA
52 #include <class/clc573.h> // NVC573_DISP_CAPABILITIES
53 #include <class/clc57d.h> // NVC57D_CORE_CHANNEL_DMA
54 #include <class/clc57e.h> // NVC57E_WINDOW_CHANNEL_DMA
55 #include <class/clc57esw.h>
56 #include <class/clc673.h> // NVC673_DISP_CAPABILITIES
57 #include <class/clc67d.h> // NVC67D_CORE_CHANNEL_DMA
58 #include <class/clc67e.h> // NVC67E_WINDOW_CHANNEL_DMA
59
60 #include <ctrl/ctrlc370/ctrlc370chnc.h>
61 #include <ctrl/ctrlc370/ctrlc370rg.h>
62 #include <ctrl/ctrlc372/ctrlc372chnc.h>
63
64 #define NV_EVO3_X_EMULATED_SURFACE_MEMORY_FORMATS_C3 \
65 (NVBIT64(NvKmsSurfaceMemoryFormatRF16GF16BF16XF16))
66
67 #define NV_EVO3_X_EMULATED_SURFACE_MEMORY_FORMATS_C5 \
68 (NVBIT64(NvKmsSurfaceMemoryFormatRF16GF16BF16XF16))
69
70 /** Number of CRCs supported by hardware on NVC37D hardware (SF/SOR, Comp, RG) */
71 #define NV_EVO3_NUM_CRC_FIELDS 3
72
73 /** Number of CRCs supported by hardware on NVC37D hardware SF/SOR, Comp, RG Ovf and Count */
74 #define NV_EVO3_NUM_CRC_FLAGS 4
75
76 enum FMTCoeffType
77 {
78 FMT_COEFF_TYPE_IDENTITY = 0,
79
80 FMT_COEFF_TYPE_REC709_YUV_8BPC_LTD_TO_RGB_16BPC_FULL,
81 FMT_COEFF_TYPE_REC709_YUV_8BPC_FULL_TO_RGB_16BPC_FULL,
82 FMT_COEFF_TYPE_REC709_YUV_10BPC_LTD_TO_RGB_16BPC_FULL,
83 FMT_COEFF_TYPE_REC709_YUV_10BPC_FULL_TO_RGB_16BPC_FULL,
84 FMT_COEFF_TYPE_REC709_YUV_12BPC_LTD_TO_RGB_16BPC_FULL,
85 FMT_COEFF_TYPE_REC709_YUV_12BPC_FULL_TO_RGB_16BPC_FULL,
86
87 // FMT is always identity for RGB to avoid possible calculation error.
88
89 // must be the last entry
90 FMT_COEFF_TYPE_MAX
91 };
92
93 static const NvU32 FMTMatrix[FMT_COEFF_TYPE_MAX][12] =
94 {
95 // FMT_COEFF_TYPE_IDENTITY
96 { 0x10000, 0, 0, 0, 0, 0x10000, 0, 0, 0, 0, 0x10000, 0 },
97 // FMT_COEFF_TYPE_REC709_YUV_8BPC_LTD_TO_RGB_16BPC_FULL
98 { 0x1CCB7, 0x12B3C, 0, 0x1F06F1, 0x1F770C, 0x12B3C, 0x1FC933, 0x4D2D, 0, 0x12B3C, 0x21EDD, 0x1EDDDE },
99 // FMT_COEFF_TYPE_REC709_YUV_8BPC_FULL_TO_RGB_16BPC_FULL
100 { 0x194B4, 0x100FD, 0, 0x1F373A, 0x1F87B3, 0x100FD, 0x1FCFDC, 0x5390, 0, 0x100FD, 0x1DCDE, 0x1F136E },
101 // FMT_COEFF_TYPE_REC709_YUV_10BPC_LTD_TO_RGB_16BPC_FULL
102 { 0x1CCB7, 0x12B3C, 0, 0x1F06F1, 0x1F770C, 0x12B3C, 0x1FC933, 0x4D2D, 0, 0x12B3C, 0x21EDD, 0x1EDDDE },
103 // FMT_COEFF_TYPE_REC709_YUV_10BPC_FULL_TO_RGB_16BPC_FULL
104 { 0x19385, 0x1003C, 0, 0x1F36A3, 0x1F880D, 0x1003C, 0x1FD000, 0x53CF, 0, 0x1003C, 0x1DB78, 0x1F12BB },
105 // FMT_COEFF_TYPE_REC709_YUV_12BPC_LTD_TO_RGB_16BPC_FULL
106 { 0x1CCB7, 0x12B3C, 0, 0x1F06F1, 0x1F770C, 0x12B3C, 0x1FC933, 0x4D2D, 0, 0x12B3C, 0x21EDD, 0x1EDDDE },
107 // FMT_COEFF_TYPE_REC709_YUV_12BPC_FULL_TO_RGB_16BPC_FULL
108 { 0x19339, 0x1000C, 0, 0x1F367D, 0x1F8823, 0x1000C, 0x1FD009, 0x53DF, 0, 0x1000C, 0x1DB1F, 0x1F128E },
109 };
110
111 static void SetCsc00MatrixC5(NVEvoChannelPtr pChannel,
112 const struct NvKmsCscMatrix *matrix);
113 static void SetCsc11MatrixC5(NVEvoChannelPtr pChannel,
114 const struct NvKmsCscMatrix *matrix);
115 static void
116 UpdateCompositionC3(NVDevEvoPtr pDevEvo,
117 NVEvoChannelPtr pChannel,
118 const struct NvKmsCompositionParams *pCompParams,
119 NVEvoUpdateState *updateState,
120 enum NvKmsSurfaceMemoryFormat format);
121 static void
122 UpdateCompositionC5(NVDevEvoPtr pDevEvo,
123 NVEvoChannelPtr pChannel,
124 const struct NvKmsCompositionParams *pCompParams,
125 NVEvoUpdateState *updateState,
126 NvBool bypassComposition,
127 enum NvKmsSurfaceMemoryFormat format);
128
129 static void
130 EvoSetupIdentityOutputLutC5(NVEvoLutDataRec *pData,
131 enum NvKmsLUTState *lutState,
132 NvU32 *lutSize,
133 NvBool *isLutModeVss);
134
135 static void
136 EvoSetupIdentityBaseLutC5(NVEvoLutDataRec *pData,
137 enum NvKmsLUTState *lutState,
138 NvU32 *lutSize,
139 NvBool *isLutModeVss);
140
141 ct_assert(NV_EVO_LOCK_PIN_0 >
142 NVC37D_HEAD_SET_CONTROL_MASTER_LOCK_PIN_INTERNAL_SCAN_LOCK__SIZE_1);
143
144 /* nvdisplay has a maximum of 2 eyes and 3 planes per surface */
145 ct_assert((NVKMS_MAX_EYES * NVKMS_MAX_PLANES_PER_SURFACE) == 6);
146
147 /* Windows support all composition modes. */
148 #define NV_EVO3_SUPPORTED_WINDOW_COMP_BLEND_MODES \
149 ((1 << NVKMS_COMPOSITION_BLENDING_MODE_OPAQUE) | \
150 (1 << NVKMS_COMPOSITION_BLENDING_MODE_TRANSPARENT) | \
151 (1 << NVKMS_COMPOSITION_BLENDING_MODE_NON_PREMULT_ALPHA) | \
152 (1 << NVKMS_COMPOSITION_BLENDING_MODE_PREMULT_ALPHA) | \
153 (1 << NVKMS_COMPOSITION_BLENDING_MODE_NON_PREMULT_SURFACE_ALPHA) | \
154 (1 << NVKMS_COMPOSITION_BLENDING_MODE_PREMULT_SURFACE_ALPHA))
155
156 #define NV_EVO3_DEFAULT_WINDOW_USAGE_BOUNDS_C3 \
157 (DRF_DEF(C37D, _WINDOW_SET_WINDOW_USAGE_BOUNDS, _INPUT_LUT, _USAGE_1025) | \
158 DRF_DEF(C37D, _WINDOW_SET_WINDOW_USAGE_BOUNDS, _INPUT_SCALER_TAPS, _TAPS_2) | \
159 DRF_DEF(C37D, _WINDOW_SET_WINDOW_USAGE_BOUNDS, _UPSCALING_ALLOWED, _FALSE))
160
EyeAndPlaneToCtxDmaIdx(const NvU8 eye,const NvU8 plane)161 static inline NvU8 EyeAndPlaneToCtxDmaIdx(const NvU8 eye, const NvU8 plane)
162 {
163 /*
164 * See the definition of the SetContextDmaIso and SetOffset methods in the
165 * relevant nvdClass_01.mfs file to see how these method array indices are
166 * mapped.
167 */
168 nvAssert((eye < NVKMS_MAX_EYES) && (plane < NVKMS_MAX_PLANES_PER_SURFACE));
169
170 return eye + (plane << 1);
171 }
172
InitChannelCapsC3(NVDevEvoPtr pDevEvo,NVEvoChannelPtr pChannel)173 static void InitChannelCapsC3(NVDevEvoPtr pDevEvo,
174 NVEvoChannelPtr pChannel)
175 {
176 if ((pChannel->channelMask & NV_EVO_CHANNEL_MASK_WINDOW_ALL) != 0) {
177 static const NVEvoChannelCaps WindowCaps = {
178 /*
179 * Window classes always support timestamp flips, and allow full
180 * use of the 64-bit timestamp value.
181 */
182 .validTimeStampBits = 64,
183 /* Window classes always support tearing flips. */
184 .tearingFlips = TRUE,
185 .vrrTearingFlips = TRUE,
186 /* Window classes support per-eye stereo flips. */
187 .perEyeStereoFlips = TRUE,
188 };
189
190 pChannel->caps = WindowCaps;
191 }
192 }
193
194 // The coefficient values are obtained from bug 1953108 comment 10
195 // Per MFS: However since all 5 coefficients have to add up to 1.0, only 4 need to be specified, and
196 // HW can derive the missing one. The center coefficient is the one that is left out, so
197 // if the 5 taps need weights (c0, c1, c2, c3, c4) then only (c0, c1, c3, c4) are stored,
198 // and c2 is calculated by HW.
199 // Phase 0 is the center phase and the corresponding filter kernel is symmetrical:
200 // c0=c4, c1=c3 --> only c0 and c1 need to be stored.
201 // Phase 16 (and -16) is the edge phase and the corresponding filter kernels are:
202 // (0, c0, c1, c1, c0) for phase +16
203 // (c0, c1, c1, c0, 0) for phase -16
204 // The difference between +16 and -16 is automatically handled by HW. The table only needs
205 // to store c0 and c1 for either case.
206 // Therefore, based on MFS above, the matrix below contains the values loaded to HW.
207 // Real Phase 0 is commented for easy reference.
208 // Also, phase 16 values (last row) are commented, but its C0,C1 values are loaded in row 0/phase 0.
209 const NvU32 scalerTaps5Coeff[NUM_SCALER_RATIOS][NUM_TAPS5_COEFF_PHASES][NUM_TAPS5_COEFF_VALUES] =
210 {
211 // ratio = 1
212 {{ 0 , 0 , -16 , 144}, // real phase 0:{ 0, 0, /*256,*/ 0, 0 },
213 { 0 , -5 , /*255,*/ 5 , 0},
214 { 0 , -9 , /*254,*/ 11 , 0},
215 { -1 , -12 , /*251,*/ 18 , -1},
216 { -1 , -15 , /*248,*/ 25 , -1},
217 { -1 , -18 , /*243,*/ 33 , -2},
218 { -2 , -20 , /*238,*/ 42 , -3},
219 { -2 , -21 , /*232,*/ 51 , -3},
220 { -3 , -22 , /*225,*/ 60 , -5},
221 { -3 , -22 , /*217,*/ 70 , -6},
222 { -4 , -22 , /*208,*/ 81 , -7},
223 { -4 , -22 , /*199,*/ 91 , -9},
224 { -5 , -21 , /*190,*/ 102 , -10},
225 { -5 , -20 , /*180,*/ 113 , -12},
226 { -5 , -19 , /*169,*/ 125 , -13},
227 { -6 , -18 , /*158,*/ 136 , -15}
228 // real phase 16: { 0 , -16 , 144, 144 , -16 }
229 },
230 // ratio = 2
231 {{ 3, 60 , 20 , 108 }, // real phase 0: {3 , 60 , 130 , 60 , 3 },
232 { 3 , 57 , /*130,*/ 63 , 4 },
233 { 2 , 54 , /*130,*/ 66 , 4 },
234 { 2 , 51 , /*129,*/ 69 , 5 },
235 { 2 , 48 , /*128,*/ 72 , 6 },
236 { 1 , 45 , /*128,*/ 75 , 7 },
237 { 1 , 43 , /*127,*/ 78 , 7 },
238 { 1 , 40 , /*125,*/ 81 , 8 },
239 { 1 , 37 , /*124,*/ 84 , 9 },
240 { 0 , 35 , /*122,*/ 88 , 10 },
241 { 0 , 33 , /*121,*/ 91 , 12 },
242 { 0 , 30 , /*119,*/ 94 , 13 },
243 { 0 , 28 , /*117,*/ 97 , 14 },
244 { 0 , 26 , /*115,*/ 99 , 16 },
245 { 0 , 24 , /*112,*/ 102 , 17 },
246 { 0 , 22 , /*110,*/ 105 , 19 },
247 // real phase 16:{0 , 20 , 108 , 108 , 20 },
248 },
249 // ratio = 4
250 {{ 4 , 62 , 23 , 105 }, // real phase 0: {4 , 62 , 124 , 62 , 4 ,
251 { 4 , 59 , /*124,*/ 64 , 5 },
252 { 3 , 56 , /*124,*/ 67 , 6 },
253 { 3 , 53 , /*123,*/ 70 , 7 },
254 { 2 , 51 , /*123,*/ 73 , 8 },
255 { 2 , 48 , /*122,*/ 76 , 8 },
256 { 2 , 45 , /*121,*/ 79 , 9 },
257 { 1 , 43 , /*120,*/ 81 , 10 },
258 { 1 , 40 , /*119,*/ 84 , 12 },
259 { 1 , 38 , /*117,*/ 87 , 13 },
260 { 1 , 36 , /*116,*/ 90 , 14 },
261 { 0 , 34 , /*114,*/ 92 , 15 },
262 { 0 , 31 , /*113,*/ 95 , 17 },
263 { 0 , 29 , /*111,*/ 97 , 18 },
264 { 0 , 27 , /*109,*/ 100 , 20 },
265 { 0 , 25 , /*107,*/ 102 , 22 },
266 // real phase 16: {0 , 23 , 105 , 105 , 23 },
267 }
268 };
269
nvInitScalerCoefficientsPrecomp5(NVEvoChannelPtr pChannel,NvU32 coeff,NvU32 index)270 void nvInitScalerCoefficientsPrecomp5(NVEvoChannelPtr pChannel,
271 NvU32 coeff, NvU32 index)
272 {
273 nvDmaSetStartEvoMethod(pChannel, NVC57E_SET_INPUT_SCALER_COEFF_VALUE, 1);
274 nvDmaSetEvoMethodData(pChannel,
275 DRF_NUM(C57E, _SET_INPUT_SCALER_COEFF_VALUE, _DATA, coeff) |
276 DRF_NUM(C57E, _SET_INPUT_SCALER_COEFF_VALUE, _INDEX, index));
277 }
278
InitScalerCoefficientsPostcomp5(NVDevEvoPtr pDevEvo,NVEvoChannelPtr pChannel,NvU32 coeff,NvU32 index)279 static void InitScalerCoefficientsPostcomp5(NVDevEvoPtr pDevEvo,
280 NVEvoChannelPtr pChannel,
281 NvU32 coeff, NvU32 index)
282 {
283 NvU32 h;
284
285 for (h = 0; h < pDevEvo->numHeads; h++) {
286 nvDmaSetStartEvoMethod(pChannel,
287 NVC57D_HEAD_SET_OUTPUT_SCALER_COEFF_VALUE(h), 1);
288 nvDmaSetEvoMethodData(pChannel,
289 DRF_NUM(C57D, _HEAD_SET_OUTPUT_SCALER_COEFF_VALUE, _DATA, coeff) |
290 DRF_NUM(C57D, _HEAD_SET_OUTPUT_SCALER_COEFF_VALUE, _INDEX, index));
291 }
292 }
293
InitTaps5ScalerCoefficientsC5(NVDevEvoPtr pDevEvo,NVEvoChannelPtr pChannel,NvBool isPrecomp)294 static void InitTaps5ScalerCoefficientsC5(NVDevEvoPtr pDevEvo,
295 NVEvoChannelPtr pChannel,
296 NvBool isPrecomp)
297 {
298 NvU8 ratio;
299
300 if (isPrecomp) {
301 const NVEvoWindowCaps *pWinCaps =
302 &pDevEvo->gpus[0].capabilities.window[pChannel->instance];
303 const NVEvoScalerCaps *pScalerCaps = &pWinCaps->scalerCaps;
304
305 if (!pScalerCaps->present) {
306 return;
307 }
308 }
309
310 for (ratio = 0; ratio < NUM_SCALER_RATIOS; ratio++) {
311 NvU8 phase;
312 for (phase = 0; phase < NUM_TAPS5_COEFF_PHASES; phase++) {
313 NvU8 coeffIdx;
314 for (coeffIdx = 0; coeffIdx < NUM_TAPS5_COEFF_VALUES; coeffIdx++) {
315 NvU32 coeff = scalerTaps5Coeff[ratio][phase][coeffIdx];
316 NvU32 index = ratio << 6 | phase << 2 | coeffIdx;
317
318 if (isPrecomp) {
319 nvInitScalerCoefficientsPrecomp5(pChannel, coeff, index);
320 } else {
321 InitScalerCoefficientsPostcomp5(pDevEvo,
322 pChannel, coeff, index);
323 }
324 }
325 }
326 }
327 }
328
329 /*
330 * This is a 3x4 matrix with S5.14 coefficients (truncated from S5.16
331 * SW-specified values).
332 */
333 static const struct NvKmsCscMatrix Rec2020RGBToLMS = {{
334 { 0x697c, 0x8620, 0x1064, 0 },
335 { 0x2aa8, 0xb86c, 0x1ce8, 0 },
336 { 0x62c, 0x1354, 0xe684, 0 },
337 }};
338
339 /*
340 * This is a 3x4 matrix with S5.14 coefficients (truncated from S5.16
341 * SW-specified values).
342 */
343 static const struct NvKmsCscMatrix Rec709RGBToLMS = {{
344 { 0x4bb8, 0x9f84, 0x14c8, 0 },
345 { 0x27fc, 0xba2c, 0x1dd4, 0 },
346 { 0x8fc, 0x2818, 0xcef0, 0 },
347 }};
348
349 /*
350 * This is a 3x4 matrix with S5.14 coefficients (truncated from S5.16
351 * SW-specified values).
352 */
353 static const struct NvKmsCscMatrix LMSToRec709RGB = {{
354 { 0x62c48, 0x1aadf4, 0x25a8, 0 },
355 { 0x1ead18, 0x28f64, 0x1fc390, 0 },
356 { 0x1ffd00, 0x1fbc34, 0x146c4, 0 },
357 }};
358
359 /*
360 * This is a 3x4 matrix with S5.14 coefficients (truncated from S5.16
361 * SW-specified values).
362 */
363 static const struct NvKmsCscMatrix LMSToRec2020RGB = {{
364 { 0x36fc0, 0x1d7e54, 0x11e0, 0 },
365 { 0x1f3584, 0x1fbc8, 0x1fcebc, 0 },
366 { 0x1ff964, 0x1fe6a4, 0x11ff4, 0 },
367 }};
368
369 /*
370 * The two arrays below specify the PQ OETF transfer function that's used to
371 * convert from linear LMS FP16 to PQ encoded L'M'S' fixed-point.
372 */
373 static const NvU32 OetfPQ512SegSizesLog2[] = {
374 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 3,
375 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5,
376 5,
377 };
378
379 static const NvU16 OetfPQ512Entries[] = {
380 0x0000, 0x000C, 0x0014, 0x001C, 0x0028, 0x003C, 0x005C, 0x008C, 0x00D0, 0x0134, 0x0184, 0x01C8, 0x0238, 0x029C, 0x033C, 0x03C4,
381 0x043C, 0x04A4, 0x0504, 0x0560, 0x0600, 0x0690, 0x0714, 0x078C, 0x07FC, 0x0864, 0x08C8, 0x0924, 0x0980, 0x09D4, 0x0A24, 0x0A70,
382 0x0B04, 0x0B90, 0x0C10, 0x0C88, 0x0CFC, 0x0D68, 0x0DD4, 0x0E38, 0x0EF4, 0x0FA4, 0x1048, 0x10E4, 0x1174, 0x1200, 0x1284, 0x1304,
383 0x13F4, 0x14D0, 0x159C, 0x165C, 0x1714, 0x17C0, 0x1864, 0x1900, 0x1A28, 0x1B34, 0x1C30, 0x1D1C, 0x1DFC, 0x1ECC, 0x1F94, 0x2050,
384 0x2104, 0x21B0, 0x2258, 0x22F8, 0x2390, 0x2424, 0x24B4, 0x2540, 0x25C4, 0x2648, 0x26C4, 0x2740, 0x27B8, 0x282C, 0x289C, 0x290C,
385 0x29E0, 0x2AAC, 0x2B70, 0x2C2C, 0x2CE0, 0x2D90, 0x2E38, 0x2ED8, 0x2F74, 0x300C, 0x30A0, 0x3130, 0x31BC, 0x3244, 0x32C8, 0x3348,
386 0x3440, 0x352C, 0x360C, 0x36E4, 0x37B4, 0x387C, 0x393C, 0x39F8, 0x3AA8, 0x3B58, 0x3C00, 0x3CA4, 0x3D44, 0x3DDC, 0x3E74, 0x3F04,
387 0x401C, 0x4128, 0x4228, 0x431C, 0x4408, 0x44E8, 0x45C4, 0x4694, 0x475C, 0x4820, 0x48DC, 0x4994, 0x4A48, 0x4AF4, 0x4B9C, 0x4C3C,
388 0x4D78, 0x4EA0, 0x4FBC, 0x50CC, 0x51D0, 0x52CC, 0x53BC, 0x54A0, 0x5580, 0x5658, 0x5728, 0x57F0, 0x58B4, 0x5974, 0x5A2C, 0x5ADC,
389 0x5C34, 0x5D7C, 0x5EB4, 0x5FDC, 0x60F4, 0x6204, 0x630C, 0x6404, 0x64F8, 0x65E0, 0x66C4, 0x679C, 0x6870, 0x693C, 0x6A04, 0x6AC4,
390 0x6C38, 0x6D94, 0x6EE4, 0x7020, 0x7150, 0x7274, 0x738C, 0x7498, 0x7598, 0x7694, 0x7784, 0x786C, 0x794C, 0x7A24, 0x7AF8, 0x7BC4,
391 0x7D50, 0x7EC4, 0x8024, 0x8174, 0x82B4, 0x83E8, 0x850C, 0x8628, 0x8738, 0x883C, 0x8938, 0x8A2C, 0x8B18, 0x8BFC, 0x8CD8, 0x8DB0,
392 0x8F4C, 0x90D0, 0x9240, 0x939C, 0x94EC, 0x962C, 0x975C, 0x9880, 0x999C, 0x9AAC, 0x9BB0, 0x9CAC, 0x9DA0, 0x9E8C, 0x9F70, 0xA04C,
393 0xA1F4, 0xA384, 0xA500, 0xA664, 0xA7BC, 0xA904, 0xAA3C, 0xAB6C, 0xAC8C, 0xADA0, 0xAEAC, 0xAFAC, 0xB0A4, 0xB194, 0xB27C, 0xB360,
394 0xB510, 0xB6A4, 0xB824, 0xB994, 0xBAF0, 0xBC3C, 0xBD78, 0xBEA8, 0xBFCC, 0xC0E4, 0xC1F0, 0xC2F4, 0xC3F0, 0xC4E4, 0xC5CC, 0xC6B0,
395 0xC78C, 0xC860, 0xC930, 0xC9F8, 0xCABC, 0xCB7C, 0xCC38, 0xCCEC, 0xCD9C, 0xCE48, 0xCEF0, 0xCF94, 0xD034, 0xD0D4, 0xD16C, 0xD200,
396 0xD294, 0xD324, 0xD3B4, 0xD43C, 0xD4C4, 0xD54C, 0xD5CC, 0xD650, 0xD6CC, 0xD748, 0xD7C4, 0xD83C, 0xD8B0, 0xD924, 0xD994, 0xDA08,
397 0xDAE0, 0xDBB4, 0xDC84, 0xDD4C, 0xDE10, 0xDECC, 0xDF84, 0xE038, 0xE0E8, 0xE194, 0xE238, 0xE2DC, 0xE37C, 0xE418, 0xE4B0, 0xE544,
398 0xE5D4, 0xE664, 0xE6F0, 0xE778, 0xE800, 0xE884, 0xE904, 0xE984, 0xEA00, 0xEA7C, 0xEAF4, 0xEB68, 0xEBDC, 0xEC50, 0xECC0, 0xED30,
399 0xEE08, 0xEED8, 0xEFA4, 0xF068, 0xF128, 0xF1E4, 0xF298, 0xF348, 0xF3F4, 0xF49C, 0xF540, 0xF5E0, 0xF67C, 0xF714, 0xF7A8, 0xF83C,
400 0xF8CC, 0xF958, 0xF9E0, 0xFA68, 0xFAEC, 0xFB6C, 0xFBE8, 0xFC64, 0xFCE0, 0xFD58, 0xFDCC, 0xFE40, 0xFEB4, 0xFF24, 0xFF90, 0xFFFC,
401 };
402
403 /*
404 * The two arrays below specify the PQ EOTF transfer function that's used to
405 * convert from PQ encoded L'M'S' fixed-point to linear LMS FP16. This transfer
406 * function is the inverse of the OETF curve.
407 */
408 static const NvU32 EotfPQ512SegSizesLog2[] = {
409 6, 6, 4, 4, 4, 3, 4, 3, 3, 3, 2, 2, 2, 3, 3, 2,
410 2, 2, 2, 2, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
411 6, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 2, 2, 1, 2,
412 2, 1, 1, 2, 2, 2, 2, 1, 2, 1, 1, 2, 1, 4, 2, 2,
413 };
414
415 static const NvU16 EotfPQ512Entries[] = {
416 0x0000, 0x0001, 0x0003, 0x0005, 0x0008, 0x000C, 0x0011, 0x0016, 0x001B, 0x0022, 0x0028, 0x002F, 0x0037, 0x003F, 0x0048, 0x0051,
417 0x005A, 0x0064, 0x006F, 0x007A, 0x0085, 0x0091, 0x009E, 0x00AB, 0x00B8, 0x00C6, 0x00D4, 0x00E3, 0x00F3, 0x0102, 0x0113, 0x0123,
418 0x0135, 0x0146, 0x0158, 0x016B, 0x017E, 0x0192, 0x01A6, 0x01BB, 0x01D0, 0x01E5, 0x01FC, 0x0212, 0x0229, 0x0241, 0x0259, 0x0272,
419 0x028B, 0x02A4, 0x02BE, 0x02D9, 0x02F4, 0x0310, 0x032C, 0x0349, 0x0366, 0x0384, 0x03A2, 0x03C1, 0x03E0, 0x0400, 0x0421, 0x0442,
420 0x0463, 0x0485, 0x04A8, 0x04CB, 0x04EF, 0x0513, 0x0538, 0x055D, 0x0583, 0x05AA, 0x05D1, 0x05F9, 0x0621, 0x064A, 0x0673, 0x069D,
421 0x06C7, 0x06F3, 0x071E, 0x074B, 0x0777, 0x07A5, 0x07D3, 0x0801, 0x0819, 0x0830, 0x0849, 0x0861, 0x087A, 0x0893, 0x08AD, 0x08C7,
422 0x08E1, 0x08FB, 0x0916, 0x0931, 0x094C, 0x0968, 0x0984, 0x09A0, 0x09BD, 0x09DA, 0x09F7, 0x0A15, 0x0A33, 0x0A51, 0x0A70, 0x0A8F,
423 0x0AAE, 0x0ACE, 0x0AEE, 0x0B0E, 0x0B2F, 0x0B50, 0x0B71, 0x0B93, 0x0BB5, 0x0BD7, 0x0BFA, 0x0C0F, 0x0C20, 0x0C32, 0x0C44, 0x0C56,
424 0x0C69, 0x0CB5, 0x0D03, 0x0D55, 0x0DA9, 0x0E01, 0x0E5B, 0x0EB9, 0x0F1B, 0x0F7F, 0x0FE7, 0x1029, 0x1061, 0x109A, 0x10D5, 0x1111,
425 0x1150, 0x1190, 0x11D3, 0x1217, 0x125E, 0x12A6, 0x12F0, 0x133D, 0x138B, 0x13DC, 0x1417, 0x1442, 0x146D, 0x149A, 0x14C8, 0x14F7,
426 0x1527, 0x1558, 0x158B, 0x15BF, 0x15F4, 0x162A, 0x1662, 0x169B, 0x16D5, 0x1711, 0x174E, 0x178C, 0x17CC, 0x1806, 0x1828, 0x184A,
427 0x186D, 0x18B4, 0x18FF, 0x194D, 0x199E, 0x19F3, 0x1A4B, 0x1AA7, 0x1B06, 0x1B37, 0x1B69, 0x1B9B, 0x1BCF, 0x1C02, 0x1C1D, 0x1C38,
428 0x1C54, 0x1C70, 0x1C8D, 0x1CAB, 0x1CC9, 0x1CE7, 0x1D06, 0x1D26, 0x1D46, 0x1D88, 0x1DCC, 0x1E13, 0x1E5C, 0x1EA8, 0x1EF6, 0x1F47,
429 0x1F9A, 0x1FF1, 0x2025, 0x2053, 0x2082, 0x20B3, 0x20E6, 0x211A, 0x214F, 0x2187, 0x21C0, 0x21FA, 0x2237, 0x2275, 0x22B5, 0x22F7,
430 0x233B, 0x23C9, 0x2430, 0x247F, 0x24D3, 0x252B, 0x2589, 0x25EB, 0x2653, 0x26C1, 0x2734, 0x27AD, 0x2817, 0x2838, 0x285A, 0x287C,
431 0x28A0, 0x28C5, 0x28EA, 0x2911, 0x2938, 0x2960, 0x298A, 0x29B4, 0x29DF, 0x2A0C, 0x2A39, 0x2A68, 0x2A98, 0x2AFA, 0x2B62, 0x2BCE,
432 0x2C20, 0x2C5B, 0x2C99, 0x2CDA, 0x2D1E, 0x2D65, 0x2DB0, 0x2DFD, 0x2E4E, 0x2EA3, 0x2EFC, 0x2F58, 0x2FB8, 0x300E, 0x3043, 0x307A,
433 0x30B3, 0x30D0, 0x30EE, 0x310D, 0x312C, 0x314C, 0x316D, 0x318E, 0x31B0, 0x31D3, 0x31F6, 0x321A, 0x323F, 0x3265, 0x328B, 0x32B2,
434 0x32DA, 0x332D, 0x3383, 0x33DC, 0x341D, 0x344D, 0x347F, 0x34B4, 0x34EA, 0x3523, 0x355E, 0x359B, 0x35DB, 0x361D, 0x3662, 0x36A9,
435 0x36F3, 0x3740, 0x3791, 0x37E4, 0x381D, 0x384A, 0x3879, 0x38A9, 0x38DB, 0x3910, 0x3946, 0x397E, 0x39B8, 0x39F5, 0x3A34, 0x3A75,
436 0x3AB9, 0x3AFF, 0x3B48, 0x3B94, 0x3BE2, 0x3C1A, 0x3C44, 0x3C70, 0x3C9D, 0x3CA0, 0x3CA3, 0x3CA6, 0x3CA9, 0x3CAC, 0x3CAF, 0x3CB1,
437 0x3CB4, 0x3CB7, 0x3CBA, 0x3CBD, 0x3CC0, 0x3CC3, 0x3CC6, 0x3CC9, 0x3CCC, 0x3CCF, 0x3CD2, 0x3CD5, 0x3CD8, 0x3CDB, 0x3CDE, 0x3CE1,
438 0x3CE4, 0x3CE7, 0x3CEA, 0x3CEE, 0x3CF1, 0x3CF4, 0x3CF7, 0x3CFA, 0x3CFD, 0x3D00, 0x3D03, 0x3D06, 0x3D09, 0x3D0D, 0x3D10, 0x3D13,
439 0x3D16, 0x3D19, 0x3D1C, 0x3D20, 0x3D23, 0x3D26, 0x3D29, 0x3D2C, 0x3D30, 0x3D33, 0x3D36, 0x3D39, 0x3D3D, 0x3D40, 0x3D43, 0x3D46,
440 0x3D4A, 0x3D4D, 0x3D50, 0x3D54, 0x3D57, 0x3D5A, 0x3D5D, 0x3D61, 0x3D64, 0x3D9B, 0x3DD3, 0x3E0D, 0x3E4A, 0x3E89, 0x3ECA, 0x3F0E,
441 0x3F54, 0x3F9C, 0x3FE8, 0x401B, 0x4043, 0x406D, 0x4099, 0x40C6, 0x40F4, 0x4124, 0x4156, 0x418A, 0x41C0, 0x41F8, 0x4232, 0x426D,
442 0x42AB, 0x42EB, 0x432E, 0x4373, 0x43BA, 0x4428, 0x4479, 0x44D0, 0x452D, 0x4591, 0x45FC, 0x466F, 0x46EB, 0x472C, 0x476F, 0x47B5,
443 0x47FE, 0x4824, 0x484B, 0x4874, 0x489D, 0x48F5, 0x4954, 0x4986, 0x49B9, 0x49EF, 0x4A26, 0x4A5F, 0x4A9B, 0x4AD9, 0x4B19, 0x4B9F,
444 0x4C18, 0x4C66, 0x4CBA, 0x4CE6, 0x4D13, 0x4D43, 0x4D74, 0x4DA7, 0x4DDC, 0x4E12, 0x4E4B, 0x4E86, 0x4EC3, 0x4F02, 0x4F44, 0x4F88,
445 0x4FCE, 0x500C, 0x5032, 0x5082, 0x50D8, 0x5106, 0x5135, 0x5166, 0x5199, 0x5205, 0x5278, 0x52F5, 0x537C, 0x53C3, 0x5406, 0x542D,
446 0x5454, 0x54A9, 0x5503, 0x550F, 0x551B, 0x5527, 0x5533, 0x5540, 0x554C, 0x5559, 0x5565, 0x5572, 0x557F, 0x558C, 0x5599, 0x55A7,
447 0x55B4, 0x55C1, 0x55CF, 0x5607, 0x5641, 0x567E, 0x56BC, 0x56FE, 0x5741, 0x5788, 0x57D1,
448 };
449
450 #define TMO_LUT_NUM_SEGMENTS 64
451 #define TMO_LUT_SEG_SIZE_LOG2 4
452 #define TMO_LUT_NUM_ENTRIES 1024
453
454 struct TmoLutSettings
455 {
456 NvU32 satMode;
457 NvU32 lowIntensityZoneEnd;
458 NvU32 lowIntensityValueLinWeight;
459 NvU32 lowIntensityValueNonLinWeight;
460 NvU32 lowIntensityValueThreshold;
461
462 NvU32 medIntensityZoneStart;
463 NvU32 medIntensityZoneEnd;
464 NvU32 medIntensityValueLinWeight;
465 NvU32 medIntensityValueNonLinWeight;
466 NvU32 medIntensityValueThreshold;
467
468 NvU32 highIntensityZoneStart;
469 NvU32 highIntensityValueLinWeight;
470 NvU32 highIntensityValueNonLinWeight;
471 NvU32 highIntensityValueThreshold;
472 };
473
474 // Default Rec.2020 weights, no color correction.
475 static const struct TmoLutSettings TMO_LUT_SETTINGS_REC2020 = { 2, 1280, 256, 256, 255, 4960, 4961, 256, 256, 255, 10640, 256, 256, 255 };
476
InitCsc0LUT(NVEvoChannelPtr pChannel,const NvU32 * pSegmentSizes,NvU32 numSegmentSizes,const NvU16 * pLUTEntries,NvU32 numEntries)477 static void InitCsc0LUT(NVEvoChannelPtr pChannel,
478 const NvU32 *pSegmentSizes, NvU32 numSegmentSizes,
479 const NvU16 *pLUTEntries, NvU32 numEntries)
480 {
481 NvU32 i;
482
483 for (i = 0; i < numSegmentSizes; i++) {
484 nvDmaSetStartEvoMethod(pChannel, NVC57E_SET_CSC0LUT_SEGMENT_SIZE, 1);
485 nvDmaSetEvoMethodData(pChannel,
486 DRF_NUM(C57E, _SET_CSC0LUT_SEGMENT_SIZE, _IDX, i) |
487 DRF_NUM(C57E, _SET_CSC0LUT_SEGMENT_SIZE, _VALUE, pSegmentSizes[i]));
488 }
489
490 for (i = 0; i < numEntries; i++) {
491 nvDmaSetStartEvoMethod(pChannel, NVC57E_SET_CSC0LUT_ENTRY, 1);
492 nvDmaSetEvoMethodData(pChannel,
493 DRF_NUM(C57E, _SET_CSC0LUT_ENTRY, _IDX, i) |
494 DRF_NUM(C57E, _SET_CSC0LUT_ENTRY, _VALUE, pLUTEntries[i]));
495 }
496 }
497
InitCsc1LUT(NVEvoChannelPtr pChannel,const NvU32 * pSegmentSizes,NvU32 numSegmentSizes,const NvU16 * pLUTEntries,NvU32 numEntries)498 static void InitCsc1LUT(NVEvoChannelPtr pChannel,
499 const NvU32 *pSegmentSizes, NvU32 numSegmentSizes,
500 const NvU16 *pLUTEntries, NvU32 numEntries)
501 {
502 NvU32 i;
503
504 for (i = 0; i < numSegmentSizes; i++) {
505 nvDmaSetStartEvoMethod(pChannel, NVC57E_SET_CSC1LUT_SEGMENT_SIZE, 1);
506 nvDmaSetEvoMethodData(pChannel,
507 DRF_NUM(C57E, _SET_CSC1LUT_SEGMENT_SIZE, _IDX, i) |
508 DRF_NUM(C57E, _SET_CSC1LUT_SEGMENT_SIZE, _VALUE, pSegmentSizes[i]));
509 }
510
511 for (i = 0; i < numEntries; i++) {
512 nvDmaSetStartEvoMethod(pChannel, NVC57E_SET_CSC1LUT_ENTRY, 1);
513 nvDmaSetEvoMethodData(pChannel,
514 DRF_NUM(C57E, _SET_CSC1LUT_ENTRY, _IDX, i) |
515 DRF_NUM(C57E, _SET_CSC1LUT_ENTRY, _VALUE, pLUTEntries[i]));
516 }
517 }
518
ConfigureCsc0C5(NVDevEvoPtr pDevEvo,NVEvoChannelPtr pChannel,enum NvKmsInputColorSpace colorspace,NvBool enable)519 static void ConfigureCsc0C5(NVDevEvoPtr pDevEvo,
520 NVEvoChannelPtr pChannel,
521 enum NvKmsInputColorSpace colorspace,
522 NvBool enable)
523 {
524 NVEvoWindowCaps *pWinCaps =
525 &pDevEvo->gpus[0].capabilities.window[pChannel->instance];
526 struct NvKmsCscMatrix matrix = { };
527 NvU32 lutData = 0;
528 NvU32 csc01Data = 0;
529
530 if (!pWinCaps->csc0MatricesPresent) {
531 return;
532 }
533
534 if (enable) {
535 if (colorspace == NVKMS_INPUT_COLORSPACE_BT2100_PQ) {
536 matrix = Rec2020RGBToLMS;
537 } else {
538 matrix = Rec709RGBToLMS;
539 }
540
541 lutData |= DRF_DEF(C57E, _SET_CSC0LUT_CONTROL, _INTERPOLATE, _ENABLE) |
542 DRF_DEF(C57E, _SET_CSC0LUT_CONTROL, _MIRROR, _DISABLE) |
543 DRF_DEF(C57E, _SET_CSC0LUT_CONTROL, _ENABLE, _ENABLE);
544
545 csc01Data |= DRF_DEF(C57E, _SET_CSC01CONTROL, _ENABLE, _ENABLE);
546 } else {
547 matrix = NVKMS_IDENTITY_CSC_MATRIX;
548
549 lutData |= DRF_DEF(C57E, _SET_CSC0LUT_CONTROL, _INTERPOLATE, _DISABLE) |
550 DRF_DEF(C57E, _SET_CSC0LUT_CONTROL, _MIRROR, _DISABLE) |
551 DRF_DEF(C57E, _SET_CSC0LUT_CONTROL, _ENABLE, _DISABLE);
552
553 csc01Data |= DRF_DEF(C57E, _SET_CSC01CONTROL, _ENABLE, _DISABLE);
554 }
555
556 /* Linear RGB FP16 -> Linear LMS FP16 */
557 SetCsc00MatrixC5(pChannel, &matrix);
558
559 /* Linear LMS FP16 -> PQ encoded L'M'S' fixed-point */
560 nvDmaSetStartEvoMethod(pChannel, NVC57E_SET_CSC0LUT_CONTROL, 1);
561 nvDmaSetEvoMethodData(pChannel, lutData);
562
563 /*
564 * PQ encoded L'M'S' fixed-point -> ICtCp
565 *
566 * Note that we're converting between fixed colorspaces, so the default HW
567 * coefficients are sufficient.
568 */
569 nvDmaSetStartEvoMethod(pChannel, NVC57E_SET_CSC01CONTROL, 1);
570 nvDmaSetEvoMethodData(pChannel, csc01Data);
571 }
572
maxF(float64_t a,float64_t b)573 static inline float64_t maxF(float64_t a, float64_t b)
574 {
575 return f64_lt(a, b) ? b : a;
576 }
577
clampF(float64_t value,float64_t min,float64_t max)578 static inline float64_t clampF(float64_t value, float64_t min, float64_t max)
579 {
580 value = maxF(value, min);
581 value = f64_lt(max, value) ? max : value;
582 return value;
583 }
584
PQEotf(float64_t colorValue,NvBool inverse)585 static float64_t PQEotf(float64_t colorValue, NvBool inverse)
586 {
587 const float64_t zero = {0x0000000000000000}; // 0.0
588 const float64_t one = {0x3FF0000000000000}; // 1.0
589 const float64_t m1 = {0x3FC463FFFFFFB9A2}; // 0.1593017578125
590 const float64_t m2 = {0x4053B60000000000}; // 78.84375
591 const float64_t c1 = {0x3FEAC00000000000}; // 0.8359375
592 const float64_t c2 = {0x4032DA0000000000}; // 18.8515625
593 const float64_t c3 = {0x4032B00000000000}; // 18.6875
594
595 const float64_t invm1 = {0x40191C0D56E72ABA}; // 1/m1 = 6.27739463602
596 const float64_t invm2 = {0x3F89F9B585D7C997}; // 1/m2 = 0.01268331351
597
598 if (inverse) {
599 // Convert from linear to PQ-encoded values.
600 float64_t L = clampF(colorValue, zero, one);
601 float64_t powLm1 = nvKmsPow(L, m1);
602 float64_t N = nvKmsPow(f64_div(f64_add(c1, f64_mul(c2, powLm1)),
603 f64_add(one, f64_mul(c3, powLm1))), m2);
604
605 return clampF(N, zero, one);
606 } else {
607 // Convert from PQ-encoded values to linear values.
608 float64_t N = clampF(colorValue, zero, one);
609 float64_t powNinvM2 = nvKmsPow(N, invm2);
610 float64_t L = nvKmsPow(f64_div(maxF(f64_sub(powNinvM2, c1), zero),
611 f64_sub(c2, f64_mul(c3, powNinvM2))),
612 invm1);
613
614 return clampF(L, zero, one);
615 }
616 }
617
618 // Hermite spline
P(float64_t B,float64_t KS,float64_t maxLum)619 static float64_t P(float64_t B, float64_t KS, float64_t maxLum)
620 {
621 const float64_t one = {0x3FF0000000000000}; // 1.0
622 const float64_t two = {0x4000000000000000}; // 2.0
623 const float64_t negtwo = {0xC000000000000000}; // -2.0
624 const float64_t three = {0x4008000000000000}; // 3.0
625
626 float64_t t = f64_div(f64_sub(B, KS), f64_sub(one, KS));
627 float64_t t2 = f64_mul(t, t);
628 float64_t t3 = f64_mul(t2, t);
629
630 return
631 f64_add(f64_add(
632 f64_mul(f64_add(f64_sub(f64_mul(two, t3), f64_mul(three, t2)), one), KS),
633 f64_mul(f64_add(f64_sub(t3, f64_mul(two, t2)), t), f64_sub(one, KS))),
634 f64_mul(f64_add(f64_mul(negtwo, t3), f64_mul(three, t2)), maxLum));
635 }
636
637 /*
638 * PQ tone mapping operator with no remapping of blacks or "toe" section of
639 * curve. Messing with nonlinearity and remapping in the SDR portion of the
640 * curve results in bad looking PC desktop and game content.
641 *
642 * Lmax = InvPQEotf(targetMaxLum/10000.0)
643 * Lw = InvPQEotf(srcMaxLum/10000.0)
644 * maxLumRatio = Lmax/Lw
645 * KS = 1.5*maxLumRatio - 0.5
646 * KSEqualsOne = (KS == 1.0)
647 *
648 * XXX HDR TODO: Remap blacks and implement toe section for video content?
649 */
TmoLutEntry(NvU32 i,const float64_t Lmax,const float64_t Lw,const float64_t maxLumRatio,const float64_t KS,const NvBool KSEqualsOne)650 static NvU16 TmoLutEntry(NvU32 i,
651 const float64_t Lmax,
652 const float64_t Lw,
653 const float64_t maxLumRatio,
654 const float64_t KS,
655 const NvBool KSEqualsOne)
656 {
657 const float64_t zero = {0x0000000000000000}; // 0.0
658 const float64_t maxIntensity = {0x40CFFF8000000000}; // 16383.0
659
660 float64_t outputF;
661 float64_t inputF =
662 f64_div(ui32_to_f64(i), ui32_to_f64(TMO_LUT_NUM_ENTRIES - 1));
663
664 float64_t E1;
665 float64_t E2;
666
667 E1 = f64_div(inputF, Lw);
668
669 if (KSEqualsOne || f64_lt(E1, KS)) {
670 E2 = E1;
671 } else {
672 E2 = P(E1, KS, maxLumRatio);
673 }
674
675 outputF = clampF(f64_mul(E2, Lw), zero, Lmax);
676
677 return (NvU16) f64_to_ui32(clampF(f64_mul(outputF, maxIntensity),
678 zero, maxIntensity),
679 softfloat_round_near_even, FALSE) << 2;
680 }
681
InitializeTmoLut(const NVEvoChannelPtr pChannel,NVLutSurfaceEvoPtr pLutSurfaceEvo,NvU32 sd)682 static void InitializeTmoLut(const NVEvoChannelPtr pChannel,
683 NVLutSurfaceEvoPtr pLutSurfaceEvo,
684 NvU32 sd)
685 {
686 NVEvoLutDataRec *pData = pLutSurfaceEvo->subDeviceAddress[sd];
687 NvU64 vssHead = 0;
688 NvU32 lutEntryCounter = 0, i;
689
690 // Precalculate constants for TmoLutEntry().
691 const float64_t tenThousand = {0x40C3880000000000}; // 10000.0
692 const float64_t one = {0x3FF0000000000000}; // 1.0
693 const float64_t half = {0x3FE0000000000000}; // 0.5
694 const float64_t oneHalf = {0x3FF8000000000000}; // 1.5
695 // Lmax = InvPQEotf(targetMaxLum/10,000)
696 const float64_t Lmax =
697 PQEotf(f64_div(ui32_to_f64(pChannel->tmoParams.targetMaxLums[sd]),
698 tenThousand), TRUE);
699 // Lw = InvPQEotf(srcMaxLum/10,000)
700 const float64_t Lw =
701 PQEotf(f64_div(ui32_to_f64(pChannel->tmoParams.srcMaxLum),
702 tenThousand), TRUE);
703 // maxLumRatio = Lmax/Lw
704 const float64_t maxLumRatio = f64_div(Lmax, Lw);
705 // KS = 1.5*maxLumRatio - 0.5
706 const float64_t KS = f64_sub(f64_mul(oneHalf, maxLumRatio), half);
707 // KSEqualsOne = (KS == 1.0)
708 const NvBool KSEqualsOne = f64_eq(KS, one);
709
710 nvAssert(pChannel->tmoParams.srcMaxLum >=
711 pChannel->tmoParams.targetMaxLums[sd]);
712
713 // VSS Header
714 for (lutEntryCounter = 0; lutEntryCounter < NV_LUT_VSS_HEADER_SIZE; lutEntryCounter++) {
715 vssHead = 0;
716 for (i = 0; ((i < 16) && (((lutEntryCounter * 16) + i) < TMO_LUT_NUM_SEGMENTS)); i++) {
717 NvU64 temp = TMO_LUT_SEG_SIZE_LOG2;
718 vssHead |= temp << (i * 3);
719 }
720 nvkms_memcpy(&(pData->base[lutEntryCounter]), &vssHead, sizeof(NVEvoLutEntryRec));
721 }
722
723 for (i = 0; i < TMO_LUT_NUM_ENTRIES; i++) {
724 pData->base[i + NV_LUT_VSS_HEADER_SIZE].Red =
725 pData->base[i + NV_LUT_VSS_HEADER_SIZE].Green =
726 pData->base[i + NV_LUT_VSS_HEADER_SIZE].Blue =
727 TmoLutEntry(i, Lmax, Lw, maxLumRatio, KS, KSEqualsOne);
728 }
729
730 // Copy the last entry for interpolation
731 pData->base[TMO_LUT_NUM_ENTRIES + NV_LUT_VSS_HEADER_SIZE].Red =
732 pData->base[TMO_LUT_NUM_ENTRIES + NV_LUT_VSS_HEADER_SIZE - 1].Red;
733 pData->base[TMO_LUT_NUM_ENTRIES + NV_LUT_VSS_HEADER_SIZE].Blue =
734 pData->base[TMO_LUT_NUM_ENTRIES + NV_LUT_VSS_HEADER_SIZE - 1].Blue;
735 pData->base[TMO_LUT_NUM_ENTRIES + NV_LUT_VSS_HEADER_SIZE].Green =
736 pData->base[TMO_LUT_NUM_ENTRIES + NV_LUT_VSS_HEADER_SIZE - 1].Green;
737 }
738
UpdateTmoParams(NVEvoChannelPtr pChannel,NvBool enabled,NvU32 srcMaxLum,const NvU32 targetMaxLums[NVKMS_MAX_SUBDEVICES])739 static NvBool UpdateTmoParams(NVEvoChannelPtr pChannel,
740 NvBool enabled,
741 NvU32 srcMaxLum,
742 const NvU32 targetMaxLums[NVKMS_MAX_SUBDEVICES])
743 {
744 NvU16 sd;
745 NvBool dirty = FALSE;
746
747 if (pChannel->tmoParams.enabled != enabled) {
748 pChannel->tmoParams.enabled = enabled;
749 dirty = TRUE;
750 }
751
752 if (pChannel->tmoParams.srcMaxLum != srcMaxLum) {
753 pChannel->tmoParams.srcMaxLum = srcMaxLum;
754 dirty = TRUE;
755 }
756
757 for (sd = 0; sd < NVKMS_MAX_SUBDEVICES; sd++) {
758 if (pChannel->tmoParams.targetMaxLums[sd] != targetMaxLums[sd]) {
759 pChannel->tmoParams.targetMaxLums[sd] = targetMaxLums[sd];
760 dirty = TRUE;
761 }
762 }
763
764 return dirty;
765 }
766
EvoSetTmoLutSurfaceAddressC5(NVEvoChannelPtr pChannel,const NVSurfaceDescriptor * pSurfaceDesc,NvU32 offset)767 static void EvoSetTmoLutSurfaceAddressC5(
768 NVEvoChannelPtr pChannel,
769 const NVSurfaceDescriptor *pSurfaceDesc,
770 NvU32 offset)
771 {
772 NvU32 ctxDmaHandle = pSurfaceDesc ? pSurfaceDesc->ctxDmaHandle : 0;
773
774 nvDmaSetStartEvoMethod(pChannel, NVC57E_SET_CONTEXT_DMA_TMO_LUT, 1);
775 nvDmaSetEvoMethodData(pChannel,
776 DRF_NUM(C57E, _SET_CONTEXT_DMA_TMO_LUT, _HANDLE, ctxDmaHandle));
777
778 nvDmaSetStartEvoMethod(pChannel, NVC57E_SET_OFFSET_TMO_LUT, 1);
779 nvDmaSetEvoMethodData(pChannel,
780 DRF_NUM(C57E, _SET_OFFSET_TMO_LUT, _ORIGIN, offset >> 8));
781 }
782
ConfigureTmoLut(NVDevEvoPtr pDevEvo,const NVFlipChannelEvoHwState * pHwState,NVEvoChannelPtr pChannel)783 static void ConfigureTmoLut(NVDevEvoPtr pDevEvo,
784 const NVFlipChannelEvoHwState *pHwState,
785 NVEvoChannelPtr pChannel)
786 {
787 NvU16 sd;
788 const NvU32 win = NV_EVO_CHANNEL_MASK_WINDOW_NUMBER(pChannel->channelMask);
789 const NvU32 head = pDevEvo->headForWindow[win];
790 const NvU32 offset = offsetof(NVEvoLutDataRec, base);
791 const struct TmoLutSettings *tmoLutSettings;
792 const NvU32 srcMaxLum = nvGetHDRSrcMaxLum(pHwState);
793
794 NvBool needsTmoLut = FALSE;
795 NvU32 targetMaxLums[NVKMS_MAX_SUBDEVICES] = {0};
796 for (sd = 0; sd < pDevEvo->numSubDevices; sd++) {
797 const NVDispHeadStateEvoRec *pHeadState =
798 &pDevEvo->pDispEvo[sd]->headState[head];
799
800 targetMaxLums[sd] = pHeadState->hdrInfoFrame.staticMetadata.maxCLL;
801
802 // If any head needs tone mapping, enable TMO for channel
803 if (nvNeedsTmoLut(pDevEvo, pChannel, pHwState,
804 srcMaxLum, targetMaxLums[sd])) {
805 needsTmoLut = TRUE;
806 }
807 }
808
809 if (!UpdateTmoParams(pChannel, needsTmoLut, srcMaxLum, targetMaxLums)) {
810 // No change in parameters, no need to reconfigure.
811 return;
812 }
813
814 if (!pChannel->tmoParams.enabled) {
815 pDevEvo->hal->SetTmoLutSurfaceAddress(pChannel,
816 NULL /* pSurfaceDesc */, 0 /* offset */);
817 return;
818 }
819
820 // Initialize TMO LUT on all subdevices
821 for (sd = 0; sd < pDevEvo->numSubDevices; sd++) {
822 nvAssert(pHwState->tmoLut.pLutSurfaceEvo != NULL);
823 InitializeTmoLut(pChannel, pHwState->tmoLut.pLutSurfaceEvo, sd);
824 }
825
826 // Program TMO LUT
827
828 // XXX HDR TODO: Support other transfer functions
829 tmoLutSettings = &TMO_LUT_SETTINGS_REC2020;
830
831 nvDmaSetStartEvoMethod(pChannel, NVC57E_SET_TMO_CONTROL, 1);
832 nvDmaSetEvoMethodData(pChannel,
833 DRF_NUM(C57E, _SET_TMO_CONTROL, _SIZE,
834 NV_LUT_VSS_HEADER_SIZE + TMO_LUT_NUM_ENTRIES + 1) |
835 DRF_DEF(C57E, _SET_TMO_CONTROL, _INTERPOLATE, _ENABLE) |
836 DRF_NUM(C57E, _SET_TMO_CONTROL, _SAT_MODE, tmoLutSettings->satMode));
837
838 pDevEvo->hal->SetTmoLutSurfaceAddress(pChannel,
839 &pHwState->tmoLut.pLutSurfaceEvo->surfaceDesc, offset);
840
841 // Low Intensity
842
843 nvDmaSetStartEvoMethod(pChannel, NVC57E_SET_TMO_LOW_INTENSITY_ZONE, 1);
844 nvDmaSetEvoMethodData(pChannel,
845 DRF_NUM(C57E, _SET_TMO_LOW_INTENSITY_ZONE, _END,
846 tmoLutSettings->lowIntensityZoneEnd));
847
848 nvDmaSetStartEvoMethod(pChannel, NVC57E_SET_TMO_LOW_INTENSITY_VALUE, 1);
849 nvDmaSetEvoMethodData(pChannel,
850 DRF_NUM(C57E, _SET_TMO_LOW_INTENSITY_VALUE, _LIN_WEIGHT,
851 tmoLutSettings->lowIntensityValueLinWeight) |
852 DRF_NUM(C57E, _SET_TMO_LOW_INTENSITY_VALUE, _NON_LIN_WEIGHT,
853 tmoLutSettings->lowIntensityValueNonLinWeight) |
854 DRF_NUM(C57E, _SET_TMO_LOW_INTENSITY_VALUE, _THRESHOLD,
855 tmoLutSettings->lowIntensityValueThreshold));
856
857 // Medium Intensity
858
859 nvDmaSetStartEvoMethod(pChannel, NVC57E_SET_TMO_MEDIUM_INTENSITY_ZONE, 1);
860 nvDmaSetEvoMethodData(pChannel,
861 DRF_NUM(C57E, _SET_TMO_MEDIUM_INTENSITY_ZONE, _START,
862 tmoLutSettings->medIntensityZoneStart) |
863 DRF_NUM(C57E, _SET_TMO_MEDIUM_INTENSITY_ZONE, _END,
864 tmoLutSettings->medIntensityZoneEnd));
865
866 nvDmaSetStartEvoMethod(pChannel, NVC57E_SET_TMO_MEDIUM_INTENSITY_VALUE, 1);
867 nvDmaSetEvoMethodData(pChannel,
868 DRF_NUM(C57E, _SET_TMO_MEDIUM_INTENSITY_VALUE, _LIN_WEIGHT,
869 tmoLutSettings->medIntensityValueLinWeight) |
870 DRF_NUM(C57E, _SET_TMO_MEDIUM_INTENSITY_VALUE, _NON_LIN_WEIGHT,
871 tmoLutSettings->medIntensityValueNonLinWeight) |
872 DRF_NUM(C57E, _SET_TMO_MEDIUM_INTENSITY_VALUE, _THRESHOLD,
873 tmoLutSettings->medIntensityValueThreshold));
874
875 // High Intensity
876
877 nvDmaSetStartEvoMethod(pChannel, NVC57E_SET_TMO_HIGH_INTENSITY_ZONE, 1);
878 nvDmaSetEvoMethodData(pChannel,
879 DRF_NUM(C57E, _SET_TMO_HIGH_INTENSITY_ZONE, _START,
880 tmoLutSettings->highIntensityZoneStart));
881
882 nvDmaSetStartEvoMethod(pChannel, NVC57E_SET_TMO_HIGH_INTENSITY_VALUE, 1);
883 nvDmaSetEvoMethodData(pChannel,
884 DRF_NUM(C57E, _SET_TMO_HIGH_INTENSITY_VALUE, _LIN_WEIGHT,
885 tmoLutSettings->highIntensityValueLinWeight) |
886 DRF_NUM(C57E, _SET_TMO_HIGH_INTENSITY_VALUE, _NON_LIN_WEIGHT,
887 tmoLutSettings->highIntensityValueNonLinWeight) |
888 DRF_NUM(C57E, _SET_TMO_HIGH_INTENSITY_VALUE, _THRESHOLD,
889 tmoLutSettings->highIntensityValueThreshold));
890 }
891
ConfigureCsc1C5(NVDevEvoPtr pDevEvo,NVEvoChannelPtr pChannel,NvBool enable)892 static void ConfigureCsc1C5(NVDevEvoPtr pDevEvo,
893 NVEvoChannelPtr pChannel,
894 NvBool enable)
895 {
896 NVEvoWindowCaps *pWinCaps =
897 &pDevEvo->gpus[0].capabilities.window[pChannel->instance];
898 struct NvKmsCscMatrix matrix = { };
899 NvU32 lutData = 0;
900 NvU32 csc10Data = 0;
901 const NvU32 win = NV_EVO_CHANNEL_MASK_WINDOW_NUMBER(pChannel->channelMask);
902 const NvU32 head = pDevEvo->headForWindow[win];
903
904 if (!pWinCaps->csc1MatricesPresent || (head == NV_INVALID_HEAD)) {
905 return;
906 }
907
908 if (enable) {
909 const NvU32 sdMask = nvPeekEvoSubDevMask(pDevEvo);
910 const NvU32 sd = (sdMask == 0) ? 0 : nv_ffs(sdMask) - 1;
911 const NVDispHeadStateEvoRec *pHeadState;
912
913 /*
914 * All callers of this path should push a single sd on the stack,
915 * so that ffs(sdMask) is safe.
916 */
917 nvAssert(nvPopCount32(sdMask) == 1);
918
919 pHeadState = &pDevEvo->pDispEvo[sd]->headState[head];
920
921 // If postcomp is PQ, composite in Rec2020
922 if (pHeadState->tf == NVKMS_OUTPUT_TF_PQ) {
923 matrix = LMSToRec2020RGB;
924 } else {
925 matrix = LMSToRec709RGB;
926 }
927
928 lutData |= DRF_DEF(C57E, _SET_CSC1LUT_CONTROL, _INTERPOLATE, _ENABLE) |
929 DRF_DEF(C57E, _SET_CSC1LUT_CONTROL, _MIRROR, _DISABLE) |
930 DRF_DEF(C57E, _SET_CSC1LUT_CONTROL, _ENABLE, _ENABLE);
931
932 csc10Data |= DRF_DEF(C57E, _SET_CSC10CONTROL, _ENABLE, _ENABLE);
933 } else {
934 matrix = NVKMS_IDENTITY_CSC_MATRIX;
935
936 lutData |= DRF_DEF(C57E, _SET_CSC1LUT_CONTROL, _INTERPOLATE, _DISABLE) |
937 DRF_DEF(C57E, _SET_CSC1LUT_CONTROL, _MIRROR, _DISABLE) |
938 DRF_DEF(C57E, _SET_CSC1LUT_CONTROL, _ENABLE, _DISABLE);
939
940 csc10Data |= DRF_DEF(C57E, _SET_CSC10CONTROL, _ENABLE, _DISABLE);
941 }
942
943 /*
944 * ICtCp -> PQ encoded L'M'S' fixed-point
945 *
946 * Note that we're converting between fixed colorspaces, so the default HW
947 * coefficients are sufficient.
948 */
949 nvDmaSetStartEvoMethod(pChannel, NVC57E_SET_CSC10CONTROL, 1);
950 nvDmaSetEvoMethodData(pChannel, csc10Data);
951
952 /* PQ encoded L'M'S' fixed-point -> Linear LMS FP16 */
953 nvDmaSetStartEvoMethod(pChannel, NVC57E_SET_CSC1LUT_CONTROL, 1);
954 nvDmaSetEvoMethodData(pChannel, lutData);
955
956 /* Linear LMS FP16 -> Linear RGB FP16 */
957 SetCsc11MatrixC5(pChannel, &matrix);
958 }
959
InitDesktopColorC3(NVDevEvoPtr pDevEvo,NVEvoChannelPtr pChannel)960 static void InitDesktopColorC3(NVDevEvoPtr pDevEvo, NVEvoChannelPtr pChannel)
961 {
962 NvU32 head;
963
964 for (head = 0; head < pDevEvo->numHeads; head++) {
965 nvDmaSetStartEvoMethod(pChannel, NVC37D_HEAD_SET_DESKTOP_COLOR(head), 1);
966 nvDmaSetEvoMethodData(pChannel,
967 DRF_NUM(C37D, _HEAD_SET_DESKTOP_COLOR, _RED, 0) |
968 DRF_NUM(C37D, _HEAD_SET_DESKTOP_COLOR, _GREEN, 0) |
969 DRF_NUM(C37D, _HEAD_SET_DESKTOP_COLOR, _BLUE, 0) |
970 DRF_NUM(C37D, _HEAD_SET_DESKTOP_COLOR, _ALPHA, 255));
971 }
972 }
973
InitDesktopColorC5(NVDevEvoPtr pDevEvo,NVEvoChannelPtr pChannel)974 static void InitDesktopColorC5(NVDevEvoPtr pDevEvo, NVEvoChannelPtr pChannel)
975 {
976 NvU32 head;
977
978 for (head = 0; head < pDevEvo->numHeads; head++) {
979 nvDmaSetStartEvoMethod(pChannel, NVC57D_HEAD_SET_DESKTOP_COLOR_ALPHA_RED(head), 1);
980 nvDmaSetEvoMethodData(pChannel,
981 DRF_NUM(C57D, _HEAD_SET_DESKTOP_COLOR_ALPHA_RED, _ALPHA, 255) |
982 DRF_NUM(C57D, _HEAD_SET_DESKTOP_COLOR_ALPHA_RED, _RED, 0));
983
984 nvDmaSetStartEvoMethod(pChannel, NVC57D_HEAD_SET_DESKTOP_COLOR_GREEN_BLUE(head), 1);
985 nvDmaSetEvoMethodData(pChannel,
986 DRF_NUM(C57D, _HEAD_SET_DESKTOP_COLOR_GREEN_BLUE, _GREEN, 0) |
987 DRF_NUM(C57D, _HEAD_SET_DESKTOP_COLOR_GREEN_BLUE, _BLUE, 0));
988 }
989 }
990
nvEvoInitChannel3(NVDevEvoPtr pDevEvo,NVEvoChannelPtr pChannel)991 void nvEvoInitChannel3(NVDevEvoPtr pDevEvo, NVEvoChannelPtr pChannel)
992 {
993 InitChannelCapsC3(pDevEvo, pChannel);
994 }
995
EvoInitChannelC3(NVDevEvoPtr pDevEvo,NVEvoChannelPtr pChannel)996 static void EvoInitChannelC3(NVDevEvoPtr pDevEvo, NVEvoChannelPtr pChannel)
997 {
998 const NvBool isCore =
999 FLD_TEST_DRF64(_EVO, _CHANNEL_MASK, _CORE, _ENABLE,
1000 pChannel->channelMask);
1001
1002 nvEvoInitChannel3(pDevEvo, pChannel);
1003
1004 if (isCore) {
1005 InitDesktopColorC3(pDevEvo, pChannel);
1006 }
1007 }
1008
EvoInitChannelC5(NVDevEvoPtr pDevEvo,NVEvoChannelPtr pChannel)1009 static void EvoInitChannelC5(NVDevEvoPtr pDevEvo, NVEvoChannelPtr pChannel)
1010 {
1011 const NvBool isCore =
1012 FLD_TEST_DRF64(_EVO, _CHANNEL_MASK, _CORE, _ENABLE,
1013 pChannel->channelMask);
1014 const NvBool isWindow =
1015 ((pChannel->channelMask & NV_EVO_CHANNEL_MASK_WINDOW_ALL) != 0);
1016
1017 nvEvoInitChannel3(pDevEvo, pChannel);
1018
1019 if (isCore) {
1020 InitTaps5ScalerCoefficientsC5(pDevEvo, pChannel, FALSE);
1021 InitDesktopColorC5(pDevEvo, pChannel);
1022 } else if (isWindow) {
1023 NVEvoWindowCaps *pWinCaps =
1024 &pDevEvo->gpus[0].capabilities.window[pChannel->instance];
1025 NvU32 csc0SizesLen = ARRAY_LEN(OetfPQ512SegSizesLog2);
1026 NvU32 csc0EntriesLen = ARRAY_LEN(OetfPQ512Entries);
1027 NvU32 csc1SizesLen = ARRAY_LEN(EotfPQ512SegSizesLog2);
1028 NvU32 csc1EntriesLen = ARRAY_LEN(EotfPQ512Entries);
1029
1030 InitTaps5ScalerCoefficientsC5(pDevEvo, pChannel, TRUE);
1031
1032 if (pWinCaps->cscLUTsPresent) {
1033 InitCsc0LUT(pChannel,
1034 OetfPQ512SegSizesLog2, csc0SizesLen,
1035 OetfPQ512Entries, csc0EntriesLen);
1036 InitCsc1LUT(pChannel,
1037 EotfPQ512SegSizesLog2, csc1SizesLen,
1038 EotfPQ512Entries, csc1EntriesLen);
1039 }
1040 }
1041 }
1042
EvoGetFMTMatrixC5(const enum NvKmsSurfaceMemoryFormat format,const NVFlipChannelEvoHwState * pHwState)1043 static const NvU32* EvoGetFMTMatrixC5(
1044 const enum NvKmsSurfaceMemoryFormat format,
1045 const NVFlipChannelEvoHwState *pHwState)
1046 {
1047 const NvU32* retValue = NULL;
1048 const NvKmsSurfaceMemoryFormatInfo *pFormatInfo =
1049 nvKmsGetSurfaceMemoryFormatInfo(format);
1050
1051 // Choose FMT matrix based on input colorspace, bpc, and colorrange.
1052 if (pFormatInfo->isYUV) {
1053 NvBool specifiedFull = (pHwState->colorRange == NVKMS_INPUT_COLORRANGE_FULL);
1054 if (pFormatInfo->yuv.depthPerComponent == 8) {
1055 if (specifiedFull) {
1056 retValue = FMTMatrix[FMT_COEFF_TYPE_REC709_YUV_8BPC_FULL_TO_RGB_16BPC_FULL];
1057 } else {
1058 retValue = FMTMatrix[FMT_COEFF_TYPE_REC709_YUV_8BPC_LTD_TO_RGB_16BPC_FULL];
1059 }
1060 } else if (pFormatInfo->yuv.depthPerComponent == 10) {
1061 if (specifiedFull) {
1062 retValue = FMTMatrix[FMT_COEFF_TYPE_REC709_YUV_10BPC_FULL_TO_RGB_16BPC_FULL];
1063 } else {
1064 retValue = FMTMatrix[FMT_COEFF_TYPE_REC709_YUV_10BPC_LTD_TO_RGB_16BPC_FULL];
1065 }
1066 } else if (pFormatInfo->yuv.depthPerComponent == 12) {
1067 if (specifiedFull) {
1068 retValue = FMTMatrix[FMT_COEFF_TYPE_REC709_YUV_12BPC_FULL_TO_RGB_16BPC_FULL];
1069 } else {
1070 retValue = FMTMatrix[FMT_COEFF_TYPE_REC709_YUV_12BPC_LTD_TO_RGB_16BPC_FULL];
1071 }
1072 } else {
1073 // Unsupported bit depth, fail silently by defaulting to identity.
1074 retValue = FMTMatrix[FMT_COEFF_TYPE_IDENTITY];
1075 }
1076 } else {
1077 // All inputs with RGB colorspace receive an identity FMT.
1078 retValue = FMTMatrix[FMT_COEFF_TYPE_IDENTITY];
1079 }
1080
1081 return retValue;
1082 }
1083
EvoSetFMTMatrixC5(NVEvoChannelPtr pChannel,const enum NvKmsSurfaceMemoryFormat format,const NVFlipChannelEvoHwState * pHwState)1084 static void EvoSetFMTMatrixC5(
1085 NVEvoChannelPtr pChannel, const enum NvKmsSurfaceMemoryFormat format,
1086 const NVFlipChannelEvoHwState *pHwState)
1087 {
1088 const NvU32 *matrix = EvoGetFMTMatrixC5(format, pHwState);
1089 NvU32 method = NVC57E_SET_FMT_COEFFICIENT_C00;
1090 int i;
1091
1092 for (i = 0; i < 12; i++) {
1093 nvDmaSetStartEvoMethod(pChannel, method, 1);
1094 nvDmaSetEvoMethodData(pChannel, matrix[i]);
1095
1096 method += 4;
1097 }
1098 }
1099
nvEvoInitDefaultLutC5(NVDevEvoPtr pDevEvo)1100 void nvEvoInitDefaultLutC5(NVDevEvoPtr pDevEvo)
1101 {
1102 NVLutSurfaceEvoPtr pLut = pDevEvo->lut.defaultLut;
1103 NvU16 sd;
1104
1105 nvAssert(pLut);
1106
1107 for (sd = 0; sd < pDevEvo->numSubDevices; sd++) {
1108 NvU32 lutSize;
1109 NvBool isLutModeVss;
1110 NVEvoLutDataRec *pData = pLut->subDeviceAddress[sd];
1111
1112 EvoSetupIdentityBaseLutC5(pData,
1113 &pDevEvo->lut.defaultBaseLUTState[sd],
1114 &lutSize, &isLutModeVss);
1115
1116 EvoSetupIdentityOutputLutC5(pData,
1117 &pDevEvo->lut.defaultOutputLUTState[sd],
1118 &lutSize, &isLutModeVss);
1119 }
1120 }
1121
EvoInitWindowMapping3(NVDevEvoPtr pDevEvo,NVEvoModesetUpdateState * pModesetUpdateState)1122 static void EvoInitWindowMapping3(NVDevEvoPtr pDevEvo,
1123 NVEvoModesetUpdateState *pModesetUpdateState)
1124 {
1125 NVEvoUpdateState *updateState = &pModesetUpdateState->updateState;
1126 NVEvoChannelPtr pChannel = pDevEvo->core;
1127 NvU32 win, sd;
1128
1129 nvAssert(pDevEvo->subDevMaskStackDepth > 0);
1130
1131 nvUpdateUpdateState(pDevEvo, updateState, pChannel);
1132
1133 /* Bind each window to a head. On GV100, there is a fixed mapping. */
1134 for (win = 0; win < pDevEvo->numWindows; win++) {
1135 NvU32 head = pDevEvo->headForWindow[win];
1136
1137 nvDmaSetStartEvoMethod(pChannel, NVC37D_WINDOW_SET_CONTROL(win), 1);
1138 if ((head == NV_INVALID_HEAD) || (head >= pDevEvo->numHeads)) {
1139 nvDmaSetEvoMethodData(pChannel,
1140 DRF_NUM(C37D, _WINDOW_SET_CONTROL, _OWNER,
1141 NVC37D_WINDOW_SET_CONTROL_OWNER_NONE));
1142 } else {
1143 nvDmaSetEvoMethodData(pChannel, DRF_NUM(C37D, _WINDOW_SET_CONTROL, _OWNER, head));
1144 }
1145 }
1146
1147 pModesetUpdateState->windowMappingChanged = FALSE;
1148
1149 for (sd = 0; sd < pDevEvo->numSubDevices; sd++) {
1150 void *pCoreDma = pDevEvo->pSubDevices[sd]->pCoreDma;
1151 /*
1152 * Short timeout (100ms) because we don't expect display to be very
1153 * busy at this point (it should at most be processing methods from
1154 * InitChannel()).
1155 */
1156 const NvU32 timeout = 100000;
1157 NvU64 startTime = 0;
1158
1159 if (!((nvPeekEvoSubDevMask(pDevEvo) & (1 << sd)))) {
1160 continue;
1161 }
1162
1163 /* This core channel must be idle before reading state cache */
1164 do {
1165 NvBool isIdle = NV_FALSE;
1166 if (!nvEvoIsChannelIdleC3(pDevEvo, pChannel, sd, &isIdle)) {
1167 nvEvoLogDevDebug(pDevEvo, EVO_LOG_ERROR, "nvEvoIsChannelIdleC3() failed!");
1168 }
1169 if (isIdle) {
1170 break;
1171 }
1172 if (nvExceedsTimeoutUSec(pDevEvo, &startTime, timeout)) {
1173 nvEvoLogDev(pDevEvo, EVO_LOG_ERROR,
1174 "Timed out waiting for core channel idle.");
1175 break;
1176 }
1177 } while (TRUE);
1178
1179 for (win = 0; win < pDevEvo->numWindows; win++) {
1180 NvU32 data = nvDmaLoadPioMethod(pCoreDma, NVC37D_WINDOW_SET_CONTROL(win));
1181
1182 if (DRF_VAL(C37D,
1183 _WINDOW_SET_CONTROL, _OWNER, data) !=
1184 pDevEvo->headForWindow[win]) {
1185
1186 pModesetUpdateState->windowMappingChanged = TRUE;
1187
1188 nvPushEvoSubDevMask(pDevEvo, NVBIT(sd));
1189 nvDisableCoreInterlockUpdateState(pDevEvo,
1190 updateState,
1191 pDevEvo->window[win]);
1192 nvPopEvoSubDevMask(pDevEvo);
1193 }
1194 }
1195 }
1196 }
1197
EvoInitWindowMappingC3(const NVDispEvoRec * pDispEvo,NVEvoModesetUpdateState * pModesetUpdateState)1198 static void EvoInitWindowMappingC3(const NVDispEvoRec *pDispEvo,
1199 NVEvoModesetUpdateState *pModesetUpdateState)
1200 {
1201 NVDevEvoRec *pDevEvo = pDispEvo->pDevEvo;
1202 NVEvoUpdateState *updateState = &pModesetUpdateState->updateState;
1203 NVEvoChannelPtr pChannel = pDevEvo->core;
1204 NvU32 win;
1205
1206 nvPushEvoSubDevMaskDisp(pDispEvo);
1207
1208 nvUpdateUpdateState(pDevEvo, updateState, pChannel);
1209
1210 EvoInitWindowMapping3(pDevEvo,
1211 pModesetUpdateState);
1212
1213 // Set window usage bounds
1214 for (win = 0; win < pDevEvo->numWindows; win++) {
1215 nvDmaSetStartEvoMethod(pChannel, NVC37D_WINDOW_SET_WINDOW_USAGE_BOUNDS(win), 1);
1216 /* XXXnvdisplay: window scaling */
1217 nvDmaSetEvoMethodData(pChannel, NV_EVO3_DEFAULT_WINDOW_USAGE_BOUNDS_C3);
1218 }
1219 nvPopEvoSubDevMask(pDevEvo);
1220 }
1221
nvEvoInitWindowMappingC5(const NVDispEvoRec * pDispEvo,NVEvoModesetUpdateState * pModesetUpdateState)1222 void nvEvoInitWindowMappingC5(const NVDispEvoRec *pDispEvo,
1223 NVEvoModesetUpdateState *pModesetUpdateState)
1224 {
1225 NVDevEvoRec *pDevEvo = pDispEvo->pDevEvo;
1226 NVEvoUpdateState *updateState = &pModesetUpdateState->updateState;
1227 NVEvoChannelPtr pChannel = pDevEvo->core;
1228 NvU32 win;
1229
1230 nvPushEvoSubDevMaskDisp(pDispEvo);
1231
1232 nvUpdateUpdateState(pDevEvo, updateState, pChannel);
1233
1234 EvoInitWindowMapping3(pDevEvo,
1235 pModesetUpdateState);
1236
1237 // Set window usage bounds
1238 for (win = 0; win < pDevEvo->numWindows; win++) {
1239 NvU32 bounds = NV_EVO3_DEFAULT_WINDOW_USAGE_BOUNDS_C5;
1240
1241 bounds |=
1242 DRF_DEF(C57D, _WINDOW_SET_WINDOW_USAGE_BOUNDS, _INPUT_SCALER_TAPS, _TAPS_2) |
1243 DRF_DEF(C57D, _WINDOW_SET_WINDOW_USAGE_BOUNDS, _UPSCALING_ALLOWED, _FALSE);
1244
1245 nvDmaSetStartEvoMethod(pChannel, NVC57D_WINDOW_SET_WINDOW_USAGE_BOUNDS(win), 1);
1246 nvDmaSetEvoMethodData(pChannel, bounds);
1247 }
1248 nvPopEvoSubDevMask(pDevEvo);
1249 }
1250
nvComputeMinFrameIdle(const NVHwModeTimingsEvo * pTimings,NvU16 * pLeadingRasterLines,NvU16 * pTrailingRasterLines)1251 NvBool nvComputeMinFrameIdle(
1252 const NVHwModeTimingsEvo *pTimings,
1253 NvU16 *pLeadingRasterLines,
1254 NvU16 *pTrailingRasterLines)
1255 {
1256 const NVHwModeViewPortEvo *pViewPort = &pTimings->viewPort;
1257
1258 /*
1259 * leadingRasterLines defines the number of lines between the start of the
1260 * frame (vsync) and the start of the active region. This includes Vsync,
1261 * Vertical Back Porch, and the top part of the overscan border. The
1262 * minimum value is 2 because vsync and VBP must be at least 1 line each.
1263 *
1264 * trailingRasterLines defines the number of lines between the end of the
1265 * active region and the end of the frame. This includes the bottom part
1266 * of the overscan border and the Vertical Front Porch.
1267 */
1268 const NvU32 activeHeight = (pTimings->rasterBlankStart.y -
1269 pTimings->rasterBlankEnd.y);
1270 /* This is how it's done in dispClassNVD20CoreUpdateErrorChecks_hls.c */
1271 const NvU32 overscan = (activeHeight / 2) - (pViewPort->out.height / 2);
1272
1273 /*
1274 * The +1 is justified by this comment in the error check:
1275 *
1276 * If the value is 1, that means there are 2 lines of vblank (lines 0 and
1277 * 1) before active. That is why the uLeadingBorder equation needs +1;
1278 */
1279 const NvU32 leadingRasterLines =
1280 pTimings->rasterBlankEnd.y + overscan + pViewPort->out.yAdjust + 1;
1281 const NvU32 trailingRasterLines =
1282 pTimings->rasterSize.y - (leadingRasterLines + pViewPort->out.height);
1283
1284 /* nvdClass_01.mfs says: "The minimum value is 2 because vsync and VBP must
1285 * be at least 1 line each." */
1286 if (leadingRasterLines < 2) {
1287 return FALSE;
1288 }
1289
1290 *pLeadingRasterLines = leadingRasterLines;
1291 *pTrailingRasterLines = trailingRasterLines;
1292
1293 return TRUE;
1294 }
1295
EvoSetRasterParams3(NVDevEvoPtr pDevEvo,int head,const NVHwModeTimingsEvo * pTimings,const NVEvoColorRec * pOverscanColor,NVEvoUpdateState * updateState)1296 static void EvoSetRasterParams3(NVDevEvoPtr pDevEvo, int head,
1297 const NVHwModeTimingsEvo *pTimings,
1298 const NVEvoColorRec *pOverscanColor,
1299 NVEvoUpdateState *updateState)
1300 {
1301 NVEvoChannelPtr pChannel = pDevEvo->core;
1302 /* XXXnvdisplay: Convert these for YCbCr, as necessary */
1303 NvU32 overscanColor =
1304 DRF_NUM(C37D, _HEAD_SET_OVERSCAN_COLOR, _RED_CR, pOverscanColor->red) |
1305 DRF_NUM(C37D, _HEAD_SET_OVERSCAN_COLOR, _GREEN_Y, pOverscanColor->green) |
1306 DRF_NUM(C37D, _HEAD_SET_OVERSCAN_COLOR, _BLUE_CB, pOverscanColor->blue);
1307 NvU32 hdmiStereoCtrl;
1308 NvU16 minFrameIdleLeadingRasterLines, minFrameIdleTrailingRasterLines;
1309 NvBool ret;
1310
1311 /* These methods should only apply to a single pDpy */
1312 nvAssert(pDevEvo->subDevMaskStackDepth > 0);
1313
1314 nvUpdateUpdateState(pDevEvo, updateState, pChannel);
1315
1316 // XXX[AGP]: These methods are sequential and could use an incrementing
1317 // method, but it's not clear if there's a bug in EVO that causes corruption
1318 // sometimes. Play it safe and send methods with count=1.
1319
1320 nvDmaSetStartEvoMethod(pChannel, NVC37D_HEAD_SET_OVERSCAN_COLOR(head), 1);
1321 nvDmaSetEvoMethodData(pChannel, overscanColor);
1322
1323 nvDmaSetStartEvoMethod(pChannel, NVC37D_HEAD_SET_RASTER_SIZE(head), 1);
1324 nvDmaSetEvoMethodData(pChannel,
1325 DRF_NUM(C37D, _HEAD_SET_RASTER_SIZE, _WIDTH, pTimings->rasterSize.x) |
1326 DRF_NUM(C37D, _HEAD_SET_RASTER_SIZE, _HEIGHT, pTimings->rasterSize.y));
1327
1328 nvDmaSetStartEvoMethod(pChannel, NVC37D_HEAD_SET_RASTER_SYNC_END(head), 1);
1329 nvDmaSetEvoMethodData(pChannel,
1330 DRF_NUM(C37D, _HEAD_SET_RASTER_SYNC_END, _X, pTimings->rasterSyncEnd.x) |
1331 DRF_NUM(C37D, _HEAD_SET_RASTER_SYNC_END, _Y, pTimings->rasterSyncEnd.y));
1332
1333 nvDmaSetStartEvoMethod(pChannel, NVC37D_HEAD_SET_RASTER_BLANK_END(head), 1);
1334 nvDmaSetEvoMethodData(pChannel,
1335 DRF_NUM(C37D, _HEAD_SET_RASTER_BLANK_END, _X, pTimings->rasterBlankEnd.x) |
1336 DRF_NUM(C37D, _HEAD_SET_RASTER_BLANK_END, _Y, pTimings->rasterBlankEnd.y));
1337
1338 nvDmaSetStartEvoMethod(pChannel, NVC37D_HEAD_SET_RASTER_BLANK_START(head), 1);
1339 nvDmaSetEvoMethodData(pChannel,
1340 DRF_NUM(C37D, _HEAD_SET_RASTER_BLANK_START, _X, pTimings->rasterBlankStart.x) |
1341 DRF_NUM(C37D, _HEAD_SET_RASTER_BLANK_START, _Y, pTimings->rasterBlankStart.y));
1342
1343 ret = nvComputeMinFrameIdle(pTimings,
1344 &minFrameIdleLeadingRasterLines,
1345 &minFrameIdleTrailingRasterLines);
1346 if (!ret) {
1347 /* This should have been ensured by IMP in AssignPerHeadImpParams. */
1348 nvAssert(ret);
1349 /* In case a mode validation override was used to skip IMP, program the
1350 * default values. This may still cause a hardware exception. */
1351 minFrameIdleLeadingRasterLines = 2;
1352 minFrameIdleTrailingRasterLines = 1;
1353 }
1354
1355 nvDmaSetStartEvoMethod(pChannel, NVC37D_HEAD_SET_MIN_FRAME_IDLE(head), 1);
1356 nvDmaSetEvoMethodData(pChannel,
1357 DRF_NUM(C37D, _HEAD_SET_MIN_FRAME_IDLE, _LEADING_RASTER_LINES,
1358 minFrameIdleLeadingRasterLines) |
1359 DRF_NUM(C37D, _HEAD_SET_MIN_FRAME_IDLE, _TRAILING_RASTER_LINES,
1360 minFrameIdleTrailingRasterLines));
1361
1362 nvDmaSetStartEvoMethod(pChannel, NVC37D_HEAD_SET_PIXEL_CLOCK_FREQUENCY(head), 1);
1363 nvDmaSetEvoMethodData(pChannel,
1364 DRF_NUM(C37D, _HEAD_SET_PIXEL_CLOCK_FREQUENCY, _HERTZ,
1365 pTimings->pixelClock * 1000) |
1366 DRF_DEF(C37D, _HEAD_SET_PIXEL_CLOCK_FREQUENCY, _ADJ1000DIV1001,_FALSE));
1367
1368 nvDmaSetStartEvoMethod(pChannel, NVC37D_HEAD_SET_PIXEL_CLOCK_CONFIGURATION(head), 1);
1369 nvDmaSetEvoMethodData(pChannel,
1370 DRF_DEF(C37D, _HEAD_SET_PIXEL_CLOCK_CONFIGURATION, _NOT_DRIVER, _FALSE) |
1371 DRF_DEF(C37D, _HEAD_SET_PIXEL_CLOCK_CONFIGURATION, _HOPPING, _DISABLE) |
1372 DRF_DEF(C37D, _HEAD_SET_PIXEL_CLOCK_CONFIGURATION, _HOPPING_MODE, _VBLANK));
1373
1374 nvDmaSetStartEvoMethod(pChannel, NVC37D_HEAD_SET_PIXEL_CLOCK_FREQUENCY_MAX(head), 1);
1375 nvDmaSetEvoMethodData(pChannel,
1376 DRF_NUM(C37D, _HEAD_SET_PIXEL_CLOCK_FREQUENCY_MAX, _HERTZ,
1377 pTimings->pixelClock * 1000) |
1378 DRF_DEF(C37D, _HEAD_SET_PIXEL_CLOCK_FREQUENCY_MAX, _ADJ1000DIV1001,_FALSE));
1379
1380 nvDmaSetStartEvoMethod(pChannel,
1381 NVC37D_HEAD_SET_FRAME_PACKED_VACTIVE_COLOR(head), 1);
1382 nvDmaSetEvoMethodData(pChannel,
1383 DRF_NUM(C37D, _HEAD_SET_FRAME_PACKED_VACTIVE_COLOR, _RED_CR, 0) |
1384 #if defined(DEBUG)
1385 DRF_NUM(C37D, _HEAD_SET_FRAME_PACKED_VACTIVE_COLOR, _GREEN_Y, 512) |
1386 #else
1387 DRF_NUM(C37D, _HEAD_SET_FRAME_PACKED_VACTIVE_COLOR, _GREEN_Y, 0) |
1388 #endif
1389 DRF_NUM(C37D, _HEAD_SET_FRAME_PACKED_VACTIVE_COLOR, _BLUE_CB, 0));
1390
1391 hdmiStereoCtrl = DRF_NUM(C37D, _HEAD_SET_HDMI_CTRL, _HDMI_VIC, 0);
1392 if (pTimings->hdmi3D) {
1393 hdmiStereoCtrl =
1394 FLD_SET_DRF(C37D, _HEAD_SET_HDMI_CTRL, _VIDEO_FORMAT, _STEREO3D, hdmiStereoCtrl);
1395 } else {
1396 hdmiStereoCtrl =
1397 FLD_SET_DRF(C37D, _HEAD_SET_HDMI_CTRL, _VIDEO_FORMAT, _NORMAL, hdmiStereoCtrl);
1398 }
1399 nvDmaSetStartEvoMethod(pChannel,
1400 NVC37D_HEAD_SET_HDMI_CTRL(head), 1);
1401 nvDmaSetEvoMethodData(pChannel, hdmiStereoCtrl);
1402 }
1403
EvoSetRasterParamsC3(NVDevEvoPtr pDevEvo,int head,const NVHwModeTimingsEvo * pTimings,const NvU8 tilePosition,const NVDscInfoEvoRec * pDscInfo,const NVEvoColorRec * pOverscanColor,NVEvoUpdateState * updateState)1404 static void EvoSetRasterParamsC3(NVDevEvoPtr pDevEvo, int head,
1405 const NVHwModeTimingsEvo *pTimings,
1406 const NvU8 tilePosition,
1407 const NVDscInfoEvoRec *pDscInfo,
1408 const NVEvoColorRec *pOverscanColor,
1409 NVEvoUpdateState *updateState)
1410 {
1411 nvAssert(tilePosition == 0);
1412 EvoSetRasterParams3(pDevEvo, head, pTimings, pOverscanColor, updateState);
1413 }
1414
EvoSetRasterParams5(NVDevEvoPtr pDevEvo,int head,const NVHwModeTimingsEvo * pTimings,const NvU8 tilePosition,const NVEvoColorRec * pOverscanColor,NVEvoUpdateState * updateState)1415 static void EvoSetRasterParams5(NVDevEvoPtr pDevEvo, int head,
1416 const NVHwModeTimingsEvo *pTimings,
1417 const NvU8 tilePosition,
1418 const NVEvoColorRec *pOverscanColor,
1419 NVEvoUpdateState *updateState)
1420 {
1421 NVEvoChannelPtr pChannel = pDevEvo->core;
1422
1423 /* These methods should only apply to a single pDpy */
1424 nvAssert(pDevEvo->subDevMaskStackDepth > 0);
1425
1426 nvUpdateUpdateState(pDevEvo, updateState, pChannel);
1427
1428 EvoSetRasterParams3(pDevEvo, head, pTimings, pOverscanColor, updateState);
1429
1430 nvDmaSetStartEvoMethod(pChannel, NVC57D_HEAD_SET_TILE_POSITION(head), 1);
1431 nvDmaSetEvoMethodData(pChannel,
1432 DRF_NUM(C57D, _HEAD_SET_TILE_POSITION, _X, tilePosition) |
1433 DRF_NUM(C57D, _HEAD_SET_TILE_POSITION, _Y, 0));
1434 }
1435
EvoSetRasterParamsC5(NVDevEvoPtr pDevEvo,int head,const NVHwModeTimingsEvo * pTimings,const NvU8 tilePosition,const NVDscInfoEvoRec * pDscInfo,const NVEvoColorRec * pOverscanColor,NVEvoUpdateState * updateState)1436 static void EvoSetRasterParamsC5(NVDevEvoPtr pDevEvo, int head,
1437 const NVHwModeTimingsEvo *pTimings,
1438 const NvU8 tilePosition,
1439 const NVDscInfoEvoRec *pDscInfo,
1440 const NVEvoColorRec *pOverscanColor,
1441 NVEvoUpdateState *updateState)
1442 {
1443 nvAssert(pDscInfo->type != NV_DSC_INFO_EVO_TYPE_HDMI);
1444 EvoSetRasterParams5(pDevEvo, head, pTimings, tilePosition, pOverscanColor,
1445 updateState);
1446 }
1447
GetHdmiDscHBlankPixelTarget(const NVHwModeTimingsEvo * pTimings,const NVDscInfoEvoRec * pDscInfo)1448 static NvU32 GetHdmiDscHBlankPixelTarget(const NVHwModeTimingsEvo *pTimings,
1449 const NVDscInfoEvoRec *pDscInfo)
1450 {
1451 nvAssert((pDscInfo->dp.dscMode == NV_DSC_EVO_MODE_DUAL) ||
1452 (pDscInfo->dp.dscMode == NV_DSC_EVO_MODE_SINGLE));
1453
1454 const NvU32 hblankMin =
1455 (pDscInfo->dp.dscMode == NV_DSC_EVO_MODE_DUAL) ?
1456 ((pDscInfo->hdmi.hblankMin + 1) / 2) :
1457 pDscInfo->hdmi.hblankMin;
1458
1459 NvU32 hBlankPixelTarget =
1460 NV_UNSIGNED_DIV_CEIL((pTimings->rasterSize.x *
1461 pDscInfo->hdmi.dscTBlankToTTotalRatioX1k),
1462 1000);
1463
1464 hBlankPixelTarget = NV_MAX(hblankMin, hBlankPixelTarget);
1465
1466 if (pDscInfo->dp.dscMode == NV_DSC_EVO_MODE_DUAL) {
1467 hBlankPixelTarget += (hBlankPixelTarget % 2);
1468 }
1469
1470 return hBlankPixelTarget;
1471 }
1472
EvoSetRasterParamsC6(NVDevEvoPtr pDevEvo,int head,const NVHwModeTimingsEvo * pTimings,const NvU8 tilePosition,const NVDscInfoEvoRec * pDscInfo,const NVEvoColorRec * pOverscanColor,NVEvoUpdateState * updateState)1473 static void EvoSetRasterParamsC6(NVDevEvoPtr pDevEvo, int head,
1474 const NVHwModeTimingsEvo *pTimings,
1475 const NvU8 tilePosition,
1476 const NVDscInfoEvoRec *pDscInfo,
1477 const NVEvoColorRec *pOverscanColor,
1478 NVEvoUpdateState *updateState)
1479 {
1480 NvU32 rasterHBlankDelay;
1481 NVEvoChannelPtr pChannel = pDevEvo->core;
1482
1483 /* These methods should only apply to a single pDpy */
1484 nvAssert(pDevEvo->subDevMaskStackDepth > 0);
1485
1486 nvUpdateUpdateState(pDevEvo, updateState, pChannel);
1487
1488 EvoSetRasterParams5(pDevEvo, head, pTimings, tilePosition, pOverscanColor,
1489 updateState);
1490
1491 if (pDscInfo->type == NV_DSC_INFO_EVO_TYPE_HDMI) {
1492 const NvU32 hBlank = pTimings->rasterSize.x -
1493 pTimings->rasterBlankStart.x + pTimings->rasterBlankEnd.x;
1494 const NvU32 hBlankPixelTarget =
1495 GetHdmiDscHBlankPixelTarget(pTimings, pDscInfo);
1496
1497 const NvU32 headSetRasterHBlankDelayStart =
1498 pTimings->rasterSize.x - pTimings->rasterBlankStart.x - 2;
1499 const NvU32 headSetRasterHBlankDelayEnd =
1500 hBlankPixelTarget - hBlank + headSetRasterHBlankDelayStart;
1501
1502 rasterHBlankDelay =
1503 DRF_NUM(C67D, _HEAD_SET_RASTER_HBLANK_DELAY, _BLANK_START,
1504 headSetRasterHBlankDelayStart);
1505 rasterHBlankDelay |=
1506 DRF_NUM(C67D, _HEAD_SET_RASTER_HBLANK_DELAY, _BLANK_END,
1507 headSetRasterHBlankDelayEnd);
1508 } else {
1509 rasterHBlankDelay = 0;
1510 }
1511
1512 nvDmaSetStartEvoMethod(pChannel, NVC67D_HEAD_SET_RASTER_HBLANK_DELAY(head), 1);
1513 nvDmaSetEvoMethodData(pChannel, rasterHBlankDelay);
1514 }
1515
EvoSetProcAmpC3(NVDispEvoPtr pDispEvo,const NvU32 head,NVEvoUpdateState * updateState)1516 static void EvoSetProcAmpC3(NVDispEvoPtr pDispEvo, const NvU32 head,
1517 NVEvoUpdateState *updateState)
1518 {
1519 NVDevEvoPtr pDevEvo = pDispEvo->pDevEvo;
1520 NVEvoChannelPtr pChannel = pDevEvo->core;
1521 const NVDispHeadStateEvoRec *pHeadState = &pDispEvo->headState[head];
1522 NvU32 dynRange;
1523
1524 /* These methods should only apply to a single pDpyEvo */
1525 nvAssert(pDevEvo->subDevMaskStackDepth > 0);
1526
1527 nvUpdateUpdateState(pDevEvo, updateState, pChannel);
1528
1529 // These NVT defines match the HEAD_SET_PROCAMP ones.
1530 ct_assert(NVT_COLORIMETRY_RGB == NVC37D_HEAD_SET_PROCAMP_COLOR_SPACE_RGB);
1531 ct_assert(NVT_COLORIMETRY_YUV_601 == NVC37D_HEAD_SET_PROCAMP_COLOR_SPACE_YUV_601);
1532 ct_assert(NVT_COLORIMETRY_YUV_709 == NVC37D_HEAD_SET_PROCAMP_COLOR_SPACE_YUV_709);
1533 /* XXXnvdisplay add REC2020 */
1534 ct_assert(NVT_COLOR_RANGE_FULL == NVC37D_HEAD_SET_PROCAMP_RANGE_COMPRESSION_DISABLE);
1535 ct_assert(NVT_COLOR_RANGE_LIMITED == NVC37D_HEAD_SET_PROCAMP_RANGE_COMPRESSION_ENABLE);
1536
1537 if (pHeadState->procAmp.colorRange == NVT_COLOR_RANGE_FULL) {
1538 dynRange = DRF_DEF(C37D, _HEAD_SET_PROCAMP, _DYNAMIC_RANGE, _VESA);
1539 } else {
1540 nvAssert(pHeadState->procAmp.colorRange == NVT_COLOR_RANGE_LIMITED);
1541 dynRange = DRF_DEF(C37D, _HEAD_SET_PROCAMP, _DYNAMIC_RANGE, _CEA);
1542 }
1543
1544 nvDmaSetStartEvoMethod(pChannel, NVC37D_HEAD_SET_PROCAMP(head), 1);
1545 nvDmaSetEvoMethodData(pChannel,
1546 DRF_NUM(C37D, _HEAD_SET_PROCAMP, _COLOR_SPACE,
1547 pHeadState->procAmp.colorimetry) |
1548 DRF_DEF(C37D, _HEAD_SET_PROCAMP, _CHROMA_LPF, _DISABLE) |
1549 DRF_NUM(C37D, _HEAD_SET_PROCAMP, _SAT_COS,
1550 pHeadState->procAmp.satCos) |
1551 DRF_NUM(C37D, _HEAD_SET_PROCAMP, _SAT_SINE, 0) |
1552 dynRange |
1553 DRF_NUM(C37D, _HEAD_SET_PROCAMP, _RANGE_COMPRESSION,
1554 pHeadState->procAmp.colorRange) |
1555 DRF_DEF(C37D, _HEAD_SET_PROCAMP, _BLACK_LEVEL, _GRAPHICS));
1556 }
1557
1558 static const struct NvKmsCscMatrix RGBToFullRangeYCbCrRec709Matrix = {{
1559 { 0x8000, 0x1f8bbc, 0x1ff444, 0x8000 },
1560 { 0x366c, 0xb718, 0x127c, 0 },
1561 { 0x1fe2ac, 0x1f9d54, 0x8000, 0x8000 },
1562 }};
1563 static const struct NvKmsCscMatrix RGBToFullRangeYCbCrRec601Matrix = {{
1564 { 0x8000, 0x1f94d0, 0x1feb30, 0x8000 },
1565 { 0x4c8c, 0x9644, 0x1d30, 0 },
1566 { 0x1fd4cc, 0x1fab34, 0x8000, 0x8000 },
1567 }};
1568 static const struct NvKmsCscMatrix RGBToLimitedRangeYCbCrRec2020Matrix = {{
1569 { 0x7000, 0x1f9900, 0x1ff700, 0x8000 },
1570 { 0x3988, 0x947c, 0xcfc, 0x1000 },
1571 { 0x1fe0b8, 0x1faf44, 0x7000, 0x8000 },
1572 }};
1573 static const struct NvKmsCscMatrix RGBToLimitedRangeYCbCrRec709Matrix = {{
1574 { 0x7000, 0x1f9a44, 0x1ff5bc, 0x8000 },
1575 { 0x2e90, 0x9ca4, 0xfd0, 0x1000 },
1576 { 0x1fe654, 0x1fa9a8, 0x7000, 0x8000 },
1577 }};
1578 static const struct NvKmsCscMatrix RGBToLimitedRangeYCbCrRec601Matrix = {{
1579 { 0x7000, 0x1fa234, 0x1fedc8, 0x8000 },
1580 { 0x417c, 0x8090, 0x18f8, 0x1000 },
1581 { 0x1fda34, 0x1fb5cc, 0x7000, 0x8000 },
1582 }};
1583 static const struct NvKmsCscMatrix RGBToLimitedRangeRGB = {{
1584 { 0xdb04, 0, 0, 0x1000 },
1585 { 0, 0xdb04, 0, 0x1000 },
1586 { 0, 0, 0xdb04, 0x1000 },
1587 }};
1588
1589
1590 /*!
1591 * Return the appropriate OCSC1 matrix for the requested color range and
1592 * colorimetry, or NULL if the OCSC1 should be disabled.
1593 */
nvEvoGetOCsc1MatrixC5(const NVDispHeadStateEvoRec * pHeadState)1594 const struct NvKmsCscMatrix* nvEvoGetOCsc1MatrixC5(const NVDispHeadStateEvoRec *pHeadState)
1595 {
1596 if (pHeadState->procAmp.colorRange == NVT_COLOR_RANGE_FULL) {
1597 switch (pHeadState->procAmp.colorimetry) {
1598 case NVT_COLORIMETRY_BT2020RGB:
1599 // fall through
1600 case NVT_COLORIMETRY_RGB:
1601 // No OCSC1 needed.
1602 return NULL;
1603 case NVT_COLORIMETRY_YUV_601:
1604 return &RGBToFullRangeYCbCrRec601Matrix;
1605 case NVT_COLORIMETRY_YUV_709:
1606 return &RGBToFullRangeYCbCrRec709Matrix;
1607 default:
1608 nvAssert(!"Unexpected colorimetry");
1609 return NULL;
1610 }
1611 } else {
1612 switch (pHeadState->procAmp.colorimetry) {
1613 case NVT_COLORIMETRY_BT2020RGB:
1614 // fall through
1615 case NVT_COLORIMETRY_RGB:
1616 return &RGBToLimitedRangeRGB;
1617 case NVT_COLORIMETRY_YUV_601:
1618 return &RGBToLimitedRangeYCbCrRec601Matrix;
1619 case NVT_COLORIMETRY_YUV_709:
1620 return &RGBToLimitedRangeYCbCrRec709Matrix;
1621 case NVT_COLORIMETRY_BT2020YCC:
1622 return &RGBToLimitedRangeYCbCrRec2020Matrix;
1623 default:
1624 nvAssert(!"Unexpected colorimetry");
1625 return NULL;
1626 }
1627 }
1628 }
1629
1630 /*!
1631 * Return the output clamping ranges for the requested color range and
1632 * colorimetry.
1633 */
1634 struct EvoClampRangeC5
nvEvoGetOCsc1ClampRange(const NVDispHeadStateEvoRec * pHeadState)1635 nvEvoGetOCsc1ClampRange(const NVDispHeadStateEvoRec *pHeadState)
1636 {
1637 if (pHeadState->procAmp.colorRange == NVT_COLOR_RANGE_FULL) {
1638 return (struct EvoClampRangeC5) {
1639 .green = DRF_NUM(C57D, _HEAD_SET_CLAMP_RANGE_GREEN, _LOW, 0x0) |
1640 DRF_NUM(C57D, _HEAD_SET_CLAMP_RANGE_GREEN, _HIGH, 0xFFF),
1641 .red_blue = DRF_NUM(C57D, _HEAD_SET_CLAMP_RANGE_RED_BLUE, _LOW, 0x0) |
1642 DRF_NUM(C57D, _HEAD_SET_CLAMP_RANGE_RED_BLUE, _HIGH, 0xFFF),
1643 };
1644 } else {
1645 switch (pHeadState->procAmp.colorimetry) {
1646 default:
1647 nvAssert(!"Unexpected colorimetry");
1648 // fall through
1649 case NVT_COLORIMETRY_BT2020RGB:
1650 // fall through
1651 case NVT_COLORIMETRY_RGB:
1652 return (struct EvoClampRangeC5) {
1653 .green = DRF_NUM(C57D, _HEAD_SET_CLAMP_RANGE_GREEN, _LOW, 0x100) |
1654 DRF_NUM(C57D, _HEAD_SET_CLAMP_RANGE_GREEN, _HIGH, 0xEB0),
1655 .red_blue = DRF_NUM(C57D, _HEAD_SET_CLAMP_RANGE_RED_BLUE, _LOW, 0x100) |
1656 DRF_NUM(C57D, _HEAD_SET_CLAMP_RANGE_RED_BLUE, _HIGH, 0xEB0),
1657 };
1658 case NVT_COLORIMETRY_YUV_601:
1659 case NVT_COLORIMETRY_YUV_709:
1660 case NVT_COLORIMETRY_BT2020YCC:
1661 return (struct EvoClampRangeC5) {
1662 .green = DRF_NUM(C57D, _HEAD_SET_CLAMP_RANGE_GREEN, _LOW, 0x100) |
1663 DRF_NUM(C57D, _HEAD_SET_CLAMP_RANGE_GREEN, _HIGH, 0xEB0),
1664 .red_blue = DRF_NUM(C57D, _HEAD_SET_CLAMP_RANGE_RED_BLUE, _LOW, 0x100) |
1665 DRF_NUM(C57D, _HEAD_SET_CLAMP_RANGE_RED_BLUE, _HIGH, 0xF00),
1666 };
1667 }
1668 }
1669 }
1670
1671 /*
1672 * 1.402 1.0 0.0
1673 * -0.714136 1.0 -0.344136
1674 * 0.0 1.0 1.772
1675 */
1676 static const struct NvKmsMatrix CrYCb601toRGBMatrix = { {
1677 { 0x3fb374bc, 0x3f800000, 0x00000000 },
1678 { 0xbf36d19e, 0x3f800000, 0xbeb03298 },
1679 { 0x00000000, 0x3f800000, 0x3fe2d0e5 }
1680 } };
1681
1682 /*
1683 * 1.5748 1.0 0.0
1684 * -0.468124 1.0 -0.187324
1685 * 0.0 1.0 1.8556
1686 */
1687 static const struct NvKmsMatrix CrYCb709toRGBMatrix = { {
1688 { 0x3fc9930c, 0x3f800000, 0x00000000 },
1689 { 0xbeefadf3, 0x3f800000, 0xbe3fd1dd },
1690 { 0x00000000, 0x3f800000, 0x3fed844d }
1691 } };
1692
1693 /*
1694 * 0.5 -0.418688 -0.081312
1695 * 0.299 0.587 0.114
1696 * -0.168736 -0.331264 0.5
1697 */
1698 static const struct NvKmsMatrix RGBtoCrYCb601Matrix = { {
1699 { 0x3f000000, 0xbed65e46, 0xbda686e8 },
1700 { 0x3e991687, 0x3f1645a2, 0x3de978d5 },
1701 { 0xbe2cc921, 0xbea99b6f, 0x3f000000 }
1702 } };
1703
1704 /*
1705 * 0.5 -0.45415 -0.04585
1706 * 0.21260 0.71520 0.07220
1707 * -0.11457 -0.38543 0.5
1708 */
1709 static const struct NvKmsMatrix RGBtoCrYCb709Matrix = { {
1710 { 0x3f000000, 0xbee88659, 0xbd3bcd36 },
1711 { 0x3e59b3d0, 0x3f371759, 0x3d93dd98 },
1712 { 0xbdeaa3ad, 0xbec55715, 0x3f000000 }
1713 } };
1714
EvoSetOCsc1C5(NVDispEvoPtr pDispEvo,const NvU32 head)1715 static void EvoSetOCsc1C5(NVDispEvoPtr pDispEvo, const NvU32 head)
1716 {
1717 NVDevEvoPtr pDevEvo = pDispEvo->pDevEvo;
1718 NVEvoChannelPtr pChannel = pDevEvo->core;
1719 const NVDispHeadStateEvoRec *pHeadState = &pDispEvo->headState[head];
1720 const struct NvKmsCscMatrix *matrix = nvEvoGetOCsc1MatrixC5(pHeadState);
1721 struct EvoClampRangeC5 clamp = nvEvoGetOCsc1ClampRange(pHeadState);
1722
1723 nvDmaSetStartEvoMethod(pChannel, NVC57D_HEAD_SET_CLAMP_RANGE_GREEN(head), 1);
1724 nvDmaSetEvoMethodData(pChannel, clamp.green);
1725 nvDmaSetStartEvoMethod(pChannel, NVC57D_HEAD_SET_CLAMP_RANGE_RED_BLUE(head), 1);
1726 nvDmaSetEvoMethodData(pChannel, clamp.red_blue);
1727
1728 if (matrix) {
1729 int x, y;
1730 NvU32 method = NVC57D_HEAD_SET_OCSC1COEFFICIENT_C00(head);
1731
1732 nvDmaSetStartEvoMethod(pChannel, NVC57D_HEAD_SET_OCSC1CONTROL(head), 1);
1733 nvDmaSetEvoMethodData(pChannel,
1734 DRF_DEF(C57D, _HEAD_SET_OCSC1CONTROL, _ENABLE, _ENABLE));
1735
1736 for (y = 0; y < 3; y++) {
1737 for (x = 0; x < 4; x++) {
1738 nvDmaSetStartEvoMethod(pChannel, method, 1);
1739 nvDmaSetEvoMethodData(pChannel, matrix->m[y][x]);
1740
1741 method += 4;
1742 }
1743 }
1744 } else {
1745 nvDmaSetStartEvoMethod(pChannel, NVC57D_HEAD_SET_OCSC1CONTROL(head), 1);
1746 nvDmaSetEvoMethodData(pChannel,
1747 DRF_DEF(C57D, _HEAD_SET_OCSC1CONTROL, _ENABLE, _DISABLE));
1748 }
1749 }
1750
1751 /*
1752 * Sets up the OCSC0 matrix coefficients, used to perform saturation
1753 * adjustment.
1754 *
1755 * The pipeline operates in FP16 RGB, however this adjustment must be
1756 * performed in CrYCb. Therefore, we multiply the saturation
1757 * adjustment matrix by the appropriate color space conversion
1758 * matrix. The specific color space used depends on the colorimetry of
1759 * the final output. Then we multiply by its inverse to convert back
1760 * to RGB. Finally, we convert the coefficients to S5.14 fixed point
1761 * format.
1762 */
nvEvo3PickOCsc0(NVDispEvoPtr pDispEvo,const NvU32 head,struct NvKms3x4MatrixF32 * ocsc0MatrixOutput)1763 void nvEvo3PickOCsc0(NVDispEvoPtr pDispEvo, const NvU32 head, struct NvKms3x4MatrixF32 *ocsc0MatrixOutput)
1764 {
1765 const NVDispHeadStateEvoRec *pHeadState = &pDispEvo->headState[head];
1766
1767 const float32_t zeroF32 = NvU32viewAsF32(NV_FLOAT_ZERO);
1768 const float32_t oneF32 = NvU32viewAsF32(NV_FLOAT_ONE);
1769 const float32_t inv2048F32 = f32_div(NvU32viewAsF32(NV_FLOAT_HALF),
1770 NvU32viewAsF32(NV_FLOAT_1024));
1771 /* divide satCos by the default setting of 1024 */
1772 const float32_t satCos = f32_div(i32_to_f32(pHeadState->procAmp.satCos),
1773 NvU32viewAsF32(NV_FLOAT_1024));
1774 const struct NvKmsMatrixF32 satHueMatrix = { {
1775 { satCos, zeroF32, zeroF32 },
1776 { zeroF32, oneF32, zeroF32 },
1777 { zeroF32, zeroF32, satCos }
1778 } };
1779 struct NvKms3x4MatrixF32 ocsc0Matrix = { {
1780 { oneF32, zeroF32, zeroF32, zeroF32 },
1781 { zeroF32, oneF32, zeroF32, zeroF32 },
1782 { zeroF32, zeroF32, oneF32, zeroF32 }
1783 } };
1784
1785 struct NvKmsMatrixF32 CrYCbtoRGBMatrix;
1786 struct NvKmsMatrixF32 RGBtoCrYCbMatrix;
1787
1788
1789 switch (pHeadState->procAmp.colorimetry) {
1790 default:
1791 nvAssert(!"Unexpected colorimetry");
1792 /* fallthrough */
1793 case NVT_COLORIMETRY_RGB:
1794 case NVT_COLORIMETRY_BT2020RGB:
1795 /* fallthrough; for RGB output, perform saturation adjustment in YUV709 */
1796 case NVT_COLORIMETRY_YUV_709:
1797 CrYCbtoRGBMatrix = NvKmsMatrixToNvKmsMatrixF32(CrYCb709toRGBMatrix);
1798 RGBtoCrYCbMatrix = NvKmsMatrixToNvKmsMatrixF32(RGBtoCrYCb709Matrix);
1799 break;
1800 case NVT_COLORIMETRY_YUV_601:
1801 CrYCbtoRGBMatrix = NvKmsMatrixToNvKmsMatrixF32(CrYCb601toRGBMatrix);
1802 RGBtoCrYCbMatrix = NvKmsMatrixToNvKmsMatrixF32(RGBtoCrYCb601Matrix);
1803 break;
1804 }
1805
1806 ocsc0Matrix = nvMultiply3x4Matrix(&RGBtoCrYCbMatrix, &ocsc0Matrix);
1807 ocsc0Matrix = nvMultiply3x4Matrix(&satHueMatrix, &ocsc0Matrix);
1808 ocsc0Matrix = nvMultiply3x4Matrix(&CrYCbtoRGBMatrix, &ocsc0Matrix);
1809
1810 if (nvkms_output_rounding_fix()) {
1811 /*
1812 * XXX Only apply WAR for bug 2267663 for linear output TFs. Non-linear
1813 * TFs could amplify the 1/2048 factor to the point of being
1814 * perceptible.
1815 */
1816 if (pHeadState->tf == NVKMS_OUTPUT_TF_NONE) {
1817 ocsc0Matrix.m[0][3] = f32_add(ocsc0Matrix.m[0][3], inv2048F32);
1818 ocsc0Matrix.m[1][3] = f32_add(ocsc0Matrix.m[1][3], inv2048F32);
1819 ocsc0Matrix.m[2][3] = f32_add(ocsc0Matrix.m[2][3], inv2048F32);
1820 }
1821 }
1822
1823 *ocsc0MatrixOutput = ocsc0Matrix;
1824 }
1825
1826 /*
1827 * Programs the OCSC0 matrix coefficients, used to perform saturation
1828 * adjustment.
1829 *
1830 * The OCSC0 matrix will be enabled later in EvoSetLUTContextDmaC5 if
1831 * and only if we also enable the OLUT as required by the
1832 * specification.
1833 */
EvoSetOCsc0C5(NVDispEvoPtr pDispEvo,const NvU32 head)1834 static void EvoSetOCsc0C5(NVDispEvoPtr pDispEvo, const NvU32 head)
1835 {
1836 NVDevEvoPtr pDevEvo = pDispEvo->pDevEvo;
1837 NVEvoChannelPtr pChannel = pDevEvo->core;
1838 struct NvKms3x4MatrixF32 ocsc0Matrix;
1839
1840 nvEvo3PickOCsc0(pDispEvo, head, &ocsc0Matrix);
1841
1842 nvDmaSetStartEvoMethod(pChannel, NVC57D_HEAD_SET_OCSC0COEFFICIENT_C00(head), 12);
1843 nvDmaSetEvoMethodData(pChannel, DRF_NUM(C57D, _HEAD_SET_OCSC0COEFFICIENT_C00, _VALUE, nvCscCoefConvertS514(ocsc0Matrix.m[0][0])));
1844 nvDmaSetEvoMethodData(pChannel, DRF_NUM(C57D, _HEAD_SET_OCSC0COEFFICIENT_C01, _VALUE, nvCscCoefConvertS514(ocsc0Matrix.m[0][1])));
1845 nvDmaSetEvoMethodData(pChannel, DRF_NUM(C57D, _HEAD_SET_OCSC0COEFFICIENT_C02, _VALUE, nvCscCoefConvertS514(ocsc0Matrix.m[0][2])));
1846 nvDmaSetEvoMethodData(pChannel, DRF_NUM(C57D, _HEAD_SET_OCSC0COEFFICIENT_C03, _VALUE, nvCscCoefConvertS514(ocsc0Matrix.m[0][3])));
1847
1848 nvDmaSetEvoMethodData(pChannel, DRF_NUM(C57D, _HEAD_SET_OCSC0COEFFICIENT_C10, _VALUE, nvCscCoefConvertS514(ocsc0Matrix.m[1][0])));
1849 nvDmaSetEvoMethodData(pChannel, DRF_NUM(C57D, _HEAD_SET_OCSC0COEFFICIENT_C11, _VALUE, nvCscCoefConvertS514(ocsc0Matrix.m[1][1])));
1850 nvDmaSetEvoMethodData(pChannel, DRF_NUM(C57D, _HEAD_SET_OCSC0COEFFICIENT_C12, _VALUE, nvCscCoefConvertS514(ocsc0Matrix.m[1][2])));
1851 nvDmaSetEvoMethodData(pChannel, DRF_NUM(C57D, _HEAD_SET_OCSC0COEFFICIENT_C13, _VALUE, nvCscCoefConvertS514(ocsc0Matrix.m[1][3])));
1852
1853 nvDmaSetEvoMethodData(pChannel, DRF_NUM(C57D, _HEAD_SET_OCSC0COEFFICIENT_C20, _VALUE, nvCscCoefConvertS514(ocsc0Matrix.m[2][0])));
1854 nvDmaSetEvoMethodData(pChannel, DRF_NUM(C57D, _HEAD_SET_OCSC0COEFFICIENT_C21, _VALUE, nvCscCoefConvertS514(ocsc0Matrix.m[2][1])));
1855 nvDmaSetEvoMethodData(pChannel, DRF_NUM(C57D, _HEAD_SET_OCSC0COEFFICIENT_C22, _VALUE, nvCscCoefConvertS514(ocsc0Matrix.m[2][2])));
1856 nvDmaSetEvoMethodData(pChannel, DRF_NUM(C57D, _HEAD_SET_OCSC0COEFFICIENT_C23, _VALUE, nvCscCoefConvertS514(ocsc0Matrix.m[2][3])));
1857 }
1858
EvoSetProcAmpC5(NVDispEvoPtr pDispEvo,const NvU32 head,NVEvoUpdateState * updateState)1859 static void EvoSetProcAmpC5(NVDispEvoPtr pDispEvo, const NvU32 head,
1860 NVEvoUpdateState *updateState)
1861 {
1862 NVDevEvoPtr pDevEvo = pDispEvo->pDevEvo;
1863 NVEvoChannelPtr pChannel = pDevEvo->core;
1864 const NVDispHeadStateEvoRec *pHeadState = &pDispEvo->headState[head];
1865 NvU32 dynRange, chromaLpf, chromaDownV;
1866 NvU32 colorimetry;
1867
1868 NVT_COLORIMETRY nvtColorimetry = pHeadState->procAmp.colorimetry;
1869 NVT_COLOR_RANGE nvtColorRange = pHeadState->procAmp.colorRange;
1870
1871 /* These methods should only apply to a single pDpyEvo */
1872 nvAssert(pDevEvo->subDevMaskStackDepth > 0);
1873
1874 nvUpdateUpdateState(pDevEvo, updateState, pChannel);
1875
1876 switch (nvtColorimetry) {
1877 default:
1878 nvAssert(!"Unrecognized colorimetry");
1879 // fall through
1880 case NVT_COLORIMETRY_BT2020RGB:
1881 // fall through
1882 case NVT_COLORIMETRY_RGB:
1883 colorimetry = DRF_DEF(C57D, _HEAD_SET_PROCAMP, _COLOR_SPACE, _RGB);
1884 break;
1885 case NVT_COLORIMETRY_YUV_601:
1886 colorimetry = DRF_DEF(C57D, _HEAD_SET_PROCAMP, _COLOR_SPACE, _YUV_601);
1887 break;
1888 case NVT_COLORIMETRY_YUV_709:
1889 colorimetry = DRF_DEF(C57D, _HEAD_SET_PROCAMP, _COLOR_SPACE, _YUV_709);
1890 break;
1891 case NVT_COLORIMETRY_BT2020YCC:
1892 colorimetry = DRF_DEF(C57D, _HEAD_SET_PROCAMP, _COLOR_SPACE, _YUV_2020);
1893 break;
1894 }
1895
1896 if (nvtColorRange == NVT_COLOR_RANGE_FULL) {
1897 dynRange = DRF_DEF(C57D, _HEAD_SET_PROCAMP, _DYNAMIC_RANGE, _VESA);
1898 } else {
1899 nvAssert(nvtColorRange == NVT_COLOR_RANGE_LIMITED);
1900 dynRange = DRF_DEF(C57D, _HEAD_SET_PROCAMP, _DYNAMIC_RANGE, _CEA);
1901 }
1902
1903 /*
1904 * NVC67D_HEAD_SET_PROCAMP_CHROMA_DOWN_V is only defined in NVC67D, but
1905 * it is an unused bit in NVC57D_HEAD_SET_PROCAMP, and YUV420 should only
1906 * be set on >=nvdisplay 4.0, so it's okay to set it here.
1907 */
1908 if (pHeadState->procAmp.colorFormat == NVT_COLOR_FORMAT_YCbCr420) {
1909 chromaLpf = DRF_DEF(C57D, _HEAD_SET_PROCAMP, _CHROMA_LPF, _ENABLE);
1910 chromaDownV = DRF_DEF(C67D, _HEAD_SET_PROCAMP, _CHROMA_DOWN_V, _ENABLE);
1911 } else {
1912 chromaLpf = DRF_DEF(C57D, _HEAD_SET_PROCAMP, _CHROMA_LPF, _DISABLE);
1913 chromaDownV = DRF_DEF(C67D, _HEAD_SET_PROCAMP, _CHROMA_DOWN_V, _DISABLE);
1914 }
1915
1916 nvDmaSetStartEvoMethod(pChannel, NVC57D_HEAD_SET_PROCAMP(head), 1);
1917 nvDmaSetEvoMethodData(pChannel,
1918 colorimetry | dynRange | chromaLpf | chromaDownV);
1919
1920 EvoSetOCsc0C5(pDispEvo, head);
1921 EvoSetOCsc1C5(pDispEvo, head);
1922 }
1923
1924 /*
1925 * With nvdisplay, external fliplock pins are controlled via a headless
1926 * SetControl method, unlike previous EVO display implementations which
1927 * specified this information in the per-head HeadSetControl method. This
1928 * function loops over all of the core nvkms HeadControl data structures to
1929 * determine which pins should be enabled in the SetControl method. It should
1930 * be called any time the HeadControl data structures are updated.
1931 */
nvEvoSetControlC3(NVDevEvoPtr pDevEvo,int sd)1932 void nvEvoSetControlC3(NVDevEvoPtr pDevEvo, int sd)
1933 {
1934 NVEvoSubDevPtr pEvoSubDev = &pDevEvo->gpus[sd];
1935 NVEvoChannelPtr pChannel = pDevEvo->core;
1936 NvU32 data = 0;
1937 NvU32 head;
1938
1939 for (head = 0; head < pDevEvo->numHeads; head++) {
1940 NVEvoHeadControlPtr pHC = &pEvoSubDev->headControl[head];
1941 if (pHC->flipLock && !NV_EVO_LOCK_PIN_IS_INTERNAL(pHC->flipLockPin)) {
1942 NvU32 pin = pHC->flipLockPin - NV_EVO_LOCK_PIN_0;
1943 data = FLD_IDX_SET_DRF(C37D, _SET_CONTROL, _FLIP_LOCK_PIN,
1944 pin, _ENABLE, data);
1945 }
1946 }
1947
1948 /*
1949 * GV100 HW bug 2062029 WAR
1950 *
1951 * GV100 always holds the external fliplock line low as if
1952 * NVC37D_SET_CONTROL_FLIP_LOCK_PIN was enabled. To work around this,
1953 * the GV100 VBIOS initializes the fliplock GPIOs to be software
1954 * controlled (forced off). The following rmctrl needs to be called to
1955 * switch HW control of the fliplock GPIOs back on whenever external
1956 * fliplock is enabled.
1957 */
1958 {
1959 NVC370_CTRL_SET_SWAPRDY_GPIO_WAR_PARAMS params = { };
1960
1961 params.base.subdeviceIndex = pEvoSubDev->subDeviceInstance;
1962 params.bEnable = (data != 0);
1963
1964 if (nvRmApiControl(
1965 nvEvoGlobal.clientHandle,
1966 pDevEvo->displayHandle,
1967 NVC370_CTRL_CMD_SET_SWAPRDY_GPIO_WAR,
1968 ¶ms, sizeof(params)) != NVOS_STATUS_SUCCESS) {
1969 nvEvoLogDevDebug(pDevEvo, EVO_LOG_ERROR, "Failed to override fliplock GPIO");
1970 }
1971 }
1972
1973 nvDmaSetStartEvoMethod(pChannel, NVC37D_SET_CONTROL, 1);
1974 nvDmaSetEvoMethodData(pChannel, data);
1975 }
1976
EvoSetHeadControlC3(NVDevEvoPtr pDevEvo,int sd,int head,NVEvoUpdateState * updateState)1977 static void EvoSetHeadControlC3(NVDevEvoPtr pDevEvo, int sd, int head,
1978 NVEvoUpdateState *updateState)
1979 {
1980 NVEvoChannelPtr pChannel = pDevEvo->core;
1981 NVEvoSubDevPtr pEvoSubDev = &pDevEvo->gpus[sd];
1982 /*
1983 * NOTE: This function should only push state to the hardware based on data
1984 * in the pHC. If not, then we may miss updates due to the memcmp of the
1985 * HeadControl structure in UpdateEvoLockState().
1986 */
1987 NVEvoHeadControlPtr pHC = &pEvoSubDev->headControl[head];
1988 NvU32 data = 0, pin;
1989 NvU32 serverLockMode, clientLockMode;
1990
1991 /* These methods should only apply to a single subdevice */
1992 nvAssert(pDevEvo->subDevMaskStackDepth > 0);
1993
1994 nvUpdateUpdateState(pDevEvo, updateState, pChannel);
1995
1996 switch (pHC->serverLock) {
1997 case NV_EVO_NO_LOCK:
1998 serverLockMode = NVC37D_HEAD_SET_CONTROL_MASTER_LOCK_MODE_NO_LOCK;
1999 break;
2000 case NV_EVO_FRAME_LOCK:
2001 serverLockMode = NVC37D_HEAD_SET_CONTROL_MASTER_LOCK_MODE_FRAME_LOCK;
2002 break;
2003 case NV_EVO_RASTER_LOCK:
2004 serverLockMode = NVC37D_HEAD_SET_CONTROL_MASTER_LOCK_MODE_RASTER_LOCK;
2005 break;
2006 default:
2007 nvAssert(!"Invalid server lock mode");
2008 return;
2009 }
2010
2011 switch (pHC->clientLock) {
2012 case NV_EVO_NO_LOCK:
2013 clientLockMode = NVC37D_HEAD_SET_CONTROL_SLAVE_LOCK_MODE_NO_LOCK;
2014 break;
2015 case NV_EVO_FRAME_LOCK:
2016 clientLockMode = NVC37D_HEAD_SET_CONTROL_SLAVE_LOCK_MODE_FRAME_LOCK;
2017 break;
2018 case NV_EVO_RASTER_LOCK:
2019 clientLockMode = NVC37D_HEAD_SET_CONTROL_SLAVE_LOCK_MODE_RASTER_LOCK;
2020 break;
2021 default:
2022 nvAssert(!"Invalid client lock mode");
2023 return;
2024 }
2025
2026 // Convert head control state to EVO method values.
2027 nvAssert(!pHC->interlaced);
2028 data |= DRF_DEF(C37D, _HEAD_SET_CONTROL, _STRUCTURE, _PROGRESSIVE);
2029
2030 nvAssert(pHC->serverLockPin != NV_EVO_LOCK_PIN_ERROR);
2031 nvAssert(pHC->clientLockPin != NV_EVO_LOCK_PIN_ERROR);
2032
2033 if (serverLockMode == NVC37D_HEAD_SET_CONTROL_MASTER_LOCK_MODE_NO_LOCK) {
2034 data |= DRF_DEF(C37D, _HEAD_SET_CONTROL, _MASTER_LOCK_PIN, _LOCK_PIN_NONE);
2035 } else if (NV_EVO_LOCK_PIN_IS_INTERNAL(pHC->serverLockPin)) {
2036 pin = pHC->serverLockPin - NV_EVO_LOCK_PIN_INTERNAL_0;
2037 /*
2038 * nvdClass_01.mfs says:
2039 * "master lock pin, if internal, must be set to the corresponding
2040 * internal pin for that head" (error check #12)
2041 */
2042 nvAssert(pin == head);
2043 data |= DRF_NUM(C37D, _HEAD_SET_CONTROL, _MASTER_LOCK_PIN,
2044 NVC37D_HEAD_SET_CONTROL_MASTER_LOCK_PIN_INTERNAL_SCAN_LOCK(pin));
2045 } else {
2046 pin = pHC->serverLockPin - NV_EVO_LOCK_PIN_0;
2047 data |= DRF_NUM(C37D, _HEAD_SET_CONTROL, _MASTER_LOCK_PIN,
2048 NVC37D_HEAD_SET_CONTROL_MASTER_LOCK_PIN_LOCK_PIN(pin));
2049 }
2050 data |= DRF_NUM(C37D, _HEAD_SET_CONTROL, _MASTER_LOCK_MODE, serverLockMode);
2051
2052 if (clientLockMode == NVC37D_HEAD_SET_CONTROL_SLAVE_LOCK_MODE_NO_LOCK) {
2053 data |= DRF_DEF(C37D, _HEAD_SET_CONTROL, _SLAVE_LOCK_PIN, _LOCK_PIN_NONE);
2054 } else if (NV_EVO_LOCK_PIN_IS_INTERNAL(pHC->clientLockPin)) {
2055 pin = pHC->clientLockPin - NV_EVO_LOCK_PIN_INTERNAL_0;
2056 data |= DRF_NUM(C37D, _HEAD_SET_CONTROL, _SLAVE_LOCK_PIN,
2057 NVC37D_HEAD_SET_CONTROL_SLAVE_LOCK_PIN_INTERNAL_SCAN_LOCK(pin));
2058 } else {
2059 pin = pHC->clientLockPin - NV_EVO_LOCK_PIN_0;
2060 data |= DRF_NUM(C37D, _HEAD_SET_CONTROL, _SLAVE_LOCK_PIN,
2061 NVC37D_HEAD_SET_CONTROL_SLAVE_LOCK_PIN_LOCK_PIN(pin));
2062 }
2063 data |= DRF_NUM(C37D, _HEAD_SET_CONTROL, _SLAVE_LOCK_MODE, clientLockMode);
2064 data |= DRF_NUM(C37D, _HEAD_SET_CONTROL, _SLAVE_LOCKOUT_WINDOW,
2065 pHC->clientLockoutWindow);
2066
2067 /*
2068 * We always enable stereo lock when it's available and either framelock
2069 * or rasterlock is in use.
2070 */
2071 if (pHC->stereoLocked) {
2072 if (pHC->serverLock != NV_EVO_NO_LOCK) {
2073 data |= DRF_NUM(C37D, _HEAD_SET_CONTROL, _MASTER_STEREO_LOCK_MODE,
2074 NVC37D_HEAD_SET_CONTROL_MASTER_STEREO_LOCK_MODE_ENABLE);
2075 }
2076 if (pHC->clientLock != NV_EVO_NO_LOCK) {
2077 data |= DRF_NUM(C37D, _HEAD_SET_CONTROL, _SLAVE_STEREO_LOCK_MODE,
2078 NVC37D_HEAD_SET_CONTROL_SLAVE_STEREO_LOCK_MODE_ENABLE);
2079 }
2080 }
2081
2082 nvAssert(pHC->stereoPin != NV_EVO_LOCK_PIN_ERROR);
2083 if (NV_EVO_LOCK_PIN_IS_INTERNAL(pHC->stereoPin)) {
2084 data |= DRF_DEF(C37D, _HEAD_SET_CONTROL, _STEREO_PIN, _LOCK_PIN_NONE);
2085 } else {
2086 pin = pHC->stereoPin - NV_EVO_LOCK_PIN_0;
2087 data |= DRF_NUM(C37D, _HEAD_SET_CONTROL, _STEREO_PIN,
2088 NVC37D_HEAD_SET_CONTROL_STEREO_PIN_LOCK_PIN(pin));
2089 }
2090
2091 if (pHC->hdmi3D) {
2092 data |= DRF_DEF(C37D, _HEAD_SET_CONTROL, _STEREO3D_STRUCTURE, _FRAME_PACKED);
2093 } else {
2094 data |= DRF_DEF(C37D, _HEAD_SET_CONTROL, _STEREO3D_STRUCTURE, _NORMAL);
2095 }
2096
2097 /*
2098 * NVC67D_HEAD_SET_CONTROL_YUV420PACKER is only defined in NVC67D, but
2099 * it is an unused bit in NVC37D_HEAD_SET_CONTROL, and YUV420 should only
2100 * be set on >=nvdisplay 4.0, so it's okay to set it here.
2101 */
2102 if (pHC->hwYuv420) {
2103 data |= DRF_DEF(C67D, _HEAD_SET_CONTROL, _YUV420PACKER, _ENABLE);
2104 } else {
2105 data |= DRF_DEF(C67D, _HEAD_SET_CONTROL, _YUV420PACKER, _DISABLE);
2106 }
2107
2108 // Send the HeadSetControl method.
2109 nvDmaSetStartEvoMethod(pChannel, NVC37D_HEAD_SET_CONTROL(head), 1);
2110 nvDmaSetEvoMethodData(pChannel, data);
2111
2112 nvEvoSetControlC3(pDevEvo, sd);
2113
2114 nvDmaSetStartEvoMethod(pChannel, NVC37D_HEAD_SET_LOCK_CHAIN(head), 1);
2115 nvDmaSetEvoMethodData(pChannel, DRF_NUM(C37D, _HEAD_SET_LOCK_CHAIN, _POSITION,
2116 pHC->lockChainPosition));
2117
2118 /* XXX temporary WAR; see bug 4028718 */
2119 #if !defined(NVC37D_HEAD_SET_LOCK_OFFSET)
2120 #define NVC37D_HEAD_SET_LOCK_OFFSET(a) (0x00002040 + (a)*0x00000400)
2121 #define NVC37D_HEAD_SET_LOCK_OFFSET_X 14:0
2122 #define NVC37D_HEAD_SET_LOCK_OFFSET_Y 30:16
2123 #endif
2124
2125 nvDmaSetStartEvoMethod(pChannel, NVC37D_HEAD_SET_LOCK_OFFSET(head), 1);
2126 nvDmaSetEvoMethodData(pChannel, pHC->setLockOffsetX ?
2127 DRF_NUM(C37D, _HEAD_SET_LOCK_OFFSET, _X,
2128 27) : 0);
2129 }
2130
EvoSetHeadRefClkC3(NVDevEvoPtr pDevEvo,int head,NvBool external,NVEvoUpdateState * updateState)2131 static void EvoSetHeadRefClkC3(NVDevEvoPtr pDevEvo, int head, NvBool external,
2132 NVEvoUpdateState *updateState)
2133 {
2134 NVEvoChannelPtr pChannel = pDevEvo->core;
2135 NvU32 sd;
2136
2137 /* These methods should only apply to a single subdevice */
2138 nvAssert(pDevEvo->subDevMaskStackDepth > 0);
2139
2140 nvUpdateUpdateState(pDevEvo, updateState, pChannel);
2141
2142 for (sd = 0; sd < pDevEvo->numSubDevices; sd++) {
2143 if (nvPeekEvoSubDevMask(pDevEvo) & (1 << sd)) {
2144 if (external) {
2145 pDevEvo->gpus[sd].setSwSpareA[head] =
2146 FLD_SET_DRF(C37D,
2147 _HEAD_SET_SW_SPARE_A_CODE,
2148 _VPLL_REF,
2149 _QSYNC,
2150 pDevEvo->gpus[sd].setSwSpareA[head]);
2151 } else {
2152 pDevEvo->gpus[sd].setSwSpareA[head] =
2153 FLD_SET_DRF(C37D,
2154 _HEAD_SET_SW_SPARE_A_CODE,
2155 _VPLL_REF,
2156 _NO_PREF,
2157 pDevEvo->gpus[sd].setSwSpareA[head]);
2158 }
2159
2160 nvPushEvoSubDevMask(pDevEvo, NVBIT(sd));
2161 nvDmaSetStartEvoMethod(pChannel, NVC37D_HEAD_SET_SW_SPARE_A(head), 1);
2162 nvDmaSetEvoMethodData(pChannel, pDevEvo->gpus[sd].setSwSpareA[head]);
2163 nvPopEvoSubDevMask(pDevEvo);
2164 }
2165 }
2166 }
2167
EvoSORSetControlC3(const NVConnectorEvoRec * pConnectorEvo,const enum nvKmsTimingsProtocol protocol,const NvU32 orIndex,const NvU32 headMask)2168 static void EvoSORSetControlC3(const NVConnectorEvoRec *pConnectorEvo,
2169 const enum nvKmsTimingsProtocol protocol,
2170 const NvU32 orIndex,
2171 const NvU32 headMask)
2172 {
2173 NVDevEvoPtr pDevEvo = pConnectorEvo->pDispEvo->pDevEvo;
2174 NVEvoChannelPtr pChannel = pDevEvo->core;
2175 NvU32 hwProtocol = 0;
2176
2177 /* These methods should only apply to a single pDpy */
2178 nvAssert(pDevEvo->subDevMaskStackDepth > 0);
2179 nvAssert(orIndex != NV_INVALID_OR);
2180
2181 if (headMask != 0) {
2182 switch (protocol) {
2183 default:
2184 nvAssert(!"Unknown SOR protocol");
2185 /* Fall through */
2186 case NVKMS_PROTOCOL_SOR_SINGLE_TMDS_A:
2187 hwProtocol = NVC37D_SOR_SET_CONTROL_PROTOCOL_SINGLE_TMDS_A;
2188 break;
2189 case NVKMS_PROTOCOL_SOR_SINGLE_TMDS_B:
2190 hwProtocol = NVC37D_SOR_SET_CONTROL_PROTOCOL_SINGLE_TMDS_B;
2191 break;
2192 case NVKMS_PROTOCOL_SOR_DUAL_TMDS:
2193 hwProtocol = NVC37D_SOR_SET_CONTROL_PROTOCOL_DUAL_TMDS;
2194 break;
2195 case NVKMS_PROTOCOL_SOR_DP_A:
2196 hwProtocol = NVC37D_SOR_SET_CONTROL_PROTOCOL_DP_A;
2197 break;
2198 case NVKMS_PROTOCOL_SOR_DP_B:
2199 hwProtocol = NVC37D_SOR_SET_CONTROL_PROTOCOL_DP_B;
2200 break;
2201 case NVKMS_PROTOCOL_SOR_LVDS_CUSTOM:
2202 hwProtocol = NVC37D_SOR_SET_CONTROL_PROTOCOL_LVDS_CUSTOM;
2203 break;
2204 case NVKMS_PROTOCOL_SOR_HDMI_FRL:
2205 hwProtocol = NVC67D_SOR_SET_CONTROL_PROTOCOL_HDMI_FRL;
2206 break;
2207 }
2208 }
2209
2210 nvDmaSetStartEvoMethod(pChannel, NVC37D_SOR_SET_CONTROL(orIndex), 1);
2211 nvDmaSetEvoMethodData(pChannel,
2212 DRF_NUM(C37D, _SOR_SET_CONTROL, _OWNER_MASK, headMask) |
2213 DRF_NUM(C37D, _SOR_SET_CONTROL, _PROTOCOL, hwProtocol) |
2214 DRF_DEF(C37D, _SOR_SET_CONTROL, _DE_SYNC_POLARITY, _POSITIVE_TRUE) |
2215 DRF_DEF(C37D, _SOR_SET_CONTROL, _PIXEL_REPLICATE_MODE, _OFF));
2216 }
2217
nvEvoGetPixelDepthC3(const enum nvKmsPixelDepth pixelDepth)2218 NvU32 nvEvoGetPixelDepthC3(const enum nvKmsPixelDepth pixelDepth)
2219 {
2220 switch (pixelDepth) {
2221 case NVKMS_PIXEL_DEPTH_18_444:
2222 return NVC37D_HEAD_SET_CONTROL_OUTPUT_RESOURCE_PIXEL_DEPTH_BPP_18_444;
2223 case NVKMS_PIXEL_DEPTH_24_444:
2224 return NVC37D_HEAD_SET_CONTROL_OUTPUT_RESOURCE_PIXEL_DEPTH_BPP_24_444;
2225 case NVKMS_PIXEL_DEPTH_30_444:
2226 return NVC37D_HEAD_SET_CONTROL_OUTPUT_RESOURCE_PIXEL_DEPTH_BPP_30_444;
2227 case NVKMS_PIXEL_DEPTH_16_422:
2228 return NVC37D_HEAD_SET_CONTROL_OUTPUT_RESOURCE_PIXEL_DEPTH_BPP_16_422;
2229 case NVKMS_PIXEL_DEPTH_20_422:
2230 return NVC37D_HEAD_SET_CONTROL_OUTPUT_RESOURCE_PIXEL_DEPTH_BPP_20_422;
2231
2232 }
2233 nvAssert(!"Unexpected pixel depth");
2234 return NVC37D_HEAD_SET_CONTROL_OUTPUT_RESOURCE_PIXEL_DEPTH_BPP_24_444;
2235 }
2236
EvoPIORSetControlC3(const NVConnectorEvoRec * pConnectorEvo,const enum nvKmsTimingsProtocol protocol,const NvU32 orIndex,const NvU32 headMask)2237 static void EvoPIORSetControlC3(const NVConnectorEvoRec *pConnectorEvo,
2238 const enum nvKmsTimingsProtocol protocol,
2239 const NvU32 orIndex,
2240 const NvU32 headMask)
2241 {
2242 NVDevEvoPtr pDevEvo = pConnectorEvo->pDispEvo->pDevEvo;
2243 NVEvoChannelPtr pChannel = pDevEvo->core;
2244
2245 /* These methods should only apply to a single pDpy */
2246 nvAssert(pDevEvo->subDevMaskStackDepth > 0);
2247
2248 if (headMask != 0) {
2249 nvAssert(protocol == NVKMS_PROTOCOL_PIOR_EXT_TMDS_ENC);
2250 }
2251
2252 nvDmaSetStartEvoMethod(pChannel, NVC37D_PIOR_SET_CONTROL(orIndex), 1);
2253 nvDmaSetEvoMethodData(pChannel,
2254 DRF_NUM(C37D, _PIOR_SET_CONTROL, _OWNER_MASK, headMask) |
2255 DRF_DEF(C37D, _PIOR_SET_CONTROL, _PROTOCOL, _EXT_TMDS_ENC) |
2256 DRF_DEF(C37D, _PIOR_SET_CONTROL, _DE_SYNC_POLARITY, _POSITIVE_TRUE));
2257 }
2258
EvoDSISetControlC6(const NVConnectorEvoRec * pConnectorEvo,const enum nvKmsTimingsProtocol protocol,const NvU32 orIndex,const NvU32 headMask)2259 static void EvoDSISetControlC6(const NVConnectorEvoRec *pConnectorEvo,
2260 const enum nvKmsTimingsProtocol protocol,
2261 const NvU32 orIndex,
2262 const NvU32 headMask)
2263 {
2264 NVDevEvoPtr pDevEvo = pConnectorEvo->pDispEvo->pDevEvo;
2265 NVEvoChannelPtr pChannel = pDevEvo->core;
2266
2267 /* These methods should only apply to a single pDpy */
2268 nvAssert(pDevEvo->subDevMaskStackDepth > 0);
2269 /* Only Head 0 can be used to drive DSI output on Orin */
2270 nvAssert((headMask == 0x0) || (headMask == 0x1));
2271 /* Only one DSI engine exists on Orin */
2272 nvAssert(orIndex == 0);
2273
2274 if (headMask != 0) {
2275 nvAssert(protocol == NVKMS_PROTOCOL_DSI);
2276 }
2277
2278 nvDmaSetStartEvoMethod(pChannel, NVC67D_DSI_SET_CONTROL(orIndex), 1);
2279 nvDmaSetEvoMethodData(pChannel,
2280 DRF_NUM(C67D, _DSI_SET_CONTROL, _OWNER_MASK, headMask));
2281 }
2282
EvoORSetControlC3Helper(const NVConnectorEvoRec * pConnectorEvo,const enum nvKmsTimingsProtocol protocol,const NvU32 orIndex,const NvU32 headMask)2283 static void EvoORSetControlC3Helper(const NVConnectorEvoRec *pConnectorEvo,
2284 const enum nvKmsTimingsProtocol protocol,
2285 const NvU32 orIndex,
2286 const NvU32 headMask)
2287 {
2288 switch (pConnectorEvo->or.type) {
2289 case NV0073_CTRL_SPECIFIC_OR_TYPE_SOR:
2290 EvoSORSetControlC3(pConnectorEvo, protocol, orIndex, headMask);
2291 break;
2292 case NV0073_CTRL_SPECIFIC_OR_TYPE_PIOR:
2293 EvoPIORSetControlC3(pConnectorEvo, protocol, orIndex, headMask);
2294 break;
2295 case NV0073_CTRL_SPECIFIC_OR_TYPE_DAC:
2296 /* No DAC support on nvdisplay. Fall through. */
2297 default:
2298 nvAssert(!"Invalid pConnectorEvo->or.type");
2299 break;
2300 }
2301 }
2302
nvEvoORSetControlC3(NVDevEvoPtr pDevEvo,const NVConnectorEvoRec * pConnectorEvo,const enum nvKmsTimingsProtocol protocol,const NvU32 orIndex,const NvU32 headMask,NVEvoUpdateState * updateState)2303 void nvEvoORSetControlC3(NVDevEvoPtr pDevEvo,
2304 const NVConnectorEvoRec *pConnectorEvo,
2305 const enum nvKmsTimingsProtocol protocol,
2306 const NvU32 orIndex,
2307 const NvU32 headMask,
2308 NVEvoUpdateState *updateState)
2309 {
2310 /* These methods should only apply to a single pDpy */
2311 nvAssert(pDevEvo->subDevMaskStackDepth > 0);
2312
2313 nvUpdateUpdateState(pDevEvo, updateState, pDevEvo->core);
2314
2315 EvoORSetControlC3Helper(pConnectorEvo, protocol, orIndex, headMask);
2316 }
2317
EvoORSetControlC6(NVDevEvoPtr pDevEvo,const NVConnectorEvoRec * pConnectorEvo,const enum nvKmsTimingsProtocol protocol,const NvU32 orIndex,const NvU32 headMask,NVEvoUpdateState * updateState)2318 static void EvoORSetControlC6(NVDevEvoPtr pDevEvo,
2319 const NVConnectorEvoRec *pConnectorEvo,
2320 const enum nvKmsTimingsProtocol protocol,
2321 const NvU32 orIndex,
2322 const NvU32 headMask,
2323 NVEvoUpdateState *updateState)
2324 {
2325 /* These methods should only apply to a single pDpy */
2326 nvAssert(pDevEvo->subDevMaskStackDepth > 0);
2327
2328 nvUpdateUpdateState(pDevEvo, updateState, pDevEvo->core);
2329
2330 switch (pConnectorEvo->or.type) {
2331 case NV0073_CTRL_SPECIFIC_OR_TYPE_DSI:
2332 EvoDSISetControlC6(pConnectorEvo, protocol, orIndex, headMask);
2333 break;
2334 default:
2335 EvoORSetControlC3Helper(pConnectorEvo, protocol, orIndex, headMask);
2336 break;
2337 }
2338 }
2339
EvoHeadSetControlORC3(NVDevEvoPtr pDevEvo,const int head,const NVHwModeTimingsEvo * pTimings,const enum nvKmsPixelDepth pixelDepth,const NvBool colorSpaceOverride,NVEvoUpdateState * updateState)2340 static void EvoHeadSetControlORC3(NVDevEvoPtr pDevEvo,
2341 const int head,
2342 const NVHwModeTimingsEvo *pTimings,
2343 const enum nvKmsPixelDepth pixelDepth,
2344 const NvBool colorSpaceOverride,
2345 NVEvoUpdateState *updateState)
2346 {
2347 NVEvoChannelPtr pChannel = pDevEvo->core;
2348 const NvU32 hwPixelDepth = nvEvoGetPixelDepthC3(pixelDepth);
2349 const NvU16 colorSpaceFlag = nvEvo1GetColorSpaceFlag(pDevEvo,
2350 colorSpaceOverride);
2351
2352 nvDmaSetStartEvoMethod(pChannel, NVC37D_HEAD_SET_CONTROL_OUTPUT_RESOURCE(head), 1);
2353 nvDmaSetEvoMethodData(pChannel,
2354 DRF_DEF(C37D, _HEAD_SET_CONTROL_OUTPUT_RESOURCE, _CRC_MODE, _COMPLETE_RASTER) |
2355 (pTimings->hSyncPol ?
2356 DRF_DEF(C37D, _HEAD_SET_CONTROL_OUTPUT_RESOURCE, _HSYNC_POLARITY, _NEGATIVE_TRUE) :
2357 DRF_DEF(C37D, _HEAD_SET_CONTROL_OUTPUT_RESOURCE, _HSYNC_POLARITY, _POSITIVE_TRUE)) |
2358 (pTimings->vSyncPol ?
2359 DRF_DEF(C37D, _HEAD_SET_CONTROL_OUTPUT_RESOURCE, _VSYNC_POLARITY, _NEGATIVE_TRUE) :
2360 DRF_DEF(C37D, _HEAD_SET_CONTROL_OUTPUT_RESOURCE, _VSYNC_POLARITY, _POSITIVE_TRUE)) |
2361 DRF_NUM(C37D, _HEAD_SET_CONTROL_OUTPUT_RESOURCE, _PIXEL_DEPTH, hwPixelDepth) |
2362 (colorSpaceOverride ?
2363 (DRF_DEF(C37D, _HEAD_SET_CONTROL_OUTPUT_RESOURCE, _COLOR_SPACE_OVERRIDE, _ENABLE) |
2364 DRF_NUM(C37D, _HEAD_SET_CONTROL_OUTPUT_RESOURCE, _COLOR_SPACE_FLAG, colorSpaceFlag)) :
2365 DRF_DEF(C37D, _HEAD_SET_CONTROL_OUTPUT_RESOURCE, _COLOR_SPACE_OVERRIDE, _DISABLE)));
2366 }
2367
EvoHeadSetControlORC5(NVDevEvoPtr pDevEvo,const int head,const NVHwModeTimingsEvo * pTimings,const enum nvKmsPixelDepth pixelDepth,const NvBool colorSpaceOverride,NVEvoUpdateState * updateState)2368 static void EvoHeadSetControlORC5(NVDevEvoPtr pDevEvo,
2369 const int head,
2370 const NVHwModeTimingsEvo *pTimings,
2371 const enum nvKmsPixelDepth pixelDepth,
2372 const NvBool colorSpaceOverride,
2373 NVEvoUpdateState *updateState)
2374 {
2375 NVEvoChannelPtr pChannel = pDevEvo->core;
2376 const NvU32 hwPixelDepth = nvEvoGetPixelDepthC3(pixelDepth);
2377 const NvU16 colorSpaceFlag = nvEvo1GetColorSpaceFlag(pDevEvo,
2378 colorSpaceOverride);
2379
2380 nvDmaSetStartEvoMethod(pChannel, NVC57D_HEAD_SET_CONTROL_OUTPUT_RESOURCE(head), 1);
2381 nvDmaSetEvoMethodData(pChannel,
2382 DRF_DEF(C57D, _HEAD_SET_CONTROL_OUTPUT_RESOURCE, _CRC_MODE, _COMPLETE_RASTER) |
2383 (pTimings->hSyncPol ?
2384 DRF_DEF(C57D, _HEAD_SET_CONTROL_OUTPUT_RESOURCE, _HSYNC_POLARITY, _NEGATIVE_TRUE) :
2385 DRF_DEF(C57D, _HEAD_SET_CONTROL_OUTPUT_RESOURCE, _HSYNC_POLARITY, _POSITIVE_TRUE)) |
2386 (pTimings->vSyncPol ?
2387 DRF_DEF(C57D, _HEAD_SET_CONTROL_OUTPUT_RESOURCE, _VSYNC_POLARITY, _NEGATIVE_TRUE) :
2388 DRF_DEF(C57D, _HEAD_SET_CONTROL_OUTPUT_RESOURCE, _VSYNC_POLARITY, _POSITIVE_TRUE)) |
2389 DRF_NUM(C57D, _HEAD_SET_CONTROL_OUTPUT_RESOURCE, _PIXEL_DEPTH, hwPixelDepth) |
2390 (colorSpaceOverride ?
2391 (DRF_DEF(C57D, _HEAD_SET_CONTROL_OUTPUT_RESOURCE, _COLOR_SPACE_OVERRIDE, _ENABLE) |
2392 DRF_NUM(C57D, _HEAD_SET_CONTROL_OUTPUT_RESOURCE, _COLOR_SPACE_FLAG, colorSpaceFlag)) :
2393 DRF_DEF(C57D, _HEAD_SET_CONTROL_OUTPUT_RESOURCE, _COLOR_SPACE_OVERRIDE, _DISABLE)) |
2394 DRF_DEF(C57D, _HEAD_SET_CONTROL_OUTPUT_RESOURCE, _EXT_PACKET_WIN, _NONE));
2395 }
2396
EvoHeadSetDisplayIdC3(NVDevEvoPtr pDevEvo,const NvU32 head,const NvU32 displayId,NVEvoUpdateState * updateState)2397 static void EvoHeadSetDisplayIdC3(NVDevEvoPtr pDevEvo,
2398 const NvU32 head, const NvU32 displayId,
2399 NVEvoUpdateState *updateState)
2400 {
2401 NVEvoChannelPtr pChannel = pDevEvo->core;
2402
2403 /* These methods should only apply to a single pDpy */
2404 nvAssert(pDevEvo->subDevMaskStackDepth > 0);
2405
2406 nvUpdateUpdateState(pDevEvo, updateState, pChannel);
2407
2408 nvDmaSetStartEvoMethod(pChannel, NVC37D_HEAD_SET_DISPLAY_ID(head, 0), 1);
2409 nvDmaSetEvoMethodData(pChannel, displayId);
2410 }
2411
SetFormatUsageBoundsOneWindow3(NVDevEvoPtr pDevEvo,NvU32 window,const NvU64 supportedFormats,NVEvoUpdateState * updateState)2412 static void SetFormatUsageBoundsOneWindow3(NVDevEvoPtr pDevEvo, NvU32 window,
2413 const NvU64 supportedFormats,
2414 NVEvoUpdateState *updateState)
2415 {
2416 NVEvoChannelPtr pChannel = pDevEvo->core;
2417 NvU32 value = 0;
2418
2419 nvUpdateUpdateState(pDevEvo, updateState, pChannel);
2420
2421 if (supportedFormats & NVKMS_SURFACE_MEMORY_FORMATS_RGB_PACKED1BPP) {
2422 value = FLD_SET_DRF(C37D, _WINDOW_SET_WINDOW_FORMAT_USAGE_BOUNDS,
2423 _RGB_PACKED1BPP, _TRUE, value);
2424 }
2425 if (supportedFormats & NVKMS_SURFACE_MEMORY_FORMATS_RGB_PACKED2BPP) {
2426 value = FLD_SET_DRF(C37D, _WINDOW_SET_WINDOW_FORMAT_USAGE_BOUNDS,
2427 _RGB_PACKED2BPP, _TRUE, value);
2428 }
2429 if (supportedFormats & NVKMS_SURFACE_MEMORY_FORMATS_RGB_PACKED4BPP) {
2430 value = FLD_SET_DRF(C37D, _WINDOW_SET_WINDOW_FORMAT_USAGE_BOUNDS,
2431 _RGB_PACKED4BPP, _TRUE, value);
2432 }
2433 if (supportedFormats & NVKMS_SURFACE_MEMORY_FORMATS_RGB_PACKED8BPP) {
2434 value = FLD_SET_DRF(C37D, _WINDOW_SET_WINDOW_FORMAT_USAGE_BOUNDS,
2435 _RGB_PACKED8BPP, _TRUE, value);
2436 }
2437 if (supportedFormats & NVKMS_SURFACE_MEMORY_FORMATS_YUV_PACKED422) {
2438 value = FLD_SET_DRF(C37D, _WINDOW_SET_WINDOW_FORMAT_USAGE_BOUNDS,
2439 _YUV_PACKED422, _TRUE, value);
2440 }
2441 if (supportedFormats & NVKMS_SURFACE_MEMORY_FORMATS_YUV_SP420) {
2442 value = FLD_SET_DRF(C37D, _WINDOW_SET_WINDOW_FORMAT_USAGE_BOUNDS,
2443 _YUV_SEMI_PLANAR420, _TRUE, value);
2444 }
2445 if (supportedFormats & NVKMS_SURFACE_MEMORY_FORMATS_YUV_SP422) {
2446 value = FLD_SET_DRF(C37D, _WINDOW_SET_WINDOW_FORMAT_USAGE_BOUNDS,
2447 _YUV_SEMI_PLANAR422, _TRUE, value);
2448 }
2449 if (supportedFormats & NVKMS_SURFACE_MEMORY_FORMATS_YUV_SP444) {
2450 value = FLD_SET_DRF(C37D, _WINDOW_SET_WINDOW_FORMAT_USAGE_BOUNDS,
2451 _YUV_SEMI_PLANAR444, _TRUE, value);
2452 }
2453 if (supportedFormats & NVKMS_SURFACE_MEMORY_FORMATS_EXT_YUV_SP420) {
2454 value = FLD_SET_DRF(C37D, _WINDOW_SET_WINDOW_FORMAT_USAGE_BOUNDS,
2455 _EXT_YUV_SEMI_PLANAR420, _TRUE, value);
2456 }
2457 if (supportedFormats & NVKMS_SURFACE_MEMORY_FORMATS_EXT_YUV_SP422) {
2458 value = FLD_SET_DRF(C37D, _WINDOW_SET_WINDOW_FORMAT_USAGE_BOUNDS,
2459 _EXT_YUV_SEMI_PLANAR422, _TRUE, value);
2460 }
2461 if (supportedFormats & NVKMS_SURFACE_MEMORY_FORMATS_EXT_YUV_SP444) {
2462 value = FLD_SET_DRF(C37D, _WINDOW_SET_WINDOW_FORMAT_USAGE_BOUNDS,
2463 _EXT_YUV_SEMI_PLANAR444, _TRUE, value);
2464 }
2465 if (supportedFormats & NVKMS_SURFACE_MEMORY_FORMATS_YUV_PLANAR444) {
2466 value = FLD_SET_DRF(C37D, _WINDOW_SET_WINDOW_FORMAT_USAGE_BOUNDS,
2467 _YUV_PLANAR444, _TRUE, value);
2468 }
2469 if (supportedFormats & NVKMS_SURFACE_MEMORY_FORMATS_YUV_PLANAR420) {
2470 value = FLD_SET_DRF(C37D, _WINDOW_SET_WINDOW_FORMAT_USAGE_BOUNDS,
2471 _YUV_PLANAR420, _TRUE, value);
2472 }
2473
2474 if (supportedFormats != 0 && value == 0) {
2475 nvAssert(!"Unknown depth in SetFormatUsageBoundsOneWindow");
2476 }
2477
2478 nvDmaSetStartEvoMethod(pChannel, NVC37D_WINDOW_SET_WINDOW_FORMAT_USAGE_BOUNDS(window), 1);
2479 nvDmaSetEvoMethodData(pChannel, value);
2480 }
2481
SetScalingUsageBoundsOneWindow5(NVDevEvoPtr pDevEvo,NvU32 window,const struct NvKmsScalingUsageBounds * pScaling,NvBool layerUsable,const NVHwModeViewPortEvo * pViewPort,NVEvoUpdateState * updateState)2482 static void SetScalingUsageBoundsOneWindow5(
2483 NVDevEvoPtr pDevEvo, NvU32 window,
2484 const struct NvKmsScalingUsageBounds *pScaling,
2485 NvBool layerUsable,
2486 const NVHwModeViewPortEvo *pViewPort,
2487 NVEvoUpdateState *updateState)
2488 {
2489 NVEvoChannelPtr pChannel = pDevEvo->core;
2490 NvU32 setWindowUsageBounds = NV_EVO3_DEFAULT_WINDOW_USAGE_BOUNDS_C5;
2491 NvU32 maxPixelsFetchedPerLine;
2492
2493 nvUpdateUpdateState(pDevEvo, updateState, pChannel);
2494
2495 nvDmaSetStartEvoMethod(pChannel,
2496 NVC57D_WINDOW_SET_MAX_INPUT_SCALE_FACTOR(window), 1);
2497 nvDmaSetEvoMethodData(pChannel,
2498 DRF_NUM(C57D, _WINDOW_SET_MAX_INPUT_SCALE_FACTOR, _HORIZONTAL,
2499 pScaling->maxHDownscaleFactor) |
2500 DRF_NUM(C57D, _WINDOW_SET_MAX_INPUT_SCALE_FACTOR, _VERTICAL,
2501 pScaling->maxVDownscaleFactor));
2502
2503 if (layerUsable) {
2504 maxPixelsFetchedPerLine = nvGetMaxPixelsFetchedPerLine(pViewPort->in.width,
2505 pScaling->maxHDownscaleFactor);
2506 } else {
2507 maxPixelsFetchedPerLine = 0;
2508 }
2509
2510 setWindowUsageBounds |=
2511 (DRF_NUM(C57D, _WINDOW_SET_WINDOW_USAGE_BOUNDS, _MAX_PIXELS_FETCHED_PER_LINE,maxPixelsFetchedPerLine)) |
2512 (pScaling->vTaps >= NV_EVO_SCALER_5TAPS ?
2513 DRF_DEF(C57D, _WINDOW_SET_WINDOW_USAGE_BOUNDS, _INPUT_SCALER_TAPS, _TAPS_5) :
2514 DRF_DEF(C57D, _WINDOW_SET_WINDOW_USAGE_BOUNDS, _INPUT_SCALER_TAPS, _TAPS_2)) |
2515 (pScaling->vUpscalingAllowed ?
2516 DRF_DEF(C57D, _WINDOW_SET_WINDOW_USAGE_BOUNDS, _UPSCALING_ALLOWED, _TRUE) :
2517 DRF_DEF(C57D, _WINDOW_SET_WINDOW_USAGE_BOUNDS, _UPSCALING_ALLOWED, _FALSE));
2518 nvDmaSetStartEvoMethod(pChannel,
2519 NVC57D_WINDOW_SET_WINDOW_USAGE_BOUNDS(window), 1);
2520 nvDmaSetEvoMethodData(pChannel, setWindowUsageBounds);
2521 }
2522
EvoSetUsageBounds3(NVDevEvoPtr pDevEvo,NvU32 sd,NvU32 head,const struct NvKmsUsageBounds * pUsage,NVEvoUpdateState * updateState)2523 static NvBool EvoSetUsageBounds3(NVDevEvoPtr pDevEvo, NvU32 sd, NvU32 head,
2524 const struct NvKmsUsageBounds *pUsage,
2525 NVEvoUpdateState *updateState)
2526 {
2527 const struct NvKmsUsageBounds *pCurrentUsage =
2528 &pDevEvo->gpus[sd].headState[head].usage;
2529 /* Return FALSE if a core channel UPDATE isn't actually needed. */
2530 NvBool needCoreUpdate = FALSE;
2531 NvU32 layer;
2532
2533 /* These methods should only apply to a single pDpy */
2534 nvAssert(pDevEvo->subDevMaskStackDepth > 0);
2535
2536 for (layer = 0; layer < pDevEvo->head[head].numLayers; layer++) {
2537 NvU64 currentFormats = 0;
2538 NvU64 targetFormats = 0;
2539
2540 if (pCurrentUsage->layer[layer].usable) {
2541 currentFormats =
2542 pCurrentUsage->layer[layer].supportedSurfaceMemoryFormats;
2543 }
2544
2545 if (pUsage->layer[layer].usable) {
2546 targetFormats = pUsage->layer[layer].supportedSurfaceMemoryFormats;
2547 }
2548
2549 if (targetFormats == currentFormats) {
2550 continue;
2551 }
2552
2553 SetFormatUsageBoundsOneWindow3(pDevEvo,
2554 NV_EVO_CHANNEL_MASK_WINDOW_NUMBER(
2555 pDevEvo->head[head].layer[layer]->channelMask),
2556 targetFormats,
2557 updateState);
2558 needCoreUpdate = TRUE;
2559 }
2560
2561 return needCoreUpdate;
2562 }
2563
EvoSetUsageBoundsC3(NVDevEvoPtr pDevEvo,NvU32 sd,NvU32 head,const struct NvKmsUsageBounds * pUsage,NVEvoUpdateState * updateState)2564 static NvBool EvoSetUsageBoundsC3(NVDevEvoPtr pDevEvo, NvU32 sd, NvU32 head,
2565 const struct NvKmsUsageBounds *pUsage,
2566 NVEvoUpdateState *updateState)
2567 {
2568 return EvoSetUsageBounds3(pDevEvo, sd, head, pUsage, updateState);
2569 }
2570
nvEvoSetUsageBoundsC5(NVDevEvoPtr pDevEvo,NvU32 sd,NvU32 head,const struct NvKmsUsageBounds * pUsage,NVEvoUpdateState * updateState)2571 NvBool nvEvoSetUsageBoundsC5(NVDevEvoPtr pDevEvo, NvU32 sd, NvU32 head,
2572 const struct NvKmsUsageBounds *pUsage,
2573 NVEvoUpdateState *updateState)
2574 {
2575 const struct NvKmsUsageBounds *pCurrentUsage =
2576 &pDevEvo->gpus[sd].headState[head].usage;
2577 NvBool needCoreUpdate;
2578 NvU32 layer;
2579
2580 needCoreUpdate = EvoSetUsageBounds3(pDevEvo, sd, head, pUsage, updateState);
2581
2582 for (layer = 0; layer < pDevEvo->head[head].numLayers; layer++) {
2583 if ((pCurrentUsage->layer[layer].usable != pUsage->layer[layer].usable) ||
2584 (!nvEvoScalingUsageBoundsEqual(&pCurrentUsage->layer[layer].scaling,
2585 &pUsage->layer[layer].scaling))) {
2586 const NVHwModeViewPortEvo *pViewPort =
2587 &pDevEvo->gpus[sd].pDispEvo->headState[head].timings.viewPort;
2588
2589 SetScalingUsageBoundsOneWindow5(
2590 pDevEvo,
2591 NV_EVO_CHANNEL_MASK_WINDOW_NUMBER(
2592 pDevEvo->head[head].layer[layer]->channelMask),
2593 &pUsage->layer[layer].scaling,
2594 pUsage->layer[layer].usable,
2595 pViewPort,
2596 updateState);
2597 needCoreUpdate = TRUE;
2598 }
2599 }
2600
2601 return needCoreUpdate;
2602 }
2603
EvoSetCoreNotifierSurfaceAddressAndControlC3(NVEvoChannelPtr pChannel,const NVSurfaceDescriptor * pSurfaceDesc,NvU32 notifierOffset,NvU32 ctrlVal)2604 static void EvoSetCoreNotifierSurfaceAddressAndControlC3(
2605 NVEvoChannelPtr pChannel,
2606 const NVSurfaceDescriptor *pSurfaceDesc,
2607 NvU32 notifierOffset,
2608 NvU32 ctrlVal)
2609 {
2610 NvU32 ctxDmaHandle = pSurfaceDesc ? pSurfaceDesc->ctxDmaHandle : 0;
2611
2612 nvDmaSetStartEvoMethod(pChannel, NVC37D_SET_CONTEXT_DMA_NOTIFIER, 1);
2613 nvDmaSetEvoMethodData(pChannel,
2614 DRF_NUM(C37D, _SET_CONTEXT_DMA_NOTIFIER, _HANDLE, ctxDmaHandle));
2615
2616 nvDmaSetStartEvoMethod(pChannel, NVC37D_SET_NOTIFIER_CONTROL, 1);
2617 nvDmaSetEvoMethodData(pChannel,
2618 DRF_NUM(C37D, _SET_NOTIFIER_CONTROL, _OFFSET, notifierOffset) | ctrlVal);
2619 }
2620
nvEvoSetNotifierC3(NVDevEvoRec * pDevEvo,const NvBool notify,const NvBool awaken,const NvU32 notifier,NVEvoUpdateState * updateState)2621 void nvEvoSetNotifierC3(NVDevEvoRec *pDevEvo,
2622 const NvBool notify,
2623 const NvBool awaken,
2624 const NvU32 notifier,
2625 NVEvoUpdateState *updateState)
2626 {
2627 NVEvoChannelPtr pChannel = pDevEvo->core;
2628 NvU32 ctrlVal = 0;
2629
2630 nvUpdateUpdateState(pDevEvo, updateState, pChannel);
2631
2632 /*
2633 * XXXnvdisplay: Note that nvdClass_01.mfs says:
2634 * "The units of the offset are 16 bytes.", while dispClass_02.mfs says:
2635 * "The units of the offset are 32 bit words."
2636 * The "legacy" 32-bit notifier format is no longer supported. This will
2637 * have to be exposed to upper layers.
2638 */
2639 ASSERT_DRF_NUM(C37D, _SET_NOTIFIER_CONTROL, _OFFSET, notifier);
2640
2641 ctrlVal = (awaken ?
2642 DRF_DEF(C37D, _SET_NOTIFIER_CONTROL, _MODE, _WRITE_AWAKEN) :
2643 DRF_DEF(C37D, _SET_NOTIFIER_CONTROL, _MODE, _WRITE));
2644 ctrlVal |= (notify ?
2645 DRF_DEF(C37D, _SET_NOTIFIER_CONTROL, _NOTIFY, _ENABLE) :
2646 DRF_DEF(C37D, _SET_NOTIFIER_CONTROL, _NOTIFY, _DISABLE));
2647
2648 // To work around HW BUG 1945716, set the core channel completion notifier
2649 // context DMA to 0 when notification is not requested.
2650 if (notify) {
2651 NvU32 sd;
2652 for (sd = 0; sd < pDevEvo->numSubDevices; sd++) {
2653 if (nvPeekEvoSubDevMask(pDevEvo) & (1 << sd)) {
2654 nvPushEvoSubDevMask(pDevEvo, NVBIT(sd));
2655 pDevEvo->hal->SetCoreNotifierSurfaceAddressAndControl(pChannel,
2656 &pDevEvo->core->notifiersDma[sd].surfaceDesc,
2657 notifier, ctrlVal);
2658 nvPopEvoSubDevMask(pDevEvo);
2659 }
2660 }
2661 } else {
2662 pDevEvo->hal->SetCoreNotifierSurfaceAddressAndControl(pChannel,
2663 NULL /* pSurfaceDesc */, 0 /* offset */ , 0 /* ctrlVal */);
2664 }
2665 }
2666
UpdateCoreC3(NVEvoChannelPtr pChannel,NVEvoChannelMask interlockChannelMask,NvU32 flipLockPin,NvBool releaseElv)2667 static void UpdateCoreC3(NVEvoChannelPtr pChannel,
2668 NVEvoChannelMask interlockChannelMask,
2669 NvU32 flipLockPin,
2670 NvBool releaseElv)
2671 {
2672 NvU32 head, interlockFlags = 0;
2673 NvU32 window, windowInterlockFlags = 0;
2674 NvU32 update = DRF_NUM(C37D, _UPDATE, _FLIP_LOCK_PIN, flipLockPin);
2675
2676 update |= releaseElv ? DRF_DEF(C37D, _UPDATE, _RELEASE_ELV, _TRUE) : 0;
2677
2678 for (head = 0; head < NV_EVO_CHANNEL_MASK_CURSOR__SIZE; head++) {
2679 if (FLD_IDX_TEST_DRF64(_EVO, _CHANNEL_MASK, _CURSOR, head, _ENABLE,
2680 interlockChannelMask)) {
2681 interlockFlags |=
2682 DRF_IDX_DEF(C37D, _SET_INTERLOCK_FLAGS,
2683 _INTERLOCK_WITH_CURSOR, head, _ENABLE);
2684 }
2685 }
2686
2687 for (window = 0; window < NV_EVO_CHANNEL_MASK_WINDOW__SIZE; window++) {
2688 if (FLD_IDX_TEST_DRF64(_EVO, _CHANNEL_MASK, _WINDOW, window, _ENABLE,
2689 interlockChannelMask)) {
2690 windowInterlockFlags |=
2691 DRF_IDX_DEF(C37D, _SET_WINDOW_INTERLOCK_FLAGS,
2692 _INTERLOCK_WITH_WINDOW, window, _ENABLE);
2693 }
2694 }
2695
2696 nvDmaSetStartEvoMethod(pChannel, NVC37D_SET_INTERLOCK_FLAGS, 1);
2697 nvDmaSetEvoMethodData(pChannel, interlockFlags);
2698
2699 nvDmaSetStartEvoMethod(pChannel, NVC37D_SET_WINDOW_INTERLOCK_FLAGS, 1);
2700 nvDmaSetEvoMethodData(pChannel, windowInterlockFlags);
2701
2702 nvDmaSetStartEvoMethod(pChannel, NVC37D_UPDATE, 1);
2703 nvDmaSetEvoMethodData(pChannel, update);
2704
2705 nvDmaKickoffEvo(pChannel);
2706 }
2707
UpdateWindowIMM(NVEvoChannelPtr pChannel,NVEvoChannelMask winImmChannelMask,NVEvoChannelMask winImmInterlockMask,NvBool releaseElv)2708 static void UpdateWindowIMM(NVEvoChannelPtr pChannel,
2709 NVEvoChannelMask winImmChannelMask,
2710 NVEvoChannelMask winImmInterlockMask,
2711 NvBool releaseElv)
2712 {
2713 nvAssert((winImmChannelMask & ~NV_EVO_CHANNEL_MASK_WINDOW_ALL) == 0);
2714 nvAssert((winImmInterlockMask & ~NV_EVO_CHANNEL_MASK_WINDOW_ALL) == 0);
2715
2716 if ((winImmChannelMask & pChannel->channelMask) != 0) {
2717 NvU32 updateImm = 0;
2718
2719 if ((winImmInterlockMask & pChannel->channelMask) != 0) {
2720 updateImm |= DRF_DEF(C37B, _UPDATE, _INTERLOCK_WITH_WINDOW, _ENABLE);
2721 } else {
2722 updateImm |= DRF_DEF(C37B, _UPDATE, _INTERLOCK_WITH_WINDOW, _DISABLE);
2723 }
2724 updateImm |= releaseElv ? DRF_DEF(C37B, _UPDATE, _RELEASE_ELV, _TRUE) : 0;
2725
2726 nvDmaSetStartEvoMethod(pChannel->imm.u.dma, NVC37B_UPDATE, 1);
2727 nvDmaSetEvoMethodData(pChannel->imm.u.dma, updateImm);
2728 nvDmaKickoffEvo(pChannel->imm.u.dma);
2729 }
2730 }
2731
UpdateWindowC3(NVEvoChannelPtr pChannel,NVEvoChannelMask interlockChannelMask,NVEvoChannelMask winImmChannelMask,NVEvoChannelMask winImmInterlockMask,NvBool transitionWAR,NvU32 flipLockPin,NvBool releaseElv)2732 static void UpdateWindowC3(NVEvoChannelPtr pChannel,
2733 NVEvoChannelMask interlockChannelMask,
2734 NVEvoChannelMask winImmChannelMask,
2735 NVEvoChannelMask winImmInterlockMask,
2736 NvBool transitionWAR,
2737 NvU32 flipLockPin,
2738 NvBool releaseElv)
2739 {
2740 NvU32 head, interlockFlags = 0;
2741 NvU32 window, windowInterlockFlags = 0;
2742 NvU32 update = DRF_NUM(C37E, _UPDATE, _FLIP_LOCK_PIN, flipLockPin);
2743
2744 update |= releaseElv ? DRF_DEF(C37E, _UPDATE, _RELEASE_ELV, _TRUE) : 0;
2745
2746 if ((winImmInterlockMask & pChannel->channelMask) != 0) {
2747 /*
2748 * We expect winImmChannelMask to always be a superset of
2749 * winImmInterlockMask. We should never interlock with a window
2750 * immediate channel if we're not also going to kick off that
2751 * window immediate channel.
2752 */
2753 nvAssert((winImmChannelMask & pChannel->channelMask) != 0);
2754
2755 update |= DRF_DEF(C37E, _UPDATE, _INTERLOCK_WITH_WIN_IMM, _ENABLE);
2756 } else {
2757 update |= DRF_DEF(C37E, _UPDATE, _INTERLOCK_WITH_WIN_IMM, _DISABLE);
2758 }
2759
2760 // Nothing currently requires updating a window channel without releasing
2761 // ELV.
2762 nvAssert(releaseElv);
2763
2764 if (FLD_TEST_DRF64(_EVO, _CHANNEL_MASK, _CORE, _ENABLE,
2765 interlockChannelMask)) {
2766 interlockFlags |=
2767 DRF_DEF(C37E, _SET_INTERLOCK_FLAGS, _INTERLOCK_WITH_CORE, _ENABLE);
2768 }
2769
2770 for (head = 0; head < NV_EVO_CHANNEL_MASK_CURSOR__SIZE; head++) {
2771 if (FLD_IDX_TEST_DRF64(_EVO, _CHANNEL_MASK, _CURSOR, head, _ENABLE,
2772 interlockChannelMask)) {
2773 interlockFlags |=
2774 DRF_IDX_DEF(C37E, _SET_INTERLOCK_FLAGS,
2775 _INTERLOCK_WITH_CURSOR, head, _ENABLE);
2776 }
2777 }
2778
2779 for (window = 0; window < NV_EVO_CHANNEL_MASK_WINDOW__SIZE; window++) {
2780 if (FLD_IDX_TEST_DRF64(_EVO, _CHANNEL_MASK, _WINDOW, window, _ENABLE,
2781 interlockChannelMask)) {
2782 windowInterlockFlags |=
2783 DRF_IDX_DEF(C37E, _SET_WINDOW_INTERLOCK_FLAGS,
2784 _INTERLOCK_WITH_WINDOW, window, _ENABLE);
2785 }
2786 }
2787
2788 nvDmaSetStartEvoMethod(pChannel, NVC37E_SET_INTERLOCK_FLAGS, 1);
2789 nvDmaSetEvoMethodData(pChannel, interlockFlags);
2790
2791 nvDmaSetStartEvoMethod(pChannel, NVC37E_SET_WINDOW_INTERLOCK_FLAGS, 1);
2792 nvDmaSetEvoMethodData(pChannel, windowInterlockFlags);
2793
2794 /*
2795 * If we determined that this update will transition from NULL to non-NULL
2796 * ctxdma or vice-versa, bookend this update method with software methods
2797 * to notify RM to apply a workaround for hardware bug 2193096.
2798 */
2799 if (transitionWAR) {
2800 nvDmaSetStartEvoMethod(pChannel, NVC57E_SW_SET_MCLK_SWITCH, 1);
2801 nvDmaSetEvoMethodData(pChannel,
2802 DRF_DEF(C57E, _SW_SET_MCLK_SWITCH, _ENABLE, _FALSE));
2803 }
2804
2805 nvDmaSetStartEvoMethod(pChannel, NVC37E_UPDATE, 1);
2806 nvDmaSetEvoMethodData(pChannel, update);
2807
2808 if (transitionWAR) {
2809 nvDmaSetStartEvoMethod(pChannel, NVC57E_SW_SET_MCLK_SWITCH, 1);
2810 nvDmaSetEvoMethodData(pChannel,
2811 DRF_DEF(C57E, _SW_SET_MCLK_SWITCH, _ENABLE, _TRUE));
2812 }
2813
2814 UpdateWindowIMM(pChannel, winImmChannelMask,
2815 winImmInterlockMask, releaseElv);
2816
2817 nvDmaKickoffEvo(pChannel);
2818 }
2819
2820 /*!
2821 * This function finds any fliplocked channels in the current update and pushes
2822 * flips for them setting the appropriate fliplock pin and interlock masks.
2823 *
2824 * All of this complexity is here to support the case where multiple heads on a
2825 * single GPU are fliplocked together, but flip requests come in for only a
2826 * subset of those heads at a time (e.g., separate X screens on a single GPU).
2827 * Unlike previous hardware, we're required to interlock all channels which are
2828 * part of a fliplock update, instead of just using fliplock across heads.
2829 */
2830 /*
2831 * There are two scenarios:
2832 * a) All fliplocked channels on this GPU are already part of this update. In
2833 * that case we just need to set the appropriate fliplock pin for each, and
2834 * we're done -- they're already interlocked.
2835 * b) Some fliplocked channels are not part of this update. We still need to
2836 * set them in the interlock mask, but it's dangerous to interlock with any
2837 * channels *not* in the fliplock group; as an example:
2838 * With two separate X screens on a single GPU, each driving one monitor,
2839 * fliplocked together, if we get a flip request for screen 0/head 0 that
2840 * interlocks core and base, then a second flip request for screen 1/head1
2841 * that interlocks core and base, we would end up programming one flip on
2842 * the window on head 0, one flip on the window on head 1, and two flips in
2843 * the core channel. The second core channel flip would never complete
2844 * since it would be waiting for an interlock with the other window
2845 * channels.
2846 *
2847 * To handle this case we pull the fliplocked channels out of this update
2848 * and update them interlocked with all fliplocked channels (including those
2849 * that aren't in this update), then proceed with a normal interlocked
2850 * update excluding the fliplocked channels.
2851 *
2852 * \return Channel mask of channels which were handled by this function.
2853 * Channels in this mask should be considered done and have no
2854 * further updates pushed. No other channels should be
2855 * interlocked with them.
2856 */
ProcessFlipLockUpdates(NVDevEvoPtr pDevEvo,NvU32 sd,NvU32 * pFlipLockPin,const NVEvoUpdateState * updateState)2857 static NVEvoChannelMask ProcessFlipLockUpdates(
2858 NVDevEvoPtr pDevEvo,
2859 NvU32 sd,
2860 NvU32 *pFlipLockPin,
2861 const NVEvoUpdateState *updateState)
2862 {
2863 NVEvoSubDevPtr pEvoSubDev = &pDevEvo->gpus[sd];
2864 NvU32 head, window;
2865 /* Channels that are part of this update which need to be fliplocked. */
2866 NVEvoChannelMask flipLockUpdateMask = 0;
2867 /* All channels on this subdevice which are fliplocked. */
2868 NVEvoChannelMask flipLockAllMask = 0;
2869 /* Channels which this function has handled and do not need further
2870 * processing. */
2871 NVEvoChannelMask handledMask = 0;
2872 NVEvoLockPin pin = NV_EVO_LOCK_PIN_ERROR;
2873 NvU32 hwPin = NVC37E_UPDATE_FLIP_LOCK_PIN_LOCK_PIN_NONE;
2874
2875 /* First check if any of the fliplock-qualifying channels are actually
2876 * fliplocked, and determine which pin they're using. */
2877 for (head = 0; head < pDevEvo->numHeads; head++) {
2878 NVEvoHeadControlPtr pHC = &pEvoSubDev->headControl[head];
2879
2880 if (pHC->flipLock) {
2881 /* Convert the head index to a window index (two windows per head,
2882 * one "base" and one "overlay"; we only fliplock "base") */
2883 NVEvoChannelMask windowMask =
2884 DRF_IDX_DEF64(_EVO, _CHANNEL_MASK, _WINDOW, head * 2, _ENABLE);
2885 if (updateState->subdev[sd].flipLockQualifyingMask & windowMask) {
2886 if (flipLockUpdateMask == 0) {
2887 pin = pHC->flipLockPin;
2888 } else {
2889 /* For now, we only support kicking off a single fliplock
2890 * group as part of a single update call. */
2891 nvAssert(pin == pHC->flipLockPin);
2892 }
2893 flipLockUpdateMask |= windowMask;
2894 }
2895 }
2896 }
2897
2898 /* If we don't have any fliplocked updates, then we're done. */
2899 if (flipLockUpdateMask == 0) {
2900 goto done;
2901 }
2902
2903 /*
2904 * Gather all of the channels on this GPU which are part of this fliplock
2905 * group (some of which may not be part of this update).
2906 */
2907 for (head = 0; head < pDevEvo->numHeads; head++) {
2908 NVEvoHeadControlPtr pHC = &pEvoSubDev->headControl[head];
2909
2910 if (pHC->flipLock && (pHC->flipLockPin == pin)) {
2911 NVEvoChannelMask windowMask =
2912 DRF_IDX_DEF64(_EVO, _CHANNEL_MASK, _WINDOW, head * 2, _ENABLE);
2913 flipLockAllMask |= windowMask;
2914 }
2915 }
2916
2917 /* Convert the pin to a hardware enum. */
2918 if (NV_EVO_LOCK_PIN_IS_INTERNAL(pin)) {
2919 hwPin = NVC37E_UPDATE_FLIP_LOCK_PIN_INTERNAL_FLIP_LOCK_0 +
2920 (pin - NV_EVO_LOCK_PIN_INTERNAL_0);
2921 } else {
2922 hwPin = NVC37E_UPDATE_FLIP_LOCK_PIN_LOCK_PIN(pin - NV_EVO_LOCK_PIN_0);
2923 }
2924
2925 /* If we're updating all of the fliplocked channels in this update, we can
2926 * interlock with other channels as normal. */
2927 if (flipLockUpdateMask == flipLockAllMask) {
2928 goto done;
2929 }
2930
2931 /*
2932 * Kick off each of our update channels, using the full fliplock mask and
2933 * hwPin calculated above.
2934 */
2935 nvAssert((flipLockUpdateMask & ~NV_EVO_CHANNEL_MASK_WINDOW_ALL) == 0);
2936 for (window = 0; window < pDevEvo->numWindows; window++) {
2937 const NVEvoChannelMask windowMask =
2938 DRF_IDX_DEF64(_EVO, _CHANNEL_MASK, _WINDOW, window, _ENABLE);
2939 NVEvoChannelMask winImmChannelMask =
2940 updateState->subdev[sd].winImmChannelMask;
2941 NVEvoChannelMask winImmInterlockMask =
2942 updateState->subdev[sd].winImmInterlockMask;
2943 if (flipLockUpdateMask & windowMask) {
2944 const NvBool transitionWAR =
2945 (updateState->subdev[sd].flipTransitionWAR & windowMask) != 0;
2946 UpdateWindowC3(pDevEvo->window[window],
2947 flipLockAllMask,
2948 winImmChannelMask,
2949 winImmInterlockMask,
2950 transitionWAR,
2951 hwPin, TRUE /* releaseElv */);
2952 } else {
2953 UpdateWindowIMM(pDevEvo->window[window], winImmChannelMask,
2954 winImmInterlockMask, TRUE /* releaseElv */);
2955 }
2956 }
2957 handledMask = flipLockUpdateMask;
2958 hwPin = NVC37E_UPDATE_FLIP_LOCK_PIN_LOCK_PIN_NONE;
2959
2960 done:
2961 *pFlipLockPin = hwPin;
2962 return handledMask;
2963 }
2964
nvEvoUpdateC3(NVDevEvoPtr pDevEvo,const NVEvoUpdateState * updateState,NvBool releaseElv)2965 void nvEvoUpdateC3(NVDevEvoPtr pDevEvo,
2966 const NVEvoUpdateState *updateState,
2967 NvBool releaseElv)
2968 {
2969 NvU32 sd, window;
2970
2971 for (sd = 0; sd < pDevEvo->numSubDevices; sd++) {
2972 NVEvoChannelMask updateChannelMask =
2973 updateState->subdev[sd].channelMask;
2974 const NVEvoChannelMask noCoreInterlockMask =
2975 updateState->subdev[sd].noCoreInterlockMask;
2976 NVEvoChannelMask coreInterlockMask =
2977 updateChannelMask & ~noCoreInterlockMask;
2978 const NvU32 subDeviceMask = (1 << sd);
2979 NvU32 flipLockPin = NVC37E_UPDATE_FLIP_LOCK_PIN_LOCK_PIN_NONE;
2980
2981 nvPushEvoSubDevMask(pDevEvo, subDeviceMask);
2982
2983 if (updateState->subdev[sd].flipLockQualifyingMask) {
2984 NVEvoChannelMask handledChannels = 0;
2985
2986 nvAssert((updateState->subdev[sd].flipLockQualifyingMask &
2987 ~updateChannelMask) == 0);
2988 nvAssert((updateState->subdev[sd].flipLockQualifyingMask &
2989 updateState->subdev[sd].noCoreInterlockMask) == 0);
2990
2991 handledChannels =
2992 ProcessFlipLockUpdates(pDevEvo, sd, &flipLockPin, updateState);
2993
2994 updateChannelMask &= ~handledChannels;
2995 coreInterlockMask &= ~handledChannels;
2996 }
2997
2998 if (FLD_TEST_DRF64(_EVO, _CHANNEL_MASK, _CORE, _ENABLE,
2999 updateChannelMask)) {
3000 const NVEvoChannelMask thisInterlockMask =
3001 FLD_TEST_DRF64(_EVO, _CHANNEL_MASK, _CORE, _ENABLE,
3002 coreInterlockMask) ? coreInterlockMask : 0;
3003 UpdateCoreC3(pDevEvo->core, thisInterlockMask, flipLockPin,
3004 releaseElv);
3005 }
3006
3007 for (window = 0; window < pDevEvo->numWindows; window++) {
3008 const NVEvoChannelMask windowMask =
3009 DRF_IDX_DEF64(_EVO, _CHANNEL_MASK, _WINDOW, window, _ENABLE);
3010 NVEvoChannelMask winImmChannelMask =
3011 updateState->subdev[sd].winImmChannelMask;
3012 NVEvoChannelMask winImmInterlockMask =
3013 updateState->subdev[sd].winImmInterlockMask;
3014 if (updateChannelMask & windowMask) {
3015 const NvBool transitionWAR =
3016 (updateState->subdev[sd].flipTransitionWAR & windowMask) != 0;
3017 NVEvoChannelMask thisInterlockMask =
3018 FLD_IDX_TEST_DRF64(_EVO, _CHANNEL_MASK, _WINDOW, window, _ENABLE,
3019 coreInterlockMask) ? coreInterlockMask : 0;
3020 UpdateWindowC3(pDevEvo->window[window],
3021 thisInterlockMask,
3022 winImmChannelMask,
3023 winImmInterlockMask,
3024 transitionWAR,
3025 flipLockPin,
3026 releaseElv);
3027 } else {
3028 UpdateWindowIMM(pDevEvo->window[window], winImmChannelMask,
3029 winImmInterlockMask, releaseElv);
3030 }
3031 }
3032
3033 nvPopEvoSubDevMask(pDevEvo);
3034 }
3035 }
3036
3037 /*!
3038 * Initialize head-specific IMP param fields.
3039 *
3040 * Initialize the NVC372_CTRL_IMP_HEAD for the specific head.
3041 *
3042 * \param[out] pImpHead The param structure to initialize.
3043 * \param[in] pTimings The rastering timings and viewport configuration.
3044 * \param[in] head The number of the head that will be driven.
3045 *
3046 * \return FALSE iff the parameters aren't even legal for HW.
3047 */
AssignPerHeadImpParams(NVC372_CTRL_IMP_HEAD * pImpHead,const NVHwModeTimingsEvo * pTimings,const NvBool enableDsc,const NvBool b2Heads1Or,const int head,const NVEvoScalerCaps * pScalerCaps)3048 static NvBool AssignPerHeadImpParams(NVC372_CTRL_IMP_HEAD *pImpHead,
3049 const NVHwModeTimingsEvo *pTimings,
3050 const NvBool enableDsc,
3051 const NvBool b2Heads1Or,
3052 const int head,
3053 const NVEvoScalerCaps *pScalerCaps)
3054 {
3055 const NVHwModeViewPortEvo *pViewPort = &pTimings->viewPort;
3056 struct NvKmsScalingUsageBounds scalingUsageBounds = { };
3057
3058 pImpHead->headIndex = head;
3059
3060 /* raster timings */
3061
3062 pImpHead->maxPixelClkKHz = pTimings->pixelClock;
3063
3064 pImpHead->rasterSize.width = pTimings->rasterSize.x;
3065 pImpHead->rasterSize.height = pTimings->rasterSize.y;
3066 pImpHead->rasterBlankStart.X = pTimings->rasterBlankStart.x;
3067 pImpHead->rasterBlankStart.Y = pTimings->rasterBlankStart.y;
3068 pImpHead->rasterBlankEnd.X = pTimings->rasterBlankEnd.x;
3069 pImpHead->rasterBlankEnd.Y = pTimings->rasterBlankEnd.y;
3070 pImpHead->rasterVertBlank2.yStart = pTimings->rasterVertBlank2Start;
3071 pImpHead->rasterVertBlank2.yEnd = pTimings->rasterVertBlank2End;
3072
3073 /* XXX TODO: Fill in correct scanlock information (only needed for
3074 * MIN_VPSTATE). */
3075 pImpHead->control.masterLockMode = NV_DISP_LOCK_MODE_NO_LOCK;
3076 pImpHead->control.masterLockPin = NV_DISP_LOCK_PIN_UNSPECIFIED;
3077 pImpHead->control.slaveLockMode = NV_DISP_LOCK_MODE_NO_LOCK;
3078 pImpHead->control.slaveLockPin = NV_DISP_LOCK_PIN_UNSPECIFIED;
3079
3080 if (!nvComputeScalingUsageBounds(pScalerCaps,
3081 pViewPort->in.width, pViewPort->in.height,
3082 pViewPort->out.width, pViewPort->out.height,
3083 pViewPort->hTaps, pViewPort->vTaps,
3084 &scalingUsageBounds)) {
3085 return FALSE;
3086 }
3087 pImpHead->bUpscalingAllowedV = scalingUsageBounds.vUpscalingAllowed;
3088 pImpHead->maxDownscaleFactorV = scalingUsageBounds.maxVDownscaleFactor;
3089 pImpHead->maxDownscaleFactorH = scalingUsageBounds.maxHDownscaleFactor;
3090 pImpHead->outputScalerVerticalTaps =
3091 NVEvoScalerTapsToNum(scalingUsageBounds.vTaps);
3092
3093 if (!nvComputeMinFrameIdle(pTimings,
3094 &pImpHead->minFrameIdle.leadingRasterLines,
3095 &pImpHead->minFrameIdle.trailingRasterLines)) {
3096 return FALSE;
3097 }
3098
3099 /* Assume we'll need the full 1025-entry output LUT. */
3100 pImpHead->lut = NVC372_CTRL_IMP_LUT_USAGE_1025;
3101
3102 /* Cursor width, in units of 32 pixels. Assume we use the maximum size. */
3103 pImpHead->cursorSize32p = 256 / 32;
3104
3105 pImpHead->bEnableDsc = enableDsc;
3106
3107 pImpHead->bIs2Head1Or = b2Heads1Or;
3108
3109 pImpHead->bYUV420Format =
3110 (pTimings->yuv420Mode == NV_YUV420_MODE_HW);
3111
3112 return TRUE;
3113 }
3114
3115 /*!
3116 * Initialize window-specific IMP param fields.
3117 *
3118 * Initialize the NVC372_CTRL_IMP_WINDOW for the specific window.
3119 *
3120 * \param[out] pImpWindow The param structure to initialize.
3121 * \param[in] pViewPort The viewport configuration for the head that
3122 * the window is bound to.
3123 * \param[in] supportedFormats The surface memory formats that can be
3124 * supported on this window.
3125 * \param[in] window The number of the window.
3126 * \param[in] head The number of the head that the window is
3127 * bound to.
3128 */
AssignPerWindowImpParams(NVC372_CTRL_IMP_WINDOW * pImpWindow,const NVHwModeViewPortEvo * pViewPort,const NvU64 supportedFormats,const struct NvKmsScalingUsageBounds * pScaling,const int window,const int head)3129 static void AssignPerWindowImpParams(NVC372_CTRL_IMP_WINDOW *pImpWindow,
3130 const NVHwModeViewPortEvo *pViewPort,
3131 const NvU64 supportedFormats,
3132 const struct NvKmsScalingUsageBounds *pScaling,
3133 const int window,
3134 const int head)
3135 {
3136 pImpWindow->windowIndex = window;
3137 pImpWindow->owningHead = head;
3138
3139 pImpWindow->formatUsageBound = 0;
3140 if (supportedFormats & NVKMS_SURFACE_MEMORY_FORMATS_RGB_PACKED1BPP) {
3141 pImpWindow->formatUsageBound |= NVC372_CTRL_FORMAT_RGB_PACKED_1_BPP;
3142 }
3143 if (supportedFormats & NVKMS_SURFACE_MEMORY_FORMATS_RGB_PACKED2BPP) {
3144 pImpWindow->formatUsageBound |= NVC372_CTRL_FORMAT_RGB_PACKED_2_BPP;
3145 }
3146 if (supportedFormats & NVKMS_SURFACE_MEMORY_FORMATS_RGB_PACKED4BPP) {
3147 pImpWindow->formatUsageBound |= NVC372_CTRL_FORMAT_RGB_PACKED_4_BPP;
3148 }
3149 if (supportedFormats & NVKMS_SURFACE_MEMORY_FORMATS_RGB_PACKED8BPP) {
3150 pImpWindow->formatUsageBound |= NVC372_CTRL_FORMAT_RGB_PACKED_8_BPP;
3151 }
3152 if (supportedFormats & NVKMS_SURFACE_MEMORY_FORMATS_YUV_PACKED422) {
3153 pImpWindow->formatUsageBound |= NVC372_CTRL_FORMAT_YUV_PACKED_422;
3154 }
3155 if (supportedFormats & NVKMS_SURFACE_MEMORY_FORMATS_YUV_SP420) {
3156 pImpWindow->formatUsageBound |= NVC372_CTRL_FORMAT_YUV_SEMI_PLANAR_420;
3157 }
3158 if (supportedFormats & NVKMS_SURFACE_MEMORY_FORMATS_YUV_SP422) {
3159 pImpWindow->formatUsageBound |= NVC372_CTRL_FORMAT_YUV_SEMI_PLANAR_422;
3160 }
3161 if (supportedFormats & NVKMS_SURFACE_MEMORY_FORMATS_YUV_SP444) {
3162 pImpWindow->formatUsageBound |= NVC372_CTRL_FORMAT_YUV_SEMI_PLANAR_444;
3163 }
3164 if (supportedFormats & NVKMS_SURFACE_MEMORY_FORMATS_EXT_YUV_SP420) {
3165 pImpWindow->formatUsageBound |=
3166 NVC372_CTRL_FORMAT_EXT_YUV_SEMI_PLANAR_420;
3167 }
3168 if (supportedFormats & NVKMS_SURFACE_MEMORY_FORMATS_EXT_YUV_SP422) {
3169 pImpWindow->formatUsageBound |=
3170 NVC372_CTRL_FORMAT_EXT_YUV_SEMI_PLANAR_422;
3171 }
3172 if (supportedFormats & NVKMS_SURFACE_MEMORY_FORMATS_EXT_YUV_SP444) {
3173 pImpWindow->formatUsageBound |=
3174 NVC372_CTRL_FORMAT_EXT_YUV_SEMI_PLANAR_444;
3175 }
3176 if (supportedFormats & NVKMS_SURFACE_MEMORY_FORMATS_YUV_PLANAR444) {
3177 pImpWindow->formatUsageBound |=
3178 NVC372_CTRL_FORMAT_YUV_PLANAR_444;
3179 }
3180 if (supportedFormats & NVKMS_SURFACE_MEMORY_FORMATS_YUV_PLANAR420) {
3181 pImpWindow->formatUsageBound |=
3182 NVC372_CTRL_FORMAT_YUV_PLANAR_420;
3183 }
3184
3185 if (pImpWindow->formatUsageBound == 0) {
3186 nvAssert(!"Unknown format in AssignPerWindowImpParams");
3187 }
3188
3189 pImpWindow->maxPixelsFetchedPerLine =
3190 nvGetMaxPixelsFetchedPerLine(pViewPort->in.width,
3191 pScaling->maxHDownscaleFactor);
3192
3193 pImpWindow->maxDownscaleFactorH = pScaling->maxHDownscaleFactor;
3194 pImpWindow->maxDownscaleFactorV = pScaling->maxVDownscaleFactor;
3195 pImpWindow->bUpscalingAllowedV = pScaling->vUpscalingAllowed;
3196 pImpWindow->inputScalerVerticalTaps =
3197 NVEvoScalerTapsToNum(pScaling->vTaps);
3198
3199 /* Assume we need a full 1025-entry window (input) and tone-mapping
3200 * output (TMO) LUT. */
3201 pImpWindow->lut = NVC372_CTRL_IMP_LUT_USAGE_1025;
3202 pImpWindow->tmoLut = NVC372_CTRL_IMP_LUT_USAGE_1025;
3203 }
3204
3205 void
nvEvoIsModePossibleC3(NVDispEvoPtr pDispEvo,const NVEvoIsModePossibleDispInput * pInput,NVEvoIsModePossibleDispOutput * pOutput)3206 nvEvoIsModePossibleC3(NVDispEvoPtr pDispEvo,
3207 const NVEvoIsModePossibleDispInput *pInput,
3208 NVEvoIsModePossibleDispOutput *pOutput)
3209 {
3210 NVDevEvoPtr pDevEvo = pDispEvo->pDevEvo;
3211 const NVEvoCapabilitiesPtr pEvoCaps = &pDevEvo->gpus[0].capabilities;
3212 NVC372_CTRL_IS_MODE_POSSIBLE_PARAMS *pImp =
3213 nvPreallocGet(pDevEvo, PREALLOC_TYPE_IMP_PARAMS, sizeof(*pImp));
3214 NvBool result = FALSE;
3215 NvU32 head;
3216 NvU32 ret;
3217
3218 nvkms_memset(pImp, 0, sizeof(*pImp));
3219
3220 for (head = 0; head < NVKMS_MAX_HEADS_PER_DISP; head++) {
3221 const NVHwModeTimingsEvo *pTimings = pInput->head[head].pTimings;
3222 const NvU32 enableDsc = pInput->head[head].enableDsc;
3223 const NvBool b2Heads1Or = pInput->head[head].b2Heads1Or;
3224 const struct NvKmsUsageBounds *pUsage = pInput->head[head].pUsage;
3225 const NVHwModeViewPortEvo *pViewPort;
3226 NvU8 impHeadIndex;
3227 NvU32 layer;
3228
3229 if (pTimings == NULL) {
3230 continue;
3231 }
3232
3233 pViewPort = &pTimings->viewPort;
3234
3235 impHeadIndex = pImp->numHeads;
3236 pImp->numHeads++;
3237 nvAssert(impHeadIndex < NVC372_CTRL_MAX_POSSIBLE_HEADS);
3238
3239 if (!AssignPerHeadImpParams(&pImp->head[impHeadIndex],
3240 pTimings,
3241 enableDsc,
3242 b2Heads1Or,
3243 head,
3244 &pEvoCaps->head[head].scalerCaps)) {
3245 goto done;
3246 }
3247
3248 /* XXXnvdisplay: This assumes a fixed window<->head mapping */
3249 for (layer = 0; layer < pDevEvo->head[head].numLayers; layer++) {
3250 if (!pUsage->layer[layer].usable) {
3251 continue;
3252 }
3253
3254 nvAssert(pImp->numWindows < NVC372_CTRL_MAX_POSSIBLE_WINDOWS);
3255
3256 AssignPerWindowImpParams(
3257 &pImp->window[pImp->numWindows],
3258 pViewPort,
3259 pUsage->layer[layer].supportedSurfaceMemoryFormats,
3260 &pUsage->layer[layer].scaling,
3261 NV_EVO_CHANNEL_MASK_WINDOW_NUMBER(
3262 pDevEvo->head[head].layer[layer]->channelMask),
3263 head);
3264
3265 pImp->numWindows++;
3266 }
3267 }
3268
3269 pImp->base.subdeviceIndex = pDispEvo->displayOwner;
3270
3271 /* XXXnvdisplay: Set bUseCachedPerfState? */
3272
3273 /*
3274 * Set NEED_MIN_VPSTATE if reallocBandwidth != NONE. RM-IMP will only
3275 * output the min required display bandwidth values if NEED_MIN_VPSTATE
3276 * is set.
3277 */
3278 if (pInput->requireBootClocks ||
3279 (pInput->reallocBandwidth != NV_EVO_REALLOCATE_BANDWIDTH_MODE_NONE)) {
3280 // XXX TODO: IMP requires lock pin information if pstate information is
3281 // requested. For now, just assume no locking.
3282 pImp->options = NVC372_CTRL_IS_MODE_POSSIBLE_OPTIONS_NEED_MIN_VPSTATE;
3283 }
3284
3285 ret = nvRmApiControl(nvEvoGlobal.clientHandle,
3286 pDevEvo->rmCtrlHandle,
3287 NVC372_CTRL_CMD_IS_MODE_POSSIBLE,
3288 pImp, sizeof(*pImp));
3289
3290 // XXXnvdisplay TODO: check pImp->minImpVPState if
3291 // pInput->requireBootClocks is true?
3292 if (ret != NV_OK || !pImp->bIsPossible) {
3293 goto done;
3294 }
3295
3296 result = TRUE;
3297
3298 done:
3299 pOutput->possible = result;
3300 if (pOutput->possible) {
3301 pOutput->minRequiredBandwidthKBPS = pImp->minRequiredBandwidthKBPS;
3302 pOutput->floorBandwidthKBPS = pImp->floorBandwidthKBPS;
3303 }
3304
3305 nvPreallocRelease(pDevEvo, PREALLOC_TYPE_IMP_PARAMS);
3306 }
3307
nvEvoPrePostIMPC3(NVDispEvoPtr pDispEvo,NvBool isPre)3308 void nvEvoPrePostIMPC3(NVDispEvoPtr pDispEvo, NvBool isPre)
3309 {
3310 /* Nothing to do on nvdisplay -- pre/post IMP calls are not required. */
3311 }
3312
3313 static void
3314 EvoFlipC3(NVDevEvoPtr pDevEvo,
3315 NVEvoChannelPtr pChannel,
3316 const NVFlipChannelEvoHwState *pHwState,
3317 NVEvoUpdateState *updateState,
3318 NvBool bypassComposition);
3319
3320 /*
3321 * Returns TRUE iff the CSC should be enabled (i.e., the matrix is not the
3322 * identity matrix).
3323 */
SetCscMatrixC3(NVEvoChannelPtr pChannel,const struct NvKmsCscMatrix * matrix)3324 static NvBool SetCscMatrixC3(NVEvoChannelPtr pChannel,
3325 const struct NvKmsCscMatrix *matrix)
3326 {
3327 NvU32 method = NVC37E_SET_CSC_RED2RED;
3328 int y;
3329
3330 if (nvIsCscMatrixIdentity(matrix)) {
3331 return FALSE;
3332 }
3333
3334 for (y = 0; y < 3; y++) {
3335 int x;
3336
3337 for (x = 0; x < 4; x++) {
3338 // Use DRF_NUM to truncate client-supplied values that are out of
3339 // range.
3340 NvU32 val = DRF_NUM(C37E, _SET_CSC_RED2RED, _COEFF,
3341 matrix->m[y][x]);
3342
3343 nvDmaSetStartEvoMethod(pChannel, method, 1);
3344 nvDmaSetEvoMethodData(pChannel, val);
3345
3346 method += 4;
3347 }
3348 }
3349
3350 return TRUE;
3351 }
3352
SetCscMatrixC5Wrapper(NVEvoChannelPtr pChannel,const struct NvKmsCscMatrix * matrix,NvU32 coeffMethod,NvU32 controlMethod,NvU32 enableMethodData,NvU32 disableMethodData)3353 static void SetCscMatrixC5Wrapper(NVEvoChannelPtr pChannel,
3354 const struct NvKmsCscMatrix *matrix,
3355 NvU32 coeffMethod, NvU32 controlMethod,
3356 NvU32 enableMethodData,
3357 NvU32 disableMethodData)
3358 {
3359 int y;
3360
3361 if (nvIsCscMatrixIdentity(matrix)) {
3362 nvDmaSetStartEvoMethod(pChannel, controlMethod, 1);
3363 nvDmaSetEvoMethodData(pChannel, disableMethodData);
3364 return;
3365 }
3366
3367 nvDmaSetStartEvoMethod(pChannel, controlMethod, 1);
3368 nvDmaSetEvoMethodData(pChannel, enableMethodData);
3369
3370 for (y = 0; y < 3; y++) {
3371 int x;
3372
3373 for (x = 0; x < 4; x++) {
3374 // Use DRF_NUM to truncate client-supplied values that are out of
3375 // range.
3376 //
3377 // Note that it doesn't matter whether we use the CSC00 or CSC11
3378 // methods to truncate since they're identical.
3379 NvU32 val = DRF_NUM(C57E, _SET_CSC00COEFFICIENT_C00, _VALUE,
3380 matrix->m[y][x]);
3381
3382 nvDmaSetStartEvoMethod(pChannel, coeffMethod, 1);
3383 nvDmaSetEvoMethodData(pChannel, val);
3384
3385 coeffMethod += 4;
3386 }
3387 }
3388 }
3389
SetCsc00MatrixC5(NVEvoChannelPtr pChannel,const struct NvKmsCscMatrix * matrix)3390 static void SetCsc00MatrixC5(NVEvoChannelPtr pChannel,
3391 const struct NvKmsCscMatrix *matrix)
3392 {
3393 SetCscMatrixC5Wrapper(pChannel,
3394 matrix,
3395 NVC57E_SET_CSC00COEFFICIENT_C00, NVC57E_SET_CSC00CONTROL,
3396 DRF_DEF(C57E, _SET_CSC00CONTROL, _ENABLE, _ENABLE),
3397 DRF_DEF(C57E, _SET_CSC00CONTROL, _ENABLE, _DISABLE));
3398 }
3399
SetCsc11MatrixC5(NVEvoChannelPtr pChannel,const struct NvKmsCscMatrix * matrix)3400 static void SetCsc11MatrixC5(NVEvoChannelPtr pChannel,
3401 const struct NvKmsCscMatrix *matrix)
3402 {
3403 SetCscMatrixC5Wrapper(pChannel,
3404 matrix,
3405 NVC57E_SET_CSC11COEFFICIENT_C00, NVC57E_SET_CSC11CONTROL,
3406 DRF_DEF(C57E, _SET_CSC11CONTROL, _ENABLE, _ENABLE),
3407 DRF_DEF(C57E, _SET_CSC11CONTROL, _ENABLE, _DISABLE));
3408 }
3409
3410 /*
3411 * WAR for GV100 HW bug 1978592:
3412 *
3413 * Timestamped flips allow SW to specify the earliest time that the next UPDATE
3414 * will complete. Due to a HW bug, GV100 waits for the timestamp in the ARMED
3415 * state (i.e. the timestamps that were pushed in the previous UPDATE) instead
3416 * of the timestamp in the ASSEMBLY state (the time we want to postpone this
3417 * flip until).
3418 *
3419 * This WAR inserts an additional UPDATE to push the timestamp from ASSEMBLY to
3420 * ARMED while changing no other state, so the following normal UPDATE can
3421 * wait for the correct timestamp.
3422 *
3423 * This update needs to have the following characteristics:
3424 *
3425 * - MIN_PRESENT_INTERVAL 0
3426 * - TIMESTAMP_MODE _ENABLE
3427 * - All other SET_PRESENT_CONTROL fields unmodified from previous UPDATE
3428 * - SET_UPDATE_TIMESTAMP (target timestamp)
3429 * - RELEASE_ELV _FALSE
3430 * - Non-interlocked
3431 * - Non-fliplocked
3432 */
3433 static void
InsertAdditionalTimestampFlip(NVDevEvoPtr pDevEvo,NVEvoChannelPtr pChannel,const NVFlipChannelEvoHwState * pHwState,NVEvoUpdateState * updateState)3434 InsertAdditionalTimestampFlip(NVDevEvoPtr pDevEvo,
3435 NVEvoChannelPtr pChannel,
3436 const NVFlipChannelEvoHwState *pHwState,
3437 NVEvoUpdateState *updateState)
3438 {
3439 NvU32 presentControl = pChannel->oldPresentControl;
3440
3441 /* This hardware bug is only present on GV100 which uses window
3442 * class C37E. */
3443 nvAssert(pChannel->hwclass == NVC37E_WINDOW_CHANNEL_DMA);
3444
3445 nvAssert(pHwState->timeStamp != 0);
3446
3447 /*
3448 * Update the necessary fields in SET_PRESENT_CONTROL without modifying
3449 * the existing values by using the cached SET_PRESENT_CONTROL values
3450 * from the previous update.
3451 *
3452 * Note that BEGIN_MODE must not be changed here; even though BEGIN_MODE
3453 * may currently be NON_TEARING, a NON_TEARING + MIN_PRESENT_INTERVAL 0
3454 * flip will be correctly collapsed with the surrounding
3455 * MIN_PRESENT_INTERVAL 1 flips. If we were to change BEGIN_MODE to
3456 * IMMEDIATE, this would cause an additional delay due to the transition
3457 * from NON_TEARING to IMMEDIATE.
3458 */
3459 presentControl = FLD_SET_DRF_NUM(C37E, _SET_PRESENT_CONTROL,
3460 _MIN_PRESENT_INTERVAL,
3461 0, presentControl);
3462 presentControl = FLD_SET_DRF(C37E, _SET_PRESENT_CONTROL,
3463 _TIMESTAMP_MODE,
3464 _ENABLE, presentControl);
3465
3466 nvDmaSetStartEvoMethod(pChannel, NVC37E_SET_PRESENT_CONTROL, 1);
3467 nvDmaSetEvoMethodData(pChannel, presentControl);
3468
3469 nvDmaSetStartEvoMethod(pChannel, NVC37E_SET_UPDATE_TIMESTAMP_LO, 2);
3470 nvDmaSetEvoMethodData(pChannel, NvU64_LO32(pHwState->timeStamp));
3471 nvDmaSetEvoMethodData(pChannel, NvU64_HI32(pHwState->timeStamp));
3472
3473 // Issue non-interlocked, non-fliplocked, non-ReleaseElv UPDATE
3474 nvDmaSetStartEvoMethod(pChannel, NVC37E_SET_INTERLOCK_FLAGS, 1);
3475 nvDmaSetEvoMethodData(pChannel, 0);
3476
3477 nvDmaSetStartEvoMethod(pChannel,
3478 NVC37E_SET_WINDOW_INTERLOCK_FLAGS,
3479 1);
3480 nvDmaSetEvoMethodData(pChannel, 0);
3481
3482 nvDmaSetStartEvoMethod(pChannel, NVC37E_UPDATE, 1);
3483 nvDmaSetEvoMethodData(pChannel,
3484 DRF_DEF(C37E, _UPDATE, _RELEASE_ELV, _FALSE) |
3485 DRF_NUM(C37E, _UPDATE, _FLIP_LOCK_PIN,
3486 NVC37E_UPDATE_FLIP_LOCK_PIN_LOCK_PIN_NONE) |
3487 DRF_DEF(C37E, _UPDATE, _INTERLOCK_WITH_WIN_IMM,
3488 _DISABLE));
3489 }
3490
3491 static void
EvoProgramSemaphore3(NVDevEvoPtr pDevEvo,NVEvoChannelPtr pChannel,const NVFlipChannelEvoHwState * pHwState)3492 EvoProgramSemaphore3(NVDevEvoPtr pDevEvo,
3493 NVEvoChannelPtr pChannel,
3494 const NVFlipChannelEvoHwState *pHwState)
3495 {
3496 nvAssertSameSemaphoreSurface(pHwState);
3497
3498 if (pHwState->syncObject.u.semaphores.acquireSurface.pSurfaceEvo == NULL) {
3499 nvDmaSetStartEvoMethod(pChannel, NVC37E_SET_CONTEXT_DMA_SEMAPHORE, 1);
3500 nvDmaSetEvoMethodData(pChannel, 0);
3501 nvDmaSetStartEvoMethod(pChannel, NVC37E_SET_SEMAPHORE_CONTROL, 1);
3502 nvDmaSetEvoMethodData(pChannel, 0);
3503 nvDmaSetStartEvoMethod(pChannel, NVC37E_SET_SEMAPHORE_ACQUIRE, 1);
3504 nvDmaSetEvoMethodData(pChannel, 0);
3505 nvDmaSetStartEvoMethod(pChannel, NVC37E_SET_SEMAPHORE_RELEASE, 1);
3506 nvDmaSetEvoMethodData(pChannel, 0);
3507 } else {
3508 const NVFlipNIsoSurfaceEvoHwState *pNIso =
3509 &pHwState->syncObject.u.semaphores.acquireSurface;
3510
3511 nvAssert(pNIso->format == NVKMS_NISO_FORMAT_FOUR_WORD_NVDISPLAY);
3512 /* XXX nvdisplay: enforce this at a higher level */
3513 nvAssert((pNIso->offsetInWords % 4) == 0);
3514
3515 nvDmaSetStartEvoMethod(pChannel, NVC37E_SET_CONTEXT_DMA_SEMAPHORE, 1);
3516 nvDmaSetEvoMethodData(pChannel, pNIso->pSurfaceEvo->planes[0].surfaceDesc.ctxDmaHandle);
3517
3518 nvDmaSetStartEvoMethod(pChannel, NVC37E_SET_SEMAPHORE_ACQUIRE, 1);
3519 nvDmaSetEvoMethodData(pChannel,
3520 pHwState->syncObject.u.semaphores.acquireValue);
3521
3522 nvDmaSetStartEvoMethod(pChannel, NVC37E_SET_SEMAPHORE_RELEASE, 1);
3523 nvDmaSetEvoMethodData(pChannel,
3524 pHwState->syncObject.u.semaphores.releaseValue);
3525
3526 nvDmaSetStartEvoMethod(pChannel, NVC37E_SET_SEMAPHORE_CONTROL, 1);
3527 nvDmaSetEvoMethodData(pChannel, DRF_NUM(C37E, _SET_SEMAPHORE_CONTROL, _OFFSET,
3528 pNIso->offsetInWords / 4));
3529 }
3530 }
3531
EvoSetSemaphoreSurfaceAddressAndControlC6(NVEvoChannelPtr pChannel,const NVSurfaceDescriptor * pSurfaceDesc,NvU32 semaphoreOffset,NvU32 ctrlVal)3532 static void EvoSetSemaphoreSurfaceAddressAndControlC6(
3533 NVEvoChannelPtr pChannel,
3534 const NVSurfaceDescriptor *pSurfaceDesc,
3535 NvU32 semaphoreOffset,
3536 NvU32 ctrlVal)
3537 {
3538 NvU32 ctxDmaHandle = pSurfaceDesc ? pSurfaceDesc->ctxDmaHandle : 0;
3539
3540 /*! set ctx dma handle */
3541 nvDmaSetStartEvoMethod(pChannel, NVC67E_SET_CONTEXT_DMA_SEMAPHORE, 1);
3542 nvDmaSetEvoMethodData(pChannel,
3543 DRF_NUM(C67E, _SET_CONTEXT_DMA_SEMAPHORE, _HANDLE, ctxDmaHandle));
3544
3545 /*! set semaphore control and acq-rel mode */
3546 nvDmaSetStartEvoMethod(pChannel, NVC67E_SET_SEMAPHORE_CONTROL, 1);
3547 nvDmaSetEvoMethodData(pChannel, semaphoreOffset | ctrlVal);
3548 }
3549
EvoSetAcqSemaphoreSurfaceAddressAndControlC6(NVEvoChannelPtr pChannel,const NVSurfaceDescriptor * pSurfaceDesc,NvU32 semaphoreOffset,NvU32 ctrlVal)3550 static void EvoSetAcqSemaphoreSurfaceAddressAndControlC6(
3551 NVEvoChannelPtr pChannel,
3552 const NVSurfaceDescriptor *pSurfaceDesc,
3553 NvU32 semaphoreOffset,
3554 NvU32 ctrlVal)
3555 {
3556 NvU32 ctxDmaHandle = pSurfaceDesc ? pSurfaceDesc->ctxDmaHandle : 0;
3557
3558 /*! set ctx dma handle */
3559 nvDmaSetStartEvoMethod(pChannel, NVC67E_SET_CONTEXT_DMA_ACQ_SEMAPHORE, 1);
3560 nvDmaSetEvoMethodData(pChannel,
3561 DRF_NUM(C67E, _SET_CONTEXT_DMA_ACQ, _SEMAPHORE_HANDLE, ctxDmaHandle));
3562
3563 /*! set semaphore control and acq mode */
3564 nvDmaSetStartEvoMethod(pChannel, NVC67E_SET_ACQ_SEMAPHORE_CONTROL, 1);
3565 nvDmaSetEvoMethodData(pChannel, semaphoreOffset | ctrlVal);
3566 }
3567
3568 /*!
3569 * On Tegra, syncpts are used for synchronization between SW and HW,
3570 * and also across HW engines. Since NvDisplay 4.0 only natively
3571 * understands semaphores, there's a SHIM layer in the memory subsystem
3572 * that will convert semaphore acquires/releases into corresponding
3573 * syncpoint reads/writes. As such, each syncpoint is mapped to an
3574 * underlying 'dummy' semaphore surface, and the methods for these surfaces
3575 * need to be programmed as if they were real memory-backed semaphores.
3576 */
3577
3578 static void
EvoProgramSemaphore6(NVDevEvoPtr pDevEvo,NVEvoChannelPtr pChannel,const NVFlipChannelEvoHwState * pHwState)3579 EvoProgramSemaphore6(NVDevEvoPtr pDevEvo,
3580 NVEvoChannelPtr pChannel,
3581 const NVFlipChannelEvoHwState *pHwState)
3582 {
3583 NvU32 offset, acqMode, relMode, value;
3584 const NVSurfaceDescriptor *pSurfaceDesc = NULL;
3585 const NVFlipNIsoSurfaceEvoHwState *pNIso;
3586
3587 /*! Program Acq-only semaphore */
3588 pSurfaceDesc = NULL;
3589 offset = acqMode = relMode = value = 0;
3590 if (pHwState->syncObject.usingSyncpt &&
3591 pHwState->syncObject.u.syncpts.isPreSyncptSpecified) {
3592 NvU32 id = pHwState->syncObject.u.syncpts.preSyncpt;
3593 pSurfaceDesc = &pDevEvo->preSyncptTable[id].surfaceDesc;
3594 acqMode = DRF_DEF(C67E, _SET_ACQ_SEMAPHORE_CONTROL, _ACQ_MODE, _CGEQ);
3595 value = pHwState->syncObject.u.syncpts.preValue;
3596 } else {
3597 if (pHwState->syncObject.u.semaphores.acquireSurface.pSurfaceEvo != NULL) {
3598 pNIso = &pHwState->syncObject.u.semaphores.acquireSurface;
3599 pSurfaceDesc = &pNIso->pSurfaceEvo->planes[0].surfaceDesc;
3600 offset = pNIso->offsetInWords / 4;
3601 acqMode = DRF_DEF(C67E, _SET_ACQ_SEMAPHORE_CONTROL, _ACQ_MODE, _EQ);
3602 value = pHwState->syncObject.u.semaphores.acquireValue;
3603 }
3604 }
3605
3606 pDevEvo->hal->SetAcqSemaphoreSurfaceAddressAndControl(pChannel,
3607 pSurfaceDesc, offset, acqMode);
3608
3609 /*! set semaphore value */
3610 nvDmaSetStartEvoMethod(pChannel, NVC67E_SET_ACQ_SEMAPHORE_VALUE, 1);
3611 nvDmaSetEvoMethodData(pChannel,
3612 DRF_NUM(C67E, _SET_ACQ_SEMAPHORE_VALUE, _VALUE, value));
3613
3614 /*! Program Rel-only semaphore */
3615 pSurfaceDesc = NULL;
3616 offset = acqMode = relMode = value = 0;
3617 if (pHwState->syncObject.usingSyncpt &&
3618 pHwState->syncObject.u.syncpts.isPostSyncptSpecified) {
3619 pSurfaceDesc = &pHwState->syncObject.u.syncpts.surfaceDesc;
3620 acqMode = DRF_DEF(C67E, _SET_SEMAPHORE_CONTROL, _SKIP_ACQ, _TRUE);
3621 relMode = DRF_DEF(C67E, _SET_SEMAPHORE_CONTROL, _REL_MODE, _WRITE);
3622 value = pHwState->syncObject.u.syncpts.postValue;
3623 /*! increase local max val as well */
3624 pChannel->postSyncpt.syncptMaxVal++;
3625 } else {
3626 if (pHwState->syncObject.u.semaphores.releaseSurface.pSurfaceEvo != NULL) {
3627 pNIso = &pHwState->syncObject.u.semaphores.releaseSurface;
3628 pSurfaceDesc = &pNIso->pSurfaceEvo->planes[0].surfaceDesc;
3629 offset = pNIso->offsetInWords / 4;
3630 acqMode = DRF_DEF(C67E, _SET_SEMAPHORE_CONTROL, _SKIP_ACQ, _TRUE);
3631 relMode = DRF_DEF(C67E, _SET_SEMAPHORE_CONTROL, _REL_MODE, _WRITE);
3632 value = pHwState->syncObject.u.semaphores.releaseValue;
3633 }
3634 }
3635
3636 pDevEvo->hal->SetSemaphoreSurfaceAddressAndControl(pChannel,
3637 pSurfaceDesc, offset, (acqMode | relMode));
3638
3639 /*! set semaphore value */
3640 nvDmaSetStartEvoMethod(pChannel, NVC67E_SET_SEMAPHORE_RELEASE, 1);
3641 nvDmaSetEvoMethodData(pChannel,
3642 DRF_NUM(C67E, _SET_SEMAPHORE_RELEASE, _VALUE, value));
3643 }
3644
EvoSetWinNotifierSurfaceAddressAndControlC3(NVEvoChannelPtr pChannel,const NVSurfaceDescriptor * pSurfaceDesc,NvU32 notifierOffset,NvU32 ctrlVal)3645 static void EvoSetWinNotifierSurfaceAddressAndControlC3(
3646 NVEvoChannelPtr pChannel,
3647 const NVSurfaceDescriptor *pSurfaceDesc,
3648 NvU32 notifierOffset,
3649 NvU32 ctrlVal)
3650 {
3651 NvU32 ctxDmaHandle = pSurfaceDesc ? pSurfaceDesc->ctxDmaHandle : 0;
3652
3653 nvDmaSetStartEvoMethod(pChannel, NVC37E_SET_CONTEXT_DMA_NOTIFIER, 1);
3654 nvDmaSetEvoMethodData(pChannel,
3655 DRF_NUM(C37E, _SET_CONTEXT_DMA_NOTIFIER, _HANDLE, ctxDmaHandle));
3656
3657 nvDmaSetStartEvoMethod(pChannel, NVC37E_SET_NOTIFIER_CONTROL, 1);
3658 nvDmaSetEvoMethodData(pChannel,
3659 DRF_NUM(C37E, _SET_NOTIFIER_CONTROL, _OFFSET, notifierOffset) | ctrlVal);
3660 }
3661
EvoSetISOSurfaceAddressC3(NVEvoChannelPtr pChannel,const NVSurfaceDescriptor * pSurfaceDesc,NvU32 offset,NvU32 ctxDmaIdx,NvBool isBlocklinear)3662 static void EvoSetISOSurfaceAddressC3(
3663 NVEvoChannelPtr pChannel,
3664 const NVSurfaceDescriptor *pSurfaceDesc,
3665 NvU32 offset,
3666 NvU32 ctxDmaIdx,
3667 NvBool isBlocklinear)
3668 {
3669 NvU32 ctxDmaHandle = pSurfaceDesc ? pSurfaceDesc->ctxDmaHandle : 0;
3670
3671 nvDmaSetStartEvoMethod(pChannel, NVC37E_SET_CONTEXT_DMA_ISO(ctxDmaIdx), 1);
3672 nvDmaSetEvoMethodData(pChannel, ctxDmaHandle);
3673
3674 nvDmaSetStartEvoMethod(pChannel, NVC37E_SET_OFFSET(ctxDmaIdx), 1);
3675 nvDmaSetEvoMethodData(pChannel, nvCtxDmaOffsetFromBytes(offset));
3676 }
3677
3678 static NvBool
EvoFlipC3Common(NVDevEvoPtr pDevEvo,NVEvoChannelPtr pChannel,const NVFlipChannelEvoHwState * pHwState,NVEvoUpdateState * updateState,NvU32 head)3679 EvoFlipC3Common(NVDevEvoPtr pDevEvo,
3680 NVEvoChannelPtr pChannel,
3681 const NVFlipChannelEvoHwState *pHwState,
3682 NVEvoUpdateState *updateState,
3683 NvU32 head)
3684 {
3685 const NvKmsSurfaceMemoryFormatInfo *pFormatInfo;
3686 NvU32 presentControl, eye;
3687 NvU32 storage;
3688 NvU8 planeIndex;
3689 NVSurfaceDescriptor *pSurfaceDesc = NULL;
3690 NvU32 offset, ctrlVal;
3691
3692 nvUpdateUpdateState(pDevEvo, updateState, pChannel);
3693
3694 /* program notifier */
3695
3696 if (pHwState->completionNotifier.surface.pSurfaceEvo == NULL) {
3697 /*
3698 * if no notifier surface is attached but vrr RGLine calculations
3699 * for frame pacing are enabled then we need to provide our own
3700 * surface and keep getting flip completion updates.
3701 */
3702 const NvU32 sdMask = nvPeekEvoSubDevMask(pDevEvo);
3703 const NvU32 sd = (sdMask == 0) ? 0 : nv_ffs(sdMask) - 1;
3704 NVDispHeadStateEvoRec *pHeadState = &pDevEvo->pDispEvo[sd]->headState[head];
3705 struct NvKmsVrrFramePacingInfo *pVrrFramePacingInfo = &pHeadState->vrrFramePacingInfo;
3706
3707 if (pVrrFramePacingInfo->framePacingActive) {
3708 pSurfaceDesc = &pChannel->notifiersDma[sd].surfaceDesc;
3709 offset = nvPrepareNextVrrNotifier(pChannel, sd, head);
3710 ctrlVal = DRF_DEF(C37E, _SET_NOTIFIER_CONTROL, _MODE, _WRITE_AWAKEN);
3711 pDevEvo->hal->SetWinNotifierSurfaceAddressAndControl(pChannel,
3712 pSurfaceDesc, offset, ctrlVal);
3713 } else {
3714 offset = ctrlVal = 0;
3715 pDevEvo->hal->SetWinNotifierSurfaceAddressAndControl(pChannel,
3716 NULL, offset, ctrlVal);
3717 }
3718 } else {
3719 const NVFlipNIsoSurfaceEvoHwState *pNIso =
3720 &pHwState->completionNotifier.surface;
3721
3722 nvAssert(pNIso->format == NVKMS_NISO_FORMAT_FOUR_WORD_NVDISPLAY);
3723 /* XXX nvdisplay: enforce this at a higher level */
3724 nvAssert((pNIso->offsetInWords % 4) == 0);
3725
3726 pSurfaceDesc = &pNIso->pSurfaceEvo->planes[0].surfaceDesc;
3727 offset = pNIso->offsetInWords / 4;
3728 ctrlVal = 0;
3729 if (pHwState->completionNotifier.awaken) {
3730 ctrlVal = FLD_SET_DRF(C37E, _SET_NOTIFIER_CONTROL, _MODE,
3731 _WRITE_AWAKEN, ctrlVal);
3732 } else {
3733 ctrlVal = FLD_SET_DRF(C37E, _SET_NOTIFIER_CONTROL, _MODE,
3734 _WRITE, ctrlVal);
3735 }
3736
3737 pDevEvo->hal->SetWinNotifierSurfaceAddressAndControl(pChannel,
3738 pSurfaceDesc, offset, ctrlVal);
3739 }
3740
3741 if (!pHwState->pSurfaceEvo[NVKMS_LEFT]) {
3742 // Disable this window, and set all its ctxdma entries to NULL.
3743 for (eye = 0; eye < NVKMS_MAX_EYES; eye++) {
3744 for (planeIndex = 0;
3745 planeIndex < NVKMS_MAX_PLANES_PER_SURFACE;
3746 planeIndex++) {
3747 const NvU8 ctxDmaIdx = EyeAndPlaneToCtxDmaIdx(eye, planeIndex);
3748 pDevEvo->hal->SetISOSurfaceAddress(pChannel,
3749 NULL /* pSurfaceDec */, 0 /* offset */, ctxDmaIdx,
3750 NV_FALSE /* isBlocklinear */);
3751 }
3752 }
3753
3754 return FALSE;
3755 }
3756
3757 presentControl = DRF_NUM(C37E, _SET_PRESENT_CONTROL, _MIN_PRESENT_INTERVAL,
3758 pHwState->minPresentInterval);
3759
3760 if (pHwState->timeStamp != 0) {
3761 presentControl = FLD_SET_DRF(C37E, _SET_PRESENT_CONTROL, _TIMESTAMP_MODE,
3762 _ENABLE, presentControl);
3763 } else {
3764 presentControl = FLD_SET_DRF(C37E, _SET_PRESENT_CONTROL, _TIMESTAMP_MODE,
3765 _DISABLE, presentControl);
3766 }
3767
3768 if (pHwState->tearing) {
3769 presentControl = FLD_SET_DRF(C37E, _SET_PRESENT_CONTROL, _BEGIN_MODE,
3770 _IMMEDIATE, presentControl);
3771 } else {
3772 presentControl = FLD_SET_DRF(C37E, _SET_PRESENT_CONTROL, _BEGIN_MODE,
3773 _NON_TEARING, presentControl);
3774 }
3775
3776 if (pHwState->pSurfaceEvo[NVKMS_RIGHT]) {
3777 if (pHwState->perEyeStereoFlip) {
3778 presentControl = FLD_SET_DRF(C37E, _SET_PRESENT_CONTROL, _STEREO_MODE,
3779 _AT_ANY_FRAME, presentControl);
3780 } else {
3781 presentControl = FLD_SET_DRF(C37E, _SET_PRESENT_CONTROL, _STEREO_MODE,
3782 _PAIR_FLIP, presentControl);
3783 }
3784 } else {
3785 presentControl = FLD_SET_DRF(C37E, _SET_PRESENT_CONTROL, _STEREO_MODE,
3786 _MONO, presentControl);
3787 }
3788 nvDmaSetStartEvoMethod(pChannel, NVC37E_SET_PRESENT_CONTROL, 1);
3789 nvDmaSetEvoMethodData(pChannel, presentControl);
3790
3791 /*
3792 * GV100 timestamped flips need a duplicate update which only changes
3793 * TIMESTAMP_MODE and MIN_PRESENT_INTERVAL fields in SET_PRESENT_CONTROL;
3794 * to allow updating these fields without changing anything else in
3795 * SET_PRESENT_CONTROL, cache the values we sent in previous flips here.
3796 * (bug 1990958)
3797 */
3798 pChannel->oldPresentControl = presentControl;
3799
3800 /* Set the surface parameters. */
3801 FOR_ALL_EYES(eye) {
3802 const NVSurfaceEvoRec *pSurfaceEvoPerEye = pHwState->pSurfaceEvo[eye];
3803 NvU8 numSurfacePlanes = 0;
3804 NvBool isBlockLinear = NV_FALSE;
3805
3806 if (pSurfaceEvoPerEye != NULL) {
3807 pFormatInfo =
3808 nvKmsGetSurfaceMemoryFormatInfo(pSurfaceEvoPerEye->format);
3809 numSurfacePlanes = pFormatInfo->numPlanes;
3810 isBlockLinear =
3811 (pSurfaceEvoPerEye->layout == NvKmsSurfaceMemoryLayoutBlockLinear);
3812 }
3813
3814 for (planeIndex = 0;
3815 planeIndex < NVKMS_MAX_PLANES_PER_SURFACE;
3816 planeIndex++) {
3817 const NVSurfaceDescriptor *pSurfaceDesc = NULL;
3818 NvU64 offset = 0;
3819 const NvU8 ctxDmaIdx = EyeAndPlaneToCtxDmaIdx(eye, planeIndex);
3820
3821 if (planeIndex < numSurfacePlanes) {
3822 pSurfaceDesc = &pSurfaceEvoPerEye->planes[planeIndex].surfaceDesc;
3823 offset = pSurfaceEvoPerEye->planes[planeIndex].offset;
3824 }
3825
3826 pDevEvo->hal->SetISOSurfaceAddress(pChannel,
3827 pSurfaceDesc, offset, ctxDmaIdx, isBlockLinear);
3828 }
3829 }
3830
3831 nvDmaSetStartEvoMethod(pChannel, NVC37E_SET_SIZE, 1);
3832 nvDmaSetEvoMethodData(pChannel,
3833 DRF_NUM(C37E, _SET_SIZE, _WIDTH, pHwState->pSurfaceEvo[NVKMS_LEFT]->widthInPixels) |
3834 DRF_NUM(C37E, _SET_SIZE, _HEIGHT, pHwState->pSurfaceEvo[NVKMS_LEFT]->heightInPixels));
3835
3836 nvDmaSetStartEvoMethod(pChannel, NVC37E_SET_SIZE_IN, 1);
3837 nvDmaSetEvoMethodData(pChannel,
3838 DRF_NUM(C37E, _SET_SIZE_IN, _WIDTH, pHwState->sizeIn.width) |
3839 DRF_NUM(C37E, _SET_SIZE_IN, _HEIGHT, pHwState->sizeIn.height));
3840
3841 nvDmaSetStartEvoMethod(pChannel, NVC37E_SET_SIZE_OUT, 1);
3842 nvDmaSetEvoMethodData(pChannel,
3843 DRF_NUM(C37E, _SET_SIZE_OUT, _WIDTH, pHwState->sizeOut.width) |
3844 DRF_NUM(C37E, _SET_SIZE_OUT, _HEIGHT, pHwState->sizeOut.height));
3845
3846 /* XXX nvdisplay: enforce pitch/BL layout are consistent between eyes at a
3847 * higher level */
3848
3849 storage = 0;
3850 if (pHwState->pSurfaceEvo[NVKMS_LEFT]->layout ==
3851 NvKmsSurfaceMemoryLayoutBlockLinear) {
3852 const NvU32 blockHeight = pHwState->pSurfaceEvo[NVKMS_LEFT]->log2GobsPerBlockY;
3853 storage |= DRF_NUM(C37E, _SET_STORAGE, _BLOCK_HEIGHT, blockHeight);
3854 if (pDevEvo->hal->caps.supportsSetStorageMemoryLayout) {
3855 storage |= DRF_DEF(C37E, _SET_STORAGE, _MEMORY_LAYOUT, _BLOCKLINEAR);
3856 }
3857 } else if (pDevEvo->hal->caps.supportsSetStorageMemoryLayout) {
3858 storage |= DRF_DEF(C37E, _SET_STORAGE, _MEMORY_LAYOUT, _PITCH);
3859 }
3860 nvDmaSetStartEvoMethod(pChannel, NVC37E_SET_STORAGE, 1);
3861 nvDmaSetEvoMethodData(pChannel, storage);
3862
3863 pFormatInfo = nvKmsGetSurfaceMemoryFormatInfo(
3864 pHwState->pSurfaceEvo[NVKMS_LEFT]->format);
3865
3866 for (planeIndex = 0;
3867 planeIndex < NVKMS_MAX_PLANES_PER_SURFACE;
3868 planeIndex++) {
3869 NvU32 pitch;
3870
3871 nvDmaSetStartEvoMethod(pChannel, NVC37E_SET_PLANAR_STORAGE(planeIndex),
3872 1);
3873
3874 if (planeIndex >= pFormatInfo->numPlanes) {
3875 nvDmaSetEvoMethodData(pChannel,
3876 DRF_NUM(C37E, _SET_PLANAR_STORAGE, _PITCH, 0));
3877 continue;
3878 }
3879
3880 /*
3881 * Per nvdClass_01.mfs, the HEAD_SET_STORAGE_PITCH "units are blocks
3882 * if the layout is BLOCKLINEAR, the units are multiples of 64 bytes
3883 * if the layout is PITCH."
3884 */
3885 pitch = pHwState->pSurfaceEvo[NVKMS_LEFT]->planes[planeIndex].pitch;
3886 if (pHwState->pSurfaceEvo[NVKMS_LEFT]->layout ==
3887 NvKmsSurfaceMemoryLayoutBlockLinear) {
3888 /* pitch is already in units of blocks; no conversion needed. */
3889 nvDmaSetEvoMethodData(pChannel,
3890 DRF_NUM(C37E, _SET_PLANAR_STORAGE, _PITCH, pitch));
3891 } else {
3892 /* XXX nvdisplay: enforce this at a higher level */
3893 nvAssert((pitch & 63) == 0);
3894 nvDmaSetEvoMethodData(pChannel,
3895 DRF_NUM(C37E, _SET_PLANAR_STORAGE, _PITCH, pitch >> 6));
3896 }
3897 }
3898
3899 ASSERT_EYES_MATCH(pHwState->pSurfaceEvo, format);
3900
3901 nvDmaSetStartEvoMethod(pChannel, NVC37E_SET_UPDATE_TIMESTAMP_LO, 2);
3902 nvDmaSetEvoMethodData(pChannel, NvU64_LO32(pHwState->timeStamp));
3903 nvDmaSetEvoMethodData(pChannel, NvU64_HI32(pHwState->timeStamp));
3904
3905 return TRUE;
3906 }
3907
3908 /*
3909 * This function returns TRUE if precomp needs to swap the U and V components to
3910 * support the given input surface format. For all such formats,
3911 * SetParams.SwapUV needs to be enabled.
3912 *
3913 * Due to the "feature" described in bug 1640117, there's a mismatch in the
3914 * ihub<->precomp interface:
3915 * - For all Yx___UxVx_N444 and Yx___UxVx_N422 formats, ihub will fetch and send
3916 * the V sample as the first chroma byte, and the U sample as the second byte.
3917 * However, precomp expects the U sample as the first byte, and the V sample
3918 * as the second byte.
3919 * - For all Yx___VxUx_N420 formats, ihub will fetch and send the U sample as
3920 * the first chroma byte, and the V sample as the second byte.
3921 * However, precomp expects the V sample as the first byte, and the U sample
3922 * as the second byte.
3923 *
3924 * In the above explanation, note that ihub simply fetches and sends the chroma
3925 * bytes in the same order that they're packed in memory.
3926 */
IsSurfaceFormatUVSwapped(const enum NvKmsSurfaceMemoryFormat format)3927 static NvBool IsSurfaceFormatUVSwapped(
3928 const enum NvKmsSurfaceMemoryFormat format)
3929 {
3930 switch (format) {
3931 case NvKmsSurfaceMemoryFormatY8___U8V8_N444:
3932 case NvKmsSurfaceMemoryFormatY8___U8V8_N422:
3933 case NvKmsSurfaceMemoryFormatY8___V8U8_N420:
3934 case NvKmsSurfaceMemoryFormatY10___U10V10_N444:
3935 case NvKmsSurfaceMemoryFormatY10___U10V10_N422:
3936 case NvKmsSurfaceMemoryFormatY10___V10U10_N420:
3937 case NvKmsSurfaceMemoryFormatY12___U12V12_N444:
3938 case NvKmsSurfaceMemoryFormatY12___U12V12_N422:
3939 case NvKmsSurfaceMemoryFormatY12___V12U12_N420:
3940 return TRUE;
3941 case NvKmsSurfaceMemoryFormatY8_U8__Y8_V8_N422:
3942 case NvKmsSurfaceMemoryFormatU8_Y8__V8_Y8_N422:
3943 case NvKmsSurfaceMemoryFormatY8___V8U8_N444:
3944 case NvKmsSurfaceMemoryFormatY8___V8U8_N422:
3945 case NvKmsSurfaceMemoryFormatY8___U8V8_N420:
3946 case NvKmsSurfaceMemoryFormatY10___V10U10_N444:
3947 case NvKmsSurfaceMemoryFormatY10___V10U10_N422:
3948 case NvKmsSurfaceMemoryFormatY10___U10V10_N420:
3949 case NvKmsSurfaceMemoryFormatY12___V12U12_N444:
3950 case NvKmsSurfaceMemoryFormatY12___V12U12_N422:
3951 case NvKmsSurfaceMemoryFormatY12___U12V12_N420:
3952 case NvKmsSurfaceMemoryFormatY8___U8___V8_N444:
3953 case NvKmsSurfaceMemoryFormatY8___U8___V8_N420:
3954 return FALSE;
3955 case NvKmsSurfaceMemoryFormatI8:
3956 case NvKmsSurfaceMemoryFormatA1R5G5B5:
3957 case NvKmsSurfaceMemoryFormatX1R5G5B5:
3958 case NvKmsSurfaceMemoryFormatR5G6B5:
3959 case NvKmsSurfaceMemoryFormatA8R8G8B8:
3960 case NvKmsSurfaceMemoryFormatX8R8G8B8:
3961 case NvKmsSurfaceMemoryFormatA8B8G8R8:
3962 case NvKmsSurfaceMemoryFormatX8B8G8R8:
3963 case NvKmsSurfaceMemoryFormatA2B10G10R10:
3964 case NvKmsSurfaceMemoryFormatX2B10G10R10:
3965 case NvKmsSurfaceMemoryFormatRF16GF16BF16AF16:
3966 case NvKmsSurfaceMemoryFormatRF16GF16BF16XF16:
3967 case NvKmsSurfaceMemoryFormatR16G16B16A16:
3968 case NvKmsSurfaceMemoryFormatRF32GF32BF32AF32:
3969 return FALSE;
3970 }
3971
3972 return FALSE;
3973 }
3974
3975 /*
3976 * Map the given NvKmsSurfaceMemoryFormat to its corresponding HW format for the
3977 * C370 (Volta) NVDISPLAY class.
3978 *
3979 * Volta supports YUV422 packed, but this function excludes the corresponding
3980 * mappings because the required programming support hasn't been added to NVKMS
3981 * yet.
3982 *
3983 * Return 0 in the case of an unrecognized NvKmsSurfaceMemoryFormat.
3984 */
nvHwFormatFromKmsFormatC3(const enum NvKmsSurfaceMemoryFormat format)3985 static NvU32 nvHwFormatFromKmsFormatC3(
3986 const enum NvKmsSurfaceMemoryFormat format)
3987 {
3988 switch (format) {
3989 case NvKmsSurfaceMemoryFormatI8:
3990 return NVC37E_SET_PARAMS_FORMAT_I8;
3991 case NvKmsSurfaceMemoryFormatA1R5G5B5:
3992 case NvKmsSurfaceMemoryFormatX1R5G5B5:
3993 return NVC37E_SET_PARAMS_FORMAT_A1R5G5B5;
3994 case NvKmsSurfaceMemoryFormatR5G6B5:
3995 return NVC37E_SET_PARAMS_FORMAT_R5G6B5;
3996 case NvKmsSurfaceMemoryFormatA8R8G8B8:
3997 return NVC37E_SET_PARAMS_FORMAT_A8R8G8B8;
3998 case NvKmsSurfaceMemoryFormatX8R8G8B8:
3999 return NVC37E_SET_PARAMS_FORMAT_X8R8G8B8;
4000 case NvKmsSurfaceMemoryFormatA8B8G8R8:
4001 return NVC37E_SET_PARAMS_FORMAT_A8B8G8R8;
4002 case NvKmsSurfaceMemoryFormatX8B8G8R8:
4003 return NVC37E_SET_PARAMS_FORMAT_X8B8G8R8;
4004 case NvKmsSurfaceMemoryFormatA2B10G10R10:
4005 return NVC37E_SET_PARAMS_FORMAT_A2B10G10R10;
4006 case NvKmsSurfaceMemoryFormatX2B10G10R10:
4007 return NVC37E_SET_PARAMS_FORMAT_X2BL10GL10RL10_XRBIAS;
4008 case NvKmsSurfaceMemoryFormatRF16GF16BF16AF16:
4009 case NvKmsSurfaceMemoryFormatRF16GF16BF16XF16:
4010 return NVC37E_SET_PARAMS_FORMAT_RF16_GF16_BF16_AF16;
4011 case NvKmsSurfaceMemoryFormatR16G16B16A16:
4012 return NVC37E_SET_PARAMS_FORMAT_R16_G16_B16_A16;
4013 case NvKmsSurfaceMemoryFormatRF32GF32BF32AF32:
4014 case NvKmsSurfaceMemoryFormatY8_U8__Y8_V8_N422:
4015 case NvKmsSurfaceMemoryFormatU8_Y8__V8_Y8_N422:
4016 case NvKmsSurfaceMemoryFormatY8___U8V8_N444:
4017 case NvKmsSurfaceMemoryFormatY8___V8U8_N444:
4018 case NvKmsSurfaceMemoryFormatY8___U8V8_N422:
4019 case NvKmsSurfaceMemoryFormatY8___V8U8_N422:
4020 case NvKmsSurfaceMemoryFormatY8___U8V8_N420:
4021 case NvKmsSurfaceMemoryFormatY8___V8U8_N420:
4022 case NvKmsSurfaceMemoryFormatY10___U10V10_N444:
4023 case NvKmsSurfaceMemoryFormatY10___V10U10_N444:
4024 case NvKmsSurfaceMemoryFormatY10___U10V10_N422:
4025 case NvKmsSurfaceMemoryFormatY10___V10U10_N422:
4026 case NvKmsSurfaceMemoryFormatY10___U10V10_N420:
4027 case NvKmsSurfaceMemoryFormatY10___V10U10_N420:
4028 case NvKmsSurfaceMemoryFormatY12___U12V12_N444:
4029 case NvKmsSurfaceMemoryFormatY12___V12U12_N444:
4030 case NvKmsSurfaceMemoryFormatY12___U12V12_N422:
4031 case NvKmsSurfaceMemoryFormatY12___V12U12_N422:
4032 case NvKmsSurfaceMemoryFormatY12___U12V12_N420:
4033 case NvKmsSurfaceMemoryFormatY12___V12U12_N420:
4034 case NvKmsSurfaceMemoryFormatY8___U8___V8_N444:
4035 case NvKmsSurfaceMemoryFormatY8___U8___V8_N420:
4036 return 0;
4037 }
4038
4039 return 0;
4040 }
4041
4042 /*
4043 * Map the given NvKmsSurfaceMemoryFormat to its corresponding HW format for the
4044 * C570 (Turing) NVDISPLAY class.
4045 *
4046 * Return 0 in the case of an unrecognized NvKmsSurfaceMemoryFormat.
4047 */
nvHwFormatFromKmsFormatC5(const enum NvKmsSurfaceMemoryFormat format)4048 static NvU32 nvHwFormatFromKmsFormatC5(
4049 const enum NvKmsSurfaceMemoryFormat format)
4050 {
4051 switch (format) {
4052 case NvKmsSurfaceMemoryFormatY8_U8__Y8_V8_N422:
4053 return NVC57E_SET_PARAMS_FORMAT_Y8_U8__Y8_V8_N422;
4054 case NvKmsSurfaceMemoryFormatU8_Y8__V8_Y8_N422:
4055 return NVC57E_SET_PARAMS_FORMAT_U8_Y8__V8_Y8_N422;
4056 case NvKmsSurfaceMemoryFormatY8___U8V8_N444:
4057 case NvKmsSurfaceMemoryFormatY8___V8U8_N444:
4058 return NVC57E_SET_PARAMS_FORMAT_Y8___U8V8_N444;
4059 case NvKmsSurfaceMemoryFormatY8___U8V8_N422:
4060 case NvKmsSurfaceMemoryFormatY8___V8U8_N422:
4061 return NVC57E_SET_PARAMS_FORMAT_Y8___U8V8_N422;
4062 case NvKmsSurfaceMemoryFormatY8___U8V8_N420:
4063 case NvKmsSurfaceMemoryFormatY8___V8U8_N420:
4064 return NVC57E_SET_PARAMS_FORMAT_Y8___V8U8_N420;
4065 case NvKmsSurfaceMemoryFormatY10___U10V10_N444:
4066 case NvKmsSurfaceMemoryFormatY10___V10U10_N444:
4067 return NVC57E_SET_PARAMS_FORMAT_Y10___U10V10_N444;
4068 case NvKmsSurfaceMemoryFormatY10___U10V10_N422:
4069 case NvKmsSurfaceMemoryFormatY10___V10U10_N422:
4070 return NVC57E_SET_PARAMS_FORMAT_Y10___U10V10_N422;
4071 case NvKmsSurfaceMemoryFormatY10___U10V10_N420:
4072 case NvKmsSurfaceMemoryFormatY10___V10U10_N420:
4073 return NVC57E_SET_PARAMS_FORMAT_Y10___V10U10_N420;
4074 case NvKmsSurfaceMemoryFormatY12___U12V12_N444:
4075 case NvKmsSurfaceMemoryFormatY12___V12U12_N444:
4076 return NVC57E_SET_PARAMS_FORMAT_Y12___U12V12_N444;
4077 case NvKmsSurfaceMemoryFormatY12___U12V12_N422:
4078 case NvKmsSurfaceMemoryFormatY12___V12U12_N422:
4079 return NVC57E_SET_PARAMS_FORMAT_Y12___U12V12_N422;
4080 case NvKmsSurfaceMemoryFormatY12___U12V12_N420:
4081 case NvKmsSurfaceMemoryFormatY12___V12U12_N420:
4082 return NVC57E_SET_PARAMS_FORMAT_Y12___V12U12_N420;
4083 case NvKmsSurfaceMemoryFormatY8___U8___V8_N444:
4084 case NvKmsSurfaceMemoryFormatY8___U8___V8_N420:
4085 case NvKmsSurfaceMemoryFormatI8:
4086 case NvKmsSurfaceMemoryFormatA1R5G5B5:
4087 case NvKmsSurfaceMemoryFormatX1R5G5B5:
4088 case NvKmsSurfaceMemoryFormatR5G6B5:
4089 case NvKmsSurfaceMemoryFormatA8R8G8B8:
4090 case NvKmsSurfaceMemoryFormatX8R8G8B8:
4091 case NvKmsSurfaceMemoryFormatA8B8G8R8:
4092 case NvKmsSurfaceMemoryFormatX8B8G8R8:
4093 case NvKmsSurfaceMemoryFormatA2B10G10R10:
4094 case NvKmsSurfaceMemoryFormatX2B10G10R10:
4095 case NvKmsSurfaceMemoryFormatRF16GF16BF16AF16:
4096 case NvKmsSurfaceMemoryFormatRF16GF16BF16XF16:
4097 case NvKmsSurfaceMemoryFormatR16G16B16A16:
4098 case NvKmsSurfaceMemoryFormatRF32GF32BF32AF32:
4099 return nvHwFormatFromKmsFormatC3(format);
4100 }
4101
4102 return 0;
4103 }
4104
4105 /*
4106 * Map the given NvKmsSurfaceMemoryFormat to its corresponding HW format for the
4107 * C670 (Orin and Ampere) NVDISPLAY class.
4108 *
4109 * Return 0 in the case of an unrecognized NvKmsSurfaceMemoryFormat.
4110 */
nvHwFormatFromKmsFormatC6(const enum NvKmsSurfaceMemoryFormat format)4111 static NvU32 nvHwFormatFromKmsFormatC6(
4112 const enum NvKmsSurfaceMemoryFormat format)
4113 {
4114 switch (format) {
4115 case NvKmsSurfaceMemoryFormatY8___U8___V8_N444:
4116 return NVC67E_SET_PARAMS_FORMAT_Y8___U8___V8_N444;
4117 case NvKmsSurfaceMemoryFormatY8___U8___V8_N420:
4118 return NVC67E_SET_PARAMS_FORMAT_Y8___U8___V8_N420;
4119 case NvKmsSurfaceMemoryFormatX2B10G10R10:
4120 return NVC67E_SET_PARAMS_FORMAT_A2B10G10R10;
4121 case NvKmsSurfaceMemoryFormatY8_U8__Y8_V8_N422:
4122 case NvKmsSurfaceMemoryFormatU8_Y8__V8_Y8_N422:
4123 case NvKmsSurfaceMemoryFormatY8___U8V8_N444:
4124 case NvKmsSurfaceMemoryFormatY8___V8U8_N444:
4125 case NvKmsSurfaceMemoryFormatY8___U8V8_N422:
4126 case NvKmsSurfaceMemoryFormatY8___V8U8_N422:
4127 case NvKmsSurfaceMemoryFormatY8___U8V8_N420:
4128 case NvKmsSurfaceMemoryFormatY8___V8U8_N420:
4129 case NvKmsSurfaceMemoryFormatY10___U10V10_N444:
4130 case NvKmsSurfaceMemoryFormatY10___V10U10_N444:
4131 case NvKmsSurfaceMemoryFormatY10___U10V10_N422:
4132 case NvKmsSurfaceMemoryFormatY10___V10U10_N422:
4133 case NvKmsSurfaceMemoryFormatY10___U10V10_N420:
4134 case NvKmsSurfaceMemoryFormatY10___V10U10_N420:
4135 case NvKmsSurfaceMemoryFormatY12___U12V12_N444:
4136 case NvKmsSurfaceMemoryFormatY12___V12U12_N444:
4137 case NvKmsSurfaceMemoryFormatY12___U12V12_N422:
4138 case NvKmsSurfaceMemoryFormatY12___V12U12_N422:
4139 case NvKmsSurfaceMemoryFormatY12___U12V12_N420:
4140 case NvKmsSurfaceMemoryFormatY12___V12U12_N420:
4141 case NvKmsSurfaceMemoryFormatI8:
4142 case NvKmsSurfaceMemoryFormatA1R5G5B5:
4143 case NvKmsSurfaceMemoryFormatX1R5G5B5:
4144 case NvKmsSurfaceMemoryFormatR5G6B5:
4145 case NvKmsSurfaceMemoryFormatA8R8G8B8:
4146 case NvKmsSurfaceMemoryFormatX8R8G8B8:
4147 case NvKmsSurfaceMemoryFormatA8B8G8R8:
4148 case NvKmsSurfaceMemoryFormatX8B8G8R8:
4149 case NvKmsSurfaceMemoryFormatA2B10G10R10:
4150 case NvKmsSurfaceMemoryFormatRF16GF16BF16AF16:
4151 case NvKmsSurfaceMemoryFormatRF16GF16BF16XF16:
4152 case NvKmsSurfaceMemoryFormatR16G16B16A16:
4153 case NvKmsSurfaceMemoryFormatRF32GF32BF32AF32:
4154 return nvHwFormatFromKmsFormatC5(format);
4155 }
4156
4157 return 0;
4158 }
4159
4160 static
EvoGetLutSurface3(NVDevEvoPtr pDevEvo,NVEvoChannelPtr pChannel,const NVFlipChannelEvoHwState * pHwState)4161 NVLutSurfaceEvoPtr EvoGetLutSurface3(NVDevEvoPtr pDevEvo,
4162 NVEvoChannelPtr pChannel,
4163 const NVFlipChannelEvoHwState *pHwState)
4164 {
4165 NvU32 win = NV_EVO_CHANNEL_MASK_WINDOW_NUMBER(pChannel->channelMask);
4166 NvU32 head = pDevEvo->headForWindow[win];
4167 NvBool found = FALSE;
4168 const NVDispEvoRec *pDispEvo = NULL;
4169 NvU32 sd;
4170
4171 if ((pHwState->pSurfaceEvo[NVKMS_LEFT] == NULL) ||
4172 (head == NV_INVALID_HEAD)) {
4173 return NULL;
4174 }
4175
4176 /* Input Lut is explicitly enabled by client */
4177 if (pHwState->inputLut.pLutSurfaceEvo != NULL) {
4178 return pHwState->inputLut.pLutSurfaceEvo;
4179 }
4180
4181 /*
4182 * For everything but I8 surfaces, we can just use the specified
4183 * LUT, even if it's NULL.
4184 * For I8 surfaces, we can only use the specified surface if it's
4185 * non-NULL (an input LUT is required).
4186 */
4187 if (pHwState->pSurfaceEvo[NVKMS_LEFT]->format !=
4188 NvKmsSurfaceMemoryFormatI8) {
4189 return NULL;
4190 }
4191
4192 /*
4193 * The rest of the function is to handle the I8 case where no input
4194 * LUT was specified: look up the LUT to use from the device.
4195 */
4196
4197 for (sd = 0; sd < pDevEvo->numSubDevices; sd++) {
4198 if (nvPeekEvoSubDevMask(pDevEvo) & (1 << sd)) {
4199 if (found) {
4200 nvAssert(pDispEvo == pDevEvo->gpus[sd].pDispEvo);
4201 } else {
4202 pDispEvo = pDevEvo->gpus[sd].pDispEvo;
4203 found = TRUE;
4204 }
4205 }
4206 }
4207
4208 nvAssert(found);
4209
4210 /*
4211 * It is not allowed to change the input LUT on immediate flips. The
4212 * higher-level code should makes sure to disable tearing if there is change
4213 * in the surface format and curLUTIndex does not change until next
4214 * EvoSetLUTContextDma3() call which also makes sure to disable tearing.
4215 */
4216 return pDispEvo->headState[head].lut.pCurrSurface;
4217 }
4218
4219 static void
EvoFlipC3(NVDevEvoPtr pDevEvo,NVEvoChannelPtr pChannel,const NVFlipChannelEvoHwState * pHwState,NVEvoUpdateState * updateState,NvBool bypassComposition)4220 EvoFlipC3(NVDevEvoPtr pDevEvo,
4221 NVEvoChannelPtr pChannel,
4222 const NVFlipChannelEvoHwState *pHwState,
4223 NVEvoUpdateState *updateState,
4224 NvBool bypassComposition)
4225 {
4226 NvBool enableCSC, swapUV, flip3Return;
4227 enum NvKmsSurfaceMemoryFormat format;
4228 NVLutSurfaceEvoPtr pLutSurfaceEvo =
4229 EvoGetLutSurface3(pDevEvo, pChannel, pHwState);
4230 NvU32 win = NV_EVO_CHANNEL_MASK_WINDOW_NUMBER(pChannel->channelMask);
4231 NvU32 head = pDevEvo->headForWindow[win];
4232
4233 if (pHwState->timeStamp != 0) {
4234 InsertAdditionalTimestampFlip(pDevEvo, pChannel, pHwState,
4235 updateState);
4236 }
4237
4238 flip3Return = EvoFlipC3Common(pDevEvo, pChannel, pHwState, updateState, head);
4239
4240 /* program semaphore */
4241 EvoProgramSemaphore3(pDevEvo, pChannel, pHwState);
4242
4243 if (!flip3Return) {
4244 return;
4245 }
4246
4247 format = pHwState->pSurfaceEvo[NVKMS_LEFT]->format;
4248
4249 enableCSC = SetCscMatrixC3(pChannel, &pHwState->cscMatrix);
4250 swapUV = IsSurfaceFormatUVSwapped(format);
4251 nvDmaSetStartEvoMethod(pChannel, NVC37E_SET_PARAMS, 1);
4252 nvDmaSetEvoMethodData(pChannel,
4253 (enableCSC ? DRF_DEF(C37E, _SET_PARAMS, _CSC, _ENABLE) :
4254 DRF_DEF(C37E, _SET_PARAMS, _CSC, _DISABLE)) |
4255 DRF_NUM(C37E, _SET_PARAMS, _FORMAT, nvHwFormatFromKmsFormatC3(format)) |
4256 (swapUV ? DRF_DEF(C37E, _SET_PARAMS, _SWAP_UV, _ENABLE) :
4257 DRF_DEF(C37E, _SET_PARAMS, _SWAP_UV, _DISABLE)) |
4258 DRF_DEF(C37E, _SET_PARAMS, _UNDERREPLICATE, _DISABLE));
4259
4260 if (pLutSurfaceEvo) {
4261 const NvU32 ctxDma = pLutSurfaceEvo->surfaceDesc.ctxDmaHandle;
4262 const NvU32 origin = offsetof(NVEvoLutDataRec, base);
4263
4264 nvDmaSetStartEvoMethod(pChannel, NVC37E_SET_CONTROL_INPUT_LUT, 1);
4265 nvDmaSetEvoMethodData(pChannel,
4266 DRF_DEF(C37E, _SET_CONTROL_INPUT_LUT, _SIZE, _SIZE_1025) |
4267 DRF_DEF(C37E, _SET_CONTROL_INPUT_LUT, _RANGE, _UNITY) |
4268 DRF_DEF(C37E, _SET_CONTROL_INPUT_LUT, _OUTPUT_MODE, _INDEX));
4269
4270 nvDmaSetStartEvoMethod(pChannel, NVC37E_SET_OFFSET_INPUT_LUT, 1);
4271 nvDmaSetEvoMethodData(pChannel,
4272 DRF_NUM(C37E, _SET_OFFSET_INPUT_LUT, _ORIGIN, origin));
4273
4274 nvDmaSetStartEvoMethod(pChannel, NVC37E_SET_CONTEXT_DMA_INPUT_LUT, 1);
4275 nvDmaSetEvoMethodData(pChannel,
4276 DRF_NUM(C37E, _SET_CONTEXT_DMA_INPUT_LUT, _HANDLE, ctxDma));
4277 } else {
4278 nvDmaSetStartEvoMethod(pChannel, NVC37E_SET_CONTEXT_DMA_INPUT_LUT, 1);
4279 nvDmaSetEvoMethodData(pChannel, 0);
4280 }
4281
4282 UpdateCompositionC3(pDevEvo, pChannel,
4283 &pHwState->composition, updateState,
4284 format);
4285 }
4286
EvoSetupPQEotfBaseLutC5(NVEvoLutDataRec * pData,enum NvKmsLUTState * lutState,NvU32 * lutSize,NvBool * isLutModeVss)4287 static void EvoSetupPQEotfBaseLutC5(NVEvoLutDataRec *pData,
4288 enum NvKmsLUTState *lutState,
4289 NvU32 *lutSize,
4290 NvBool *isLutModeVss)
4291 {
4292 NvU32 lutDataStartingIndex = NV_LUT_VSS_HEADER_SIZE;
4293 NvU32 numEotfPQ512Entries = ARRAY_LEN(EotfPQ512Entries);
4294 NvU32 eotfTableIdx;
4295 NvU64 vssHead = 0;
4296 NvU32 lutEntryCounter = 0, i;
4297
4298 // Skip LUT data init if already done
4299 if (*lutState == NvKmsLUTStatePQ) {
4300 goto skipInit;
4301 }
4302
4303 // VSS Header
4304 for (lutEntryCounter = 0; lutEntryCounter < NV_LUT_VSS_HEADER_SIZE; lutEntryCounter++) {
4305 vssHead = 0;
4306 for (i = 0; ((i < 16) && (((lutEntryCounter * 16) + i) < ARRAY_LEN(EotfPQ512SegSizesLog2))); i++) {
4307 NvU64 temp = EotfPQ512SegSizesLog2[(lutEntryCounter * 16) + i];
4308 temp = temp << (i * 3);
4309 vssHead |= temp;
4310 }
4311 nvkms_memcpy(&(pData->base[lutEntryCounter]), &vssHead, sizeof(NVEvoLutEntryRec));
4312 }
4313
4314 for (eotfTableIdx = 0; eotfTableIdx < numEotfPQ512Entries; eotfTableIdx++) {
4315 /*
4316 * Values are in range [0.0, 125.0], will be scaled back by OLUT.
4317 * XXX HDR TODO: Divide by 125.0 if output mode is not HDR?
4318 */
4319 pData->base[eotfTableIdx + lutDataStartingIndex].Red =
4320 pData->base[eotfTableIdx + lutDataStartingIndex].Green =
4321 pData->base[eotfTableIdx + lutDataStartingIndex].Blue =
4322 EotfPQ512Entries[eotfTableIdx];
4323 }
4324
4325 // Copy the last entry for interpolation
4326 pData->base[numEotfPQ512Entries + lutDataStartingIndex].Red =
4327 pData->base[numEotfPQ512Entries + lutDataStartingIndex - 1].Red;
4328 pData->base[numEotfPQ512Entries + lutDataStartingIndex].Green =
4329 pData->base[numEotfPQ512Entries + lutDataStartingIndex - 1].Green;
4330 pData->base[numEotfPQ512Entries + lutDataStartingIndex].Blue =
4331 pData->base[numEotfPQ512Entries + lutDataStartingIndex - 1].Blue;
4332
4333 skipInit:
4334 *lutState = NvKmsLUTStatePQ;
4335 *lutSize = NV_LUT_VSS_HEADER_SIZE + numEotfPQ512Entries + 1;
4336 *isLutModeVss = TRUE;
4337 }
4338
4339 static void
EvoSetupIdentityBaseLutC5(NVEvoLutDataRec * pData,enum NvKmsLUTState * lutState,NvU32 * lutSize,NvBool * isLutModeVss)4340 EvoSetupIdentityBaseLutC5(NVEvoLutDataRec *pData,
4341 enum NvKmsLUTState *lutState,
4342 NvU32 *lutSize,
4343 NvBool *isLutModeVss)
4344 {
4345 int i;
4346
4347 // Skip LUT data init if already done
4348 if (*lutState == NvKmsLUTStateIdentity) {
4349 goto skipInit;
4350 }
4351
4352 ct_assert(NV_NUM_EVO_LUT_ENTRIES == 1025);
4353
4354 // nvdisplay 3 uses FP16 entries in the ILUT.
4355 for (i = 0; i < 1024; i++) {
4356 pData->base[NV_LUT_VSS_HEADER_SIZE + i].Red =
4357 pData->base[NV_LUT_VSS_HEADER_SIZE + i].Green =
4358 pData->base[NV_LUT_VSS_HEADER_SIZE + i].Blue = nvUnorm10ToFp16(i).v;
4359 }
4360 pData->base[NV_LUT_VSS_HEADER_SIZE + 1024] =
4361 pData->base[NV_LUT_VSS_HEADER_SIZE + 1023];
4362
4363 skipInit:
4364 *lutState = NvKmsLUTStateIdentity;
4365 *lutSize = NV_LUT_VSS_HEADER_SIZE + NV_NUM_EVO_LUT_ENTRIES;
4366 *isLutModeVss = FALSE;
4367 }
4368
EvoSetILUTSurfaceAddressC5(NVEvoChannelPtr pChannel,const NVSurfaceDescriptor * pSurfaceDesc,NvU32 offset)4369 static void EvoSetILUTSurfaceAddressC5(
4370 NVEvoChannelPtr pChannel,
4371 const NVSurfaceDescriptor *pSurfaceDesc,
4372 NvU32 offset)
4373 {
4374 NvU32 ctxDmaHandle = pSurfaceDesc ? pSurfaceDesc->ctxDmaHandle : 0;
4375
4376 nvDmaSetStartEvoMethod(pChannel, NVC57E_SET_CONTEXT_DMA_ILUT, 1);
4377 nvDmaSetEvoMethodData(pChannel, DRF_NUM(C57E, _SET_CONTEXT_DMA_ILUT, _HANDLE, ctxDmaHandle));
4378
4379 nvDmaSetStartEvoMethod(pChannel, NVC57E_SET_OFFSET_ILUT, 1);
4380 nvDmaSetEvoMethodData(pChannel, DRF_NUM(C57E, _SET_OFFSET_ILUT, _ORIGIN, offset));
4381 }
4382
4383 static void
EvoFlipC5Common(NVDevEvoPtr pDevEvo,NVEvoChannelPtr pChannel,const NVFlipChannelEvoHwState * pHwState,NVEvoUpdateState * updateState,NvBool bypassComposition)4384 EvoFlipC5Common(NVDevEvoPtr pDevEvo,
4385 NVEvoChannelPtr pChannel,
4386 const NVFlipChannelEvoHwState *pHwState,
4387 NVEvoUpdateState *updateState,
4388 NvBool bypassComposition)
4389 {
4390 enum NvKmsSurfaceMemoryFormat format;
4391 NvBool swapUV;
4392 NvU32 hTaps, vTaps;
4393 NvBool scaling = FALSE;
4394 NVLutSurfaceEvoPtr pLutSurfaceEvo = NULL;
4395 NvU32 lutSize = NV_NUM_EVO_LUT_ENTRIES;
4396 NvBool isLutModeVss = FALSE;
4397
4398 NvU32 win = NV_EVO_CHANNEL_MASK_WINDOW_NUMBER(pChannel->channelMask);
4399 NvU32 head = pDevEvo->headForWindow[win];
4400
4401 const NvU32 sdMask = nvPeekEvoSubDevMask(pDevEvo);
4402 const NvU32 sd = (sdMask == 0) ? 0 : nv_ffs(sdMask) - 1;
4403 const NVDispHeadStateEvoRec *pHeadState = &pDevEvo->pDispEvo[sd]->headState[head];
4404
4405 // XXX HDR TODO: Handle other colorspaces
4406 // XXX HDR TODO: Enable custom input LUTs with HDR
4407 if (pHwState->colorSpace != NVKMS_INPUT_COLORSPACE_BT2100_PQ) {
4408 pLutSurfaceEvo = EvoGetLutSurface3(pDevEvo, pChannel, pHwState);
4409 }
4410
4411 if (!EvoFlipC3Common(pDevEvo, pChannel, pHwState, updateState, head)) {
4412 ConfigureTmoLut(pDevEvo, pHwState, pChannel);
4413 return;
4414 }
4415
4416 format = pHwState->pSurfaceEvo[NVKMS_LEFT]->format;
4417
4418 swapUV = IsSurfaceFormatUVSwapped(format);
4419 nvDmaSetStartEvoMethod(pChannel, NVC57E_SET_PARAMS, 1);
4420 nvDmaSetEvoMethodData(pChannel,
4421 DRF_NUM(C57E, _SET_PARAMS, _FORMAT, nvHwFormatFromKmsFormatC6(format)) |
4422 (swapUV ? DRF_DEF(C57E, _SET_PARAMS, _SWAP_UV, _ENABLE) :
4423 DRF_DEF(C57E, _SET_PARAMS, _SWAP_UV, _DISABLE)));
4424
4425 /*
4426 * In nvdisplay 2, there was a fixed-function block in the precomp FMT
4427 * module that was responsible for YUV->RGB conversion.
4428 *
4429 * In nvdisplay 3, that fixed-function block no longer exists.
4430 * In its place, there's a generic 3x4 S5.16 coefficient matrix that SW must
4431 * explicitly configure to convert the input surface format to the internal
4432 * RGB pipe native format.
4433 */
4434 EvoSetFMTMatrixC5(pChannel, format, pHwState);
4435
4436 vTaps = (pHwState->vTaps >= NV_EVO_SCALER_5TAPS) ?
4437 NVC57E_SET_CONTROL_INPUT_SCALER_VERTICAL_TAPS_TAPS_5 :
4438 NVC57E_SET_CONTROL_INPUT_SCALER_VERTICAL_TAPS_TAPS_2;
4439 hTaps = (pHwState->hTaps >= NV_EVO_SCALER_5TAPS) ?
4440 NVC57E_SET_CONTROL_INPUT_SCALER_HORIZONTAL_TAPS_TAPS_5 :
4441 NVC57E_SET_CONTROL_INPUT_SCALER_HORIZONTAL_TAPS_TAPS_2;
4442
4443 nvDmaSetStartEvoMethod(pChannel, NVC57E_SET_CONTROL_INPUT_SCALER, 1);
4444 nvDmaSetEvoMethodData(pChannel,
4445 DRF_NUM(C57E, _SET_CONTROL_INPUT_SCALER, _VERTICAL_TAPS, vTaps) |
4446 DRF_NUM(C57E, _SET_CONTROL_INPUT_SCALER, _HORIZONTAL_TAPS, hTaps));
4447
4448 scaling = (pHwState->sizeIn.width != pHwState->sizeOut.width) ||
4449 (pHwState->sizeIn.height != pHwState->sizeOut.height);
4450 nvAssert(!(scaling && bypassComposition));
4451
4452 /*
4453 * If scaling or tonemapping, we must enable the CSC0 and CSC1 pipelines.
4454 *
4455 * If no scaling or tonemapping, just use CSC11 to convert from the input
4456 * gamut to the output (panel) gamut, and disable everything else.
4457 */
4458 if (scaling ||
4459 nvNeedsTmoLut(pDevEvo, pChannel, pHwState,
4460 nvGetHDRSrcMaxLum(pHwState),
4461 pHeadState->hdrInfoFrame.staticMetadata.maxCLL)) {
4462 ConfigureCsc0C5(pDevEvo, pChannel, pHwState->colorSpace, TRUE);
4463 ConfigureCsc1C5(pDevEvo, pChannel, TRUE);
4464 } else {
4465 ConfigureCsc0C5(pDevEvo, pChannel, pHwState->colorSpace, FALSE);
4466 ConfigureCsc1C5(pDevEvo, pChannel, FALSE);
4467
4468 SetCsc11MatrixC5(pChannel, &pHwState->cscMatrix);
4469 }
4470
4471 // In nvdisplay 3, an ILUT is required to convert the input surface to FP16,
4472 // unless the surface being displayed is already FP16 to begin with.
4473 if ((format == NvKmsSurfaceMemoryFormatRF16GF16BF16AF16) ||
4474 (format == NvKmsSurfaceMemoryFormatRF16GF16BF16XF16) || bypassComposition) {
4475 nvAssert((pHwState->colorSpace == NVKMS_INPUT_COLORSPACE_SCRGB_LINEAR) ||
4476 (pHwState->colorSpace == NVKMS_INPUT_COLORSPACE_NONE));
4477 pLutSurfaceEvo = NULL;
4478 } else if (!pLutSurfaceEvo) {
4479 NVEvoLutDataRec *pData = NULL;
4480
4481 pLutSurfaceEvo = pDevEvo->lut.defaultLut;
4482 pData = pLutSurfaceEvo->subDeviceAddress[sd];
4483
4484 nvAssert(pData);
4485
4486 switch (pHwState->colorSpace) {
4487 case NVKMS_INPUT_COLORSPACE_BT2100_PQ:
4488 EvoSetupPQEotfBaseLutC5(pData,
4489 &pDevEvo->lut.defaultBaseLUTState[sd],
4490 &lutSize, &isLutModeVss);
4491 break;
4492 case NVKMS_INPUT_COLORSPACE_NONE:
4493 EvoSetupIdentityBaseLutC5(pData,
4494 &pDevEvo->lut.defaultBaseLUTState[sd],
4495 &lutSize, &isLutModeVss);
4496 break;
4497 default: // XXX HDR TODO: Handle other colorspaces
4498 nvAssert(FALSE);
4499 EvoSetupIdentityBaseLutC5(pData,
4500 &pDevEvo->lut.defaultBaseLUTState[sd],
4501 &lutSize, &isLutModeVss);
4502 break;
4503 }
4504 }
4505
4506 if (pLutSurfaceEvo) {
4507 const NvU32 origin = offsetof(NVEvoLutDataRec, base);
4508
4509 nvDmaSetStartEvoMethod(pChannel, NVC57E_SET_ILUT_CONTROL, 1);
4510 nvDmaSetEvoMethodData(pChannel,
4511 (isLutModeVss ? DRF_DEF(C57E, _SET_ILUT_CONTROL, _INTERPOLATE, _ENABLE) :
4512 DRF_DEF(C57E, _SET_ILUT_CONTROL, _INTERPOLATE, _DISABLE)) |
4513 DRF_DEF(C57E, _SET_ILUT_CONTROL, _MIRROR, _DISABLE) |
4514 (isLutModeVss ? DRF_DEF(C57E, _SET_ILUT_CONTROL, _MODE, _SEGMENTED) :
4515 DRF_DEF(C57E, _SET_ILUT_CONTROL, _MODE, _DIRECT10)) |
4516 DRF_NUM(C57E, _SET_ILUT_CONTROL, _SIZE, lutSize));
4517
4518 pDevEvo->hal->SetILUTSurfaceAddress(pChannel,
4519 &pLutSurfaceEvo->surfaceDesc, origin);
4520 } else {
4521 pDevEvo->hal->SetILUTSurfaceAddress(pChannel,
4522 NULL /* pSurfaceDesc */, 0 /* offset */);
4523 }
4524
4525 ConfigureTmoLut(pDevEvo, pHwState, pChannel);
4526
4527 UpdateCompositionC5(pDevEvo, pChannel,
4528 &pHwState->composition, updateState,
4529 bypassComposition,
4530 format);
4531 }
4532
4533 static void
EvoFlipC5(NVDevEvoPtr pDevEvo,NVEvoChannelPtr pChannel,const NVFlipChannelEvoHwState * pHwState,NVEvoUpdateState * updateState,NvBool bypassComposition)4534 EvoFlipC5(NVDevEvoPtr pDevEvo,
4535 NVEvoChannelPtr pChannel,
4536 const NVFlipChannelEvoHwState *pHwState,
4537 NVEvoUpdateState *updateState,
4538 NvBool bypassComposition)
4539 {
4540 EvoFlipC5Common(pDevEvo, pChannel, pHwState, updateState, bypassComposition);
4541
4542 /* Work around bug 2117571: whenever the tearing mode is changing, send a
4543 * software method to notify RM. */
4544 if (pHwState->tearing != pChannel->oldTearingMode) {
4545 NvU32 win = NV_EVO_CHANNEL_MASK_WINDOW_NUMBER(pChannel->channelMask);
4546 NvU32 head = pDevEvo->headForWindow[win];
4547
4548 if (head != NV_INVALID_HEAD) {
4549 nvDmaSetStartEvoMethod(pChannel, NVC57E_WINDOWS_NOTIFY_RM, 1);
4550 nvDmaSetEvoMethodData(pChannel,
4551 DRF_DEF(C57E, _WINDOWS_NOTIFY_RM, _VSYNC_STATE_CHANGE, _TRUE) |
4552 DRF_NUM(C57E, _WINDOWS_NOTIFY_RM, _ASSOCIATED_HEAD, head) |
4553 (pHwState->tearing ?
4554 DRF_DEF(C57E, _WINDOWS_NOTIFY_RM, _VSYNC_STATE, _OFF) :
4555 DRF_DEF(C57E, _WINDOWS_NOTIFY_RM, _VSYNC_STATE, _ON)));
4556 }
4557
4558 pChannel->oldTearingMode = pHwState->tearing;
4559 }
4560
4561 /* program semaphore */
4562 EvoProgramSemaphore3(pDevEvo, pChannel, pHwState);
4563 }
4564
4565 void
nvEvoFlipC6(NVDevEvoPtr pDevEvo,NVEvoChannelPtr pChannel,const NVFlipChannelEvoHwState * pHwState,NVEvoUpdateState * updateState,NvBool bypassComposition)4566 nvEvoFlipC6(NVDevEvoPtr pDevEvo,
4567 NVEvoChannelPtr pChannel,
4568 const NVFlipChannelEvoHwState *pHwState,
4569 NVEvoUpdateState *updateState,
4570 NvBool bypassComposition)
4571 {
4572 NvBool fromTop = TRUE;
4573 NvBool fromLeft = TRUE;
4574
4575 NvU32 vDirVal = 0;
4576 NvU32 hDirVal = 0;
4577
4578 switch (pHwState->rrParams.rotation) {
4579 case NVKMS_ROTATION_90:
4580 case NVKMS_ROTATION_270:
4581 nvAssert(!"Invalid rotation requested.");
4582 /* Fall-through */
4583 case NVKMS_ROTATION_0:
4584 break;
4585 case NVKMS_ROTATION_180:
4586 fromTop = FALSE;
4587 fromLeft = FALSE;
4588 break;
4589 }
4590
4591 if (pHwState->rrParams.reflectionX) {
4592 fromLeft = !fromLeft;
4593 }
4594 if (pHwState->rrParams.reflectionY) {
4595 fromTop = !fromTop;
4596 }
4597
4598 vDirVal = (fromTop ?
4599 DRF_DEF(C67E, _SET_SCAN_DIRECTION, _VERTICAL_DIRECTION, _FROM_TOP) :
4600 DRF_DEF(C67E, _SET_SCAN_DIRECTION, _VERTICAL_DIRECTION, _FROM_BOTTOM));
4601 hDirVal = (fromLeft ?
4602 DRF_DEF(C67E, _SET_SCAN_DIRECTION, _HORIZONTAL_DIRECTION, _FROM_LEFT) :
4603 DRF_DEF(C67E, _SET_SCAN_DIRECTION, _HORIZONTAL_DIRECTION, _FROM_RIGHT));
4604
4605 nvDmaSetStartEvoMethod(pChannel, NVC67E_SET_SCAN_DIRECTION, 1);
4606 nvDmaSetEvoMethodData(pChannel, vDirVal | hDirVal);
4607
4608 EvoFlipC5Common(pDevEvo, pChannel, pHwState, updateState, bypassComposition);
4609
4610 /* program semaphore */
4611 EvoProgramSemaphore6(pDevEvo, pChannel, pHwState);
4612 }
4613
UpdateComposition(NVDevEvoPtr pDevEvo,NVEvoChannelPtr pChannel,NvU32 depth,NvU32 colorKeySelect,NvU32 constantAlpha,NvU32 compositionFactorSelect,const NVColorKey key,NVEvoUpdateState * updateState)4614 static void UpdateComposition(NVDevEvoPtr pDevEvo,
4615 NVEvoChannelPtr pChannel,
4616 /* smaller => closer to front */
4617 NvU32 depth,
4618 NvU32 colorKeySelect,
4619 NvU32 constantAlpha,
4620 NvU32 compositionFactorSelect,
4621 const NVColorKey key,
4622 NVEvoUpdateState *updateState)
4623 {
4624 nvUpdateUpdateState(pDevEvo, updateState, pChannel);
4625
4626 nvDmaSetStartEvoMethod(pChannel, NVC37E_SET_COMPOSITION_CONTROL, 1);
4627 nvDmaSetEvoMethodData(pChannel,
4628 DRF_NUM(C37E, _SET_COMPOSITION_CONTROL, _COLOR_KEY_SELECT, colorKeySelect) |
4629 DRF_NUM(C37E, _SET_COMPOSITION_CONTROL, _DEPTH, depth));
4630
4631 nvDmaSetStartEvoMethod(pChannel, NVC37E_SET_COMPOSITION_CONSTANT_ALPHA, 1);
4632 nvDmaSetEvoMethodData(pChannel,
4633 DRF_NUM(C37E, _SET_COMPOSITION_CONSTANT_ALPHA, _K1, constantAlpha));
4634
4635 nvDmaSetStartEvoMethod(pChannel, NVC37E_SET_COMPOSITION_FACTOR_SELECT, 1);
4636 nvDmaSetEvoMethodData(pChannel, compositionFactorSelect);
4637
4638 #define UPDATE_COMPONENT(_COMP, _C, _c) \
4639 nvDmaSetStartEvoMethod(pChannel, NVC37E_SET_KEY_##_COMP, 1); \
4640 if (key.match##_C) { \
4641 nvDmaSetEvoMethodData(pChannel, \
4642 DRF_NUM(C37E, _SET_KEY_##_COMP, _MIN, key._c) | \
4643 DRF_NUM(C37E, _SET_KEY_##_COMP, _MAX, key._c)); \
4644 } else { \
4645 nvDmaSetEvoMethodData(pChannel, \
4646 DRF_NUM(C37E, _SET_KEY_##_COMP, _MIN, 0) | \
4647 DRF_SHIFTMASK(NVC37E_SET_KEY_##_COMP##_MAX)); \
4648 }
4649
4650 if (colorKeySelect !=
4651 NVC37E_SET_COMPOSITION_CONTROL_COLOR_KEY_SELECT_DISABLE) {
4652 UPDATE_COMPONENT(ALPHA, A, a);
4653 UPDATE_COMPONENT(RED_CR, R, r);
4654 UPDATE_COMPONENT(GREEN_Y, G, g);
4655 UPDATE_COMPONENT(BLUE_CB, B, b);
4656 }
4657
4658 #undef UPDATE_COMPONENT
4659 }
4660
EvoFlipTransitionWARC3(NVDevEvoPtr pDevEvo,NvU32 sd,NvU32 head,const NVEvoSubDevHeadStateRec * pSdHeadState,const NVFlipEvoHwState * pFlipState,NVEvoUpdateState * updateState)4661 static void EvoFlipTransitionWARC3(NVDevEvoPtr pDevEvo, NvU32 sd, NvU32 head,
4662 const NVEvoSubDevHeadStateRec *pSdHeadState,
4663 const NVFlipEvoHwState *pFlipState,
4664 NVEvoUpdateState *updateState)
4665 {
4666 /* Nothing to do for Volta */
4667 }
4668
4669 /*
4670 * Hardware bug 2193096 requires that we send special software methods around
4671 * a window channel update that transitions from NULL ctxdma to non-NULL or
4672 * vice versa. Below we compare the current hardware state in pSdHeadState
4673 * against the state to be pushed in this update in pFlipState, and add any
4674 * window(s) that qualify to the 'flipTransitionWAR' mask in the updateState.
4675 */
EvoFlipTransitionWARC5(NVDevEvoPtr pDevEvo,NvU32 sd,NvU32 head,const NVEvoSubDevHeadStateRec * pSdHeadState,const NVFlipEvoHwState * pFlipState,NVEvoUpdateState * updateState)4676 static void EvoFlipTransitionWARC5(NVDevEvoPtr pDevEvo, NvU32 sd, NvU32 head,
4677 const NVEvoSubDevHeadStateRec *pSdHeadState,
4678 const NVFlipEvoHwState *pFlipState,
4679 NVEvoUpdateState *updateState)
4680 {
4681 NvU32 layer;
4682
4683 for (layer = 0; layer < pDevEvo->head[head].numLayers; layer++) {
4684 const NvBool enabledPrev =
4685 pSdHeadState->layer[layer].pSurfaceEvo[NVKMS_LEFT] != NULL;
4686 const NvBool enabledNext =
4687 pFlipState->layer[layer].pSurfaceEvo[NVKMS_LEFT] != NULL;
4688
4689 if (enabledPrev != enabledNext) {
4690 /* XXX TODO: dynamic window assignment */
4691 const NvU32 win = NV_EVO_CHANNEL_MASK_WINDOW_NUMBER(
4692 pDevEvo->head[head].layer[layer]->channelMask);
4693 updateState->subdev[sd].flipTransitionWAR |=
4694 DRF_IDX_DEF64(_EVO, _CHANNEL_MASK, _WINDOW, win, _ENABLE);
4695
4696 nvAssert(pFlipState->dirty.layer[layer]);
4697 }
4698 }
4699 }
4700
nvEvoFlipTransitionWARC6(NVDevEvoPtr pDevEvo,NvU32 sd,NvU32 head,const NVEvoSubDevHeadStateRec * pSdHeadState,const NVFlipEvoHwState * pFlipState,NVEvoUpdateState * updateState)4701 void nvEvoFlipTransitionWARC6(NVDevEvoPtr pDevEvo, NvU32 sd, NvU32 head,
4702 const NVEvoSubDevHeadStateRec *pSdHeadState,
4703 const NVFlipEvoHwState *pFlipState,
4704 NVEvoUpdateState *updateState)
4705 {
4706 /* Nothing to do for Orin/Ampere for now */
4707 }
4708
4709 static void
UpdateCompositionC3(NVDevEvoPtr pDevEvo,NVEvoChannelPtr pChannel,const struct NvKmsCompositionParams * pCompParams,NVEvoUpdateState * updateState,enum NvKmsSurfaceMemoryFormat format)4710 UpdateCompositionC3(NVDevEvoPtr pDevEvo,
4711 NVEvoChannelPtr pChannel,
4712 const struct NvKmsCompositionParams *pCompParams,
4713 NVEvoUpdateState *updateState,
4714 enum NvKmsSurfaceMemoryFormat format)
4715 {
4716 NvU32 colorKeySelect;
4717 NvU32 compositionFactorSelect = 0;
4718 NvU32 constantAlpha = 0;
4719 NvU32 match;
4720
4721 switch (pCompParams->colorKeySelect) {
4722 case NVKMS_COMPOSITION_COLOR_KEY_SELECT_DISABLE:
4723 colorKeySelect =
4724 NVC37E_SET_COMPOSITION_CONTROL_COLOR_KEY_SELECT_DISABLE;
4725 break;
4726 case NVKMS_COMPOSITION_COLOR_KEY_SELECT_SRC:
4727 colorKeySelect =
4728 NVC37E_SET_COMPOSITION_CONTROL_COLOR_KEY_SELECT_SRC;
4729
4730 break;
4731 case NVKMS_COMPOSITION_COLOR_KEY_SELECT_DST:
4732 colorKeySelect =
4733 NVC37E_SET_COMPOSITION_CONTROL_COLOR_KEY_SELECT_DST;
4734
4735 break;
4736 default:
4737 nvAssert(!"Invalid color key select");
4738 return;
4739 }
4740
4741 /* Match and nomatch pixels should not use alpha blending mode at once. */
4742 nvAssert((colorKeySelect == NVKMS_COMPOSITION_COLOR_KEY_SELECT_DISABLE) ||
4743 (!NvKmsIsCompositionModeUseAlpha(pCompParams->blendingMode[0])) ||
4744 (!NvKmsIsCompositionModeUseAlpha(pCompParams->blendingMode[1])));
4745
4746 /*
4747 * Match and nomatch pixels should not use blending mode PREMULT_ALPHA,
4748 * NON_PREMULT_ALPHA, PREMULT_SURFACE_ALPHA, and NON_PREMULT_SURFACE_ALPHA
4749 * at once.
4750 */
4751 nvAssert(pCompParams->blendingMode[0] == NVKMS_COMPOSITION_BLENDING_MODE_OPAQUE ||
4752 pCompParams->blendingMode[0] == NVKMS_COMPOSITION_BLENDING_MODE_TRANSPARENT ||
4753 pCompParams->blendingMode[1] == NVKMS_COMPOSITION_BLENDING_MODE_OPAQUE ||
4754 pCompParams->blendingMode[1] == NVKMS_COMPOSITION_BLENDING_MODE_TRANSPARENT);
4755
4756 for (match = 0; match <= 1; match++) {
4757 switch (pCompParams->blendingMode[match]) {
4758 case NVKMS_COMPOSITION_BLENDING_MODE_OPAQUE:
4759 if (match == 1) {
4760 compositionFactorSelect |=
4761 DRF_DEF(C37E, _SET_COMPOSITION_FACTOR_SELECT, _SRC_COLOR_FACTOR_MATCH_SELECT, _ONE) |
4762 DRF_DEF(C37E, _SET_COMPOSITION_FACTOR_SELECT, _DST_COLOR_FACTOR_MATCH_SELECT, _ZERO);
4763 } else {
4764 compositionFactorSelect |=
4765 DRF_DEF(C37E, _SET_COMPOSITION_FACTOR_SELECT, _SRC_COLOR_FACTOR_NO_MATCH_SELECT, _ONE) |
4766 DRF_DEF(C37E, _SET_COMPOSITION_FACTOR_SELECT, _DST_COLOR_FACTOR_NO_MATCH_SELECT, _ZERO);
4767 }
4768 break;
4769 case NVKMS_COMPOSITION_BLENDING_MODE_TRANSPARENT:
4770 if (match == 1) {
4771 compositionFactorSelect |=
4772 DRF_DEF(C37E, _SET_COMPOSITION_FACTOR_SELECT, _SRC_COLOR_FACTOR_MATCH_SELECT, _ZERO) |
4773 DRF_DEF(C37E, _SET_COMPOSITION_FACTOR_SELECT, _DST_COLOR_FACTOR_MATCH_SELECT, _ONE);
4774 } else {
4775 compositionFactorSelect |=
4776 DRF_DEF(C37E, _SET_COMPOSITION_FACTOR_SELECT, _SRC_COLOR_FACTOR_NO_MATCH_SELECT, _ZERO) |
4777 DRF_DEF(C37E, _SET_COMPOSITION_FACTOR_SELECT, _DST_COLOR_FACTOR_NO_MATCH_SELECT, _ONE);
4778 }
4779 break;
4780 case NVKMS_COMPOSITION_BLENDING_MODE_NON_PREMULT_ALPHA:
4781 constantAlpha = 255;
4782 if (match == 1) {
4783 compositionFactorSelect |=
4784 DRF_DEF(C37E, _SET_COMPOSITION_FACTOR_SELECT, _SRC_COLOR_FACTOR_MATCH_SELECT, _K1_TIMES_SRC) |
4785 DRF_DEF(C37E, _SET_COMPOSITION_FACTOR_SELECT, _DST_COLOR_FACTOR_MATCH_SELECT, _NEG_K1_TIMES_SRC);
4786 } else {
4787 compositionFactorSelect |=
4788 DRF_DEF(C37E, _SET_COMPOSITION_FACTOR_SELECT, _SRC_COLOR_FACTOR_NO_MATCH_SELECT, _K1_TIMES_SRC) |
4789 DRF_DEF(C37E, _SET_COMPOSITION_FACTOR_SELECT, _DST_COLOR_FACTOR_NO_MATCH_SELECT, _NEG_K1_TIMES_SRC);
4790 }
4791 break;
4792 case NVKMS_COMPOSITION_BLENDING_MODE_PREMULT_ALPHA:
4793 constantAlpha = 255;
4794 if (match == 1) {
4795 compositionFactorSelect |=
4796 DRF_DEF(C37E, _SET_COMPOSITION_FACTOR_SELECT, _SRC_COLOR_FACTOR_MATCH_SELECT, _K1) |
4797 DRF_DEF(C37E, _SET_COMPOSITION_FACTOR_SELECT, _DST_COLOR_FACTOR_MATCH_SELECT, _NEG_K1_TIMES_SRC);
4798 } else {
4799 compositionFactorSelect |=
4800 DRF_DEF(C37E, _SET_COMPOSITION_FACTOR_SELECT, _SRC_COLOR_FACTOR_NO_MATCH_SELECT, _K1) |
4801 DRF_DEF(C37E, _SET_COMPOSITION_FACTOR_SELECT, _DST_COLOR_FACTOR_NO_MATCH_SELECT, _NEG_K1_TIMES_SRC);
4802 }
4803 break;
4804 case NVKMS_COMPOSITION_BLENDING_MODE_NON_PREMULT_SURFACE_ALPHA:
4805 constantAlpha = pCompParams->surfaceAlpha;
4806 if (match == 1) {
4807 compositionFactorSelect |=
4808 DRF_DEF(C37E, _SET_COMPOSITION_FACTOR_SELECT, _SRC_COLOR_FACTOR_MATCH_SELECT, _K1_TIMES_SRC) |
4809 DRF_DEF(C37E, _SET_COMPOSITION_FACTOR_SELECT, _DST_COLOR_FACTOR_MATCH_SELECT, _NEG_K1_TIMES_SRC);
4810 } else {
4811 compositionFactorSelect |=
4812 DRF_DEF(C37E, _SET_COMPOSITION_FACTOR_SELECT, _SRC_COLOR_FACTOR_NO_MATCH_SELECT, _K1_TIMES_SRC) |
4813 DRF_DEF(C37E, _SET_COMPOSITION_FACTOR_SELECT, _DST_COLOR_FACTOR_NO_MATCH_SELECT, _NEG_K1_TIMES_SRC);
4814 }
4815 break;
4816 case NVKMS_COMPOSITION_BLENDING_MODE_PREMULT_SURFACE_ALPHA:
4817 constantAlpha = pCompParams->surfaceAlpha;
4818 if (match == 1) {
4819 compositionFactorSelect |=
4820 DRF_DEF(C37E, _SET_COMPOSITION_FACTOR_SELECT, _SRC_COLOR_FACTOR_MATCH_SELECT, _K1) |
4821 DRF_DEF(C37E, _SET_COMPOSITION_FACTOR_SELECT, _DST_COLOR_FACTOR_MATCH_SELECT, _NEG_K1_TIMES_SRC);
4822 } else {
4823 compositionFactorSelect |=
4824 DRF_DEF(C37E, _SET_COMPOSITION_FACTOR_SELECT, _SRC_COLOR_FACTOR_NO_MATCH_SELECT, _K1) |
4825 DRF_DEF(C37E, _SET_COMPOSITION_FACTOR_SELECT, _DST_COLOR_FACTOR_NO_MATCH_SELECT, _NEG_K1_TIMES_SRC);
4826 }
4827 break;
4828 default:
4829 nvAssert(!"Invalid blend mode");
4830 return;
4831 }
4832
4833 /* Override the composition factors for X channel emulated surface format. */
4834 if (NvKmsIsCompositionModeUseAlpha(pCompParams->blendingMode[match]) &&
4835 ((pDevEvo->hal->caps.xEmulatedSurfaceMemoryFormats & NVBIT64(format)) != 0U)) {
4836 if (match == 1) {
4837 /* Clear the previously selected composition factors for match pixels. */
4838 compositionFactorSelect &= ~(DRF_MASK(NVC37E_SET_COMPOSITION_FACTOR_SELECT_SRC_COLOR_FACTOR_MATCH_SELECT) <<
4839 DRF_SHIFT(NVC37E_SET_COMPOSITION_FACTOR_SELECT_SRC_COLOR_FACTOR_MATCH_SELECT));
4840 compositionFactorSelect &= ~(DRF_MASK(NVC37E_SET_COMPOSITION_FACTOR_SELECT_DST_COLOR_FACTOR_MATCH_SELECT) <<
4841 DRF_SHIFT(NVC37E_SET_COMPOSITION_FACTOR_SELECT_DST_COLOR_FACTOR_MATCH_SELECT));
4842
4843 compositionFactorSelect |=
4844 DRF_DEF(C37E, _SET_COMPOSITION_FACTOR_SELECT, _SRC_COLOR_FACTOR_MATCH_SELECT, _K1) |
4845 DRF_DEF(C37E, _SET_COMPOSITION_FACTOR_SELECT, _DST_COLOR_FACTOR_MATCH_SELECT, _NEG_K1);
4846 } else {
4847 /* Clear the previously selected composition factors for no-match pixels. */
4848 compositionFactorSelect &= ~(DRF_MASK(NVC37E_SET_COMPOSITION_FACTOR_SELECT_SRC_COLOR_FACTOR_NO_MATCH_SELECT) <<
4849 DRF_SHIFT(NVC37E_SET_COMPOSITION_FACTOR_SELECT_SRC_COLOR_FACTOR_NO_MATCH_SELECT));
4850 compositionFactorSelect &= ~(DRF_MASK(NVC37E_SET_COMPOSITION_FACTOR_SELECT_DST_COLOR_FACTOR_NO_MATCH_SELECT) <<
4851 DRF_SHIFT(NVC37E_SET_COMPOSITION_FACTOR_SELECT_DST_COLOR_FACTOR_NO_MATCH_SELECT));
4852
4853 compositionFactorSelect |=
4854 DRF_DEF(C37E, _SET_COMPOSITION_FACTOR_SELECT, _SRC_COLOR_FACTOR_NO_MATCH_SELECT, _K1) |
4855 DRF_DEF(C37E, _SET_COMPOSITION_FACTOR_SELECT, _DST_COLOR_FACTOR_NO_MATCH_SELECT, _NEG_K1);
4856 }
4857 }
4858 }
4859
4860 UpdateComposition(pDevEvo,
4861 pChannel,
4862 pCompParams->depth,
4863 colorKeySelect,
4864 constantAlpha,
4865 compositionFactorSelect,
4866 pCompParams->colorKey,
4867 updateState);
4868 }
4869
EvoBypassCompositionC5(NVDevEvoPtr pDevEvo,NVEvoChannelPtr pChannel,NVEvoUpdateState * updateState)4870 static void EvoBypassCompositionC5(NVDevEvoPtr pDevEvo,
4871 NVEvoChannelPtr pChannel,
4872 NVEvoUpdateState *updateState)
4873 {
4874 nvUpdateUpdateState(pDevEvo, updateState, pChannel);
4875
4876 nvDmaSetStartEvoMethod(pChannel, NVC57E_SET_COMPOSITION_CONTROL, 1);
4877 nvDmaSetEvoMethodData(pChannel,
4878 DRF_DEF(C57E, _SET_COMPOSITION_CONTROL, _BYPASS, _ENABLE));
4879 }
4880
4881 static void
UpdateCompositionC5(NVDevEvoPtr pDevEvo,NVEvoChannelPtr pChannel,const struct NvKmsCompositionParams * pCompParams,NVEvoUpdateState * updateState,NvBool bypassComposition,enum NvKmsSurfaceMemoryFormat format)4882 UpdateCompositionC5(NVDevEvoPtr pDevEvo,
4883 NVEvoChannelPtr pChannel,
4884 const struct NvKmsCompositionParams *pCompParams,
4885 NVEvoUpdateState *updateState,
4886 NvBool bypassComposition,
4887 enum NvKmsSurfaceMemoryFormat format)
4888 {
4889 if (bypassComposition) {
4890 EvoBypassCompositionC5(pDevEvo, pChannel, updateState);
4891 } else {
4892 UpdateCompositionC3(pDevEvo, pChannel, pCompParams,
4893 updateState, format);
4894 }
4895 }
4896
4897 /*
4898 * The LUT entries in INDEX_1025_UNITY_RANGE have 16 bits, with the
4899 * black value at 24576, and the white at 49151. Since the effective
4900 * range is 16384, we treat this as a 14-bit LUT. However, we need to
4901 * clear the low 3 bits to WAR hardware bug 813188. This gives us
4902 * 14-bit LUT values, but only 11 bits of precision.
4903 * XXXnvdisplay: Bug 813188 is supposed to be fixed on NVDisplay; can we expose
4904 * more precision?
4905 */
ColorToLUTEntry(NvU16 val)4906 static inline NvU16 ColorToLUTEntry(NvU16 val)
4907 {
4908 const NvU16 val14bit = val >> 2;
4909 return (val14bit & ~7) + 24576;
4910 }
4911
4912 /*
4913 * Unlike earlier EVO implementations, the INDEX mode of the input LUT on
4914 * NVDisplay is straightforward: the value of the input component is expanded
4915 * to the LUT size by simply shifting left by the difference between the LUT
4916 * index width and the component width. We do the same, here, to select the
4917 * right LUT entry to fill.
4918 */
GetLUTIndex(int i,int componentSize)4919 static inline NvU32 GetLUTIndex(int i, int componentSize)
4920 {
4921 return i << (10 - componentSize);
4922 }
4923
4924 static void
EvoFillLUTSurfaceC3(NVEvoLutEntryRec * pLUTBuffer,const NvU16 * red,const NvU16 * green,const NvU16 * blue,int nColorMapEntries,int depth)4925 EvoFillLUTSurfaceC3(NVEvoLutEntryRec *pLUTBuffer,
4926 const NvU16 *red,
4927 const NvU16 *green,
4928 const NvU16 *blue,
4929 int nColorMapEntries, int depth)
4930 {
4931 int i;
4932 NvU32 rSize, gSize, bSize;
4933
4934 switch (depth) {
4935 case 15:
4936 rSize = gSize = bSize = 5;
4937 break;
4938 case 16:
4939 rSize = bSize = 5;
4940 gSize = 6;
4941 break;
4942 case 8:
4943 case 24:
4944 rSize = gSize = bSize = 8;
4945 break;
4946 case 30:
4947 rSize = gSize = bSize = 10;
4948 break;
4949 default:
4950 nvAssert(!"invalid depth");
4951 return;
4952 }
4953
4954 for (i = 0; i < nColorMapEntries; i++) {
4955 if (i < (1 << rSize)) {
4956 pLUTBuffer[GetLUTIndex(i, rSize)].Red = ColorToLUTEntry(red[i]);
4957 }
4958 if (i < (1 << gSize)) {
4959 pLUTBuffer[GetLUTIndex(i, gSize)].Green = ColorToLUTEntry(green[i]);
4960 }
4961 if (i < (1 << bSize)) {
4962 pLUTBuffer[GetLUTIndex(i, bSize)].Blue = ColorToLUTEntry(blue[i]);
4963 }
4964 }
4965 }
4966
ColorToFp16(NvU16 val,float32_t maxf)4967 static inline float16_t ColorToFp16(NvU16 val, float32_t maxf)
4968 {
4969 return nvUnormToFp16(val, maxf);
4970 }
4971
4972 void
nvEvoFillLUTSurfaceC5(NVEvoLutEntryRec * pLUTBuffer,const NvU16 * red,const NvU16 * green,const NvU16 * blue,int nColorMapEntries,int depth)4973 nvEvoFillLUTSurfaceC5(NVEvoLutEntryRec *pLUTBuffer,
4974 const NvU16 *red,
4975 const NvU16 *green,
4976 const NvU16 *blue,
4977 int nColorMapEntries, int depth)
4978 {
4979 int i;
4980 NvU32 rSize, gSize, bSize;
4981 const float32_t maxf = ui32_to_f32(0xffff);
4982
4983 switch (depth) {
4984 case 15:
4985 rSize = gSize = bSize = 5;
4986 break;
4987 case 16:
4988 rSize = bSize = 5;
4989 gSize = 6;
4990 break;
4991 case 8:
4992 case 24:
4993 rSize = gSize = bSize = 8;
4994 break;
4995 case 30:
4996 rSize = gSize = bSize = 10;
4997 break;
4998 default:
4999 nvAssert(!"invalid depth");
5000 return;
5001 }
5002
5003 // Skip the VSS header
5004 pLUTBuffer += NV_LUT_VSS_HEADER_SIZE;
5005
5006 for (i = 0; i < nColorMapEntries; i++) {
5007 if (i < (1 << rSize)) {
5008 pLUTBuffer[GetLUTIndex(i, rSize)].Red =
5009 ColorToFp16(red[i], maxf).v;
5010 }
5011 if (i < (1 << gSize)) {
5012 pLUTBuffer[GetLUTIndex(i, gSize)].Green =
5013 ColorToFp16(green[i], maxf).v;
5014 }
5015 if (i < (1 << bSize)) {
5016 pLUTBuffer[GetLUTIndex(i, bSize)].Blue =
5017 ColorToFp16(blue[i], maxf).v;
5018 }
5019 }
5020 }
5021
EvoSetLUTContextDma3(NVDevEvoPtr pDevEvo,const int head,NVLutSurfaceEvoPtr pLutSurfEvo,NvBool enableBaseLut,NVEvoUpdateState * updateState,NvBool bypassComposition)5022 static void EvoSetLUTContextDma3(NVDevEvoPtr pDevEvo,
5023 const int head,
5024 NVLutSurfaceEvoPtr pLutSurfEvo,
5025 NvBool enableBaseLut,
5026 NVEvoUpdateState *updateState,
5027 NvBool bypassComposition)
5028 {
5029 NVEvoChannelPtr pChannel = pDevEvo->core;
5030 NvU32 sd;
5031
5032 /* These methods should only apply to a single pDpy */
5033 nvAssert(pDevEvo->subDevMaskStackDepth > 0);
5034
5035 nvUpdateUpdateState(pDevEvo, updateState, pChannel);
5036
5037 /*
5038 * For Window semaphores and Notifiers, the general rule of thumb is that
5039 * the current semaphore/notifier will be released if the address for the
5040 * semaphore/notifier changes (via context DMA change or offset change).
5041 * This allows SW to push updates in the window channel that change other
5042 * methods, but do not cause the semaphore or notifier to be released. This
5043 * make it possible to reprogram the window channel with new input Lut
5044 * without releasing semaphore.
5045 *
5046 * Note that higher-level code will use core channel notifiers to
5047 * synchronize these LUT updates, but that's okay because nvEvoUpdateC3()
5048 * will interlock the core and window channel(s) updates together.
5049 */
5050 for (sd = 0; sd < pDevEvo->numSubDevices; sd++) {
5051 if (nvPeekEvoSubDevMask(pDevEvo) & (1 << sd)) {
5052 NVEvoChannelPtr pChannel = pDevEvo->window[head << 1];
5053 NVEvoSubDevHeadStateRec *pSdHeadState =
5054 &pDevEvo->gpus[sd].headState[head];
5055 NVFlipChannelEvoHwState *pMainFlipState =
5056 &pSdHeadState->layer[NVKMS_MAIN_LAYER];
5057 NVLutSurfaceEvoPtr pInputLutSurfEvo = enableBaseLut ?
5058 pLutSurfEvo : NULL;
5059
5060 if (pMainFlipState->inputLut.pLutSurfaceEvo == pInputLutSurfEvo) {
5061 continue;
5062 }
5063
5064 pMainFlipState->inputLut.pLutSurfaceEvo = pInputLutSurfEvo;
5065 /* It is not allowed to change the input LUT on immediate flips. */
5066 pMainFlipState->tearing = FALSE;
5067
5068 nvPushEvoSubDevMask(pDevEvo, NVBIT(sd));
5069
5070 pDevEvo->hal->Flip(pDevEvo, pChannel, pMainFlipState, updateState,
5071 bypassComposition);
5072
5073 nvPopEvoSubDevMask(pDevEvo);
5074 }
5075 }
5076 }
5077
EvoSetLUTContextDmaC3(const NVDispEvoRec * pDispEvo,const int head,NVLutSurfaceEvoPtr pLutSurfEvo,NvBool enableBaseLut,NvBool enableOutputLut,NVEvoUpdateState * updateState,NvBool bypassComposition)5078 static void EvoSetLUTContextDmaC3(const NVDispEvoRec *pDispEvo,
5079 const int head,
5080 NVLutSurfaceEvoPtr pLutSurfEvo,
5081 NvBool enableBaseLut,
5082 NvBool enableOutputLut,
5083 NVEvoUpdateState *updateState,
5084 NvBool bypassComposition)
5085 {
5086 NvU32 ctxdma = (pLutSurfEvo != NULL) ? pLutSurfEvo->surfaceDesc.ctxDmaHandle : 0;
5087 NVDevEvoPtr pDevEvo = pDispEvo->pDevEvo;
5088 NVEvoChannelPtr pChannel = pDevEvo->core;
5089 NvU64 offset;
5090
5091 nvAssert(ctxdma || (!enableBaseLut && !enableOutputLut));
5092
5093 nvPushEvoSubDevMaskDisp(pDispEvo);
5094
5095 EvoSetLUTContextDma3(pDevEvo,
5096 head,
5097 pLutSurfEvo,
5098 enableBaseLut,
5099 updateState,
5100 bypassComposition);
5101
5102 /* Program the output LUT */
5103
5104 offset = offsetof(NVEvoLutDataRec, output);
5105 nvAssert((offset & 0xff) == 0);
5106
5107 nvDmaSetStartEvoMethod(pChannel, NVC37D_HEAD_SET_CONTROL_OUTPUT_LUT(head), 1);
5108 nvDmaSetEvoMethodData(pChannel,
5109 DRF_DEF(C37D, _HEAD_SET_CONTROL_OUTPUT_LUT, _SIZE, _SIZE_1025) |
5110 DRF_DEF(C37D, _HEAD_SET_CONTROL_OUTPUT_LUT, _RANGE, _UNITY) |
5111 DRF_DEF(C37D, _HEAD_SET_CONTROL_OUTPUT_LUT, _OUTPUT_MODE, _INTERPOLATE));
5112
5113 nvDmaSetStartEvoMethod(pChannel, NVC37D_HEAD_SET_OFFSET_OUTPUT_LUT(head), 1);
5114 nvDmaSetEvoMethodData(pChannel,
5115 DRF_NUM(C37D, _HEAD_SET_OFFSET_OUTPUT_LUT, _ORIGIN, offset >> 8));
5116
5117 /* Set the ctxdma for the output LUT */
5118
5119 if (!enableOutputLut) {
5120 /* Class C37D has no separate enable flag. */
5121 ctxdma = 0;
5122 }
5123 nvDmaSetStartEvoMethod(pChannel, NVC37D_HEAD_SET_CONTEXT_DMA_OUTPUT_LUT(head), 1);
5124 nvDmaSetEvoMethodData(pChannel,
5125 DRF_NUM(C37D, _HEAD_SET_CONTEXT_DMA_OUTPUT_LUT, _HANDLE, ctxdma));
5126
5127 nvPopEvoSubDevMask(pDevEvo);
5128 }
5129
EvoSetupPQOetfOutputLutC5(NVEvoLutDataRec * pData,enum NvKmsLUTState * lutState,NvU32 * lutSize,NvBool * isLutModeVss)5130 static void EvoSetupPQOetfOutputLutC5(NVEvoLutDataRec *pData,
5131 enum NvKmsLUTState *lutState,
5132 NvU32 *lutSize,
5133 NvBool *isLutModeVss)
5134 {
5135 NvU32 lutDataStartingIndex = NV_LUT_VSS_HEADER_SIZE;
5136 NvU32 numOetfPQ512Entries = ARRAY_LEN(OetfPQ512Entries);
5137 NvU32 oetfTableIdx;
5138 NvU64 vssHead = 0;
5139 NvU32 lutEntryCounter = 0, i;
5140
5141 // Skip LUT data init if already done
5142 if (*lutState == NvKmsLUTStatePQ) {
5143 goto skipInit;
5144 }
5145
5146 // VSS Header
5147 for (lutEntryCounter = 0; lutEntryCounter < NV_LUT_VSS_HEADER_SIZE; lutEntryCounter++) {
5148 vssHead = 0;
5149 for (i = 0; ((i < 16) && (((lutEntryCounter * 16) + i) < ARRAY_LEN(OetfPQ512SegSizesLog2))); i++) {
5150 NvU64 temp = OetfPQ512SegSizesLog2[(lutEntryCounter * 16) + i];
5151 temp = temp << (i * 3);
5152 vssHead |= temp;
5153 }
5154 nvkms_memcpy(&(pData->output[lutEntryCounter]), &vssHead, sizeof(NVEvoLutEntryRec));
5155 }
5156
5157 for (oetfTableIdx = 0; oetfTableIdx < numOetfPQ512Entries; oetfTableIdx++) {
5158 pData->output[oetfTableIdx + lutDataStartingIndex].Red =
5159 pData->output[oetfTableIdx + lutDataStartingIndex].Green =
5160 pData->output[oetfTableIdx + lutDataStartingIndex].Blue =
5161 OetfPQ512Entries[oetfTableIdx];
5162 }
5163
5164 // Copy the last entry for interpolation
5165 pData->output[numOetfPQ512Entries + lutDataStartingIndex].Red =
5166 pData->output[numOetfPQ512Entries + lutDataStartingIndex - 1].Red;
5167 pData->output[numOetfPQ512Entries + lutDataStartingIndex].Green =
5168 pData->output[numOetfPQ512Entries + lutDataStartingIndex - 1].Green;
5169 pData->output[numOetfPQ512Entries + lutDataStartingIndex].Blue =
5170 pData->output[numOetfPQ512Entries + lutDataStartingIndex - 1].Blue;
5171
5172 skipInit:
5173 *lutState = NvKmsLUTStatePQ;
5174 *lutSize = numOetfPQ512Entries + 1;
5175 *isLutModeVss = TRUE;
5176 }
5177
EvoSetupIdentityOutputLutC5(NVEvoLutDataRec * pData,enum NvKmsLUTState * lutState,NvU32 * lutSize,NvBool * isLutModeVss)5178 static void EvoSetupIdentityOutputLutC5(NVEvoLutDataRec *pData,
5179 enum NvKmsLUTState *lutState,
5180 NvU32 *lutSize,
5181 NvBool *isLutModeVss)
5182 {
5183 NvU32 i;
5184
5185 // Skip LUT data init if already done
5186 if (*lutState == NvKmsLUTStateIdentity) {
5187 goto skipInit;
5188 }
5189
5190 ct_assert(NV_NUM_EVO_LUT_ENTRIES == 1025);
5191
5192 // nvdisplay 3 uses 16-bit fixed-point entries in the OLUT.
5193 for (i = 0; i < 1024; i++) {
5194 pData->output[NV_LUT_VSS_HEADER_SIZE + i].Red =
5195 pData->output[NV_LUT_VSS_HEADER_SIZE + i].Green =
5196 pData->output[NV_LUT_VSS_HEADER_SIZE + i].Blue = (i << (16 - 10));
5197 }
5198 pData->output[NV_LUT_VSS_HEADER_SIZE + 1024] =
5199 pData->output[NV_LUT_VSS_HEADER_SIZE + 1023];
5200
5201 skipInit:
5202 *lutState = NvKmsLUTStateIdentity;
5203 *lutSize = 1025;
5204 *isLutModeVss = FALSE;
5205 }
5206
SetupHDROutputLUT(NVDevEvoPtr pDevEvo,const NVDispHeadStateEvoRec * pHeadState,NvU32 sd,enum NvKmsLUTState * lutState,NvU32 * lutSize,NvBool * isLutModeVss)5207 static void SetupHDROutputLUT(NVDevEvoPtr pDevEvo,
5208 const NVDispHeadStateEvoRec *pHeadState,
5209 NvU32 sd,
5210 enum NvKmsLUTState *lutState,
5211 NvU32 *lutSize,
5212 NvBool *isLutModeVss)
5213 {
5214 NVLutSurfaceEvoPtr pLut = pDevEvo->lut.defaultLut;
5215 NVEvoLutDataRec *pData = pLut->subDeviceAddress[sd];
5216
5217 // XXX HDR TODO: Support other transfer functions
5218 nvAssert(pHeadState->tf == NVKMS_OUTPUT_TF_PQ);
5219
5220 EvoSetupPQOetfOutputLutC5(pData, lutState, lutSize, isLutModeVss);
5221 }
5222
nvSetupOutputLUT5(NVDevEvoPtr pDevEvo,const NVDispHeadStateEvoRec * pHeadState,const int head,NVLutSurfaceEvoPtr pLutSurfEvo,NvBool enableBaseLut,NvBool enableOutputLut,NVEvoUpdateState * updateState,NvBool bypassComposition,NVSurfaceDescriptor ** pSurfaceDesc,NvU32 * lutSize,NvBool * disableOcsc0,NvU32 * fpNormScale,NvBool * isLutModeVss)5223 void nvSetupOutputLUT5(NVDevEvoPtr pDevEvo,
5224 const NVDispHeadStateEvoRec *pHeadState,
5225 const int head,
5226 NVLutSurfaceEvoPtr pLutSurfEvo,
5227 NvBool enableBaseLut,
5228 NvBool enableOutputLut,
5229 NVEvoUpdateState *updateState,
5230 NvBool bypassComposition,
5231 NVSurfaceDescriptor **pSurfaceDesc,
5232 NvU32 *lutSize,
5233 NvBool *disableOcsc0,
5234 NvU32 *fpNormScale,
5235 NvBool *isLutModeVss)
5236 {
5237 NvU32 sd;
5238
5239 EvoSetLUTContextDma3(pDevEvo,
5240 head,
5241 pLutSurfEvo,
5242 enableBaseLut,
5243 updateState,
5244 bypassComposition);
5245
5246 /* Set the ctxdma for the output LUT */
5247
5248 if (bypassComposition) {
5249 *pSurfaceDesc = NULL;
5250
5251 /* if we're not enabling the OLUT, OCSC0 also needs to be disabled */
5252 *disableOcsc0 = TRUE;
5253 } else if (!enableOutputLut) {
5254 /* Use the default OLUT if the client didn't provide one */
5255 *pSurfaceDesc = &pDevEvo->lut.defaultLut->surfaceDesc;
5256
5257 // Setup default OLUT
5258 for (sd = 0; sd < pDevEvo->numSubDevices; sd++) {
5259 // XXX HDR TODO: Support other transfer functions
5260 if (pHeadState->tf == NVKMS_OUTPUT_TF_PQ) {
5261 SetupHDROutputLUT(pDevEvo, pHeadState, sd,
5262 &pDevEvo->lut.defaultOutputLUTState[sd],
5263 lutSize, isLutModeVss);
5264
5265 *disableOcsc0 = TRUE;
5266
5267 /*
5268 * Scale from [0.0, 125.0] to [0.0, 1.0]
5269 * XXX HDR TODO: Assumes input is in this range, SDR is not.
5270 */
5271 *fpNormScale = 0xFFFFFFFF / 125;
5272 } else {
5273 NVLutSurfaceEvoPtr pLut = pDevEvo->lut.defaultLut;
5274 NVEvoLutDataRec *pData = pLut->subDeviceAddress[sd];
5275
5276 EvoSetupIdentityOutputLutC5(
5277 pData,
5278 &pDevEvo->lut.defaultOutputLUTState[sd],
5279 lutSize, isLutModeVss);
5280 }
5281 }
5282 }
5283 }
5284
SetOLUTSurfaceAddress(NVEvoChannelPtr pChannel,const NVSurfaceDescriptor * pSurfaceDesc,NvU32 offset,NvU32 head)5285 static void SetOLUTSurfaceAddress(
5286 NVEvoChannelPtr pChannel,
5287 const NVSurfaceDescriptor *pSurfaceDesc,
5288 NvU32 offset,
5289 NvU32 head)
5290 {
5291 NvU32 ctxDmaHandle = pSurfaceDesc ? pSurfaceDesc->ctxDmaHandle : 0;
5292
5293 nvDmaSetStartEvoMethod(pChannel, NVC57D_HEAD_SET_CONTEXT_DMA_OLUT(head), 1);
5294 nvDmaSetEvoMethodData(pChannel,
5295 DRF_NUM(C57D, _HEAD_SET_CONTEXT_DMA_OLUT, _HANDLE, ctxDmaHandle));
5296
5297 nvDmaSetStartEvoMethod(pChannel, NVC57D_HEAD_SET_OFFSET_OLUT(head), 1);
5298 nvDmaSetEvoMethodData(pChannel,
5299 DRF_NUM(C57D, _HEAD_SET_OFFSET_OLUT, _ORIGIN, offset >> 8));
5300 }
5301
EvoSetLUTContextDmaC5(const NVDispEvoRec * pDispEvo,const int head,NVLutSurfaceEvoPtr pLutSurfEvo,NvBool enableBaseLut,NvBool enableOutputLut,NVEvoUpdateState * updateState,NvBool bypassComposition)5302 static void EvoSetLUTContextDmaC5(const NVDispEvoRec *pDispEvo,
5303 const int head,
5304 NVLutSurfaceEvoPtr pLutSurfEvo,
5305 NvBool enableBaseLut,
5306 NvBool enableOutputLut,
5307 NVEvoUpdateState *updateState,
5308 NvBool bypassComposition)
5309 {
5310 NVSurfaceDescriptor *pSurfaceDesc =
5311 (pLutSurfEvo != NULL) ? &pLutSurfEvo->surfaceDesc : NULL;
5312 NVDevEvoPtr pDevEvo = pDispEvo->pDevEvo;
5313 NVEvoChannelPtr pChannel = pDevEvo->core;
5314 NvU64 offset;
5315 NvU32 lutSize = NV_NUM_EVO_LUT_ENTRIES;
5316 NvBool isLutModeVss = FALSE;
5317 const NVDispHeadStateEvoRec *pHeadState = &pDispEvo->headState[head];
5318 NvBool disableOcsc0 = FALSE;
5319 NvU32 fpNormScale = 0xFFFFFFFF;
5320
5321 // XXX HDR TODO: Enable custom output LUTs with HDR
5322 // XXX HDR TODO: Support other transfer functions
5323 if (pHeadState->tf == NVKMS_OUTPUT_TF_PQ) {
5324 enableOutputLut = FALSE;
5325 }
5326
5327 nvAssert(pSurfaceDesc || (!enableBaseLut && !enableOutputLut));
5328
5329 nvPushEvoSubDevMaskDisp(pDispEvo);
5330
5331 nvSetupOutputLUT5(pDevEvo,
5332 pHeadState,
5333 head,
5334 pLutSurfEvo,
5335 enableBaseLut,
5336 enableOutputLut,
5337 updateState,
5338 bypassComposition,
5339 &pSurfaceDesc,
5340 &lutSize,
5341 &disableOcsc0,
5342 &fpNormScale,
5343 &isLutModeVss);
5344
5345 if (disableOcsc0) {
5346 nvDmaSetStartEvoMethod(pChannel, NVC57D_HEAD_SET_OCSC0CONTROL(head), 1);
5347 nvDmaSetEvoMethodData(pChannel, DRF_DEF(C57D, _HEAD_SET_OCSC0CONTROL, _ENABLE, _DISABLE));
5348 }
5349
5350 /* Program the output LUT */
5351
5352 offset = offsetof(NVEvoLutDataRec, output);
5353 nvAssert((offset & 0xff) == 0);
5354
5355 nvDmaSetStartEvoMethod(pChannel, NVC57D_HEAD_SET_OLUT_CONTROL(head), 1);
5356 nvDmaSetEvoMethodData(pChannel,
5357 ((isLutModeVss || !nvkms_output_rounding_fix()) ?
5358 DRF_DEF(C57D, _HEAD_SET_OLUT_CONTROL, _INTERPOLATE, _ENABLE) :
5359 DRF_DEF(C57D, _HEAD_SET_OLUT_CONTROL, _INTERPOLATE, _DISABLE)) |
5360 DRF_DEF(C57D, _HEAD_SET_OLUT_CONTROL, _MIRROR, _DISABLE) |
5361 (isLutModeVss ? DRF_DEF(C57D, _HEAD_SET_OLUT_CONTROL, _MODE, _SEGMENTED) :
5362 DRF_DEF(C57D, _HEAD_SET_OLUT_CONTROL, _MODE, _DIRECT10)) |
5363 DRF_NUM(C57D, _HEAD_SET_OLUT_CONTROL, _SIZE, NV_LUT_VSS_HEADER_SIZE +
5364 lutSize));
5365
5366 SetOLUTSurfaceAddress(pChannel, pSurfaceDesc, offset, head);
5367
5368 nvDmaSetStartEvoMethod(pChannel, NVC57D_HEAD_SET_OLUT_FP_NORM_SCALE(head), 1);
5369 nvDmaSetEvoMethodData(pChannel, fpNormScale);
5370
5371 if (!disableOcsc0) {
5372 /* only enable OCSC0 after enabling the OLUT */
5373 nvDmaSetStartEvoMethod(pChannel, NVC57D_HEAD_SET_OCSC0CONTROL(head), 1);
5374 nvDmaSetEvoMethodData(pChannel, DRF_DEF(C57D, _HEAD_SET_OCSC0CONTROL, _ENABLE, _ENABLE));
5375 }
5376
5377 nvPopEvoSubDevMask(pDevEvo);
5378 }
5379
ReadCapReg(volatile const NvU32 * pCaps,NvU32 offset)5380 static inline NvU32 ReadCapReg(volatile const NvU32 *pCaps, NvU32 offset)
5381 {
5382 /* Offsets are in bytes, but the array has dword-sized elements. */
5383 return pCaps[offset / sizeof(NvU32)];
5384 }
5385
QueryStereoPinC3(NVDevEvoPtr pDevEvo,NVEvoSubDevPtr pEvoSubDev,NvU32 * pStereoPin)5386 static NvBool QueryStereoPinC3(NVDevEvoPtr pDevEvo,
5387 NVEvoSubDevPtr pEvoSubDev,
5388 NvU32 *pStereoPin)
5389 {
5390 NVC370_CTRL_GET_LOCKPINS_CAPS_PARAMS params = { };
5391
5392 params.base.subdeviceIndex = pEvoSubDev->subDeviceInstance;
5393
5394 if (nvRmApiControl(nvEvoGlobal.clientHandle,
5395 pDevEvo->displayHandle,
5396 NVC370_CTRL_CMD_GET_LOCKPINS_CAPS,
5397 ¶ms, sizeof(params)) != NVOS_STATUS_SUCCESS) {
5398 nvEvoLogDevDebug(pDevEvo, EVO_LOG_ERROR,
5399 "Failed to query stereo pin");
5400 return FALSE;
5401 }
5402
5403 if ((params.stereoPin >= NV_EVO_NUM_LOCK_PIN_CAPS) ||
5404 (params.stereoPin == NVC370_CTRL_GET_LOCKPINS_CAPS_STEREO_PIN_NONE)) {
5405 return FALSE;
5406 } else {
5407 *pStereoPin = params.stereoPin;
5408 return TRUE;
5409 }
5410 }
5411
EvoParseCapabilityNotifier3(NVDevEvoPtr pDevEvo,NVEvoSubDevPtr pEvoSubDev,volatile const NvU32 * pCaps)5412 static void EvoParseCapabilityNotifier3(NVDevEvoPtr pDevEvo,
5413 NVEvoSubDevPtr pEvoSubDev,
5414 volatile const NvU32 *pCaps)
5415 {
5416 NVEvoCapabilitiesPtr pEvoCaps = &pEvoSubDev->capabilities;
5417 const NvU32 sysCap = ReadCapReg(pCaps, NVC373_SYS_CAP);
5418 const NvU32 sysCapB = ReadCapReg(pCaps, NVC373_SYS_CAPB);
5419 NvU32 i, stereoPin;
5420 NvU32 layer;
5421
5422 pDevEvo->caps.cursorCompositionCaps =
5423 (struct NvKmsCompositionCapabilities) {
5424 .supportedColorKeySelects =
5425 NVBIT(NVKMS_COMPOSITION_COLOR_KEY_SELECT_DISABLE),
5426
5427 .colorKeySelect = {
5428 [NVKMS_COMPOSITION_COLOR_KEY_SELECT_DISABLE] = {
5429 .supportedBlendModes = {
5430 [1] = NV_EVO3_SUPPORTED_CURSOR_COMP_BLEND_MODES,
5431 },
5432 },
5433 }
5434 };
5435
5436 for (layer = 0;
5437 layer < ARRAY_LEN(pDevEvo->caps.layerCaps); layer++) {
5438 pDevEvo->caps.layerCaps[layer].composition =
5439 (struct NvKmsCompositionCapabilities) {
5440 .supportedColorKeySelects =
5441 NVBIT(NVKMS_COMPOSITION_COLOR_KEY_SELECT_DISABLE) |
5442 NVBIT(NVKMS_COMPOSITION_COLOR_KEY_SELECT_SRC) |
5443 NVBIT(NVKMS_COMPOSITION_COLOR_KEY_SELECT_DST),
5444
5445 .colorKeySelect = {
5446 [NVKMS_COMPOSITION_COLOR_KEY_SELECT_DISABLE] = {
5447 .supportedBlendModes = {
5448 [1] = NV_EVO3_SUPPORTED_WINDOW_COMP_BLEND_MODES,
5449 },
5450 },
5451
5452 [NVKMS_COMPOSITION_COLOR_KEY_SELECT_SRC] = {
5453 .supportedBlendModes = {
5454 [0] = NV_EVO3_SUPPORTED_WINDOW_COMP_BLEND_MODES,
5455 [1] = NV_EVO3_SUPPORTED_WINDOW_COMP_BLEND_MODES,
5456 },
5457 },
5458
5459 [NVKMS_COMPOSITION_COLOR_KEY_SELECT_DST] = {
5460 .supportedBlendModes = {
5461 [0] = NV_EVO3_SUPPORTED_WINDOW_COMP_BLEND_MODES,
5462 [1] = NV_EVO3_SUPPORTED_WINDOW_COMP_BLEND_MODES,
5463 },
5464 },
5465 },
5466 };
5467 }
5468
5469 /*
5470 * Previous EVO display implementations exposed capabilities for lock pins,
5471 * detailing which pin(s) could be used for which functions. The idea was
5472 * that it didn't make sense to try to drive a stereo pin with a fliplock
5473 * signal (for example), so the pin associated with the stereo function was
5474 * marked as stereo-capable but not any other function; attempting to use a
5475 * non-stereo-capable pin for stereo or vice-versa would result in an error.
5476 *
5477 * With nvdisplay, the meaning of lock pins was changed such that they no
5478 * longer have a shared namespace. So stereo lockpin 0 is not the same as
5479 * fliplock lockpin 0 and neither is the same as scanlock lockpin 0. With
5480 * this scheme, there is no way to specify a pin that is incapable of a
5481 * given function, so the entire capabilities mechanism was removed.
5482 *
5483 * However, the pins chosen for HEAD_SET_CONTROL still need to match the
5484 * pins selected for each function in the VBIOS DCB. Fliplock and scanlock
5485 * query this information through
5486 * NV5070_CTRL_CMD_GET_FRAMELOCK_HEADER_LOCKPINS. Stereo is handled
5487 * here, using NVC370_CTRL_CMD_GET_LOCKPINS_CAPS.
5488 */
5489
5490 for (i = 0; i < NV_EVO_NUM_LOCK_PIN_CAPS; i++) {
5491 pEvoCaps->pin[i].flipLock = TRUE;
5492 pEvoCaps->pin[i].scanLock = TRUE;
5493 }
5494
5495 if (QueryStereoPinC3(pDevEvo, pEvoSubDev, &stereoPin)) {
5496 pEvoCaps->pin[stereoPin].stereo = TRUE;
5497 }
5498
5499 // Miscellaneous capabilities
5500 // NVDisplay does not support interlaced modes.
5501 pEvoCaps->misc.supportsInterlaced = FALSE;
5502
5503 /* XXX temporary WAR; see bug 4028718 */
5504 #if !defined(NVC373_HEAD_CLK_CAP)
5505 #define NVC373_HEAD_CLK_CAP(i) (0x5e8+(i)*4) /* RW-4A */
5506 #define NVC373_HEAD_CLK_CAP__SIZE_1 8 /* */
5507 #define NVC373_HEAD_CLK_CAP_PCLK_MAX 7:0 /* RWIUF */
5508 #define NVC373_HEAD_CLK_CAP_PCLK_MAX_INIT 0x00000085 /* RWI-V */
5509 #endif
5510
5511 // Heads
5512 ct_assert(ARRAY_LEN(pEvoCaps->head) >= NVC373_HEAD_CAPA__SIZE_1);
5513 for (i = 0; i < NVC373_HEAD_CAPA__SIZE_1; i++) {
5514 NVEvoHeadCaps *pHeadCaps = &pEvoCaps->head[i];
5515
5516 pHeadCaps->usable =
5517 FLD_IDX_TEST_DRF(C373, _SYS_CAP, _HEAD_EXISTS, i, _YES, sysCap);
5518 if (pHeadCaps->usable) {
5519 pHeadCaps->maxPClkKHz =
5520 DRF_VAL(C373, _HEAD_CLK_CAP, _PCLK_MAX,
5521 ReadCapReg(pCaps, NVC373_HEAD_CLK_CAP(i))) * 10000;
5522 }
5523
5524 }
5525
5526 // SORs
5527 ct_assert(ARRAY_LEN(pEvoCaps->sor) >= NVC373_SOR_CAP__SIZE_1);
5528 for (i = 0; i < NVC373_SOR_CAP__SIZE_1; i++) {
5529 NVEvoSorCaps *pSorCaps = &pEvoCaps->sor[i];
5530
5531 NvBool sorUsable =
5532 FLD_IDX_TEST_DRF(C373, _SYS_CAP, _SOR_EXISTS, i, _YES, sysCap);
5533
5534 /* XXXnvdisplay: add SOR caps: max DP clk, ... */
5535 if (sorUsable) {
5536 const NvU32 sorCap = ReadCapReg(pCaps, NVC373_SOR_CAP(i));
5537 pSorCaps->dualTMDS =
5538 FLD_TEST_DRF(C373, _SOR_CAP, _DUAL_TMDS, _TRUE, sorCap);
5539
5540 /*
5541 * Assume that all SORs are equally capable, and that all SORs
5542 * support HDMI FRL if the display class supports it. (If this
5543 * assert fires, we may need to rework SOR assignment for such HDMI
5544 * sinks.)
5545 *
5546 * Although HDMI_FRL is only defined for class C6, classes C3 and
5547 * C5 don't use that bit in the SOR_CAP register so it should
5548 * always be 0 on those chips.
5549 */
5550 nvAssert(!!FLD_TEST_DRF(C673, _SOR_CAP, _HDMI_FRL, _TRUE, sorCap) ==
5551 !!pDevEvo->hal->caps.supportsHDMIFRL);
5552
5553 pSorCaps->maxTMDSClkKHz =
5554 DRF_VAL(C373, _SOR_CLK_CAP, _TMDS_MAX,
5555 ReadCapReg(pCaps, NVC373_SOR_CLK_CAP(i))) * 10000;
5556 }
5557 }
5558
5559 // Don't need any PIOR caps currently.
5560
5561 // Windows
5562 ct_assert(ARRAY_LEN(pEvoCaps->window) >= NVC373_SYS_CAPB_WINDOW_EXISTS__SIZE_1);
5563 for (i = 0; i < NVC373_SYS_CAPB_WINDOW_EXISTS__SIZE_1; i++) {
5564 NVEvoWindowCaps *pWinCaps = &pEvoCaps->window[i];
5565
5566 pWinCaps->usable =
5567 FLD_IDX_TEST_DRF(C373, _SYS_CAPB, _WINDOW_EXISTS, i, _YES, sysCapB);
5568 }
5569 }
5570
EvoParseCapabilityNotifierC3(NVDevEvoPtr pDevEvo,NVEvoSubDevPtr pEvoSubDev,volatile const NvU32 * pCaps)5571 static void EvoParseCapabilityNotifierC3(NVDevEvoPtr pDevEvo,
5572 NVEvoSubDevPtr pEvoSubDev,
5573 volatile const NvU32 *pCaps)
5574 {
5575 NVEvoCapabilitiesPtr pEvoCaps = &pEvoSubDev->capabilities;
5576 NvU32 i;
5577
5578 // Miscellaneous capabilities
5579 pEvoCaps->misc.supportsSemiPlanar = FALSE;
5580 pEvoCaps->misc.supportsPlanar = FALSE;
5581 pEvoCaps->misc.supportsDSI = FALSE;
5582
5583 // Heads
5584 ct_assert(ARRAY_LEN(pEvoCaps->head) >= NVC373_HEAD_CAPA__SIZE_1);
5585 for (i = 0; i < NVC373_HEAD_CAPA__SIZE_1; i++) {
5586 NVEvoHeadCaps *pHeadCaps = &pEvoCaps->head[i];
5587
5588 /* XXXnvdisplay: add caps for hsat, ocsc, lut */
5589 if (pHeadCaps->usable) {
5590 NVEvoScalerCaps *pScalerCaps = &pHeadCaps->scalerCaps;
5591
5592 pScalerCaps->present =
5593 FLD_TEST_DRF(C373, _HEAD_CAPA, _SCALER, _TRUE,
5594 ReadCapReg(pCaps, NVC373_HEAD_CAPA(i)));
5595 if (pScalerCaps->present) {
5596 NVEvoScalerTapsCaps *pTapsCaps;
5597 NvU32 tmp;
5598
5599 /*
5600 * Note that some of these may be zero (e.g., only 2-tap 444
5601 * mode is supported on GV100, so the rest are all zero.
5602 *
5603 * Downscaling by more than 2x in either direction is not
5604 * allowed by state error check for both horizontal and
5605 * vertical 2-tap scaling.
5606 *
5607 * Downscaling by more than 4x in either direction is not
5608 * allowed by argument error check (and state error check) for
5609 * 5-tap scaling.
5610 *
5611 * 5-tap scaling is not implemented on GV100, though, so we
5612 * should never see numTaps == 5 on GV100, and we can just use a
5613 * max of 2 here all the time.
5614 */
5615
5616 /* 2-tap capabilities */
5617 tmp = ReadCapReg(pCaps, NVC373_HEAD_CAPD(i));
5618 pTapsCaps = &pScalerCaps->taps[NV_EVO_SCALER_2TAPS];
5619 pTapsCaps->maxVDownscaleFactor = NV_EVO_SCALE_FACTOR_2X;
5620 pTapsCaps->maxHDownscaleFactor = NV_EVO_SCALE_FACTOR_2X;
5621 pTapsCaps->maxPixelsVTaps =
5622 NV_MAX(DRF_VAL(C373, _HEAD_CAPD, _MAX_PIXELS_2TAP422, tmp),
5623 DRF_VAL(C373, _HEAD_CAPD, _MAX_PIXELS_2TAP444, tmp));
5624
5625 /*
5626 * Note that there is a capability register for 1TAP, but there
5627 * doesn't appear to be a way to select 1-tap scaling in the
5628 * channel methods, so don't bother reading it for now.
5629 */
5630 }
5631 }
5632 }
5633 }
5634
EvoParsePrecompScalerCaps5(NVEvoCapabilitiesPtr pEvoCaps,volatile const NvU32 * pCaps)5635 static void EvoParsePrecompScalerCaps5(NVEvoCapabilitiesPtr pEvoCaps,
5636 volatile const NvU32 *pCaps)
5637 {
5638 int i;
5639
5640 for (i = 0; i < NVC573_SYS_CAPB_WINDOW_EXISTS__SIZE_1; i++) {
5641 NVEvoWindowCaps *pWinCaps = &pEvoCaps->window[i];
5642 NVEvoScalerCaps *pScalerCaps = &pWinCaps->scalerCaps;
5643 NVEvoScalerTapsCaps *pTapsCaps;
5644 NvU32 capA = ReadCapReg(pCaps, NVC573_PRECOMP_WIN_PIPE_HDR_CAPA(i));
5645 NvU32 capD, capF;
5646
5647 pScalerCaps->present =
5648 FLD_TEST_DRF(C573, _PRECOMP_WIN_PIPE_HDR_CAPA, _SCLR_PRESENT,
5649 _TRUE, capA);
5650 if (pScalerCaps->present) {
5651 capD = ReadCapReg(pCaps, NVC573_PRECOMP_WIN_PIPE_HDR_CAPD(i));
5652 capF = ReadCapReg(pCaps, NVC573_PRECOMP_WIN_PIPE_HDR_CAPF(i));
5653
5654 /* 5-tap capabilities */
5655 pTapsCaps = &pScalerCaps->taps[NV_EVO_SCALER_5TAPS];
5656 if (FLD_TEST_DRF(C573, _PRECOMP_WIN_PIPE_HDR_CAPD,
5657 _SCLR_VS_MAX_SCALE_FACTOR, _4X, capD)) {
5658 pTapsCaps->maxVDownscaleFactor = NV_EVO_SCALE_FACTOR_4X;
5659 } else {
5660 pTapsCaps->maxVDownscaleFactor = NV_EVO_SCALE_FACTOR_2X;
5661 }
5662
5663 if (FLD_TEST_DRF(C573, _PRECOMP_WIN_PIPE_HDR_CAPD,
5664 _SCLR_HS_MAX_SCALE_FACTOR, _4X, capD)) {
5665 pTapsCaps->maxHDownscaleFactor = NV_EVO_SCALE_FACTOR_4X;
5666 } else {
5667 pTapsCaps->maxHDownscaleFactor = NV_EVO_SCALE_FACTOR_2X;
5668 }
5669
5670 pTapsCaps->maxPixelsVTaps =
5671 DRF_VAL(C573, _PRECOMP_WIN_PIPE_HDR_CAPF,
5672 _VSCLR_MAX_PIXELS_5TAP, capF);
5673
5674 /* 2-tap capabilities */
5675 pTapsCaps = &pScalerCaps->taps[NV_EVO_SCALER_2TAPS];
5676 pTapsCaps->maxVDownscaleFactor = NV_EVO_SCALE_FACTOR_2X;
5677 pTapsCaps->maxHDownscaleFactor = NV_EVO_SCALE_FACTOR_2X;
5678 pTapsCaps->maxPixelsVTaps =
5679 DRF_VAL(C573, _PRECOMP_WIN_PIPE_HDR_CAPF, _VSCLR_MAX_PIXELS_2TAP,
5680 capF);
5681 }
5682 }
5683 }
5684
EvoParseCapabilityNotifierC5C6Common(NVEvoCapabilitiesPtr pEvoCaps,volatile const NvU32 * pCaps)5685 static void EvoParseCapabilityNotifierC5C6Common(NVEvoCapabilitiesPtr pEvoCaps,
5686 volatile const NvU32 *pCaps)
5687 {
5688 NvU32 i;
5689 NvBool postcompScalingSupported = FALSE;
5690
5691 // Heads
5692 ct_assert(ARRAY_LEN(pEvoCaps->head) >= NVC573_SYS_CAP_HEAD_EXISTS__SIZE_1);
5693 for (i = 0; i < NVC573_SYS_CAP_HEAD_EXISTS__SIZE_1; i++) {
5694 NVEvoHeadCaps *pHeadCaps = &pEvoCaps->head[i];
5695
5696 if (pHeadCaps->usable) {
5697 NVEvoScalerCaps *pScalerCaps = &pHeadCaps->scalerCaps;
5698 NVEvoScalerTapsCaps *pTapsCaps;
5699 NvU32 capA = ReadCapReg(pCaps, NVC573_POSTCOMP_HEAD_HDR_CAPA(i));
5700 NvU32 capC, capD;
5701
5702 pScalerCaps->present =
5703 FLD_TEST_DRF(C573, _POSTCOMP_HEAD_HDR_CAPA, _SCLR_PRESENT,
5704 _TRUE, capA);
5705 if (pScalerCaps->present) {
5706 postcompScalingSupported = TRUE;
5707
5708 capC = ReadCapReg(pCaps, NVC573_POSTCOMP_HEAD_HDR_CAPC(i));
5709 capD = ReadCapReg(pCaps, NVC573_POSTCOMP_HEAD_HDR_CAPD(i));
5710
5711 /*
5712 * Note that some of these may be zero.
5713 *
5714 * XXXnvdisplay: what about POSTCOMP_HEAD_HDR_CAPC_SCLR_*?
5715 */
5716
5717 /* 5-tap capabilities */
5718 pTapsCaps = &pScalerCaps->taps[NV_EVO_SCALER_5TAPS];
5719 if (FLD_TEST_DRF(C573, _POSTCOMP_HEAD_HDR_CAPC,
5720 _SCLR_VS_MAX_SCALE_FACTOR, _4X, capC)) {
5721 pTapsCaps->maxVDownscaleFactor = NV_EVO_SCALE_FACTOR_4X;
5722 } else {
5723 pTapsCaps->maxVDownscaleFactor = NV_EVO_SCALE_FACTOR_2X;
5724 }
5725
5726 if (FLD_TEST_DRF(C573, _POSTCOMP_HEAD_HDR_CAPC,
5727 _SCLR_HS_MAX_SCALE_FACTOR, _4X, capC)) {
5728 pTapsCaps->maxHDownscaleFactor = NV_EVO_SCALE_FACTOR_4X;
5729 } else {
5730 pTapsCaps->maxHDownscaleFactor = NV_EVO_SCALE_FACTOR_2X;
5731 }
5732
5733 pTapsCaps->maxPixelsVTaps =
5734 DRF_VAL(C573, _POSTCOMP_HEAD_HDR_CAPD,
5735 _VSCLR_MAX_PIXELS_5TAP, capD);
5736
5737 /* 2-tap capabilities */
5738 pTapsCaps = &pScalerCaps->taps[NV_EVO_SCALER_2TAPS];
5739 pTapsCaps->maxVDownscaleFactor = NV_EVO_SCALE_FACTOR_2X;
5740 pTapsCaps->maxHDownscaleFactor = NV_EVO_SCALE_FACTOR_2X;
5741 pTapsCaps->maxPixelsVTaps =
5742 DRF_VAL(C573, _POSTCOMP_HEAD_HDR_CAPD,
5743 _VSCLR_MAX_PIXELS_2TAP, capD);
5744 }
5745
5746 #if defined(NV_DEBUG)
5747 NvU32 capA = ReadCapReg(pCaps, NVC573_POSTCOMP_HEAD_HDR_CAPA(i));
5748 NvU32 unitWidth = DRF_VAL(C573, _POSTCOMP_HEAD_HDR_CAPA, _UNIT_WIDTH, capA);
5749
5750 // EvoInitChannelC5 assumes 16-bit fixed-point.
5751 nvAssert(unitWidth == 16);
5752 #endif
5753 }
5754 }
5755
5756 for (i = 0; i < NVC573_SYS_CAPB_WINDOW_EXISTS__SIZE_1; i++) {
5757 NVEvoWindowCaps *pWinCaps = &pEvoCaps->window[i];
5758 NvU32 capA = ReadCapReg(pCaps, NVC573_PRECOMP_WIN_PIPE_HDR_CAPA(i));
5759
5760 pWinCaps->tmoPresent = FLD_TEST_DRF(C573, _PRECOMP_WIN_PIPE_HDR_CAPA,
5761 _TMO_PRESENT, _TRUE, capA);
5762
5763 pWinCaps->csc0MatricesPresent =
5764 FLD_TEST_DRF(C573, _PRECOMP_WIN_PIPE_HDR_CAPA,
5765 _CSC00_PRESENT, _TRUE, capA) &&
5766 FLD_TEST_DRF(C573, _PRECOMP_WIN_PIPE_HDR_CAPA,
5767 _CSC01_PRESENT, _TRUE, capA);
5768
5769 pWinCaps->csc1MatricesPresent =
5770 (FLD_TEST_DRF(C573, _PRECOMP_WIN_PIPE_HDR_CAPA,
5771 _CSC10_PRESENT, _TRUE, capA) &&
5772 FLD_TEST_DRF(C573, _PRECOMP_WIN_PIPE_HDR_CAPA,
5773 _CSC11_PRESENT, _TRUE, capA));
5774
5775 pWinCaps->cscLUTsPresent =
5776 FLD_TEST_DRF(C573, _PRECOMP_WIN_PIPE_HDR_CAPA,
5777 _CSC0LUT_PRESENT, _TRUE, capA) &&
5778 FLD_TEST_DRF(C573, _PRECOMP_WIN_PIPE_HDR_CAPA,
5779 _CSC1LUT_PRESENT, _TRUE, capA);
5780
5781 nvAssert(!pWinCaps->tmoPresent ||
5782 (pWinCaps->csc0MatricesPresent &&
5783 pWinCaps->csc1MatricesPresent &&
5784 pWinCaps->cscLUTsPresent));
5785 }
5786
5787 /*
5788 * To keep the design simple, NVKMS will expose support for precomp scaling
5789 * iff postcomp scaling isn't supported. This means that on chips which have
5790 * both precomp and postcomp scalers (e.g., Turing), NVKMS will only report
5791 * that postcomp scaling is supported.
5792 */
5793 if (!postcompScalingSupported) {
5794 EvoParsePrecompScalerCaps5(pEvoCaps, pCaps);
5795 }
5796
5797 // XXXnvdisplay3: add SOR caps for DP over USB
5798 }
5799
EvoParseCapabilityNotifierC5(NVDevEvoPtr pDevEvo,NVEvoSubDevPtr pEvoSubDev,volatile const NvU32 * pCaps)5800 static void EvoParseCapabilityNotifierC5(NVDevEvoPtr pDevEvo,
5801 NVEvoSubDevPtr pEvoSubDev,
5802 volatile const NvU32 *pCaps)
5803 {
5804 NVEvoCapabilitiesPtr pEvoCaps = &pEvoSubDev->capabilities;
5805
5806 // Miscellaneous capabilities
5807
5808 /*
5809 * On Turing, the NVC573_IHUB_COMMON_CAPA_SUPPORT_PLANAR bit actually
5810 * reports whether IHUB supports YUV _semi-planar_ formats.
5811 */
5812 pEvoCaps->misc.supportsSemiPlanar =
5813 FLD_TEST_DRF(C573, _IHUB_COMMON_CAPA, _SUPPORT_PLANAR, _TRUE,
5814 ReadCapReg(pCaps, NVC573_IHUB_COMMON_CAPA));
5815 pEvoCaps->misc.supportsDSI = FALSE;
5816
5817 EvoParseCapabilityNotifierC5C6Common(pEvoCaps, pCaps);
5818 }
5819
EvoParseCapabilityNotifierC6(NVDevEvoPtr pDevEvo,NVEvoSubDevPtr pEvoSubDev,volatile const NvU32 * pCaps)5820 static void EvoParseCapabilityNotifierC6(NVDevEvoPtr pDevEvo,
5821 NVEvoSubDevPtr pEvoSubDev,
5822 volatile const NvU32 *pCaps)
5823 {
5824 NVEvoCapabilitiesPtr pEvoCaps = &pEvoSubDev->capabilities;
5825 NvU32 capC = ReadCapReg(pCaps, NVC673_IHUB_COMMON_CAPC);
5826 NvU32 i;
5827
5828 // Miscellaneous capabilities
5829
5830 pEvoCaps->misc.supportsPlanar =
5831 FLD_TEST_DRF(C673, _IHUB_COMMON_CAPA, _SUPPORT_PLANAR, _TRUE,
5832 ReadCapReg(pCaps, NVC673_IHUB_COMMON_CAPA));
5833
5834 pEvoCaps->misc.supportsSemiPlanar =
5835 FLD_TEST_DRF(C673, _IHUB_COMMON_CAPC, _SUPPORT_SEMI_PLANAR, _TRUE, capC);
5836
5837 pEvoCaps->misc.supportsHVFlip =
5838 FLD_TEST_DRF(C673, _IHUB_COMMON_CAPC, _SUPPORT_HOR_VER_FLIP, _TRUE, capC);
5839
5840 ct_assert(ARRAY_LEN(pEvoCaps->head) >= NVC673_SYS_CAP_HEAD_EXISTS__SIZE_1);
5841
5842 // DSI is currently supported on just Orin, which has only 1 DSI engine (DSI0).
5843 pEvoCaps->misc.supportsDSI =
5844 FLD_TEST_DRF(C673, _SYS_CAP, _DSI0_EXISTS, _YES,
5845 ReadCapReg(pCaps, NVC673_SYS_CAP));
5846
5847 for (i = 0; i < NVC673_SYS_CAP_HEAD_EXISTS__SIZE_1; i++) {
5848 NVEvoHeadCaps *pHeadCaps = &pEvoCaps->head[i];
5849
5850 if (pHeadCaps->usable) {
5851 NvU32 capA = ReadCapReg(pCaps, NVC673_POSTCOMP_HEAD_HDR_CAPA(i));
5852 NvBool hclpfPresent =
5853 FLD_TEST_DRF(C673, _POSTCOMP_HEAD_HDR_CAPA, _HCLPF_PRESENT,
5854 _TRUE, capA);
5855 NvBool vfilterPresent =
5856 FLD_TEST_DRF(C673, _POSTCOMP_HEAD_HDR_CAPA, _VFILTER_PRESENT,
5857 _TRUE, capA);
5858
5859 pHeadCaps->supportsHDMIYUV420HW = hclpfPresent && vfilterPresent;
5860 }
5861 }
5862
5863 EvoParseCapabilityNotifierC5C6Common(pEvoCaps, pCaps);
5864 }
5865
UsableWindowCount(const NVEvoCapabilities * pEvoCaps)5866 static NvU32 UsableWindowCount(const NVEvoCapabilities *pEvoCaps)
5867 {
5868 NvU32 i, count = 0;
5869 NvBool foundUnusable = FALSE;
5870
5871 for (i = 0; i < ARRAY_LEN(pEvoCaps->window); i++) {
5872 if (pEvoCaps->window[i].usable) {
5873 count++;
5874 /* Assert that usable windows are contiguous starting from 0. */
5875 if (foundUnusable) {
5876 nvAssert(!foundUnusable);
5877 }
5878 } else {
5879 foundUnusable = TRUE;
5880 }
5881 }
5882
5883 return count;
5884 }
5885
5886 typedef typeof(EvoParseCapabilityNotifierC3) parse_caps_t;
5887 typedef typeof(nvHwFormatFromKmsFormatC3) get_hw_fmt_t;
5888
SetHDRLayerCaps(NVDevEvoPtr pDevEvo)5889 static void SetHDRLayerCaps(NVDevEvoPtr pDevEvo)
5890 {
5891 NVEvoSubDevPtr pEvoSubDev = &pDevEvo->gpus[0];
5892 NVEvoCapabilitiesPtr pEvoCaps = &pEvoSubDev->capabilities;
5893 NvU32 win;
5894 #if defined(DEBUG)
5895 NvBool hdrLayerCapSet[NVKMS_MAX_LAYERS_PER_HEAD] = {FALSE};
5896 #endif
5897 NvU32 numLayers[NVKMS_MAX_HEADS_PER_DISP] = {0};
5898
5899 /*
5900 * XXX HDR: This assumes the window => layer mapping from
5901 * nvAllocCoreChannelEvo().
5902 *
5903 * TODO: Rework API to explicitly factor in window => layer mapping.
5904 */
5905 for (win = 0; win < pDevEvo->numWindows; win++) {
5906 NVEvoWindowCaps *pWinCaps = &pEvoCaps->window[win];
5907 const NvU32 head = pDevEvo->headForWindow[win];
5908
5909 if (head == NV_INVALID_HEAD) {
5910 continue;
5911 }
5912
5913 /*
5914 * XXX HDR: layerCaps assumes that every head has layers with the
5915 * same capabilities.
5916 *
5917 * TODO: Rework API for per-head layerCaps if this assert trips.
5918 */
5919 nvAssert(!hdrLayerCapSet[numLayers[head]] ||
5920 (pDevEvo->caps.layerCaps[numLayers[head]].supportsHDR ==
5921 pWinCaps->tmoPresent));
5922
5923 pDevEvo->caps.layerCaps[numLayers[head]].supportsHDR = pWinCaps->tmoPresent;
5924
5925 #if defined(DEBUG)
5926 hdrLayerCapSet[numLayers[head]] = TRUE;
5927 #endif
5928
5929 numLayers[head]++;
5930 }
5931 }
5932
EvoGetCapabilities3(NVDevEvoPtr pDevEvo,parse_caps_t * pParse,get_hw_fmt_t * pGetHwFmt,NvU32 hwclass,size_t length)5933 static NvBool EvoGetCapabilities3(NVDevEvoPtr pDevEvo,
5934 parse_caps_t *pParse,
5935 get_hw_fmt_t *pGetHwFmt,
5936 NvU32 hwclass,
5937 size_t length)
5938 {
5939 NvU32 capsHandle = nvGenerateUnixRmHandle(&pDevEvo->handleAllocator);
5940 NVDispEvoPtr pDispEvo;
5941 NvU32 sd;
5942 NvU32 status;
5943 NvBool ret = FALSE;
5944 NvBool first = TRUE;
5945 NvBool supportsSemiPlanar = TRUE;
5946 NvBool supportsPlanar = TRUE;
5947 NvBool supportsHVFlip = TRUE;
5948 unsigned int i;
5949 enum NvKmsRotation curRotation;
5950 NvBool reflectionX;
5951 NvBool reflectionY;
5952 NvU8 layer;
5953
5954 /* With nvdisplay, capabilities are exposed in a separate object. */
5955 status = nvRmApiAlloc(nvEvoGlobal.clientHandle,
5956 pDevEvo->displayHandle,
5957 capsHandle,
5958 hwclass, NULL);
5959 if (status != NVOS_STATUS_SUCCESS) {
5960 nvAssert(!"Failed to allocate caps object");
5961 goto free_handle;
5962 }
5963
5964 for (layer = 0;
5965 layer < ARRAY_LEN(pDevEvo->caps.layerCaps);
5966 layer++) {
5967 pDevEvo->caps.layerCaps[layer].supportsWindowMode = TRUE;
5968 }
5969
5970 FOR_ALL_EVO_DISPLAYS(pDispEvo, sd, pDevEvo) {
5971
5972 NVEvoSubDevPtr pEvoSubDev = &pDevEvo->gpus[sd];
5973 void *ptr;
5974
5975 status = nvRmApiMapMemory(nvEvoGlobal.clientHandle,
5976 pDevEvo->pSubDevices[sd]->handle,
5977 capsHandle,
5978 0,
5979 length,
5980 &ptr,
5981 0);
5982 if (status != NVOS_STATUS_SUCCESS) {
5983 nvAssert(!"Failed to map caps memory");
5984 goto free_object;
5985 }
5986
5987 nvkms_memset(&pEvoSubDev->capabilities, 0,
5988 sizeof(pEvoSubDev->capabilities));
5989
5990 EvoParseCapabilityNotifier3(pDevEvo, pEvoSubDev, ptr);
5991 pParse(pDevEvo, pEvoSubDev, ptr);
5992
5993 status = nvRmApiUnmapMemory(nvEvoGlobal.clientHandle,
5994 pDevEvo->pSubDevices[sd]->handle,
5995 capsHandle, ptr, 0);
5996 if (status != NVOS_STATUS_SUCCESS) {
5997 nvAssert(!"Failed to unmap caps memory");
5998 }
5999
6000 if (first) {
6001 pDevEvo->numWindows =
6002 UsableWindowCount(&pEvoSubDev->capabilities);
6003 first = FALSE;
6004 } else {
6005 /* Assert that each subdevice has the same number of windows. */
6006 nvAssert(pDevEvo->numWindows ==
6007 UsableWindowCount(&pEvoSubDev->capabilities));
6008 }
6009
6010 /*
6011 * Expose YUV semi-planar iff all of the disps belonging to pDevEvo
6012 * support it.
6013 */
6014 supportsSemiPlanar &=
6015 pEvoSubDev->capabilities.misc.supportsSemiPlanar;
6016
6017 /*
6018 * Expose YUV planar iff all of the disps belonging to pDevEvo
6019 * support it.
6020 */
6021 supportsPlanar &=
6022 pEvoSubDev->capabilities.misc.supportsPlanar;
6023
6024 supportsHVFlip &=
6025 pEvoSubDev->capabilities.misc.supportsHVFlip;
6026 }
6027
6028 SetHDRLayerCaps(pDevEvo);
6029
6030 for (i = NvKmsSurfaceMemoryFormatMin;
6031 i <= NvKmsSurfaceMemoryFormatMax;
6032 i++) {
6033 const NvKmsSurfaceMemoryFormatInfo *pFormatInfo =
6034 nvKmsGetSurfaceMemoryFormatInfo(i);
6035
6036 if ((pFormatInfo->numPlanes == 2 && !supportsSemiPlanar) ||
6037 (pFormatInfo->numPlanes == 3 && !supportsPlanar)) {
6038 continue;
6039 }
6040
6041 if (pGetHwFmt(i) != 0) {
6042 NvU8 layer;
6043
6044 for (layer = 0;
6045 layer < ARRAY_LEN(pDevEvo->caps.layerCaps);
6046 layer++) {
6047 pDevEvo->caps.layerCaps[layer].supportedSurfaceMemoryFormats |=
6048 NVBIT64(i);
6049 }
6050 }
6051 }
6052
6053 for (reflectionX = FALSE;
6054 reflectionX <= TRUE;
6055 reflectionX++) {
6056
6057 for (reflectionY = FALSE;
6058 reflectionY <= TRUE;
6059 reflectionY++) {
6060
6061 for (curRotation = NVKMS_ROTATION_MIN;
6062 curRotation <= NVKMS_ROTATION_MAX;
6063 curRotation++) {
6064 struct NvKmsRRParams rrParams = { curRotation,
6065 reflectionX,
6066 reflectionY };
6067 NvU8 bitPosition;
6068
6069 if ((reflectionX || reflectionY) && !supportsHVFlip) {
6070 continue;
6071 }
6072
6073 if (curRotation == NVKMS_ROTATION_180 && !supportsHVFlip) {
6074 continue;
6075 }
6076
6077 /*
6078 * Skipping over rotations by 90 and 270 degrees
6079 * because these rotations require support for
6080 * SCAN_COLUMN rotation, which hasn't been added
6081 * to NVKMS yet.
6082 */
6083 if (curRotation == NVKMS_ROTATION_90 ||
6084 curRotation == NVKMS_ROTATION_270) {
6085 continue;
6086 }
6087
6088 bitPosition = NvKmsRRParamsToCapBit(&rrParams);
6089 pDevEvo->caps.validLayerRRTransforms |= NVBIT(bitPosition);
6090 }
6091 }
6092 }
6093
6094 ret = TRUE;
6095
6096 free_object:
6097 status = nvRmApiFree(nvEvoGlobal.clientHandle,
6098 pDevEvo->displayHandle,
6099 capsHandle);
6100 if (status != NVOS_STATUS_SUCCESS) {
6101 nvAssert(!"Failed to free caps object");
6102 }
6103
6104 free_handle:
6105 nvFreeUnixRmHandle(&pDevEvo->handleAllocator, capsHandle);
6106
6107 return ret;
6108 }
6109
EvoGetCapabilitiesC3(NVDevEvoPtr pDevEvo)6110 static NvBool EvoGetCapabilitiesC3(NVDevEvoPtr pDevEvo)
6111 {
6112 return EvoGetCapabilities3(pDevEvo, EvoParseCapabilityNotifierC3,
6113 nvHwFormatFromKmsFormatC3,
6114 NVC373_DISP_CAPABILITIES,
6115 sizeof(_NvC373DispCapabilities));
6116 }
6117
EvoGetCapabilitiesC5(NVDevEvoPtr pDevEvo)6118 static NvBool EvoGetCapabilitiesC5(NVDevEvoPtr pDevEvo)
6119 {
6120 return EvoGetCapabilities3(pDevEvo, EvoParseCapabilityNotifierC5,
6121 nvHwFormatFromKmsFormatC5,
6122 NVC573_DISP_CAPABILITIES,
6123 sizeof(_NvC573DispCapabilities));
6124 }
6125
nvEvoGetCapabilitiesC6(NVDevEvoPtr pDevEvo)6126 NvBool nvEvoGetCapabilitiesC6(NVDevEvoPtr pDevEvo)
6127 {
6128 return EvoGetCapabilities3(pDevEvo, EvoParseCapabilityNotifierC6,
6129 nvHwFormatFromKmsFormatC6,
6130 NVC673_DISP_CAPABILITIES,
6131 sizeof(_NvC673DispCapabilities));
6132 }
6133
EvoSetViewportPointInC3(NVDevEvoPtr pDevEvo,const int head,NvU16 x,NvU16 y,NVEvoUpdateState * updateState)6134 static void EvoSetViewportPointInC3(NVDevEvoPtr pDevEvo, const int head,
6135 NvU16 x, NvU16 y,
6136 NVEvoUpdateState *updateState)
6137 {
6138 NVEvoChannelPtr pChannel = pDevEvo->core;
6139
6140 /* These methods should only apply to a single pDpy */
6141 nvAssert(pDevEvo->subDevMaskStackDepth > 0);
6142
6143 nvUpdateUpdateState(pDevEvo, updateState, pChannel);
6144
6145 /* Set the input viewport point */
6146 nvDmaSetStartEvoMethod(pChannel, NVC37D_HEAD_SET_VIEWPORT_POINT_IN(head), 1);
6147 nvDmaSetEvoMethodData(pChannel, DRF_NUM(C37D, _HEAD_SET_VIEWPORT_POINT_IN, _X, x) |
6148 DRF_NUM(C37D, _HEAD_SET_VIEWPORT_POINT_IN, _Y, y));
6149 /* XXXnvdisplay set ViewportValidPointIn to configure overfetch */
6150 }
6151
EvoSetOutputScalerC3(const NVDispEvoRec * pDispEvo,const NvU32 head,const NvU32 imageSharpeningValue,NVEvoUpdateState * updateState)6152 static void EvoSetOutputScalerC3(const NVDispEvoRec *pDispEvo, const NvU32 head,
6153 const NvU32 imageSharpeningValue,
6154 NVEvoUpdateState *updateState)
6155 {
6156 NVDevEvoPtr pDevEvo = pDispEvo->pDevEvo;
6157 NVEvoChannelPtr pChannel = pDevEvo->core;
6158 const NVDispHeadStateEvoRec *pHeadState = &pDispEvo->headState[head];
6159 const NVHwModeViewPortEvo *pViewPort = &pHeadState->timings.viewPort;
6160
6161 /* These methods should only apply to a single pDpyEvo */
6162 nvAssert(pDevEvo->subDevMaskStackDepth > 0);
6163
6164 nvUpdateUpdateState(pDevEvo, updateState, pChannel);
6165
6166 NvU32 vTaps = pViewPort->vTaps > NV_EVO_SCALER_2TAPS ?
6167 NVC37D_HEAD_SET_CONTROL_OUTPUT_SCALER_VERTICAL_TAPS_TAPS_5 :
6168 NVC37D_HEAD_SET_CONTROL_OUTPUT_SCALER_VERTICAL_TAPS_TAPS_2;
6169 NvU32 hTaps = pViewPort->hTaps > NV_EVO_SCALER_2TAPS ?
6170 NVC37D_HEAD_SET_CONTROL_OUTPUT_SCALER_HORIZONTAL_TAPS_TAPS_5 :
6171 NVC37D_HEAD_SET_CONTROL_OUTPUT_SCALER_HORIZONTAL_TAPS_TAPS_2;
6172
6173 nvDmaSetStartEvoMethod(pChannel, NVC37D_HEAD_SET_CONTROL_OUTPUT_SCALER(head), 1);
6174 nvDmaSetEvoMethodData(pChannel,
6175 DRF_NUM(C37D, _HEAD_SET_CONTROL_OUTPUT_SCALER, _VERTICAL_TAPS, vTaps) |
6176 DRF_NUM(C37D, _HEAD_SET_CONTROL_OUTPUT_SCALER, _HORIZONTAL_TAPS, hTaps));
6177 }
6178
EvoSetViewportInOut3(NVDevEvoPtr pDevEvo,const int head,const NVHwModeViewPortEvo * pViewPortMin,const NVHwModeViewPortEvo * pViewPort,const NVHwModeViewPortEvo * pViewPortMax,NVEvoUpdateState * updateState,NvU32 setWindowUsageBounds)6179 static NvBool EvoSetViewportInOut3(NVDevEvoPtr pDevEvo, const int head,
6180 const NVHwModeViewPortEvo *pViewPortMin,
6181 const NVHwModeViewPortEvo *pViewPort,
6182 const NVHwModeViewPortEvo *pViewPortMax,
6183 NVEvoUpdateState *updateState,
6184 NvU32 setWindowUsageBounds)
6185 {
6186 const NVEvoCapabilitiesPtr pEvoCaps = &pDevEvo->gpus[0].capabilities;
6187 NVEvoChannelPtr pChannel = pDevEvo->core;
6188 struct NvKmsScalingUsageBounds scalingUsageBounds = { };
6189 NvU32 win;
6190
6191 /* These methods should only apply to a single pDpy */
6192 nvAssert(pDevEvo->subDevMaskStackDepth > 0);
6193
6194 nvUpdateUpdateState(pDevEvo, updateState, pChannel);
6195
6196 /* The input viewport shouldn't vary. */
6197 nvAssert(pViewPortMin->in.width == pViewPort->in.width);
6198 nvAssert(pViewPortMax->in.width == pViewPort->in.width);
6199 nvAssert(pViewPortMin->in.height == pViewPort->in.height);
6200 nvAssert(pViewPortMax->in.height == pViewPort->in.height);
6201 nvDmaSetStartEvoMethod(pChannel, NVC37D_HEAD_SET_VIEWPORT_SIZE_IN(head), 1);
6202 nvDmaSetEvoMethodData(pChannel,
6203 DRF_NUM(C37D, _HEAD_SET_VIEWPORT_SIZE_IN, _WIDTH, pViewPort->in.width) |
6204 DRF_NUM(C37D, _HEAD_SET_VIEWPORT_SIZE_IN, _HEIGHT, pViewPort->in.height));
6205 /* XXXnvdisplay set ViewportValidSizeIn to configure overfetch */
6206
6207 nvDmaSetStartEvoMethod(pChannel, NVC37D_HEAD_SET_VIEWPORT_POINT_OUT_ADJUST(head), 1);
6208 nvDmaSetEvoMethodData(pChannel,
6209 DRF_NUM(C37D, _HEAD_SET_VIEWPORT_POINT_OUT, _ADJUST_X, pViewPort->out.xAdjust) |
6210 DRF_NUM(C37D, _HEAD_SET_VIEWPORT_POINT_OUT, _ADJUST_Y, pViewPort->out.yAdjust));
6211
6212 nvDmaSetStartEvoMethod(pChannel, NVC37D_HEAD_SET_VIEWPORT_SIZE_OUT(head), 1);
6213 nvDmaSetEvoMethodData(pChannel,
6214 DRF_NUM(C37D, _HEAD_SET_VIEWPORT_SIZE_OUT, _WIDTH, pViewPort->out.width) |
6215 DRF_NUM(C37D, _HEAD_SET_VIEWPORT_SIZE_OUT, _HEIGHT, pViewPort->out.height));
6216
6217 /* XXXnvdisplay deal with pViewPortMin, pViewPortMax */
6218
6219 if (!nvComputeScalingUsageBounds(&pEvoCaps->head[head].scalerCaps,
6220 pViewPort->in.width, pViewPort->in.height,
6221 pViewPort->out.width, pViewPort->out.height,
6222 pViewPort->hTaps, pViewPort->vTaps,
6223 &scalingUsageBounds)) {
6224 /* Should have been rejected by validation */
6225 nvAssert(!"Attempt to program invalid viewport");
6226 }
6227
6228 nvDmaSetStartEvoMethod(pChannel, NVC37D_HEAD_SET_MAX_OUTPUT_SCALE_FACTOR(head), 1);
6229 nvDmaSetEvoMethodData(pChannel,
6230 DRF_NUM(C37D, _HEAD_SET_MAX_OUTPUT_SCALE_FACTOR, _HORIZONTAL,
6231 scalingUsageBounds.maxHDownscaleFactor) |
6232 DRF_NUM(C37D, _HEAD_SET_MAX_OUTPUT_SCALE_FACTOR, _VERTICAL,
6233 scalingUsageBounds.maxVDownscaleFactor));
6234
6235 /*
6236 * Program MAX_PIXELS_FETCHED_PER_LINE window usage bounds
6237 * for each window that is attached to the head.
6238 *
6239 * Precomp will clip the post-scaled window to the input viewport, reverse-scale
6240 * this cropped size back to the input surface domain, and isohub will fetch
6241 * this cropped size. This function assumes that there's no window scaling yet,
6242 * so the MAX_PIXELS_FETCHED_PER_LINE will be bounded by the input viewport
6243 * width. SetScalingUsageBoundsOneWindow5() will take care of updating
6244 * MAX_PIXELS_FETCHED_PER_LINE, if window scaling is enabled later.
6245 *
6246 * Program MAX_PIXELS_FETCHED_PER_LINE for each window that is attached to
6247 * head. For Turing+, SetScalingUsageBoundsOneWindow5() will take care of
6248 * programming window usage bounds only for the layers/windows in use.
6249 */
6250 setWindowUsageBounds |=
6251 DRF_NUM(C37D, _WINDOW_SET_WINDOW_USAGE_BOUNDS, _MAX_PIXELS_FETCHED_PER_LINE,
6252 nvGetMaxPixelsFetchedPerLine(pViewPort->in.width,
6253 NV_EVO_SCALE_FACTOR_1X));
6254
6255 for (win = 0; win < pDevEvo->numWindows; win++) {
6256 if (head != pDevEvo->headForWindow[win]) {
6257 continue;
6258 }
6259
6260 nvDmaSetStartEvoMethod(pChannel, NVC37D_WINDOW_SET_WINDOW_USAGE_BOUNDS(win), 1);
6261 nvDmaSetEvoMethodData(pChannel, setWindowUsageBounds);
6262 }
6263
6264 return scalingUsageBounds.vUpscalingAllowed;
6265 }
6266
EvoSetViewportInOutC3(NVDevEvoPtr pDevEvo,const int head,const NVHwModeViewPortEvo * pViewPortMin,const NVHwModeViewPortEvo * pViewPort,const NVHwModeViewPortEvo * pViewPortMax,NVEvoUpdateState * updateState)6267 static void EvoSetViewportInOutC3(NVDevEvoPtr pDevEvo, const int head,
6268 const NVHwModeViewPortEvo *pViewPortMin,
6269 const NVHwModeViewPortEvo *pViewPort,
6270 const NVHwModeViewPortEvo *pViewPortMax,
6271 NVEvoUpdateState *updateState)
6272 {
6273 NVEvoChannelPtr pChannel = pDevEvo->core;
6274 NvBool verticalUpscalingAllowed =
6275 EvoSetViewportInOut3(pDevEvo, head, pViewPortMin, pViewPort,
6276 pViewPortMax, updateState,
6277 NV_EVO3_DEFAULT_WINDOW_USAGE_BOUNDS_C3);
6278
6279 nvDmaSetStartEvoMethod(pChannel,
6280 NVC37D_HEAD_SET_HEAD_USAGE_BOUNDS(head), 1);
6281 nvDmaSetEvoMethodData(pChannel,
6282 DRF_DEF(C37D, _HEAD_SET_HEAD_USAGE_BOUNDS, _CURSOR, _USAGE_W256_H256) |
6283 DRF_DEF(C37D, _HEAD_SET_HEAD_USAGE_BOUNDS, _OUTPUT_LUT, _USAGE_1025) |
6284 (verticalUpscalingAllowed ?
6285 DRF_DEF(C37D, _HEAD_SET_HEAD_USAGE_BOUNDS, _UPSCALING_ALLOWED, _TRUE) :
6286 DRF_DEF(C37D, _HEAD_SET_HEAD_USAGE_BOUNDS, _UPSCALING_ALLOWED, _FALSE)));
6287 }
6288
EvoSetViewportInOutC5(NVDevEvoPtr pDevEvo,const int head,const NVHwModeViewPortEvo * pViewPortMin,const NVHwModeViewPortEvo * pViewPort,const NVHwModeViewPortEvo * pViewPortMax,NVEvoUpdateState * updateState)6289 static void EvoSetViewportInOutC5(NVDevEvoPtr pDevEvo, const int head,
6290 const NVHwModeViewPortEvo *pViewPortMin,
6291 const NVHwModeViewPortEvo *pViewPort,
6292 const NVHwModeViewPortEvo *pViewPortMax,
6293 NVEvoUpdateState *updateState)
6294 {
6295 NVEvoChannelPtr pChannel = pDevEvo->core;
6296 NvU32 setWindowUsageBounds =
6297 (NV_EVO3_DEFAULT_WINDOW_USAGE_BOUNDS_C5 |
6298 DRF_DEF(C57D, _WINDOW_SET_WINDOW_USAGE_BOUNDS, _INPUT_SCALER_TAPS, _TAPS_2) |
6299 DRF_DEF(C57D, _WINDOW_SET_WINDOW_USAGE_BOUNDS, _UPSCALING_ALLOWED, _FALSE));
6300 NvU32 verticalUpscalingAllowed =
6301 EvoSetViewportInOut3(pDevEvo, head, pViewPortMin, pViewPort,
6302 pViewPortMax, updateState, setWindowUsageBounds);
6303
6304 nvDmaSetStartEvoMethod(pChannel,
6305 NVC57D_HEAD_SET_HEAD_USAGE_BOUNDS(head), 1);
6306 nvDmaSetEvoMethodData(pChannel,
6307 DRF_DEF(C57D, _HEAD_SET_HEAD_USAGE_BOUNDS, _CURSOR, _USAGE_W256_H256) |
6308 DRF_DEF(C57D, _HEAD_SET_HEAD_USAGE_BOUNDS, _OLUT_ALLOWED, _TRUE) |
6309 /* Despite the generic name of this field, it's specific to vertical taps. */
6310 (pViewPort->vTaps > NV_EVO_SCALER_2TAPS ?
6311 DRF_DEF(C57D, _HEAD_SET_HEAD_USAGE_BOUNDS, _OUTPUT_SCALER_TAPS, _TAPS_5) :
6312 DRF_DEF(C57D, _HEAD_SET_HEAD_USAGE_BOUNDS, _OUTPUT_SCALER_TAPS, _TAPS_2)) |
6313 (verticalUpscalingAllowed ?
6314 DRF_DEF(C57D, _HEAD_SET_HEAD_USAGE_BOUNDS, _UPSCALING_ALLOWED, _TRUE) :
6315 DRF_DEF(C57D, _HEAD_SET_HEAD_USAGE_BOUNDS, _UPSCALING_ALLOWED, _FALSE)));
6316 }
6317
6318 /*!
6319 * Compute the C37D_HEAD_SET_CONTROL_CURSOR method value.
6320 *
6321 * This function also validates that the given NVSurfaceEvoRec can be
6322 * used as a cursor image.
6323
6324 *
6325 * \param[in] pDevEvo The device on which the cursor will be programmed.
6326 * \param[in] pSurfaceEvo The surface to be used as the cursor image.
6327 * \param[out] pValue The C37D_HEAD_SET_CONTROL_CURSOR method value.
6328
6329 * \return If TRUE, the surface can be used as a cursor image, and
6330 * pValue contains the method value. If FALSE, the surface
6331 * cannot be used as a cursor image.
6332 */
nvEvoGetHeadSetControlCursorValueC3(const NVDevEvoRec * pDevEvo,const NVSurfaceEvoRec * pSurfaceEvo,NvU32 * pValue)6333 NvBool nvEvoGetHeadSetControlCursorValueC3(const NVDevEvoRec *pDevEvo,
6334 const NVSurfaceEvoRec *pSurfaceEvo,
6335 NvU32 *pValue)
6336 {
6337 NvU32 value = 0;
6338
6339 if (pSurfaceEvo == NULL) {
6340 value |= DRF_DEF(C37D, _HEAD_SET_CONTROL_CURSOR, _ENABLE, _DISABLE);
6341 value |= DRF_DEF(C37D, _HEAD_SET_CONTROL_CURSOR, _FORMAT, _A8R8G8B8);
6342 goto done;
6343 } else {
6344 value |= DRF_DEF(C37D, _HEAD_SET_CONTROL_CURSOR, _ENABLE, _ENABLE);
6345 }
6346
6347 /* The cursor must always be pitch. */
6348
6349 if (pSurfaceEvo->layout != NvKmsSurfaceMemoryLayoutPitch) {
6350 return FALSE;
6351 }
6352
6353 /*
6354 * The only supported cursor image memory format is A8R8G8B8.
6355 */
6356 if (pSurfaceEvo->format == NvKmsSurfaceMemoryFormatA8R8G8B8) {
6357 value |= DRF_DEF(C37D, _HEAD_SET_CONTROL_CURSOR, _FORMAT, _A8R8G8B8);
6358 } else {
6359 return FALSE;
6360 }
6361
6362 /*
6363 * The cursor only supports a few image sizes.
6364 */
6365 if ((pSurfaceEvo->widthInPixels == 32) &&
6366 (pSurfaceEvo->heightInPixels == 32)) {
6367 value |= DRF_DEF(C37D, _HEAD_SET_CONTROL_CURSOR, _SIZE, _W32_H32);
6368 } else if ((pSurfaceEvo->widthInPixels == 64) &&
6369 (pSurfaceEvo->heightInPixels == 64)) {
6370 value |= DRF_DEF(C37D, _HEAD_SET_CONTROL_CURSOR, _SIZE, _W64_H64);
6371 } else if ((pDevEvo->cursorHal->caps.maxSize >= 128) &&
6372 (pSurfaceEvo->widthInPixels == 128) &&
6373 (pSurfaceEvo->heightInPixels == 128)) {
6374 value |= DRF_DEF(C37D, _HEAD_SET_CONTROL_CURSOR, _SIZE, _W128_H128);
6375 } else if ((pDevEvo->cursorHal->caps.maxSize >= 256) &&
6376 (pSurfaceEvo->widthInPixels == 256) &&
6377 (pSurfaceEvo->heightInPixels == 256)) {
6378 value |= DRF_DEF(C37D, _HEAD_SET_CONTROL_CURSOR, _SIZE, _W256_H256);
6379 } else {
6380 return FALSE;
6381 }
6382
6383 /*
6384 * Hard code the cursor hotspot.
6385 */
6386 value |= DRF_NUM(C37D, _HEAD_SET_CONTROL_CURSOR, _HOT_SPOT_Y, 0);
6387 value |= DRF_NUM(C37D, _HEAD_SET_CONTROL_CURSOR, _HOT_SPOT_X, 0);
6388
6389 // XXXnvdisplay: Add support for cursor de-gamma.
6390
6391 done:
6392
6393 if (pValue != NULL) {
6394 *pValue = value;
6395 }
6396
6397 return TRUE;
6398 }
6399
SetCursorSurfaceAddress(NVEvoChannelPtr pChannel,const NVSurfaceDescriptor * pSurfaceDesc,NvU32 offset,NvU32 head)6400 static void SetCursorSurfaceAddress(
6401 NVEvoChannelPtr pChannel,
6402 const NVSurfaceDescriptor *pSurfaceDesc,
6403 NvU32 offset,
6404 NvU32 head)
6405 {
6406 NvU32 ctxDmaHandle = pSurfaceDesc ? pSurfaceDesc->ctxDmaHandle : 0;
6407
6408 nvAssert(!pSurfaceDesc || ctxDmaHandle);
6409
6410 nvDmaSetStartEvoMethod(pChannel, NVC37D_HEAD_SET_CONTEXT_DMA_CURSOR(head, 0), 4);
6411 nvDmaSetEvoMethodData(pChannel,
6412 DRF_NUM(C37D, _HEAD_SET_CONTEXT_DMA_CURSOR, _HANDLE, ctxDmaHandle));
6413
6414 // Always set the right cursor context DMA.
6415 // HW will just ignore this if it is not in stereo cursor mode.
6416 nvDmaSetEvoMethodData(pChannel,
6417 DRF_NUM(C37D, _HEAD_SET_CONTEXT_DMA_CURSOR, _HANDLE, ctxDmaHandle));
6418 nvDmaSetEvoMethodData(pChannel,
6419 DRF_NUM(C37D, _HEAD_SET_OFFSET_CURSOR, _ORIGIN,
6420 nvCtxDmaOffsetFromBytes(offset)));
6421 nvDmaSetEvoMethodData(pChannel,
6422 DRF_NUM(C37D, _HEAD_SET_OFFSET_CURSOR, _ORIGIN,
6423 nvCtxDmaOffsetFromBytes(offset)));
6424 }
6425
EvoSetCursorImageC3(NVDevEvoPtr pDevEvo,const int head,const NVSurfaceEvoRec * pSurfaceEvo,NVEvoUpdateState * updateState,const struct NvKmsCompositionParams * pCursorCompParams)6426 static void EvoSetCursorImageC3(NVDevEvoPtr pDevEvo, const int head,
6427 const NVSurfaceEvoRec *pSurfaceEvo,
6428 NVEvoUpdateState *updateState,
6429 const struct NvKmsCompositionParams *pCursorCompParams)
6430 {
6431 NVEvoChannelPtr pChannel = pDevEvo->core;
6432 const NVSurfaceDescriptor *pSurfaceDesc =
6433 pSurfaceEvo ? &pSurfaceEvo->planes[0].surfaceDesc : NULL;
6434 const NvU64 offset = pSurfaceEvo ? pSurfaceEvo->planes[0].offset : 0;
6435 NvU32 headSetControlCursorValue = 0;
6436 NvBool ret;
6437
6438 nvUpdateUpdateState(pDevEvo, updateState, pChannel);
6439 nvAssert(pCursorCompParams->colorKeySelect ==
6440 NVKMS_COMPOSITION_COLOR_KEY_SELECT_DISABLE);
6441 nvAssert(NVBIT(pCursorCompParams->blendingMode[1]) &
6442 NV_EVO3_SUPPORTED_CURSOR_COMP_BLEND_MODES);
6443 /* These methods should only apply to a single pDpy */
6444 nvAssert(pDevEvo->subDevMaskStackDepth > 0);
6445
6446 ret = nvEvoGetHeadSetControlCursorValueC3(pDevEvo, pSurfaceEvo,
6447 &headSetControlCursorValue);
6448 /*
6449 * The caller should have already validated the surface, so there
6450 * shouldn't be a failure.
6451 */
6452 if (!ret) {
6453 nvAssert(!"Could not construct HEAD_SET_CONTROL_CURSOR value");
6454 }
6455
6456 nvDmaSetStartEvoMethod(pChannel, NVC37D_HEAD_SET_PRESENT_CONTROL_CURSOR(head), 1);
6457 nvDmaSetEvoMethodData(pChannel,
6458 DRF_DEF(C37D, _HEAD_SET_PRESENT_CONTROL_CURSOR, _MODE, _MONO));
6459
6460 SetCursorSurfaceAddress(pChannel, pSurfaceDesc, offset, head);
6461
6462 nvDmaSetStartEvoMethod(pChannel, NVC37D_HEAD_SET_CONTROL_CURSOR(head), 1);
6463 nvDmaSetEvoMethodData(pChannel, headSetControlCursorValue);
6464
6465 nvDmaSetStartEvoMethod(pChannel,
6466 NVC37D_HEAD_SET_CONTROL_CURSOR_COMPOSITION(head), 1);
6467 switch (pCursorCompParams->blendingMode[1]) {
6468 case NVKMS_COMPOSITION_BLENDING_MODE_OPAQUE:
6469 nvDmaSetEvoMethodData(pChannel,
6470 DRF_NUM(C37D, _HEAD_SET_CONTROL_CURSOR_COMPOSITION, _K1, 255) |
6471 DRF_DEF(C37D, _HEAD_SET_CONTROL_CURSOR_COMPOSITION,
6472 _CURSOR_COLOR_FACTOR_SELECT, _K1) |
6473 DRF_DEF(C37D, _HEAD_SET_CONTROL_CURSOR_COMPOSITION,
6474 _VIEWPORT_COLOR_FACTOR_SELECT, _ZERO) |
6475 DRF_DEF(C37D, _HEAD_SET_CONTROL_CURSOR_COMPOSITION, _MODE, _BLEND));
6476 break;
6477 case NVKMS_COMPOSITION_BLENDING_MODE_NON_PREMULT_ALPHA:
6478 nvDmaSetEvoMethodData(pChannel,
6479 DRF_NUM(C37D, _HEAD_SET_CONTROL_CURSOR_COMPOSITION, _K1, 255) |
6480 DRF_DEF(C37D, _HEAD_SET_CONTROL_CURSOR_COMPOSITION,
6481 _CURSOR_COLOR_FACTOR_SELECT, _K1_TIMES_SRC) |
6482 DRF_DEF(C37D, _HEAD_SET_CONTROL_CURSOR_COMPOSITION,
6483 _VIEWPORT_COLOR_FACTOR_SELECT, _NEG_K1_TIMES_SRC) |
6484 DRF_DEF(C37D, _HEAD_SET_CONTROL_CURSOR_COMPOSITION, _MODE, _BLEND));
6485 break;
6486 case NVKMS_COMPOSITION_BLENDING_MODE_PREMULT_ALPHA:
6487 nvDmaSetEvoMethodData(pChannel,
6488 DRF_NUM(C37D, _HEAD_SET_CONTROL_CURSOR_COMPOSITION, _K1, 255) |
6489 DRF_DEF(C37D, _HEAD_SET_CONTROL_CURSOR_COMPOSITION,
6490 _CURSOR_COLOR_FACTOR_SELECT, _K1) |
6491 DRF_DEF(C37D, _HEAD_SET_CONTROL_CURSOR_COMPOSITION,
6492 _VIEWPORT_COLOR_FACTOR_SELECT, _NEG_K1_TIMES_SRC) |
6493 DRF_DEF(C37D, _HEAD_SET_CONTROL_CURSOR_COMPOSITION, _MODE, _BLEND));
6494 break;
6495 case NVKMS_COMPOSITION_BLENDING_MODE_NON_PREMULT_SURFACE_ALPHA:
6496 nvDmaSetEvoMethodData(pChannel,
6497 DRF_NUM(C37D, _HEAD_SET_CONTROL_CURSOR_COMPOSITION, _K1,
6498 pCursorCompParams->surfaceAlpha) |
6499 DRF_DEF(C37D, _HEAD_SET_CONTROL_CURSOR_COMPOSITION,
6500 _CURSOR_COLOR_FACTOR_SELECT, _K1_TIMES_SRC) |
6501 DRF_DEF(C37D, _HEAD_SET_CONTROL_CURSOR_COMPOSITION,
6502 _VIEWPORT_COLOR_FACTOR_SELECT, _NEG_K1_TIMES_SRC) |
6503 DRF_DEF(C37D, _HEAD_SET_CONTROL_CURSOR_COMPOSITION, _MODE, _BLEND));
6504 break;
6505 case NVKMS_COMPOSITION_BLENDING_MODE_PREMULT_SURFACE_ALPHA:
6506 nvDmaSetEvoMethodData(pChannel,
6507 DRF_NUM(C37D, _HEAD_SET_CONTROL_CURSOR_COMPOSITION, _K1,
6508 pCursorCompParams->surfaceAlpha) |
6509 DRF_DEF(C37D, _HEAD_SET_CONTROL_CURSOR_COMPOSITION,
6510 _CURSOR_COLOR_FACTOR_SELECT, _K1) |
6511 DRF_DEF(C37D, _HEAD_SET_CONTROL_CURSOR_COMPOSITION,
6512 _VIEWPORT_COLOR_FACTOR_SELECT, _NEG_K1_TIMES_SRC) |
6513 DRF_DEF(C37D, _HEAD_SET_CONTROL_CURSOR_COMPOSITION, _MODE, _BLEND));
6514 break;
6515 default:
6516 nvEvoLogDevDebug(pDevEvo, EVO_LOG_ERROR,
6517 "%s: composition mode %d not supported for cursor",
6518 __func__, pCursorCompParams->blendingMode[1]);
6519 break;
6520 }
6521 }
6522
nvEvoValidateCursorSurfaceC3(const NVDevEvoRec * pDevEvo,const NVSurfaceEvoRec * pSurfaceEvo)6523 NvBool nvEvoValidateCursorSurfaceC3(const NVDevEvoRec *pDevEvo,
6524 const NVSurfaceEvoRec *pSurfaceEvo)
6525 {
6526 return nvEvoGetHeadSetControlCursorValueC3(pDevEvo, pSurfaceEvo, NULL);
6527 }
6528
ValidateWindowFormatSourceRectC3(const struct NvKmsRect * sourceFetchRect,const enum NvKmsSurfaceMemoryFormat format)6529 static NvBool ValidateWindowFormatSourceRectC3(
6530 const struct NvKmsRect *sourceFetchRect,
6531 const enum NvKmsSurfaceMemoryFormat format)
6532 {
6533 const NvKmsSurfaceMemoryFormatInfo *pFormatInfo =
6534 nvKmsGetSurfaceMemoryFormatInfo(format);
6535
6536 /*
6537 * sourceFetchRect represents the dimensions of the source fetch rectangle.
6538 * If YUV crop and scaler overfetch are supported, it is up to the caller to
6539 * provide the correct dimensions (e.g., ValidSizeIn/ValidPointIn vs.
6540 * SizeIn/PointIn).
6541 *
6542 * For all YUV formats, the position and size of the fetch rectangle must be
6543 * even in the horizontal direction.
6544 *
6545 * For YUV420 formats, there is an additional restriction that the position
6546 * and size of the fetch rectangle must be even in the vertical direction as
6547 * well.
6548 */
6549 if (pFormatInfo->isYUV) {
6550 if (((sourceFetchRect->x & 1) != 0) ||
6551 (sourceFetchRect->width & 1) != 0) {
6552 return FALSE;
6553 }
6554
6555 if (pFormatInfo->yuv.vertChromaDecimationFactor > 1) {
6556 if (((sourceFetchRect->y & 1) != 0) ||
6557 (sourceFetchRect->height & 1) != 0) {
6558 return FALSE;
6559 }
6560 }
6561 }
6562
6563 return TRUE;
6564 }
6565
6566 typedef typeof(ValidateWindowFormatSourceRectC3) val_src_rect_t;
6567
EvoValidateWindowFormatWrapper(const enum NvKmsSurfaceMemoryFormat format,get_hw_fmt_t * pGetHwFmt,const struct NvKmsRect * sourceFetchRect,val_src_rect_t * pValSrcRect,NvU32 * hwFormatOut)6568 static NvBool EvoValidateWindowFormatWrapper(
6569 const enum NvKmsSurfaceMemoryFormat format,
6570 get_hw_fmt_t *pGetHwFmt,
6571 const struct NvKmsRect *sourceFetchRect,
6572 val_src_rect_t *pValSrcRect,
6573 NvU32 *hwFormatOut)
6574 {
6575 const NvU32 hwFormat = pGetHwFmt(format);
6576
6577 if (hwFormat == 0) {
6578 return FALSE;
6579 }
6580
6581 if (hwFormatOut != NULL) {
6582 *hwFormatOut = hwFormat;
6583 }
6584
6585 /*
6586 * If sourceFetchRect is NULL, this function is only responsible for
6587 * verifying whether the given NvKmsSurfaceMemoryFormat has a corresponding
6588 * HW format.
6589 */
6590 if (sourceFetchRect == NULL) {
6591 return TRUE;
6592 }
6593
6594 return pValSrcRect(sourceFetchRect, format);
6595 }
6596
EvoValidateWindowFormatC3(const enum NvKmsSurfaceMemoryFormat format,const struct NvKmsRect * sourceFetchRect,NvU32 * hwFormatOut)6597 static NvBool EvoValidateWindowFormatC3(
6598 const enum NvKmsSurfaceMemoryFormat format,
6599 const struct NvKmsRect *sourceFetchRect,
6600 NvU32 *hwFormatOut)
6601 {
6602 return EvoValidateWindowFormatWrapper(
6603 format,
6604 nvHwFormatFromKmsFormatC3,
6605 sourceFetchRect,
6606 ValidateWindowFormatSourceRectC3,
6607 hwFormatOut);
6608 }
6609
EvoValidateWindowFormatC5(const enum NvKmsSurfaceMemoryFormat format,const struct NvKmsRect * sourceFetchRect,NvU32 * hwFormatOut)6610 static NvBool EvoValidateWindowFormatC5(
6611 const enum NvKmsSurfaceMemoryFormat format,
6612 const struct NvKmsRect *sourceFetchRect,
6613 NvU32 *hwFormatOut)
6614 {
6615 return EvoValidateWindowFormatWrapper(
6616 format,
6617 nvHwFormatFromKmsFormatC5,
6618 sourceFetchRect,
6619 ValidateWindowFormatSourceRectC3,
6620 hwFormatOut);
6621 }
6622
nvEvoValidateWindowFormatC6(const enum NvKmsSurfaceMemoryFormat format,const struct NvKmsRect * sourceFetchRect,NvU32 * hwFormatOut)6623 NvBool nvEvoValidateWindowFormatC6(
6624 const enum NvKmsSurfaceMemoryFormat format,
6625 const struct NvKmsRect *sourceFetchRect,
6626 NvU32 *hwFormatOut)
6627 {
6628 return EvoValidateWindowFormatWrapper(
6629 format,
6630 nvHwFormatFromKmsFormatC6,
6631 sourceFetchRect,
6632 ValidateWindowFormatSourceRectC3,
6633 hwFormatOut);
6634 }
6635
OffsetForNotifier(int idx)6636 static NvU32 OffsetForNotifier(int idx)
6637 {
6638 /* NVDisplay notifiers are always the 16-byte variety. We only care about
6639 * the NV_DISP_NOTIFIER__0 dword which contains the status. */
6640 NvU32 base = idx * (NV_DISP_NOTIFIER_SIZEOF / sizeof(NvU32));
6641 return base + NV_DISP_NOTIFIER__0;
6642 }
6643
nvEvoInitCompNotifierC3(const NVDispEvoRec * pDispEvo,int idx)6644 void nvEvoInitCompNotifierC3(const NVDispEvoRec *pDispEvo, int idx)
6645 {
6646 nvWriteEvoCoreNotifier(pDispEvo, OffsetForNotifier(idx),
6647 DRF_DEF(_DISP, _NOTIFIER__0, _STATUS, _NOT_BEGUN));
6648 }
6649
nvEvoIsCompNotifierCompleteC3(NVDispEvoPtr pDispEvo,int idx)6650 NvBool nvEvoIsCompNotifierCompleteC3(NVDispEvoPtr pDispEvo, int idx) {
6651 return nvEvoIsCoreNotifierComplete(pDispEvo, OffsetForNotifier(idx),
6652 DRF_BASE(NV_DISP_NOTIFIER__0_STATUS),
6653 DRF_EXTENT(NV_DISP_NOTIFIER__0_STATUS),
6654 NV_DISP_NOTIFIER__0_STATUS_FINISHED);
6655 }
6656
nvEvoWaitForCompNotifierC3(const NVDispEvoRec * pDispEvo,int idx)6657 void nvEvoWaitForCompNotifierC3(const NVDispEvoRec *pDispEvo, int idx)
6658 {
6659 nvEvoWaitForCoreNotifier(pDispEvo, OffsetForNotifier(idx),
6660 DRF_BASE(NV_DISP_NOTIFIER__0_STATUS),
6661 DRF_EXTENT(NV_DISP_NOTIFIER__0_STATUS),
6662 NV_DISP_NOTIFIER__0_STATUS_FINISHED);
6663 }
6664
EvoSetDitherC3(NVDispEvoPtr pDispEvo,const int head,const NvBool enabled,const NvU32 type,const NvU32 algo,NVEvoUpdateState * updateState)6665 static void EvoSetDitherC3(NVDispEvoPtr pDispEvo, const int head,
6666 const NvBool enabled, const NvU32 type,
6667 const NvU32 algo,
6668 NVEvoUpdateState *updateState)
6669 {
6670 NVDevEvoPtr pDevEvo = pDispEvo->pDevEvo;
6671 NVEvoChannelPtr pChannel = pDevEvo->core;
6672 NvU32 ditherControl;
6673
6674 nvUpdateUpdateState(pDevEvo, updateState, pChannel);
6675
6676 if (enabled) {
6677 ditherControl = DRF_DEF(C37D, _HEAD_SET_DITHER_CONTROL, _ENABLE, _ENABLE);
6678
6679 switch (type) {
6680 case NV0073_CTRL_SPECIFIC_OR_DITHER_TYPE_6_BITS:
6681 ditherControl |=
6682 DRF_DEF(C37D, _HEAD_SET_DITHER_CONTROL, _BITS, _TO_6_BITS);
6683 break;
6684 case NV0073_CTRL_SPECIFIC_OR_DITHER_TYPE_8_BITS:
6685 ditherControl |=
6686 DRF_DEF(C37D, _HEAD_SET_DITHER_CONTROL, _BITS, _TO_8_BITS);
6687 break;
6688 /* XXXnvdisplay: Support DITHER_TO_{10,12}_BITS (see also bug 1729668). */
6689 default:
6690 nvAssert(!"Unknown ditherType");
6691 // Fall through
6692 case NV0073_CTRL_SPECIFIC_OR_DITHER_TYPE_OFF:
6693 ditherControl = NVC37D_HEAD_SET_DITHER_CONTROL_ENABLE_DISABLE;
6694 break;
6695 }
6696
6697 } else {
6698 ditherControl = DRF_DEF(C37D, _HEAD_SET_DITHER_CONTROL, _ENABLE, _DISABLE);
6699 }
6700
6701 switch (algo) {
6702 case NV0073_CTRL_SPECIFIC_OR_DITHER_ALGO_STATIC_ERR_ACC:
6703 ditherControl |=
6704 DRF_DEF(C37D, _HEAD_SET_DITHER_CONTROL, _MODE, _STATIC_ERR_ACC);
6705 break;
6706 case NV0073_CTRL_SPECIFIC_OR_DITHER_ALGO_DYNAMIC_2X2:
6707 ditherControl |=
6708 DRF_DEF(C37D, _HEAD_SET_DITHER_CONTROL, _MODE, _DYNAMIC_2X2);
6709 break;
6710 case NV0073_CTRL_SPECIFIC_OR_DITHER_ALGO_STATIC_2X2:
6711 ditherControl |=
6712 DRF_DEF(C37D, _HEAD_SET_DITHER_CONTROL, _MODE, _STATIC_2X2);
6713 break;
6714 case NV0073_CTRL_SPECIFIC_OR_DITHER_ALGO_TEMPORAL:
6715 ditherControl |=
6716 DRF_DEF(C37D, _HEAD_SET_DITHER_CONTROL, _MODE, _TEMPORAL);
6717 break;
6718 default:
6719 nvAssert(!"Unknown DitherAlgo");
6720 // Fall through
6721 case NV0073_CTRL_SPECIFIC_OR_DITHER_ALGO_UNKNOWN:
6722 case NV0073_CTRL_SPECIFIC_OR_DITHER_ALGO_DYNAMIC_ERR_ACC:
6723 ditherControl |=
6724 DRF_DEF(C37D, _HEAD_SET_DITHER_CONTROL, _MODE, _DYNAMIC_ERR_ACC);
6725 break;
6726 }
6727
6728 nvDmaSetStartEvoMethod(pChannel, NVC37D_HEAD_SET_DITHER_CONTROL(head), 1);
6729 nvDmaSetEvoMethodData(pChannel, ditherControl);
6730 }
6731
EvoSetDisplayRateC3(NVDispEvoPtr pDispEvo,const int head,NvBool enable,NVEvoUpdateState * updateState,NvU32 timeoutMicroseconds)6732 static void EvoSetDisplayRateC3(NVDispEvoPtr pDispEvo, const int head,
6733 NvBool enable,
6734 NVEvoUpdateState *updateState,
6735 NvU32 timeoutMicroseconds)
6736 {
6737 NVDevEvoPtr pDevEvo = pDispEvo->pDevEvo;
6738 NVEvoChannelPtr pChannel = pDevEvo->core;
6739
6740 nvUpdateUpdateState(pDevEvo, updateState, pChannel);
6741
6742 if (enable) {
6743 timeoutMicroseconds =
6744 NV_MIN(timeoutMicroseconds,
6745 DRF_MASK(NVC37D_HEAD_SET_DISPLAY_RATE_MIN_REFRESH_INTERVAL));
6746
6747 nvDmaSetStartEvoMethod(pChannel, NVC37D_HEAD_SET_DISPLAY_RATE(head), 1);
6748 nvDmaSetEvoMethodData(pChannel,
6749 DRF_DEF(C37D, _HEAD_SET_DISPLAY_RATE, _RUN_MODE, _ONE_SHOT) |
6750 DRF_NUM(C37D, _HEAD_SET_DISPLAY_RATE, _MIN_REFRESH_INTERVAL,
6751 timeoutMicroseconds) |
6752 (timeoutMicroseconds == 0 ?
6753 DRF_DEF(C37D, _HEAD_SET_DISPLAY_RATE, _MIN_REFRESH, _DISABLE) :
6754 DRF_DEF(C37D, _HEAD_SET_DISPLAY_RATE, _MIN_REFRESH, _ENABLE)));
6755 } else {
6756 nvDmaSetStartEvoMethod(pChannel, NVC37D_HEAD_SET_DISPLAY_RATE(head), 1);
6757 nvDmaSetEvoMethodData(pChannel,
6758 DRF_DEF(C37D, _HEAD_SET_DISPLAY_RATE, _RUN_MODE, _CONTINUOUS));
6759 }
6760 }
6761
EvoSetStallLockC3(NVDispEvoPtr pDispEvo,const int head,NvBool enable,NVEvoUpdateState * updateState)6762 static void EvoSetStallLockC3(NVDispEvoPtr pDispEvo, const int head,
6763 NvBool enable, NVEvoUpdateState *updateState)
6764 {
6765 NVDevEvoPtr pDevEvo = pDispEvo->pDevEvo;
6766 NVEvoChannelPtr pChannel = pDevEvo->core;
6767 NVEvoSubDevPtr pEvoSubDev = &pDevEvo->gpus[pDispEvo->displayOwner];
6768 NVEvoHeadControlPtr pHC = &pEvoSubDev->headControl[head];
6769 NvU32 data = 0x0;
6770
6771 nvUpdateUpdateState(pDevEvo, updateState, pChannel);
6772
6773 if (pHC->crashLockUnstallMode) {
6774 data |= DRF_DEF(C37D, _HEAD_SET_STALL_LOCK, _UNSTALL_MODE, _CRASH_LOCK);
6775 } else {
6776 data |= DRF_DEF(C37D, _HEAD_SET_STALL_LOCK, _UNSTALL_MODE, _LINE_LOCK);
6777 }
6778
6779 if (enable) {
6780 data |= DRF_DEF(C37D, _HEAD_SET_STALL_LOCK, _ENABLE, _TRUE) |
6781 DRF_DEF(C37D, _HEAD_SET_STALL_LOCK, _MODE, _ONE_SHOT);
6782
6783 if (!pHC->useStallLockPin) {
6784 data |= DRF_DEF(C37D, _HEAD_SET_STALL_LOCK, _LOCK_PIN, _LOCK_PIN_NONE);
6785 } else if (NV_EVO_LOCK_PIN_IS_INTERNAL(pHC->stallLockPin)) {
6786 NvU32 pin = pHC->stallLockPin - NV_EVO_LOCK_PIN_INTERNAL_0;
6787 data |= DRF_NUM(C37D, _HEAD_SET_STALL_LOCK, _LOCK_PIN,
6788 NVC37D_HEAD_SET_STALL_LOCK_LOCK_PIN_INTERNAL_SCAN_LOCK(pin));
6789 } else {
6790 NvU32 pin = pHC->stallLockPin - NV_EVO_LOCK_PIN_0;
6791 data |= DRF_NUM(C37D, _HEAD_SET_STALL_LOCK, _LOCK_PIN,
6792 NVC37D_HEAD_SET_STALL_LOCK_LOCK_PIN_LOCK_PIN(pin));
6793 }
6794 } else {
6795 data |= DRF_DEF(C37D, _HEAD_SET_STALL_LOCK, _ENABLE, _FALSE);
6796 }
6797
6798 nvDmaSetStartEvoMethod(pChannel, NVC37D_HEAD_SET_STALL_LOCK(head), 1);
6799 nvDmaSetEvoMethodData(pChannel, data);
6800 }
6801
GetChannelState(NVDevEvoPtr pDevEvo,NVEvoChannelPtr pChan,NvU32 sd,NvU32 * result)6802 static NvBool GetChannelState(NVDevEvoPtr pDevEvo,
6803 NVEvoChannelPtr pChan,
6804 NvU32 sd,
6805 NvU32 *result)
6806 {
6807 NVC370_CTRL_CMD_GET_CHANNEL_INFO_PARAMS info = { };
6808 NvU32 ret;
6809
6810 info.base.subdeviceIndex = sd;
6811 info.channelClass = pChan->hwclass;
6812 info.channelInstance = pChan->instance;
6813
6814 ret = nvRmApiControl(nvEvoGlobal.clientHandle,
6815 pDevEvo->displayHandle,
6816 NVC370_CTRL_CMD_GET_CHANNEL_INFO,
6817 &info, sizeof(info));
6818 if (ret != NVOS_STATUS_SUCCESS) {
6819 nvEvoLogDev(pDevEvo, EVO_LOG_ERROR,
6820 "Failed to query display engine channel state: 0x%08x:%d:%d:0x%08x",
6821 pChan->hwclass, pChan->instance, sd, ret);
6822 return FALSE;
6823 }
6824
6825 *result = info.channelState;
6826
6827 return TRUE;
6828 }
6829
nvEvoIsChannelIdleC3(NVDevEvoPtr pDevEvo,NVEvoChannelPtr pChan,NvU32 sd,NvBool * result)6830 NvBool nvEvoIsChannelIdleC3(NVDevEvoPtr pDevEvo,
6831 NVEvoChannelPtr pChan,
6832 NvU32 sd,
6833 NvBool *result)
6834 {
6835 NvU32 channelState;
6836
6837 if (!GetChannelState(pDevEvo, pChan, sd, &channelState)) {
6838 return FALSE;
6839 }
6840
6841 *result = (channelState == NVC370_CTRL_GET_CHANNEL_INFO_STATE_IDLE);
6842
6843 return TRUE;
6844 }
6845
nvEvoIsChannelMethodPendingC3(NVDevEvoPtr pDevEvo,NVEvoChannelPtr pChan,NvU32 sd,NvBool * result)6846 NvBool nvEvoIsChannelMethodPendingC3(NVDevEvoPtr pDevEvo,
6847 NVEvoChannelPtr pChan,
6848 NvU32 sd,
6849 NvBool *result)
6850 {
6851 NvBool tmpResult;
6852
6853 /* With C370, Idle and NoMethodPending are equivalent. */
6854 ct_assert(NVC370_CTRL_GET_CHANNEL_INFO_STATE_IDLE ==
6855 NVC370_CTRL_GET_CHANNEL_INFO_STATE_NO_METHOD_PENDING);
6856
6857 if (!nvEvoIsChannelIdleC3(pDevEvo, pChan, sd, &tmpResult)) {
6858 return FALSE;
6859 }
6860
6861 *result = !tmpResult;
6862
6863 return TRUE;
6864 }
6865
nvEvoAllocRmCtrlObjectC3(NVDevEvoPtr pDevEvo)6866 NvBool nvEvoAllocRmCtrlObjectC3(NVDevEvoPtr pDevEvo)
6867 {
6868 const NvU32 handle = nvGenerateUnixRmHandle(&pDevEvo->handleAllocator);
6869
6870 /* Note that this object is not at all related to the GF100_DISP_SW (9072)
6871 * or NV50_DISPLAY_SW (5072) objects, despite their similarity in name. */
6872 NvU32 status = nvRmApiAlloc(nvEvoGlobal.clientHandle,
6873 pDevEvo->deviceHandle,
6874 handle,
6875 NVC372_DISPLAY_SW, NULL);
6876 if (status != NVOS_STATUS_SUCCESS) {
6877 nvAssert(!"Failed to allocate nvdisplay rmctrl object");
6878 goto fail;
6879 }
6880
6881 pDevEvo->rmCtrlHandle = handle;
6882
6883 return TRUE;
6884
6885 fail:
6886 nvFreeUnixRmHandle(&pDevEvo->handleAllocator, handle);
6887 return FALSE;
6888 }
6889
GetAccelerators(NVDevEvoPtr pDevEvo,NVEvoChannelPtr pChannel,NvU32 sd)6890 static NvU32 GetAccelerators(
6891 NVDevEvoPtr pDevEvo,
6892 NVEvoChannelPtr pChannel,
6893 NvU32 sd)
6894 {
6895 NVC370_CTRL_GET_ACCL_PARAMS params = { };
6896 NvU32 ret;
6897
6898 params.base.subdeviceIndex = sd;
6899 params.channelClass = pChannel->hwclass;
6900 nvAssert(pChannel->channelMask & NV_EVO_CHANNEL_MASK_WINDOW_ALL);
6901 params.channelInstance =
6902 NV_EVO_CHANNEL_MASK_WINDOW_NUMBER(pChannel->channelMask);
6903
6904 ret = nvRmApiControl(nvEvoGlobal.clientHandle,
6905 pDevEvo->displayHandle,
6906 NVC370_CTRL_CMD_GET_ACCL,
6907 ¶ms, sizeof(params));
6908 if (ret != NVOS_STATUS_SUCCESS) {
6909 nvEvoLogDevDebug(pDevEvo, EVO_LOG_ERROR,
6910 "Failed to retrieve accelerators");
6911 return 0;
6912 }
6913
6914 return params.accelerators;
6915 }
6916
SetAccelerators(NVDevEvoPtr pDevEvo,NVEvoChannelPtr pChannel,NvU32 sd,NvU32 accelerators,NvU32 accelMask)6917 static NvBool SetAccelerators(
6918 NVDevEvoPtr pDevEvo,
6919 NVEvoChannelPtr pChannel,
6920 NvU32 sd,
6921 NvU32 accelerators,
6922 NvU32 accelMask)
6923 {
6924 NVC370_CTRL_SET_ACCL_PARAMS params = { };
6925 NvU32 ret;
6926
6927 params.base.subdeviceIndex = sd;
6928 params.channelClass = pChannel->hwclass;
6929 nvAssert(pChannel->channelMask & NV_EVO_CHANNEL_MASK_WINDOW_ALL);
6930 params.channelInstance =
6931 NV_EVO_CHANNEL_MASK_WINDOW_NUMBER(pChannel->channelMask);
6932 params.accelerators = accelerators;
6933 params.accelMask = accelMask;
6934
6935 ret = nvRmApiControl(nvEvoGlobal.clientHandle,
6936 pDevEvo->displayHandle,
6937 NVC370_CTRL_CMD_SET_ACCL,
6938 ¶ms, sizeof(params));
6939 if (ret != NVOS_STATUS_SUCCESS) {
6940 nvEvoLogDevDebug(pDevEvo, EVO_LOG_ERROR,
6941 "Failed to set accelerators");
6942 return FALSE;
6943 }
6944
6945 return TRUE;
6946 }
6947
nvEvoAccelerateChannelC3(NVDevEvoPtr pDevEvo,NVEvoChannelPtr pChannel,const NvU32 sd,const NvBool trashPendingMethods,const NvBool unblockMethodsInExecutation,NvU32 * pOldAccelerators)6948 void nvEvoAccelerateChannelC3(NVDevEvoPtr pDevEvo,
6949 NVEvoChannelPtr pChannel,
6950 const NvU32 sd,
6951 const NvBool trashPendingMethods,
6952 const NvBool unblockMethodsInExecutation,
6953 NvU32 *pOldAccelerators)
6954 {
6955 NvU32 accelMask = 0x0;
6956
6957 if (trashPendingMethods) {
6958 accelMask |= NVC370_CTRL_ACCL_TRASH_ONLY;
6959 }
6960
6961 /* Start with a conservative set of accelerators; may need to add more
6962 * later. */
6963 if (unblockMethodsInExecutation) {
6964 accelMask |= NVC370_CTRL_ACCL_IGNORE_PI |
6965 NVC370_CTRL_ACCL_SKIP_SEMA |
6966 NVC370_CTRL_ACCL_IGNORE_FLIPLOCK;
6967 }
6968
6969 if (accelMask == 0x0) {
6970 return;
6971 }
6972
6973 *pOldAccelerators = GetAccelerators(pDevEvo, pChannel, sd);
6974
6975 /* Accelerate window channel. */
6976 if (!SetAccelerators(pDevEvo, pChannel, sd, accelMask, accelMask)) {
6977 nvAssert(!"Failed to set accelerators");
6978 }
6979 }
6980
nvEvoResetChannelAcceleratorsC3(NVDevEvoPtr pDevEvo,NVEvoChannelPtr pChannel,const NvU32 sd,const NvBool trashPendingMethods,const NvBool unblockMethodsInExecutation,NvU32 oldAccelerators)6981 void nvEvoResetChannelAcceleratorsC3(NVDevEvoPtr pDevEvo,
6982 NVEvoChannelPtr pChannel,
6983 const NvU32 sd,
6984 const NvBool trashPendingMethods,
6985 const NvBool unblockMethodsInExecutation,
6986 NvU32 oldAccelerators)
6987 {
6988 NvU32 accelMask = 0x0;
6989
6990 if (trashPendingMethods) {
6991 accelMask |= NVC370_CTRL_ACCL_TRASH_ONLY;
6992 }
6993
6994 /* Start with a conservative set of accelerators; may need to add more
6995 * later. */
6996 if (unblockMethodsInExecutation) {
6997 accelMask |= NVC370_CTRL_ACCL_IGNORE_PI |
6998 NVC370_CTRL_ACCL_SKIP_SEMA |
6999 NVC370_CTRL_ACCL_IGNORE_FLIPLOCK;
7000 }
7001
7002 if (accelMask == 0x0) {
7003 return;
7004 }
7005
7006 /* Accelerate window channel. */
7007 if (!SetAccelerators(pDevEvo, pChannel, sd, oldAccelerators, accelMask)) {
7008 nvAssert(!"Failed to set accelerators");
7009 }
7010 }
7011
ForceFlipToNull(NVDevEvoPtr pDevEvo,NVEvoChannelPtr pChannel,NvU32 sd,NVEvoUpdateState * updateState)7012 static void ForceFlipToNull(
7013 NVDevEvoPtr pDevEvo,
7014 NVEvoChannelPtr pChannel,
7015 NvU32 sd,
7016 NVEvoUpdateState *updateState)
7017 {
7018 NVFlipChannelEvoHwState hwState = { };
7019 const NvU32 subDeviceMask = (1 << sd);
7020
7021 nvPushEvoSubDevMask(pDevEvo, subDeviceMask);
7022
7023 pDevEvo->hal->Flip(pDevEvo, pChannel, &hwState, updateState,
7024 FALSE /* bypassComposition */);
7025
7026 nvPopEvoSubDevMask(pDevEvo);
7027 }
7028
PollForChannelIdle(NVDevEvoPtr pDevEvo,NVEvoChannelPtr pChannel,NvU32 sd)7029 static NvBool PollForChannelIdle(
7030 NVDevEvoPtr pDevEvo,
7031 NVEvoChannelPtr pChannel,
7032 NvU32 sd)
7033 {
7034 const NvU32 timeout = 2000000; // 2 seconds
7035 NvU64 startTime = 0;
7036 NvBool isMethodPending = TRUE;
7037
7038 do {
7039 if (!nvEvoIsChannelMethodPendingC3(pDevEvo, pChannel, sd,
7040 &isMethodPending)) {
7041 break;
7042 }
7043
7044 if (!isMethodPending) {
7045 break;
7046 }
7047
7048 if (nvExceedsTimeoutUSec(pDevEvo, &startTime, timeout)) {
7049 return FALSE;
7050 }
7051
7052 nvkms_yield();
7053
7054 } while (TRUE);
7055
7056 return TRUE;
7057 }
7058
7059 /*!
7060 * This function emulates the behavior of the STOP_BASE/STOP_OVERLAY RM control
7061 * calls for pre-EVO hardware.
7062 *
7063 * STOP_BASE/STOP_OVERLAY will apply hardware channel accelerators, push
7064 * methods via the debug interface to NULL context DMAs, and wait for the
7065 * channel to go idle (which means the surface programmed into the core channel
7066 * will become visible).
7067 *
7068 * If we asked RM to do the same thing for the window channel that is emulating
7069 * the base channel on nvdisplay, the display would just go black: there's no
7070 * surface in the core channel, so NULLing the context DMA in the window
7071 * channel will disable both "core" and "base".
7072 *
7073 * So instead, similar functionality is implemented here: we apply
7074 * accelerators, push methods to flip to core, and wait for the channel to
7075 * idle.
7076 */
7077 typedef struct {
7078 struct {
7079 NvU32 accelerators;
7080 NvBool overridden;
7081 } window[NVKMS_MAX_WINDOWS_PER_DISP];
7082 } EvoIdleChannelAcceleratorState;
7083
EvoForceIdleSatelliteChannelsWithAccel(NVDevEvoPtr pDevEvo,const NVEvoIdleChannelState * idleChannelState,const NvU32 accelMask)7084 static NvBool EvoForceIdleSatelliteChannelsWithAccel(
7085 NVDevEvoPtr pDevEvo,
7086 const NVEvoIdleChannelState *idleChannelState,
7087 const NvU32 accelMask)
7088 {
7089 NvU32 sd, window;
7090 NVEvoUpdateState updateState = { };
7091 NvBool ret = FALSE;
7092
7093 EvoIdleChannelAcceleratorState *pAcceleratorState = nvCalloc(
7094 pDevEvo->numSubDevices, sizeof(EvoIdleChannelAcceleratorState));
7095
7096 if (!pAcceleratorState) {
7097 nvEvoLogDevDebug(pDevEvo, EVO_LOG_ERROR,
7098 "Failed to alloc accelerator state");
7099 return FALSE;
7100 }
7101
7102 for (sd = 0; sd < pDevEvo->numSubDevices; sd++) {
7103 /*
7104 * Forcing a channel to be idle is currently only implemented for window
7105 * channels.
7106 */
7107 if ((idleChannelState->subdev[sd].channelMask &
7108 ~NV_EVO_CHANNEL_MASK_WINDOW_ALL) != 0) {
7109
7110 nvEvoLogDevDebug(pDevEvo, EVO_LOG_ERROR,
7111 "Forcing non-window channel idle not implemented");
7112 goto done;
7113 }
7114
7115 for (window = 0; window < pDevEvo->numWindows; window++) {
7116 if (FLD_IDX_TEST_DRF64(_EVO, _CHANNEL_MASK,
7117 _WINDOW, window, _ENABLE,
7118 idleChannelState->subdev[sd].channelMask)) {
7119 NVEvoChannelPtr pChannel = pDevEvo->window[window];
7120
7121 /* Save old window channel accelerators. */
7122 NvU32 oldAccel = GetAccelerators(pDevEvo, pChannel, sd);
7123
7124 pAcceleratorState[sd].window[window].accelerators =
7125 oldAccel;
7126
7127 /* Accelerate window channel. */
7128 if (!SetAccelerators(pDevEvo, pChannel, sd, accelMask,
7129 accelMask)) {
7130 nvEvoLogDevDebug(pDevEvo, EVO_LOG_ERROR,
7131 "Failed to set accelerators");
7132 goto done;
7133 }
7134 pAcceleratorState[sd].window[window].overridden = TRUE;
7135
7136 /* Push a flip to null in this channel. */
7137 ForceFlipToNull(pDevEvo, pChannel, sd, &updateState);
7138 }
7139 }
7140 }
7141
7142 /* Push one update for all of the flips programmed above. */
7143 nvEvoUpdateC3(pDevEvo, &updateState, TRUE /* releaseElv */);
7144
7145 for (sd = 0; sd < pDevEvo->numSubDevices; sd++) {
7146 for (window = 0; window < pDevEvo->numWindows; window++) {
7147 if (FLD_IDX_TEST_DRF64(_EVO, _CHANNEL_MASK, _WINDOW, window, _ENABLE,
7148 idleChannelState->subdev[sd].channelMask)) {
7149 NVEvoChannelPtr pChannel = pDevEvo->window[window];
7150
7151 /* Wait for the flips to complete. */
7152 if (!PollForChannelIdle(pDevEvo, pChannel, sd)) {
7153 nvEvoLogDevDebug(pDevEvo, EVO_LOG_ERROR,
7154 "Timed out while idling base channel");
7155 goto done;
7156 }
7157 }
7158 }
7159 }
7160
7161 ret = TRUE;
7162
7163 done:
7164 for (sd = 0; sd < pDevEvo->numSubDevices; sd++) {
7165 for (window = 0; window < pDevEvo->numWindows; window++) {
7166 if (FLD_IDX_TEST_DRF64(_EVO, _CHANNEL_MASK, _WINDOW, window, _ENABLE,
7167 idleChannelState->subdev[sd].channelMask)) {
7168 NVEvoChannelPtr pChannel = pDevEvo->window[window];
7169
7170 const NvU32 oldAccel =
7171 pAcceleratorState[sd].window[window].accelerators;
7172
7173 if (!pAcceleratorState[sd].window[window].overridden) {
7174 continue;
7175 }
7176
7177 /* Restore window channel accelerators. */
7178 if (!SetAccelerators(pDevEvo, pChannel, sd, oldAccel,
7179 accelMask)) {
7180 nvEvoLogDevDebug(pDevEvo, EVO_LOG_ERROR,
7181 "Failed to restore accelerators");
7182 }
7183 }
7184 }
7185 }
7186
7187 nvFree(pAcceleratorState);
7188 return ret;
7189 }
7190
nvEvoForceIdleSatelliteChannelC3(NVDevEvoPtr pDevEvo,const NVEvoIdleChannelState * idleChannelState)7191 NvBool nvEvoForceIdleSatelliteChannelC3(
7192 NVDevEvoPtr pDevEvo,
7193 const NVEvoIdleChannelState *idleChannelState)
7194 {
7195 /* Start with a conservative set of accelerators; may need to add more
7196 * later. */
7197 const NvU32 accelMask =
7198 NVC370_CTRL_ACCL_IGNORE_PI |
7199 NVC370_CTRL_ACCL_SKIP_SEMA;
7200
7201 return EvoForceIdleSatelliteChannelsWithAccel(pDevEvo,
7202 idleChannelState,
7203 accelMask);
7204 }
7205
nvEvoForceIdleSatelliteChannelIgnoreLockC3(NVDevEvoPtr pDevEvo,const NVEvoIdleChannelState * idleChannelState)7206 NvBool nvEvoForceIdleSatelliteChannelIgnoreLockC3(
7207 NVDevEvoPtr pDevEvo,
7208 const NVEvoIdleChannelState *idleChannelState)
7209 {
7210 const NvU32 accelMask =
7211 NVC370_CTRL_ACCL_IGNORE_PI |
7212 NVC370_CTRL_ACCL_SKIP_SEMA |
7213 NVC370_CTRL_ACCL_IGNORE_FLIPLOCK |
7214 NVC370_CTRL_ACCL_IGNORE_INTERLOCK;
7215
7216 return EvoForceIdleSatelliteChannelsWithAccel(pDevEvo,
7217 idleChannelState,
7218 accelMask);
7219 }
7220
nvEvoFreeRmCtrlObjectC3(NVDevEvoPtr pDevEvo)7221 void nvEvoFreeRmCtrlObjectC3(NVDevEvoPtr pDevEvo)
7222 {
7223 if (pDevEvo->rmCtrlHandle) {
7224 NvU32 status;
7225
7226 status = nvRmApiFree(nvEvoGlobal.clientHandle,
7227 pDevEvo->deviceHandle,
7228 pDevEvo->rmCtrlHandle);
7229
7230 if (status != NVOS_STATUS_SUCCESS) {
7231 nvAssert(!"Failed to free nvdisplay rmctrl object");
7232 }
7233
7234 nvFreeUnixRmHandle(&pDevEvo->handleAllocator, pDevEvo->rmCtrlHandle);
7235 pDevEvo->rmCtrlHandle = 0;
7236 }
7237 }
7238
nvEvoSetImmPointOutC3(NVDevEvoPtr pDevEvo,NVEvoChannelPtr pChannel,NvU32 sd,NVEvoUpdateState * updateState,NvU16 x,NvU16 y)7239 void nvEvoSetImmPointOutC3(NVDevEvoPtr pDevEvo,
7240 NVEvoChannelPtr pChannel,
7241 NvU32 sd,
7242 NVEvoUpdateState *updateState,
7243 NvU16 x, NvU16 y)
7244 {
7245 NVEvoChannelPtr pImmChannel = pChannel->imm.u.dma;
7246
7247 nvAssert((pChannel->channelMask & NV_EVO_CHANNEL_MASK_WINDOW_ALL) != 0);
7248 nvAssert(pChannel->imm.type == NV_EVO_IMM_CHANNEL_DMA);
7249
7250 /* This should only be called for one GPU at a time, since the
7251 * pre-nvdisplay version uses PIO and cannot broadcast. */
7252 nvAssert(ONEBITSET(nvPeekEvoSubDevMask(pDevEvo)));
7253
7254 nvDmaSetStartEvoMethod(pImmChannel,
7255 NVC37B_SET_POINT_OUT(0 /* Left eye */), 1);
7256
7257 nvDmaSetEvoMethodData(pImmChannel,
7258 DRF_NUM(C37B, _SET_POINT_OUT, _X, x) |
7259 DRF_NUM(C37B, _SET_POINT_OUT, _Y, y));
7260
7261 nvWinImmChannelUpdateState(pDevEvo, updateState, pChannel);
7262 }
7263
SetCrcSurfaceAddress(NVEvoChannelPtr pChannel,const NVSurfaceDescriptor * pSurfaceDesc,NvU32 head)7264 static void SetCrcSurfaceAddress(
7265 NVEvoChannelPtr pChannel,
7266 const NVSurfaceDescriptor *pSurfaceDesc,
7267 NvU32 head)
7268 {
7269 NvU32 ctxDmaHandle = pSurfaceDesc ? pSurfaceDesc->ctxDmaHandle : 0;
7270
7271 nvDmaSetStartEvoMethod(pChannel, NVC37D_HEAD_SET_CONTEXT_DMA_CRC(head), 1);
7272 nvDmaSetEvoMethodData(pChannel,
7273 DRF_NUM(C37D, _HEAD_SET_CONTEXT_DMA_CRC, _HANDLE, ctxDmaHandle));
7274 }
7275
EvoStartHeadCRC32CaptureC3(NVDevEvoPtr pDevEvo,NVEvoDmaPtr pDma,NVConnectorEvoPtr pConnectorEvo,const enum nvKmsTimingsProtocol protocol,const NvU32 orIndex,NvU32 head,NvU32 sd,NVEvoUpdateState * updateState)7276 static void EvoStartHeadCRC32CaptureC3(NVDevEvoPtr pDevEvo,
7277 NVEvoDmaPtr pDma,
7278 NVConnectorEvoPtr pConnectorEvo,
7279 const enum nvKmsTimingsProtocol protocol,
7280 const NvU32 orIndex,
7281 NvU32 head,
7282 NvU32 sd,
7283 NVEvoUpdateState *updateState)
7284 {
7285 const NvU32 winChannel = head << 1;
7286 NVEvoChannelPtr pChannel = pDevEvo->core;
7287 NvU32 orOutput = 0;
7288
7289 /* These method should only apply to a single pDpy */
7290 nvAssert(pDevEvo->subDevMaskStackDepth > 0);
7291
7292 /* The window channel should fit in
7293 * NVC37D_HEAD_SET_CRC_CONTROL_CONTROLLING_CHANNEL */
7294 nvAssert(winChannel < DRF_MASK(NVC37D_HEAD_SET_CRC_CONTROL_CONTROLLING_CHANNEL));
7295
7296 nvUpdateUpdateState(pDevEvo, updateState, pChannel);
7297
7298 switch (pConnectorEvo->or.type) {
7299 case NV0073_CTRL_SPECIFIC_OR_TYPE_SOR:
7300 if (protocol == NVKMS_PROTOCOL_SOR_DP_A ||
7301 protocol == NVKMS_PROTOCOL_SOR_DP_B) {
7302 orOutput = NVC37D_HEAD_SET_CRC_CONTROL_PRIMARY_CRC_SF;
7303 } else {
7304 orOutput =
7305 NVC37D_HEAD_SET_CRC_CONTROL_PRIMARY_CRC_SOR(orIndex);
7306 }
7307 break;
7308 case NV0073_CTRL_SPECIFIC_OR_TYPE_PIOR:
7309 orOutput =
7310 NVC37D_HEAD_SET_CRC_CONTROL_PRIMARY_CRC_PIOR(orIndex);
7311 break;
7312 case NV0073_CTRL_SPECIFIC_OR_TYPE_DAC:
7313 /* No DAC support on nvdisplay. Fall through. */
7314 default:
7315 nvAssert(!"Invalid pConnectorEvo->or.type");
7316 break;
7317 }
7318
7319 SetCrcSurfaceAddress(pChannel, &pDma->surfaceDesc, head);
7320
7321 nvDmaSetStartEvoMethod(pChannel, NVC37D_HEAD_SET_CRC_CONTROL(head), 1);
7322 nvDmaSetEvoMethodData(pChannel,
7323 DRF_NUM(C37D, _HEAD_SET_CRC_CONTROL, _PRIMARY_CRC, orOutput) |
7324 DRF_DEF(C37D, _HEAD_SET_CRC_CONTROL, _SECONDARY_CRC, _NONE) |
7325 DRF_NUM(C37D, _HEAD_SET_CRC_CONTROL, _CONTROLLING_CHANNEL, winChannel) |
7326 DRF_DEF(C37D, _HEAD_SET_CRC_CONTROL, _EXPECT_BUFFER_COLLAPSE, _FALSE) |
7327 DRF_DEF(C37D, _HEAD_SET_CRC_CONTROL, _CRC_DURING_SNOOZE, _DISABLE));
7328
7329 /* Reset the CRC notifier */
7330 nvEvoResetCRC32Notifier(pDma->subDeviceAddress[sd],
7331 NVC37D_NOTIFIER_CRC_STATUS_0,
7332 DRF_BASE(NVC37D_NOTIFIER_CRC_STATUS_0_DONE),
7333 NVC37D_NOTIFIER_CRC_STATUS_0_DONE_FALSE);
7334 }
7335
EvoStopHeadCRC32CaptureC3(NVDevEvoPtr pDevEvo,NvU32 head,NVEvoUpdateState * updateState)7336 static void EvoStopHeadCRC32CaptureC3(NVDevEvoPtr pDevEvo,
7337 NvU32 head,
7338 NVEvoUpdateState *updateState)
7339 {
7340 NVEvoChannelPtr pChannel = pDevEvo->core;
7341
7342 /* These method should only apply to a single pDpy */
7343 nvAssert(pDevEvo->subDevMaskStackDepth > 0);
7344
7345 nvUpdateUpdateState(pDevEvo, updateState, pChannel);
7346
7347 SetCrcSurfaceAddress(pChannel, NULL /* pSurfaceDesc */, head);
7348
7349 nvDmaSetStartEvoMethod(pChannel, NVC37D_HEAD_SET_CRC_CONTROL(head), 1);
7350 nvDmaSetEvoMethodData(pChannel,
7351 DRF_DEF(C37D, _HEAD_SET_CRC_CONTROL, _PRIMARY_CRC, _NONE) |
7352 DRF_DEF(C37D, _HEAD_SET_CRC_CONTROL, _SECONDARY_CRC, _NONE) |
7353 DRF_NUM(C37D, _HEAD_SET_CRC_CONTROL, _CONTROLLING_CHANNEL, 0) |
7354 DRF_DEF(C37D, _HEAD_SET_CRC_CONTROL, _EXPECT_BUFFER_COLLAPSE, _FALSE) |
7355 DRF_DEF(C37D, _HEAD_SET_CRC_CONTROL, _CRC_DURING_SNOOZE, _DISABLE));
7356 }
7357
7358 /*!
7359 * Queries the current head's CRC Notifier and returns values if successful
7360 *
7361 * First waits for hardware to finish writing to the CRC32Notifier,
7362 * and performs a read of the Compositor, SF/OR CRCs,
7363 * and the RG CRC in numCRC32 frames.
7364 * Crc fields in input array crc32 should be calloc'd to 0s.
7365 *
7366 * \param[in] pDevEvo NVKMS device pointer
7367 * \param[in] pDma Pointer to DMA-mapped memory
7368 * \param[in] sd Subdevice index
7369 * \param[in] entry_count Number of independent frames to read CRCs from
7370 * \param[out] crc32 Contains pointers to CRC output arrays
7371 * \param[out] numCRC32 Number of CRC frames successfully read from DMA
7372 *
7373 * \return Returns TRUE if was able to successfully read CRCs from DMA,
7374 * otherwise FALSE
7375 */
nvEvoQueryHeadCRC32_C3(NVDevEvoPtr pDevEvo,NVEvoDmaPtr pDma,NvU32 sd,NvU32 entry_count,CRC32NotifierCrcOut * crc32,NvU32 * numCRC32)7376 NvBool nvEvoQueryHeadCRC32_C3(NVDevEvoPtr pDevEvo,
7377 NVEvoDmaPtr pDma,
7378 NvU32 sd,
7379 NvU32 entry_count,
7380 CRC32NotifierCrcOut *crc32,
7381 NvU32 *numCRC32)
7382 {
7383 volatile NvU32 *pCRC32Notifier = pDma->subDeviceAddress[sd];
7384 const NvU32 entry_stride =
7385 NVC37D_NOTIFIER_CRC_CRC_ENTRY1_21 - NVC37D_NOTIFIER_CRC_CRC_ENTRY0_13;
7386 // Define how many/which variables to read from each CRCNotifierEntry struct
7387 const CRC32NotifierEntryRec field_info[NV_EVO3_NUM_CRC_FIELDS] = {
7388 {
7389 .field_offset = NVC37D_NOTIFIER_CRC_CRC_ENTRY0_11,
7390 .field_base_bit =
7391 DRF_BASE(NVC37D_NOTIFIER_CRC_CRC_ENTRY0_11_COMPOSITOR_CRC),
7392 .field_extent_bit =
7393 DRF_EXTENT(NVC37D_NOTIFIER_CRC_CRC_ENTRY0_11_COMPOSITOR_CRC),
7394 .field_frame_values = crc32->compositorCrc32,
7395 },
7396 {
7397 .field_offset = NVC37D_NOTIFIER_CRC_CRC_ENTRY0_12,
7398 .field_base_bit =
7399 DRF_BASE(NVC37D_NOTIFIER_CRC_CRC_ENTRY0_12_RG_CRC),
7400 .field_extent_bit =
7401 DRF_EXTENT(NVC37D_NOTIFIER_CRC_CRC_ENTRY0_12_RG_CRC),
7402 .field_frame_values = crc32->rasterGeneratorCrc32,
7403 },
7404 {
7405 .field_offset = NVC37D_NOTIFIER_CRC_CRC_ENTRY0_13,
7406 .field_base_bit =
7407 DRF_BASE(NVC37D_NOTIFIER_CRC_CRC_ENTRY0_13_PRIMARY_OUTPUT_CRC),
7408 .field_extent_bit =
7409 DRF_EXTENT(NVC37D_NOTIFIER_CRC_CRC_ENTRY0_13_PRIMARY_OUTPUT_CRC),
7410 .field_frame_values = crc32->outputCrc32
7411 }
7412 };
7413
7414 const CRC32NotifierEntryFlags flag_info[NV_EVO3_NUM_CRC_FLAGS] = {
7415 {
7416 .flag_base_bit =
7417 DRF_BASE(NVC37D_NOTIFIER_CRC_STATUS_0_COUNT),
7418 .flag_extent_bit =
7419 DRF_EXTENT(NVC37D_NOTIFIER_CRC_STATUS_0_COUNT),
7420 .flag_type = NVEvoCrc32NotifierFlagCount
7421 },
7422 {
7423 .flag_base_bit =
7424 DRF_BASE(NVC37D_NOTIFIER_CRC_STATUS_0_COMPOSITOR_OVERFLOW),
7425 .flag_extent_bit =
7426 DRF_EXTENT(NVC37D_NOTIFIER_CRC_STATUS_0_COMPOSITOR_OVERFLOW),
7427 .flag_type = NVEvoCrc32NotifierFlagCrcOverflow
7428 },
7429 {
7430 .flag_base_bit =
7431 DRF_BASE(NVC37D_NOTIFIER_CRC_STATUS_0_RG_OVERFLOW),
7432 .flag_extent_bit =
7433 DRF_EXTENT(NVC37D_NOTIFIER_CRC_STATUS_0_RG_OVERFLOW),
7434 .flag_type = NVEvoCrc32NotifierFlagCrcOverflow
7435 },
7436 {
7437 .flag_base_bit =
7438 DRF_BASE(NVC37D_NOTIFIER_CRC_STATUS_0_PRIMARY_OUTPUT_OVERFLOW),
7439 .flag_extent_bit =
7440 DRF_EXTENT(NVC37D_NOTIFIER_CRC_STATUS_0_PRIMARY_OUTPUT_OVERFLOW),
7441 .flag_type = NVEvoCrc32NotifierFlagCrcOverflow
7442 }
7443 };
7444
7445 if (!nvEvoWaitForCRC32Notifier(pDevEvo,
7446 pCRC32Notifier,
7447 NVC37D_NOTIFIER_CRC_STATUS_0,
7448 DRF_BASE(NVC37D_NOTIFIER_CRC_STATUS_0_DONE),
7449 DRF_EXTENT(NVC37D_NOTIFIER_CRC_STATUS_0_DONE),
7450 NVC37D_NOTIFIER_CRC_STATUS_0_DONE_TRUE)) {
7451 return FALSE;
7452 }
7453
7454 *numCRC32 = nvEvoReadCRC32Notifier(pCRC32Notifier,
7455 entry_stride,
7456 entry_count,
7457 NVC37D_NOTIFIER_CRC_STATUS_0, /* Status offset */
7458 NV_EVO3_NUM_CRC_FIELDS,
7459 NV_EVO3_NUM_CRC_FLAGS,
7460 field_info,
7461 flag_info);
7462
7463 nvEvoResetCRC32Notifier(pCRC32Notifier,
7464 NVC37D_NOTIFIER_CRC_STATUS_0,
7465 DRF_BASE(NVC37D_NOTIFIER_CRC_STATUS_0_DONE),
7466 NVC37D_NOTIFIER_CRC_STATUS_0_DONE_FALSE);
7467
7468 return TRUE;
7469 }
7470
nvEvoGetScanLineC3(const NVDispEvoRec * pDispEvo,const NvU32 head,NvU16 * pScanLine,NvBool * pInBlankingPeriod)7471 void nvEvoGetScanLineC3(const NVDispEvoRec *pDispEvo,
7472 const NvU32 head,
7473 NvU16 *pScanLine,
7474 NvBool *pInBlankingPeriod)
7475 {
7476 const NVDevEvoRec *pDevEvo = pDispEvo->pDevEvo;
7477 const NvU32 sd = pDispEvo->displayOwner;
7478 const NvU32 window = head << 1;
7479 void *pDma = pDevEvo->window[window]->pb.control[sd];
7480 const NvU32 scanLine = nvDmaLoadPioMethod(pDma, NVC37E_GET_LINE);
7481
7482 if ((scanLine & NVBIT(15)) == 0) {
7483 *pInBlankingPeriod = FALSE;
7484 *pScanLine = scanLine & DRF_MASK(14:0);
7485 } else {
7486 *pInBlankingPeriod = TRUE;
7487 }
7488 }
7489
7490 /*
7491 * This method configures and programs the RG Core Semaphores. Default behavior
7492 * is to continuously trigger on the specified rasterline when enabled.
7493 */
7494 static void
EvoConfigureVblankSyncObjectC6(const NVDevEvoPtr pDevEvo,const NvU16 rasterLine,const NvU32 head,const NvU32 semaphoreIndex,const NVSurfaceDescriptor * pSurfaceDesc,NVEvoUpdateState * pUpdateState)7495 EvoConfigureVblankSyncObjectC6(const NVDevEvoPtr pDevEvo,
7496 const NvU16 rasterLine,
7497 const NvU32 head,
7498 const NvU32 semaphoreIndex,
7499 const NVSurfaceDescriptor *pSurfaceDesc,
7500 NVEvoUpdateState* pUpdateState)
7501 {
7502 NVEvoChannelPtr pChannel = pDevEvo->core;
7503
7504 /*
7505 * Populate the NVEvoUpdateState for the caller. The Update State contains
7506 * a mask of which display channels need to be updated.
7507 */
7508 nvUpdateUpdateState(pDevEvo, pUpdateState, pChannel);
7509
7510 /*
7511 * Tell HW what ctxdma entry to use to look up actual RG semaphore surface.
7512 * If ctxdma handle is 0, HW will disable the semaphore.
7513 */
7514 nvDmaSetStartEvoMethod(pChannel,
7515 NVC67D_HEAD_SET_CONTEXT_DMA_RG_REL_SEMAPHORE(head, semaphoreIndex),
7516 1);
7517 nvDmaSetEvoMethodData(pChannel,
7518 DRF_NUM(C67D, _HEAD_SET_CONTEXT_DMA_RG_REL_SEMAPHORE, _HANDLE,
7519 (pSurfaceDesc == NULL) ? 0 : pSurfaceDesc->ctxDmaHandle));
7520
7521 if ((pSurfaceDesc == NULL) || (pSurfaceDesc->ctxDmaHandle == 0)) {
7522 /* Disabling semaphore so no configuration necessary. */
7523 return;
7524 }
7525
7526 /*
7527 * Configure the semaphore with the following:
7528 * Set OFFSET to 0 (default).
7529 * Set PAYLOAD_SIZE to 32bits (default).
7530 * Set REL_MODE to WRITE (default).
7531 * Set RUN_MODE to CONTINUOUS.
7532 * Set RASTER_LINE to start of Vblank: Vsync + Vbp + Vactive.
7533 *
7534 * Note that all these options together fit in 32bits, and that all 32 bits
7535 * must be written each time any given option changes.
7536 *
7537 * The actual payload value doesn't currently matter since this RG
7538 * semaphore will be mapped to a syncpt for now. Each HW-issued payload
7539 * write is converted to a single syncpt increment irrespective of what the
7540 * actual semaphore payload value is.
7541 */
7542 nvDmaSetStartEvoMethod(pChannel,
7543 NVC67D_HEAD_SET_RG_REL_SEMAPHORE_CONTROL(head, semaphoreIndex),
7544 1);
7545 nvDmaSetEvoMethodData(pChannel,
7546 DRF_NUM(C67D, _HEAD_SET_RG_REL_SEMAPHORE_CONTROL, _OFFSET, 0) |
7547 DRF_DEF(C67D, _HEAD_SET_RG_REL_SEMAPHORE_CONTROL, _PAYLOAD_SIZE,
7548 _PAYLOAD_32BIT) |
7549 DRF_DEF(C67D, _HEAD_SET_RG_REL_SEMAPHORE_CONTROL, _REL_MODE,
7550 _WRITE) |
7551 DRF_DEF(C67D, _HEAD_SET_RG_REL_SEMAPHORE_CONTROL, _RUN_MODE,
7552 _CONTINUOUS) |
7553 DRF_NUM(C67D, _HEAD_SET_RG_REL_SEMAPHORE_CONTROL, _RASTER_LINE,
7554 rasterLine));
7555 }
7556
EvoSetHdmiDscParams(const NVDispEvoRec * pDispEvo,const NvU32 head,const NVDscInfoEvoRec * pDscInfo,const enum nvKmsPixelDepth pixelDepth)7557 static void EvoSetHdmiDscParams(const NVDispEvoRec *pDispEvo,
7558 const NvU32 head,
7559 const NVDscInfoEvoRec *pDscInfo,
7560 const enum nvKmsPixelDepth pixelDepth)
7561 {
7562 NVEvoChannelPtr pChannel = pDispEvo->pDevEvo->core;
7563 NvU32 bpc, flatnessDetThresh;
7564 NvU32 i;
7565
7566 nvAssert(pDispEvo->pDevEvo->hal->caps.supportsHDMIFRL &&
7567 pDscInfo->type == NV_DSC_INFO_EVO_TYPE_HDMI);
7568
7569 bpc = nvPixelDepthToBitsPerComponent(pixelDepth);
7570 if (bpc < 8) {
7571 nvAssert(bpc >= 8);
7572 bpc = 8;
7573 }
7574 flatnessDetThresh = (2 << (bpc - 8));
7575
7576 nvDmaSetStartEvoMethod(pChannel, NVC67D_HEAD_SET_DSC_CONTROL(head), 1);
7577 nvDmaSetEvoMethodData(pChannel,
7578 DRF_DEF(C67D, _HEAD_SET_DSC_CONTROL, _ENABLE, _TRUE) |
7579 ((pDscInfo->hdmi.dscMode == NV_DSC_EVO_MODE_DUAL) ?
7580 DRF_DEF(C57D, _HEAD_SET_DSC_CONTROL, _MODE, _DUAL) :
7581 DRF_DEF(C57D, _HEAD_SET_DSC_CONTROL, _MODE, _SINGLE)) |
7582 DRF_NUM(C67D, _HEAD_SET_DSC_CONTROL, _FLATNESS_DET_THRESH, flatnessDetThresh) |
7583 DRF_DEF(C67D, _HEAD_SET_DSC_CONTROL, _FULL_ICH_ERR_PRECISION, _ENABLE) |
7584 DRF_DEF(C67D, _HEAD_SET_DSC_CONTROL, _AUTO_RESET, _ENABLE) |
7585 DRF_DEF(C67D, _HEAD_SET_DSC_CONTROL, _FORCE_ICH_RESET, _FALSE));
7586
7587 nvDmaSetStartEvoMethod(pChannel, NVC67D_HEAD_SET_DSC_PPS_CONTROL(head), 1);
7588 nvDmaSetEvoMethodData(pChannel,
7589 DRF_DEF(C67D, _HEAD_SET_DSC_PPS_CONTROL, _ENABLE, _TRUE) |
7590 DRF_DEF(C67D, _HEAD_SET_DSC_PPS_CONTROL, _LOCATION, _VBLANK) |
7591 DRF_DEF(C67D, _HEAD_SET_DSC_PPS_CONTROL, _FREQUENCY, _EVERY_FRAME) |
7592 /* MFS says "For FRL DSC CVTEM, it should be 0x21 (136bytes)." */
7593 DRF_NUM(C67D, _HEAD_SET_DSC_PPS_CONTROL, _SIZE, 0x21));
7594
7595 /* The loop below assumes the methods are tightly packed. */
7596 ct_assert(ARRAY_LEN(pDscInfo->hdmi.pps) == 32);
7597 ct_assert((NVC67D_HEAD_SET_DSC_PPS_DATA1(0) - NVC67D_HEAD_SET_DSC_PPS_DATA0(0)) == 4);
7598 ct_assert((NVC67D_HEAD_SET_DSC_PPS_DATA31(0) - NVC67D_HEAD_SET_DSC_PPS_DATA0(0)) == (31 * 4));
7599 for (i = 0; i < ARRAY_LEN(pDscInfo->hdmi.pps); i++) {
7600 nvDmaSetStartEvoMethod(pChannel, NVC67D_HEAD_SET_DSC_PPS_DATA0(head) + (i * 4), 1);
7601 nvDmaSetEvoMethodData(pChannel, pDscInfo->hdmi.pps[i]);
7602 }
7603
7604 /* Byte 0 must be 0x7f, the rest are don't care (will be filled in by HW) */
7605 nvDmaSetStartEvoMethod(pChannel, NVC67D_HEAD_SET_DSC_PPS_HEAD(head), 1);
7606 nvDmaSetEvoMethodData(pChannel,
7607 DRF_NUM(C67D, _HEAD_SET_DSC_PPS_HEAD, _BYTE0, 0x7f));
7608
7609 nvDmaSetStartEvoMethod(pChannel, NVC67D_HEAD_SET_HDMI_DSC_HCACTIVE(head), 1);
7610 nvDmaSetEvoMethodData(pChannel,
7611 DRF_NUM(C67D, _HEAD_SET_HDMI_DSC_HCACTIVE, _BYTES, pDscInfo->hdmi.dscHActiveBytes) |
7612 DRF_NUM(C67D, _HEAD_SET_HDMI_DSC_HCACTIVE, _TRI_BYTES, pDscInfo->hdmi.dscHActiveTriBytes));
7613 nvDmaSetStartEvoMethod(pChannel, NVC67D_HEAD_SET_HDMI_DSC_HCBLANK(head), 1);
7614 nvDmaSetEvoMethodData(pChannel,
7615 DRF_NUM(C67D, _HEAD_SET_HDMI_DSC_HCBLANK, _WIDTH, pDscInfo->hdmi.dscHBlankTriBytes));
7616 }
7617
EvoSetDpDscParams(const NVDispEvoRec * pDispEvo,const NvU32 head,const NVDscInfoEvoRec * pDscInfo)7618 static void EvoSetDpDscParams(const NVDispEvoRec *pDispEvo,
7619 const NvU32 head,
7620 const NVDscInfoEvoRec *pDscInfo)
7621 {
7622 NVEvoChannelPtr pChannel = pDispEvo->pDevEvo->core;
7623 NvU32 flatnessDetThresh;
7624 NvU32 i;
7625
7626 nvAssert(pDscInfo->type == NV_DSC_INFO_EVO_TYPE_DP);
7627
7628 // XXX: I'm pretty sure that this is wrong.
7629 // BitsPerPixelx16 is something like (24 * 16) = 384, and 2 << (384 - 8) is
7630 // an insanely large number.
7631 flatnessDetThresh = (2 << (pDscInfo->dp.bitsPerPixelX16 - 8)); /* ??? */
7632
7633 nvAssert((pDscInfo->dp.dscMode == NV_DSC_EVO_MODE_DUAL) ||
7634 (pDscInfo->dp.dscMode == NV_DSC_EVO_MODE_SINGLE));
7635
7636 nvDmaSetStartEvoMethod(pChannel, NVC57D_HEAD_SET_DSC_CONTROL(head), 1);
7637 nvDmaSetEvoMethodData(pChannel,
7638 DRF_DEF(C57D, _HEAD_SET_DSC_CONTROL, _ENABLE, _TRUE) |
7639 ((pDscInfo->dp.dscMode == NV_DSC_EVO_MODE_DUAL) ?
7640 DRF_DEF(C57D, _HEAD_SET_DSC_CONTROL, _MODE, _DUAL) :
7641 DRF_DEF(C57D, _HEAD_SET_DSC_CONTROL, _MODE, _SINGLE)) |
7642 DRF_NUM(C57D, _HEAD_SET_DSC_CONTROL, _FLATNESS_DET_THRESH, flatnessDetThresh) |
7643 DRF_DEF(C57D, _HEAD_SET_DSC_CONTROL, _FULL_ICH_ERR_PRECISION, _ENABLE) |
7644 DRF_DEF(C57D, _HEAD_SET_DSC_CONTROL, _AUTO_RESET, _DISABLE) |
7645 DRF_DEF(C57D, _HEAD_SET_DSC_CONTROL, _FORCE_ICH_RESET, _TRUE));
7646
7647 nvDmaSetStartEvoMethod(pChannel, NVC57D_HEAD_SET_DSC_PPS_CONTROL(head), 1);
7648 nvDmaSetEvoMethodData(pChannel,
7649 DRF_DEF(C57D, _HEAD_SET_DSC_PPS_CONTROL, _ENABLE, _TRUE) |
7650 DRF_DEF(C57D, _HEAD_SET_DSC_PPS_CONTROL, _LOCATION, _VSYNC) |
7651 DRF_DEF(C57D, _HEAD_SET_DSC_PPS_CONTROL, _FREQUENCY, _EVERY_FRAME) |
7652 DRF_NUM(C57D, _HEAD_SET_DSC_PPS_CONTROL, _SIZE, 0x1F /* 32 PPS Dwords - 1 = 31 */));
7653
7654
7655 #define NV_EVO5_NUM_HEAD_SET_DSC_PPS_DATA_DWORDS \
7656 (((NVC57D_HEAD_SET_DSC_PPS_DATA31(0) - NVC57D_HEAD_SET_DSC_PPS_DATA0(0)) / 4) + 1)
7657
7658 ct_assert(NV_EVO5_NUM_HEAD_SET_DSC_PPS_DATA_DWORDS <= ARRAY_LEN(pDscInfo->dp.pps));
7659
7660 for (i = 0; i < NV_EVO5_NUM_HEAD_SET_DSC_PPS_DATA_DWORDS; i++) {
7661 nvDmaSetStartEvoMethod(pChannel,(NVC57D_HEAD_SET_DSC_PPS_DATA0(head) + (i * 4)), 1);
7662 nvDmaSetEvoMethodData(pChannel, pDscInfo->dp.pps[i]);
7663 }
7664
7665 /*
7666 * In case of DP, PPS is sent using the SDP over the Main-Link
7667 * during the vertical blanking interval. The PPS SDP header is defined
7668 * in DP 1.4 specification under section 2.2.5.9.1.
7669 */
7670
7671 nvDmaSetStartEvoMethod(pChannel,
7672 NVC57D_HEAD_SET_DSC_PPS_HEAD(head), 1);
7673 nvDmaSetEvoMethodData(pChannel,
7674 DRF_NUM(C57D, _HEAD_SET_DSC_PPS_HEAD, _BYTE0, 0x00) | /* SDP ID = 0x0 */
7675 DRF_NUM(C57D, _HEAD_SET_DSC_PPS_HEAD, _BYTE1, 0x10) | /* SDP Type = 0x10 */
7676 DRF_NUM(C57D, _HEAD_SET_DSC_PPS_HEAD, _BYTE2, 0x7f) | /* Number of payload data bytes - 1 = 0x7F */
7677 DRF_NUM(C57D, _HEAD_SET_DSC_PPS_HEAD, _BYTE3, 0x00)); /* Reserved */
7678 }
7679
EvoSetDscParamsC5(const NVDispEvoRec * pDispEvo,const NvU32 head,const NVDscInfoEvoRec * pDscInfo,const enum nvKmsPixelDepth pixelDepth)7680 static void EvoSetDscParamsC5(const NVDispEvoRec *pDispEvo,
7681 const NvU32 head,
7682 const NVDscInfoEvoRec *pDscInfo,
7683 const enum nvKmsPixelDepth pixelDepth)
7684 {
7685 if (pDscInfo->type == NV_DSC_INFO_EVO_TYPE_HDMI) {
7686 EvoSetHdmiDscParams(pDispEvo, head, pDscInfo, pixelDepth);
7687 } else if (pDscInfo->type == NV_DSC_INFO_EVO_TYPE_DP) {
7688 EvoSetDpDscParams(pDispEvo, head, pDscInfo);
7689 } else {
7690 NVEvoChannelPtr pChannel = pDispEvo->pDevEvo->core;
7691
7692 nvAssert(pDscInfo->type == NV_DSC_INFO_EVO_TYPE_DISABLED);
7693
7694 /* Disable DSC function */
7695 nvDmaSetStartEvoMethod(pChannel, NVC57D_HEAD_SET_DSC_CONTROL(head), 1);
7696 nvDmaSetEvoMethodData(pChannel,
7697 DRF_DEF(C57D, _HEAD_SET_DSC_CONTROL, _ENABLE, _FALSE));
7698
7699 /* Disable PPS SDP (Secondary-Data Packet), DP won't send out PPS SDP */
7700 nvDmaSetStartEvoMethod(pChannel, NVC57D_HEAD_SET_DSC_PPS_CONTROL(head), 1);
7701 nvDmaSetEvoMethodData(pChannel,
7702 DRF_DEF(C57D, _HEAD_SET_DSC_PPS_CONTROL, _ENABLE, _FALSE));
7703 }
7704 }
7705
7706 static void
EvoEnableMidFrameAndDWCFWatermarkC5(NVDevEvoPtr pDevEvo,NvU32 sd,NvU32 head,NvBool enable,NVEvoUpdateState * pUpdateState)7707 EvoEnableMidFrameAndDWCFWatermarkC5(NVDevEvoPtr pDevEvo,
7708 NvU32 sd,
7709 NvU32 head,
7710 NvBool enable,
7711 NVEvoUpdateState *pUpdateState)
7712 {
7713 NVEvoChannelPtr pChannel = pDevEvo->core;
7714
7715 if (enable) {
7716 pDevEvo->gpus[sd].setSwSpareA[head] =
7717 FLD_SET_DRF(C37D,
7718 _HEAD_SET_SW_SPARE_A,
7719 _DISABLE_MID_FRAME_AND_DWCF_WATERMARK,
7720 _FALSE,
7721 pDevEvo->gpus[sd].setSwSpareA[head]);
7722 } else {
7723 pDevEvo->gpus[sd].setSwSpareA[head] =
7724 FLD_SET_DRF(C37D,
7725 _HEAD_SET_SW_SPARE_A,
7726 _DISABLE_MID_FRAME_AND_DWCF_WATERMARK,
7727 _TRUE,
7728 pDevEvo->gpus[sd].setSwSpareA[head]);
7729 }
7730
7731 nvPushEvoSubDevMask(pDevEvo, NVBIT(sd));
7732
7733 nvUpdateUpdateState(pDevEvo, pUpdateState, pChannel);
7734
7735 nvDmaSetStartEvoMethod(pChannel, NVC37D_HEAD_SET_SW_SPARE_A(head), 1);
7736 nvDmaSetEvoMethodData(pChannel, pDevEvo->gpus[sd].setSwSpareA[head]);
7737
7738 nvPopEvoSubDevMask(pDevEvo);
7739 }
7740
nvEvoGetActiveViewportOffsetC3(NVDispEvoRec * pDispEvo,NvU32 head)7741 NvU32 nvEvoGetActiveViewportOffsetC3(NVDispEvoRec *pDispEvo, NvU32 head)
7742 {
7743 NVC372_CTRL_CMD_GET_ACTIVE_VIEWPORT_POINT_IN_PARAMS params = { };
7744 NvU32 ret;
7745 NVDevEvoRec *pDevEvo = pDispEvo->pDevEvo;
7746
7747 params.base.subdeviceIndex = pDispEvo->displayOwner;
7748 params.windowIndex = head << 1;
7749
7750 ret = nvRmApiControl(nvEvoGlobal.clientHandle,
7751 pDevEvo->rmCtrlHandle,
7752 NVC372_CTRL_CMD_GET_ACTIVE_VIEWPORT_POINT_IN,
7753 ¶ms, sizeof(params));
7754
7755 if (ret != NVOS_STATUS_SUCCESS) {
7756 nvEvoLogDevDebug(pDevEvo, EVO_LOG_ERROR,
7757 "Failed to query active viewport offset");
7758 }
7759
7760 return params.activeViewportPointIn.y;
7761 }
7762
EvoComputeWindowScalingTapsC3(const NVDevEvoRec * pDevEvo,const NVEvoChannel * pChannel,NVFlipChannelEvoHwState * pHwState)7763 static NvBool EvoComputeWindowScalingTapsC3(const NVDevEvoRec *pDevEvo,
7764 const NVEvoChannel *pChannel,
7765 NVFlipChannelEvoHwState *pHwState)
7766 {
7767 NvU32 win = NV_EVO_CHANNEL_MASK_WINDOW_NUMBER(pChannel->channelMask);
7768 const NVEvoScalerCaps *pScalerCaps =
7769 &pDevEvo->gpus[0].capabilities.window[win].scalerCaps;
7770
7771 if (!nvAssignScalerTaps(pDevEvo,
7772 pScalerCaps,
7773 pHwState->sizeIn.width, pHwState->sizeIn.height,
7774 pHwState->sizeOut.width, pHwState->sizeOut.height,
7775 FALSE /* doubleScan */,
7776 &pHwState->hTaps, &pHwState->vTaps)) {
7777 return FALSE;
7778 }
7779
7780 return TRUE;
7781 }
7782
nvEvoComputeWindowScalingTapsC5(const NVDevEvoRec * pDevEvo,const NVEvoChannel * pChannel,NVFlipChannelEvoHwState * pHwState)7783 NvBool nvEvoComputeWindowScalingTapsC5(const NVDevEvoRec *pDevEvo,
7784 const NVEvoChannel *pChannel,
7785 NVFlipChannelEvoHwState *pHwState)
7786 {
7787 if (!EvoComputeWindowScalingTapsC3(pDevEvo, pChannel, pHwState)) {
7788 return FALSE;
7789 }
7790
7791 /*
7792 * If scaling is enabled, CSC11 will be used by NVKMS to convert from
7793 * linear FP16 LMS to linear FP16 RGB. As such, the user-supplied precomp
7794 * CSC can't be programmed into CSC11 in this case.
7795 */
7796 if ((pHwState->sizeIn.width != pHwState->sizeOut.width) ||
7797 (pHwState->sizeIn.height != pHwState->sizeOut.height)) {
7798 if (!nvIsCscMatrixIdentity(&pHwState->cscMatrix)) {
7799 return FALSE;
7800 }
7801 }
7802
7803 return TRUE;
7804 }
7805
EvoSetMergeModeC5(const NVDispEvoRec * pDispEvo,const NvU32 head,const NVEvoMergeMode mode,NVEvoUpdateState * pUpdateState)7806 static void EvoSetMergeModeC5(const NVDispEvoRec *pDispEvo,
7807 const NvU32 head,
7808 const NVEvoMergeMode mode,
7809 NVEvoUpdateState* pUpdateState)
7810 {
7811 NVDevEvoRec *pDevEvo = pDispEvo->pDevEvo;
7812 NVEvoChannelPtr pChannel = pDevEvo->core;
7813 NvU32 data = 0x0;
7814
7815 nvPushEvoSubDevMask(pDevEvo, NVBIT(pDispEvo->displayOwner));
7816
7817 nvUpdateUpdateState(pDevEvo, pUpdateState, pChannel);
7818
7819 switch (mode) {
7820 case NV_EVO_MERGE_MODE_DISABLED:
7821 data = DRF_DEF(C57D, _HEAD_SET_RG_MERGE, _MODE, _DISABLE);
7822 break;
7823 case NV_EVO_MERGE_MODE_SETUP:
7824 data = DRF_DEF(C57D, _HEAD_SET_RG_MERGE, _MODE, _SETUP);
7825 break;
7826 case NV_EVO_MERGE_MODE_PRIMARY:
7827 data = DRF_DEF(C57D, _HEAD_SET_RG_MERGE, _MODE, _MASTER);
7828 break;
7829 case NV_EVO_MERGE_MODE_SECONDARY:
7830 data = DRF_DEF(C57D, _HEAD_SET_RG_MERGE, _MODE, _SLAVE);
7831 break;
7832 }
7833
7834 nvDmaSetStartEvoMethod(pChannel, NVC57D_HEAD_SET_RG_MERGE(head), 1);
7835 nvDmaSetEvoMethodData(pChannel, data);
7836
7837 nvPopEvoSubDevMask(pDevEvo);
7838 }
7839
EvoAllocSurfaceDescriptorC3(NVDevEvoPtr pDevEvo,NVSurfaceDescriptor * pSurfaceDesc,NvU32 memoryHandle,NvU32 localCtxDmaFlags,NvU64 limit)7840 static NvU32 EvoAllocSurfaceDescriptorC3(
7841 NVDevEvoPtr pDevEvo, NVSurfaceDescriptor *pSurfaceDesc,
7842 NvU32 memoryHandle, NvU32 localCtxDmaFlags,
7843 NvU64 limit)
7844 {
7845 return nvCtxDmaAlloc(pDevEvo, &pSurfaceDesc->ctxDmaHandle,
7846 memoryHandle,
7847 localCtxDmaFlags, limit);
7848 }
7849
EvoFreeSurfaceDescriptorC3(NVDevEvoPtr pDevEvo,NvU32 deviceHandle,NVSurfaceDescriptor * pSurfaceDesc)7850 static void EvoFreeSurfaceDescriptorC3(
7851 NVDevEvoPtr pDevEvo,
7852 NvU32 deviceHandle,
7853 NVSurfaceDescriptor *pSurfaceDesc)
7854 {
7855 nvCtxDmaFree(pDevEvo, deviceHandle, &pSurfaceDesc->ctxDmaHandle);
7856 }
7857
EvoBindSurfaceDescriptorC3(NVDevEvoPtr pDevEvo,NVEvoChannelPtr pChannel,NVSurfaceDescriptor * pSurfaceDesc)7858 static NvU32 EvoBindSurfaceDescriptorC3(
7859 NVDevEvoPtr pDevEvo,
7860 NVEvoChannelPtr pChannel,
7861 NVSurfaceDescriptor *pSurfaceDesc)
7862 {
7863 return nvCtxDmaBind(pDevEvo, pChannel, pSurfaceDesc->ctxDmaHandle);
7864 }
7865
7866 NVEvoHAL nvEvoC3 = {
7867 EvoSetRasterParamsC3, /* SetRasterParams */
7868 EvoSetProcAmpC3, /* SetProcAmp */
7869 EvoSetHeadControlC3, /* SetHeadControl */
7870 EvoSetHeadRefClkC3, /* SetHeadRefClk */
7871 EvoHeadSetControlORC3, /* HeadSetControlOR */
7872 nvEvoORSetControlC3, /* ORSetControl */
7873 EvoHeadSetDisplayIdC3, /* HeadSetDisplayId */
7874 EvoSetUsageBoundsC3, /* SetUsageBounds */
7875 nvEvoUpdateC3, /* Update */
7876 nvEvoIsModePossibleC3, /* IsModePossible */
7877 nvEvoPrePostIMPC3, /* PrePostIMP */
7878 nvEvoSetNotifierC3, /* SetNotifier */
7879 EvoGetCapabilitiesC3, /* GetCapabilities */
7880 EvoFlipC3, /* Flip */
7881 EvoFlipTransitionWARC3, /* FlipTransitionWAR */
7882 EvoFillLUTSurfaceC3, /* FillLUTSurface */
7883 EvoSetLUTContextDmaC3, /* SetLUTContextDma */
7884 EvoSetOutputScalerC3, /* SetOutputScaler */
7885 EvoSetViewportPointInC3, /* SetViewportPointIn */
7886 EvoSetViewportInOutC3, /* SetViewportInOut */
7887 EvoSetCursorImageC3, /* SetCursorImage */
7888 nvEvoValidateCursorSurfaceC3, /* ValidateCursorSurface */
7889 EvoValidateWindowFormatC3, /* ValidateWindowFormat */
7890 nvEvoInitCompNotifierC3, /* InitCompNotifier */
7891 nvEvoIsCompNotifierCompleteC3, /* IsCompNotifierComplete */
7892 nvEvoWaitForCompNotifierC3, /* WaitForCompNotifier */
7893 EvoSetDitherC3, /* SetDither */
7894 EvoSetStallLockC3, /* SetStallLock */
7895 EvoSetDisplayRateC3, /* SetDisplayRate */
7896 EvoInitChannelC3, /* InitChannel */
7897 NULL, /* InitDefaultLut */
7898 EvoInitWindowMappingC3, /* InitWindowMapping */
7899 nvEvoIsChannelIdleC3, /* IsChannelIdle */
7900 nvEvoIsChannelMethodPendingC3, /* IsChannelMethodPending */
7901 nvEvoForceIdleSatelliteChannelC3, /* ForceIdleSatelliteChannel */
7902 nvEvoForceIdleSatelliteChannelIgnoreLockC3, /* ForceIdleSatelliteChannelIgnoreLock */
7903 nvEvoAccelerateChannelC3, /* AccelerateChannel */
7904 nvEvoResetChannelAcceleratorsC3, /* ResetChannelAccelerators */
7905 nvEvoAllocRmCtrlObjectC3, /* AllocRmCtrlObject */
7906 nvEvoFreeRmCtrlObjectC3, /* FreeRmCtrlObject */
7907 nvEvoSetImmPointOutC3, /* SetImmPointOut */
7908 EvoStartHeadCRC32CaptureC3, /* StartCRC32Capture */
7909 EvoStopHeadCRC32CaptureC3, /* StopCRC32Capture */
7910 nvEvoQueryHeadCRC32_C3, /* QueryCRC32 */
7911 nvEvoGetScanLineC3, /* GetScanLine */
7912 NULL, /* ConfigureVblankSyncObject */
7913 nvEvo1SetDscParams, /* SetDscParams */
7914 NULL, /* EnableMidFrameAndDWCFWatermark */
7915 nvEvoGetActiveViewportOffsetC3, /* GetActiveViewportOffset */
7916 NULL, /* ClearSurfaceUsage */
7917 EvoComputeWindowScalingTapsC3, /* ComputeWindowScalingTaps */
7918 nvEvoGetWindowScalingCapsC3, /* GetWindowScalingCaps */
7919 NULL, /* SetMergeMode */
7920 EvoAllocSurfaceDescriptorC3, /* AllocSurfaceDescriptor */
7921 EvoFreeSurfaceDescriptorC3, /* FreeSurfaceDescriptor */
7922 EvoBindSurfaceDescriptorC3, /* BindSurfaceDescriptor */
7923 NULL, /* SetTmoLutSurfaceAddress */
7924 NULL, /* SetILUTSurfaceAddress */
7925 EvoSetISOSurfaceAddressC3, /* SetISOSurfaceAddress */
7926 EvoSetCoreNotifierSurfaceAddressAndControlC3, /* SetCoreNotifierSurfaceAddressAndControl */
7927 EvoSetWinNotifierSurfaceAddressAndControlC3, /* SetWinNotifierSurfaceAddressAndControl */
7928 NULL, /* SetSemaphoreSurfaceAddressAndControl */
7929 NULL, /* SetAcqSemaphoreSurfaceAddressAndControl */
7930 { /* caps */
7931 TRUE, /* supportsNonInterlockedUsageBoundsUpdate */
7932 TRUE, /* supportsDisplayRate */
7933 FALSE, /* supportsFlipLockRGStatus */
7934 FALSE, /* needDefaultLutSurface */
7935 FALSE, /* hasUnorm10OLUT */
7936 FALSE, /* supportsImageSharpening */
7937 FALSE, /* supportsHDMIVRR */
7938 FALSE, /* supportsCoreChannelSurface */
7939 FALSE, /* supportsHDMIFRL */
7940 TRUE, /* supportsSetStorageMemoryLayout */
7941 FALSE, /* supportsIndependentAcqRelSemaphore */
7942 FALSE, /* supportsCoreLut */
7943 TRUE, /* supportsSynchronizedOverlayPositionUpdate */
7944 FALSE, /* supportsVblankSyncObjects */
7945 FALSE, /* requiresScalingTapsInBothDimensions */
7946 FALSE, /* supportsMergeMode */
7947 FALSE, /* supportsHDMI10BPC */
7948 NV_EVO3_SUPPORTED_DITHERING_MODES, /* supportedDitheringModes */
7949 sizeof(NVC372_CTRL_IS_MODE_POSSIBLE_PARAMS), /* impStructSize */
7950 NV_EVO_SCALER_2TAPS, /* minScalerTaps */
7951 NV_EVO3_X_EMULATED_SURFACE_MEMORY_FORMATS_C3, /* xEmulatedSurfaceMemoryFormats */
7952 },
7953 };
7954
7955 NVEvoHAL nvEvoC5 = {
7956 EvoSetRasterParamsC5, /* SetRasterParams */
7957 EvoSetProcAmpC5, /* SetProcAmp */
7958 EvoSetHeadControlC3, /* SetHeadControl */
7959 EvoSetHeadRefClkC3, /* SetHeadRefClk */
7960 EvoHeadSetControlORC5, /* HeadSetControlOR */
7961 nvEvoORSetControlC3, /* ORSetControl */
7962 EvoHeadSetDisplayIdC3, /* HeadSetDisplayId */
7963 nvEvoSetUsageBoundsC5, /* SetUsageBounds */
7964 nvEvoUpdateC3, /* Update */
7965 nvEvoIsModePossibleC3, /* IsModePossible */
7966 nvEvoPrePostIMPC3, /* PrePostIMP */
7967 nvEvoSetNotifierC3, /* SetNotifier */
7968 EvoGetCapabilitiesC5, /* GetCapabilities */
7969 EvoFlipC5, /* Flip */
7970 EvoFlipTransitionWARC5, /* FlipTransitionWAR */
7971 nvEvoFillLUTSurfaceC5, /* FillLUTSurface */
7972 EvoSetLUTContextDmaC5, /* SetLUTContextDma */
7973 EvoSetOutputScalerC3, /* SetOutputScaler */
7974 EvoSetViewportPointInC3, /* SetViewportPointIn */
7975 EvoSetViewportInOutC5, /* SetViewportInOut */
7976 EvoSetCursorImageC3, /* SetCursorImage */
7977 nvEvoValidateCursorSurfaceC3, /* ValidateCursorSurface */
7978 EvoValidateWindowFormatC5, /* ValidateWindowFormat */
7979 nvEvoInitCompNotifierC3, /* InitCompNotifier */
7980 nvEvoIsCompNotifierCompleteC3, /* IsCompNotifierComplete */
7981 nvEvoWaitForCompNotifierC3, /* WaitForCompNotifier */
7982 EvoSetDitherC3, /* SetDither */
7983 EvoSetStallLockC3, /* SetStallLock */
7984 EvoSetDisplayRateC3, /* SetDisplayRate */
7985 EvoInitChannelC5, /* InitChannel */
7986 nvEvoInitDefaultLutC5, /* InitDefaultLut */
7987 nvEvoInitWindowMappingC5, /* InitWindowMapping */
7988 nvEvoIsChannelIdleC3, /* IsChannelIdle */
7989 nvEvoIsChannelMethodPendingC3, /* IsChannelMethodPending */
7990 nvEvoForceIdleSatelliteChannelC3, /* ForceIdleSatelliteChannel */
7991 nvEvoForceIdleSatelliteChannelIgnoreLockC3, /* ForceIdleSatelliteChannelIgnoreLock */
7992 nvEvoAccelerateChannelC3, /* AccelerateChannel */
7993 nvEvoResetChannelAcceleratorsC3, /* ResetChannelAccelerators */
7994 nvEvoAllocRmCtrlObjectC3, /* AllocRmCtrlObject */
7995 nvEvoFreeRmCtrlObjectC3, /* FreeRmCtrlObject */
7996 nvEvoSetImmPointOutC3, /* SetImmPointOut */
7997 EvoStartHeadCRC32CaptureC3, /* StartCRC32Capture */
7998 EvoStopHeadCRC32CaptureC3, /* StopCRC32Capture */
7999 nvEvoQueryHeadCRC32_C3, /* QueryCRC32 */
8000 nvEvoGetScanLineC3, /* GetScanLine */
8001 NULL, /* ConfigureVblankSyncObject */
8002 EvoSetDscParamsC5, /* SetDscParams */
8003 EvoEnableMidFrameAndDWCFWatermarkC5, /* EnableMidFrameAndDWCFWatermark */
8004 nvEvoGetActiveViewportOffsetC3, /* GetActiveViewportOffset */
8005 NULL, /* ClearSurfaceUsage */
8006 nvEvoComputeWindowScalingTapsC5, /* ComputeWindowScalingTaps */
8007 nvEvoGetWindowScalingCapsC3, /* GetWindowScalingCaps */
8008 EvoSetMergeModeC5, /* SetMergeMode */
8009 EvoAllocSurfaceDescriptorC3, /* AllocSurfaceDescriptor */
8010 EvoFreeSurfaceDescriptorC3, /* FreeSurfaceDescriptor */
8011 EvoBindSurfaceDescriptorC3, /* BindSurfaceDescriptor */
8012 EvoSetTmoLutSurfaceAddressC5, /* SetTmoLutSurfaceAddress */
8013 EvoSetILUTSurfaceAddressC5, /* SetILUTSurfaceAddress */
8014 EvoSetISOSurfaceAddressC3, /* SetISOSurfaceAddress */
8015 EvoSetCoreNotifierSurfaceAddressAndControlC3, /* SetCoreNotifierSurfaceAddressAndControl */
8016 EvoSetWinNotifierSurfaceAddressAndControlC3, /* SetWinNotifierSurfaceAddressAndControl */
8017 NULL, /* SetSemaphoreSurfaceAddressAndControl */
8018 NULL, /* SetAcqSemaphoreSurfaceAddressAndControl */
8019 { /* caps */
8020 TRUE, /* supportsNonInterlockedUsageBoundsUpdate */
8021 TRUE, /* supportsDisplayRate */
8022 FALSE, /* supportsFlipLockRGStatus */
8023 TRUE, /* needDefaultLutSurface */
8024 TRUE, /* hasUnorm10OLUT */
8025 FALSE, /* supportsImageSharpening */
8026 TRUE, /* supportsHDMIVRR */
8027 FALSE, /* supportsCoreChannelSurface */
8028 FALSE, /* supportsHDMIFRL */
8029 TRUE, /* supportsSetStorageMemoryLayout */
8030 FALSE, /* supportsIndependentAcqRelSemaphore */
8031 FALSE, /* supportsCoreLut */
8032 TRUE, /* supportsSynchronizedOverlayPositionUpdate */
8033 FALSE, /* supportsVblankSyncObjects */
8034 FALSE, /* requiresScalingTapsInBothDimensions */
8035 TRUE, /* supportsMergeMode */
8036 FALSE, /* supportsHDMI10BPC */
8037 NV_EVO3_SUPPORTED_DITHERING_MODES, /* supportedDitheringModes */
8038 sizeof(NVC372_CTRL_IS_MODE_POSSIBLE_PARAMS), /* impStructSize */
8039 NV_EVO_SCALER_2TAPS, /* minScalerTaps */
8040 NV_EVO3_X_EMULATED_SURFACE_MEMORY_FORMATS_C5, /* xEmulatedSurfaceMemoryFormats */
8041 },
8042 };
8043
8044 NVEvoHAL nvEvoC6 = {
8045 EvoSetRasterParamsC6, /* SetRasterParams */
8046 EvoSetProcAmpC5, /* SetProcAmp */
8047 EvoSetHeadControlC3, /* SetHeadControl */
8048 EvoSetHeadRefClkC3, /* SetHeadRefClk */
8049 EvoHeadSetControlORC5, /* HeadSetControlOR */
8050 EvoORSetControlC6, /* ORSetControl */
8051 EvoHeadSetDisplayIdC3, /* HeadSetDisplayId */
8052 nvEvoSetUsageBoundsC5, /* SetUsageBounds */
8053 nvEvoUpdateC3, /* Update */
8054 nvEvoIsModePossibleC3, /* IsModePossible */
8055 nvEvoPrePostIMPC3, /* PrePostIMP */
8056 nvEvoSetNotifierC3, /* SetNotifier */
8057 nvEvoGetCapabilitiesC6, /* GetCapabilities */
8058 nvEvoFlipC6, /* Flip */
8059 nvEvoFlipTransitionWARC6, /* FlipTransitionWAR */
8060 nvEvoFillLUTSurfaceC5, /* FillLUTSurface */
8061 EvoSetLUTContextDmaC5, /* SetLUTContextDma */
8062 EvoSetOutputScalerC3, /* SetOutputScaler */
8063 EvoSetViewportPointInC3, /* SetViewportPointIn */
8064 EvoSetViewportInOutC5, /* SetViewportInOut */
8065 EvoSetCursorImageC3, /* SetCursorImage */
8066 nvEvoValidateCursorSurfaceC3, /* ValidateCursorSurface */
8067 nvEvoValidateWindowFormatC6, /* ValidateWindowFormat */
8068 nvEvoInitCompNotifierC3, /* InitCompNotifier */
8069 nvEvoIsCompNotifierCompleteC3, /* IsCompNotifierComplete */
8070 nvEvoWaitForCompNotifierC3, /* WaitForCompNotifier */
8071 EvoSetDitherC3, /* SetDither */
8072 EvoSetStallLockC3, /* SetStallLock */
8073 EvoSetDisplayRateC3, /* SetDisplayRate */
8074 EvoInitChannelC5, /* InitChannel */
8075 nvEvoInitDefaultLutC5, /* InitDefaultLut */
8076 nvEvoInitWindowMappingC5, /* InitWindowMapping */
8077 nvEvoIsChannelIdleC3, /* IsChannelIdle */
8078 nvEvoIsChannelMethodPendingC3, /* IsChannelMethodPending */
8079 nvEvoForceIdleSatelliteChannelC3, /* ForceIdleSatelliteChannel */
8080 nvEvoForceIdleSatelliteChannelIgnoreLockC3, /* ForceIdleSatelliteChannelIgnoreLock */
8081 nvEvoAccelerateChannelC3, /* AccelerateChannel */
8082 nvEvoResetChannelAcceleratorsC3, /* ResetChannelAccelerators */
8083 nvEvoAllocRmCtrlObjectC3, /* AllocRmCtrlObject */
8084 nvEvoFreeRmCtrlObjectC3, /* FreeRmCtrlObject */
8085 nvEvoSetImmPointOutC3, /* SetImmPointOut */
8086 EvoStartHeadCRC32CaptureC3, /* StartCRC32Capture */
8087 EvoStopHeadCRC32CaptureC3, /* StopCRC32Capture */
8088 nvEvoQueryHeadCRC32_C3, /* QueryCRC32 */
8089 nvEvoGetScanLineC3, /* GetScanLine */
8090 EvoConfigureVblankSyncObjectC6, /* ConfigureVblankSyncObject */
8091 EvoSetDscParamsC5, /* SetDscParams */
8092 NULL, /* EnableMidFrameAndDWCFWatermark */
8093 nvEvoGetActiveViewportOffsetC3, /* GetActiveViewportOffset */
8094 NULL, /* ClearSurfaceUsage */
8095 nvEvoComputeWindowScalingTapsC5, /* ComputeWindowScalingTaps */
8096 nvEvoGetWindowScalingCapsC3, /* GetWindowScalingCaps */
8097 EvoSetMergeModeC5, /* SetMergeMode */
8098 EvoAllocSurfaceDescriptorC3, /* AllocSurfaceDescriptor */
8099 EvoFreeSurfaceDescriptorC3, /* FreeSurfaceDescriptor */
8100 EvoBindSurfaceDescriptorC3, /* BindSurfaceDescriptor */
8101 EvoSetTmoLutSurfaceAddressC5, /* SetTmoLutSurfaceAddress */
8102 EvoSetILUTSurfaceAddressC5, /* SetILUTSurfaceAddress */
8103 EvoSetISOSurfaceAddressC3, /* SetISOSurfaceAddress */
8104 EvoSetCoreNotifierSurfaceAddressAndControlC3, /* SetCoreNotifierSurfaceAddressAndControl */
8105 EvoSetWinNotifierSurfaceAddressAndControlC3, /* SetWinNotifierSurfaceAddressAndControl */
8106 EvoSetSemaphoreSurfaceAddressAndControlC6, /* SetSemaphoreSurfaceAddressAndControl */
8107 EvoSetAcqSemaphoreSurfaceAddressAndControlC6, /* SetAcqSemaphoreSurfaceAddressAndControl */
8108 { /* caps */
8109 TRUE, /* supportsNonInterlockedUsageBoundsUpdate */
8110 TRUE, /* supportsDisplayRate */
8111 FALSE, /* supportsFlipLockRGStatus */
8112 TRUE, /* needDefaultLutSurface */
8113 TRUE, /* hasUnorm10OLUT */
8114 FALSE, /* supportsImageSharpening */
8115 TRUE, /* supportsHDMIVRR */
8116 FALSE, /* supportsCoreChannelSurface */
8117 TRUE, /* supportsHDMIFRL */
8118 FALSE, /* supportsSetStorageMemoryLayout */
8119 TRUE, /* supportsIndependentAcqRelSemaphore */
8120 FALSE, /* supportsCoreLut */
8121 TRUE, /* supportsSynchronizedOverlayPositionUpdate */
8122 TRUE, /* supportsVblankSyncObjects */
8123 FALSE, /* requiresScalingTapsInBothDimensions */
8124 TRUE, /* supportsMergeMode */
8125 TRUE, /* supportsHDMI10BPC */
8126 NV_EVO3_SUPPORTED_DITHERING_MODES, /* supportedDitheringModes */
8127 sizeof(NVC372_CTRL_IS_MODE_POSSIBLE_PARAMS), /* impStructSize */
8128 NV_EVO_SCALER_2TAPS, /* minScalerTaps */
8129 NV_EVO3_X_EMULATED_SURFACE_MEMORY_FORMATS_C6, /* xEmulatedSurfaceMemoryFormats */
8130 },
8131 };
8132