1/*
2 * Copyright © 2016 Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * 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#include <drm/drm_print.h>
26
27#include "i9xx_plane_regs.h"
28#include "intel_color.h"
29#include "intel_color_regs.h"
30#include "intel_de.h"
31#include "intel_display_types.h"
32#include "intel_display_utils.h"
33#include "intel_dsb.h"
34#include "intel_vrr.h"
35#include "skl_universal_plane.h"
36#include "skl_universal_plane_regs.h"
37
38struct intel_color_funcs {
39 int (*color_check)(struct intel_atomic_state *state,
40 struct intel_crtc *crtc);
41 /*
42 * Program non-arming double buffered color management registers
43 * before vblank evasion. The registers should then latch after
44 * the arming register is written (by color_commit_arm()) during
45 * the next vblank start, alongside any other double buffered
46 * registers involved with the same commit. This hook is optional.
47 */
48 void (*color_commit_noarm)(struct intel_dsb *dsb,
49 const struct intel_crtc_state *crtc_state);
50 /*
51 * Program arming double buffered color management registers
52 * during vblank evasion. The registers (and whatever other registers
53 * they arm that were written by color_commit_noarm) should then latch
54 * during the next vblank start, alongside any other double buffered
55 * registers involved with the same commit.
56 */
57 void (*color_commit_arm)(struct intel_dsb *dsb,
58 const struct intel_crtc_state *crtc_state);
59 /*
60 * Perform any extra tasks needed after all the
61 * double buffered registers have been latched.
62 */
63 void (*color_post_update)(const struct intel_crtc_state *crtc_state);
64 /*
65 * Load LUTs (and other single buffered color management
66 * registers). Will (hopefully) be called during the vblank
67 * following the latching of any double buffered registers
68 * involved with the same commit.
69 */
70 void (*load_luts)(const struct intel_crtc_state *crtc_state);
71 /*
72 * Read out the LUTs from the hardware into the software state.
73 * Used by eg. the hardware state checker.
74 */
75 void (*read_luts)(struct intel_crtc_state *crtc_state);
76 /*
77 * Compare the LUTs
78 */
79 bool (*lut_equal)(const struct intel_crtc_state *crtc_state,
80 const struct drm_property_blob *blob1,
81 const struct drm_property_blob *blob2,
82 bool is_pre_csc_lut);
83 /*
84 * Read out the CSCs (if any) from the hardware into the
85 * software state. Used by eg. the hardware state checker.
86 */
87 void (*read_csc)(struct intel_crtc_state *crtc_state);
88 /*
89 * Read config other than LUTs and CSCs, before them. Optional.
90 */
91 void (*get_config)(struct intel_crtc_state *crtc_state);
92
93 /* Plane CSC*/
94 void (*load_plane_csc_matrix)(struct intel_dsb *dsb,
95 const struct intel_plane_state *plane_state);
96
97 /* Plane Pre/Post CSC */
98 void (*load_plane_luts)(struct intel_dsb *dsb,
99 const struct intel_plane_state *plane_state);
100};
101
102#define CTM_COEFF_SIGN (1ULL << 63)
103
104#define CTM_COEFF_1_0 (1ULL << 32)
105#define CTM_COEFF_2_0 (CTM_COEFF_1_0 << 1)
106#define CTM_COEFF_4_0 (CTM_COEFF_2_0 << 1)
107#define CTM_COEFF_8_0 (CTM_COEFF_4_0 << 1)
108#define CTM_COEFF_0_5 (CTM_COEFF_1_0 >> 1)
109#define CTM_COEFF_0_25 (CTM_COEFF_0_5 >> 1)
110#define CTM_COEFF_0_125 (CTM_COEFF_0_25 >> 1)
111
112#define CTM_COEFF_LIMITED_RANGE ((235ULL - 16ULL) * CTM_COEFF_1_0 / 255)
113
114#define CTM_COEFF_NEGATIVE(coeff) (((coeff) & CTM_COEFF_SIGN) != 0)
115#define CTM_COEFF_ABS(coeff) ((coeff) & (CTM_COEFF_SIGN - 1))
116
117#define LEGACY_LUT_LENGTH 256
118
119/*
120 * ILK+ csc matrix:
121 *
122 * |R/Cr| | c0 c1 c2 | ( |R/Cr| |preoff0| ) |postoff0|
123 * |G/Y | = | c3 c4 c5 | x ( |G/Y | + |preoff1| ) + |postoff1|
124 * |B/Cb| | c6 c7 c8 | ( |B/Cb| |preoff2| ) |postoff2|
125 *
126 * ILK/SNB don't have explicit post offsets, and instead
127 * CSC_MODE_YUV_TO_RGB and CSC_BLACK_SCREEN_OFFSET are used:
128 * CSC_MODE_YUV_TO_RGB=0 + CSC_BLACK_SCREEN_OFFSET=0 -> 1/2, 0, 1/2
129 * CSC_MODE_YUV_TO_RGB=0 + CSC_BLACK_SCREEN_OFFSET=1 -> 1/2, 1/16, 1/2
130 * CSC_MODE_YUV_TO_RGB=1 + CSC_BLACK_SCREEN_OFFSET=0 -> 0, 0, 0
131 * CSC_MODE_YUV_TO_RGB=1 + CSC_BLACK_SCREEN_OFFSET=1 -> 1/16, 1/16, 1/16
132 */
133
134/*
135 * Extract the CSC coefficient from a CTM coefficient (in U32.32 fixed point
136 * format). This macro takes the coefficient we want transformed and the
137 * number of fractional bits.
138 *
139 * We only have a 9 bits precision window which slides depending on the value
140 * of the CTM coefficient and we write the value from bit 3. We also round the
141 * value.
142 */
143#define ILK_CSC_COEFF_FP(coeff, fbits) \
144 (clamp_val(((coeff) >> (32 - (fbits) - 3)) + 4, 0, 0xfff) & 0xff8)
145
146#define ILK_CSC_COEFF_1_0 0x7800
147#define ILK_CSC_COEFF_LIMITED_RANGE ((235 - 16) << (12 - 8)) /* exponent 0 */
148#define ILK_CSC_POSTOFF_LIMITED_RANGE (16 << (12 - 8))
149
150static const struct intel_csc_matrix ilk_csc_matrix_identity = {
151 .preoff = {},
152 .coeff = {
153 ILK_CSC_COEFF_1_0, 0, 0,
154 0, ILK_CSC_COEFF_1_0, 0,
155 0, 0, ILK_CSC_COEFF_1_0,
156 },
157 .postoff = {},
158};
159
160/* Full range RGB -> limited range RGB matrix */
161static const struct intel_csc_matrix ilk_csc_matrix_limited_range = {
162 .preoff = {},
163 .coeff = {
164 ILK_CSC_COEFF_LIMITED_RANGE, 0, 0,
165 0, ILK_CSC_COEFF_LIMITED_RANGE, 0,
166 0, 0, ILK_CSC_COEFF_LIMITED_RANGE,
167 },
168 .postoff = {
169 ILK_CSC_POSTOFF_LIMITED_RANGE,
170 ILK_CSC_POSTOFF_LIMITED_RANGE,
171 ILK_CSC_POSTOFF_LIMITED_RANGE,
172 },
173};
174
175/* BT.709 full range RGB -> limited range YCbCr matrix */
176static const struct intel_csc_matrix ilk_csc_matrix_rgb_to_ycbcr = {
177 .preoff = {},
178 .coeff = {
179 0x1e08, 0x9cc0, 0xb528,
180 0x2ba8, 0x09d8, 0x37e8,
181 0xbce8, 0x9ad8, 0x1e08,
182 },
183 .postoff = {
184 0x0800, 0x0100, 0x0800,
185 },
186};
187
188static void intel_csc_clear(struct intel_csc_matrix *csc)
189{
190 memset(csc, 0, sizeof(*csc));
191}
192
193static bool lut_is_legacy(const struct drm_property_blob *lut)
194{
195 return lut && drm_color_lut_size(blob: lut) == LEGACY_LUT_LENGTH;
196}
197
198/*
199 * When using limited range, multiply the matrix given by userspace by
200 * the matrix that we would use for the limited range.
201 */
202static u64 *ctm_mult_by_limited(u64 *result, const u64 *input)
203{
204 int i;
205
206 for (i = 0; i < 9; i++) {
207 u64 user_coeff = input[i];
208 u32 limited_coeff = CTM_COEFF_LIMITED_RANGE;
209 u32 abs_coeff = clamp_val(CTM_COEFF_ABS(user_coeff), 0,
210 CTM_COEFF_4_0 - 1) >> 2;
211
212 /*
213 * By scaling every co-efficient with limited range (16-235)
214 * vs full range (0-255) the final o/p will be scaled down to
215 * fit in the limited range supported by the panel.
216 */
217 result[i] = mul_u32_u32(a: limited_coeff, b: abs_coeff) >> 30;
218 result[i] |= user_coeff & CTM_COEFF_SIGN;
219 }
220
221 return result;
222}
223
224static void ilk_update_pipe_csc(struct intel_dsb *dsb,
225 struct intel_crtc *crtc,
226 const struct intel_csc_matrix *csc)
227{
228 struct intel_display *display = to_intel_display(crtc->base.dev);
229 enum pipe pipe = crtc->pipe;
230
231 intel_de_write_dsb(display, dsb, PIPE_CSC_PREOFF_HI(pipe),
232 val: csc->preoff[0]);
233 intel_de_write_dsb(display, dsb, PIPE_CSC_PREOFF_ME(pipe),
234 val: csc->preoff[1]);
235 intel_de_write_dsb(display, dsb, PIPE_CSC_PREOFF_LO(pipe),
236 val: csc->preoff[2]);
237
238 intel_de_write_dsb(display, dsb, PIPE_CSC_COEFF_RY_GY(pipe),
239 val: csc->coeff[0] << 16 | csc->coeff[1]);
240 intel_de_write_dsb(display, dsb, PIPE_CSC_COEFF_BY(pipe),
241 val: csc->coeff[2] << 16);
242
243 intel_de_write_dsb(display, dsb, PIPE_CSC_COEFF_RU_GU(pipe),
244 val: csc->coeff[3] << 16 | csc->coeff[4]);
245 intel_de_write_dsb(display, dsb, PIPE_CSC_COEFF_BU(pipe),
246 val: csc->coeff[5] << 16);
247
248 intel_de_write_dsb(display, dsb, PIPE_CSC_COEFF_RV_GV(pipe),
249 val: csc->coeff[6] << 16 | csc->coeff[7]);
250 intel_de_write_dsb(display, dsb, PIPE_CSC_COEFF_BV(pipe),
251 val: csc->coeff[8] << 16);
252
253 if (DISPLAY_VER(display) < 7)
254 return;
255
256 intel_de_write_dsb(display, dsb, PIPE_CSC_POSTOFF_HI(pipe),
257 val: csc->postoff[0]);
258 intel_de_write_dsb(display, dsb, PIPE_CSC_POSTOFF_ME(pipe),
259 val: csc->postoff[1]);
260 intel_de_write_dsb(display, dsb, PIPE_CSC_POSTOFF_LO(pipe),
261 val: csc->postoff[2]);
262}
263
264static void ilk_read_pipe_csc(struct intel_crtc *crtc,
265 struct intel_csc_matrix *csc)
266{
267 struct intel_display *display = to_intel_display(crtc);
268 enum pipe pipe = crtc->pipe;
269 u32 tmp;
270
271 csc->preoff[0] = intel_de_read_fw(display, PIPE_CSC_PREOFF_HI(pipe));
272 csc->preoff[1] = intel_de_read_fw(display, PIPE_CSC_PREOFF_ME(pipe));
273 csc->preoff[2] = intel_de_read_fw(display, PIPE_CSC_PREOFF_LO(pipe));
274
275 tmp = intel_de_read_fw(display, PIPE_CSC_COEFF_RY_GY(pipe));
276 csc->coeff[0] = tmp >> 16;
277 csc->coeff[1] = tmp & 0xffff;
278 tmp = intel_de_read_fw(display, PIPE_CSC_COEFF_BY(pipe));
279 csc->coeff[2] = tmp >> 16;
280
281 tmp = intel_de_read_fw(display, PIPE_CSC_COEFF_RU_GU(pipe));
282 csc->coeff[3] = tmp >> 16;
283 csc->coeff[4] = tmp & 0xffff;
284 tmp = intel_de_read_fw(display, PIPE_CSC_COEFF_BU(pipe));
285 csc->coeff[5] = tmp >> 16;
286
287 tmp = intel_de_read_fw(display, PIPE_CSC_COEFF_RV_GV(pipe));
288 csc->coeff[6] = tmp >> 16;
289 csc->coeff[7] = tmp & 0xffff;
290 tmp = intel_de_read_fw(display, PIPE_CSC_COEFF_BV(pipe));
291 csc->coeff[8] = tmp >> 16;
292
293 if (DISPLAY_VER(display) < 7)
294 return;
295
296 csc->postoff[0] = intel_de_read_fw(display, PIPE_CSC_POSTOFF_HI(pipe));
297 csc->postoff[1] = intel_de_read_fw(display, PIPE_CSC_POSTOFF_ME(pipe));
298 csc->postoff[2] = intel_de_read_fw(display, PIPE_CSC_POSTOFF_LO(pipe));
299}
300
301static void ilk_read_csc(struct intel_crtc_state *crtc_state)
302{
303 struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
304
305 if (crtc_state->csc_enable)
306 ilk_read_pipe_csc(crtc, csc: &crtc_state->csc);
307}
308
309static void skl_read_csc(struct intel_crtc_state *crtc_state)
310{
311 struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
312
313 /*
314 * Display WA #1184: skl,glk
315 * Wa_1406463849: icl
316 *
317 * Danger! On SKL-ICL *reads* from the CSC coeff/offset registers
318 * will disarm an already armed CSC double buffer update.
319 * So this must not be called while armed. Fortunately the state checker
320 * readout happens only after the update has been already been latched.
321 *
322 * On earlier and later platforms only writes to said registers will
323 * disarm the update. This is considered normal behavior and also
324 * happens with various other hardware units.
325 */
326 if (crtc_state->csc_enable)
327 ilk_read_pipe_csc(crtc, csc: &crtc_state->csc);
328}
329
330static void icl_update_output_csc(struct intel_dsb *dsb,
331 struct intel_crtc *crtc,
332 const struct intel_csc_matrix *csc)
333{
334 struct intel_display *display = to_intel_display(crtc->base.dev);
335 enum pipe pipe = crtc->pipe;
336
337 intel_de_write_dsb(display, dsb, PIPE_CSC_OUTPUT_PREOFF_HI(pipe),
338 val: csc->preoff[0]);
339 intel_de_write_dsb(display, dsb, PIPE_CSC_OUTPUT_PREOFF_ME(pipe),
340 val: csc->preoff[1]);
341 intel_de_write_dsb(display, dsb, PIPE_CSC_OUTPUT_PREOFF_LO(pipe),
342 val: csc->preoff[2]);
343
344 intel_de_write_dsb(display, dsb, PIPE_CSC_OUTPUT_COEFF_RY_GY(pipe),
345 val: csc->coeff[0] << 16 | csc->coeff[1]);
346 intel_de_write_dsb(display, dsb, PIPE_CSC_OUTPUT_COEFF_BY(pipe),
347 val: csc->coeff[2] << 16);
348
349 intel_de_write_dsb(display, dsb, PIPE_CSC_OUTPUT_COEFF_RU_GU(pipe),
350 val: csc->coeff[3] << 16 | csc->coeff[4]);
351 intel_de_write_dsb(display, dsb, PIPE_CSC_OUTPUT_COEFF_BU(pipe),
352 val: csc->coeff[5] << 16);
353
354 intel_de_write_dsb(display, dsb, PIPE_CSC_OUTPUT_COEFF_RV_GV(pipe),
355 val: csc->coeff[6] << 16 | csc->coeff[7]);
356 intel_de_write_dsb(display, dsb, PIPE_CSC_OUTPUT_COEFF_BV(pipe),
357 val: csc->coeff[8] << 16);
358
359 intel_de_write_dsb(display, dsb, PIPE_CSC_OUTPUT_POSTOFF_HI(pipe),
360 val: csc->postoff[0]);
361 intel_de_write_dsb(display, dsb, PIPE_CSC_OUTPUT_POSTOFF_ME(pipe),
362 val: csc->postoff[1]);
363 intel_de_write_dsb(display, dsb, PIPE_CSC_OUTPUT_POSTOFF_LO(pipe),
364 val: csc->postoff[2]);
365}
366
367static void icl_read_output_csc(struct intel_crtc *crtc,
368 struct intel_csc_matrix *csc)
369{
370 struct intel_display *display = to_intel_display(crtc);
371 enum pipe pipe = crtc->pipe;
372 u32 tmp;
373
374 csc->preoff[0] = intel_de_read_fw(display, PIPE_CSC_OUTPUT_PREOFF_HI(pipe));
375 csc->preoff[1] = intel_de_read_fw(display, PIPE_CSC_OUTPUT_PREOFF_ME(pipe));
376 csc->preoff[2] = intel_de_read_fw(display, PIPE_CSC_OUTPUT_PREOFF_LO(pipe));
377
378 tmp = intel_de_read_fw(display, PIPE_CSC_OUTPUT_COEFF_RY_GY(pipe));
379 csc->coeff[0] = tmp >> 16;
380 csc->coeff[1] = tmp & 0xffff;
381 tmp = intel_de_read_fw(display, PIPE_CSC_OUTPUT_COEFF_BY(pipe));
382 csc->coeff[2] = tmp >> 16;
383
384 tmp = intel_de_read_fw(display, PIPE_CSC_OUTPUT_COEFF_RU_GU(pipe));
385 csc->coeff[3] = tmp >> 16;
386 csc->coeff[4] = tmp & 0xffff;
387 tmp = intel_de_read_fw(display, PIPE_CSC_OUTPUT_COEFF_BU(pipe));
388 csc->coeff[5] = tmp >> 16;
389
390 tmp = intel_de_read_fw(display, PIPE_CSC_OUTPUT_COEFF_RV_GV(pipe));
391 csc->coeff[6] = tmp >> 16;
392 csc->coeff[7] = tmp & 0xffff;
393 tmp = intel_de_read_fw(display, PIPE_CSC_OUTPUT_COEFF_BV(pipe));
394 csc->coeff[8] = tmp >> 16;
395
396 csc->postoff[0] = intel_de_read_fw(display, PIPE_CSC_OUTPUT_POSTOFF_HI(pipe));
397 csc->postoff[1] = intel_de_read_fw(display, PIPE_CSC_OUTPUT_POSTOFF_ME(pipe));
398 csc->postoff[2] = intel_de_read_fw(display, PIPE_CSC_OUTPUT_POSTOFF_LO(pipe));
399}
400
401static void icl_read_csc(struct intel_crtc_state *crtc_state)
402{
403 struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
404
405 /*
406 * Wa_1406463849: icl
407 *
408 * See skl_read_csc()
409 */
410 if (crtc_state->csc_mode & ICL_CSC_ENABLE)
411 ilk_read_pipe_csc(crtc, csc: &crtc_state->csc);
412
413 if (crtc_state->csc_mode & ICL_OUTPUT_CSC_ENABLE)
414 icl_read_output_csc(crtc, csc: &crtc_state->output_csc);
415}
416
417static bool ilk_limited_range(const struct intel_crtc_state *crtc_state)
418{
419 struct intel_display *display = to_intel_display(crtc_state);
420
421 /* icl+ have dedicated output CSC */
422 if (DISPLAY_VER(display) >= 11)
423 return false;
424
425 /* pre-hsw have TRANSCONF_COLOR_RANGE_SELECT */
426 if (DISPLAY_VER(display) < 7 || display->platform.ivybridge)
427 return false;
428
429 return crtc_state->limited_color_range;
430}
431
432static bool ilk_lut_limited_range(const struct intel_crtc_state *crtc_state)
433{
434 struct intel_display *display = to_intel_display(crtc_state);
435
436 if (!ilk_limited_range(crtc_state))
437 return false;
438
439 if (crtc_state->c8_planes)
440 return false;
441
442 if (DISPLAY_VER(display) == 10)
443 return crtc_state->hw.gamma_lut;
444 else
445 return crtc_state->hw.gamma_lut &&
446 (crtc_state->hw.degamma_lut || crtc_state->hw.ctm);
447}
448
449static bool ilk_csc_limited_range(const struct intel_crtc_state *crtc_state)
450{
451 if (!ilk_limited_range(crtc_state))
452 return false;
453
454 return !ilk_lut_limited_range(crtc_state);
455}
456
457static void ilk_csc_copy(struct intel_display *display,
458 struct intel_csc_matrix *dst,
459 const struct intel_csc_matrix *src)
460{
461 *dst = *src;
462
463 if (DISPLAY_VER(display) < 7)
464 memset(dst->postoff, 0, sizeof(dst->postoff));
465}
466
467static void ilk_csc_convert_ctm(const struct intel_crtc_state *crtc_state,
468 struct intel_csc_matrix *csc,
469 bool limited_color_range)
470{
471 struct intel_display *display = to_intel_display(crtc_state);
472 const struct drm_color_ctm *ctm = crtc_state->hw.ctm->data;
473 const u64 *input;
474 u64 temp[9];
475 int i;
476
477 /* for preoff/postoff */
478 if (limited_color_range)
479 ilk_csc_copy(display, dst: csc, src: &ilk_csc_matrix_limited_range);
480 else
481 ilk_csc_copy(display, dst: csc, src: &ilk_csc_matrix_identity);
482
483 if (limited_color_range)
484 input = ctm_mult_by_limited(result: temp, input: ctm->matrix);
485 else
486 input = ctm->matrix;
487
488 /*
489 * Convert fixed point S31.32 input to format supported by the
490 * hardware.
491 */
492 for (i = 0; i < 9; i++) {
493 u64 abs_coeff = ((1ULL << 63) - 1) & input[i];
494
495 /*
496 * Clamp input value to min/max supported by
497 * hardware.
498 */
499 abs_coeff = clamp_val(abs_coeff, 0, CTM_COEFF_4_0 - 1);
500
501 csc->coeff[i] = 0;
502
503 /* sign bit */
504 if (CTM_COEFF_NEGATIVE(input[i]))
505 csc->coeff[i] |= 1 << 15;
506
507 if (abs_coeff < CTM_COEFF_0_125)
508 csc->coeff[i] |= (3 << 12) |
509 ILK_CSC_COEFF_FP(abs_coeff, 12);
510 else if (abs_coeff < CTM_COEFF_0_25)
511 csc->coeff[i] |= (2 << 12) |
512 ILK_CSC_COEFF_FP(abs_coeff, 11);
513 else if (abs_coeff < CTM_COEFF_0_5)
514 csc->coeff[i] |= (1 << 12) |
515 ILK_CSC_COEFF_FP(abs_coeff, 10);
516 else if (abs_coeff < CTM_COEFF_1_0)
517 csc->coeff[i] |= ILK_CSC_COEFF_FP(abs_coeff, 9);
518 else if (abs_coeff < CTM_COEFF_2_0)
519 csc->coeff[i] |= (7 << 12) |
520 ILK_CSC_COEFF_FP(abs_coeff, 8);
521 else
522 csc->coeff[i] |= (6 << 12) |
523 ILK_CSC_COEFF_FP(abs_coeff, 7);
524 }
525}
526
527static void ilk_assign_csc(struct intel_crtc_state *crtc_state)
528{
529 struct intel_display *display = to_intel_display(crtc_state);
530 bool limited_color_range = ilk_csc_limited_range(crtc_state);
531
532 if (crtc_state->hw.ctm) {
533 drm_WARN_ON(display->drm, !crtc_state->csc_enable);
534
535 ilk_csc_convert_ctm(crtc_state, csc: &crtc_state->csc, limited_color_range);
536 } else if (crtc_state->output_format != INTEL_OUTPUT_FORMAT_RGB) {
537 drm_WARN_ON(display->drm, !crtc_state->csc_enable);
538
539 ilk_csc_copy(display, dst: &crtc_state->csc, src: &ilk_csc_matrix_rgb_to_ycbcr);
540 } else if (limited_color_range) {
541 drm_WARN_ON(display->drm, !crtc_state->csc_enable);
542
543 ilk_csc_copy(display, dst: &crtc_state->csc, src: &ilk_csc_matrix_limited_range);
544 } else if (crtc_state->csc_enable) {
545 /*
546 * On GLK both pipe CSC and degamma LUT are controlled
547 * by csc_enable. Hence for the cases where the degama
548 * LUT is needed but CSC is not we need to load an
549 * identity matrix.
550 */
551 drm_WARN_ON(display->drm, !display->platform.geminilake);
552
553 ilk_csc_copy(display, dst: &crtc_state->csc, src: &ilk_csc_matrix_identity);
554 } else {
555 intel_csc_clear(csc: &crtc_state->csc);
556 }
557}
558
559static void ilk_load_csc_matrix(struct intel_dsb *dsb,
560 const struct intel_crtc_state *crtc_state)
561{
562 struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
563
564 if (crtc_state->csc_enable)
565 ilk_update_pipe_csc(dsb, crtc, csc: &crtc_state->csc);
566}
567
568static void icl_assign_csc(struct intel_crtc_state *crtc_state)
569{
570 struct intel_display *display = to_intel_display(crtc_state);
571
572 if (crtc_state->hw.ctm) {
573 drm_WARN_ON(display->drm, (crtc_state->csc_mode & ICL_CSC_ENABLE) == 0);
574
575 ilk_csc_convert_ctm(crtc_state, csc: &crtc_state->csc, limited_color_range: false);
576 } else {
577 drm_WARN_ON(display->drm, (crtc_state->csc_mode & ICL_CSC_ENABLE) != 0);
578
579 intel_csc_clear(csc: &crtc_state->csc);
580 }
581
582 if (crtc_state->output_format != INTEL_OUTPUT_FORMAT_RGB) {
583 drm_WARN_ON(display->drm, (crtc_state->csc_mode & ICL_OUTPUT_CSC_ENABLE) == 0);
584
585 ilk_csc_copy(display, dst: &crtc_state->output_csc, src: &ilk_csc_matrix_rgb_to_ycbcr);
586 } else if (crtc_state->limited_color_range) {
587 drm_WARN_ON(display->drm, (crtc_state->csc_mode & ICL_OUTPUT_CSC_ENABLE) == 0);
588
589 ilk_csc_copy(display, dst: &crtc_state->output_csc, src: &ilk_csc_matrix_limited_range);
590 } else {
591 drm_WARN_ON(display->drm, (crtc_state->csc_mode & ICL_OUTPUT_CSC_ENABLE) != 0);
592
593 intel_csc_clear(csc: &crtc_state->output_csc);
594 }
595}
596
597static void icl_load_csc_matrix(struct intel_dsb *dsb,
598 const struct intel_crtc_state *crtc_state)
599{
600 struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
601
602 if (crtc_state->csc_mode & ICL_CSC_ENABLE)
603 ilk_update_pipe_csc(dsb, crtc, csc: &crtc_state->csc);
604
605 if (crtc_state->csc_mode & ICL_OUTPUT_CSC_ENABLE)
606 icl_update_output_csc(dsb, crtc, csc: &crtc_state->output_csc);
607}
608
609static u16 ctm_to_twos_complement(u64 coeff, int int_bits, int frac_bits)
610{
611 s64 c = CTM_COEFF_ABS(coeff);
612
613 /* leave an extra bit for rounding */
614 c >>= 32 - frac_bits - 1;
615
616 /* round and drop the extra bit */
617 c = (c + 1) >> 1;
618
619 if (CTM_COEFF_NEGATIVE(coeff))
620 c = -c;
621
622 int_bits = max(int_bits, 1);
623
624 c = clamp(c, -(s64)BIT(int_bits + frac_bits - 1),
625 (s64)(BIT(int_bits + frac_bits - 1) - 1));
626
627 return c & (BIT(int_bits + frac_bits) - 1);
628}
629
630/*
631 * VLV/CHV Wide Gamut Color Correction (WGC) CSC
632 * |r| | c0 c1 c2 | |r|
633 * |g| = | c3 c4 c5 | x |g|
634 * |b| | c6 c7 c8 | |b|
635 *
636 * Coefficients are two's complement s2.10.
637 */
638static void vlv_wgc_csc_convert_ctm(const struct intel_crtc_state *crtc_state,
639 struct intel_csc_matrix *csc)
640{
641 const struct drm_color_ctm *ctm = crtc_state->hw.ctm->data;
642 int i;
643
644 for (i = 0; i < 9; i++)
645 csc->coeff[i] = ctm_to_twos_complement(coeff: ctm->matrix[i], int_bits: 2, frac_bits: 10);
646}
647
648static void vlv_load_wgc_csc(struct intel_crtc *crtc,
649 const struct intel_csc_matrix *csc)
650{
651 struct intel_display *display = to_intel_display(crtc);
652 enum pipe pipe = crtc->pipe;
653
654 intel_de_write_fw(display, PIPE_WGC_C01_C00(display, pipe),
655 val: csc->coeff[1] << 16 | csc->coeff[0]);
656 intel_de_write_fw(display, PIPE_WGC_C02(display, pipe),
657 val: csc->coeff[2]);
658
659 intel_de_write_fw(display, PIPE_WGC_C11_C10(display, pipe),
660 val: csc->coeff[4] << 16 | csc->coeff[3]);
661 intel_de_write_fw(display, PIPE_WGC_C12(display, pipe),
662 val: csc->coeff[5]);
663
664 intel_de_write_fw(display, PIPE_WGC_C21_C20(display, pipe),
665 val: csc->coeff[7] << 16 | csc->coeff[6]);
666 intel_de_write_fw(display, PIPE_WGC_C22(display, pipe),
667 val: csc->coeff[8]);
668}
669
670static void vlv_read_wgc_csc(struct intel_crtc *crtc,
671 struct intel_csc_matrix *csc)
672{
673 struct intel_display *display = to_intel_display(crtc);
674 enum pipe pipe = crtc->pipe;
675 u32 tmp;
676
677 tmp = intel_de_read_fw(display, PIPE_WGC_C01_C00(display, pipe));
678 csc->coeff[0] = tmp & 0xffff;
679 csc->coeff[1] = tmp >> 16;
680
681 tmp = intel_de_read_fw(display, PIPE_WGC_C02(display, pipe));
682 csc->coeff[2] = tmp & 0xffff;
683
684 tmp = intel_de_read_fw(display, PIPE_WGC_C11_C10(display, pipe));
685 csc->coeff[3] = tmp & 0xffff;
686 csc->coeff[4] = tmp >> 16;
687
688 tmp = intel_de_read_fw(display, PIPE_WGC_C12(display, pipe));
689 csc->coeff[5] = tmp & 0xffff;
690
691 tmp = intel_de_read_fw(display, PIPE_WGC_C21_C20(display, pipe));
692 csc->coeff[6] = tmp & 0xffff;
693 csc->coeff[7] = tmp >> 16;
694
695 tmp = intel_de_read_fw(display, PIPE_WGC_C22(display, pipe));
696 csc->coeff[8] = tmp & 0xffff;
697}
698
699static void vlv_read_csc(struct intel_crtc_state *crtc_state)
700{
701 struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
702
703 if (crtc_state->wgc_enable)
704 vlv_read_wgc_csc(crtc, csc: &crtc_state->csc);
705}
706
707static void vlv_assign_csc(struct intel_crtc_state *crtc_state)
708{
709 struct intel_display *display = to_intel_display(crtc_state);
710
711 if (crtc_state->hw.ctm) {
712 drm_WARN_ON(display->drm, !crtc_state->wgc_enable);
713
714 vlv_wgc_csc_convert_ctm(crtc_state, csc: &crtc_state->csc);
715 } else {
716 drm_WARN_ON(display->drm, crtc_state->wgc_enable);
717
718 intel_csc_clear(csc: &crtc_state->csc);
719 }
720}
721
722/*
723 * CHV Color Gamut Mapping (CGM) CSC
724 * |r| | c0 c1 c2 | |r|
725 * |g| = | c3 c4 c5 | x |g|
726 * |b| | c6 c7 c8 | |b|
727 *
728 * Coefficients are two's complement s4.12.
729 */
730static void chv_cgm_csc_convert_ctm(const struct intel_crtc_state *crtc_state,
731 struct intel_csc_matrix *csc)
732{
733 const struct drm_color_ctm *ctm = crtc_state->hw.ctm->data;
734 int i;
735
736 for (i = 0; i < 9; i++)
737 csc->coeff[i] = ctm_to_twos_complement(coeff: ctm->matrix[i], int_bits: 4, frac_bits: 12);
738}
739
740#define CHV_CGM_CSC_COEFF_1_0 (1 << 12)
741
742static const struct intel_csc_matrix chv_cgm_csc_matrix_identity = {
743 .coeff = {
744 CHV_CGM_CSC_COEFF_1_0, 0, 0,
745 0, CHV_CGM_CSC_COEFF_1_0, 0,
746 0, 0, CHV_CGM_CSC_COEFF_1_0,
747 },
748};
749
750static void chv_load_cgm_csc(struct intel_crtc *crtc,
751 const struct intel_csc_matrix *csc)
752{
753 struct intel_display *display = to_intel_display(crtc);
754 enum pipe pipe = crtc->pipe;
755
756 intel_de_write_fw(display, CGM_PIPE_CSC_COEFF01(pipe),
757 val: csc->coeff[1] << 16 | csc->coeff[0]);
758 intel_de_write_fw(display, CGM_PIPE_CSC_COEFF23(pipe),
759 val: csc->coeff[3] << 16 | csc->coeff[2]);
760 intel_de_write_fw(display, CGM_PIPE_CSC_COEFF45(pipe),
761 val: csc->coeff[5] << 16 | csc->coeff[4]);
762 intel_de_write_fw(display, CGM_PIPE_CSC_COEFF67(pipe),
763 val: csc->coeff[7] << 16 | csc->coeff[6]);
764 intel_de_write_fw(display, CGM_PIPE_CSC_COEFF8(pipe),
765 val: csc->coeff[8]);
766}
767
768static void chv_read_cgm_csc(struct intel_crtc *crtc,
769 struct intel_csc_matrix *csc)
770{
771 struct intel_display *display = to_intel_display(crtc);
772 enum pipe pipe = crtc->pipe;
773 u32 tmp;
774
775 tmp = intel_de_read_fw(display, CGM_PIPE_CSC_COEFF01(pipe));
776 csc->coeff[0] = tmp & 0xffff;
777 csc->coeff[1] = tmp >> 16;
778
779 tmp = intel_de_read_fw(display, CGM_PIPE_CSC_COEFF23(pipe));
780 csc->coeff[2] = tmp & 0xffff;
781 csc->coeff[3] = tmp >> 16;
782
783 tmp = intel_de_read_fw(display, CGM_PIPE_CSC_COEFF45(pipe));
784 csc->coeff[4] = tmp & 0xffff;
785 csc->coeff[5] = tmp >> 16;
786
787 tmp = intel_de_read_fw(display, CGM_PIPE_CSC_COEFF67(pipe));
788 csc->coeff[6] = tmp & 0xffff;
789 csc->coeff[7] = tmp >> 16;
790
791 tmp = intel_de_read_fw(display, CGM_PIPE_CSC_COEFF8(pipe));
792 csc->coeff[8] = tmp & 0xffff;
793}
794
795static void chv_read_csc(struct intel_crtc_state *crtc_state)
796{
797 struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
798
799 if (crtc_state->cgm_mode & CGM_PIPE_MODE_CSC)
800 chv_read_cgm_csc(crtc, csc: &crtc_state->csc);
801}
802
803static void chv_assign_csc(struct intel_crtc_state *crtc_state)
804{
805 struct intel_display *display = to_intel_display(crtc_state);
806
807 drm_WARN_ON(display->drm, crtc_state->wgc_enable);
808
809 if (crtc_state->hw.ctm) {
810 drm_WARN_ON(display->drm, (crtc_state->cgm_mode & CGM_PIPE_MODE_CSC) == 0);
811
812 chv_cgm_csc_convert_ctm(crtc_state, csc: &crtc_state->csc);
813 } else {
814 drm_WARN_ON(display->drm, (crtc_state->cgm_mode & CGM_PIPE_MODE_CSC) == 0);
815
816 crtc_state->csc = chv_cgm_csc_matrix_identity;
817 }
818}
819
820/* convert hw value with given bit_precision to lut property val */
821static u32 intel_color_lut_pack(u32 val, int bit_precision)
822{
823 if (bit_precision > 16)
824 return DIV_ROUND_CLOSEST_ULL(mul_u32_u32(val, (1 << 16) - 1),
825 (1 << bit_precision) - 1);
826 else
827 return DIV_ROUND_CLOSEST(val * ((1 << 16) - 1),
828 (1 << bit_precision) - 1);
829}
830
831static u32 i9xx_lut_8(const struct drm_color_lut *color)
832{
833 return REG_FIELD_PREP(PALETTE_RED_MASK, drm_color_lut_extract(color->red, 8)) |
834 REG_FIELD_PREP(PALETTE_GREEN_MASK, drm_color_lut_extract(color->green, 8)) |
835 REG_FIELD_PREP(PALETTE_BLUE_MASK, drm_color_lut_extract(color->blue, 8));
836}
837
838static void i9xx_lut_8_pack(struct drm_color_lut *entry, u32 val)
839{
840 entry->red = intel_color_lut_pack(REG_FIELD_GET(PALETTE_RED_MASK, val), bit_precision: 8);
841 entry->green = intel_color_lut_pack(REG_FIELD_GET(PALETTE_GREEN_MASK, val), bit_precision: 8);
842 entry->blue = intel_color_lut_pack(REG_FIELD_GET(PALETTE_BLUE_MASK, val), bit_precision: 8);
843}
844
845/* i8xx/i9xx+ 10bit slope format "even DW" (low 8 bits) */
846static u32 _i9xx_lut_10_ldw(u16 a)
847{
848 return drm_color_lut_extract(user_input: a, bit_precision: 10) & 0xff;
849}
850
851static u32 i9xx_lut_10_ldw(const struct drm_color_lut *color)
852{
853 return REG_FIELD_PREP(PALETTE_RED_MASK, _i9xx_lut_10_ldw(color[0].red)) |
854 REG_FIELD_PREP(PALETTE_GREEN_MASK, _i9xx_lut_10_ldw(color[0].green)) |
855 REG_FIELD_PREP(PALETTE_BLUE_MASK, _i9xx_lut_10_ldw(color[0].blue));
856}
857
858/* i8xx/i9xx+ 10bit slope format "odd DW" (high 2 bits + slope) */
859static u32 _i9xx_lut_10_udw(u16 a, u16 b)
860{
861 unsigned int mantissa, exponent;
862
863 a = drm_color_lut_extract(user_input: a, bit_precision: 10);
864 b = drm_color_lut_extract(user_input: b, bit_precision: 10);
865
866 /* b = a + 8 * m * 2 ^ -e */
867 mantissa = clamp(b - a, 0, 0x7f);
868 exponent = 3;
869 while (mantissa > 0xf) {
870 mantissa >>= 1;
871 exponent--;
872 }
873
874 return (exponent << 6) |
875 (mantissa << 2) |
876 (a >> 8);
877}
878
879static u32 i9xx_lut_10_udw(const struct drm_color_lut *color)
880{
881 return REG_FIELD_PREP(PALETTE_RED_MASK, _i9xx_lut_10_udw(color[0].red, color[1].red)) |
882 REG_FIELD_PREP(PALETTE_GREEN_MASK, _i9xx_lut_10_udw(color[0].green, color[1].green)) |
883 REG_FIELD_PREP(PALETTE_BLUE_MASK, _i9xx_lut_10_udw(color[0].blue, color[1].blue));
884}
885
886static void i9xx_lut_10_pack(struct drm_color_lut *color,
887 u32 ldw, u32 udw)
888{
889 u16 red = REG_FIELD_GET(PALETTE_10BIT_RED_LDW_MASK, ldw) |
890 REG_FIELD_GET(PALETTE_10BIT_RED_UDW_MASK, udw) << 8;
891 u16 green = REG_FIELD_GET(PALETTE_10BIT_GREEN_LDW_MASK, ldw) |
892 REG_FIELD_GET(PALETTE_10BIT_GREEN_UDW_MASK, udw) << 8;
893 u16 blue = REG_FIELD_GET(PALETTE_10BIT_BLUE_LDW_MASK, ldw) |
894 REG_FIELD_GET(PALETTE_10BIT_BLUE_UDW_MASK, udw) << 8;
895
896 color->red = intel_color_lut_pack(val: red, bit_precision: 10);
897 color->green = intel_color_lut_pack(val: green, bit_precision: 10);
898 color->blue = intel_color_lut_pack(val: blue, bit_precision: 10);
899}
900
901static void i9xx_lut_10_pack_slope(struct drm_color_lut *color,
902 u32 ldw, u32 udw)
903{
904 int r_exp = REG_FIELD_GET(PALETTE_10BIT_RED_EXP_MASK, udw);
905 int r_mant = REG_FIELD_GET(PALETTE_10BIT_RED_MANT_MASK, udw);
906 int g_exp = REG_FIELD_GET(PALETTE_10BIT_GREEN_EXP_MASK, udw);
907 int g_mant = REG_FIELD_GET(PALETTE_10BIT_GREEN_MANT_MASK, udw);
908 int b_exp = REG_FIELD_GET(PALETTE_10BIT_BLUE_EXP_MASK, udw);
909 int b_mant = REG_FIELD_GET(PALETTE_10BIT_BLUE_MANT_MASK, udw);
910
911 i9xx_lut_10_pack(color, ldw, udw);
912
913 color->red += r_mant << (3 - r_exp);
914 color->green += g_mant << (3 - g_exp);
915 color->blue += b_mant << (3 - b_exp);
916}
917
918/* i965+ "10.6" bit interpolated format "even DW" (low 8 bits) */
919static u32 i965_lut_10p6_ldw(const struct drm_color_lut *color)
920{
921 return REG_FIELD_PREP(PALETTE_RED_MASK, color->red & 0xff) |
922 REG_FIELD_PREP(PALETTE_GREEN_MASK, color->green & 0xff) |
923 REG_FIELD_PREP(PALETTE_BLUE_MASK, color->blue & 0xff);
924}
925
926/* i965+ "10.6" interpolated format "odd DW" (high 8 bits) */
927static u32 i965_lut_10p6_udw(const struct drm_color_lut *color)
928{
929 return REG_FIELD_PREP(PALETTE_RED_MASK, color->red >> 8) |
930 REG_FIELD_PREP(PALETTE_GREEN_MASK, color->green >> 8) |
931 REG_FIELD_PREP(PALETTE_BLUE_MASK, color->blue >> 8);
932}
933
934static void i965_lut_10p6_pack(struct drm_color_lut *entry, u32 ldw, u32 udw)
935{
936 entry->red = REG_FIELD_GET(PALETTE_RED_MASK, udw) << 8 |
937 REG_FIELD_GET(PALETTE_RED_MASK, ldw);
938 entry->green = REG_FIELD_GET(PALETTE_GREEN_MASK, udw) << 8 |
939 REG_FIELD_GET(PALETTE_GREEN_MASK, ldw);
940 entry->blue = REG_FIELD_GET(PALETTE_BLUE_MASK, udw) << 8 |
941 REG_FIELD_GET(PALETTE_BLUE_MASK, ldw);
942}
943
944static u16 i965_lut_11p6_max_pack(u32 val)
945{
946 /* PIPEGCMAX is 11.6, clamp to 10.6 */
947 return min(val, 0xffffu);
948}
949
950static u32 ilk_lut_10(const struct drm_color_lut *color)
951{
952 return REG_FIELD_PREP(PREC_PALETTE_10_RED_MASK, drm_color_lut_extract(color->red, 10)) |
953 REG_FIELD_PREP(PREC_PALETTE_10_GREEN_MASK, drm_color_lut_extract(color->green, 10)) |
954 REG_FIELD_PREP(PREC_PALETTE_10_BLUE_MASK, drm_color_lut_extract(color->blue, 10));
955}
956
957static void ilk_lut_10_pack(struct drm_color_lut *entry, u32 val)
958{
959 entry->red = intel_color_lut_pack(REG_FIELD_GET(PREC_PALETTE_10_RED_MASK, val), bit_precision: 10);
960 entry->green = intel_color_lut_pack(REG_FIELD_GET(PREC_PALETTE_10_GREEN_MASK, val), bit_precision: 10);
961 entry->blue = intel_color_lut_pack(REG_FIELD_GET(PREC_PALETTE_10_BLUE_MASK, val), bit_precision: 10);
962}
963
964/* ilk+ "12.4" interpolated format (low 6 bits) */
965static u32 ilk_lut_12p4_ldw(const struct drm_color_lut *color)
966{
967 return REG_FIELD_PREP(PREC_PALETTE_12P4_RED_LDW_MASK, color->red & 0x3f) |
968 REG_FIELD_PREP(PREC_PALETTE_12P4_GREEN_LDW_MASK, color->green & 0x3f) |
969 REG_FIELD_PREP(PREC_PALETTE_12P4_BLUE_LDW_MASK, color->blue & 0x3f);
970}
971
972/* ilk+ "12.4" interpolated format (high 10 bits) */
973static u32 ilk_lut_12p4_udw(const struct drm_color_lut *color)
974{
975 return REG_FIELD_PREP(PREC_PALETTE_12P4_RED_UDW_MASK, color->red >> 6) |
976 REG_FIELD_PREP(PREC_PALETTE_12P4_GREEN_UDW_MASK, color->green >> 6) |
977 REG_FIELD_PREP(PREC_PALETTE_12P4_BLUE_UDW_MASK, color->blue >> 6);
978}
979
980static void ilk_lut_12p4_pack(struct drm_color_lut *entry, u32 ldw, u32 udw)
981{
982 entry->red = REG_FIELD_GET(PREC_PALETTE_12P4_RED_UDW_MASK, udw) << 6 |
983 REG_FIELD_GET(PREC_PALETTE_12P4_RED_LDW_MASK, ldw);
984 entry->green = REG_FIELD_GET(PREC_PALETTE_12P4_GREEN_UDW_MASK, udw) << 6 |
985 REG_FIELD_GET(PREC_PALETTE_12P4_GREEN_LDW_MASK, ldw);
986 entry->blue = REG_FIELD_GET(PREC_PALETTE_12P4_BLUE_UDW_MASK, udw) << 6 |
987 REG_FIELD_GET(PREC_PALETTE_12P4_BLUE_LDW_MASK, ldw);
988}
989
990static void icl_color_commit_noarm(struct intel_dsb *dsb,
991 const struct intel_crtc_state *crtc_state)
992{
993 /*
994 * Despite Wa_1406463849, ICL no longer suffers from the SKL
995 * DC5/PSR CSC black screen issue (see skl_color_commit_noarm()).
996 * Possibly due to the extra sticky CSC arming
997 * (see icl_color_post_update()).
998 *
999 * On TGL+ all CSC arming issues have been properly fixed.
1000 */
1001 icl_load_csc_matrix(dsb, crtc_state);
1002}
1003
1004static void skl_color_commit_noarm(struct intel_dsb *dsb,
1005 const struct intel_crtc_state *crtc_state)
1006{
1007 /*
1008 * Possibly related to display WA #1184, SKL CSC loses the latched
1009 * CSC coeff/offset register values if the CSC registers are disarmed
1010 * between DC5 exit and PSR exit. This will cause the plane(s) to
1011 * output all black (until CSC_MODE is rearmed and properly latched).
1012 * Once PSR exit (and proper register latching) has occurred the
1013 * danger is over. Thus when PSR is enabled the CSC coeff/offset
1014 * register programming will be performed from skl_color_commit_arm()
1015 * which is called after PSR exit.
1016 */
1017 if (!crtc_state->has_psr)
1018 ilk_load_csc_matrix(dsb, crtc_state);
1019}
1020
1021static void ilk_color_commit_noarm(struct intel_dsb *dsb,
1022 const struct intel_crtc_state *crtc_state)
1023{
1024 ilk_load_csc_matrix(dsb, crtc_state);
1025}
1026
1027static void i9xx_color_commit_arm(struct intel_dsb *dsb,
1028 const struct intel_crtc_state *crtc_state)
1029{
1030 /* update TRANSCONF GAMMA_MODE */
1031 i9xx_set_pipeconf(crtc_state);
1032}
1033
1034static void ilk_color_commit_arm(struct intel_dsb *dsb,
1035 const struct intel_crtc_state *crtc_state)
1036{
1037 struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
1038 struct intel_display *display = to_intel_display(crtc);
1039
1040 /* update TRANSCONF GAMMA_MODE */
1041 ilk_set_pipeconf(crtc_state);
1042
1043 intel_de_write_fw(display, PIPE_CSC_MODE(crtc->pipe),
1044 val: crtc_state->csc_mode);
1045}
1046
1047static void hsw_color_commit_arm(struct intel_dsb *dsb,
1048 const struct intel_crtc_state *crtc_state)
1049{
1050 struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
1051 struct intel_display *display = to_intel_display(crtc);
1052
1053 intel_de_write(display, GAMMA_MODE(crtc->pipe),
1054 val: crtc_state->gamma_mode);
1055
1056 intel_de_write_fw(display, PIPE_CSC_MODE(crtc->pipe),
1057 val: crtc_state->csc_mode);
1058}
1059
1060static u32 hsw_read_gamma_mode(struct intel_crtc *crtc)
1061{
1062 struct intel_display *display = to_intel_display(crtc);
1063
1064 return intel_de_read(display, GAMMA_MODE(crtc->pipe));
1065}
1066
1067static u32 ilk_read_csc_mode(struct intel_crtc *crtc)
1068{
1069 struct intel_display *display = to_intel_display(crtc);
1070
1071 return intel_de_read(display, PIPE_CSC_MODE(crtc->pipe));
1072}
1073
1074static void i9xx_get_config(struct intel_crtc_state *crtc_state)
1075{
1076 struct intel_display *display = to_intel_display(crtc_state);
1077 struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
1078 struct intel_plane *plane = to_intel_plane(crtc->base.primary);
1079 enum i9xx_plane_id i9xx_plane = plane->i9xx_plane;
1080 u32 tmp;
1081
1082 tmp = intel_de_read(display, DSPCNTR(display, i9xx_plane));
1083
1084 if (tmp & DISP_PIPE_GAMMA_ENABLE)
1085 crtc_state->gamma_enable = true;
1086
1087 if (!HAS_GMCH(display) && tmp & DISP_PIPE_CSC_ENABLE)
1088 crtc_state->csc_enable = true;
1089}
1090
1091static void hsw_get_config(struct intel_crtc_state *crtc_state)
1092{
1093 struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
1094
1095 crtc_state->gamma_mode = hsw_read_gamma_mode(crtc);
1096 crtc_state->csc_mode = ilk_read_csc_mode(crtc);
1097
1098 i9xx_get_config(crtc_state);
1099}
1100
1101static void skl_get_config(struct intel_crtc_state *crtc_state)
1102{
1103 struct intel_display *display = to_intel_display(crtc_state);
1104 struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
1105
1106 crtc_state->gamma_mode = hsw_read_gamma_mode(crtc);
1107 crtc_state->csc_mode = ilk_read_csc_mode(crtc);
1108
1109 if (DISPLAY_VER(display) < 35) {
1110 u32 tmp = intel_de_read(display, SKL_BOTTOM_COLOR(crtc->pipe));
1111
1112 if (tmp & SKL_BOTTOM_COLOR_GAMMA_ENABLE)
1113 crtc_state->gamma_enable = true;
1114
1115 if (tmp & SKL_BOTTOM_COLOR_CSC_ENABLE)
1116 crtc_state->csc_enable = true;
1117 }
1118}
1119
1120static void skl_color_commit_arm(struct intel_dsb *dsb,
1121 const struct intel_crtc_state *crtc_state)
1122{
1123 struct intel_display *display = to_intel_display(crtc_state);
1124 struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
1125 enum pipe pipe = crtc->pipe;
1126 u32 val = 0;
1127
1128 if (crtc_state->has_psr)
1129 ilk_load_csc_matrix(dsb, crtc_state);
1130
1131 /*
1132 * We don't (yet) allow userspace to control the pipe background color,
1133 * so force it to black, but apply pipe gamma and CSC appropriately
1134 * so that its handling will match how we program our planes.
1135 */
1136 if (crtc_state->gamma_enable)
1137 val |= SKL_BOTTOM_COLOR_GAMMA_ENABLE;
1138 if (crtc_state->csc_enable)
1139 val |= SKL_BOTTOM_COLOR_CSC_ENABLE;
1140 intel_de_write_dsb(display, dsb, SKL_BOTTOM_COLOR(pipe), val);
1141
1142 intel_de_write_dsb(display, dsb, GAMMA_MODE(crtc->pipe), val: crtc_state->gamma_mode);
1143
1144 intel_de_write_dsb(display, dsb, PIPE_CSC_MODE(crtc->pipe), val: crtc_state->csc_mode);
1145}
1146
1147static void icl_color_commit_arm(struct intel_dsb *dsb,
1148 const struct intel_crtc_state *crtc_state)
1149{
1150 struct intel_display *display = to_intel_display(crtc_state);
1151 struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
1152 enum pipe pipe = crtc->pipe;
1153
1154 /*
1155 * We don't (yet) allow userspace to control the pipe background color,
1156 * so force it to black.
1157 */
1158 intel_de_write_dsb(display, dsb, SKL_BOTTOM_COLOR(pipe), val: 0);
1159
1160 intel_de_write_dsb(display, dsb, GAMMA_MODE(crtc->pipe), val: crtc_state->gamma_mode);
1161
1162 intel_de_write_dsb(display, dsb, PIPE_CSC_MODE(crtc->pipe), val: crtc_state->csc_mode);
1163}
1164
1165static void icl_color_post_update(const struct intel_crtc_state *crtc_state)
1166{
1167 struct intel_display *display = to_intel_display(crtc_state);
1168 struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
1169
1170 /*
1171 * Despite Wa_1406463849, ICL CSC is no longer disarmed by
1172 * coeff/offset register *writes*. Instead, once CSC_MODE
1173 * is armed it stays armed, even after it has been latched.
1174 * Afterwards the coeff/offset registers become effectively
1175 * self-arming. That self-arming must be disabled before the
1176 * next icl_color_commit_noarm() tries to write the next set
1177 * of coeff/offset registers. Fortunately register *reads*
1178 * do still disarm the CSC. Naturally this must not be done
1179 * until the previously written CSC registers have actually
1180 * been latched.
1181 *
1182 * TGL+ no longer need this workaround.
1183 */
1184 intel_de_read_fw(display, PIPE_CSC_PREOFF_HI(crtc->pipe));
1185}
1186
1187static struct drm_property_blob *
1188create_linear_lut(struct intel_display *display, int lut_size)
1189{
1190 struct drm_property_blob *blob;
1191 struct drm_color_lut *lut;
1192 int i;
1193
1194 blob = drm_property_create_blob(dev: display->drm,
1195 length: sizeof(lut[0]) * lut_size,
1196 NULL);
1197 if (IS_ERR(ptr: blob))
1198 return blob;
1199
1200 lut = blob->data;
1201
1202 for (i = 0; i < lut_size; i++) {
1203 u16 val = 0xffff * i / (lut_size - 1);
1204
1205 lut[i].red = val;
1206 lut[i].green = val;
1207 lut[i].blue = val;
1208 }
1209
1210 return blob;
1211}
1212
1213static u16 lut_limited_range(unsigned int value)
1214{
1215 unsigned int min = 16 << 8;
1216 unsigned int max = 235 << 8;
1217
1218 return value * (max - min) / 0xffff + min;
1219}
1220
1221static struct drm_property_blob *
1222create_resized_lut(struct intel_display *display,
1223 const struct drm_property_blob *blob_in, int lut_out_size,
1224 bool limited_color_range)
1225{
1226 int i, lut_in_size = drm_color_lut_size(blob: blob_in);
1227 struct drm_property_blob *blob_out;
1228 const struct drm_color_lut *lut_in;
1229 struct drm_color_lut *lut_out;
1230
1231 blob_out = drm_property_create_blob(dev: display->drm,
1232 length: sizeof(lut_out[0]) * lut_out_size,
1233 NULL);
1234 if (IS_ERR(ptr: blob_out))
1235 return blob_out;
1236
1237 lut_in = blob_in->data;
1238 lut_out = blob_out->data;
1239
1240 for (i = 0; i < lut_out_size; i++) {
1241 const struct drm_color_lut *entry =
1242 &lut_in[i * (lut_in_size - 1) / (lut_out_size - 1)];
1243
1244 if (limited_color_range) {
1245 lut_out[i].red = lut_limited_range(value: entry->red);
1246 lut_out[i].green = lut_limited_range(value: entry->green);
1247 lut_out[i].blue = lut_limited_range(value: entry->blue);
1248 } else {
1249 lut_out[i] = *entry;
1250 }
1251 }
1252
1253 return blob_out;
1254}
1255
1256static void i9xx_load_lut_8(struct intel_crtc *crtc,
1257 const struct drm_property_blob *blob)
1258{
1259 struct intel_display *display = to_intel_display(crtc);
1260 const struct drm_color_lut *lut;
1261 enum pipe pipe = crtc->pipe;
1262 int i;
1263
1264 if (!blob)
1265 return;
1266
1267 lut = blob->data;
1268
1269 for (i = 0; i < 256; i++)
1270 intel_de_write_fw(display, PALETTE(display, pipe, i),
1271 val: i9xx_lut_8(color: &lut[i]));
1272}
1273
1274static void i9xx_load_lut_10(struct intel_crtc *crtc,
1275 const struct drm_property_blob *blob)
1276{
1277 struct intel_display *display = to_intel_display(crtc);
1278 const struct drm_color_lut *lut = blob->data;
1279 int i, lut_size = drm_color_lut_size(blob);
1280 enum pipe pipe = crtc->pipe;
1281
1282 for (i = 0; i < lut_size - 1; i++) {
1283 intel_de_write_fw(display,
1284 PALETTE(display, pipe, 2 * i + 0),
1285 val: i9xx_lut_10_ldw(color: &lut[i]));
1286 intel_de_write_fw(display,
1287 PALETTE(display, pipe, 2 * i + 1),
1288 val: i9xx_lut_10_udw(color: &lut[i]));
1289 }
1290}
1291
1292static void i9xx_load_luts(const struct intel_crtc_state *crtc_state)
1293{
1294 struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
1295 const struct drm_property_blob *post_csc_lut = crtc_state->post_csc_lut;
1296
1297 switch (crtc_state->gamma_mode) {
1298 case GAMMA_MODE_MODE_8BIT:
1299 i9xx_load_lut_8(crtc, blob: post_csc_lut);
1300 break;
1301 case GAMMA_MODE_MODE_10BIT:
1302 i9xx_load_lut_10(crtc, blob: post_csc_lut);
1303 break;
1304 default:
1305 MISSING_CASE(crtc_state->gamma_mode);
1306 break;
1307 }
1308}
1309
1310static void i965_load_lut_10p6(struct intel_crtc *crtc,
1311 const struct drm_property_blob *blob)
1312{
1313 struct intel_display *display = to_intel_display(crtc);
1314 const struct drm_color_lut *lut = blob->data;
1315 int i, lut_size = drm_color_lut_size(blob);
1316 enum pipe pipe = crtc->pipe;
1317
1318 for (i = 0; i < lut_size - 1; i++) {
1319 intel_de_write_fw(display,
1320 PALETTE(display, pipe, 2 * i + 0),
1321 val: i965_lut_10p6_ldw(color: &lut[i]));
1322 intel_de_write_fw(display,
1323 PALETTE(display, pipe, 2 * i + 1),
1324 val: i965_lut_10p6_udw(color: &lut[i]));
1325 }
1326
1327 intel_de_write_fw(display, PIPEGCMAX(display, pipe, 0), val: lut[i].red);
1328 intel_de_write_fw(display, PIPEGCMAX(display, pipe, 1), val: lut[i].green);
1329 intel_de_write_fw(display, PIPEGCMAX(display, pipe, 2), val: lut[i].blue);
1330}
1331
1332static void i965_load_luts(const struct intel_crtc_state *crtc_state)
1333{
1334 struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
1335 const struct drm_property_blob *post_csc_lut = crtc_state->post_csc_lut;
1336
1337 switch (crtc_state->gamma_mode) {
1338 case GAMMA_MODE_MODE_8BIT:
1339 i9xx_load_lut_8(crtc, blob: post_csc_lut);
1340 break;
1341 case GAMMA_MODE_MODE_10BIT:
1342 i965_load_lut_10p6(crtc, blob: post_csc_lut);
1343 break;
1344 default:
1345 MISSING_CASE(crtc_state->gamma_mode);
1346 break;
1347 }
1348}
1349
1350static void ilk_lut_write(const struct intel_crtc_state *crtc_state,
1351 i915_reg_t reg, u32 val)
1352{
1353 struct intel_display *display = to_intel_display(crtc_state);
1354
1355 if (crtc_state->dsb_color)
1356 intel_dsb_reg_write(dsb: crtc_state->dsb_color, reg, val);
1357 else
1358 intel_de_write_fw(display, reg, val);
1359}
1360
1361static void ilk_lut_write_indexed(const struct intel_crtc_state *crtc_state,
1362 i915_reg_t reg, u32 val)
1363{
1364 struct intel_display *display = to_intel_display(crtc_state);
1365
1366 if (crtc_state->dsb_color)
1367 intel_dsb_reg_write_indexed(dsb: crtc_state->dsb_color, reg, val);
1368 else
1369 intel_de_write_fw(display, reg, val);
1370}
1371
1372static void ilk_load_lut_8(const struct intel_crtc_state *crtc_state,
1373 const struct drm_property_blob *blob)
1374{
1375 struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
1376 const struct drm_color_lut *lut;
1377 enum pipe pipe = crtc->pipe;
1378 int i;
1379
1380 if (!blob)
1381 return;
1382
1383 lut = blob->data;
1384
1385 /*
1386 * DSB fails to correctly load the legacy LUT unless
1387 * we either write each entry twice when using posted
1388 * writes, or we use non-posted writes.
1389 *
1390 * If palette anti-collision is active during LUT
1391 * register writes:
1392 * - posted writes simply get dropped and thus the LUT
1393 * contents may not be correctly updated
1394 * - non-posted writes are blocked and thus the LUT
1395 * contents are always correct, but simultaneous CPU
1396 * MMIO access will start to fail
1397 *
1398 * Choose the lesser of two evils and use posted writes.
1399 * Using posted writes is also faster, even when having
1400 * to write each register twice.
1401 */
1402 for (i = 0; i < 256; i++) {
1403 ilk_lut_write(crtc_state, LGC_PALETTE(pipe, i),
1404 val: i9xx_lut_8(color: &lut[i]));
1405 if (crtc_state->dsb_color)
1406 ilk_lut_write(crtc_state, LGC_PALETTE(pipe, i),
1407 val: i9xx_lut_8(color: &lut[i]));
1408 }
1409}
1410
1411static void ilk_load_lut_10(const struct intel_crtc_state *crtc_state,
1412 const struct drm_property_blob *blob)
1413{
1414 struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
1415 const struct drm_color_lut *lut = blob->data;
1416 int i, lut_size = drm_color_lut_size(blob);
1417 enum pipe pipe = crtc->pipe;
1418
1419 for (i = 0; i < lut_size; i++)
1420 ilk_lut_write(crtc_state, PREC_PALETTE(pipe, i),
1421 val: ilk_lut_10(color: &lut[i]));
1422}
1423
1424static void ilk_load_luts(const struct intel_crtc_state *crtc_state)
1425{
1426 const struct drm_property_blob *post_csc_lut = crtc_state->post_csc_lut;
1427 const struct drm_property_blob *pre_csc_lut = crtc_state->pre_csc_lut;
1428 const struct drm_property_blob *blob = post_csc_lut ?: pre_csc_lut;
1429
1430 switch (crtc_state->gamma_mode) {
1431 case GAMMA_MODE_MODE_8BIT:
1432 ilk_load_lut_8(crtc_state, blob);
1433 break;
1434 case GAMMA_MODE_MODE_10BIT:
1435 ilk_load_lut_10(crtc_state, blob);
1436 break;
1437 default:
1438 MISSING_CASE(crtc_state->gamma_mode);
1439 break;
1440 }
1441}
1442
1443static int ivb_lut_10_size(u32 prec_index)
1444{
1445 if (prec_index & PAL_PREC_SPLIT_MODE)
1446 return 512;
1447 else
1448 return 1024;
1449}
1450
1451/*
1452 * IVB/HSW Bspec / PAL_PREC_INDEX:
1453 * "Restriction : Index auto increment mode is not
1454 * supported and must not be enabled."
1455 */
1456static void ivb_load_lut_10(const struct intel_crtc_state *crtc_state,
1457 const struct drm_property_blob *blob,
1458 u32 prec_index)
1459{
1460 const struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
1461 const struct drm_color_lut *lut = blob->data;
1462 int i, lut_size = drm_color_lut_size(blob);
1463 enum pipe pipe = crtc->pipe;
1464
1465 for (i = 0; i < lut_size; i++) {
1466 ilk_lut_write(crtc_state, PREC_PAL_INDEX(pipe),
1467 val: prec_index + i);
1468 ilk_lut_write(crtc_state, PREC_PAL_DATA(pipe),
1469 val: ilk_lut_10(color: &lut[i]));
1470 }
1471
1472 /*
1473 * Reset the index, otherwise it prevents the legacy palette to be
1474 * written properly.
1475 */
1476 ilk_lut_write(crtc_state, PREC_PAL_INDEX(pipe),
1477 PAL_PREC_INDEX_VALUE(0));
1478}
1479
1480/* On BDW+ the index auto increment mode actually works */
1481static void bdw_load_lut_10(const struct intel_crtc_state *crtc_state,
1482 const struct drm_property_blob *blob,
1483 u32 prec_index)
1484{
1485 struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
1486 const struct drm_color_lut *lut = blob->data;
1487 int i, lut_size = drm_color_lut_size(blob);
1488 enum pipe pipe = crtc->pipe;
1489
1490 ilk_lut_write(crtc_state, PREC_PAL_INDEX(pipe),
1491 val: prec_index);
1492 ilk_lut_write(crtc_state, PREC_PAL_INDEX(pipe),
1493 PAL_PREC_AUTO_INCREMENT |
1494 prec_index);
1495
1496 for (i = 0; i < lut_size; i++)
1497 ilk_lut_write_indexed(crtc_state, PREC_PAL_DATA(pipe),
1498 val: ilk_lut_10(color: &lut[i]));
1499
1500 /*
1501 * Reset the index, otherwise it prevents the legacy palette to be
1502 * written properly.
1503 */
1504 ilk_lut_write(crtc_state, PREC_PAL_INDEX(pipe),
1505 PAL_PREC_INDEX_VALUE(0));
1506}
1507
1508static void ivb_load_lut_ext_max(const struct intel_crtc_state *crtc_state)
1509{
1510 struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
1511 enum pipe pipe = crtc->pipe;
1512
1513 /* Program the max register to clamp values > 1.0. */
1514 ilk_lut_write(crtc_state, PREC_PAL_EXT_GC_MAX(pipe, 0), val: 1 << 16);
1515 ilk_lut_write(crtc_state, PREC_PAL_EXT_GC_MAX(pipe, 1), val: 1 << 16);
1516 ilk_lut_write(crtc_state, PREC_PAL_EXT_GC_MAX(pipe, 2), val: 1 << 16);
1517}
1518
1519static void glk_load_lut_ext2_max(const struct intel_crtc_state *crtc_state)
1520{
1521 struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
1522 enum pipe pipe = crtc->pipe;
1523
1524 /* Program the max register to clamp values > 1.0. */
1525 ilk_lut_write(crtc_state, PREC_PAL_EXT2_GC_MAX(pipe, 0), val: 1 << 16);
1526 ilk_lut_write(crtc_state, PREC_PAL_EXT2_GC_MAX(pipe, 1), val: 1 << 16);
1527 ilk_lut_write(crtc_state, PREC_PAL_EXT2_GC_MAX(pipe, 2), val: 1 << 16);
1528}
1529
1530static void ivb_load_luts(const struct intel_crtc_state *crtc_state)
1531{
1532 const struct drm_property_blob *post_csc_lut = crtc_state->post_csc_lut;
1533 const struct drm_property_blob *pre_csc_lut = crtc_state->pre_csc_lut;
1534 const struct drm_property_blob *blob = post_csc_lut ?: pre_csc_lut;
1535
1536 switch (crtc_state->gamma_mode) {
1537 case GAMMA_MODE_MODE_8BIT:
1538 ilk_load_lut_8(crtc_state, blob);
1539 break;
1540 case GAMMA_MODE_MODE_SPLIT:
1541 ivb_load_lut_10(crtc_state, blob: pre_csc_lut, PAL_PREC_SPLIT_MODE |
1542 PAL_PREC_INDEX_VALUE(0));
1543 ivb_load_lut_ext_max(crtc_state);
1544 ivb_load_lut_10(crtc_state, blob: post_csc_lut, PAL_PREC_SPLIT_MODE |
1545 PAL_PREC_INDEX_VALUE(512));
1546 break;
1547 case GAMMA_MODE_MODE_10BIT:
1548 ivb_load_lut_10(crtc_state, blob,
1549 PAL_PREC_INDEX_VALUE(0));
1550 ivb_load_lut_ext_max(crtc_state);
1551 break;
1552 default:
1553 MISSING_CASE(crtc_state->gamma_mode);
1554 break;
1555 }
1556}
1557
1558static void bdw_load_luts(const struct intel_crtc_state *crtc_state)
1559{
1560 const struct drm_property_blob *post_csc_lut = crtc_state->post_csc_lut;
1561 const struct drm_property_blob *pre_csc_lut = crtc_state->pre_csc_lut;
1562 const struct drm_property_blob *blob = post_csc_lut ?: pre_csc_lut;
1563
1564 switch (crtc_state->gamma_mode) {
1565 case GAMMA_MODE_MODE_8BIT:
1566 ilk_load_lut_8(crtc_state, blob);
1567 break;
1568 case GAMMA_MODE_MODE_SPLIT:
1569 bdw_load_lut_10(crtc_state, blob: pre_csc_lut, PAL_PREC_SPLIT_MODE |
1570 PAL_PREC_INDEX_VALUE(0));
1571 ivb_load_lut_ext_max(crtc_state);
1572 bdw_load_lut_10(crtc_state, blob: post_csc_lut, PAL_PREC_SPLIT_MODE |
1573 PAL_PREC_INDEX_VALUE(512));
1574 break;
1575 case GAMMA_MODE_MODE_10BIT:
1576 bdw_load_lut_10(crtc_state, blob,
1577 PAL_PREC_INDEX_VALUE(0));
1578 ivb_load_lut_ext_max(crtc_state);
1579 break;
1580 default:
1581 MISSING_CASE(crtc_state->gamma_mode);
1582 break;
1583 }
1584}
1585
1586static int glk_degamma_lut_size(struct intel_display *display)
1587{
1588 if (DISPLAY_VER(display) >= 13)
1589 return 131;
1590 else
1591 return 35;
1592}
1593
1594static u32 glk_degamma_lut(const struct drm_color_lut *color)
1595{
1596 return color->green;
1597}
1598
1599static void glk_degamma_lut_pack(struct drm_color_lut *entry, u32 val)
1600{
1601 /* PRE_CSC_GAMC_DATA is 3.16, clamp to 0.16 */
1602 entry->red = entry->green = entry->blue = min(val, 0xffffu);
1603}
1604
1605static u32 mtl_degamma_lut(const struct drm_color_lut *color)
1606{
1607 return drm_color_lut_extract(user_input: color->green, bit_precision: 24);
1608}
1609
1610static void mtl_degamma_lut_pack(struct drm_color_lut *entry, u32 val)
1611{
1612 /* PRE_CSC_GAMC_DATA is 3.24, clamp to 0.16 */
1613 entry->red = entry->green = entry->blue =
1614 intel_color_lut_pack(min(val, 0xffffffu), bit_precision: 24);
1615}
1616
1617static void glk_load_degamma_lut(const struct intel_crtc_state *crtc_state,
1618 const struct drm_property_blob *blob)
1619{
1620 struct intel_display *display = to_intel_display(crtc_state);
1621 struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
1622 const struct drm_color_lut *lut = blob->data;
1623 int i, lut_size = drm_color_lut_size(blob);
1624 enum pipe pipe = crtc->pipe;
1625
1626 /*
1627 * When setting the auto-increment bit, the hardware seems to
1628 * ignore the index bits, so we need to reset it to index 0
1629 * separately.
1630 */
1631 ilk_lut_write(crtc_state, PRE_CSC_GAMC_INDEX(pipe),
1632 PRE_CSC_GAMC_INDEX_VALUE(0));
1633 ilk_lut_write(crtc_state, PRE_CSC_GAMC_INDEX(pipe),
1634 PRE_CSC_GAMC_AUTO_INCREMENT |
1635 PRE_CSC_GAMC_INDEX_VALUE(0));
1636
1637 for (i = 0; i < lut_size; i++) {
1638 /*
1639 * First lut_size entries represent range from 0 to 1.0
1640 * 3 additional lut entries will represent extended range
1641 * inputs 3.0 and 7.0 respectively, currently clamped
1642 * at 1.0. Since the precision is 16bit, the user
1643 * value can be directly filled to register.
1644 * The pipe degamma table in GLK+ onwards doesn't
1645 * support different values per channel, so this just
1646 * programs green value which will be equal to Red and
1647 * Blue into the lut registers.
1648 * ToDo: Extend to max 7.0. Enable 32 bit input value
1649 * as compared to just 16 to achieve this.
1650 */
1651 ilk_lut_write_indexed(crtc_state, PRE_CSC_GAMC_DATA(pipe),
1652 DISPLAY_VER(display) >= 14 ?
1653 mtl_degamma_lut(color: &lut[i]) : glk_degamma_lut(color: &lut[i]));
1654 }
1655
1656 /* Clamp values > 1.0. */
1657 while (i++ < glk_degamma_lut_size(display))
1658 ilk_lut_write_indexed(crtc_state, PRE_CSC_GAMC_DATA(pipe),
1659 DISPLAY_VER(display) >= 14 ?
1660 1 << 24 : 1 << 16);
1661
1662 ilk_lut_write(crtc_state, PRE_CSC_GAMC_INDEX(pipe), val: 0);
1663}
1664
1665static void glk_load_luts(const struct intel_crtc_state *crtc_state)
1666{
1667 const struct drm_property_blob *pre_csc_lut = crtc_state->pre_csc_lut;
1668 const struct drm_property_blob *post_csc_lut = crtc_state->post_csc_lut;
1669
1670 if (pre_csc_lut)
1671 glk_load_degamma_lut(crtc_state, blob: pre_csc_lut);
1672
1673 switch (crtc_state->gamma_mode) {
1674 case GAMMA_MODE_MODE_8BIT:
1675 ilk_load_lut_8(crtc_state, blob: post_csc_lut);
1676 break;
1677 case GAMMA_MODE_MODE_10BIT:
1678 bdw_load_lut_10(crtc_state, blob: post_csc_lut, PAL_PREC_INDEX_VALUE(0));
1679 ivb_load_lut_ext_max(crtc_state);
1680 glk_load_lut_ext2_max(crtc_state);
1681 break;
1682 default:
1683 MISSING_CASE(crtc_state->gamma_mode);
1684 break;
1685 }
1686}
1687
1688static void
1689ivb_load_lut_max(const struct intel_crtc_state *crtc_state,
1690 const struct drm_color_lut *color)
1691{
1692 struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
1693 enum pipe pipe = crtc->pipe;
1694
1695 /* FIXME LUT entries are 16 bit only, so we can prog 0xFFFF max */
1696 ilk_lut_write(crtc_state, PREC_PAL_GC_MAX(pipe, 0), val: color->red);
1697 ilk_lut_write(crtc_state, PREC_PAL_GC_MAX(pipe, 1), val: color->green);
1698 ilk_lut_write(crtc_state, PREC_PAL_GC_MAX(pipe, 2), val: color->blue);
1699}
1700
1701static void
1702icl_program_gamma_superfine_segment(const struct intel_crtc_state *crtc_state)
1703{
1704 struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
1705 const struct drm_property_blob *blob = crtc_state->post_csc_lut;
1706 const struct drm_color_lut *lut = blob->data;
1707 enum pipe pipe = crtc->pipe;
1708 int i;
1709
1710 /*
1711 * Program Super Fine segment (let's call it seg1)...
1712 *
1713 * Super Fine segment's step is 1/(8 * 128 * 256) and it has
1714 * 9 entries, corresponding to values 0, 1/(8 * 128 * 256),
1715 * 2/(8 * 128 * 256) ... 8/(8 * 128 * 256).
1716 */
1717 ilk_lut_write(crtc_state, PREC_PAL_MULTI_SEG_INDEX(pipe),
1718 PAL_PREC_MULTI_SEG_INDEX_VALUE(0));
1719 ilk_lut_write(crtc_state, PREC_PAL_MULTI_SEG_INDEX(pipe),
1720 PAL_PREC_AUTO_INCREMENT |
1721 PAL_PREC_MULTI_SEG_INDEX_VALUE(0));
1722
1723 for (i = 0; i < 9; i++) {
1724 const struct drm_color_lut *entry = &lut[i];
1725
1726 ilk_lut_write_indexed(crtc_state, PREC_PAL_MULTI_SEG_DATA(pipe),
1727 val: ilk_lut_12p4_ldw(color: entry));
1728 ilk_lut_write_indexed(crtc_state, PREC_PAL_MULTI_SEG_DATA(pipe),
1729 val: ilk_lut_12p4_udw(color: entry));
1730 }
1731
1732 ilk_lut_write(crtc_state, PREC_PAL_MULTI_SEG_INDEX(pipe),
1733 PAL_PREC_MULTI_SEG_INDEX_VALUE(0));
1734}
1735
1736static void
1737icl_program_gamma_multi_segment(const struct intel_crtc_state *crtc_state)
1738{
1739 struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
1740 const struct drm_property_blob *blob = crtc_state->post_csc_lut;
1741 const struct drm_color_lut *lut = blob->data;
1742 const struct drm_color_lut *entry;
1743 enum pipe pipe = crtc->pipe;
1744 int i;
1745
1746 /*
1747 * Program Fine segment (let's call it seg2)...
1748 *
1749 * Fine segment's step is 1/(128 * 256) i.e. 1/(128 * 256), 2/(128 * 256)
1750 * ... 256/(128 * 256). So in order to program fine segment of LUT we
1751 * need to pick every 8th entry in the LUT, and program 256 indexes.
1752 *
1753 * PAL_PREC_INDEX[0] and PAL_PREC_INDEX[1] map to seg2[1],
1754 * seg2[0] being unused by the hardware.
1755 */
1756 ilk_lut_write(crtc_state, PREC_PAL_INDEX(pipe),
1757 PAL_PREC_INDEX_VALUE(0));
1758 ilk_lut_write(crtc_state, PREC_PAL_INDEX(pipe),
1759 PAL_PREC_AUTO_INCREMENT |
1760 PAL_PREC_INDEX_VALUE(0));
1761
1762 for (i = 1; i < 257; i++) {
1763 entry = &lut[i * 8];
1764
1765 ilk_lut_write_indexed(crtc_state, PREC_PAL_DATA(pipe),
1766 val: ilk_lut_12p4_ldw(color: entry));
1767 ilk_lut_write_indexed(crtc_state, PREC_PAL_DATA(pipe),
1768 val: ilk_lut_12p4_udw(color: entry));
1769 }
1770
1771 /*
1772 * Program Coarse segment (let's call it seg3)...
1773 *
1774 * Coarse segment starts from index 0 and it's step is 1/256 ie 0,
1775 * 1/256, 2/256 ... 256/256. As per the description of each entry in LUT
1776 * above, we need to pick every (8 * 128)th entry in LUT, and
1777 * program 256 of those.
1778 *
1779 * Spec is not very clear about if entries seg3[0] and seg3[1] are
1780 * being used or not, but we still need to program these to advance
1781 * the index.
1782 */
1783 for (i = 0; i < 256; i++) {
1784 entry = &lut[i * 8 * 128];
1785
1786 ilk_lut_write_indexed(crtc_state, PREC_PAL_DATA(pipe),
1787 val: ilk_lut_12p4_ldw(color: entry));
1788 ilk_lut_write_indexed(crtc_state, PREC_PAL_DATA(pipe),
1789 val: ilk_lut_12p4_udw(color: entry));
1790 }
1791
1792 ilk_lut_write(crtc_state, PREC_PAL_INDEX(pipe),
1793 PAL_PREC_INDEX_VALUE(0));
1794
1795 /* The last entry in the LUT is to be programmed in GCMAX */
1796 entry = &lut[256 * 8 * 128];
1797 ivb_load_lut_max(crtc_state, color: entry);
1798}
1799
1800static void icl_load_luts(const struct intel_crtc_state *crtc_state)
1801{
1802 const struct drm_property_blob *pre_csc_lut = crtc_state->pre_csc_lut;
1803 const struct drm_property_blob *post_csc_lut = crtc_state->post_csc_lut;
1804
1805 if (pre_csc_lut)
1806 glk_load_degamma_lut(crtc_state, blob: pre_csc_lut);
1807
1808 switch (crtc_state->gamma_mode & GAMMA_MODE_MODE_MASK) {
1809 case GAMMA_MODE_MODE_8BIT:
1810 ilk_load_lut_8(crtc_state, blob: post_csc_lut);
1811 break;
1812 case GAMMA_MODE_MODE_12BIT_MULTI_SEG:
1813 icl_program_gamma_superfine_segment(crtc_state);
1814 icl_program_gamma_multi_segment(crtc_state);
1815 ivb_load_lut_ext_max(crtc_state);
1816 glk_load_lut_ext2_max(crtc_state);
1817 break;
1818 case GAMMA_MODE_MODE_10BIT:
1819 bdw_load_lut_10(crtc_state, blob: post_csc_lut, PAL_PREC_INDEX_VALUE(0));
1820 ivb_load_lut_ext_max(crtc_state);
1821 glk_load_lut_ext2_max(crtc_state);
1822 break;
1823 default:
1824 MISSING_CASE(crtc_state->gamma_mode);
1825 break;
1826 }
1827}
1828
1829static void vlv_load_luts(const struct intel_crtc_state *crtc_state)
1830{
1831 struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
1832
1833 if (crtc_state->wgc_enable)
1834 vlv_load_wgc_csc(crtc, csc: &crtc_state->csc);
1835
1836 i965_load_luts(crtc_state);
1837}
1838
1839static u32 chv_cgm_degamma_ldw(const struct drm_color_lut *color)
1840{
1841 return REG_FIELD_PREP(CGM_PIPE_DEGAMMA_GREEN_LDW_MASK, drm_color_lut_extract(color->green, 14)) |
1842 REG_FIELD_PREP(CGM_PIPE_DEGAMMA_BLUE_LDW_MASK, drm_color_lut_extract(color->blue, 14));
1843}
1844
1845static u32 chv_cgm_degamma_udw(const struct drm_color_lut *color)
1846{
1847 return REG_FIELD_PREP(CGM_PIPE_DEGAMMA_RED_UDW_MASK, drm_color_lut_extract(color->red, 14));
1848}
1849
1850static void chv_cgm_degamma_pack(struct drm_color_lut *entry, u32 ldw, u32 udw)
1851{
1852 entry->green = intel_color_lut_pack(REG_FIELD_GET(CGM_PIPE_DEGAMMA_GREEN_LDW_MASK, ldw), bit_precision: 14);
1853 entry->blue = intel_color_lut_pack(REG_FIELD_GET(CGM_PIPE_DEGAMMA_BLUE_LDW_MASK, ldw), bit_precision: 14);
1854 entry->red = intel_color_lut_pack(REG_FIELD_GET(CGM_PIPE_DEGAMMA_RED_UDW_MASK, udw), bit_precision: 14);
1855}
1856
1857static void chv_load_cgm_degamma(struct intel_crtc *crtc,
1858 const struct drm_property_blob *blob)
1859{
1860 struct intel_display *display = to_intel_display(crtc);
1861 const struct drm_color_lut *lut = blob->data;
1862 int i, lut_size = drm_color_lut_size(blob);
1863 enum pipe pipe = crtc->pipe;
1864
1865 for (i = 0; i < lut_size; i++) {
1866 intel_de_write_fw(display, CGM_PIPE_DEGAMMA(pipe, i, 0),
1867 val: chv_cgm_degamma_ldw(color: &lut[i]));
1868 intel_de_write_fw(display, CGM_PIPE_DEGAMMA(pipe, i, 1),
1869 val: chv_cgm_degamma_udw(color: &lut[i]));
1870 }
1871}
1872
1873static u32 chv_cgm_gamma_ldw(const struct drm_color_lut *color)
1874{
1875 return REG_FIELD_PREP(CGM_PIPE_GAMMA_GREEN_LDW_MASK, drm_color_lut_extract(color->green, 10)) |
1876 REG_FIELD_PREP(CGM_PIPE_GAMMA_BLUE_LDW_MASK, drm_color_lut_extract(color->blue, 10));
1877}
1878
1879static u32 chv_cgm_gamma_udw(const struct drm_color_lut *color)
1880{
1881 return REG_FIELD_PREP(CGM_PIPE_GAMMA_RED_UDW_MASK, drm_color_lut_extract(color->red, 10));
1882}
1883
1884static void chv_cgm_gamma_pack(struct drm_color_lut *entry, u32 ldw, u32 udw)
1885{
1886 entry->green = intel_color_lut_pack(REG_FIELD_GET(CGM_PIPE_GAMMA_GREEN_LDW_MASK, ldw), bit_precision: 10);
1887 entry->blue = intel_color_lut_pack(REG_FIELD_GET(CGM_PIPE_GAMMA_BLUE_LDW_MASK, ldw), bit_precision: 10);
1888 entry->red = intel_color_lut_pack(REG_FIELD_GET(CGM_PIPE_GAMMA_RED_UDW_MASK, udw), bit_precision: 10);
1889}
1890
1891static void chv_load_cgm_gamma(struct intel_crtc *crtc,
1892 const struct drm_property_blob *blob)
1893{
1894 struct intel_display *display = to_intel_display(crtc);
1895 const struct drm_color_lut *lut = blob->data;
1896 int i, lut_size = drm_color_lut_size(blob);
1897 enum pipe pipe = crtc->pipe;
1898
1899 for (i = 0; i < lut_size; i++) {
1900 intel_de_write_fw(display, CGM_PIPE_GAMMA(pipe, i, 0),
1901 val: chv_cgm_gamma_ldw(color: &lut[i]));
1902 intel_de_write_fw(display, CGM_PIPE_GAMMA(pipe, i, 1),
1903 val: chv_cgm_gamma_udw(color: &lut[i]));
1904 }
1905}
1906
1907static void chv_load_luts(const struct intel_crtc_state *crtc_state)
1908{
1909 struct intel_display *display = to_intel_display(crtc_state);
1910 struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
1911 const struct drm_property_blob *pre_csc_lut = crtc_state->pre_csc_lut;
1912 const struct drm_property_blob *post_csc_lut = crtc_state->post_csc_lut;
1913
1914 if (crtc_state->cgm_mode & CGM_PIPE_MODE_CSC)
1915 chv_load_cgm_csc(crtc, csc: &crtc_state->csc);
1916
1917 if (crtc_state->cgm_mode & CGM_PIPE_MODE_DEGAMMA)
1918 chv_load_cgm_degamma(crtc, blob: pre_csc_lut);
1919
1920 if (crtc_state->cgm_mode & CGM_PIPE_MODE_GAMMA)
1921 chv_load_cgm_gamma(crtc, blob: post_csc_lut);
1922 else
1923 i965_load_luts(crtc_state);
1924
1925 intel_de_write_fw(display, CGM_PIPE_MODE(crtc->pipe),
1926 val: crtc_state->cgm_mode);
1927}
1928
1929void intel_color_load_luts(const struct intel_crtc_state *crtc_state)
1930{
1931 struct intel_display *display = to_intel_display(crtc_state);
1932
1933 if (crtc_state->dsb_color)
1934 return;
1935
1936 display->funcs.color->load_luts(crtc_state);
1937}
1938
1939void intel_color_commit_noarm(struct intel_dsb *dsb,
1940 const struct intel_crtc_state *crtc_state)
1941{
1942 struct intel_display *display = to_intel_display(crtc_state);
1943
1944 if (display->funcs.color->color_commit_noarm)
1945 display->funcs.color->color_commit_noarm(dsb, crtc_state);
1946}
1947
1948void intel_color_commit_arm(struct intel_dsb *dsb,
1949 const struct intel_crtc_state *crtc_state)
1950{
1951 struct intel_display *display = to_intel_display(crtc_state);
1952
1953 display->funcs.color->color_commit_arm(dsb, crtc_state);
1954}
1955
1956void intel_color_post_update(const struct intel_crtc_state *crtc_state)
1957{
1958 struct intel_display *display = to_intel_display(crtc_state);
1959
1960 if (display->funcs.color->color_post_update)
1961 display->funcs.color->color_post_update(crtc_state);
1962}
1963
1964void intel_color_modeset(const struct intel_crtc_state *crtc_state)
1965{
1966 struct intel_display *display = to_intel_display(crtc_state);
1967
1968 intel_color_load_luts(crtc_state);
1969 intel_color_commit_noarm(NULL, crtc_state);
1970 intel_color_commit_arm(NULL, crtc_state);
1971
1972 if (DISPLAY_VER(display) < 9) {
1973 struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
1974 struct intel_plane *plane = to_intel_plane(crtc->base.primary);
1975
1976 /* update DSPCNTR to configure gamma/csc for pipe bottom color */
1977 plane->disable_arm(NULL, plane, crtc_state);
1978 }
1979}
1980
1981bool intel_color_uses_dsb(const struct intel_crtc_state *crtc_state)
1982{
1983 return crtc_state->dsb_color;
1984}
1985
1986bool intel_color_uses_chained_dsb(const struct intel_crtc_state *crtc_state)
1987{
1988 struct intel_display *display = to_intel_display(crtc_state);
1989
1990 return crtc_state->dsb_color && !HAS_DOUBLE_BUFFERED_LUT(display);
1991}
1992
1993bool intel_color_uses_gosub_dsb(const struct intel_crtc_state *crtc_state)
1994{
1995 struct intel_display *display = to_intel_display(crtc_state);
1996
1997 return crtc_state->dsb_color && HAS_DOUBLE_BUFFERED_LUT(display);
1998}
1999
2000void intel_color_prepare_commit(struct intel_atomic_state *state,
2001 struct intel_crtc *crtc)
2002{
2003 struct intel_display *display = to_intel_display(state);
2004 struct intel_crtc_state *crtc_state =
2005 intel_atomic_get_new_crtc_state(state, crtc);
2006
2007 if (!crtc_state->hw.active ||
2008 intel_crtc_needs_modeset(crtc_state))
2009 return;
2010
2011 if (!intel_crtc_needs_color_update(crtc_state))
2012 return;
2013
2014 if (!crtc_state->pre_csc_lut && !crtc_state->post_csc_lut)
2015 return;
2016
2017 if (HAS_DOUBLE_BUFFERED_LUT(display))
2018 crtc_state->dsb_color = intel_dsb_prepare(state, crtc, dsb_id: INTEL_DSB_0, max_cmds: 1024);
2019 else
2020 crtc_state->dsb_color = intel_dsb_prepare(state, crtc, dsb_id: INTEL_DSB_1, max_cmds: 1024);
2021
2022 if (!intel_color_uses_dsb(crtc_state))
2023 return;
2024
2025 display->funcs.color->load_luts(crtc_state);
2026
2027 if (crtc_state->use_dsb && intel_color_uses_chained_dsb(crtc_state)) {
2028 intel_vrr_send_push(dsb: crtc_state->dsb_color, crtc_state);
2029 intel_dsb_wait_for_delayed_vblank(state, dsb: crtc_state->dsb_color);
2030 intel_vrr_check_push_sent(dsb: crtc_state->dsb_color, crtc_state);
2031 intel_dsb_interrupt(dsb: crtc_state->dsb_color);
2032 }
2033
2034 if (intel_color_uses_gosub_dsb(crtc_state))
2035 intel_dsb_gosub_finish(dsb: crtc_state->dsb_color);
2036 else
2037 intel_dsb_finish(dsb: crtc_state->dsb_color);
2038}
2039
2040void intel_color_cleanup_commit(struct intel_crtc_state *crtc_state)
2041{
2042 if (crtc_state->dsb_color) {
2043 intel_dsb_cleanup(dsb: crtc_state->dsb_color);
2044 crtc_state->dsb_color = NULL;
2045 }
2046}
2047
2048void intel_color_wait_commit(const struct intel_crtc_state *crtc_state)
2049{
2050 if (crtc_state->dsb_color)
2051 intel_dsb_wait(dsb: crtc_state->dsb_color);
2052}
2053
2054static bool intel_can_preload_luts(struct intel_atomic_state *state,
2055 struct intel_crtc *crtc)
2056{
2057 struct intel_display *display = to_intel_display(state);
2058 const struct intel_crtc_state *old_crtc_state =
2059 intel_atomic_get_old_crtc_state(state, crtc);
2060
2061 if (HAS_DOUBLE_BUFFERED_LUT(display))
2062 return false;
2063
2064 return !old_crtc_state->post_csc_lut &&
2065 !old_crtc_state->pre_csc_lut;
2066}
2067
2068static bool vlv_can_preload_luts(struct intel_atomic_state *state,
2069 struct intel_crtc *crtc)
2070{
2071 const struct intel_crtc_state *old_crtc_state =
2072 intel_atomic_get_old_crtc_state(state, crtc);
2073
2074 return !old_crtc_state->wgc_enable &&
2075 !old_crtc_state->post_csc_lut;
2076}
2077
2078static bool chv_can_preload_luts(struct intel_atomic_state *state,
2079 struct intel_crtc *crtc)
2080{
2081 const struct intel_crtc_state *old_crtc_state =
2082 intel_atomic_get_old_crtc_state(state, crtc);
2083 const struct intel_crtc_state *new_crtc_state =
2084 intel_atomic_get_new_crtc_state(state, crtc);
2085
2086 /*
2087 * CGM_PIPE_MODE is itself single buffered. We'd have to
2088 * somehow split it out from chv_load_luts() if we wanted
2089 * the ability to preload the CGM LUTs/CSC without tearing.
2090 */
2091 if (old_crtc_state->cgm_mode || new_crtc_state->cgm_mode)
2092 return false;
2093
2094 return vlv_can_preload_luts(state, crtc);
2095}
2096
2097int intel_color_check(struct intel_atomic_state *state,
2098 struct intel_crtc *crtc)
2099{
2100 struct intel_display *display = to_intel_display(state);
2101 const struct intel_crtc_state *old_crtc_state =
2102 intel_atomic_get_old_crtc_state(state, crtc);
2103 struct intel_crtc_state *new_crtc_state =
2104 intel_atomic_get_new_crtc_state(state, crtc);
2105
2106 /*
2107 * May need to update pipe gamma enable bits
2108 * when C8 planes are getting enabled/disabled.
2109 */
2110 if (!old_crtc_state->c8_planes != !new_crtc_state->c8_planes)
2111 new_crtc_state->uapi.color_mgmt_changed = true;
2112
2113 if (!intel_crtc_needs_color_update(crtc_state: new_crtc_state))
2114 return 0;
2115
2116 return display->funcs.color->color_check(state, crtc);
2117}
2118
2119void intel_color_get_config(struct intel_crtc_state *crtc_state)
2120{
2121 struct intel_display *display = to_intel_display(crtc_state);
2122
2123 display->funcs.color->get_config(crtc_state);
2124
2125 display->funcs.color->read_luts(crtc_state);
2126
2127 if (display->funcs.color->read_csc)
2128 display->funcs.color->read_csc(crtc_state);
2129}
2130
2131bool intel_color_lut_equal(const struct intel_crtc_state *crtc_state,
2132 const struct drm_property_blob *blob1,
2133 const struct drm_property_blob *blob2,
2134 bool is_pre_csc_lut)
2135{
2136 struct intel_display *display = to_intel_display(crtc_state);
2137
2138 /*
2139 * FIXME c8_planes readout missing thus
2140 * .read_luts() doesn't read out post_csc_lut.
2141 */
2142 if (!is_pre_csc_lut && crtc_state->c8_planes)
2143 return true;
2144
2145 return display->funcs.color->lut_equal(crtc_state, blob1, blob2,
2146 is_pre_csc_lut);
2147}
2148
2149static bool need_plane_update(struct intel_plane *plane,
2150 const struct intel_crtc_state *crtc_state)
2151{
2152 struct intel_display *display = to_intel_display(plane);
2153
2154 /*
2155 * On pre-SKL the pipe gamma enable and pipe csc enable for
2156 * the pipe bottom color are configured via the primary plane.
2157 * We have to reconfigure that even if the plane is inactive.
2158 */
2159 return crtc_state->active_planes & BIT(plane->id) ||
2160 (DISPLAY_VER(display) < 9 && plane->id == PLANE_PRIMARY);
2161}
2162
2163static int
2164intel_color_add_affected_planes(struct intel_atomic_state *state,
2165 struct intel_crtc *crtc)
2166{
2167 struct intel_display *display = to_intel_display(state);
2168 const struct intel_crtc_state *old_crtc_state =
2169 intel_atomic_get_old_crtc_state(state, crtc);
2170 struct intel_crtc_state *new_crtc_state =
2171 intel_atomic_get_new_crtc_state(state, crtc);
2172 struct intel_plane *plane;
2173
2174 if (!new_crtc_state->hw.active ||
2175 intel_crtc_needs_modeset(crtc_state: new_crtc_state))
2176 return 0;
2177
2178 if (new_crtc_state->gamma_enable == old_crtc_state->gamma_enable &&
2179 new_crtc_state->csc_enable == old_crtc_state->csc_enable)
2180 return 0;
2181
2182 for_each_intel_plane_on_crtc(display->drm, crtc, plane) {
2183 struct intel_plane_state *plane_state;
2184
2185 if (!need_plane_update(plane, crtc_state: new_crtc_state))
2186 continue;
2187
2188 plane_state = intel_atomic_get_plane_state(state, plane);
2189 if (IS_ERR(ptr: plane_state))
2190 return PTR_ERR(ptr: plane_state);
2191
2192 new_crtc_state->update_planes |= BIT(plane->id);
2193 new_crtc_state->async_flip_planes = 0;
2194 new_crtc_state->do_async_flip = false;
2195
2196 /* plane control register changes blocked by CxSR */
2197 if (HAS_GMCH(display))
2198 new_crtc_state->disable_cxsr = true;
2199 }
2200
2201 return 0;
2202}
2203
2204static u32 intel_gamma_lut_tests(const struct intel_crtc_state *crtc_state)
2205{
2206 struct intel_display *display = to_intel_display(crtc_state);
2207 const struct drm_property_blob *gamma_lut = crtc_state->hw.gamma_lut;
2208
2209 if (lut_is_legacy(lut: gamma_lut))
2210 return 0;
2211
2212 return DISPLAY_INFO(display)->color.gamma_lut_tests;
2213}
2214
2215static u32 intel_degamma_lut_tests(const struct intel_crtc_state *crtc_state)
2216{
2217 struct intel_display *display = to_intel_display(crtc_state);
2218
2219 return DISPLAY_INFO(display)->color.degamma_lut_tests;
2220}
2221
2222static int intel_gamma_lut_size(const struct intel_crtc_state *crtc_state)
2223{
2224 struct intel_display *display = to_intel_display(crtc_state);
2225 const struct drm_property_blob *gamma_lut = crtc_state->hw.gamma_lut;
2226
2227 if (lut_is_legacy(lut: gamma_lut))
2228 return LEGACY_LUT_LENGTH;
2229
2230 return DISPLAY_INFO(display)->color.gamma_lut_size;
2231}
2232
2233static u32 intel_degamma_lut_size(const struct intel_crtc_state *crtc_state)
2234{
2235 struct intel_display *display = to_intel_display(crtc_state);
2236
2237 return DISPLAY_INFO(display)->color.degamma_lut_size;
2238}
2239
2240static int check_lut_size(struct intel_crtc *crtc, const char *lut_name,
2241 const struct drm_property_blob *lut, int expected)
2242{
2243 struct intel_display *display = to_intel_display(crtc);
2244 int len;
2245
2246 if (!lut)
2247 return 0;
2248
2249 len = drm_color_lut_size(blob: lut);
2250 if (len != expected) {
2251 drm_dbg_kms(display->drm,
2252 "[CRTC:%d:%s] Invalid %s LUT size; got %d, expected %d\n",
2253 crtc->base.base.id, crtc->base.name, lut_name, len, expected);
2254 return -EINVAL;
2255 }
2256
2257 return 0;
2258}
2259
2260static int _check_luts(const struct intel_crtc_state *crtc_state,
2261 u32 degamma_tests, u32 gamma_tests)
2262{
2263 struct intel_display *display = to_intel_display(crtc_state);
2264 struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
2265 const struct drm_property_blob *gamma_lut = crtc_state->hw.gamma_lut;
2266 const struct drm_property_blob *degamma_lut = crtc_state->hw.degamma_lut;
2267 int gamma_length, degamma_length;
2268
2269 /* C8 relies on its palette being stored in the legacy LUT */
2270 if (crtc_state->c8_planes && !lut_is_legacy(lut: crtc_state->hw.gamma_lut)) {
2271 drm_dbg_kms(display->drm,
2272 "[CRTC:%d:%s] C8 pixelformat requires the legacy LUT\n",
2273 crtc->base.base.id, crtc->base.name);
2274 return -EINVAL;
2275 }
2276
2277 degamma_length = intel_degamma_lut_size(crtc_state);
2278 gamma_length = intel_gamma_lut_size(crtc_state);
2279
2280 if (check_lut_size(crtc, lut_name: "degamma", lut: degamma_lut, expected: degamma_length) ||
2281 check_lut_size(crtc, lut_name: "gamma", lut: gamma_lut, expected: gamma_length))
2282 return -EINVAL;
2283
2284 if (drm_color_lut_check(lut: degamma_lut, tests: degamma_tests) ||
2285 drm_color_lut_check(lut: gamma_lut, tests: gamma_tests))
2286 return -EINVAL;
2287
2288 return 0;
2289}
2290
2291static int check_luts(const struct intel_crtc_state *crtc_state)
2292{
2293 return _check_luts(crtc_state,
2294 degamma_tests: intel_degamma_lut_tests(crtc_state),
2295 gamma_tests: intel_gamma_lut_tests(crtc_state));
2296}
2297
2298static u32 i9xx_gamma_mode(struct intel_crtc_state *crtc_state)
2299{
2300 if (!crtc_state->gamma_enable ||
2301 lut_is_legacy(lut: crtc_state->hw.gamma_lut))
2302 return GAMMA_MODE_MODE_8BIT;
2303 else
2304 return GAMMA_MODE_MODE_10BIT;
2305}
2306
2307static int i9xx_lut_10_diff(u16 a, u16 b)
2308{
2309 return drm_color_lut_extract(user_input: a, bit_precision: 10) -
2310 drm_color_lut_extract(user_input: b, bit_precision: 10);
2311}
2312
2313static int i9xx_check_lut_10(struct intel_crtc *crtc,
2314 const struct drm_property_blob *blob)
2315{
2316 struct intel_display *display = to_intel_display(crtc);
2317 const struct drm_color_lut *lut = blob->data;
2318 int lut_size = drm_color_lut_size(blob);
2319 const struct drm_color_lut *a = &lut[lut_size - 2];
2320 const struct drm_color_lut *b = &lut[lut_size - 1];
2321
2322 if (i9xx_lut_10_diff(a: b->red, b: a->red) > 0x7f ||
2323 i9xx_lut_10_diff(a: b->green, b: a->green) > 0x7f ||
2324 i9xx_lut_10_diff(a: b->blue, b: a->blue) > 0x7f) {
2325 drm_dbg_kms(display->drm,
2326 "[CRTC:%d:%s] Last gamma LUT entry exceeds max slope\n",
2327 crtc->base.base.id, crtc->base.name);
2328 return -EINVAL;
2329 }
2330
2331 return 0;
2332}
2333
2334void intel_color_assert_luts(const struct intel_crtc_state *crtc_state)
2335{
2336 struct intel_display *display = to_intel_display(crtc_state);
2337
2338 /* make sure {pre,post}_csc_lut were correctly assigned */
2339 if (DISPLAY_VER(display) >= 11 || HAS_GMCH(display)) {
2340 drm_WARN_ON(display->drm,
2341 crtc_state->pre_csc_lut != crtc_state->hw.degamma_lut);
2342 drm_WARN_ON(display->drm,
2343 crtc_state->post_csc_lut != crtc_state->hw.gamma_lut);
2344 } else if (DISPLAY_VER(display) == 10) {
2345 drm_WARN_ON(display->drm,
2346 crtc_state->post_csc_lut == crtc_state->hw.gamma_lut &&
2347 crtc_state->pre_csc_lut != crtc_state->hw.degamma_lut &&
2348 crtc_state->pre_csc_lut != display->color.glk_linear_degamma_lut);
2349 drm_WARN_ON(display->drm,
2350 !ilk_lut_limited_range(crtc_state) &&
2351 crtc_state->post_csc_lut != NULL &&
2352 crtc_state->post_csc_lut != crtc_state->hw.gamma_lut);
2353 } else if (crtc_state->gamma_mode != GAMMA_MODE_MODE_SPLIT) {
2354 drm_WARN_ON(display->drm,
2355 crtc_state->pre_csc_lut != crtc_state->hw.degamma_lut &&
2356 crtc_state->pre_csc_lut != crtc_state->hw.gamma_lut);
2357 drm_WARN_ON(display->drm,
2358 !ilk_lut_limited_range(crtc_state) &&
2359 crtc_state->post_csc_lut != crtc_state->hw.degamma_lut &&
2360 crtc_state->post_csc_lut != crtc_state->hw.gamma_lut);
2361 }
2362}
2363
2364static void intel_assign_luts(struct intel_crtc_state *crtc_state)
2365{
2366 drm_property_replace_blob(blob: &crtc_state->pre_csc_lut,
2367 new_blob: crtc_state->hw.degamma_lut);
2368 drm_property_replace_blob(blob: &crtc_state->post_csc_lut,
2369 new_blob: crtc_state->hw.gamma_lut);
2370}
2371
2372static int i9xx_color_check(struct intel_atomic_state *state,
2373 struct intel_crtc *crtc)
2374{
2375 struct intel_display *display = to_intel_display(state);
2376 struct intel_crtc_state *crtc_state =
2377 intel_atomic_get_new_crtc_state(state, crtc);
2378 int ret;
2379
2380 ret = check_luts(crtc_state);
2381 if (ret)
2382 return ret;
2383
2384 crtc_state->gamma_enable =
2385 crtc_state->hw.gamma_lut &&
2386 !crtc_state->c8_planes;
2387
2388 crtc_state->gamma_mode = i9xx_gamma_mode(crtc_state);
2389
2390 if (DISPLAY_VER(display) < 4 &&
2391 crtc_state->gamma_mode == GAMMA_MODE_MODE_10BIT) {
2392 ret = i9xx_check_lut_10(crtc, blob: crtc_state->hw.gamma_lut);
2393 if (ret)
2394 return ret;
2395 }
2396
2397 ret = intel_color_add_affected_planes(state, crtc);
2398 if (ret)
2399 return ret;
2400
2401 intel_assign_luts(crtc_state);
2402
2403 crtc_state->preload_luts = intel_can_preload_luts(state, crtc);
2404
2405 return 0;
2406}
2407
2408/*
2409 * VLV color pipeline:
2410 * u0.10 -> WGC csc -> u0.10 -> pipe gamma -> u0.10
2411 */
2412static int vlv_color_check(struct intel_atomic_state *state,
2413 struct intel_crtc *crtc)
2414{
2415 struct intel_crtc_state *crtc_state =
2416 intel_atomic_get_new_crtc_state(state, crtc);
2417 int ret;
2418
2419 ret = check_luts(crtc_state);
2420 if (ret)
2421 return ret;
2422
2423 crtc_state->gamma_enable =
2424 crtc_state->hw.gamma_lut &&
2425 !crtc_state->c8_planes;
2426
2427 crtc_state->gamma_mode = i9xx_gamma_mode(crtc_state);
2428
2429 crtc_state->wgc_enable = crtc_state->hw.ctm;
2430
2431 ret = intel_color_add_affected_planes(state, crtc);
2432 if (ret)
2433 return ret;
2434
2435 intel_assign_luts(crtc_state);
2436
2437 vlv_assign_csc(crtc_state);
2438
2439 crtc_state->preload_luts = vlv_can_preload_luts(state, crtc);
2440
2441 return 0;
2442}
2443
2444static u32 chv_cgm_mode(const struct intel_crtc_state *crtc_state)
2445{
2446 u32 cgm_mode = 0;
2447
2448 if (crtc_state->hw.degamma_lut)
2449 cgm_mode |= CGM_PIPE_MODE_DEGAMMA;
2450 if (crtc_state->hw.ctm)
2451 cgm_mode |= CGM_PIPE_MODE_CSC;
2452 if (crtc_state->hw.gamma_lut &&
2453 !lut_is_legacy(lut: crtc_state->hw.gamma_lut))
2454 cgm_mode |= CGM_PIPE_MODE_GAMMA;
2455
2456 /*
2457 * Toggling the CGM CSC on/off outside of the tiny window
2458 * between start of vblank and frame start causes underruns.
2459 * Always enable the CGM CSC as a workaround.
2460 */
2461 cgm_mode |= CGM_PIPE_MODE_CSC;
2462
2463 return cgm_mode;
2464}
2465
2466/*
2467 * CHV color pipeline:
2468 * u0.10 -> CGM degamma -> u0.14 -> CGM csc -> u0.14 -> CGM gamma ->
2469 * u0.10 -> WGC csc -> u0.10 -> pipe gamma -> u0.10
2470 *
2471 * We always bypass the WGC csc and use the CGM csc
2472 * instead since it has degamma and better precision.
2473 */
2474static int chv_color_check(struct intel_atomic_state *state,
2475 struct intel_crtc *crtc)
2476{
2477 struct intel_crtc_state *crtc_state =
2478 intel_atomic_get_new_crtc_state(state, crtc);
2479 int ret;
2480
2481 ret = check_luts(crtc_state);
2482 if (ret)
2483 return ret;
2484
2485 /*
2486 * Pipe gamma will be used only for the legacy LUT.
2487 * Otherwise we bypass it and use the CGM gamma instead.
2488 */
2489 crtc_state->gamma_enable =
2490 lut_is_legacy(lut: crtc_state->hw.gamma_lut) &&
2491 !crtc_state->c8_planes;
2492
2493 crtc_state->gamma_mode = GAMMA_MODE_MODE_8BIT;
2494
2495 crtc_state->cgm_mode = chv_cgm_mode(crtc_state);
2496
2497 /*
2498 * We always bypass the WGC CSC and use the CGM CSC
2499 * instead since it has degamma and better precision.
2500 */
2501 crtc_state->wgc_enable = false;
2502
2503 ret = intel_color_add_affected_planes(state, crtc);
2504 if (ret)
2505 return ret;
2506
2507 intel_assign_luts(crtc_state);
2508
2509 chv_assign_csc(crtc_state);
2510
2511 crtc_state->preload_luts = chv_can_preload_luts(state, crtc);
2512
2513 return 0;
2514}
2515
2516static bool ilk_gamma_enable(const struct intel_crtc_state *crtc_state)
2517{
2518 return (crtc_state->hw.gamma_lut ||
2519 crtc_state->hw.degamma_lut) &&
2520 !crtc_state->c8_planes;
2521}
2522
2523static bool ilk_csc_enable(const struct intel_crtc_state *crtc_state)
2524{
2525 return crtc_state->output_format != INTEL_OUTPUT_FORMAT_RGB ||
2526 ilk_csc_limited_range(crtc_state) ||
2527 crtc_state->hw.ctm;
2528}
2529
2530static u32 ilk_gamma_mode(const struct intel_crtc_state *crtc_state)
2531{
2532 if (!crtc_state->gamma_enable ||
2533 lut_is_legacy(lut: crtc_state->hw.gamma_lut))
2534 return GAMMA_MODE_MODE_8BIT;
2535 else
2536 return GAMMA_MODE_MODE_10BIT;
2537}
2538
2539static u32 ilk_csc_mode(const struct intel_crtc_state *crtc_state)
2540{
2541 /*
2542 * CSC comes after the LUT in RGB->YCbCr mode.
2543 * RGB->YCbCr needs the limited range offsets added to
2544 * the output. RGB limited range output is handled by
2545 * the hw automagically elsewhere.
2546 */
2547 if (crtc_state->output_format != INTEL_OUTPUT_FORMAT_RGB)
2548 return CSC_BLACK_SCREEN_OFFSET;
2549
2550 if (crtc_state->hw.degamma_lut)
2551 return CSC_MODE_YUV_TO_RGB;
2552
2553 return CSC_MODE_YUV_TO_RGB |
2554 CSC_POSITION_BEFORE_GAMMA;
2555}
2556
2557static int ilk_assign_luts(struct intel_crtc_state *crtc_state)
2558{
2559 struct intel_display *display = to_intel_display(crtc_state);
2560
2561 if (ilk_lut_limited_range(crtc_state)) {
2562 struct drm_property_blob *gamma_lut;
2563
2564 gamma_lut = create_resized_lut(display, blob_in: crtc_state->hw.gamma_lut,
2565 lut_out_size: drm_color_lut_size(blob: crtc_state->hw.gamma_lut),
2566 limited_color_range: true);
2567 if (IS_ERR(ptr: gamma_lut))
2568 return PTR_ERR(ptr: gamma_lut);
2569
2570 drm_property_replace_blob(blob: &crtc_state->post_csc_lut, new_blob: gamma_lut);
2571
2572 drm_property_blob_put(blob: gamma_lut);
2573
2574 drm_property_replace_blob(blob: &crtc_state->pre_csc_lut, new_blob: crtc_state->hw.degamma_lut);
2575
2576 return 0;
2577 }
2578
2579 if (crtc_state->hw.degamma_lut ||
2580 crtc_state->csc_mode & CSC_POSITION_BEFORE_GAMMA) {
2581 drm_property_replace_blob(blob: &crtc_state->pre_csc_lut,
2582 new_blob: crtc_state->hw.degamma_lut);
2583 drm_property_replace_blob(blob: &crtc_state->post_csc_lut,
2584 new_blob: crtc_state->hw.gamma_lut);
2585 } else {
2586 drm_property_replace_blob(blob: &crtc_state->pre_csc_lut,
2587 new_blob: crtc_state->hw.gamma_lut);
2588 drm_property_replace_blob(blob: &crtc_state->post_csc_lut,
2589 NULL);
2590 }
2591
2592 return 0;
2593}
2594
2595static int ilk_color_check(struct intel_atomic_state *state,
2596 struct intel_crtc *crtc)
2597{
2598 struct intel_display *display = to_intel_display(state);
2599 struct intel_crtc_state *crtc_state =
2600 intel_atomic_get_new_crtc_state(state, crtc);
2601 int ret;
2602
2603 ret = check_luts(crtc_state);
2604 if (ret)
2605 return ret;
2606
2607 if (crtc_state->hw.degamma_lut && crtc_state->hw.gamma_lut) {
2608 drm_dbg_kms(display->drm,
2609 "[CRTC:%d:%s] Degamma and gamma together are not possible\n",
2610 crtc->base.base.id, crtc->base.name);
2611 return -EINVAL;
2612 }
2613
2614 if (crtc_state->output_format != INTEL_OUTPUT_FORMAT_RGB &&
2615 crtc_state->hw.ctm) {
2616 drm_dbg_kms(display->drm,
2617 "[CRTC:%d:%s] YCbCr and CTM together are not possible\n",
2618 crtc->base.base.id, crtc->base.name);
2619 return -EINVAL;
2620 }
2621
2622 crtc_state->gamma_enable = ilk_gamma_enable(crtc_state);
2623
2624 crtc_state->csc_enable = ilk_csc_enable(crtc_state);
2625
2626 crtc_state->gamma_mode = ilk_gamma_mode(crtc_state);
2627
2628 crtc_state->csc_mode = ilk_csc_mode(crtc_state);
2629
2630 ret = intel_color_add_affected_planes(state, crtc);
2631 if (ret)
2632 return ret;
2633
2634 ret = ilk_assign_luts(crtc_state);
2635 if (ret)
2636 return ret;
2637
2638 ilk_assign_csc(crtc_state);
2639
2640 crtc_state->preload_luts = intel_can_preload_luts(state, crtc);
2641
2642 return 0;
2643}
2644
2645static u32 ivb_gamma_mode(const struct intel_crtc_state *crtc_state)
2646{
2647 if (crtc_state->hw.degamma_lut && crtc_state->hw.gamma_lut)
2648 return GAMMA_MODE_MODE_SPLIT;
2649
2650 return ilk_gamma_mode(crtc_state);
2651}
2652
2653static u32 ivb_csc_mode(const struct intel_crtc_state *crtc_state)
2654{
2655 bool limited_color_range = ilk_csc_limited_range(crtc_state);
2656
2657 /*
2658 * CSC comes after the LUT in degamma, RGB->YCbCr,
2659 * and RGB full->limited range mode.
2660 */
2661 if (crtc_state->hw.degamma_lut ||
2662 crtc_state->output_format != INTEL_OUTPUT_FORMAT_RGB ||
2663 limited_color_range)
2664 return 0;
2665
2666 return CSC_POSITION_BEFORE_GAMMA;
2667}
2668
2669static int ivb_assign_luts(struct intel_crtc_state *crtc_state)
2670{
2671 struct intel_display *display = to_intel_display(crtc_state);
2672 struct drm_property_blob *degamma_lut, *gamma_lut;
2673
2674 if (crtc_state->gamma_mode != GAMMA_MODE_MODE_SPLIT)
2675 return ilk_assign_luts(crtc_state);
2676
2677 drm_WARN_ON(display->drm, drm_color_lut_size(crtc_state->hw.degamma_lut) != 1024);
2678 drm_WARN_ON(display->drm, drm_color_lut_size(crtc_state->hw.gamma_lut) != 1024);
2679
2680 degamma_lut = create_resized_lut(display, blob_in: crtc_state->hw.degamma_lut, lut_out_size: 512,
2681 limited_color_range: false);
2682 if (IS_ERR(ptr: degamma_lut))
2683 return PTR_ERR(ptr: degamma_lut);
2684
2685 gamma_lut = create_resized_lut(display, blob_in: crtc_state->hw.gamma_lut, lut_out_size: 512,
2686 limited_color_range: ilk_lut_limited_range(crtc_state));
2687 if (IS_ERR(ptr: gamma_lut)) {
2688 drm_property_blob_put(blob: degamma_lut);
2689 return PTR_ERR(ptr: gamma_lut);
2690 }
2691
2692 drm_property_replace_blob(blob: &crtc_state->pre_csc_lut, new_blob: degamma_lut);
2693 drm_property_replace_blob(blob: &crtc_state->post_csc_lut, new_blob: gamma_lut);
2694
2695 drm_property_blob_put(blob: degamma_lut);
2696 drm_property_blob_put(blob: gamma_lut);
2697
2698 return 0;
2699}
2700
2701static int ivb_color_check(struct intel_atomic_state *state,
2702 struct intel_crtc *crtc)
2703{
2704 struct intel_display *display = to_intel_display(state);
2705 struct intel_crtc_state *crtc_state =
2706 intel_atomic_get_new_crtc_state(state, crtc);
2707 int ret;
2708
2709 ret = check_luts(crtc_state);
2710 if (ret)
2711 return ret;
2712
2713 if (crtc_state->c8_planes && crtc_state->hw.degamma_lut) {
2714 drm_dbg_kms(display->drm,
2715 "[CRTC:%d:%s] C8 pixelformat and degamma together are not possible\n",
2716 crtc->base.base.id, crtc->base.name);
2717 return -EINVAL;
2718 }
2719
2720 if (crtc_state->output_format != INTEL_OUTPUT_FORMAT_RGB &&
2721 crtc_state->hw.ctm) {
2722 drm_dbg_kms(display->drm,
2723 "[CRTC:%d:%s] YCbCr and CTM together are not possible\n",
2724 crtc->base.base.id, crtc->base.name);
2725 return -EINVAL;
2726 }
2727
2728 if (crtc_state->output_format != INTEL_OUTPUT_FORMAT_RGB &&
2729 crtc_state->hw.degamma_lut && crtc_state->hw.gamma_lut) {
2730 drm_dbg_kms(display->drm,
2731 "[CRTC:%d:%s] YCbCr and degamma+gamma together are not possible\n",
2732 crtc->base.base.id, crtc->base.name);
2733 return -EINVAL;
2734 }
2735
2736 crtc_state->gamma_enable = ilk_gamma_enable(crtc_state);
2737
2738 crtc_state->csc_enable = ilk_csc_enable(crtc_state);
2739
2740 crtc_state->gamma_mode = ivb_gamma_mode(crtc_state);
2741
2742 crtc_state->csc_mode = ivb_csc_mode(crtc_state);
2743
2744 ret = intel_color_add_affected_planes(state, crtc);
2745 if (ret)
2746 return ret;
2747
2748 ret = ivb_assign_luts(crtc_state);
2749 if (ret)
2750 return ret;
2751
2752 ilk_assign_csc(crtc_state);
2753
2754 crtc_state->preload_luts = intel_can_preload_luts(state, crtc);
2755
2756 return 0;
2757}
2758
2759static u32 glk_gamma_mode(const struct intel_crtc_state *crtc_state)
2760{
2761 if (!crtc_state->gamma_enable ||
2762 lut_is_legacy(lut: crtc_state->hw.gamma_lut))
2763 return GAMMA_MODE_MODE_8BIT;
2764 else
2765 return GAMMA_MODE_MODE_10BIT;
2766}
2767
2768static bool glk_use_pre_csc_lut_for_gamma(const struct intel_crtc_state *crtc_state)
2769{
2770 return crtc_state->hw.gamma_lut &&
2771 !crtc_state->c8_planes &&
2772 crtc_state->output_format != INTEL_OUTPUT_FORMAT_RGB;
2773}
2774
2775static int glk_assign_luts(struct intel_crtc_state *crtc_state)
2776{
2777 struct intel_display *display = to_intel_display(crtc_state);
2778
2779 if (glk_use_pre_csc_lut_for_gamma(crtc_state)) {
2780 struct drm_property_blob *gamma_lut;
2781
2782 gamma_lut = create_resized_lut(display, blob_in: crtc_state->hw.gamma_lut,
2783 DISPLAY_INFO(display)->color.degamma_lut_size,
2784 limited_color_range: false);
2785 if (IS_ERR(ptr: gamma_lut))
2786 return PTR_ERR(ptr: gamma_lut);
2787
2788 drm_property_replace_blob(blob: &crtc_state->pre_csc_lut, new_blob: gamma_lut);
2789 drm_property_replace_blob(blob: &crtc_state->post_csc_lut, NULL);
2790
2791 drm_property_blob_put(blob: gamma_lut);
2792
2793 return 0;
2794 }
2795
2796 if (ilk_lut_limited_range(crtc_state)) {
2797 struct drm_property_blob *gamma_lut;
2798
2799 gamma_lut = create_resized_lut(display, blob_in: crtc_state->hw.gamma_lut,
2800 lut_out_size: drm_color_lut_size(blob: crtc_state->hw.gamma_lut),
2801 limited_color_range: true);
2802 if (IS_ERR(ptr: gamma_lut))
2803 return PTR_ERR(ptr: gamma_lut);
2804
2805 drm_property_replace_blob(blob: &crtc_state->post_csc_lut, new_blob: gamma_lut);
2806
2807 drm_property_blob_put(blob: gamma_lut);
2808 } else {
2809 drm_property_replace_blob(blob: &crtc_state->post_csc_lut, new_blob: crtc_state->hw.gamma_lut);
2810 }
2811
2812 drm_property_replace_blob(blob: &crtc_state->pre_csc_lut, new_blob: crtc_state->hw.degamma_lut);
2813
2814 /*
2815 * On GLK+ both pipe CSC and degamma LUT are controlled
2816 * by csc_enable. Hence for the cases where the CSC is
2817 * needed but degamma LUT is not we need to load a
2818 * linear degamma LUT.
2819 */
2820 if (crtc_state->csc_enable && !crtc_state->pre_csc_lut)
2821 drm_property_replace_blob(blob: &crtc_state->pre_csc_lut,
2822 new_blob: display->color.glk_linear_degamma_lut);
2823
2824 return 0;
2825}
2826
2827static int glk_check_luts(const struct intel_crtc_state *crtc_state)
2828{
2829 u32 degamma_tests = intel_degamma_lut_tests(crtc_state);
2830 u32 gamma_tests = intel_gamma_lut_tests(crtc_state);
2831
2832 if (glk_use_pre_csc_lut_for_gamma(crtc_state))
2833 gamma_tests |= degamma_tests;
2834
2835 return _check_luts(crtc_state, degamma_tests, gamma_tests);
2836}
2837
2838static int glk_color_check(struct intel_atomic_state *state,
2839 struct intel_crtc *crtc)
2840{
2841 struct intel_display *display = to_intel_display(state);
2842 struct intel_crtc_state *crtc_state =
2843 intel_atomic_get_new_crtc_state(state, crtc);
2844 int ret;
2845
2846 ret = glk_check_luts(crtc_state);
2847 if (ret)
2848 return ret;
2849
2850 if (crtc_state->output_format != INTEL_OUTPUT_FORMAT_RGB &&
2851 crtc_state->hw.ctm) {
2852 drm_dbg_kms(display->drm,
2853 "[CRTC:%d:%s] YCbCr and CTM together are not possible\n",
2854 crtc->base.base.id, crtc->base.name);
2855 return -EINVAL;
2856 }
2857
2858 if (crtc_state->output_format != INTEL_OUTPUT_FORMAT_RGB &&
2859 crtc_state->hw.degamma_lut && crtc_state->hw.gamma_lut) {
2860 drm_dbg_kms(display->drm,
2861 "[CRTC:%d:%s] YCbCr and degamma+gamma together are not possible\n",
2862 crtc->base.base.id, crtc->base.name);
2863 return -EINVAL;
2864 }
2865
2866 crtc_state->gamma_enable =
2867 !glk_use_pre_csc_lut_for_gamma(crtc_state) &&
2868 crtc_state->hw.gamma_lut &&
2869 !crtc_state->c8_planes;
2870
2871 /* On GLK+ degamma LUT is controlled by csc_enable */
2872 crtc_state->csc_enable =
2873 glk_use_pre_csc_lut_for_gamma(crtc_state) ||
2874 crtc_state->hw.degamma_lut ||
2875 crtc_state->output_format != INTEL_OUTPUT_FORMAT_RGB ||
2876 crtc_state->hw.ctm || ilk_csc_limited_range(crtc_state);
2877
2878 crtc_state->gamma_mode = glk_gamma_mode(crtc_state);
2879
2880 crtc_state->csc_mode = 0;
2881
2882 ret = intel_color_add_affected_planes(state, crtc);
2883 if (ret)
2884 return ret;
2885
2886 ret = glk_assign_luts(crtc_state);
2887 if (ret)
2888 return ret;
2889
2890 ilk_assign_csc(crtc_state);
2891
2892 crtc_state->preload_luts = intel_can_preload_luts(state, crtc);
2893
2894 return 0;
2895}
2896
2897static u32 icl_gamma_mode(const struct intel_crtc_state *crtc_state)
2898{
2899 struct intel_display *display = to_intel_display(crtc_state);
2900 u32 gamma_mode = 0;
2901
2902 if (crtc_state->hw.degamma_lut)
2903 gamma_mode |= PRE_CSC_GAMMA_ENABLE;
2904
2905 if (crtc_state->hw.gamma_lut &&
2906 !crtc_state->c8_planes)
2907 gamma_mode |= POST_CSC_GAMMA_ENABLE;
2908
2909 if (!crtc_state->hw.gamma_lut ||
2910 lut_is_legacy(lut: crtc_state->hw.gamma_lut))
2911 gamma_mode |= GAMMA_MODE_MODE_8BIT;
2912 /*
2913 * Enable 10bit gamma for D13
2914 * ToDo: Extend to Logarithmic Gamma once the new UAPI
2915 * is accepted and implemented by a userspace consumer
2916 */
2917 else if (DISPLAY_VER(display) >= 13)
2918 gamma_mode |= GAMMA_MODE_MODE_10BIT;
2919 else
2920 gamma_mode |= GAMMA_MODE_MODE_12BIT_MULTI_SEG;
2921
2922 return gamma_mode;
2923}
2924
2925static u32 icl_csc_mode(const struct intel_crtc_state *crtc_state)
2926{
2927 u32 csc_mode = 0;
2928
2929 if (crtc_state->hw.ctm)
2930 csc_mode |= ICL_CSC_ENABLE;
2931
2932 if (crtc_state->output_format != INTEL_OUTPUT_FORMAT_RGB ||
2933 crtc_state->limited_color_range)
2934 csc_mode |= ICL_OUTPUT_CSC_ENABLE;
2935
2936 return csc_mode;
2937}
2938
2939static int icl_color_check(struct intel_atomic_state *state,
2940 struct intel_crtc *crtc)
2941{
2942 struct intel_crtc_state *crtc_state =
2943 intel_atomic_get_new_crtc_state(state, crtc);
2944 int ret;
2945
2946 ret = check_luts(crtc_state);
2947 if (ret)
2948 return ret;
2949
2950 crtc_state->gamma_mode = icl_gamma_mode(crtc_state);
2951
2952 crtc_state->csc_mode = icl_csc_mode(crtc_state);
2953
2954 intel_assign_luts(crtc_state);
2955
2956 icl_assign_csc(crtc_state);
2957
2958 crtc_state->preload_luts = intel_can_preload_luts(state, crtc);
2959
2960 return 0;
2961}
2962
2963static int i9xx_post_csc_lut_precision(const struct intel_crtc_state *crtc_state)
2964{
2965 if (!crtc_state->gamma_enable && !crtc_state->c8_planes)
2966 return 0;
2967
2968 switch (crtc_state->gamma_mode) {
2969 case GAMMA_MODE_MODE_8BIT:
2970 return 8;
2971 case GAMMA_MODE_MODE_10BIT:
2972 return 10;
2973 default:
2974 MISSING_CASE(crtc_state->gamma_mode);
2975 return 0;
2976 }
2977}
2978
2979static int i9xx_pre_csc_lut_precision(const struct intel_crtc_state *crtc_state)
2980{
2981 return 0;
2982}
2983
2984static int i965_post_csc_lut_precision(const struct intel_crtc_state *crtc_state)
2985{
2986 if (!crtc_state->gamma_enable && !crtc_state->c8_planes)
2987 return 0;
2988
2989 switch (crtc_state->gamma_mode) {
2990 case GAMMA_MODE_MODE_8BIT:
2991 return 8;
2992 case GAMMA_MODE_MODE_10BIT:
2993 return 16;
2994 default:
2995 MISSING_CASE(crtc_state->gamma_mode);
2996 return 0;
2997 }
2998}
2999
3000static int ilk_gamma_mode_precision(u32 gamma_mode)
3001{
3002 switch (gamma_mode) {
3003 case GAMMA_MODE_MODE_8BIT:
3004 return 8;
3005 case GAMMA_MODE_MODE_10BIT:
3006 return 10;
3007 default:
3008 MISSING_CASE(gamma_mode);
3009 return 0;
3010 }
3011}
3012
3013static bool ilk_has_post_csc_lut(const struct intel_crtc_state *crtc_state)
3014{
3015 if (crtc_state->c8_planes)
3016 return true;
3017
3018 return crtc_state->gamma_enable &&
3019 (crtc_state->csc_mode & CSC_POSITION_BEFORE_GAMMA) != 0;
3020}
3021
3022static bool ilk_has_pre_csc_lut(const struct intel_crtc_state *crtc_state)
3023{
3024 return crtc_state->gamma_enable &&
3025 (crtc_state->csc_mode & CSC_POSITION_BEFORE_GAMMA) == 0;
3026}
3027
3028static int ilk_post_csc_lut_precision(const struct intel_crtc_state *crtc_state)
3029{
3030 if (!ilk_has_post_csc_lut(crtc_state))
3031 return 0;
3032
3033 return ilk_gamma_mode_precision(gamma_mode: crtc_state->gamma_mode);
3034}
3035
3036static int ilk_pre_csc_lut_precision(const struct intel_crtc_state *crtc_state)
3037{
3038 if (!ilk_has_pre_csc_lut(crtc_state))
3039 return 0;
3040
3041 return ilk_gamma_mode_precision(gamma_mode: crtc_state->gamma_mode);
3042}
3043
3044static int ivb_post_csc_lut_precision(const struct intel_crtc_state *crtc_state)
3045{
3046 if (crtc_state->gamma_enable &&
3047 crtc_state->gamma_mode == GAMMA_MODE_MODE_SPLIT)
3048 return 10;
3049
3050 return ilk_post_csc_lut_precision(crtc_state);
3051}
3052
3053static int ivb_pre_csc_lut_precision(const struct intel_crtc_state *crtc_state)
3054{
3055 if (crtc_state->gamma_enable &&
3056 crtc_state->gamma_mode == GAMMA_MODE_MODE_SPLIT)
3057 return 10;
3058
3059 return ilk_pre_csc_lut_precision(crtc_state);
3060}
3061
3062static int chv_post_csc_lut_precision(const struct intel_crtc_state *crtc_state)
3063{
3064 if (crtc_state->cgm_mode & CGM_PIPE_MODE_GAMMA)
3065 return 10;
3066
3067 return i965_post_csc_lut_precision(crtc_state);
3068}
3069
3070static int chv_pre_csc_lut_precision(const struct intel_crtc_state *crtc_state)
3071{
3072 if (crtc_state->cgm_mode & CGM_PIPE_MODE_DEGAMMA)
3073 return 14;
3074
3075 return 0;
3076}
3077
3078static int glk_post_csc_lut_precision(const struct intel_crtc_state *crtc_state)
3079{
3080 if (!crtc_state->gamma_enable && !crtc_state->c8_planes)
3081 return 0;
3082
3083 return ilk_gamma_mode_precision(gamma_mode: crtc_state->gamma_mode);
3084}
3085
3086static int glk_pre_csc_lut_precision(const struct intel_crtc_state *crtc_state)
3087{
3088 if (!crtc_state->csc_enable)
3089 return 0;
3090
3091 return 16;
3092}
3093
3094static bool icl_has_post_csc_lut(const struct intel_crtc_state *crtc_state)
3095{
3096 if (crtc_state->c8_planes)
3097 return true;
3098
3099 return crtc_state->gamma_mode & POST_CSC_GAMMA_ENABLE;
3100}
3101
3102static bool icl_has_pre_csc_lut(const struct intel_crtc_state *crtc_state)
3103{
3104 return crtc_state->gamma_mode & PRE_CSC_GAMMA_ENABLE;
3105}
3106
3107static int icl_post_csc_lut_precision(const struct intel_crtc_state *crtc_state)
3108{
3109 if (!icl_has_post_csc_lut(crtc_state))
3110 return 0;
3111
3112 switch (crtc_state->gamma_mode & GAMMA_MODE_MODE_MASK) {
3113 case GAMMA_MODE_MODE_8BIT:
3114 return 8;
3115 case GAMMA_MODE_MODE_10BIT:
3116 return 10;
3117 case GAMMA_MODE_MODE_12BIT_MULTI_SEG:
3118 return 16;
3119 default:
3120 MISSING_CASE(crtc_state->gamma_mode);
3121 return 0;
3122 }
3123}
3124
3125static int icl_pre_csc_lut_precision(const struct intel_crtc_state *crtc_state)
3126{
3127 if (!icl_has_pre_csc_lut(crtc_state))
3128 return 0;
3129
3130 return 16;
3131}
3132
3133static bool err_check(const struct drm_color_lut *lut1,
3134 const struct drm_color_lut *lut2, u32 err)
3135{
3136 return ((abs((long)lut2->red - lut1->red)) <= err) &&
3137 ((abs((long)lut2->blue - lut1->blue)) <= err) &&
3138 ((abs((long)lut2->green - lut1->green)) <= err);
3139}
3140
3141static bool intel_lut_entries_equal(const struct drm_color_lut *lut1,
3142 const struct drm_color_lut *lut2,
3143 int lut_size, u32 err)
3144{
3145 int i;
3146
3147 for (i = 0; i < lut_size; i++) {
3148 if (!err_check(lut1: &lut1[i], lut2: &lut2[i], err))
3149 return false;
3150 }
3151
3152 return true;
3153}
3154
3155static bool intel_lut_equal(const struct drm_property_blob *blob1,
3156 const struct drm_property_blob *blob2,
3157 int check_size, int precision)
3158{
3159 const struct drm_color_lut *lut1, *lut2;
3160 int lut_size1, lut_size2;
3161 u32 err;
3162
3163 if (!blob1 != !blob2)
3164 return false;
3165
3166 if (!blob1 != !precision)
3167 return false;
3168
3169 if (!blob1)
3170 return true;
3171
3172 lut_size1 = drm_color_lut_size(blob: blob1);
3173 lut_size2 = drm_color_lut_size(blob: blob2);
3174
3175 if (lut_size1 != lut_size2)
3176 return false;
3177
3178 if (check_size > lut_size1)
3179 return false;
3180
3181 lut1 = blob1->data;
3182 lut2 = blob2->data;
3183
3184 err = 0xffff >> precision;
3185
3186 if (!check_size)
3187 check_size = lut_size1;
3188
3189 return intel_lut_entries_equal(lut1, lut2, lut_size: check_size, err);
3190}
3191
3192static bool i9xx_lut_equal(const struct intel_crtc_state *crtc_state,
3193 const struct drm_property_blob *blob1,
3194 const struct drm_property_blob *blob2,
3195 bool is_pre_csc_lut)
3196{
3197 int check_size = 0;
3198
3199 if (is_pre_csc_lut)
3200 return intel_lut_equal(blob1, blob2, check_size: 0,
3201 precision: i9xx_pre_csc_lut_precision(crtc_state));
3202
3203 /* 10bit mode last entry is implicit, just skip it */
3204 if (crtc_state->gamma_mode == GAMMA_MODE_MODE_10BIT)
3205 check_size = 128;
3206
3207 return intel_lut_equal(blob1, blob2, check_size,
3208 precision: i9xx_post_csc_lut_precision(crtc_state));
3209}
3210
3211static bool i965_lut_equal(const struct intel_crtc_state *crtc_state,
3212 const struct drm_property_blob *blob1,
3213 const struct drm_property_blob *blob2,
3214 bool is_pre_csc_lut)
3215{
3216 if (is_pre_csc_lut)
3217 return intel_lut_equal(blob1, blob2, check_size: 0,
3218 precision: i9xx_pre_csc_lut_precision(crtc_state));
3219 else
3220 return intel_lut_equal(blob1, blob2, check_size: 0,
3221 precision: i965_post_csc_lut_precision(crtc_state));
3222}
3223
3224static bool chv_lut_equal(const struct intel_crtc_state *crtc_state,
3225 const struct drm_property_blob *blob1,
3226 const struct drm_property_blob *blob2,
3227 bool is_pre_csc_lut)
3228{
3229 if (is_pre_csc_lut)
3230 return intel_lut_equal(blob1, blob2, check_size: 0,
3231 precision: chv_pre_csc_lut_precision(crtc_state));
3232 else
3233 return intel_lut_equal(blob1, blob2, check_size: 0,
3234 precision: chv_post_csc_lut_precision(crtc_state));
3235}
3236
3237static bool ilk_lut_equal(const struct intel_crtc_state *crtc_state,
3238 const struct drm_property_blob *blob1,
3239 const struct drm_property_blob *blob2,
3240 bool is_pre_csc_lut)
3241{
3242 if (is_pre_csc_lut)
3243 return intel_lut_equal(blob1, blob2, check_size: 0,
3244 precision: ilk_pre_csc_lut_precision(crtc_state));
3245 else
3246 return intel_lut_equal(blob1, blob2, check_size: 0,
3247 precision: ilk_post_csc_lut_precision(crtc_state));
3248}
3249
3250static bool ivb_lut_equal(const struct intel_crtc_state *crtc_state,
3251 const struct drm_property_blob *blob1,
3252 const struct drm_property_blob *blob2,
3253 bool is_pre_csc_lut)
3254{
3255 if (is_pre_csc_lut)
3256 return intel_lut_equal(blob1, blob2, check_size: 0,
3257 precision: ivb_pre_csc_lut_precision(crtc_state));
3258 else
3259 return intel_lut_equal(blob1, blob2, check_size: 0,
3260 precision: ivb_post_csc_lut_precision(crtc_state));
3261}
3262
3263static bool glk_lut_equal(const struct intel_crtc_state *crtc_state,
3264 const struct drm_property_blob *blob1,
3265 const struct drm_property_blob *blob2,
3266 bool is_pre_csc_lut)
3267{
3268 if (is_pre_csc_lut)
3269 return intel_lut_equal(blob1, blob2, check_size: 0,
3270 precision: glk_pre_csc_lut_precision(crtc_state));
3271 else
3272 return intel_lut_equal(blob1, blob2, check_size: 0,
3273 precision: glk_post_csc_lut_precision(crtc_state));
3274}
3275
3276static bool icl_lut_equal(const struct intel_crtc_state *crtc_state,
3277 const struct drm_property_blob *blob1,
3278 const struct drm_property_blob *blob2,
3279 bool is_pre_csc_lut)
3280{
3281 int check_size = 0;
3282
3283 if (is_pre_csc_lut)
3284 return intel_lut_equal(blob1, blob2, check_size: 0,
3285 precision: icl_pre_csc_lut_precision(crtc_state));
3286
3287 /* hw readout broken except for the super fine segment :( */
3288 if ((crtc_state->gamma_mode & GAMMA_MODE_MODE_MASK) ==
3289 GAMMA_MODE_MODE_12BIT_MULTI_SEG)
3290 check_size = 9;
3291
3292 return intel_lut_equal(blob1, blob2, check_size,
3293 precision: icl_post_csc_lut_precision(crtc_state));
3294}
3295
3296static struct drm_property_blob *i9xx_read_lut_8(struct intel_crtc *crtc)
3297{
3298 struct intel_display *display = to_intel_display(crtc);
3299 enum pipe pipe = crtc->pipe;
3300 struct drm_property_blob *blob;
3301 struct drm_color_lut *lut;
3302 int i;
3303
3304 blob = drm_property_create_blob(dev: display->drm,
3305 length: sizeof(lut[0]) * LEGACY_LUT_LENGTH,
3306 NULL);
3307 if (IS_ERR(ptr: blob))
3308 return NULL;
3309
3310 lut = blob->data;
3311
3312 for (i = 0; i < LEGACY_LUT_LENGTH; i++) {
3313 u32 val = intel_de_read_fw(display,
3314 PALETTE(display, pipe, i));
3315
3316 i9xx_lut_8_pack(entry: &lut[i], val);
3317 }
3318
3319 return blob;
3320}
3321
3322static struct drm_property_blob *i9xx_read_lut_10(struct intel_crtc *crtc)
3323{
3324 struct intel_display *display = to_intel_display(crtc);
3325 u32 lut_size = DISPLAY_INFO(display)->color.gamma_lut_size;
3326 enum pipe pipe = crtc->pipe;
3327 struct drm_property_blob *blob;
3328 struct drm_color_lut *lut;
3329 u32 ldw, udw;
3330 int i;
3331
3332 blob = drm_property_create_blob(dev: display->drm,
3333 length: lut_size * sizeof(lut[0]), NULL);
3334 if (IS_ERR(ptr: blob))
3335 return NULL;
3336
3337 lut = blob->data;
3338
3339 for (i = 0; i < lut_size - 1; i++) {
3340 ldw = intel_de_read_fw(display,
3341 PALETTE(display, pipe, 2 * i + 0));
3342 udw = intel_de_read_fw(display,
3343 PALETTE(display, pipe, 2 * i + 1));
3344
3345 i9xx_lut_10_pack(color: &lut[i], ldw, udw);
3346 }
3347
3348 i9xx_lut_10_pack_slope(color: &lut[i], ldw, udw);
3349
3350 return blob;
3351}
3352
3353static void i9xx_read_luts(struct intel_crtc_state *crtc_state)
3354{
3355 struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
3356
3357 if (!crtc_state->gamma_enable && !crtc_state->c8_planes)
3358 return;
3359
3360 switch (crtc_state->gamma_mode) {
3361 case GAMMA_MODE_MODE_8BIT:
3362 crtc_state->post_csc_lut = i9xx_read_lut_8(crtc);
3363 break;
3364 case GAMMA_MODE_MODE_10BIT:
3365 crtc_state->post_csc_lut = i9xx_read_lut_10(crtc);
3366 break;
3367 default:
3368 MISSING_CASE(crtc_state->gamma_mode);
3369 break;
3370 }
3371}
3372
3373static struct drm_property_blob *i965_read_lut_10p6(struct intel_crtc *crtc)
3374{
3375 struct intel_display *display = to_intel_display(crtc);
3376 int i, lut_size = DISPLAY_INFO(display)->color.gamma_lut_size;
3377 enum pipe pipe = crtc->pipe;
3378 struct drm_property_blob *blob;
3379 struct drm_color_lut *lut;
3380
3381 blob = drm_property_create_blob(dev: display->drm,
3382 length: sizeof(lut[0]) * lut_size,
3383 NULL);
3384 if (IS_ERR(ptr: blob))
3385 return NULL;
3386
3387 lut = blob->data;
3388
3389 for (i = 0; i < lut_size - 1; i++) {
3390 u32 ldw = intel_de_read_fw(display,
3391 PALETTE(display, pipe, 2 * i + 0));
3392 u32 udw = intel_de_read_fw(display,
3393 PALETTE(display, pipe, 2 * i + 1));
3394
3395 i965_lut_10p6_pack(entry: &lut[i], ldw, udw);
3396 }
3397
3398 lut[i].red = i965_lut_11p6_max_pack(val: intel_de_read_fw(display, PIPEGCMAX(display, pipe, 0)));
3399 lut[i].green = i965_lut_11p6_max_pack(val: intel_de_read_fw(display, PIPEGCMAX(display, pipe, 1)));
3400 lut[i].blue = i965_lut_11p6_max_pack(val: intel_de_read_fw(display, PIPEGCMAX(display, pipe, 2)));
3401
3402 return blob;
3403}
3404
3405static void i965_read_luts(struct intel_crtc_state *crtc_state)
3406{
3407 struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
3408
3409 if (!crtc_state->gamma_enable && !crtc_state->c8_planes)
3410 return;
3411
3412 switch (crtc_state->gamma_mode) {
3413 case GAMMA_MODE_MODE_8BIT:
3414 crtc_state->post_csc_lut = i9xx_read_lut_8(crtc);
3415 break;
3416 case GAMMA_MODE_MODE_10BIT:
3417 crtc_state->post_csc_lut = i965_read_lut_10p6(crtc);
3418 break;
3419 default:
3420 MISSING_CASE(crtc_state->gamma_mode);
3421 break;
3422 }
3423}
3424
3425static struct drm_property_blob *chv_read_cgm_degamma(struct intel_crtc *crtc)
3426{
3427 struct intel_display *display = to_intel_display(crtc);
3428 int i, lut_size = DISPLAY_INFO(display)->color.degamma_lut_size;
3429 enum pipe pipe = crtc->pipe;
3430 struct drm_property_blob *blob;
3431 struct drm_color_lut *lut;
3432
3433 blob = drm_property_create_blob(dev: display->drm,
3434 length: sizeof(lut[0]) * lut_size,
3435 NULL);
3436 if (IS_ERR(ptr: blob))
3437 return NULL;
3438
3439 lut = blob->data;
3440
3441 for (i = 0; i < lut_size; i++) {
3442 u32 ldw = intel_de_read_fw(display, CGM_PIPE_DEGAMMA(pipe, i, 0));
3443 u32 udw = intel_de_read_fw(display, CGM_PIPE_DEGAMMA(pipe, i, 1));
3444
3445 chv_cgm_degamma_pack(entry: &lut[i], ldw, udw);
3446 }
3447
3448 return blob;
3449}
3450
3451static struct drm_property_blob *chv_read_cgm_gamma(struct intel_crtc *crtc)
3452{
3453 struct intel_display *display = to_intel_display(crtc);
3454 int i, lut_size = DISPLAY_INFO(display)->color.gamma_lut_size;
3455 enum pipe pipe = crtc->pipe;
3456 struct drm_property_blob *blob;
3457 struct drm_color_lut *lut;
3458
3459 blob = drm_property_create_blob(dev: display->drm,
3460 length: sizeof(lut[0]) * lut_size,
3461 NULL);
3462 if (IS_ERR(ptr: blob))
3463 return NULL;
3464
3465 lut = blob->data;
3466
3467 for (i = 0; i < lut_size; i++) {
3468 u32 ldw = intel_de_read_fw(display, CGM_PIPE_GAMMA(pipe, i, 0));
3469 u32 udw = intel_de_read_fw(display, CGM_PIPE_GAMMA(pipe, i, 1));
3470
3471 chv_cgm_gamma_pack(entry: &lut[i], ldw, udw);
3472 }
3473
3474 return blob;
3475}
3476
3477static void chv_get_config(struct intel_crtc_state *crtc_state)
3478{
3479 struct intel_display *display = to_intel_display(crtc_state);
3480 struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
3481
3482 crtc_state->cgm_mode = intel_de_read(display, CGM_PIPE_MODE(crtc->pipe));
3483
3484 i9xx_get_config(crtc_state);
3485}
3486
3487static void chv_read_luts(struct intel_crtc_state *crtc_state)
3488{
3489 struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
3490
3491 if (crtc_state->cgm_mode & CGM_PIPE_MODE_DEGAMMA)
3492 crtc_state->pre_csc_lut = chv_read_cgm_degamma(crtc);
3493
3494 if (crtc_state->cgm_mode & CGM_PIPE_MODE_GAMMA)
3495 crtc_state->post_csc_lut = chv_read_cgm_gamma(crtc);
3496 else
3497 i965_read_luts(crtc_state);
3498}
3499
3500static struct drm_property_blob *ilk_read_lut_8(struct intel_crtc *crtc)
3501{
3502 struct intel_display *display = to_intel_display(crtc);
3503 enum pipe pipe = crtc->pipe;
3504 struct drm_property_blob *blob;
3505 struct drm_color_lut *lut;
3506 int i;
3507
3508 blob = drm_property_create_blob(dev: display->drm,
3509 length: sizeof(lut[0]) * LEGACY_LUT_LENGTH,
3510 NULL);
3511 if (IS_ERR(ptr: blob))
3512 return NULL;
3513
3514 lut = blob->data;
3515
3516 for (i = 0; i < LEGACY_LUT_LENGTH; i++) {
3517 u32 val = intel_de_read_fw(display, LGC_PALETTE(pipe, i));
3518
3519 i9xx_lut_8_pack(entry: &lut[i], val);
3520 }
3521
3522 return blob;
3523}
3524
3525static struct drm_property_blob *ilk_read_lut_10(struct intel_crtc *crtc)
3526{
3527 struct intel_display *display = to_intel_display(crtc);
3528 int i, lut_size = DISPLAY_INFO(display)->color.gamma_lut_size;
3529 enum pipe pipe = crtc->pipe;
3530 struct drm_property_blob *blob;
3531 struct drm_color_lut *lut;
3532
3533 blob = drm_property_create_blob(dev: display->drm,
3534 length: sizeof(lut[0]) * lut_size,
3535 NULL);
3536 if (IS_ERR(ptr: blob))
3537 return NULL;
3538
3539 lut = blob->data;
3540
3541 for (i = 0; i < lut_size; i++) {
3542 u32 val = intel_de_read_fw(display, PREC_PALETTE(pipe, i));
3543
3544 ilk_lut_10_pack(entry: &lut[i], val);
3545 }
3546
3547 return blob;
3548}
3549
3550static void ilk_get_config(struct intel_crtc_state *crtc_state)
3551{
3552 struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
3553
3554 crtc_state->csc_mode = ilk_read_csc_mode(crtc);
3555
3556 i9xx_get_config(crtc_state);
3557}
3558
3559static void ilk_read_luts(struct intel_crtc_state *crtc_state)
3560{
3561 struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
3562 struct drm_property_blob **blob =
3563 ilk_has_post_csc_lut(crtc_state) ?
3564 &crtc_state->post_csc_lut : &crtc_state->pre_csc_lut;
3565
3566 if (!crtc_state->gamma_enable && !crtc_state->c8_planes)
3567 return;
3568
3569 switch (crtc_state->gamma_mode) {
3570 case GAMMA_MODE_MODE_8BIT:
3571 *blob = ilk_read_lut_8(crtc);
3572 break;
3573 case GAMMA_MODE_MODE_10BIT:
3574 *blob = ilk_read_lut_10(crtc);
3575 break;
3576 default:
3577 MISSING_CASE(crtc_state->gamma_mode);
3578 break;
3579 }
3580}
3581
3582/*
3583 * IVB/HSW Bspec / PAL_PREC_INDEX:
3584 * "Restriction : Index auto increment mode is not
3585 * supported and must not be enabled."
3586 */
3587static struct drm_property_blob *ivb_read_lut_10(struct intel_crtc *crtc,
3588 u32 prec_index)
3589{
3590 struct intel_display *display = to_intel_display(crtc);
3591 int i, lut_size = ivb_lut_10_size(prec_index);
3592 enum pipe pipe = crtc->pipe;
3593 struct drm_property_blob *blob;
3594 struct drm_color_lut *lut;
3595
3596 blob = drm_property_create_blob(dev: display->drm,
3597 length: sizeof(lut[0]) * lut_size,
3598 NULL);
3599 if (IS_ERR(ptr: blob))
3600 return NULL;
3601
3602 lut = blob->data;
3603
3604 for (i = 0; i < lut_size; i++) {
3605 u32 val;
3606
3607 intel_de_write_fw(display, PREC_PAL_INDEX(pipe),
3608 val: prec_index + i);
3609 val = intel_de_read_fw(display, PREC_PAL_DATA(pipe));
3610
3611 ilk_lut_10_pack(entry: &lut[i], val);
3612 }
3613
3614 intel_de_write_fw(display, PREC_PAL_INDEX(pipe),
3615 PAL_PREC_INDEX_VALUE(0));
3616
3617 return blob;
3618}
3619
3620static void ivb_read_luts(struct intel_crtc_state *crtc_state)
3621{
3622 struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
3623 struct drm_property_blob **blob =
3624 ilk_has_post_csc_lut(crtc_state) ?
3625 &crtc_state->post_csc_lut : &crtc_state->pre_csc_lut;
3626
3627 if (!crtc_state->gamma_enable && !crtc_state->c8_planes)
3628 return;
3629
3630 switch (crtc_state->gamma_mode) {
3631 case GAMMA_MODE_MODE_8BIT:
3632 *blob = ilk_read_lut_8(crtc);
3633 break;
3634 case GAMMA_MODE_MODE_SPLIT:
3635 crtc_state->pre_csc_lut =
3636 ivb_read_lut_10(crtc, PAL_PREC_SPLIT_MODE |
3637 PAL_PREC_INDEX_VALUE(0));
3638 crtc_state->post_csc_lut =
3639 ivb_read_lut_10(crtc, PAL_PREC_SPLIT_MODE |
3640 PAL_PREC_INDEX_VALUE(512));
3641 break;
3642 case GAMMA_MODE_MODE_10BIT:
3643 *blob = ivb_read_lut_10(crtc, PAL_PREC_INDEX_VALUE(0));
3644 break;
3645 default:
3646 MISSING_CASE(crtc_state->gamma_mode);
3647 break;
3648 }
3649}
3650
3651/* On BDW+ the index auto increment mode actually works */
3652static struct drm_property_blob *bdw_read_lut_10(struct intel_crtc *crtc,
3653 u32 prec_index)
3654{
3655 struct intel_display *display = to_intel_display(crtc);
3656 int i, lut_size = ivb_lut_10_size(prec_index);
3657 enum pipe pipe = crtc->pipe;
3658 struct drm_property_blob *blob;
3659 struct drm_color_lut *lut;
3660
3661 blob = drm_property_create_blob(dev: display->drm,
3662 length: sizeof(lut[0]) * lut_size,
3663 NULL);
3664 if (IS_ERR(ptr: blob))
3665 return NULL;
3666
3667 lut = blob->data;
3668
3669 intel_de_write_fw(display, PREC_PAL_INDEX(pipe),
3670 val: prec_index);
3671 intel_de_write_fw(display, PREC_PAL_INDEX(pipe),
3672 PAL_PREC_AUTO_INCREMENT |
3673 prec_index);
3674
3675 for (i = 0; i < lut_size; i++) {
3676 u32 val = intel_de_read_fw(display, PREC_PAL_DATA(pipe));
3677
3678 ilk_lut_10_pack(entry: &lut[i], val);
3679 }
3680
3681 intel_de_write_fw(display, PREC_PAL_INDEX(pipe),
3682 PAL_PREC_INDEX_VALUE(0));
3683
3684 return blob;
3685}
3686
3687static void bdw_read_luts(struct intel_crtc_state *crtc_state)
3688{
3689 struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
3690 struct drm_property_blob **blob =
3691 ilk_has_post_csc_lut(crtc_state) ?
3692 &crtc_state->post_csc_lut : &crtc_state->pre_csc_lut;
3693
3694 if (!crtc_state->gamma_enable && !crtc_state->c8_planes)
3695 return;
3696
3697 switch (crtc_state->gamma_mode) {
3698 case GAMMA_MODE_MODE_8BIT:
3699 *blob = ilk_read_lut_8(crtc);
3700 break;
3701 case GAMMA_MODE_MODE_SPLIT:
3702 crtc_state->pre_csc_lut =
3703 bdw_read_lut_10(crtc, PAL_PREC_SPLIT_MODE |
3704 PAL_PREC_INDEX_VALUE(0));
3705 crtc_state->post_csc_lut =
3706 bdw_read_lut_10(crtc, PAL_PREC_SPLIT_MODE |
3707 PAL_PREC_INDEX_VALUE(512));
3708 break;
3709 case GAMMA_MODE_MODE_10BIT:
3710 *blob = bdw_read_lut_10(crtc, PAL_PREC_INDEX_VALUE(0));
3711 break;
3712 default:
3713 MISSING_CASE(crtc_state->gamma_mode);
3714 break;
3715 }
3716}
3717
3718static struct drm_property_blob *glk_read_degamma_lut(struct intel_crtc *crtc)
3719{
3720 struct intel_display *display = to_intel_display(crtc);
3721 int i, lut_size = DISPLAY_INFO(display)->color.degamma_lut_size;
3722 enum pipe pipe = crtc->pipe;
3723 struct drm_property_blob *blob;
3724 struct drm_color_lut *lut;
3725
3726 blob = drm_property_create_blob(dev: display->drm,
3727 length: sizeof(lut[0]) * lut_size,
3728 NULL);
3729 if (IS_ERR(ptr: blob))
3730 return NULL;
3731
3732 lut = blob->data;
3733
3734 /*
3735 * When setting the auto-increment bit, the hardware seems to
3736 * ignore the index bits, so we need to reset it to index 0
3737 * separately.
3738 */
3739 intel_de_write_fw(display, PRE_CSC_GAMC_INDEX(pipe),
3740 PRE_CSC_GAMC_INDEX_VALUE(0));
3741 intel_de_write_fw(display, PRE_CSC_GAMC_INDEX(pipe),
3742 PRE_CSC_GAMC_AUTO_INCREMENT |
3743 PRE_CSC_GAMC_INDEX_VALUE(0));
3744
3745 for (i = 0; i < lut_size; i++) {
3746 u32 val = intel_de_read_fw(display, PRE_CSC_GAMC_DATA(pipe));
3747
3748 if (DISPLAY_VER(display) >= 14)
3749 mtl_degamma_lut_pack(entry: &lut[i], val);
3750 else
3751 glk_degamma_lut_pack(entry: &lut[i], val);
3752 }
3753
3754 intel_de_write_fw(display, PRE_CSC_GAMC_INDEX(pipe),
3755 PRE_CSC_GAMC_INDEX_VALUE(0));
3756
3757 return blob;
3758}
3759
3760static void glk_read_luts(struct intel_crtc_state *crtc_state)
3761{
3762 struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
3763
3764 if (crtc_state->csc_enable)
3765 crtc_state->pre_csc_lut = glk_read_degamma_lut(crtc);
3766
3767 if (!crtc_state->gamma_enable && !crtc_state->c8_planes)
3768 return;
3769
3770 switch (crtc_state->gamma_mode) {
3771 case GAMMA_MODE_MODE_8BIT:
3772 crtc_state->post_csc_lut = ilk_read_lut_8(crtc);
3773 break;
3774 case GAMMA_MODE_MODE_10BIT:
3775 crtc_state->post_csc_lut = bdw_read_lut_10(crtc, PAL_PREC_INDEX_VALUE(0));
3776 break;
3777 default:
3778 MISSING_CASE(crtc_state->gamma_mode);
3779 break;
3780 }
3781}
3782
3783static struct drm_property_blob *
3784icl_read_lut_multi_segment(struct intel_crtc *crtc)
3785{
3786 struct intel_display *display = to_intel_display(crtc);
3787 int i, lut_size = DISPLAY_INFO(display)->color.gamma_lut_size;
3788 enum pipe pipe = crtc->pipe;
3789 struct drm_property_blob *blob;
3790 struct drm_color_lut *lut;
3791
3792 blob = drm_property_create_blob(dev: display->drm,
3793 length: sizeof(lut[0]) * lut_size,
3794 NULL);
3795 if (IS_ERR(ptr: blob))
3796 return NULL;
3797
3798 lut = blob->data;
3799
3800 intel_de_write_fw(display, PREC_PAL_MULTI_SEG_INDEX(pipe),
3801 PAL_PREC_MULTI_SEG_INDEX_VALUE(0));
3802 intel_de_write_fw(display, PREC_PAL_MULTI_SEG_INDEX(pipe),
3803 PAL_PREC_MULTI_SEG_AUTO_INCREMENT |
3804 PAL_PREC_MULTI_SEG_INDEX_VALUE(0));
3805
3806 for (i = 0; i < 9; i++) {
3807 u32 ldw = intel_de_read_fw(display, PREC_PAL_MULTI_SEG_DATA(pipe));
3808 u32 udw = intel_de_read_fw(display, PREC_PAL_MULTI_SEG_DATA(pipe));
3809
3810 ilk_lut_12p4_pack(entry: &lut[i], ldw, udw);
3811 }
3812
3813 intel_de_write_fw(display, PREC_PAL_MULTI_SEG_INDEX(pipe),
3814 PAL_PREC_MULTI_SEG_INDEX_VALUE(0));
3815
3816 /*
3817 * FIXME readouts from PAL_PREC_DATA register aren't giving
3818 * correct values in the case of fine and coarse segments.
3819 * Restricting readouts only for super fine segment as of now.
3820 */
3821
3822 return blob;
3823}
3824
3825static void icl_read_luts(struct intel_crtc_state *crtc_state)
3826{
3827 struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
3828
3829 if (icl_has_pre_csc_lut(crtc_state))
3830 crtc_state->pre_csc_lut = glk_read_degamma_lut(crtc);
3831
3832 if (!icl_has_post_csc_lut(crtc_state))
3833 return;
3834
3835 switch (crtc_state->gamma_mode & GAMMA_MODE_MODE_MASK) {
3836 case GAMMA_MODE_MODE_8BIT:
3837 crtc_state->post_csc_lut = ilk_read_lut_8(crtc);
3838 break;
3839 case GAMMA_MODE_MODE_10BIT:
3840 crtc_state->post_csc_lut = bdw_read_lut_10(crtc, PAL_PREC_INDEX_VALUE(0));
3841 break;
3842 case GAMMA_MODE_MODE_12BIT_MULTI_SEG:
3843 crtc_state->post_csc_lut = icl_read_lut_multi_segment(crtc);
3844 break;
3845 default:
3846 MISSING_CASE(crtc_state->gamma_mode);
3847 break;
3848 }
3849}
3850
3851static void
3852xelpd_load_plane_csc_matrix(struct intel_dsb *dsb,
3853 const struct intel_plane_state *plane_state)
3854{
3855 struct intel_display *display = to_intel_display(plane_state);
3856 const struct drm_plane_state *state = &plane_state->uapi;
3857 enum pipe pipe = to_intel_plane(state->plane)->pipe;
3858 enum plane_id plane = to_intel_plane(state->plane)->id;
3859 const struct drm_property_blob *blob = plane_state->hw.ctm;
3860 struct drm_color_ctm_3x4 *ctm;
3861 const u64 *input;
3862 u16 coeffs[9] = {};
3863 int i, j;
3864
3865 if (!icl_is_hdr_plane(display, plane_id: plane) || !blob)
3866 return;
3867
3868 ctm = blob->data;
3869 input = ctm->matrix;
3870
3871 /*
3872 * Convert fixed point S31.32 input to format supported by the
3873 * hardware.
3874 */
3875 for (i = 0, j = 0; i < ARRAY_SIZE(coeffs); i++) {
3876 u64 abs_coeff = ((1ULL << 63) - 1) & input[j];
3877
3878 /*
3879 * Clamp input value to min/max supported by
3880 * hardware.
3881 */
3882 abs_coeff = clamp_val(abs_coeff, 0, CTM_COEFF_4_0 - 1);
3883
3884 /* sign bit */
3885 if (CTM_COEFF_NEGATIVE(input[j]))
3886 coeffs[i] |= 1 << 15;
3887
3888 if (abs_coeff < CTM_COEFF_0_125)
3889 coeffs[i] |= (3 << 12) |
3890 ILK_CSC_COEFF_FP(abs_coeff, 12);
3891 else if (abs_coeff < CTM_COEFF_0_25)
3892 coeffs[i] |= (2 << 12) |
3893 ILK_CSC_COEFF_FP(abs_coeff, 11);
3894 else if (abs_coeff < CTM_COEFF_0_5)
3895 coeffs[i] |= (1 << 12) |
3896 ILK_CSC_COEFF_FP(abs_coeff, 10);
3897 else if (abs_coeff < CTM_COEFF_1_0)
3898 coeffs[i] |= ILK_CSC_COEFF_FP(abs_coeff, 9);
3899 else if (abs_coeff < CTM_COEFF_2_0)
3900 coeffs[i] |= (7 << 12) |
3901 ILK_CSC_COEFF_FP(abs_coeff, 8);
3902 else
3903 coeffs[i] |= (6 << 12) |
3904 ILK_CSC_COEFF_FP(abs_coeff, 7);
3905
3906 /* Skip postoffs */
3907 if (!((j + 2) % 4))
3908 j += 2;
3909 else
3910 j++;
3911 }
3912
3913 intel_de_write_dsb(display, dsb, PLANE_CSC_COEFF(pipe, plane, 0),
3914 val: coeffs[0] << 16 | coeffs[1]);
3915 intel_de_write_dsb(display, dsb, PLANE_CSC_COEFF(pipe, plane, 1),
3916 val: coeffs[2] << 16);
3917
3918 intel_de_write_dsb(display, dsb, PLANE_CSC_COEFF(pipe, plane, 2),
3919 val: coeffs[3] << 16 | coeffs[4]);
3920 intel_de_write_dsb(display, dsb, PLANE_CSC_COEFF(pipe, plane, 3),
3921 val: coeffs[5] << 16);
3922
3923 intel_de_write_dsb(display, dsb, PLANE_CSC_COEFF(pipe, plane, 4),
3924 val: coeffs[6] << 16 | coeffs[7]);
3925 intel_de_write_dsb(display, dsb, PLANE_CSC_COEFF(pipe, plane, 5),
3926 val: coeffs[8] << 16);
3927
3928 intel_de_write_dsb(display, dsb, PLANE_CSC_PREOFF(pipe, plane, 0), val: 0);
3929 intel_de_write_dsb(display, dsb, PLANE_CSC_PREOFF(pipe, plane, 1), val: 0);
3930 intel_de_write_dsb(display, dsb, PLANE_CSC_PREOFF(pipe, plane, 2), val: 0);
3931
3932 /*
3933 * Conversion from S31.32 to S0.12. BIT[12] is the signed bit
3934 */
3935 intel_de_write_dsb(display, dsb,
3936 PLANE_CSC_POSTOFF(pipe, plane, 0),
3937 val: ctm_to_twos_complement(coeff: input[3], int_bits: 0, frac_bits: 12));
3938 intel_de_write_dsb(display, dsb,
3939 PLANE_CSC_POSTOFF(pipe, plane, 1),
3940 val: ctm_to_twos_complement(coeff: input[7], int_bits: 0, frac_bits: 12));
3941 intel_de_write_dsb(display, dsb,
3942 PLANE_CSC_POSTOFF(pipe, plane, 2),
3943 val: ctm_to_twos_complement(coeff: input[11], int_bits: 0, frac_bits: 12));
3944}
3945
3946static void
3947xelpd_program_plane_pre_csc_lut(struct intel_dsb *dsb,
3948 const struct intel_plane_state *plane_state)
3949{
3950 struct intel_display *display = to_intel_display(plane_state);
3951 const struct drm_plane_state *state = &plane_state->uapi;
3952 enum pipe pipe = to_intel_plane(state->plane)->pipe;
3953 enum plane_id plane = to_intel_plane(state->plane)->id;
3954 const struct drm_color_lut32 *pre_csc_lut = plane_state->hw.degamma_lut->data;
3955 u32 i, lut_size;
3956
3957 if (icl_is_hdr_plane(display, plane_id: plane)) {
3958 lut_size = 128;
3959
3960 intel_de_write_dsb(display, dsb,
3961 PLANE_PRE_CSC_GAMC_INDEX_ENH(pipe, plane, 0),
3962 PLANE_PAL_PREC_AUTO_INCREMENT);
3963
3964 if (pre_csc_lut) {
3965 for (i = 0; i < lut_size; i++) {
3966 u32 lut_val = drm_color_lut32_extract(user_input: pre_csc_lut[i].green, bit_precision: 24);
3967
3968 intel_de_write_dsb(display, dsb,
3969 PLANE_PRE_CSC_GAMC_DATA_ENH(pipe, plane, 0),
3970 val: lut_val);
3971 }
3972
3973 /* Program the max register to clamp values > 1.0. */
3974 /* TODO: Restrict to 0x7ffffff */
3975 do {
3976 intel_de_write_dsb(display, dsb,
3977 PLANE_PRE_CSC_GAMC_DATA_ENH(pipe, plane, 0),
3978 val: (1 << 24));
3979 } while (i++ > 130);
3980 } else {
3981 for (i = 0; i < lut_size; i++) {
3982 u32 v = (i * ((1 << 24) - 1)) / (lut_size - 1);
3983
3984 intel_de_write_dsb(display, dsb,
3985 PLANE_PRE_CSC_GAMC_DATA_ENH(pipe, plane, 0), val: v);
3986 }
3987
3988 do {
3989 intel_de_write_dsb(display, dsb,
3990 PLANE_PRE_CSC_GAMC_DATA_ENH(pipe, plane, 0),
3991 val: 1 << 24);
3992 } while (i++ < 130);
3993 }
3994
3995 intel_de_write_dsb(display, dsb, PLANE_PRE_CSC_GAMC_INDEX_ENH(pipe, plane, 0), val: 0);
3996 }
3997}
3998
3999static void
4000xelpd_program_plane_post_csc_lut(struct intel_dsb *dsb,
4001 const struct intel_plane_state *plane_state)
4002{
4003 struct intel_display *display = to_intel_display(plane_state);
4004 const struct drm_plane_state *state = &plane_state->uapi;
4005 enum pipe pipe = to_intel_plane(state->plane)->pipe;
4006 enum plane_id plane = to_intel_plane(state->plane)->id;
4007 const struct drm_color_lut32 *post_csc_lut = plane_state->hw.gamma_lut->data;
4008 u32 i, lut_size, lut_val;
4009
4010 if (icl_is_hdr_plane(display, plane_id: plane)) {
4011 intel_de_write_dsb(display, dsb, PLANE_POST_CSC_GAMC_INDEX_ENH(pipe, plane, 0),
4012 PLANE_PAL_PREC_AUTO_INCREMENT);
4013 /* TODO: Add macro */
4014 intel_de_write_dsb(display, dsb, PLANE_POST_CSC_GAMC_SEG0_INDEX_ENH(pipe, plane, 0),
4015 PLANE_PAL_PREC_AUTO_INCREMENT);
4016 if (post_csc_lut) {
4017 lut_size = 32;
4018 for (i = 0; i < lut_size; i++) {
4019 lut_val = drm_color_lut32_extract(user_input: post_csc_lut[i].green, bit_precision: 24);
4020
4021 intel_de_write_dsb(display, dsb,
4022 PLANE_POST_CSC_GAMC_DATA_ENH(pipe, plane, 0),
4023 val: lut_val);
4024 }
4025
4026 /* Segment 2 */
4027 do {
4028 intel_de_write_dsb(display, dsb,
4029 PLANE_POST_CSC_GAMC_DATA_ENH(pipe, plane, 0),
4030 val: (1 << 24));
4031 } while (i++ < 34);
4032 } else {
4033 /*TODO: Add for segment 0 */
4034 lut_size = 32;
4035 for (i = 0; i < lut_size; i++) {
4036 u32 v = (i * ((1 << 24) - 1)) / (lut_size - 1);
4037
4038 intel_de_write_dsb(display, dsb,
4039 PLANE_POST_CSC_GAMC_DATA_ENH(pipe, plane, 0), val: v);
4040 }
4041
4042 do {
4043 intel_de_write_dsb(display, dsb,
4044 PLANE_POST_CSC_GAMC_DATA_ENH(pipe, plane, 0),
4045 val: 1 << 24);
4046 } while (i++ < 34);
4047 }
4048
4049 intel_de_write_dsb(display, dsb, PLANE_POST_CSC_GAMC_INDEX_ENH(pipe, plane, 0), val: 0);
4050 intel_de_write_dsb(display, dsb,
4051 PLANE_POST_CSC_GAMC_SEG0_INDEX_ENH(pipe, plane, 0), val: 0);
4052 }
4053}
4054
4055static void
4056xelpd_plane_load_luts(struct intel_dsb *dsb, const struct intel_plane_state *plane_state)
4057{
4058 if (plane_state->hw.degamma_lut)
4059 xelpd_program_plane_pre_csc_lut(dsb, plane_state);
4060
4061 if (plane_state->hw.gamma_lut)
4062 xelpd_program_plane_post_csc_lut(dsb, plane_state);
4063}
4064
4065static u32 glk_3dlut_10(const struct drm_color_lut32 *color)
4066{
4067 return REG_FIELD_PREP(LUT_3D_DATA_RED_MASK, drm_color_lut32_extract(color->red, 10)) |
4068 REG_FIELD_PREP(LUT_3D_DATA_GREEN_MASK, drm_color_lut32_extract(color->green, 10)) |
4069 REG_FIELD_PREP(LUT_3D_DATA_BLUE_MASK, drm_color_lut32_extract(color->blue, 10));
4070}
4071
4072static void glk_load_lut_3d(struct intel_dsb *dsb,
4073 struct intel_crtc *crtc,
4074 const struct drm_property_blob *blob)
4075{
4076 struct intel_display *display = to_intel_display(crtc->base.dev);
4077 const struct drm_color_lut32 *lut = blob->data;
4078 int i, lut_size = drm_color_lut32_size(blob);
4079 enum pipe pipe = crtc->pipe;
4080
4081 if (!dsb && intel_de_read(display, LUT_3D_CTL(pipe)) & LUT_3D_READY) {
4082 drm_err(display->drm, "[CRTC:%d:%s] 3D LUT not ready, not loading LUTs\n",
4083 crtc->base.base.id, crtc->base.name);
4084 return;
4085 }
4086
4087 intel_de_write_dsb(display, dsb, LUT_3D_INDEX(pipe), LUT_3D_AUTO_INCREMENT);
4088 for (i = 0; i < lut_size; i++)
4089 intel_de_write_dsb(display, dsb, LUT_3D_DATA(pipe), val: glk_3dlut_10(color: &lut[i]));
4090 intel_de_write_dsb(display, dsb, LUT_3D_INDEX(pipe), val: 0);
4091}
4092
4093static void glk_lut_3d_commit(struct intel_dsb *dsb, struct intel_crtc *crtc, bool enable)
4094{
4095 struct intel_display *display = to_intel_display(crtc);
4096 enum pipe pipe = crtc->pipe;
4097 u32 val = 0;
4098
4099 if (!dsb && intel_de_read(display, LUT_3D_CTL(pipe)) & LUT_3D_READY) {
4100 drm_err(display->drm, "[CRTC:%d:%s] 3D LUT not ready, not committing change\n",
4101 crtc->base.base.id, crtc->base.name);
4102 return;
4103 }
4104
4105 if (enable)
4106 val = LUT_3D_ENABLE | LUT_3D_READY | LUT_3D_BIND_PLANE_1;
4107
4108 intel_de_write_dsb(display, dsb, LUT_3D_CTL(pipe), val);
4109}
4110
4111static const struct intel_color_funcs chv_color_funcs = {
4112 .color_check = chv_color_check,
4113 .color_commit_arm = i9xx_color_commit_arm,
4114 .load_luts = chv_load_luts,
4115 .read_luts = chv_read_luts,
4116 .lut_equal = chv_lut_equal,
4117 .read_csc = chv_read_csc,
4118 .get_config = chv_get_config,
4119};
4120
4121static const struct intel_color_funcs vlv_color_funcs = {
4122 .color_check = vlv_color_check,
4123 .color_commit_arm = i9xx_color_commit_arm,
4124 .load_luts = vlv_load_luts,
4125 .read_luts = i965_read_luts,
4126 .lut_equal = i965_lut_equal,
4127 .read_csc = vlv_read_csc,
4128 .get_config = i9xx_get_config,
4129};
4130
4131static const struct intel_color_funcs i965_color_funcs = {
4132 .color_check = i9xx_color_check,
4133 .color_commit_arm = i9xx_color_commit_arm,
4134 .load_luts = i965_load_luts,
4135 .read_luts = i965_read_luts,
4136 .lut_equal = i965_lut_equal,
4137 .get_config = i9xx_get_config,
4138};
4139
4140static const struct intel_color_funcs i9xx_color_funcs = {
4141 .color_check = i9xx_color_check,
4142 .color_commit_arm = i9xx_color_commit_arm,
4143 .load_luts = i9xx_load_luts,
4144 .read_luts = i9xx_read_luts,
4145 .lut_equal = i9xx_lut_equal,
4146 .get_config = i9xx_get_config,
4147};
4148
4149static const struct intel_color_funcs tgl_color_funcs = {
4150 .color_check = icl_color_check,
4151 .color_commit_noarm = icl_color_commit_noarm,
4152 .color_commit_arm = icl_color_commit_arm,
4153 .load_luts = icl_load_luts,
4154 .read_luts = icl_read_luts,
4155 .lut_equal = icl_lut_equal,
4156 .read_csc = icl_read_csc,
4157 .get_config = skl_get_config,
4158 .load_plane_csc_matrix = xelpd_load_plane_csc_matrix,
4159 .load_plane_luts = xelpd_plane_load_luts,
4160};
4161
4162static const struct intel_color_funcs icl_color_funcs = {
4163 .color_check = icl_color_check,
4164 .color_commit_noarm = icl_color_commit_noarm,
4165 .color_commit_arm = icl_color_commit_arm,
4166 .color_post_update = icl_color_post_update,
4167 .load_luts = icl_load_luts,
4168 .read_luts = icl_read_luts,
4169 .lut_equal = icl_lut_equal,
4170 .read_csc = icl_read_csc,
4171 .get_config = skl_get_config,
4172};
4173
4174static const struct intel_color_funcs glk_color_funcs = {
4175 .color_check = glk_color_check,
4176 .color_commit_noarm = skl_color_commit_noarm,
4177 .color_commit_arm = skl_color_commit_arm,
4178 .load_luts = glk_load_luts,
4179 .read_luts = glk_read_luts,
4180 .lut_equal = glk_lut_equal,
4181 .read_csc = skl_read_csc,
4182 .get_config = skl_get_config,
4183};
4184
4185static const struct intel_color_funcs skl_color_funcs = {
4186 .color_check = ivb_color_check,
4187 .color_commit_noarm = skl_color_commit_noarm,
4188 .color_commit_arm = skl_color_commit_arm,
4189 .load_luts = bdw_load_luts,
4190 .read_luts = bdw_read_luts,
4191 .lut_equal = ivb_lut_equal,
4192 .read_csc = skl_read_csc,
4193 .get_config = skl_get_config,
4194};
4195
4196static const struct intel_color_funcs bdw_color_funcs = {
4197 .color_check = ivb_color_check,
4198 .color_commit_noarm = ilk_color_commit_noarm,
4199 .color_commit_arm = hsw_color_commit_arm,
4200 .load_luts = bdw_load_luts,
4201 .read_luts = bdw_read_luts,
4202 .lut_equal = ivb_lut_equal,
4203 .read_csc = ilk_read_csc,
4204 .get_config = hsw_get_config,
4205};
4206
4207static const struct intel_color_funcs hsw_color_funcs = {
4208 .color_check = ivb_color_check,
4209 .color_commit_noarm = ilk_color_commit_noarm,
4210 .color_commit_arm = hsw_color_commit_arm,
4211 .load_luts = ivb_load_luts,
4212 .read_luts = ivb_read_luts,
4213 .lut_equal = ivb_lut_equal,
4214 .read_csc = ilk_read_csc,
4215 .get_config = hsw_get_config,
4216};
4217
4218static const struct intel_color_funcs ivb_color_funcs = {
4219 .color_check = ivb_color_check,
4220 .color_commit_noarm = ilk_color_commit_noarm,
4221 .color_commit_arm = ilk_color_commit_arm,
4222 .load_luts = ivb_load_luts,
4223 .read_luts = ivb_read_luts,
4224 .lut_equal = ivb_lut_equal,
4225 .read_csc = ilk_read_csc,
4226 .get_config = ilk_get_config,
4227};
4228
4229static const struct intel_color_funcs ilk_color_funcs = {
4230 .color_check = ilk_color_check,
4231 .color_commit_noarm = ilk_color_commit_noarm,
4232 .color_commit_arm = ilk_color_commit_arm,
4233 .load_luts = ilk_load_luts,
4234 .read_luts = ilk_read_luts,
4235 .lut_equal = ilk_lut_equal,
4236 .read_csc = ilk_read_csc,
4237 .get_config = ilk_get_config,
4238};
4239
4240void intel_color_plane_commit_arm(struct intel_dsb *dsb,
4241 const struct intel_plane_state *plane_state)
4242{
4243 struct intel_display *display = to_intel_display(plane_state);
4244 struct intel_crtc *crtc = to_intel_crtc(plane_state->uapi.crtc);
4245
4246 if (crtc && intel_color_crtc_has_3dlut(display, pipe: crtc->pipe))
4247 glk_lut_3d_commit(dsb, crtc, enable: !!plane_state->hw.lut_3d);
4248}
4249
4250static void
4251intel_color_load_plane_csc_matrix(struct intel_dsb *dsb,
4252 const struct intel_plane_state *plane_state)
4253{
4254 struct intel_display *display = to_intel_display(plane_state);
4255
4256 if (display->funcs.color->load_plane_csc_matrix)
4257 display->funcs.color->load_plane_csc_matrix(dsb, plane_state);
4258}
4259
4260static void
4261intel_color_load_plane_luts(struct intel_dsb *dsb,
4262 const struct intel_plane_state *plane_state)
4263{
4264 struct intel_display *display = to_intel_display(plane_state);
4265
4266 if (display->funcs.color->load_plane_luts)
4267 display->funcs.color->load_plane_luts(dsb, plane_state);
4268}
4269
4270bool
4271intel_color_crtc_has_3dlut(struct intel_display *display, enum pipe pipe)
4272{
4273 if (DISPLAY_VER(display) >= 12)
4274 return pipe == PIPE_A || pipe == PIPE_B;
4275 else
4276 return false;
4277}
4278
4279static void
4280intel_color_load_3dlut(struct intel_dsb *dsb,
4281 const struct intel_plane_state *plane_state)
4282{
4283 struct intel_display *display = to_intel_display(plane_state);
4284 struct intel_crtc *crtc = to_intel_crtc(plane_state->uapi.crtc);
4285
4286 if (crtc && intel_color_crtc_has_3dlut(display, pipe: crtc->pipe))
4287 glk_load_lut_3d(dsb, crtc, blob: plane_state->hw.lut_3d);
4288}
4289
4290void intel_color_plane_program_pipeline(struct intel_dsb *dsb,
4291 const struct intel_plane_state *plane_state)
4292{
4293 if (plane_state->hw.ctm)
4294 intel_color_load_plane_csc_matrix(dsb, plane_state);
4295 if (plane_state->hw.degamma_lut || plane_state->hw.gamma_lut)
4296 intel_color_load_plane_luts(dsb, plane_state);
4297 if (plane_state->hw.lut_3d)
4298 intel_color_load_3dlut(dsb, plane_state);
4299}
4300
4301void intel_color_crtc_init(struct intel_crtc *crtc)
4302{
4303 struct intel_display *display = to_intel_display(crtc);
4304 int degamma_lut_size, gamma_lut_size;
4305 bool has_ctm;
4306
4307 drm_mode_crtc_set_gamma_size(crtc: &crtc->base, gamma_size: 256);
4308
4309 gamma_lut_size = DISPLAY_INFO(display)->color.gamma_lut_size;
4310 degamma_lut_size = DISPLAY_INFO(display)->color.degamma_lut_size;
4311 has_ctm = DISPLAY_VER(display) >= 5;
4312
4313 /*
4314 * "DPALETTE_A: NOTE: The 8-bit (non-10-bit) mode is the
4315 * only mode supported by Alviso and Grantsdale."
4316 *
4317 * Actually looks like this affects all of gen3.
4318 * Confirmed on alv,cst,pnv. Mobile gen2 parts (alm,mgm)
4319 * are confirmed not to suffer from this restriction.
4320 */
4321 if (DISPLAY_VER(display) == 3 && crtc->pipe == PIPE_A)
4322 gamma_lut_size = 256;
4323
4324 drm_crtc_enable_color_mgmt(crtc: &crtc->base, degamma_lut_size,
4325 has_ctm, gamma_lut_size);
4326}
4327
4328int intel_color_init(struct intel_display *display)
4329{
4330 struct drm_property_blob *blob;
4331
4332 if (DISPLAY_VER(display) != 10)
4333 return 0;
4334
4335 blob = create_linear_lut(display,
4336 DISPLAY_INFO(display)->color.degamma_lut_size);
4337 if (IS_ERR(ptr: blob))
4338 return PTR_ERR(ptr: blob);
4339
4340 display->color.glk_linear_degamma_lut = blob;
4341
4342 return 0;
4343}
4344
4345void intel_color_init_hooks(struct intel_display *display)
4346{
4347 if (HAS_GMCH(display)) {
4348 if (display->platform.cherryview)
4349 display->funcs.color = &chv_color_funcs;
4350 else if (display->platform.valleyview)
4351 display->funcs.color = &vlv_color_funcs;
4352 else if (DISPLAY_VER(display) >= 4)
4353 display->funcs.color = &i965_color_funcs;
4354 else
4355 display->funcs.color = &i9xx_color_funcs;
4356 } else {
4357 if (DISPLAY_VER(display) >= 12)
4358 display->funcs.color = &tgl_color_funcs;
4359 else if (DISPLAY_VER(display) == 11)
4360 display->funcs.color = &icl_color_funcs;
4361 else if (DISPLAY_VER(display) == 10)
4362 display->funcs.color = &glk_color_funcs;
4363 else if (DISPLAY_VER(display) == 9)
4364 display->funcs.color = &skl_color_funcs;
4365 else if (DISPLAY_VER(display) == 8)
4366 display->funcs.color = &bdw_color_funcs;
4367 else if (display->platform.haswell)
4368 display->funcs.color = &hsw_color_funcs;
4369 else if (DISPLAY_VER(display) == 7)
4370 display->funcs.color = &ivb_color_funcs;
4371 else
4372 display->funcs.color = &ilk_color_funcs;
4373 }
4374}
4375

source code of linux/drivers/gpu/drm/i915/display/intel_color.c