]>
Commit | Line | Data |
---|---|---|
8563b1e8 LL |
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 | ||
78c61320 | 25 | #include "intel_color.h" |
7785ae0b | 26 | #include "intel_de.h" |
1d455f8d | 27 | #include "intel_display_types.h" |
8563b1e8 | 28 | |
82cf435b LL |
29 | #define CTM_COEFF_SIGN (1ULL << 63) |
30 | ||
31 | #define CTM_COEFF_1_0 (1ULL << 32) | |
32 | #define CTM_COEFF_2_0 (CTM_COEFF_1_0 << 1) | |
33 | #define CTM_COEFF_4_0 (CTM_COEFF_2_0 << 1) | |
29dc3739 | 34 | #define CTM_COEFF_8_0 (CTM_COEFF_4_0 << 1) |
82cf435b LL |
35 | #define CTM_COEFF_0_5 (CTM_COEFF_1_0 >> 1) |
36 | #define CTM_COEFF_0_25 (CTM_COEFF_0_5 >> 1) | |
37 | #define CTM_COEFF_0_125 (CTM_COEFF_0_25 >> 1) | |
38 | ||
39 | #define CTM_COEFF_LIMITED_RANGE ((235ULL - 16ULL) * CTM_COEFF_1_0 / 255) | |
40 | ||
41 | #define CTM_COEFF_NEGATIVE(coeff) (((coeff) & CTM_COEFF_SIGN) != 0) | |
42 | #define CTM_COEFF_ABS(coeff) ((coeff) & (CTM_COEFF_SIGN - 1)) | |
43 | ||
80343b3e | 44 | #define LEGACY_LUT_LENGTH 256 |
02ae8ba9 | 45 | |
174d12bc VS |
46 | /* |
47 | * ILK+ csc matrix: | |
48 | * | |
49 | * |R/Cr| | c0 c1 c2 | ( |R/Cr| |preoff0| ) |postoff0| | |
50 | * |G/Y | = | c3 c4 c5 | x ( |G/Y | + |preoff1| ) + |postoff1| | |
51 | * |B/Cb| | c6 c7 c8 | ( |B/Cb| |preoff2| ) |postoff2| | |
52 | * | |
53 | * ILK/SNB don't have explicit post offsets, and instead | |
54 | * CSC_MODE_YUV_TO_RGB and CSC_BLACK_SCREEN_OFFSET are used: | |
55 | * CSC_MODE_YUV_TO_RGB=0 + CSC_BLACK_SCREEN_OFFSET=0 -> 1/2, 0, 1/2 | |
56 | * CSC_MODE_YUV_TO_RGB=0 + CSC_BLACK_SCREEN_OFFSET=1 -> 1/2, 1/16, 1/2 | |
57 | * CSC_MODE_YUV_TO_RGB=1 + CSC_BLACK_SCREEN_OFFSET=0 -> 0, 0, 0 | |
58 | * CSC_MODE_YUV_TO_RGB=1 + CSC_BLACK_SCREEN_OFFSET=1 -> 1/16, 1/16, 1/16 | |
59 | */ | |
60 | ||
8563b1e8 | 61 | /* |
82cf435b LL |
62 | * Extract the CSC coefficient from a CTM coefficient (in U32.32 fixed point |
63 | * format). This macro takes the coefficient we want transformed and the | |
64 | * number of fractional bits. | |
8563b1e8 | 65 | * |
82cf435b LL |
66 | * We only have a 9 bits precision window which slides depending on the value |
67 | * of the CTM coefficient and we write the value from bit 3. We also round the | |
68 | * value. | |
8563b1e8 | 69 | */ |
c35e8a25 | 70 | #define ILK_CSC_COEFF_FP(coeff, fbits) \ |
82cf435b LL |
71 | (clamp_val(((coeff) >> (32 - (fbits) - 3)) + 4, 0, 0xfff) & 0xff8) |
72 | ||
b281264f VS |
73 | #define ILK_CSC_COEFF_LIMITED_RANGE 0x0dc0 |
74 | #define ILK_CSC_COEFF_1_0 0x7800 | |
82cf435b | 75 | |
d2c19b06 VS |
76 | #define ILK_CSC_POSTOFF_LIMITED_RANGE (16 * (1 << 12) / 255) |
77 | ||
174d12bc | 78 | /* Nop pre/post offsets */ |
d2c19b06 VS |
79 | static const u16 ilk_csc_off_zero[3] = {}; |
80 | ||
174d12bc | 81 | /* Identity matrix */ |
b281264f VS |
82 | static const u16 ilk_csc_coeff_identity[9] = { |
83 | ILK_CSC_COEFF_1_0, 0, 0, | |
84 | 0, ILK_CSC_COEFF_1_0, 0, | |
85 | 0, 0, ILK_CSC_COEFF_1_0, | |
86 | }; | |
87 | ||
174d12bc | 88 | /* Limited range RGB post offsets */ |
d2c19b06 VS |
89 | static const u16 ilk_csc_postoff_limited_range[3] = { |
90 | ILK_CSC_POSTOFF_LIMITED_RANGE, | |
91 | ILK_CSC_POSTOFF_LIMITED_RANGE, | |
92 | ILK_CSC_POSTOFF_LIMITED_RANGE, | |
93 | }; | |
94 | ||
174d12bc | 95 | /* Full range RGB -> limited range RGB matrix */ |
b281264f VS |
96 | static const u16 ilk_csc_coeff_limited_range[9] = { |
97 | ILK_CSC_COEFF_LIMITED_RANGE, 0, 0, | |
98 | 0, ILK_CSC_COEFF_LIMITED_RANGE, 0, | |
99 | 0, 0, ILK_CSC_COEFF_LIMITED_RANGE, | |
100 | }; | |
101 | ||
174d12bc | 102 | /* BT.709 full range RGB -> limited range YCbCr matrix */ |
d2c19b06 VS |
103 | static const u16 ilk_csc_coeff_rgb_to_ycbcr[9] = { |
104 | 0x1e08, 0x9cc0, 0xb528, | |
105 | 0x2ba8, 0x09d8, 0x37e8, | |
106 | 0xbce8, 0x9ad8, 0x1e08, | |
107 | }; | |
108 | ||
174d12bc | 109 | /* Limited range YCbCr post offsets */ |
d2c19b06 VS |
110 | static const u16 ilk_csc_postoff_rgb_to_ycbcr[3] = { |
111 | 0x0800, 0x0100, 0x0800, | |
112 | }; | |
113 | ||
23b03a27 | 114 | static bool lut_is_legacy(const struct drm_property_blob *lut) |
82cf435b | 115 | { |
a4893349 CW |
116 | return drm_color_lut_size(lut) == LEGACY_LUT_LENGTH; |
117 | } | |
302da0cd | 118 | |
23b03a27 | 119 | static bool crtc_state_is_legacy_gamma(const struct intel_crtc_state *crtc_state) |
a4893349 | 120 | { |
1326a92c ML |
121 | return !crtc_state->hw.degamma_lut && |
122 | !crtc_state->hw.ctm && | |
123 | crtc_state->hw.gamma_lut && | |
124 | lut_is_legacy(crtc_state->hw.gamma_lut); | |
82cf435b LL |
125 | } |
126 | ||
127 | /* | |
128 | * When using limited range, multiply the matrix given by userspace by | |
db9c06df | 129 | * the matrix that we would use for the limited range. |
82cf435b | 130 | */ |
db61d160 | 131 | static u64 *ctm_mult_by_limited(u64 *result, const u64 *input) |
82cf435b LL |
132 | { |
133 | int i; | |
134 | ||
db9c06df JL |
135 | for (i = 0; i < 9; i++) { |
136 | u64 user_coeff = input[i]; | |
137 | u32 limited_coeff = CTM_COEFF_LIMITED_RANGE; | |
138 | u32 abs_coeff = clamp_val(CTM_COEFF_ABS(user_coeff), 0, | |
139 | CTM_COEFF_4_0 - 1) >> 2; | |
82cf435b | 140 | |
db9c06df JL |
141 | /* |
142 | * By scaling every co-efficient with limited range (16-235) | |
143 | * vs full range (0-255) the final o/p will be scaled down to | |
144 | * fit in the limited range supported by the panel. | |
145 | */ | |
146 | result[i] = mul_u32_u32(limited_coeff, abs_coeff) >> 30; | |
147 | result[i] |= user_coeff & CTM_COEFF_SIGN; | |
82cf435b | 148 | } |
db61d160 VS |
149 | |
150 | return result; | |
82cf435b LL |
151 | } |
152 | ||
d2c19b06 VS |
153 | static void ilk_update_pipe_csc(struct intel_crtc *crtc, |
154 | const u16 preoff[3], | |
155 | const u16 coeff[9], | |
156 | const u16 postoff[3]) | |
25edf915 | 157 | { |
302da0cd | 158 | struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); |
23b03a27 | 159 | enum pipe pipe = crtc->pipe; |
25edf915 | 160 | |
3fd7c450 JN |
161 | intel_de_write(dev_priv, PIPE_CSC_PREOFF_HI(pipe), preoff[0]); |
162 | intel_de_write(dev_priv, PIPE_CSC_PREOFF_ME(pipe), preoff[1]); | |
163 | intel_de_write(dev_priv, PIPE_CSC_PREOFF_LO(pipe), preoff[2]); | |
25edf915 | 164 | |
3fd7c450 JN |
165 | intel_de_write(dev_priv, PIPE_CSC_COEFF_RY_GY(pipe), |
166 | coeff[0] << 16 | coeff[1]); | |
167 | intel_de_write(dev_priv, PIPE_CSC_COEFF_BY(pipe), coeff[2] << 16); | |
25edf915 | 168 | |
3fd7c450 JN |
169 | intel_de_write(dev_priv, PIPE_CSC_COEFF_RU_GU(pipe), |
170 | coeff[3] << 16 | coeff[4]); | |
171 | intel_de_write(dev_priv, PIPE_CSC_COEFF_BU(pipe), coeff[5] << 16); | |
25edf915 | 172 | |
3fd7c450 JN |
173 | intel_de_write(dev_priv, PIPE_CSC_COEFF_RV_GV(pipe), |
174 | coeff[6] << 16 | coeff[7]); | |
175 | intel_de_write(dev_priv, PIPE_CSC_COEFF_BV(pipe), coeff[8] << 16); | |
25edf915 | 176 | |
005e9537 | 177 | if (DISPLAY_VER(dev_priv) >= 7) { |
3fd7c450 JN |
178 | intel_de_write(dev_priv, PIPE_CSC_POSTOFF_HI(pipe), |
179 | postoff[0]); | |
180 | intel_de_write(dev_priv, PIPE_CSC_POSTOFF_ME(pipe), | |
181 | postoff[1]); | |
182 | intel_de_write(dev_priv, PIPE_CSC_POSTOFF_LO(pipe), | |
183 | postoff[2]); | |
a91de580 | 184 | } |
25edf915 SS |
185 | } |
186 | ||
d2c19b06 VS |
187 | static void icl_update_output_csc(struct intel_crtc *crtc, |
188 | const u16 preoff[3], | |
189 | const u16 coeff[9], | |
190 | const u16 postoff[3]) | |
191 | { | |
192 | struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); | |
193 | enum pipe pipe = crtc->pipe; | |
194 | ||
3fd7c450 JN |
195 | intel_de_write(dev_priv, PIPE_CSC_OUTPUT_PREOFF_HI(pipe), preoff[0]); |
196 | intel_de_write(dev_priv, PIPE_CSC_OUTPUT_PREOFF_ME(pipe), preoff[1]); | |
197 | intel_de_write(dev_priv, PIPE_CSC_OUTPUT_PREOFF_LO(pipe), preoff[2]); | |
d2c19b06 | 198 | |
3fd7c450 JN |
199 | intel_de_write(dev_priv, PIPE_CSC_OUTPUT_COEFF_RY_GY(pipe), |
200 | coeff[0] << 16 | coeff[1]); | |
201 | intel_de_write(dev_priv, PIPE_CSC_OUTPUT_COEFF_BY(pipe), | |
202 | coeff[2] << 16); | |
d2c19b06 | 203 | |
3fd7c450 JN |
204 | intel_de_write(dev_priv, PIPE_CSC_OUTPUT_COEFF_RU_GU(pipe), |
205 | coeff[3] << 16 | coeff[4]); | |
206 | intel_de_write(dev_priv, PIPE_CSC_OUTPUT_COEFF_BU(pipe), | |
207 | coeff[5] << 16); | |
d2c19b06 | 208 | |
3fd7c450 JN |
209 | intel_de_write(dev_priv, PIPE_CSC_OUTPUT_COEFF_RV_GV(pipe), |
210 | coeff[6] << 16 | coeff[7]); | |
211 | intel_de_write(dev_priv, PIPE_CSC_OUTPUT_COEFF_BV(pipe), | |
212 | coeff[8] << 16); | |
d2c19b06 | 213 | |
3fd7c450 JN |
214 | intel_de_write(dev_priv, PIPE_CSC_OUTPUT_POSTOFF_HI(pipe), postoff[0]); |
215 | intel_de_write(dev_priv, PIPE_CSC_OUTPUT_POSTOFF_ME(pipe), postoff[1]); | |
216 | intel_de_write(dev_priv, PIPE_CSC_OUTPUT_POSTOFF_LO(pipe), postoff[2]); | |
d2c19b06 VS |
217 | } |
218 | ||
386ba08f VS |
219 | static bool ilk_csc_limited_range(const struct intel_crtc_state *crtc_state) |
220 | { | |
2225f3c6 | 221 | struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev); |
386ba08f VS |
222 | |
223 | /* | |
224 | * FIXME if there's a gamma LUT after the CSC, we should | |
225 | * do the range compression using the gamma LUT instead. | |
226 | */ | |
227 | return crtc_state->limited_color_range && | |
228 | (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv) || | |
93e7e61e | 229 | IS_DISPLAY_VER(dev_priv, 9, 10)); |
386ba08f VS |
230 | } |
231 | ||
c9e235aa VS |
232 | static void ilk_csc_convert_ctm(const struct intel_crtc_state *crtc_state, |
233 | u16 coeffs[9]) | |
234 | { | |
1326a92c | 235 | const struct drm_color_ctm *ctm = crtc_state->hw.ctm->data; |
c9e235aa VS |
236 | const u64 *input; |
237 | u64 temp[9]; | |
238 | int i; | |
239 | ||
240 | if (ilk_csc_limited_range(crtc_state)) | |
241 | input = ctm_mult_by_limited(temp, ctm->matrix); | |
242 | else | |
243 | input = ctm->matrix; | |
244 | ||
245 | /* | |
246 | * Convert fixed point S31.32 input to format supported by the | |
247 | * hardware. | |
248 | */ | |
249 | for (i = 0; i < 9; i++) { | |
250 | u64 abs_coeff = ((1ULL << 63) - 1) & input[i]; | |
251 | ||
252 | /* | |
253 | * Clamp input value to min/max supported by | |
254 | * hardware. | |
255 | */ | |
256 | abs_coeff = clamp_val(abs_coeff, 0, CTM_COEFF_4_0 - 1); | |
257 | ||
258 | coeffs[i] = 0; | |
259 | ||
260 | /* sign bit */ | |
261 | if (CTM_COEFF_NEGATIVE(input[i])) | |
262 | coeffs[i] |= 1 << 15; | |
263 | ||
264 | if (abs_coeff < CTM_COEFF_0_125) | |
265 | coeffs[i] |= (3 << 12) | | |
266 | ILK_CSC_COEFF_FP(abs_coeff, 12); | |
267 | else if (abs_coeff < CTM_COEFF_0_25) | |
268 | coeffs[i] |= (2 << 12) | | |
269 | ILK_CSC_COEFF_FP(abs_coeff, 11); | |
270 | else if (abs_coeff < CTM_COEFF_0_5) | |
271 | coeffs[i] |= (1 << 12) | | |
272 | ILK_CSC_COEFF_FP(abs_coeff, 10); | |
273 | else if (abs_coeff < CTM_COEFF_1_0) | |
274 | coeffs[i] |= ILK_CSC_COEFF_FP(abs_coeff, 9); | |
275 | else if (abs_coeff < CTM_COEFF_2_0) | |
276 | coeffs[i] |= (7 << 12) | | |
277 | ILK_CSC_COEFF_FP(abs_coeff, 8); | |
278 | else | |
279 | coeffs[i] |= (6 << 12) | | |
280 | ILK_CSC_COEFF_FP(abs_coeff, 7); | |
281 | } | |
282 | } | |
283 | ||
23b03a27 | 284 | static void ilk_load_csc_matrix(const struct intel_crtc_state *crtc_state) |
8563b1e8 | 285 | { |
2225f3c6 | 286 | struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); |
302da0cd | 287 | struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); |
386ba08f | 288 | bool limited_color_range = ilk_csc_limited_range(crtc_state); |
a91de580 | 289 | |
1326a92c | 290 | if (crtc_state->hw.ctm) { |
f19d90ee | 291 | u16 coeff[9]; |
8563b1e8 | 292 | |
f19d90ee VS |
293 | ilk_csc_convert_ctm(crtc_state, coeff); |
294 | ilk_update_pipe_csc(crtc, ilk_csc_off_zero, coeff, | |
b281264f VS |
295 | limited_color_range ? |
296 | ilk_csc_postoff_limited_range : | |
297 | ilk_csc_off_zero); | |
f19d90ee VS |
298 | } else if (crtc_state->output_format != INTEL_OUTPUT_FORMAT_RGB) { |
299 | ilk_update_pipe_csc(crtc, ilk_csc_off_zero, | |
300 | ilk_csc_coeff_rgb_to_ycbcr, | |
301 | ilk_csc_postoff_rgb_to_ycbcr); | |
b281264f VS |
302 | } else if (limited_color_range) { |
303 | ilk_update_pipe_csc(crtc, ilk_csc_off_zero, | |
304 | ilk_csc_coeff_limited_range, | |
305 | ilk_csc_postoff_limited_range); | |
306 | } else if (crtc_state->csc_enable) { | |
c4128ce7 | 307 | /* |
44bf1b73 | 308 | * On GLK both pipe CSC and degamma LUT are controlled |
c4128ce7 VS |
309 | * by csc_enable. Hence for the cases where the degama |
310 | * LUT is needed but CSC is not we need to load an | |
311 | * identity matrix. | |
312 | */ | |
44bf1b73 | 313 | drm_WARN_ON(&dev_priv->drm, !IS_GEMINILAKE(dev_priv)); |
c4128ce7 | 314 | |
b281264f VS |
315 | ilk_update_pipe_csc(crtc, ilk_csc_off_zero, |
316 | ilk_csc_coeff_identity, | |
317 | ilk_csc_off_zero); | |
318 | } | |
8563b1e8 | 319 | |
3fd7c450 JN |
320 | intel_de_write(dev_priv, PIPE_CSC_MODE(crtc->pipe), |
321 | crtc_state->csc_mode); | |
f19d90ee VS |
322 | } |
323 | ||
324 | static void icl_load_csc_matrix(const struct intel_crtc_state *crtc_state) | |
325 | { | |
2225f3c6 | 326 | struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); |
f19d90ee VS |
327 | struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); |
328 | ||
1326a92c | 329 | if (crtc_state->hw.ctm) { |
f19d90ee VS |
330 | u16 coeff[9]; |
331 | ||
332 | ilk_csc_convert_ctm(crtc_state, coeff); | |
333 | ilk_update_pipe_csc(crtc, ilk_csc_off_zero, | |
334 | coeff, ilk_csc_off_zero); | |
335 | } | |
336 | ||
337 | if (crtc_state->output_format != INTEL_OUTPUT_FORMAT_RGB) { | |
338 | icl_update_output_csc(crtc, ilk_csc_off_zero, | |
339 | ilk_csc_coeff_rgb_to_ycbcr, | |
340 | ilk_csc_postoff_rgb_to_ycbcr); | |
341 | } else if (crtc_state->limited_color_range) { | |
342 | icl_update_output_csc(crtc, ilk_csc_off_zero, | |
343 | ilk_csc_coeff_limited_range, | |
344 | ilk_csc_postoff_limited_range); | |
345 | } | |
346 | ||
3fd7c450 JN |
347 | intel_de_write(dev_priv, PIPE_CSC_MODE(crtc->pipe), |
348 | crtc_state->csc_mode); | |
8563b1e8 LL |
349 | } |
350 | ||
d191832d VS |
351 | static void chv_load_cgm_csc(struct intel_crtc *crtc, |
352 | const struct drm_property_blob *blob) | |
29dc3739 | 353 | { |
23b03a27 | 354 | struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); |
d191832d | 355 | const struct drm_color_ctm *ctm = blob->data; |
23b03a27 | 356 | enum pipe pipe = crtc->pipe; |
d191832d VS |
357 | u16 coeffs[9]; |
358 | int i; | |
29dc3739 | 359 | |
d191832d VS |
360 | for (i = 0; i < ARRAY_SIZE(coeffs); i++) { |
361 | u64 abs_coeff = ((1ULL << 63) - 1) & ctm->matrix[i]; | |
29dc3739 | 362 | |
d191832d VS |
363 | /* Round coefficient. */ |
364 | abs_coeff += 1 << (32 - 13); | |
365 | /* Clamp to hardware limits. */ | |
366 | abs_coeff = clamp_val(abs_coeff, 0, CTM_COEFF_8_0 - 1); | |
367 | ||
368 | coeffs[i] = 0; | |
369 | ||
370 | /* Write coefficients in S3.12 format. */ | |
371 | if (ctm->matrix[i] & (1ULL << 63)) | |
372 | coeffs[i] |= 1 << 15; | |
373 | ||
374 | coeffs[i] |= ((abs_coeff >> 32) & 7) << 12; | |
375 | coeffs[i] |= (abs_coeff >> 20) & 0xfff; | |
29dc3739 LL |
376 | } |
377 | ||
d191832d VS |
378 | intel_de_write(dev_priv, CGM_PIPE_CSC_COEFF01(pipe), |
379 | coeffs[1] << 16 | coeffs[0]); | |
380 | intel_de_write(dev_priv, CGM_PIPE_CSC_COEFF23(pipe), | |
381 | coeffs[3] << 16 | coeffs[2]); | |
382 | intel_de_write(dev_priv, CGM_PIPE_CSC_COEFF45(pipe), | |
383 | coeffs[5] << 16 | coeffs[4]); | |
384 | intel_de_write(dev_priv, CGM_PIPE_CSC_COEFF67(pipe), | |
385 | coeffs[7] << 16 | coeffs[6]); | |
386 | intel_de_write(dev_priv, CGM_PIPE_CSC_COEFF8(pipe), | |
387 | coeffs[8]); | |
29dc3739 LL |
388 | } |
389 | ||
0ff3b23f VS |
390 | /* convert hw value with given bit_precision to lut property val */ |
391 | static u32 intel_color_lut_pack(u32 val, int bit_precision) | |
392 | { | |
393 | u32 max = 0xffff >> (16 - bit_precision); | |
394 | ||
395 | val = clamp_val(val, 0, max); | |
396 | ||
397 | if (bit_precision < 16) | |
398 | val <<= 16 - bit_precision; | |
399 | ||
400 | return val; | |
401 | } | |
402 | ||
70697e29 VS |
403 | static u32 i9xx_lut_8(const struct drm_color_lut *color) |
404 | { | |
405 | return drm_color_lut_extract(color->red, 8) << 16 | | |
406 | drm_color_lut_extract(color->green, 8) << 8 | | |
407 | drm_color_lut_extract(color->blue, 8); | |
408 | } | |
409 | ||
0ff3b23f VS |
410 | static void i9xx_lut_8_pack(struct drm_color_lut *entry, u32 val) |
411 | { | |
412 | entry->red = intel_color_lut_pack(REG_FIELD_GET(LGC_PALETTE_RED_MASK, val), 8); | |
413 | entry->green = intel_color_lut_pack(REG_FIELD_GET(LGC_PALETTE_GREEN_MASK, val), 8); | |
414 | entry->blue = intel_color_lut_pack(REG_FIELD_GET(LGC_PALETTE_BLUE_MASK, val), 8); | |
415 | } | |
416 | ||
e262568e VS |
417 | /* i965+ "10.6" bit interpolated format "even DW" (low 8 bits) */ |
418 | static u32 i965_lut_10p6_ldw(const struct drm_color_lut *color) | |
419 | { | |
420 | return (color->red & 0xff) << 16 | | |
421 | (color->green & 0xff) << 8 | | |
422 | (color->blue & 0xff); | |
423 | } | |
424 | ||
425 | /* i965+ "10.6" interpolated format "odd DW" (high 8 bits) */ | |
426 | static u32 i965_lut_10p6_udw(const struct drm_color_lut *color) | |
427 | { | |
428 | return (color->red >> 8) << 16 | | |
429 | (color->green >> 8) << 8 | | |
430 | (color->blue >> 8); | |
431 | } | |
432 | ||
0ff3b23f VS |
433 | static void i965_lut_10p6_pack(struct drm_color_lut *entry, u32 ldw, u32 udw) |
434 | { | |
435 | entry->red = REG_FIELD_GET(PALETTE_RED_MASK, udw) << 8 | | |
436 | REG_FIELD_GET(PALETTE_RED_MASK, ldw); | |
437 | entry->green = REG_FIELD_GET(PALETTE_GREEN_MASK, udw) << 8 | | |
438 | REG_FIELD_GET(PALETTE_GREEN_MASK, ldw); | |
439 | entry->blue = REG_FIELD_GET(PALETTE_BLUE_MASK, udw) << 8 | | |
440 | REG_FIELD_GET(PALETTE_BLUE_MASK, ldw); | |
441 | } | |
442 | ||
443 | static u16 i965_lut_11p6_max_pack(u32 val) | |
444 | { | |
62153bdd VS |
445 | /* PIPEGCMAX is 11.6, clamp to 10.6 */ |
446 | return clamp_val(val, 0, 0xffff); | |
0ff3b23f VS |
447 | } |
448 | ||
320d41b3 VS |
449 | static u32 ilk_lut_10(const struct drm_color_lut *color) |
450 | { | |
451 | return drm_color_lut_extract(color->red, 10) << 20 | | |
452 | drm_color_lut_extract(color->green, 10) << 10 | | |
453 | drm_color_lut_extract(color->blue, 10); | |
454 | } | |
455 | ||
0ff3b23f VS |
456 | static void ilk_lut_10_pack(struct drm_color_lut *entry, u32 val) |
457 | { | |
458 | entry->red = intel_color_lut_pack(REG_FIELD_GET(PREC_PALETTE_RED_MASK, val), 10); | |
459 | entry->green = intel_color_lut_pack(REG_FIELD_GET(PREC_PALETTE_GREEN_MASK, val), 10); | |
460 | entry->blue = intel_color_lut_pack(REG_FIELD_GET(PREC_PALETTE_BLUE_MASK, val), 10); | |
461 | } | |
462 | ||
b4ab7aa8 SS |
463 | static void icl_lut_multi_seg_pack(struct drm_color_lut *entry, u32 ldw, u32 udw) |
464 | { | |
465 | entry->red = REG_FIELD_GET(PAL_PREC_MULTI_SEG_RED_UDW_MASK, udw) << 6 | | |
466 | REG_FIELD_GET(PAL_PREC_MULTI_SEG_RED_LDW_MASK, ldw); | |
467 | entry->green = REG_FIELD_GET(PAL_PREC_MULTI_SEG_GREEN_UDW_MASK, udw) << 6 | | |
468 | REG_FIELD_GET(PAL_PREC_MULTI_SEG_GREEN_LDW_MASK, ldw); | |
469 | entry->blue = REG_FIELD_GET(PAL_PREC_MULTI_SEG_BLUE_UDW_MASK, udw) << 6 | | |
470 | REG_FIELD_GET(PAL_PREC_MULTI_SEG_BLUE_LDW_MASK, ldw); | |
471 | } | |
472 | ||
9d5441de VS |
473 | static void i9xx_color_commit(const struct intel_crtc_state *crtc_state) |
474 | { | |
2225f3c6 | 475 | struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); |
9d5441de VS |
476 | struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); |
477 | enum pipe pipe = crtc->pipe; | |
478 | u32 val; | |
479 | ||
3fd7c450 | 480 | val = intel_de_read(dev_priv, PIPECONF(pipe)); |
9d5441de VS |
481 | val &= ~PIPECONF_GAMMA_MODE_MASK_I9XX; |
482 | val |= PIPECONF_GAMMA_MODE(crtc_state->gamma_mode); | |
3fd7c450 | 483 | intel_de_write(dev_priv, PIPECONF(pipe), val); |
9d5441de VS |
484 | } |
485 | ||
486 | static void ilk_color_commit(const struct intel_crtc_state *crtc_state) | |
487 | { | |
2225f3c6 | 488 | struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); |
9d5441de VS |
489 | struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); |
490 | enum pipe pipe = crtc->pipe; | |
491 | u32 val; | |
492 | ||
3fd7c450 | 493 | val = intel_de_read(dev_priv, PIPECONF(pipe)); |
9d5441de VS |
494 | val &= ~PIPECONF_GAMMA_MODE_MASK_ILK; |
495 | val |= PIPECONF_GAMMA_MODE(crtc_state->gamma_mode); | |
3fd7c450 | 496 | intel_de_write(dev_priv, PIPECONF(pipe), val); |
c21ce2ef VS |
497 | |
498 | ilk_load_csc_matrix(crtc_state); | |
9d5441de VS |
499 | } |
500 | ||
4d8ed54c VS |
501 | static void hsw_color_commit(const struct intel_crtc_state *crtc_state) |
502 | { | |
2225f3c6 | 503 | struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); |
4d8ed54c VS |
504 | struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); |
505 | ||
3fd7c450 JN |
506 | intel_de_write(dev_priv, GAMMA_MODE(crtc->pipe), |
507 | crtc_state->gamma_mode); | |
4d8ed54c VS |
508 | |
509 | ilk_load_csc_matrix(crtc_state); | |
510 | } | |
511 | ||
5f29ab23 VS |
512 | static void skl_color_commit(const struct intel_crtc_state *crtc_state) |
513 | { | |
2225f3c6 | 514 | struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); |
5f29ab23 VS |
515 | struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); |
516 | enum pipe pipe = crtc->pipe; | |
517 | u32 val = 0; | |
518 | ||
519 | /* | |
520 | * We don't (yet) allow userspace to control the pipe background color, | |
521 | * so force it to black, but apply pipe gamma and CSC appropriately | |
522 | * so that its handling will match how we program our planes. | |
523 | */ | |
524 | if (crtc_state->gamma_enable) | |
525 | val |= SKL_BOTTOM_COLOR_GAMMA_ENABLE; | |
8271b2ef VS |
526 | if (crtc_state->csc_enable) |
527 | val |= SKL_BOTTOM_COLOR_CSC_ENABLE; | |
3fd7c450 | 528 | intel_de_write(dev_priv, SKL_BOTTOM_COLOR(pipe), val); |
5f29ab23 | 529 | |
3fd7c450 JN |
530 | intel_de_write(dev_priv, GAMMA_MODE(crtc->pipe), |
531 | crtc_state->gamma_mode); | |
5f29ab23 | 532 | |
005e9537 | 533 | if (DISPLAY_VER(dev_priv) >= 11) |
f19d90ee VS |
534 | icl_load_csc_matrix(crtc_state); |
535 | else | |
536 | ilk_load_csc_matrix(crtc_state); | |
5f29ab23 VS |
537 | } |
538 | ||
f0bb7c9f VS |
539 | static void i9xx_load_lut_8(struct intel_crtc *crtc, |
540 | const struct drm_property_blob *blob) | |
541 | { | |
542 | struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); | |
543 | const struct drm_color_lut *lut; | |
544 | enum pipe pipe = crtc->pipe; | |
545 | int i; | |
546 | ||
547 | if (!blob) | |
548 | return; | |
549 | ||
550 | lut = blob->data; | |
551 | ||
552 | for (i = 0; i < 256; i++) | |
e536bc93 VS |
553 | intel_de_write_fw(dev_priv, PALETTE(pipe, i), |
554 | i9xx_lut_8(&lut[i])); | |
f0bb7c9f VS |
555 | } |
556 | ||
557 | static void i9xx_load_luts(const struct intel_crtc_state *crtc_state) | |
558 | { | |
559 | struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); | |
560 | struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); | |
561 | const struct drm_property_blob *gamma_lut = crtc_state->hw.gamma_lut; | |
562 | ||
563 | assert_pll_enabled(dev_priv, crtc->pipe); | |
564 | ||
565 | i9xx_load_lut_8(crtc, gamma_lut); | |
566 | } | |
567 | ||
e262568e VS |
568 | static void i965_load_lut_10p6(struct intel_crtc *crtc, |
569 | const struct drm_property_blob *blob) | |
570 | { | |
571 | struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); | |
572 | const struct drm_color_lut *lut = blob->data; | |
573 | int i, lut_size = drm_color_lut_size(blob); | |
574 | enum pipe pipe = crtc->pipe; | |
575 | ||
576 | for (i = 0; i < lut_size - 1; i++) { | |
e536bc93 VS |
577 | intel_de_write_fw(dev_priv, PALETTE(pipe, 2 * i + 0), |
578 | i965_lut_10p6_ldw(&lut[i])); | |
579 | intel_de_write_fw(dev_priv, PALETTE(pipe, 2 * i + 1), | |
580 | i965_lut_10p6_udw(&lut[i])); | |
e262568e VS |
581 | } |
582 | ||
e536bc93 VS |
583 | intel_de_write_fw(dev_priv, PIPEGCMAX(pipe, 0), lut[i].red); |
584 | intel_de_write_fw(dev_priv, PIPEGCMAX(pipe, 1), lut[i].green); | |
585 | intel_de_write_fw(dev_priv, PIPEGCMAX(pipe, 2), lut[i].blue); | |
e262568e VS |
586 | } |
587 | ||
588 | static void i965_load_luts(const struct intel_crtc_state *crtc_state) | |
589 | { | |
2225f3c6 | 590 | struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); |
f0bb7c9f | 591 | struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); |
1326a92c | 592 | const struct drm_property_blob *gamma_lut = crtc_state->hw.gamma_lut; |
e262568e | 593 | |
f0bb7c9f VS |
594 | if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DSI)) |
595 | assert_dsi_pll_enabled(dev_priv); | |
596 | else | |
597 | assert_pll_enabled(dev_priv, crtc->pipe); | |
598 | ||
e262568e | 599 | if (crtc_state->gamma_mode == GAMMA_MODE_MODE_8BIT) |
f0bb7c9f | 600 | i9xx_load_lut_8(crtc, gamma_lut); |
e262568e VS |
601 | else |
602 | i965_load_lut_10p6(crtc, gamma_lut); | |
603 | } | |
604 | ||
f0bb7c9f VS |
605 | static void ilk_load_lut_8(struct intel_crtc *crtc, |
606 | const struct drm_property_blob *blob) | |
607 | { | |
608 | struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); | |
609 | const struct drm_color_lut *lut; | |
610 | enum pipe pipe = crtc->pipe; | |
611 | int i; | |
612 | ||
613 | if (!blob) | |
614 | return; | |
615 | ||
616 | lut = blob->data; | |
617 | ||
618 | for (i = 0; i < 256; i++) | |
e536bc93 VS |
619 | intel_de_write_fw(dev_priv, LGC_PALETTE(pipe, i), |
620 | i9xx_lut_8(&lut[i])); | |
f0bb7c9f VS |
621 | } |
622 | ||
514462ca VS |
623 | static void ilk_load_lut_10(struct intel_crtc *crtc, |
624 | const struct drm_property_blob *blob) | |
625 | { | |
626 | struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); | |
627 | const struct drm_color_lut *lut = blob->data; | |
628 | int i, lut_size = drm_color_lut_size(blob); | |
629 | enum pipe pipe = crtc->pipe; | |
630 | ||
631 | for (i = 0; i < lut_size; i++) | |
e536bc93 VS |
632 | intel_de_write_fw(dev_priv, PREC_PALETTE(pipe, i), |
633 | ilk_lut_10(&lut[i])); | |
514462ca VS |
634 | } |
635 | ||
636 | static void ilk_load_luts(const struct intel_crtc_state *crtc_state) | |
637 | { | |
2225f3c6 | 638 | struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); |
1326a92c | 639 | const struct drm_property_blob *gamma_lut = crtc_state->hw.gamma_lut; |
514462ca | 640 | |
7852ddd5 VS |
641 | switch (crtc_state->gamma_mode) { |
642 | case GAMMA_MODE_MODE_8BIT: | |
f0bb7c9f | 643 | ilk_load_lut_8(crtc, gamma_lut); |
7852ddd5 VS |
644 | break; |
645 | case GAMMA_MODE_MODE_10BIT: | |
514462ca | 646 | ilk_load_lut_10(crtc, gamma_lut); |
7852ddd5 VS |
647 | break; |
648 | default: | |
649 | MISSING_CASE(crtc_state->gamma_mode); | |
650 | break; | |
651 | } | |
514462ca VS |
652 | } |
653 | ||
795f672b VS |
654 | static int ivb_lut_10_size(u32 prec_index) |
655 | { | |
656 | if (prec_index & PAL_PREC_SPLIT_MODE) | |
657 | return 512; | |
658 | else | |
659 | return 1024; | |
660 | } | |
661 | ||
c21ce2ef VS |
662 | /* |
663 | * IVB/HSW Bspec / PAL_PREC_INDEX: | |
664 | * "Restriction : Index auto increment mode is not | |
665 | * supported and must not be enabled." | |
666 | */ | |
667 | static void ivb_load_lut_10(struct intel_crtc *crtc, | |
668 | const struct drm_property_blob *blob, | |
795f672b | 669 | u32 prec_index) |
c21ce2ef VS |
670 | { |
671 | struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); | |
795f672b | 672 | int hw_lut_size = ivb_lut_10_size(prec_index); |
c21ce2ef VS |
673 | const struct drm_color_lut *lut = blob->data; |
674 | int i, lut_size = drm_color_lut_size(blob); | |
675 | enum pipe pipe = crtc->pipe; | |
676 | ||
795f672b VS |
677 | for (i = 0; i < hw_lut_size; i++) { |
678 | /* We discard half the user entries in split gamma mode */ | |
679 | const struct drm_color_lut *entry = | |
680 | &lut[i * (lut_size - 1) / (hw_lut_size - 1)]; | |
681 | ||
e536bc93 VS |
682 | intel_de_write_fw(dev_priv, PREC_PAL_INDEX(pipe), prec_index++); |
683 | intel_de_write_fw(dev_priv, PREC_PAL_DATA(pipe), | |
684 | ilk_lut_10(entry)); | |
c21ce2ef VS |
685 | } |
686 | ||
687 | /* | |
688 | * Reset the index, otherwise it prevents the legacy palette to be | |
689 | * written properly. | |
690 | */ | |
e536bc93 | 691 | intel_de_write_fw(dev_priv, PREC_PAL_INDEX(pipe), 0); |
c21ce2ef VS |
692 | } |
693 | ||
694 | /* On BDW+ the index auto increment mode actually works */ | |
5bda1aca VS |
695 | static void bdw_load_lut_10(struct intel_crtc *crtc, |
696 | const struct drm_property_blob *blob, | |
795f672b | 697 | u32 prec_index) |
82cf435b | 698 | { |
23b03a27 | 699 | struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); |
795f672b | 700 | int hw_lut_size = ivb_lut_10_size(prec_index); |
5bda1aca VS |
701 | const struct drm_color_lut *lut = blob->data; |
702 | int i, lut_size = drm_color_lut_size(blob); | |
23b03a27 | 703 | enum pipe pipe = crtc->pipe; |
82cf435b | 704 | |
e536bc93 VS |
705 | intel_de_write_fw(dev_priv, PREC_PAL_INDEX(pipe), |
706 | prec_index | PAL_PREC_AUTO_INCREMENT); | |
82cf435b | 707 | |
795f672b VS |
708 | for (i = 0; i < hw_lut_size; i++) { |
709 | /* We discard half the user entries in split gamma mode */ | |
710 | const struct drm_color_lut *entry = | |
711 | &lut[i * (lut_size - 1) / (hw_lut_size - 1)]; | |
712 | ||
e536bc93 VS |
713 | intel_de_write_fw(dev_priv, PREC_PAL_DATA(pipe), |
714 | ilk_lut_10(entry)); | |
82cf435b | 715 | } |
5bda1aca VS |
716 | |
717 | /* | |
718 | * Reset the index, otherwise it prevents the legacy palette to be | |
719 | * written properly. | |
720 | */ | |
e536bc93 | 721 | intel_de_write_fw(dev_priv, PREC_PAL_INDEX(pipe), 0); |
2fcb2066 ACO |
722 | } |
723 | ||
afeda4f3 | 724 | static void ivb_load_lut_ext_max(const struct intel_crtc_state *crtc_state) |
2fcb2066 | 725 | { |
afeda4f3 | 726 | struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); |
23b03a27 | 727 | struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); |
23b03a27 | 728 | enum pipe pipe = crtc->pipe; |
2fcb2066 | 729 | |
5bda1aca | 730 | /* Program the max register to clamp values > 1.0. */ |
afeda4f3 AM |
731 | intel_dsb_reg_write(crtc_state, PREC_PAL_EXT_GC_MAX(pipe, 0), 1 << 16); |
732 | intel_dsb_reg_write(crtc_state, PREC_PAL_EXT_GC_MAX(pipe, 1), 1 << 16); | |
733 | intel_dsb_reg_write(crtc_state, PREC_PAL_EXT_GC_MAX(pipe, 2), 1 << 16); | |
8957129c US |
734 | |
735 | /* | |
5bda1aca VS |
736 | * Program the gc max 2 register to clamp values > 1.0. |
737 | * ToDo: Extend the ABI to be able to program values | |
738 | * from 3.0 to 7.0 | |
8957129c | 739 | */ |
2b5a4562 | 740 | if (DISPLAY_VER(dev_priv) >= 10) { |
afeda4f3 | 741 | intel_dsb_reg_write(crtc_state, PREC_PAL_EXT2_GC_MAX(pipe, 0), |
49e3fb7f | 742 | 1 << 16); |
afeda4f3 | 743 | intel_dsb_reg_write(crtc_state, PREC_PAL_EXT2_GC_MAX(pipe, 1), |
49e3fb7f | 744 | 1 << 16); |
afeda4f3 | 745 | intel_dsb_reg_write(crtc_state, PREC_PAL_EXT2_GC_MAX(pipe, 2), |
49e3fb7f | 746 | 1 << 16); |
5bda1aca | 747 | } |
2fcb2066 ACO |
748 | } |
749 | ||
c21ce2ef VS |
750 | static void ivb_load_luts(const struct intel_crtc_state *crtc_state) |
751 | { | |
2225f3c6 | 752 | struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); |
1326a92c ML |
753 | const struct drm_property_blob *gamma_lut = crtc_state->hw.gamma_lut; |
754 | const struct drm_property_blob *degamma_lut = crtc_state->hw.degamma_lut; | |
7852ddd5 | 755 | const struct drm_property_blob *blob = gamma_lut ?: degamma_lut; |
c21ce2ef | 756 | |
7852ddd5 VS |
757 | switch (crtc_state->gamma_mode) { |
758 | case GAMMA_MODE_MODE_8BIT: | |
759 | ilk_load_lut_8(crtc, blob); | |
760 | break; | |
761 | case GAMMA_MODE_MODE_SPLIT: | |
c21ce2ef | 762 | ivb_load_lut_10(crtc, degamma_lut, PAL_PREC_SPLIT_MODE | |
795f672b | 763 | PAL_PREC_INDEX_VALUE(0)); |
afeda4f3 | 764 | ivb_load_lut_ext_max(crtc_state); |
c21ce2ef | 765 | ivb_load_lut_10(crtc, gamma_lut, PAL_PREC_SPLIT_MODE | |
795f672b | 766 | PAL_PREC_INDEX_VALUE(512)); |
7852ddd5 VS |
767 | break; |
768 | case GAMMA_MODE_MODE_10BIT: | |
c21ce2ef | 769 | ivb_load_lut_10(crtc, blob, |
795f672b | 770 | PAL_PREC_INDEX_VALUE(0)); |
afeda4f3 | 771 | ivb_load_lut_ext_max(crtc_state); |
7852ddd5 VS |
772 | break; |
773 | default: | |
774 | MISSING_CASE(crtc_state->gamma_mode); | |
775 | break; | |
c21ce2ef VS |
776 | } |
777 | } | |
778 | ||
5bda1aca | 779 | static void bdw_load_luts(const struct intel_crtc_state *crtc_state) |
2fcb2066 | 780 | { |
2225f3c6 | 781 | struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); |
1326a92c ML |
782 | const struct drm_property_blob *gamma_lut = crtc_state->hw.gamma_lut; |
783 | const struct drm_property_blob *degamma_lut = crtc_state->hw.degamma_lut; | |
7852ddd5 | 784 | const struct drm_property_blob *blob = gamma_lut ?: degamma_lut; |
2fcb2066 | 785 | |
7852ddd5 VS |
786 | switch (crtc_state->gamma_mode) { |
787 | case GAMMA_MODE_MODE_8BIT: | |
788 | ilk_load_lut_8(crtc, blob); | |
789 | break; | |
790 | case GAMMA_MODE_MODE_SPLIT: | |
5bda1aca | 791 | bdw_load_lut_10(crtc, degamma_lut, PAL_PREC_SPLIT_MODE | |
795f672b | 792 | PAL_PREC_INDEX_VALUE(0)); |
afeda4f3 | 793 | ivb_load_lut_ext_max(crtc_state); |
5bda1aca | 794 | bdw_load_lut_10(crtc, gamma_lut, PAL_PREC_SPLIT_MODE | |
795f672b | 795 | PAL_PREC_INDEX_VALUE(512)); |
7852ddd5 VS |
796 | break; |
797 | case GAMMA_MODE_MODE_10BIT: | |
5bda1aca VS |
798 | |
799 | bdw_load_lut_10(crtc, blob, | |
795f672b | 800 | PAL_PREC_INDEX_VALUE(0)); |
afeda4f3 | 801 | ivb_load_lut_ext_max(crtc_state); |
7852ddd5 VS |
802 | break; |
803 | default: | |
804 | MISSING_CASE(crtc_state->gamma_mode); | |
805 | break; | |
87cefd57 | 806 | } |
82cf435b LL |
807 | } |
808 | ||
9be7a7ff US |
809 | static int glk_degamma_lut_size(struct drm_i915_private *i915) |
810 | { | |
811 | if (DISPLAY_VER(i915) >= 13) | |
812 | return 131; | |
813 | else | |
814 | return 35; | |
815 | } | |
816 | ||
23b03a27 | 817 | static void glk_load_degamma_lut(const struct intel_crtc_state *crtc_state) |
9751bafc | 818 | { |
2225f3c6 | 819 | struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); |
23b03a27 VS |
820 | struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); |
821 | enum pipe pipe = crtc->pipe; | |
73ce0969 | 822 | int i, lut_size = INTEL_INFO(dev_priv)->color.degamma_lut_size; |
1326a92c | 823 | const struct drm_color_lut *lut = crtc_state->hw.degamma_lut->data; |
9751bafc ACO |
824 | |
825 | /* | |
826 | * When setting the auto-increment bit, the hardware seems to | |
827 | * ignore the index bits, so we need to reset it to index 0 | |
828 | * separately. | |
829 | */ | |
e536bc93 VS |
830 | intel_de_write_fw(dev_priv, PRE_CSC_GAMC_INDEX(pipe), 0); |
831 | intel_de_write_fw(dev_priv, PRE_CSC_GAMC_INDEX(pipe), | |
832 | PRE_CSC_GAMC_AUTO_INCREMENT); | |
9751bafc | 833 | |
c4128ce7 VS |
834 | for (i = 0; i < lut_size; i++) { |
835 | /* | |
9be7a7ff US |
836 | * First lut_size entries represent range from 0 to 1.0 |
837 | * 3 additional lut entries will represent extended range | |
c4128ce7 VS |
838 | * inputs 3.0 and 7.0 respectively, currently clamped |
839 | * at 1.0. Since the precision is 16bit, the user | |
840 | * value can be directly filled to register. | |
841 | * The pipe degamma table in GLK+ onwards doesn't | |
842 | * support different values per channel, so this just | |
843 | * programs green value which will be equal to Red and | |
844 | * Blue into the lut registers. | |
845 | * ToDo: Extend to max 7.0. Enable 32 bit input value | |
846 | * as compared to just 16 to achieve this. | |
847 | */ | |
e536bc93 VS |
848 | intel_de_write_fw(dev_priv, PRE_CSC_GAMC_DATA(pipe), |
849 | lut[i].green); | |
c4128ce7 | 850 | } |
9751bafc | 851 | |
c4128ce7 | 852 | /* Clamp values > 1.0. */ |
9be7a7ff | 853 | while (i++ < glk_degamma_lut_size(dev_priv)) |
e536bc93 | 854 | intel_de_write_fw(dev_priv, PRE_CSC_GAMC_DATA(pipe), 1 << 16); |
4073a4ee | 855 | |
e536bc93 | 856 | intel_de_write_fw(dev_priv, PRE_CSC_GAMC_INDEX(pipe), 0); |
c4128ce7 | 857 | } |
8957129c | 858 | |
c4128ce7 VS |
859 | static void glk_load_degamma_lut_linear(const struct intel_crtc_state *crtc_state) |
860 | { | |
2225f3c6 | 861 | struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); |
c4128ce7 VS |
862 | struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); |
863 | enum pipe pipe = crtc->pipe; | |
73ce0969 | 864 | int i, lut_size = INTEL_INFO(dev_priv)->color.degamma_lut_size; |
c4128ce7 VS |
865 | |
866 | /* | |
867 | * When setting the auto-increment bit, the hardware seems to | |
868 | * ignore the index bits, so we need to reset it to index 0 | |
869 | * separately. | |
870 | */ | |
e536bc93 VS |
871 | intel_de_write_fw(dev_priv, PRE_CSC_GAMC_INDEX(pipe), 0); |
872 | intel_de_write_fw(dev_priv, PRE_CSC_GAMC_INDEX(pipe), | |
873 | PRE_CSC_GAMC_AUTO_INCREMENT); | |
c4128ce7 VS |
874 | |
875 | for (i = 0; i < lut_size; i++) { | |
876 | u32 v = (i << 16) / (lut_size - 1); | |
877 | ||
e536bc93 | 878 | intel_de_write_fw(dev_priv, PRE_CSC_GAMC_DATA(pipe), v); |
9751bafc ACO |
879 | } |
880 | ||
881 | /* Clamp values > 1.0. */ | |
882 | while (i++ < 35) | |
e536bc93 | 883 | intel_de_write_fw(dev_priv, PRE_CSC_GAMC_DATA(pipe), 1 << 16); |
4073a4ee | 884 | |
e536bc93 | 885 | intel_de_write_fw(dev_priv, PRE_CSC_GAMC_INDEX(pipe), 0); |
9751bafc ACO |
886 | } |
887 | ||
23b03a27 | 888 | static void glk_load_luts(const struct intel_crtc_state *crtc_state) |
9751bafc | 889 | { |
1326a92c | 890 | const struct drm_property_blob *gamma_lut = crtc_state->hw.gamma_lut; |
2225f3c6 | 891 | struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); |
5bda1aca | 892 | |
c4128ce7 VS |
893 | /* |
894 | * On GLK+ both pipe CSC and degamma LUT are controlled | |
895 | * by csc_enable. Hence for the cases where the CSC is | |
896 | * needed but degamma LUT is not we need to load a | |
897 | * linear degamma LUT. In fact we'll just always load | |
898 | * the degama LUT so that we don't have to reload | |
899 | * it every time the pipe CSC is being enabled. | |
900 | */ | |
1326a92c | 901 | if (crtc_state->hw.degamma_lut) |
c4128ce7 VS |
902 | glk_load_degamma_lut(crtc_state); |
903 | else | |
904 | glk_load_degamma_lut_linear(crtc_state); | |
8d371db4 | 905 | |
7852ddd5 VS |
906 | switch (crtc_state->gamma_mode) { |
907 | case GAMMA_MODE_MODE_8BIT: | |
f0bb7c9f | 908 | ilk_load_lut_8(crtc, gamma_lut); |
7852ddd5 VS |
909 | break; |
910 | case GAMMA_MODE_MODE_10BIT: | |
795f672b | 911 | bdw_load_lut_10(crtc, gamma_lut, PAL_PREC_INDEX_VALUE(0)); |
afeda4f3 | 912 | ivb_load_lut_ext_max(crtc_state); |
7852ddd5 VS |
913 | break; |
914 | default: | |
915 | MISSING_CASE(crtc_state->gamma_mode); | |
916 | break; | |
5bda1aca | 917 | } |
9751bafc ACO |
918 | } |
919 | ||
02ae8ba9 SS |
920 | /* ilk+ "12.4" interpolated format (high 10 bits) */ |
921 | static u32 ilk_lut_12p4_udw(const struct drm_color_lut *color) | |
922 | { | |
923 | return (color->red >> 6) << 20 | (color->green >> 6) << 10 | | |
924 | (color->blue >> 6); | |
925 | } | |
926 | ||
927 | /* ilk+ "12.4" interpolated format (low 6 bits) */ | |
928 | static u32 ilk_lut_12p4_ldw(const struct drm_color_lut *color) | |
929 | { | |
930 | return (color->red & 0x3f) << 24 | (color->green & 0x3f) << 14 | | |
931 | (color->blue & 0x3f) << 4; | |
932 | } | |
933 | ||
934 | static void | |
935 | icl_load_gcmax(const struct intel_crtc_state *crtc_state, | |
936 | const struct drm_color_lut *color) | |
937 | { | |
2225f3c6 | 938 | struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); |
02ae8ba9 SS |
939 | enum pipe pipe = crtc->pipe; |
940 | ||
b4ab7aa8 | 941 | /* FIXME LUT entries are 16 bit only, so we can prog 0xFFFF max */ |
afeda4f3 AM |
942 | intel_dsb_reg_write(crtc_state, PREC_PAL_GC_MAX(pipe, 0), color->red); |
943 | intel_dsb_reg_write(crtc_state, PREC_PAL_GC_MAX(pipe, 1), color->green); | |
944 | intel_dsb_reg_write(crtc_state, PREC_PAL_GC_MAX(pipe, 2), color->blue); | |
02ae8ba9 SS |
945 | } |
946 | ||
947 | static void | |
948 | icl_program_gamma_superfine_segment(const struct intel_crtc_state *crtc_state) | |
949 | { | |
2225f3c6 | 950 | struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); |
1326a92c | 951 | const struct drm_property_blob *blob = crtc_state->hw.gamma_lut; |
02ae8ba9 SS |
952 | const struct drm_color_lut *lut = blob->data; |
953 | enum pipe pipe = crtc->pipe; | |
73ce0969 | 954 | int i; |
02ae8ba9 SS |
955 | |
956 | /* | |
bf93b724 | 957 | * Program Super Fine segment (let's call it seg1)... |
02ae8ba9 | 958 | * |
bf93b724 SS |
959 | * Super Fine segment's step is 1/(8 * 128 * 256) and it has |
960 | * 9 entries, corresponding to values 0, 1/(8 * 128 * 256), | |
961 | * 2/(8 * 128 * 256) ... 8/(8 * 128 * 256). | |
02ae8ba9 | 962 | */ |
afeda4f3 | 963 | intel_dsb_reg_write(crtc_state, PREC_PAL_MULTI_SEG_INDEX(pipe), |
49e3fb7f | 964 | PAL_PREC_AUTO_INCREMENT); |
02ae8ba9 SS |
965 | |
966 | for (i = 0; i < 9; i++) { | |
967 | const struct drm_color_lut *entry = &lut[i]; | |
968 | ||
afeda4f3 | 969 | intel_dsb_indexed_reg_write(crtc_state, PREC_PAL_MULTI_SEG_DATA(pipe), |
49e3fb7f | 970 | ilk_lut_12p4_ldw(entry)); |
afeda4f3 | 971 | intel_dsb_indexed_reg_write(crtc_state, PREC_PAL_MULTI_SEG_DATA(pipe), |
49e3fb7f | 972 | ilk_lut_12p4_udw(entry)); |
02ae8ba9 SS |
973 | } |
974 | } | |
975 | ||
976 | static void | |
977 | icl_program_gamma_multi_segment(const struct intel_crtc_state *crtc_state) | |
978 | { | |
2225f3c6 | 979 | struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); |
1326a92c | 980 | const struct drm_property_blob *blob = crtc_state->hw.gamma_lut; |
02ae8ba9 SS |
981 | const struct drm_color_lut *lut = blob->data; |
982 | const struct drm_color_lut *entry; | |
983 | enum pipe pipe = crtc->pipe; | |
73ce0969 | 984 | int i; |
02ae8ba9 SS |
985 | |
986 | /* | |
02ae8ba9 SS |
987 | * Program Fine segment (let's call it seg2)... |
988 | * | |
bf93b724 SS |
989 | * Fine segment's step is 1/(128 * 256) i.e. 1/(128 * 256), 2/(128 * 256) |
990 | * ... 256/(128 * 256). So in order to program fine segment of LUT we | |
991 | * need to pick every 8th entry in the LUT, and program 256 indexes. | |
02ae8ba9 SS |
992 | * |
993 | * PAL_PREC_INDEX[0] and PAL_PREC_INDEX[1] map to seg2[1], | |
bf93b724 | 994 | * seg2[0] being unused by the hardware. |
02ae8ba9 | 995 | */ |
afeda4f3 AM |
996 | intel_dsb_reg_write(crtc_state, PREC_PAL_INDEX(pipe), |
997 | PAL_PREC_AUTO_INCREMENT); | |
02ae8ba9 SS |
998 | for (i = 1; i < 257; i++) { |
999 | entry = &lut[i * 8]; | |
afeda4f3 | 1000 | intel_dsb_indexed_reg_write(crtc_state, PREC_PAL_DATA(pipe), |
49e3fb7f | 1001 | ilk_lut_12p4_ldw(entry)); |
afeda4f3 | 1002 | intel_dsb_indexed_reg_write(crtc_state, PREC_PAL_DATA(pipe), |
49e3fb7f | 1003 | ilk_lut_12p4_udw(entry)); |
02ae8ba9 SS |
1004 | } |
1005 | ||
1006 | /* | |
1007 | * Program Coarse segment (let's call it seg3)... | |
1008 | * | |
bf93b724 SS |
1009 | * Coarse segment starts from index 0 and it's step is 1/256 ie 0, |
1010 | * 1/256, 2/256 ... 256/256. As per the description of each entry in LUT | |
02ae8ba9 SS |
1011 | * above, we need to pick every (8 * 128)th entry in LUT, and |
1012 | * program 256 of those. | |
1013 | * | |
1014 | * Spec is not very clear about if entries seg3[0] and seg3[1] are | |
1015 | * being used or not, but we still need to program these to advance | |
1016 | * the index. | |
1017 | */ | |
1018 | for (i = 0; i < 256; i++) { | |
1019 | entry = &lut[i * 8 * 128]; | |
afeda4f3 | 1020 | intel_dsb_indexed_reg_write(crtc_state, PREC_PAL_DATA(pipe), |
49e3fb7f | 1021 | ilk_lut_12p4_ldw(entry)); |
afeda4f3 | 1022 | intel_dsb_indexed_reg_write(crtc_state, PREC_PAL_DATA(pipe), |
49e3fb7f | 1023 | ilk_lut_12p4_udw(entry)); |
02ae8ba9 SS |
1024 | } |
1025 | ||
1026 | /* The last entry in the LUT is to be programmed in GCMAX */ | |
1027 | entry = &lut[256 * 8 * 128]; | |
1028 | icl_load_gcmax(crtc_state, entry); | |
afeda4f3 | 1029 | ivb_load_lut_ext_max(crtc_state); |
02ae8ba9 SS |
1030 | } |
1031 | ||
13717cef US |
1032 | static void icl_load_luts(const struct intel_crtc_state *crtc_state) |
1033 | { | |
1326a92c | 1034 | const struct drm_property_blob *gamma_lut = crtc_state->hw.gamma_lut; |
2225f3c6 | 1035 | struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); |
5bda1aca | 1036 | |
1326a92c | 1037 | if (crtc_state->hw.degamma_lut) |
c4128ce7 | 1038 | glk_load_degamma_lut(crtc_state); |
13717cef | 1039 | |
02ae8ba9 SS |
1040 | switch (crtc_state->gamma_mode & GAMMA_MODE_MODE_MASK) { |
1041 | case GAMMA_MODE_MODE_8BIT: | |
f0bb7c9f | 1042 | ilk_load_lut_8(crtc, gamma_lut); |
02ae8ba9 | 1043 | break; |
02ae8ba9 SS |
1044 | case GAMMA_MODE_MODE_12BIT_MULTI_SEGMENTED: |
1045 | icl_program_gamma_superfine_segment(crtc_state); | |
1046 | icl_program_gamma_multi_segment(crtc_state); | |
1047 | break; | |
7852ddd5 | 1048 | case GAMMA_MODE_MODE_10BIT: |
795f672b | 1049 | bdw_load_lut_10(crtc, gamma_lut, PAL_PREC_INDEX_VALUE(0)); |
afeda4f3 | 1050 | ivb_load_lut_ext_max(crtc_state); |
7852ddd5 VS |
1051 | break; |
1052 | default: | |
1053 | MISSING_CASE(crtc_state->gamma_mode); | |
1054 | break; | |
5bda1aca | 1055 | } |
49e3fb7f | 1056 | |
afeda4f3 | 1057 | intel_dsb_commit(crtc_state); |
13717cef US |
1058 | } |
1059 | ||
f61a8f36 VS |
1060 | static u32 chv_cgm_degamma_ldw(const struct drm_color_lut *color) |
1061 | { | |
1062 | return drm_color_lut_extract(color->green, 14) << 16 | | |
1063 | drm_color_lut_extract(color->blue, 14); | |
1064 | } | |
1065 | ||
1066 | static u32 chv_cgm_degamma_udw(const struct drm_color_lut *color) | |
1067 | { | |
1068 | return drm_color_lut_extract(color->red, 14); | |
1069 | } | |
1070 | ||
1071 | static void chv_load_cgm_degamma(struct intel_crtc *crtc, | |
1072 | const struct drm_property_blob *blob) | |
29dc3739 | 1073 | { |
23b03a27 | 1074 | struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); |
f61a8f36 VS |
1075 | const struct drm_color_lut *lut = blob->data; |
1076 | int i, lut_size = drm_color_lut_size(blob); | |
23b03a27 | 1077 | enum pipe pipe = crtc->pipe; |
29dc3739 | 1078 | |
f61a8f36 | 1079 | for (i = 0; i < lut_size; i++) { |
e536bc93 VS |
1080 | intel_de_write_fw(dev_priv, CGM_PIPE_DEGAMMA(pipe, i, 0), |
1081 | chv_cgm_degamma_ldw(&lut[i])); | |
1082 | intel_de_write_fw(dev_priv, CGM_PIPE_DEGAMMA(pipe, i, 1), | |
1083 | chv_cgm_degamma_udw(&lut[i])); | |
29dc3739 | 1084 | } |
f61a8f36 | 1085 | } |
29dc3739 | 1086 | |
f61a8f36 VS |
1087 | static u32 chv_cgm_gamma_ldw(const struct drm_color_lut *color) |
1088 | { | |
1089 | return drm_color_lut_extract(color->green, 10) << 16 | | |
1090 | drm_color_lut_extract(color->blue, 10); | |
1091 | } | |
23b03a27 | 1092 | |
f61a8f36 VS |
1093 | static u32 chv_cgm_gamma_udw(const struct drm_color_lut *color) |
1094 | { | |
1095 | return drm_color_lut_extract(color->red, 10); | |
1096 | } | |
23b03a27 | 1097 | |
d3135691 VS |
1098 | static void chv_cgm_gamma_pack(struct drm_color_lut *entry, u32 ldw, u32 udw) |
1099 | { | |
1100 | entry->green = intel_color_lut_pack(REG_FIELD_GET(CGM_PIPE_GAMMA_GREEN_MASK, ldw), 10); | |
1101 | entry->blue = intel_color_lut_pack(REG_FIELD_GET(CGM_PIPE_GAMMA_BLUE_MASK, ldw), 10); | |
1102 | entry->red = intel_color_lut_pack(REG_FIELD_GET(CGM_PIPE_GAMMA_RED_MASK, udw), 10); | |
1103 | } | |
1104 | ||
f61a8f36 VS |
1105 | static void chv_load_cgm_gamma(struct intel_crtc *crtc, |
1106 | const struct drm_property_blob *blob) | |
1107 | { | |
1108 | struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); | |
1109 | const struct drm_color_lut *lut = blob->data; | |
1110 | int i, lut_size = drm_color_lut_size(blob); | |
1111 | enum pipe pipe = crtc->pipe; | |
29dc3739 | 1112 | |
f61a8f36 | 1113 | for (i = 0; i < lut_size; i++) { |
e536bc93 VS |
1114 | intel_de_write_fw(dev_priv, CGM_PIPE_GAMMA(pipe, i, 0), |
1115 | chv_cgm_gamma_ldw(&lut[i])); | |
1116 | intel_de_write_fw(dev_priv, CGM_PIPE_GAMMA(pipe, i, 1), | |
1117 | chv_cgm_gamma_udw(&lut[i])); | |
29dc3739 | 1118 | } |
f61a8f36 | 1119 | } |
29dc3739 | 1120 | |
f61a8f36 VS |
1121 | static void chv_load_luts(const struct intel_crtc_state *crtc_state) |
1122 | { | |
2225f3c6 | 1123 | struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); |
d191832d | 1124 | struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); |
1326a92c | 1125 | const struct drm_property_blob *degamma_lut = crtc_state->hw.degamma_lut; |
d191832d VS |
1126 | const struct drm_property_blob *gamma_lut = crtc_state->hw.gamma_lut; |
1127 | const struct drm_property_blob *ctm = crtc_state->hw.ctm; | |
23b03a27 | 1128 | |
d191832d VS |
1129 | if (crtc_state->cgm_mode & CGM_PIPE_MODE_CSC) |
1130 | chv_load_cgm_csc(crtc, ctm); | |
29dc3739 | 1131 | |
3faf8b85 | 1132 | if (crtc_state->cgm_mode & CGM_PIPE_MODE_DEGAMMA) |
f61a8f36 VS |
1133 | chv_load_cgm_degamma(crtc, degamma_lut); |
1134 | ||
3faf8b85 | 1135 | if (crtc_state->cgm_mode & CGM_PIPE_MODE_GAMMA) |
f61a8f36 | 1136 | chv_load_cgm_gamma(crtc, gamma_lut); |
3faf8b85 VS |
1137 | else |
1138 | i965_load_luts(crtc_state); | |
d191832d | 1139 | |
e536bc93 VS |
1140 | intel_de_write_fw(dev_priv, CGM_PIPE_MODE(crtc->pipe), |
1141 | crtc_state->cgm_mode); | |
29dc3739 LL |
1142 | } |
1143 | ||
23b03a27 | 1144 | void intel_color_load_luts(const struct intel_crtc_state *crtc_state) |
8563b1e8 | 1145 | { |
2225f3c6 | 1146 | struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev); |
8563b1e8 | 1147 | |
b95c5321 | 1148 | dev_priv->display.load_luts(crtc_state); |
8563b1e8 LL |
1149 | } |
1150 | ||
4d8ed54c VS |
1151 | void intel_color_commit(const struct intel_crtc_state *crtc_state) |
1152 | { | |
2225f3c6 | 1153 | struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev); |
4d8ed54c | 1154 | |
9d5441de | 1155 | dev_priv->display.color_commit(crtc_state); |
4d8ed54c VS |
1156 | } |
1157 | ||
0ccc42a2 VS |
1158 | static bool intel_can_preload_luts(const struct intel_crtc_state *new_crtc_state) |
1159 | { | |
1160 | struct intel_crtc *crtc = to_intel_crtc(new_crtc_state->uapi.crtc); | |
1161 | struct intel_atomic_state *state = | |
1162 | to_intel_atomic_state(new_crtc_state->uapi.state); | |
1163 | const struct intel_crtc_state *old_crtc_state = | |
1164 | intel_atomic_get_old_crtc_state(state, crtc); | |
1165 | ||
1166 | return !old_crtc_state->hw.gamma_lut && | |
1167 | !old_crtc_state->hw.degamma_lut; | |
1168 | } | |
1169 | ||
1170 | static bool chv_can_preload_luts(const struct intel_crtc_state *new_crtc_state) | |
1171 | { | |
1172 | struct intel_crtc *crtc = to_intel_crtc(new_crtc_state->uapi.crtc); | |
1173 | struct intel_atomic_state *state = | |
1174 | to_intel_atomic_state(new_crtc_state->uapi.state); | |
1175 | const struct intel_crtc_state *old_crtc_state = | |
1176 | intel_atomic_get_old_crtc_state(state, crtc); | |
1177 | ||
1178 | /* | |
1179 | * CGM_PIPE_MODE is itself single buffered. We'd have to | |
1180 | * somehow split it out from chv_load_luts() if we wanted | |
1181 | * the ability to preload the CGM LUTs/CSC without tearing. | |
1182 | */ | |
1183 | if (old_crtc_state->cgm_mode || new_crtc_state->cgm_mode) | |
1184 | return false; | |
1185 | ||
1186 | return !old_crtc_state->hw.gamma_lut; | |
1187 | } | |
1188 | ||
1189 | static bool glk_can_preload_luts(const struct intel_crtc_state *new_crtc_state) | |
1190 | { | |
1191 | struct intel_crtc *crtc = to_intel_crtc(new_crtc_state->uapi.crtc); | |
1192 | struct intel_atomic_state *state = | |
1193 | to_intel_atomic_state(new_crtc_state->uapi.state); | |
1194 | const struct intel_crtc_state *old_crtc_state = | |
1195 | intel_atomic_get_old_crtc_state(state, crtc); | |
1196 | ||
1197 | /* | |
1198 | * The hardware degamma is active whenever the pipe | |
1199 | * CSC is active. Thus even if the old state has no | |
1200 | * software degamma we need to avoid clobbering the | |
1201 | * linear hardware degamma mid scanout. | |
1202 | */ | |
1203 | return !old_crtc_state->csc_enable && | |
1204 | !old_crtc_state->hw.gamma_lut; | |
1205 | } | |
1206 | ||
9d9cb9c1 VS |
1207 | int intel_color_check(struct intel_crtc_state *crtc_state) |
1208 | { | |
2225f3c6 | 1209 | struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev); |
9d9cb9c1 VS |
1210 | |
1211 | return dev_priv->display.color_check(crtc_state); | |
1212 | } | |
1213 | ||
2740e81a SS |
1214 | void intel_color_get_config(struct intel_crtc_state *crtc_state) |
1215 | { | |
2225f3c6 | 1216 | struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev); |
2740e81a SS |
1217 | |
1218 | if (dev_priv->display.read_luts) | |
1219 | dev_priv->display.read_luts(crtc_state); | |
1220 | } | |
1221 | ||
0fc3f8e7 VS |
1222 | static bool need_plane_update(struct intel_plane *plane, |
1223 | const struct intel_crtc_state *crtc_state) | |
1224 | { | |
1225 | struct drm_i915_private *dev_priv = to_i915(plane->base.dev); | |
1226 | ||
1227 | /* | |
1228 | * On pre-SKL the pipe gamma enable and pipe csc enable for | |
1229 | * the pipe bottom color are configured via the primary plane. | |
1230 | * We have to reconfigure that even if the plane is inactive. | |
1231 | */ | |
1232 | return crtc_state->active_planes & BIT(plane->id) || | |
005e9537 | 1233 | (DISPLAY_VER(dev_priv) < 9 && |
0fc3f8e7 VS |
1234 | plane->id == PLANE_PRIMARY); |
1235 | } | |
1236 | ||
1237 | static int | |
1238 | intel_color_add_affected_planes(struct intel_crtc_state *new_crtc_state) | |
1239 | { | |
2225f3c6 | 1240 | struct intel_crtc *crtc = to_intel_crtc(new_crtc_state->uapi.crtc); |
0fc3f8e7 VS |
1241 | struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); |
1242 | struct intel_atomic_state *state = | |
2225f3c6 | 1243 | to_intel_atomic_state(new_crtc_state->uapi.state); |
0fc3f8e7 VS |
1244 | const struct intel_crtc_state *old_crtc_state = |
1245 | intel_atomic_get_old_crtc_state(state, crtc); | |
1246 | struct intel_plane *plane; | |
1247 | ||
1326a92c | 1248 | if (!new_crtc_state->hw.active || |
2225f3c6 | 1249 | drm_atomic_crtc_needs_modeset(&new_crtc_state->uapi)) |
73a116be VS |
1250 | return 0; |
1251 | ||
0593d2cd VS |
1252 | if (new_crtc_state->gamma_enable == old_crtc_state->gamma_enable && |
1253 | new_crtc_state->csc_enable == old_crtc_state->csc_enable) | |
0fc3f8e7 VS |
1254 | return 0; |
1255 | ||
1256 | for_each_intel_plane_on_crtc(&dev_priv->drm, crtc, plane) { | |
1257 | struct intel_plane_state *plane_state; | |
1258 | ||
1259 | if (!need_plane_update(plane, new_crtc_state)) | |
1260 | continue; | |
1261 | ||
1262 | plane_state = intel_atomic_get_plane_state(state, plane); | |
1263 | if (IS_ERR(plane_state)) | |
1264 | return PTR_ERR(plane_state); | |
1265 | ||
1266 | new_crtc_state->update_planes |= BIT(plane->id); | |
1267 | } | |
1268 | ||
1269 | return 0; | |
1270 | } | |
1271 | ||
e4c0d531 MR |
1272 | static int check_lut_size(const struct drm_property_blob *lut, int expected) |
1273 | { | |
1274 | int len; | |
1275 | ||
1276 | if (!lut) | |
1277 | return 0; | |
1278 | ||
1279 | len = drm_color_lut_size(lut); | |
1280 | if (len != expected) { | |
1281 | DRM_DEBUG_KMS("Invalid LUT size; got %d, expected %d\n", | |
1282 | len, expected); | |
1283 | return -EINVAL; | |
1284 | } | |
1285 | ||
1286 | return 0; | |
1287 | } | |
1288 | ||
e0510da0 VS |
1289 | static int check_luts(const struct intel_crtc_state *crtc_state) |
1290 | { | |
2225f3c6 | 1291 | struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev); |
1326a92c ML |
1292 | const struct drm_property_blob *gamma_lut = crtc_state->hw.gamma_lut; |
1293 | const struct drm_property_blob *degamma_lut = crtc_state->hw.degamma_lut; | |
e0510da0 VS |
1294 | int gamma_length, degamma_length; |
1295 | u32 gamma_tests, degamma_tests; | |
1296 | ||
1297 | /* Always allow legacy gamma LUT with no further checking. */ | |
1298 | if (crtc_state_is_legacy_gamma(crtc_state)) | |
1299 | return 0; | |
1300 | ||
1301 | /* C8 relies on its palette being stored in the legacy LUT */ | |
be8a4b2d | 1302 | if (crtc_state->c8_planes) { |
959a9445 WK |
1303 | drm_dbg_kms(&dev_priv->drm, |
1304 | "C8 pixelformat requires the legacy LUT\n"); | |
e0510da0 | 1305 | return -EINVAL; |
be8a4b2d | 1306 | } |
e0510da0 VS |
1307 | |
1308 | degamma_length = INTEL_INFO(dev_priv)->color.degamma_lut_size; | |
1309 | gamma_length = INTEL_INFO(dev_priv)->color.gamma_lut_size; | |
1310 | degamma_tests = INTEL_INFO(dev_priv)->color.degamma_lut_tests; | |
1311 | gamma_tests = INTEL_INFO(dev_priv)->color.gamma_lut_tests; | |
1312 | ||
1313 | if (check_lut_size(degamma_lut, degamma_length) || | |
1314 | check_lut_size(gamma_lut, gamma_length)) | |
1315 | return -EINVAL; | |
1316 | ||
1317 | if (drm_color_lut_check(degamma_lut, degamma_tests) || | |
1318 | drm_color_lut_check(gamma_lut, gamma_tests)) | |
1319 | return -EINVAL; | |
1320 | ||
1321 | return 0; | |
1322 | } | |
1323 | ||
e262568e VS |
1324 | static u32 i9xx_gamma_mode(struct intel_crtc_state *crtc_state) |
1325 | { | |
1326 | if (!crtc_state->gamma_enable || | |
1327 | crtc_state_is_legacy_gamma(crtc_state)) | |
1328 | return GAMMA_MODE_MODE_8BIT; | |
1329 | else | |
1330 | return GAMMA_MODE_MODE_10BIT; /* i965+ only */ | |
1331 | } | |
1332 | ||
e98f3562 VS |
1333 | static int i9xx_color_check(struct intel_crtc_state *crtc_state) |
1334 | { | |
1335 | int ret; | |
1336 | ||
1337 | ret = check_luts(crtc_state); | |
1338 | if (ret) | |
1339 | return ret; | |
1340 | ||
1341 | crtc_state->gamma_enable = | |
1326a92c | 1342 | crtc_state->hw.gamma_lut && |
e98f3562 VS |
1343 | !crtc_state->c8_planes; |
1344 | ||
e262568e | 1345 | crtc_state->gamma_mode = i9xx_gamma_mode(crtc_state); |
e98f3562 VS |
1346 | |
1347 | ret = intel_color_add_affected_planes(crtc_state); | |
1348 | if (ret) | |
1349 | return ret; | |
1350 | ||
0ccc42a2 VS |
1351 | crtc_state->preload_luts = intel_can_preload_luts(crtc_state); |
1352 | ||
e98f3562 VS |
1353 | return 0; |
1354 | } | |
1355 | ||
9fdfb8e7 VS |
1356 | static u32 chv_cgm_mode(const struct intel_crtc_state *crtc_state) |
1357 | { | |
1358 | u32 cgm_mode = 0; | |
1359 | ||
1360 | if (crtc_state_is_legacy_gamma(crtc_state)) | |
1361 | return 0; | |
1362 | ||
1326a92c | 1363 | if (crtc_state->hw.degamma_lut) |
9fdfb8e7 | 1364 | cgm_mode |= CGM_PIPE_MODE_DEGAMMA; |
1326a92c | 1365 | if (crtc_state->hw.ctm) |
9fdfb8e7 | 1366 | cgm_mode |= CGM_PIPE_MODE_CSC; |
1326a92c | 1367 | if (crtc_state->hw.gamma_lut) |
9fdfb8e7 VS |
1368 | cgm_mode |= CGM_PIPE_MODE_GAMMA; |
1369 | ||
1370 | return cgm_mode; | |
1371 | } | |
1372 | ||
3cdd5174 VS |
1373 | /* |
1374 | * CHV color pipeline: | |
1375 | * u0.10 -> CGM degamma -> u0.14 -> CGM csc -> u0.14 -> CGM gamma -> | |
1376 | * u0.10 -> WGC csc -> u0.10 -> pipe gamma -> u0.10 | |
1377 | * | |
1378 | * We always bypass the WGC csc and use the CGM csc | |
1379 | * instead since it has degamma and better precision. | |
1380 | */ | |
1381 | static int chv_color_check(struct intel_crtc_state *crtc_state) | |
1382 | { | |
1383 | int ret; | |
1384 | ||
1385 | ret = check_luts(crtc_state); | |
1386 | if (ret) | |
1387 | return ret; | |
1388 | ||
1389 | /* | |
1390 | * Pipe gamma will be used only for the legacy LUT. | |
1391 | * Otherwise we bypass it and use the CGM gamma instead. | |
1392 | */ | |
1393 | crtc_state->gamma_enable = | |
1394 | crtc_state_is_legacy_gamma(crtc_state) && | |
1395 | !crtc_state->c8_planes; | |
1396 | ||
1397 | crtc_state->gamma_mode = GAMMA_MODE_MODE_8BIT; | |
1398 | ||
1399 | crtc_state->cgm_mode = chv_cgm_mode(crtc_state); | |
1400 | ||
1401 | ret = intel_color_add_affected_planes(crtc_state); | |
1402 | if (ret) | |
1403 | return ret; | |
1404 | ||
0ccc42a2 VS |
1405 | crtc_state->preload_luts = chv_can_preload_luts(crtc_state); |
1406 | ||
3cdd5174 VS |
1407 | return 0; |
1408 | } | |
1409 | ||
514462ca VS |
1410 | static u32 ilk_gamma_mode(const struct intel_crtc_state *crtc_state) |
1411 | { | |
1412 | if (!crtc_state->gamma_enable || | |
1413 | crtc_state_is_legacy_gamma(crtc_state)) | |
1414 | return GAMMA_MODE_MODE_8BIT; | |
1415 | else | |
1416 | return GAMMA_MODE_MODE_10BIT; | |
1417 | } | |
1418 | ||
af28cc4c VS |
1419 | static u32 ilk_csc_mode(const struct intel_crtc_state *crtc_state) |
1420 | { | |
1421 | /* | |
1422 | * CSC comes after the LUT in RGB->YCbCr mode. | |
1423 | * RGB->YCbCr needs the limited range offsets added to | |
1424 | * the output. RGB limited range output is handled by | |
1425 | * the hw automagically elsewhere. | |
1426 | */ | |
1427 | if (crtc_state->output_format != INTEL_OUTPUT_FORMAT_RGB) | |
1428 | return CSC_BLACK_SCREEN_OFFSET; | |
1429 | ||
1430 | return CSC_MODE_YUV_TO_RGB | | |
1431 | CSC_POSITION_BEFORE_GAMMA; | |
1432 | } | |
1433 | ||
f65d5528 VS |
1434 | static int ilk_color_check(struct intel_crtc_state *crtc_state) |
1435 | { | |
1436 | int ret; | |
1437 | ||
1438 | ret = check_luts(crtc_state); | |
1439 | if (ret) | |
1440 | return ret; | |
1441 | ||
1442 | crtc_state->gamma_enable = | |
1326a92c | 1443 | crtc_state->hw.gamma_lut && |
f65d5528 VS |
1444 | !crtc_state->c8_planes; |
1445 | ||
1446 | /* | |
af28cc4c VS |
1447 | * We don't expose the ctm on ilk/snb currently, also RGB |
1448 | * limited range output is handled by the hw automagically. | |
f65d5528 | 1449 | */ |
af28cc4c VS |
1450 | crtc_state->csc_enable = |
1451 | crtc_state->output_format != INTEL_OUTPUT_FORMAT_RGB; | |
f65d5528 | 1452 | |
514462ca | 1453 | crtc_state->gamma_mode = ilk_gamma_mode(crtc_state); |
f65d5528 | 1454 | |
af28cc4c | 1455 | crtc_state->csc_mode = ilk_csc_mode(crtc_state); |
f65d5528 VS |
1456 | |
1457 | ret = intel_color_add_affected_planes(crtc_state); | |
1458 | if (ret) | |
1459 | return ret; | |
1460 | ||
0ccc42a2 VS |
1461 | crtc_state->preload_luts = intel_can_preload_luts(crtc_state); |
1462 | ||
f65d5528 VS |
1463 | return 0; |
1464 | } | |
1465 | ||
c21ce2ef | 1466 | static u32 ivb_gamma_mode(const struct intel_crtc_state *crtc_state) |
1eb63156 VS |
1467 | { |
1468 | if (!crtc_state->gamma_enable || | |
1469 | crtc_state_is_legacy_gamma(crtc_state)) | |
1470 | return GAMMA_MODE_MODE_8BIT; | |
1326a92c ML |
1471 | else if (crtc_state->hw.gamma_lut && |
1472 | crtc_state->hw.degamma_lut) | |
1eb63156 | 1473 | return GAMMA_MODE_MODE_SPLIT; |
5bda1aca VS |
1474 | else |
1475 | return GAMMA_MODE_MODE_10BIT; | |
1476 | } | |
1477 | ||
c21ce2ef | 1478 | static u32 ivb_csc_mode(const struct intel_crtc_state *crtc_state) |
5bda1aca | 1479 | { |
c21ce2ef VS |
1480 | bool limited_color_range = ilk_csc_limited_range(crtc_state); |
1481 | ||
5bda1aca VS |
1482 | /* |
1483 | * CSC comes after the LUT in degamma, RGB->YCbCr, | |
1484 | * and RGB full->limited range mode. | |
1485 | */ | |
1326a92c | 1486 | if (crtc_state->hw.degamma_lut || |
5bda1aca | 1487 | crtc_state->output_format != INTEL_OUTPUT_FORMAT_RGB || |
c21ce2ef | 1488 | limited_color_range) |
5bda1aca VS |
1489 | return 0; |
1490 | ||
1491 | return CSC_POSITION_BEFORE_GAMMA; | |
1eb63156 VS |
1492 | } |
1493 | ||
c21ce2ef | 1494 | static int ivb_color_check(struct intel_crtc_state *crtc_state) |
1eb63156 | 1495 | { |
0aa5c383 | 1496 | struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev); |
c21ce2ef | 1497 | bool limited_color_range = ilk_csc_limited_range(crtc_state); |
1eb63156 VS |
1498 | int ret; |
1499 | ||
1500 | ret = check_luts(crtc_state); | |
1501 | if (ret) | |
1502 | return ret; | |
1503 | ||
0aa5c383 LS |
1504 | if (crtc_state->output_format != INTEL_OUTPUT_FORMAT_RGB && |
1505 | crtc_state->hw.ctm) { | |
1506 | drm_dbg_kms(&dev_priv->drm, | |
1507 | "YCBCR and CTM together are not possible\n"); | |
1508 | return -EINVAL; | |
1509 | } | |
1510 | ||
1eb63156 | 1511 | crtc_state->gamma_enable = |
1326a92c ML |
1512 | (crtc_state->hw.gamma_lut || |
1513 | crtc_state->hw.degamma_lut) && | |
1eb63156 VS |
1514 | !crtc_state->c8_planes; |
1515 | ||
1516 | crtc_state->csc_enable = | |
1517 | crtc_state->output_format != INTEL_OUTPUT_FORMAT_RGB || | |
1326a92c | 1518 | crtc_state->hw.ctm || limited_color_range; |
1eb63156 | 1519 | |
c21ce2ef | 1520 | crtc_state->gamma_mode = ivb_gamma_mode(crtc_state); |
1eb63156 | 1521 | |
c21ce2ef | 1522 | crtc_state->csc_mode = ivb_csc_mode(crtc_state); |
1eb63156 VS |
1523 | |
1524 | ret = intel_color_add_affected_planes(crtc_state); | |
1525 | if (ret) | |
1526 | return ret; | |
1527 | ||
0ccc42a2 VS |
1528 | crtc_state->preload_luts = intel_can_preload_luts(crtc_state); |
1529 | ||
1eb63156 VS |
1530 | return 0; |
1531 | } | |
1532 | ||
fbeb4f36 VS |
1533 | static u32 glk_gamma_mode(const struct intel_crtc_state *crtc_state) |
1534 | { | |
1535 | if (!crtc_state->gamma_enable || | |
1536 | crtc_state_is_legacy_gamma(crtc_state)) | |
1537 | return GAMMA_MODE_MODE_8BIT; | |
1538 | else | |
1539 | return GAMMA_MODE_MODE_10BIT; | |
1540 | } | |
1541 | ||
1542 | static int glk_color_check(struct intel_crtc_state *crtc_state) | |
1543 | { | |
0aa5c383 | 1544 | struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev); |
fbeb4f36 VS |
1545 | int ret; |
1546 | ||
1547 | ret = check_luts(crtc_state); | |
1548 | if (ret) | |
1549 | return ret; | |
1550 | ||
0aa5c383 LS |
1551 | if (crtc_state->output_format != INTEL_OUTPUT_FORMAT_RGB && |
1552 | crtc_state->hw.ctm) { | |
1553 | drm_dbg_kms(&dev_priv->drm, | |
1554 | "YCBCR and CTM together are not possible\n"); | |
1555 | return -EINVAL; | |
1556 | } | |
1557 | ||
fbeb4f36 | 1558 | crtc_state->gamma_enable = |
1326a92c | 1559 | crtc_state->hw.gamma_lut && |
fbeb4f36 VS |
1560 | !crtc_state->c8_planes; |
1561 | ||
1562 | /* On GLK+ degamma LUT is controlled by csc_enable */ | |
1563 | crtc_state->csc_enable = | |
1326a92c | 1564 | crtc_state->hw.degamma_lut || |
fbeb4f36 | 1565 | crtc_state->output_format != INTEL_OUTPUT_FORMAT_RGB || |
1326a92c | 1566 | crtc_state->hw.ctm || crtc_state->limited_color_range; |
fbeb4f36 VS |
1567 | |
1568 | crtc_state->gamma_mode = glk_gamma_mode(crtc_state); | |
1569 | ||
1570 | crtc_state->csc_mode = 0; | |
1571 | ||
1572 | ret = intel_color_add_affected_planes(crtc_state); | |
1573 | if (ret) | |
1574 | return ret; | |
1575 | ||
0ccc42a2 VS |
1576 | crtc_state->preload_luts = glk_can_preload_luts(crtc_state); |
1577 | ||
fbeb4f36 VS |
1578 | return 0; |
1579 | } | |
1580 | ||
1b386cf8 VS |
1581 | static u32 icl_gamma_mode(const struct intel_crtc_state *crtc_state) |
1582 | { | |
a856ce90 US |
1583 | struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); |
1584 | struct drm_i915_private *i915 = to_i915(crtc->base.dev); | |
1b386cf8 VS |
1585 | u32 gamma_mode = 0; |
1586 | ||
1326a92c | 1587 | if (crtc_state->hw.degamma_lut) |
1b386cf8 VS |
1588 | gamma_mode |= PRE_CSC_GAMMA_ENABLE; |
1589 | ||
1326a92c | 1590 | if (crtc_state->hw.gamma_lut && |
1b386cf8 VS |
1591 | !crtc_state->c8_planes) |
1592 | gamma_mode |= POST_CSC_GAMMA_ENABLE; | |
1593 | ||
1326a92c | 1594 | if (!crtc_state->hw.gamma_lut || |
1b386cf8 VS |
1595 | crtc_state_is_legacy_gamma(crtc_state)) |
1596 | gamma_mode |= GAMMA_MODE_MODE_8BIT; | |
a856ce90 US |
1597 | /* |
1598 | * Enable 10bit gamma for D13 | |
1599 | * ToDo: Extend to Logarithmic Gamma once the new UAPI | |
1600 | * is acccepted and implemented by a userspace consumer | |
1601 | */ | |
1602 | else if (DISPLAY_VER(i915) >= 13) | |
1603 | gamma_mode |= GAMMA_MODE_MODE_10BIT; | |
1b386cf8 | 1604 | else |
02ae8ba9 | 1605 | gamma_mode |= GAMMA_MODE_MODE_12BIT_MULTI_SEGMENTED; |
1b386cf8 VS |
1606 | |
1607 | return gamma_mode; | |
1608 | } | |
1609 | ||
1610 | static u32 icl_csc_mode(const struct intel_crtc_state *crtc_state) | |
1611 | { | |
1612 | u32 csc_mode = 0; | |
1613 | ||
1326a92c | 1614 | if (crtc_state->hw.ctm) |
1b386cf8 VS |
1615 | csc_mode |= ICL_CSC_ENABLE; |
1616 | ||
1617 | if (crtc_state->output_format != INTEL_OUTPUT_FORMAT_RGB || | |
1618 | crtc_state->limited_color_range) | |
1619 | csc_mode |= ICL_OUTPUT_CSC_ENABLE; | |
1620 | ||
1621 | return csc_mode; | |
1622 | } | |
1623 | ||
1624 | static int icl_color_check(struct intel_crtc_state *crtc_state) | |
1625 | { | |
1626 | int ret; | |
1627 | ||
1628 | ret = check_luts(crtc_state); | |
1629 | if (ret) | |
1630 | return ret; | |
1631 | ||
1632 | crtc_state->gamma_mode = icl_gamma_mode(crtc_state); | |
1633 | ||
1634 | crtc_state->csc_mode = icl_csc_mode(crtc_state); | |
145450f6 | 1635 | |
0ccc42a2 VS |
1636 | crtc_state->preload_luts = intel_can_preload_luts(crtc_state); |
1637 | ||
145450f6 SS |
1638 | return 0; |
1639 | } | |
1640 | ||
1641 | static int i9xx_gamma_precision(const struct intel_crtc_state *crtc_state) | |
1642 | { | |
d5034127 SS |
1643 | if (!crtc_state->gamma_enable) |
1644 | return 0; | |
1645 | ||
145450f6 SS |
1646 | switch (crtc_state->gamma_mode) { |
1647 | case GAMMA_MODE_MODE_8BIT: | |
1648 | return 8; | |
1649 | case GAMMA_MODE_MODE_10BIT: | |
1650 | return 16; | |
1651 | default: | |
1652 | MISSING_CASE(crtc_state->gamma_mode); | |
1653 | return 0; | |
1654 | } | |
1655 | } | |
1656 | ||
1657 | static int ilk_gamma_precision(const struct intel_crtc_state *crtc_state) | |
1658 | { | |
d5034127 SS |
1659 | if (!crtc_state->gamma_enable) |
1660 | return 0; | |
1661 | ||
145450f6 SS |
1662 | if ((crtc_state->csc_mode & CSC_POSITION_BEFORE_GAMMA) == 0) |
1663 | return 0; | |
1664 | ||
1665 | switch (crtc_state->gamma_mode) { | |
1666 | case GAMMA_MODE_MODE_8BIT: | |
1667 | return 8; | |
1668 | case GAMMA_MODE_MODE_10BIT: | |
1669 | return 10; | |
1670 | default: | |
1671 | MISSING_CASE(crtc_state->gamma_mode); | |
1672 | return 0; | |
1673 | } | |
1674 | } | |
1675 | ||
b0a7c754 SS |
1676 | static int chv_gamma_precision(const struct intel_crtc_state *crtc_state) |
1677 | { | |
1678 | if (crtc_state->cgm_mode & CGM_PIPE_MODE_GAMMA) | |
1679 | return 10; | |
1680 | else | |
1681 | return i9xx_gamma_precision(crtc_state); | |
1682 | } | |
1683 | ||
145450f6 SS |
1684 | static int glk_gamma_precision(const struct intel_crtc_state *crtc_state) |
1685 | { | |
d5034127 SS |
1686 | if (!crtc_state->gamma_enable) |
1687 | return 0; | |
1688 | ||
145450f6 SS |
1689 | switch (crtc_state->gamma_mode) { |
1690 | case GAMMA_MODE_MODE_8BIT: | |
1691 | return 8; | |
1692 | case GAMMA_MODE_MODE_10BIT: | |
1693 | return 10; | |
1694 | default: | |
1695 | MISSING_CASE(crtc_state->gamma_mode); | |
1696 | return 0; | |
1697 | } | |
1698 | } | |
1699 | ||
b4ab7aa8 SS |
1700 | static int icl_gamma_precision(const struct intel_crtc_state *crtc_state) |
1701 | { | |
1702 | if ((crtc_state->gamma_mode & POST_CSC_GAMMA_ENABLE) == 0) | |
1703 | return 0; | |
1704 | ||
1705 | switch (crtc_state->gamma_mode & GAMMA_MODE_MODE_MASK) { | |
1706 | case GAMMA_MODE_MODE_8BIT: | |
1707 | return 8; | |
1708 | case GAMMA_MODE_MODE_10BIT: | |
1709 | return 10; | |
1710 | case GAMMA_MODE_MODE_12BIT_MULTI_SEGMENTED: | |
1711 | return 16; | |
1712 | default: | |
1713 | MISSING_CASE(crtc_state->gamma_mode); | |
1714 | return 0; | |
1715 | } | |
1716 | } | |
1717 | ||
145450f6 SS |
1718 | int intel_color_get_gamma_bit_precision(const struct intel_crtc_state *crtc_state) |
1719 | { | |
2225f3c6 | 1720 | struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); |
145450f6 SS |
1721 | struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); |
1722 | ||
b0a7c754 SS |
1723 | if (HAS_GMCH(dev_priv)) { |
1724 | if (IS_CHERRYVIEW(dev_priv)) | |
1725 | return chv_gamma_precision(crtc_state); | |
1726 | else | |
1727 | return i9xx_gamma_precision(crtc_state); | |
1728 | } else { | |
005e9537 | 1729 | if (DISPLAY_VER(dev_priv) >= 11) |
b4ab7aa8 | 1730 | return icl_gamma_precision(crtc_state); |
93e7e61e | 1731 | else if (DISPLAY_VER(dev_priv) == 10) |
b0a7c754 SS |
1732 | return glk_gamma_precision(crtc_state); |
1733 | else if (IS_IRONLAKE(dev_priv)) | |
1734 | return ilk_gamma_precision(crtc_state); | |
1735 | } | |
1b386cf8 VS |
1736 | |
1737 | return 0; | |
1738 | } | |
1739 | ||
e9c8f591 SS |
1740 | static bool err_check(struct drm_color_lut *lut1, |
1741 | struct drm_color_lut *lut2, u32 err) | |
1742 | { | |
1743 | return ((abs((long)lut2->red - lut1->red)) <= err) && | |
1744 | ((abs((long)lut2->blue - lut1->blue)) <= err) && | |
1745 | ((abs((long)lut2->green - lut1->green)) <= err); | |
1746 | } | |
1747 | ||
b4ab7aa8 SS |
1748 | static bool intel_color_lut_entries_equal(struct drm_color_lut *lut1, |
1749 | struct drm_color_lut *lut2, | |
1750 | int lut_size, u32 err) | |
e9c8f591 SS |
1751 | { |
1752 | int i; | |
1753 | ||
1754 | for (i = 0; i < lut_size; i++) { | |
1755 | if (!err_check(&lut1[i], &lut2[i], err)) | |
1756 | return false; | |
1757 | } | |
1758 | ||
1759 | return true; | |
1760 | } | |
1761 | ||
1762 | bool intel_color_lut_equal(struct drm_property_blob *blob1, | |
1763 | struct drm_property_blob *blob2, | |
1764 | u32 gamma_mode, u32 bit_precision) | |
1765 | { | |
1766 | struct drm_color_lut *lut1, *lut2; | |
1767 | int lut_size1, lut_size2; | |
1768 | u32 err; | |
1769 | ||
1770 | if (!blob1 != !blob2) | |
1771 | return false; | |
1772 | ||
1773 | if (!blob1) | |
1774 | return true; | |
1775 | ||
1776 | lut_size1 = drm_color_lut_size(blob1); | |
1777 | lut_size2 = drm_color_lut_size(blob2); | |
1778 | ||
1779 | /* check sw and hw lut size */ | |
b4ab7aa8 SS |
1780 | if (lut_size1 != lut_size2) |
1781 | return false; | |
e9c8f591 SS |
1782 | |
1783 | lut1 = blob1->data; | |
1784 | lut2 = blob2->data; | |
1785 | ||
1786 | err = 0xffff >> bit_precision; | |
1787 | ||
1788 | /* check sw and hw lut entry to be equal */ | |
b4ab7aa8 | 1789 | switch (gamma_mode & GAMMA_MODE_MODE_MASK) { |
e9c8f591 SS |
1790 | case GAMMA_MODE_MODE_8BIT: |
1791 | case GAMMA_MODE_MODE_10BIT: | |
b4ab7aa8 SS |
1792 | if (!intel_color_lut_entries_equal(lut1, lut2, |
1793 | lut_size2, err)) | |
1794 | return false; | |
1795 | break; | |
1796 | case GAMMA_MODE_MODE_12BIT_MULTI_SEGMENTED: | |
1797 | if (!intel_color_lut_entries_equal(lut1, lut2, | |
1798 | 9, err)) | |
e9c8f591 SS |
1799 | return false; |
1800 | break; | |
1801 | default: | |
1802 | MISSING_CASE(gamma_mode); | |
7852ddd5 | 1803 | return false; |
e9c8f591 SS |
1804 | } |
1805 | ||
1806 | return true; | |
1807 | } | |
1808 | ||
e10eb8dd | 1809 | static struct drm_property_blob *i9xx_read_lut_8(struct intel_crtc *crtc) |
1af22383 | 1810 | { |
1af22383 SS |
1811 | struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); |
1812 | enum pipe pipe = crtc->pipe; | |
1813 | struct drm_property_blob *blob; | |
7fd33655 | 1814 | struct drm_color_lut *lut; |
73ce0969 | 1815 | int i; |
1af22383 SS |
1816 | |
1817 | blob = drm_property_create_blob(&dev_priv->drm, | |
1818 | sizeof(struct drm_color_lut) * LEGACY_LUT_LENGTH, | |
1819 | NULL); | |
1820 | if (IS_ERR(blob)) | |
1821 | return NULL; | |
1822 | ||
7fd33655 | 1823 | lut = blob->data; |
1af22383 SS |
1824 | |
1825 | for (i = 0; i < LEGACY_LUT_LENGTH; i++) { | |
e536bc93 | 1826 | u32 val = intel_de_read_fw(dev_priv, PALETTE(pipe, i)); |
1af22383 | 1827 | |
0ff3b23f | 1828 | i9xx_lut_8_pack(&lut[i], val); |
1af22383 SS |
1829 | } |
1830 | ||
1831 | return blob; | |
1832 | } | |
1833 | ||
1834 | static void i9xx_read_luts(struct intel_crtc_state *crtc_state) | |
1835 | { | |
e10eb8dd VS |
1836 | struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); |
1837 | ||
9b000b47 SS |
1838 | if (!crtc_state->gamma_enable) |
1839 | return; | |
1840 | ||
e10eb8dd | 1841 | crtc_state->hw.gamma_lut = i9xx_read_lut_8(crtc); |
1af22383 SS |
1842 | } |
1843 | ||
e10eb8dd | 1844 | static struct drm_property_blob *i965_read_lut_10p6(struct intel_crtc *crtc) |
8efd0698 | 1845 | { |
8efd0698 | 1846 | struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); |
73ce0969 | 1847 | int i, lut_size = INTEL_INFO(dev_priv)->color.gamma_lut_size; |
8efd0698 SS |
1848 | enum pipe pipe = crtc->pipe; |
1849 | struct drm_property_blob *blob; | |
7fd33655 | 1850 | struct drm_color_lut *lut; |
8efd0698 SS |
1851 | |
1852 | blob = drm_property_create_blob(&dev_priv->drm, | |
1853 | sizeof(struct drm_color_lut) * lut_size, | |
1854 | NULL); | |
1855 | if (IS_ERR(blob)) | |
1856 | return NULL; | |
1857 | ||
7fd33655 | 1858 | lut = blob->data; |
8efd0698 SS |
1859 | |
1860 | for (i = 0; i < lut_size - 1; i++) { | |
e536bc93 VS |
1861 | u32 ldw = intel_de_read_fw(dev_priv, PALETTE(pipe, 2 * i + 0)); |
1862 | u32 udw = intel_de_read_fw(dev_priv, PALETTE(pipe, 2 * i + 1)); | |
0ff3b23f VS |
1863 | |
1864 | i965_lut_10p6_pack(&lut[i], ldw, udw); | |
8efd0698 SS |
1865 | } |
1866 | ||
e536bc93 VS |
1867 | lut[i].red = i965_lut_11p6_max_pack(intel_de_read_fw(dev_priv, PIPEGCMAX(pipe, 0))); |
1868 | lut[i].green = i965_lut_11p6_max_pack(intel_de_read_fw(dev_priv, PIPEGCMAX(pipe, 1))); | |
1869 | lut[i].blue = i965_lut_11p6_max_pack(intel_de_read_fw(dev_priv, PIPEGCMAX(pipe, 2))); | |
8efd0698 SS |
1870 | |
1871 | return blob; | |
1872 | } | |
1873 | ||
1874 | static void i965_read_luts(struct intel_crtc_state *crtc_state) | |
1875 | { | |
e10eb8dd VS |
1876 | struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); |
1877 | ||
9b000b47 SS |
1878 | if (!crtc_state->gamma_enable) |
1879 | return; | |
1880 | ||
8efd0698 | 1881 | if (crtc_state->gamma_mode == GAMMA_MODE_MODE_8BIT) |
e10eb8dd | 1882 | crtc_state->hw.gamma_lut = i9xx_read_lut_8(crtc); |
8efd0698 | 1883 | else |
e10eb8dd | 1884 | crtc_state->hw.gamma_lut = i965_read_lut_10p6(crtc); |
8efd0698 SS |
1885 | } |
1886 | ||
e10eb8dd | 1887 | static struct drm_property_blob *chv_read_cgm_gamma(struct intel_crtc *crtc) |
4d154d33 | 1888 | { |
4d154d33 | 1889 | struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); |
73ce0969 | 1890 | int i, lut_size = INTEL_INFO(dev_priv)->color.gamma_lut_size; |
4d154d33 SS |
1891 | enum pipe pipe = crtc->pipe; |
1892 | struct drm_property_blob *blob; | |
7fd33655 | 1893 | struct drm_color_lut *lut; |
4d154d33 SS |
1894 | |
1895 | blob = drm_property_create_blob(&dev_priv->drm, | |
1896 | sizeof(struct drm_color_lut) * lut_size, | |
1897 | NULL); | |
1898 | if (IS_ERR(blob)) | |
1899 | return NULL; | |
1900 | ||
7fd33655 | 1901 | lut = blob->data; |
4d154d33 SS |
1902 | |
1903 | for (i = 0; i < lut_size; i++) { | |
e536bc93 VS |
1904 | u32 ldw = intel_de_read_fw(dev_priv, CGM_PIPE_GAMMA(pipe, i, 0)); |
1905 | u32 udw = intel_de_read_fw(dev_priv, CGM_PIPE_GAMMA(pipe, i, 1)); | |
4d154d33 | 1906 | |
0ff3b23f | 1907 | chv_cgm_gamma_pack(&lut[i], ldw, udw); |
4d154d33 SS |
1908 | } |
1909 | ||
1910 | return blob; | |
1911 | } | |
1912 | ||
1913 | static void chv_read_luts(struct intel_crtc_state *crtc_state) | |
1914 | { | |
e10eb8dd VS |
1915 | struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); |
1916 | ||
9b000b47 | 1917 | if (crtc_state->cgm_mode & CGM_PIPE_MODE_GAMMA) |
e10eb8dd | 1918 | crtc_state->hw.gamma_lut = chv_read_cgm_gamma(crtc); |
9b000b47 SS |
1919 | else |
1920 | i965_read_luts(crtc_state); | |
4d154d33 SS |
1921 | } |
1922 | ||
e10eb8dd | 1923 | static struct drm_property_blob *ilk_read_lut_8(struct intel_crtc *crtc) |
10088267 | 1924 | { |
10088267 VS |
1925 | struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); |
1926 | enum pipe pipe = crtc->pipe; | |
1927 | struct drm_property_blob *blob; | |
7fd33655 | 1928 | struct drm_color_lut *lut; |
73ce0969 | 1929 | int i; |
10088267 VS |
1930 | |
1931 | blob = drm_property_create_blob(&dev_priv->drm, | |
1932 | sizeof(struct drm_color_lut) * LEGACY_LUT_LENGTH, | |
1933 | NULL); | |
1934 | if (IS_ERR(blob)) | |
1935 | return NULL; | |
1936 | ||
7fd33655 | 1937 | lut = blob->data; |
10088267 VS |
1938 | |
1939 | for (i = 0; i < LEGACY_LUT_LENGTH; i++) { | |
e536bc93 | 1940 | u32 val = intel_de_read_fw(dev_priv, LGC_PALETTE(pipe, i)); |
10088267 | 1941 | |
0ff3b23f | 1942 | i9xx_lut_8_pack(&lut[i], val); |
10088267 VS |
1943 | } |
1944 | ||
1945 | return blob; | |
1946 | } | |
1947 | ||
e10eb8dd | 1948 | static struct drm_property_blob *ilk_read_lut_10(struct intel_crtc *crtc) |
6b97b118 | 1949 | { |
6b97b118 | 1950 | struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); |
73ce0969 | 1951 | int i, lut_size = INTEL_INFO(dev_priv)->color.gamma_lut_size; |
6b97b118 SS |
1952 | enum pipe pipe = crtc->pipe; |
1953 | struct drm_property_blob *blob; | |
7fd33655 | 1954 | struct drm_color_lut *lut; |
6b97b118 SS |
1955 | |
1956 | blob = drm_property_create_blob(&dev_priv->drm, | |
1957 | sizeof(struct drm_color_lut) * lut_size, | |
1958 | NULL); | |
1959 | if (IS_ERR(blob)) | |
1960 | return NULL; | |
1961 | ||
7fd33655 | 1962 | lut = blob->data; |
6b97b118 SS |
1963 | |
1964 | for (i = 0; i < lut_size; i++) { | |
e536bc93 | 1965 | u32 val = intel_de_read_fw(dev_priv, PREC_PALETTE(pipe, i)); |
6b97b118 | 1966 | |
0ff3b23f | 1967 | ilk_lut_10_pack(&lut[i], val); |
6b97b118 SS |
1968 | } |
1969 | ||
1970 | return blob; | |
1971 | } | |
1972 | ||
1973 | static void ilk_read_luts(struct intel_crtc_state *crtc_state) | |
1974 | { | |
e10eb8dd VS |
1975 | struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); |
1976 | ||
9b000b47 SS |
1977 | if (!crtc_state->gamma_enable) |
1978 | return; | |
1979 | ||
1980 | if ((crtc_state->csc_mode & CSC_POSITION_BEFORE_GAMMA) == 0) | |
1981 | return; | |
1982 | ||
7852ddd5 VS |
1983 | switch (crtc_state->gamma_mode) { |
1984 | case GAMMA_MODE_MODE_8BIT: | |
e10eb8dd | 1985 | crtc_state->hw.gamma_lut = ilk_read_lut_8(crtc); |
7852ddd5 VS |
1986 | break; |
1987 | case GAMMA_MODE_MODE_10BIT: | |
e10eb8dd | 1988 | crtc_state->hw.gamma_lut = ilk_read_lut_10(crtc); |
7852ddd5 VS |
1989 | break; |
1990 | default: | |
1991 | MISSING_CASE(crtc_state->gamma_mode); | |
1992 | break; | |
1993 | } | |
6b97b118 SS |
1994 | } |
1995 | ||
e0122138 VS |
1996 | /* On BDW+ the index auto increment mode actually works */ |
1997 | static struct drm_property_blob *bdw_read_lut_10(struct intel_crtc *crtc, | |
e10eb8dd | 1998 | u32 prec_index) |
4bb6a9d5 | 1999 | { |
4bb6a9d5 | 2000 | struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); |
73ce0969 | 2001 | int i, hw_lut_size = ivb_lut_10_size(prec_index); |
d0a9acaa | 2002 | int lut_size = INTEL_INFO(dev_priv)->color.gamma_lut_size; |
4bb6a9d5 SS |
2003 | enum pipe pipe = crtc->pipe; |
2004 | struct drm_property_blob *blob; | |
7fd33655 | 2005 | struct drm_color_lut *lut; |
4bb6a9d5 | 2006 | |
d0a9acaa VS |
2007 | drm_WARN_ON(&dev_priv->drm, lut_size != hw_lut_size); |
2008 | ||
4bb6a9d5 | 2009 | blob = drm_property_create_blob(&dev_priv->drm, |
d0a9acaa | 2010 | sizeof(struct drm_color_lut) * lut_size, |
4bb6a9d5 SS |
2011 | NULL); |
2012 | if (IS_ERR(blob)) | |
2013 | return NULL; | |
2014 | ||
7fd33655 | 2015 | lut = blob->data; |
4bb6a9d5 | 2016 | |
e536bc93 VS |
2017 | intel_de_write_fw(dev_priv, PREC_PAL_INDEX(pipe), |
2018 | prec_index | PAL_PREC_AUTO_INCREMENT); | |
bf93b724 | 2019 | |
d0a9acaa | 2020 | for (i = 0; i < lut_size; i++) { |
e536bc93 | 2021 | u32 val = intel_de_read_fw(dev_priv, PREC_PAL_DATA(pipe)); |
4bb6a9d5 | 2022 | |
0ff3b23f | 2023 | ilk_lut_10_pack(&lut[i], val); |
4bb6a9d5 SS |
2024 | } |
2025 | ||
e536bc93 | 2026 | intel_de_write_fw(dev_priv, PREC_PAL_INDEX(pipe), 0); |
4bb6a9d5 SS |
2027 | |
2028 | return blob; | |
2029 | } | |
2030 | ||
2031 | static void glk_read_luts(struct intel_crtc_state *crtc_state) | |
2032 | { | |
e10eb8dd VS |
2033 | struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); |
2034 | ||
9b000b47 SS |
2035 | if (!crtc_state->gamma_enable) |
2036 | return; | |
2037 | ||
7852ddd5 VS |
2038 | switch (crtc_state->gamma_mode) { |
2039 | case GAMMA_MODE_MODE_8BIT: | |
e10eb8dd | 2040 | crtc_state->hw.gamma_lut = ilk_read_lut_8(crtc); |
7852ddd5 VS |
2041 | break; |
2042 | case GAMMA_MODE_MODE_10BIT: | |
e0122138 | 2043 | crtc_state->hw.gamma_lut = bdw_read_lut_10(crtc, PAL_PREC_INDEX_VALUE(0)); |
7852ddd5 VS |
2044 | break; |
2045 | default: | |
2046 | MISSING_CASE(crtc_state->gamma_mode); | |
2047 | break; | |
2048 | } | |
4bb6a9d5 SS |
2049 | } |
2050 | ||
b4ab7aa8 SS |
2051 | static struct drm_property_blob * |
2052 | icl_read_lut_multi_segment(struct intel_crtc *crtc) | |
2053 | { | |
2054 | struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); | |
2055 | int i, lut_size = INTEL_INFO(dev_priv)->color.gamma_lut_size; | |
2056 | enum pipe pipe = crtc->pipe; | |
2057 | struct drm_property_blob *blob; | |
2058 | struct drm_color_lut *lut; | |
2059 | ||
2060 | blob = drm_property_create_blob(&dev_priv->drm, | |
2061 | sizeof(struct drm_color_lut) * lut_size, | |
2062 | NULL); | |
2063 | if (IS_ERR(blob)) | |
2064 | return NULL; | |
2065 | ||
2066 | lut = blob->data; | |
2067 | ||
e536bc93 VS |
2068 | intel_de_write_fw(dev_priv, PREC_PAL_MULTI_SEG_INDEX(pipe), |
2069 | PAL_PREC_AUTO_INCREMENT); | |
b4ab7aa8 SS |
2070 | |
2071 | for (i = 0; i < 9; i++) { | |
e536bc93 VS |
2072 | u32 ldw = intel_de_read_fw(dev_priv, PREC_PAL_MULTI_SEG_DATA(pipe)); |
2073 | u32 udw = intel_de_read_fw(dev_priv, PREC_PAL_MULTI_SEG_DATA(pipe)); | |
b4ab7aa8 SS |
2074 | |
2075 | icl_lut_multi_seg_pack(&lut[i], ldw, udw); | |
2076 | } | |
2077 | ||
e536bc93 | 2078 | intel_de_write_fw(dev_priv, PREC_PAL_MULTI_SEG_INDEX(pipe), 0); |
b4ab7aa8 SS |
2079 | |
2080 | /* | |
2081 | * FIXME readouts from PAL_PREC_DATA register aren't giving | |
2082 | * correct values in the case of fine and coarse segments. | |
2083 | * Restricting readouts only for super fine segment as of now. | |
2084 | */ | |
2085 | ||
2086 | return blob; | |
2087 | } | |
2088 | ||
2089 | static void icl_read_luts(struct intel_crtc_state *crtc_state) | |
2090 | { | |
2091 | struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); | |
2092 | ||
2093 | if ((crtc_state->gamma_mode & POST_CSC_GAMMA_ENABLE) == 0) | |
2094 | return; | |
2095 | ||
2096 | switch (crtc_state->gamma_mode & GAMMA_MODE_MODE_MASK) { | |
2097 | case GAMMA_MODE_MODE_8BIT: | |
2098 | crtc_state->hw.gamma_lut = ilk_read_lut_8(crtc); | |
2099 | break; | |
7852ddd5 VS |
2100 | case GAMMA_MODE_MODE_10BIT: |
2101 | crtc_state->hw.gamma_lut = bdw_read_lut_10(crtc, PAL_PREC_INDEX_VALUE(0)); | |
2102 | break; | |
b4ab7aa8 SS |
2103 | case GAMMA_MODE_MODE_12BIT_MULTI_SEGMENTED: |
2104 | crtc_state->hw.gamma_lut = icl_read_lut_multi_segment(crtc); | |
2105 | break; | |
2106 | default: | |
7852ddd5 VS |
2107 | MISSING_CASE(crtc_state->gamma_mode); |
2108 | break; | |
b4ab7aa8 SS |
2109 | } |
2110 | } | |
2111 | ||
302da0cd | 2112 | void intel_color_init(struct intel_crtc *crtc) |
8563b1e8 | 2113 | { |
302da0cd | 2114 | struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); |
514462ca | 2115 | bool has_ctm = INTEL_INFO(dev_priv)->color.degamma_lut_size != 0; |
8563b1e8 | 2116 | |
302da0cd | 2117 | drm_mode_crtc_set_gamma_size(&crtc->base, 256); |
8563b1e8 | 2118 | |
9d5441de | 2119 | if (HAS_GMCH(dev_priv)) { |
e98f3562 | 2120 | if (IS_CHERRYVIEW(dev_priv)) { |
3cdd5174 | 2121 | dev_priv->display.color_check = chv_color_check; |
e98f3562 | 2122 | dev_priv->display.color_commit = i9xx_color_commit; |
f61a8f36 | 2123 | dev_priv->display.load_luts = chv_load_luts; |
4d154d33 | 2124 | dev_priv->display.read_luts = chv_read_luts; |
005e9537 | 2125 | } else if (DISPLAY_VER(dev_priv) >= 4) { |
e262568e VS |
2126 | dev_priv->display.color_check = i9xx_color_check; |
2127 | dev_priv->display.color_commit = i9xx_color_commit; | |
2128 | dev_priv->display.load_luts = i965_load_luts; | |
8efd0698 | 2129 | dev_priv->display.read_luts = i965_read_luts; |
e98f3562 VS |
2130 | } else { |
2131 | dev_priv->display.color_check = i9xx_color_check; | |
2132 | dev_priv->display.color_commit = i9xx_color_commit; | |
9d5441de | 2133 | dev_priv->display.load_luts = i9xx_load_luts; |
1af22383 | 2134 | dev_priv->display.read_luts = i9xx_read_luts; |
e98f3562 | 2135 | } |
8563b1e8 | 2136 | } else { |
005e9537 | 2137 | if (DISPLAY_VER(dev_priv) >= 11) |
1b386cf8 | 2138 | dev_priv->display.color_check = icl_color_check; |
2b5a4562 | 2139 | else if (DISPLAY_VER(dev_priv) >= 10) |
fbeb4f36 | 2140 | dev_priv->display.color_check = glk_color_check; |
005e9537 | 2141 | else if (DISPLAY_VER(dev_priv) >= 7) |
c21ce2ef | 2142 | dev_priv->display.color_check = ivb_color_check; |
1b386cf8 | 2143 | else |
f65d5528 | 2144 | dev_priv->display.color_check = ilk_color_check; |
9d9cb9c1 | 2145 | |
005e9537 | 2146 | if (DISPLAY_VER(dev_priv) >= 9) |
9d9cb9c1 VS |
2147 | dev_priv->display.color_commit = skl_color_commit; |
2148 | else if (IS_BROADWELL(dev_priv) || IS_HASWELL(dev_priv)) | |
2149 | dev_priv->display.color_commit = hsw_color_commit; | |
2150 | else | |
2151 | dev_priv->display.color_commit = ilk_color_commit; | |
2152 | ||
005e9537 | 2153 | if (DISPLAY_VER(dev_priv) >= 11) { |
13717cef | 2154 | dev_priv->display.load_luts = icl_load_luts; |
b4ab7aa8 | 2155 | dev_priv->display.read_luts = icl_read_luts; |
93e7e61e | 2156 | } else if (DISPLAY_VER(dev_priv) == 10) { |
9d5441de | 2157 | dev_priv->display.load_luts = glk_load_luts; |
4bb6a9d5 | 2158 | dev_priv->display.read_luts = glk_read_luts; |
005e9537 | 2159 | } else if (DISPLAY_VER(dev_priv) >= 8) { |
5bda1aca | 2160 | dev_priv->display.load_luts = bdw_load_luts; |
005e9537 | 2161 | } else if (DISPLAY_VER(dev_priv) >= 7) { |
c21ce2ef | 2162 | dev_priv->display.load_luts = ivb_load_luts; |
bf93b724 | 2163 | } else { |
514462ca | 2164 | dev_priv->display.load_luts = ilk_load_luts; |
6b97b118 SS |
2165 | dev_priv->display.read_luts = ilk_read_luts; |
2166 | } | |
8563b1e8 | 2167 | } |
82cf435b | 2168 | |
514462ca VS |
2169 | drm_crtc_enable_color_mgmt(&crtc->base, |
2170 | INTEL_INFO(dev_priv)->color.degamma_lut_size, | |
2171 | has_ctm, | |
2172 | INTEL_INFO(dev_priv)->color.gamma_lut_size); | |
8563b1e8 | 2173 | } |