drm/i915: Implement color management on bdw/skl/bxt/kbl
[deliverable/linux.git] / drivers / gpu / drm / i915 / intel_color.c
CommitLineData
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
25#include "intel_drv.h"
26
82cf435b
LL
27#define CTM_COEFF_SIGN (1ULL << 63)
28
29#define CTM_COEFF_1_0 (1ULL << 32)
30#define CTM_COEFF_2_0 (CTM_COEFF_1_0 << 1)
31#define CTM_COEFF_4_0 (CTM_COEFF_2_0 << 1)
32#define CTM_COEFF_0_5 (CTM_COEFF_1_0 >> 1)
33#define CTM_COEFF_0_25 (CTM_COEFF_0_5 >> 1)
34#define CTM_COEFF_0_125 (CTM_COEFF_0_25 >> 1)
35
36#define CTM_COEFF_LIMITED_RANGE ((235ULL - 16ULL) * CTM_COEFF_1_0 / 255)
37
38#define CTM_COEFF_NEGATIVE(coeff) (((coeff) & CTM_COEFF_SIGN) != 0)
39#define CTM_COEFF_ABS(coeff) ((coeff) & (CTM_COEFF_SIGN - 1))
40
41#define LEGACY_LUT_LENGTH (sizeof(struct drm_color_lut) * 256)
42
8563b1e8 43/*
82cf435b
LL
44 * Extract the CSC coefficient from a CTM coefficient (in U32.32 fixed point
45 * format). This macro takes the coefficient we want transformed and the
46 * number of fractional bits.
8563b1e8 47 *
82cf435b
LL
48 * We only have a 9 bits precision window which slides depending on the value
49 * of the CTM coefficient and we write the value from bit 3. We also round the
50 * value.
8563b1e8 51 */
82cf435b
LL
52#define I9XX_CSC_COEFF_FP(coeff, fbits) \
53 (clamp_val(((coeff) >> (32 - (fbits) - 3)) + 4, 0, 0xfff) & 0xff8)
54
55#define I9XX_CSC_COEFF_LIMITED_RANGE \
56 I9XX_CSC_COEFF_FP(CTM_COEFF_LIMITED_RANGE, 9)
57#define I9XX_CSC_COEFF_1_0 \
58 ((7 << 12) | I9XX_CSC_COEFF_FP(CTM_COEFF_1_0, 8))
59
60static bool crtc_state_is_legacy(struct drm_crtc_state *state)
61{
62 return !state->degamma_lut &&
63 !state->ctm &&
64 state->gamma_lut &&
65 state->gamma_lut->length == LEGACY_LUT_LENGTH;
66}
67
68/*
69 * When using limited range, multiply the matrix given by userspace by
70 * the matrix that we would use for the limited range. We do the
71 * multiplication in U2.30 format.
72 */
73static void ctm_mult_by_limited(uint64_t *result, int64_t *input)
74{
75 int i;
76
77 for (i = 0; i < 9; i++)
78 result[i] = 0;
79
80 for (i = 0; i < 3; i++) {
81 int64_t user_coeff = input[i * 3 + i];
82 uint64_t limited_coeff = CTM_COEFF_LIMITED_RANGE >> 2;
83 uint64_t abs_coeff = clamp_val(CTM_COEFF_ABS(user_coeff),
84 0,
85 CTM_COEFF_4_0 - 1) >> 2;
86
87 result[i * 3 + i] = (limited_coeff * abs_coeff) >> 27;
88 if (CTM_COEFF_NEGATIVE(user_coeff))
89 result[i * 3 + i] |= CTM_COEFF_SIGN;
90 }
91}
92
93/* Set up the pipe CSC unit. */
8563b1e8
LL
94static void i9xx_load_csc_matrix(struct drm_crtc *crtc)
95{
96 struct drm_device *dev = crtc->dev;
82cf435b 97 struct drm_crtc_state *crtc_state = crtc->state;
8563b1e8
LL
98 struct drm_i915_private *dev_priv = dev->dev_private;
99 struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
82cf435b
LL
100 int i, pipe = intel_crtc->pipe;
101 uint16_t coeffs[9] = { 0, };
102
103 if (crtc_state->ctm) {
104 struct drm_color_ctm *ctm =
105 (struct drm_color_ctm *)crtc_state->ctm->data;
106 uint64_t input[9] = { 0, };
107
108 if (intel_crtc->config->limited_color_range) {
109 ctm_mult_by_limited(input, ctm->matrix);
110 } else {
111 for (i = 0; i < ARRAY_SIZE(input); i++)
112 input[i] = ctm->matrix[i];
113 }
114
115 /*
116 * Convert fixed point S31.32 input to format supported by the
117 * hardware.
118 */
119 for (i = 0; i < ARRAY_SIZE(coeffs); i++) {
120 uint64_t abs_coeff = ((1ULL << 63) - 1) & input[i];
121
122 /*
123 * Clamp input value to min/max supported by
124 * hardware.
125 */
126 abs_coeff = clamp_val(abs_coeff, 0, CTM_COEFF_4_0 - 1);
127
128 /* sign bit */
129 if (CTM_COEFF_NEGATIVE(input[i]))
130 coeffs[i] |= 1 << 15;
131
132 if (abs_coeff < CTM_COEFF_0_125)
133 coeffs[i] |= (3 << 12) |
134 I9XX_CSC_COEFF_FP(abs_coeff, 12);
135 else if (abs_coeff < CTM_COEFF_0_25)
136 coeffs[i] |= (2 << 12) |
137 I9XX_CSC_COEFF_FP(abs_coeff, 11);
138 else if (abs_coeff < CTM_COEFF_0_5)
139 coeffs[i] |= (1 << 12) |
140 I9XX_CSC_COEFF_FP(abs_coeff, 10);
141 else if (abs_coeff < CTM_COEFF_1_0)
142 coeffs[i] |= I9XX_CSC_COEFF_FP(abs_coeff, 9);
143 else if (abs_coeff < CTM_COEFF_2_0)
144 coeffs[i] |= (7 << 12) |
145 I9XX_CSC_COEFF_FP(abs_coeff, 8);
146 else
147 coeffs[i] |= (6 << 12) |
148 I9XX_CSC_COEFF_FP(abs_coeff, 7);
149 }
150 } else {
151 /*
152 * Load an identity matrix if no coefficients are provided.
153 *
154 * TODO: Check what kind of values actually come out of the
155 * pipe with these coeff/postoff values and adjust to get the
156 * best accuracy. Perhaps we even need to take the bpc value
157 * into consideration.
158 */
159 for (i = 0; i < 3; i++) {
160 if (intel_crtc->config->limited_color_range)
161 coeffs[i * 3 + i] =
162 I9XX_CSC_COEFF_LIMITED_RANGE;
163 else
164 coeffs[i * 3 + i] = I9XX_CSC_COEFF_1_0;
165 }
166 }
8563b1e8 167
82cf435b
LL
168 I915_WRITE(PIPE_CSC_COEFF_RY_GY(pipe), coeffs[0] << 16 | coeffs[1]);
169 I915_WRITE(PIPE_CSC_COEFF_BY(pipe), coeffs[2] << 16);
8563b1e8 170
82cf435b
LL
171 I915_WRITE(PIPE_CSC_COEFF_RU_GU(pipe), coeffs[3] << 16 | coeffs[4]);
172 I915_WRITE(PIPE_CSC_COEFF_BU(pipe), coeffs[5] << 16);
8563b1e8 173
82cf435b
LL
174 I915_WRITE(PIPE_CSC_COEFF_RV_GV(pipe), coeffs[6] << 16 | coeffs[7]);
175 I915_WRITE(PIPE_CSC_COEFF_BV(pipe), coeffs[8] << 16);
8563b1e8
LL
176
177 I915_WRITE(PIPE_CSC_PREOFF_HI(pipe), 0);
178 I915_WRITE(PIPE_CSC_PREOFF_ME(pipe), 0);
179 I915_WRITE(PIPE_CSC_PREOFF_LO(pipe), 0);
180
181 if (INTEL_INFO(dev)->gen > 6) {
182 uint16_t postoff = 0;
183
184 if (intel_crtc->config->limited_color_range)
185 postoff = (16 * (1 << 12) / 255) & 0x1fff;
186
187 I915_WRITE(PIPE_CSC_POSTOFF_HI(pipe), postoff);
188 I915_WRITE(PIPE_CSC_POSTOFF_ME(pipe), postoff);
189 I915_WRITE(PIPE_CSC_POSTOFF_LO(pipe), postoff);
190
191 I915_WRITE(PIPE_CSC_MODE(pipe), 0);
192 } else {
193 uint32_t mode = CSC_MODE_YUV_TO_RGB;
194
195 if (intel_crtc->config->limited_color_range)
196 mode |= CSC_BLACK_SCREEN_OFFSET;
197
198 I915_WRITE(PIPE_CSC_MODE(pipe), mode);
199 }
200}
201
202void intel_color_set_csc(struct drm_crtc *crtc)
203{
82cf435b
LL
204 struct drm_device *dev = crtc->dev;
205 struct drm_i915_private *dev_priv = dev->dev_private;
206
207 if (dev_priv->display.load_csc_matrix)
208 dev_priv->display.load_csc_matrix(crtc);
8563b1e8
LL
209}
210
82cf435b 211/* Loads the legacy palette/gamma unit for the CRTC. */
8563b1e8
LL
212static void i9xx_load_luts(struct drm_crtc *crtc)
213{
214 struct drm_device *dev = crtc->dev;
82cf435b 215 struct drm_crtc_state *state = crtc->state;
8563b1e8
LL
216 struct drm_i915_private *dev_priv = dev->dev_private;
217 struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
218 enum pipe pipe = intel_crtc->pipe;
219 int i;
220
221 if (HAS_GMCH_DISPLAY(dev)) {
222 if (intel_crtc->config->has_dsi_encoder)
223 assert_dsi_pll_enabled(dev_priv);
224 else
225 assert_pll_enabled(dev_priv, pipe);
226 }
227
82cf435b
LL
228 if (state->gamma_lut) {
229 struct drm_color_lut *lut =
230 (struct drm_color_lut *) state->gamma_lut->data;
231 for (i = 0; i < 256; i++) {
232 uint32_t word =
233 (drm_color_lut_extract(lut[i].red, 8) << 16) |
234 (drm_color_lut_extract(lut[i].green, 8) << 8) |
235 drm_color_lut_extract(lut[i].blue, 8);
236
237 if (HAS_GMCH_DISPLAY(dev))
238 I915_WRITE(PALETTE(pipe, i), word);
239 else
240 I915_WRITE(LGC_PALETTE(pipe, i), word);
241 }
242 } else {
243 for (i = 0; i < 256; i++) {
244 uint32_t word = (i << 16) | (i << 8) | i;
245
246 if (HAS_GMCH_DISPLAY(dev))
247 I915_WRITE(PALETTE(pipe, i), word);
248 else
249 I915_WRITE(LGC_PALETTE(pipe, i), word);
250 }
8563b1e8
LL
251 }
252}
253
82cf435b 254/* Loads the legacy palette/gamma unit for the CRTC on Haswell. */
8563b1e8
LL
255static void haswell_load_luts(struct drm_crtc *crtc)
256{
257 struct drm_device *dev = crtc->dev;
258 struct drm_i915_private *dev_priv = dev->dev_private;
259 struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
05dc698c
LL
260 struct intel_crtc_state *intel_crtc_state =
261 to_intel_crtc_state(crtc->state);
8563b1e8
LL
262 bool reenable_ips = false;
263
264 /*
265 * Workaround : Do not read or write the pipe palette/gamma data while
266 * GAMMA_MODE is configured for split gamma and IPS_CTL has IPS enabled.
267 */
268 if (IS_HASWELL(dev) && intel_crtc->config->ips_enabled &&
05dc698c 269 (intel_crtc_state->gamma_mode == GAMMA_MODE_MODE_SPLIT)) {
8563b1e8
LL
270 hsw_disable_ips(intel_crtc);
271 reenable_ips = true;
272 }
05dc698c
LL
273
274 intel_crtc_state->gamma_mode = GAMMA_MODE_MODE_8BIT;
8563b1e8
LL
275 I915_WRITE(GAMMA_MODE(intel_crtc->pipe), GAMMA_MODE_MODE_8BIT);
276
277 i9xx_load_luts(crtc);
278
279 if (reenable_ips)
280 hsw_enable_ips(intel_crtc);
281}
282
82cf435b
LL
283/* Loads the palette/gamma unit for the CRTC on Broadwell+. */
284static void broadwell_load_luts(struct drm_crtc *crtc)
285{
286 struct drm_device *dev = crtc->dev;
287 struct drm_crtc_state *state = crtc->state;
288 struct drm_i915_private *dev_priv = dev->dev_private;
289 struct intel_crtc_state *intel_state = to_intel_crtc_state(state);
290 enum pipe pipe = to_intel_crtc(crtc)->pipe;
291 uint32_t i, lut_size = INTEL_INFO(dev)->color.degamma_lut_size;
292
293 if (crtc_state_is_legacy(state)) {
294 haswell_load_luts(crtc);
295 return;
296 }
297
298 I915_WRITE(PREC_PAL_INDEX(pipe),
299 PAL_PREC_SPLIT_MODE | PAL_PREC_AUTO_INCREMENT);
300
301 if (state->degamma_lut) {
302 struct drm_color_lut *lut =
303 (struct drm_color_lut *) state->degamma_lut->data;
304
305 for (i = 0; i < lut_size; i++) {
306 uint32_t word =
307 drm_color_lut_extract(lut[i].red, 10) << 20 |
308 drm_color_lut_extract(lut[i].green, 10) << 10 |
309 drm_color_lut_extract(lut[i].blue, 10);
310
311 I915_WRITE(PREC_PAL_DATA(pipe), word);
312 }
313 } else {
314 for (i = 0; i < lut_size; i++) {
315 uint32_t v = (i * ((1 << 10) - 1)) / (lut_size - 1);
316
317 I915_WRITE(PREC_PAL_DATA(pipe),
318 (v << 20) | (v << 10) | v);
319 }
320 }
321
322 if (state->gamma_lut) {
323 struct drm_color_lut *lut =
324 (struct drm_color_lut *) state->gamma_lut->data;
325
326 for (i = 0; i < lut_size; i++) {
327 uint32_t word =
328 (drm_color_lut_extract(lut[i].red, 10) << 20) |
329 (drm_color_lut_extract(lut[i].green, 10) << 10) |
330 drm_color_lut_extract(lut[i].blue, 10);
331
332 I915_WRITE(PREC_PAL_DATA(pipe), word);
333 }
334
335 /* Program the max register to clamp values > 1.0. */
336 I915_WRITE(PREC_PAL_GC_MAX(pipe, 0),
337 drm_color_lut_extract(lut[i].red, 16));
338 I915_WRITE(PREC_PAL_GC_MAX(pipe, 1),
339 drm_color_lut_extract(lut[i].green, 16));
340 I915_WRITE(PREC_PAL_GC_MAX(pipe, 2),
341 drm_color_lut_extract(lut[i].blue, 16));
342 } else {
343 for (i = 0; i < lut_size; i++) {
344 uint32_t v = (i * ((1 << 10) - 1)) / (lut_size - 1);
345
346 I915_WRITE(PREC_PAL_DATA(pipe),
347 (v << 20) | (v << 10) | v);
348 }
349
350 I915_WRITE(PREC_PAL_GC_MAX(pipe, 0), (1 << 16) - 1);
351 I915_WRITE(PREC_PAL_GC_MAX(pipe, 1), (1 << 16) - 1);
352 I915_WRITE(PREC_PAL_GC_MAX(pipe, 2), (1 << 16) - 1);
353 }
354
355 intel_state->gamma_mode = GAMMA_MODE_MODE_SPLIT;
356 I915_WRITE(GAMMA_MODE(pipe), GAMMA_MODE_MODE_SPLIT);
357 POSTING_READ(GAMMA_MODE(pipe));
358
359 /*
360 * Reset the index, otherwise it prevents the legacy palette to be
361 * written properly.
362 */
363 I915_WRITE(PREC_PAL_INDEX(pipe), 0);
364}
365
8563b1e8
LL
366void intel_color_load_luts(struct drm_crtc *crtc)
367{
368 struct drm_device *dev = crtc->dev;
369 struct drm_i915_private *dev_priv = dev->dev_private;
370
371 /* The clocks have to be on to load the palette. */
372 if (!crtc->state->active)
373 return;
374
375 dev_priv->display.load_luts(crtc);
376}
377
82cf435b
LL
378int intel_color_check(struct drm_crtc *crtc,
379 struct drm_crtc_state *crtc_state)
8563b1e8 380{
82cf435b
LL
381 struct drm_device *dev = crtc->dev;
382 size_t gamma_length, degamma_length;
8563b1e8 383
82cf435b
LL
384 degamma_length = INTEL_INFO(dev)->color.degamma_lut_size *
385 sizeof(struct drm_color_lut);
386 gamma_length = INTEL_INFO(dev)->color.gamma_lut_size *
387 sizeof(struct drm_color_lut);
8563b1e8 388
82cf435b
LL
389 /*
390 * We allow both degamma & gamma luts at the right size or
391 * NULL.
392 */
393 if ((!crtc_state->degamma_lut ||
394 crtc_state->degamma_lut->length == degamma_length) &&
395 (!crtc_state->gamma_lut ||
396 crtc_state->gamma_lut->length == gamma_length))
397 return 0;
398
399 /*
400 * We also allow no degamma lut and a gamma lut at the legacy
401 * size (256 entries).
402 */
403 if (!crtc_state->degamma_lut &&
404 crtc_state->gamma_lut &&
405 crtc_state->gamma_lut->length == LEGACY_LUT_LENGTH)
406 return 0;
407
408 return -EINVAL;
8563b1e8
LL
409}
410
411void intel_color_init(struct drm_crtc *crtc)
412{
413 struct drm_device *dev = crtc->dev;
414 struct drm_i915_private *dev_priv = dev->dev_private;
8563b1e8
LL
415
416 drm_mode_crtc_set_gamma_size(crtc, 256);
8563b1e8 417
82cf435b
LL
418 if (IS_HASWELL(dev)) {
419 dev_priv->display.load_csc_matrix = i9xx_load_csc_matrix;
8563b1e8 420 dev_priv->display.load_luts = haswell_load_luts;
82cf435b
LL
421 } else if (IS_BROADWELL(dev) || IS_SKYLAKE(dev) ||
422 IS_BROXTON(dev) || IS_KABYLAKE(dev)) {
423 dev_priv->display.load_csc_matrix = i9xx_load_csc_matrix;
424 dev_priv->display.load_luts = broadwell_load_luts;
8563b1e8
LL
425 } else {
426 dev_priv->display.load_luts = i9xx_load_luts;
427 }
82cf435b
LL
428
429 /* Enable color management support when we have degamma & gamma LUTs. */
430 if (INTEL_INFO(dev)->color.degamma_lut_size != 0 &&
431 INTEL_INFO(dev)->color.gamma_lut_size != 0)
432 drm_helper_crtc_enable_color_mgmt(crtc,
433 INTEL_INFO(dev)->color.degamma_lut_size,
434 INTEL_INFO(dev)->color.gamma_lut_size);
8563b1e8 435}
This page took 0.056306 seconds and 5 git commands to generate.