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                 &params, 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                        &params, 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                          &params, 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                          &params, 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                          &params, 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