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