This source file includes following definitions.
- amdgpu_dm_init_color_mod
- __extract_blob_lut
- __is_lut_linear
- __drm_lut_to_dc_gamma
- __drm_ctm_to_dc_matrix
- __set_legacy_tf
- __set_output_tf
- __set_input_tf
- amdgpu_dm_update_crtc_color_mgmt
- amdgpu_dm_update_plane_color_mgmt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 #include "amdgpu.h"
26 #include "amdgpu_mode.h"
27 #include "amdgpu_dm.h"
28 #include "dc.h"
29 #include "modules/color/color_gamma.h"
30 #include "basics/conversion.h"
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72 #define MAX_DRM_LUT_VALUE 0xFFFF
73
74
75
76
77
78
79
80 void amdgpu_dm_init_color_mod(void)
81 {
82 setup_x_points_distribution();
83 }
84
85
86 static const struct drm_color_lut *
87 __extract_blob_lut(const struct drm_property_blob *blob, uint32_t *size)
88 {
89 *size = blob ? drm_color_lut_size(blob) : 0;
90 return blob ? (struct drm_color_lut *)blob->data : NULL;
91 }
92
93
94
95
96
97
98
99
100
101 static bool __is_lut_linear(const struct drm_color_lut *lut, uint32_t size)
102 {
103 int i;
104 uint32_t expected;
105 int delta;
106
107 for (i = 0; i < size; i++) {
108
109 if ((lut[i].red != lut[i].green) || (lut[i].green != lut[i].blue))
110 return false;
111
112 expected = i * MAX_DRM_LUT_VALUE / (size-1);
113
114
115 delta = lut[i].red - expected;
116 if (delta < -1 || 1 < delta)
117 return false;
118 }
119 return true;
120 }
121
122
123
124
125
126 static void __drm_lut_to_dc_gamma(const struct drm_color_lut *lut,
127 struct dc_gamma *gamma, bool is_legacy)
128 {
129 uint32_t r, g, b;
130 int i;
131
132 if (is_legacy) {
133 for (i = 0; i < MAX_COLOR_LEGACY_LUT_ENTRIES; i++) {
134 r = drm_color_lut_extract(lut[i].red, 16);
135 g = drm_color_lut_extract(lut[i].green, 16);
136 b = drm_color_lut_extract(lut[i].blue, 16);
137
138 gamma->entries.red[i] = dc_fixpt_from_int(r);
139 gamma->entries.green[i] = dc_fixpt_from_int(g);
140 gamma->entries.blue[i] = dc_fixpt_from_int(b);
141 }
142 return;
143 }
144
145
146 for (i = 0; i < MAX_COLOR_LUT_ENTRIES; i++) {
147 r = drm_color_lut_extract(lut[i].red, 16);
148 g = drm_color_lut_extract(lut[i].green, 16);
149 b = drm_color_lut_extract(lut[i].blue, 16);
150
151 gamma->entries.red[i] = dc_fixpt_from_fraction(r, MAX_DRM_LUT_VALUE);
152 gamma->entries.green[i] = dc_fixpt_from_fraction(g, MAX_DRM_LUT_VALUE);
153 gamma->entries.blue[i] = dc_fixpt_from_fraction(b, MAX_DRM_LUT_VALUE);
154 }
155 }
156
157
158
159
160
161 static void __drm_ctm_to_dc_matrix(const struct drm_color_ctm *ctm,
162 struct fixed31_32 *matrix)
163 {
164 int64_t val;
165 int i;
166
167
168
169
170
171
172
173
174
175 for (i = 0; i < 12; i++) {
176
177 if (i % 4 == 3) {
178 matrix[i] = dc_fixpt_zero;
179 continue;
180 }
181
182
183 val = ctm->matrix[i - (i / 4)];
184
185 if (val & (1ULL << 63))
186 val = -(val & ~(1ULL << 63));
187
188 matrix[i].value = val;
189 }
190 }
191
192
193 static int __set_legacy_tf(struct dc_transfer_func *func,
194 const struct drm_color_lut *lut, uint32_t lut_size,
195 bool has_rom)
196 {
197 struct dc_gamma *gamma = NULL;
198 bool res;
199
200 ASSERT(lut && lut_size == MAX_COLOR_LEGACY_LUT_ENTRIES);
201
202 gamma = dc_create_gamma();
203 if (!gamma)
204 return -ENOMEM;
205
206 gamma->type = GAMMA_RGB_256;
207 gamma->num_entries = lut_size;
208 __drm_lut_to_dc_gamma(lut, gamma, true);
209
210 res = mod_color_calculate_regamma_params(func, gamma, true, has_rom,
211 NULL);
212
213 return res ? 0 : -ENOMEM;
214 }
215
216
217 static int __set_output_tf(struct dc_transfer_func *func,
218 const struct drm_color_lut *lut, uint32_t lut_size,
219 bool has_rom)
220 {
221 struct dc_gamma *gamma = NULL;
222 bool res;
223
224 ASSERT(lut && lut_size == MAX_COLOR_LUT_ENTRIES);
225
226 gamma = dc_create_gamma();
227 if (!gamma)
228 return -ENOMEM;
229
230 gamma->num_entries = lut_size;
231 __drm_lut_to_dc_gamma(lut, gamma, false);
232
233 if (func->tf == TRANSFER_FUNCTION_LINEAR) {
234
235
236
237
238
239 gamma->type = GAMMA_CUSTOM;
240 res = mod_color_calculate_degamma_params(func, gamma, true);
241 } else {
242
243
244
245
246 gamma->type = GAMMA_CS_TFM_1D;
247 res = mod_color_calculate_regamma_params(func, gamma, false,
248 has_rom, NULL);
249 }
250
251 dc_gamma_release(&gamma);
252
253 return res ? 0 : -ENOMEM;
254 }
255
256
257 static int __set_input_tf(struct dc_transfer_func *func,
258 const struct drm_color_lut *lut, uint32_t lut_size)
259 {
260 struct dc_gamma *gamma = NULL;
261 bool res;
262
263 gamma = dc_create_gamma();
264 if (!gamma)
265 return -ENOMEM;
266
267 gamma->type = GAMMA_CUSTOM;
268 gamma->num_entries = lut_size;
269
270 __drm_lut_to_dc_gamma(lut, gamma, false);
271
272 res = mod_color_calculate_degamma_params(func, gamma, true);
273 dc_gamma_release(&gamma);
274
275 return res ? 0 : -ENOMEM;
276 }
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299 int amdgpu_dm_update_crtc_color_mgmt(struct dm_crtc_state *crtc)
300 {
301 struct dc_stream_state *stream = crtc->stream;
302 struct amdgpu_device *adev =
303 (struct amdgpu_device *)crtc->base.state->dev->dev_private;
304 bool has_rom = adev->asic_type <= CHIP_RAVEN;
305 struct drm_color_ctm *ctm = NULL;
306 const struct drm_color_lut *degamma_lut, *regamma_lut;
307 uint32_t degamma_size, regamma_size;
308 bool has_regamma, has_degamma;
309 bool is_legacy;
310 int r;
311
312 degamma_lut = __extract_blob_lut(crtc->base.degamma_lut, °amma_size);
313 if (degamma_lut && degamma_size != MAX_COLOR_LUT_ENTRIES)
314 return -EINVAL;
315
316 regamma_lut = __extract_blob_lut(crtc->base.gamma_lut, ®amma_size);
317 if (regamma_lut && regamma_size != MAX_COLOR_LUT_ENTRIES &&
318 regamma_size != MAX_COLOR_LEGACY_LUT_ENTRIES)
319 return -EINVAL;
320
321 has_degamma =
322 degamma_lut && !__is_lut_linear(degamma_lut, degamma_size);
323
324 has_regamma =
325 regamma_lut && !__is_lut_linear(regamma_lut, regamma_size);
326
327 is_legacy = regamma_size == MAX_COLOR_LEGACY_LUT_ENTRIES;
328
329
330 crtc->cm_has_degamma = false;
331 crtc->cm_is_degamma_srgb = false;
332
333
334 if (is_legacy) {
335
336
337
338
339
340
341
342
343
344
345
346 crtc->cm_is_degamma_srgb = true;
347 stream->out_transfer_func->type = TF_TYPE_DISTRIBUTED_POINTS;
348 stream->out_transfer_func->tf = TRANSFER_FUNCTION_SRGB;
349
350 r = __set_legacy_tf(stream->out_transfer_func, regamma_lut,
351 regamma_size, has_rom);
352 if (r)
353 return r;
354 } else if (has_regamma) {
355
356 stream->out_transfer_func->type = TF_TYPE_DISTRIBUTED_POINTS;
357 stream->out_transfer_func->tf = TRANSFER_FUNCTION_LINEAR;
358
359 r = __set_output_tf(stream->out_transfer_func, regamma_lut,
360 regamma_size, has_rom);
361 if (r)
362 return r;
363 } else {
364
365
366
367
368 stream->out_transfer_func->type = TF_TYPE_BYPASS;
369 stream->out_transfer_func->tf = TRANSFER_FUNCTION_LINEAR;
370 }
371
372
373
374
375
376
377 crtc->cm_has_degamma = has_degamma;
378
379
380 if (crtc->base.ctm) {
381 ctm = (struct drm_color_ctm *)crtc->base.ctm->data;
382
383
384
385
386
387
388
389
390
391
392 __drm_ctm_to_dc_matrix(ctm, stream->gamut_remap_matrix.matrix);
393
394 stream->gamut_remap_matrix.enable_remap = true;
395 stream->csc_color_matrix.enable_adjustment = false;
396 } else {
397
398 stream->gamut_remap_matrix.enable_remap = false;
399 stream->csc_color_matrix.enable_adjustment = false;
400 }
401
402 return 0;
403 }
404
405
406
407
408
409
410
411
412
413
414
415
416 int amdgpu_dm_update_plane_color_mgmt(struct dm_crtc_state *crtc,
417 struct dc_plane_state *dc_plane_state)
418 {
419 const struct drm_color_lut *degamma_lut;
420 uint32_t degamma_size;
421 int r;
422
423 if (crtc->cm_has_degamma) {
424 degamma_lut = __extract_blob_lut(crtc->base.degamma_lut,
425 °amma_size);
426 ASSERT(degamma_size == MAX_COLOR_LUT_ENTRIES);
427
428 dc_plane_state->in_transfer_func->type =
429 TF_TYPE_DISTRIBUTED_POINTS;
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455 if (crtc->cm_is_degamma_srgb)
456 dc_plane_state->in_transfer_func->tf =
457 TRANSFER_FUNCTION_SRGB;
458 else
459 dc_plane_state->in_transfer_func->tf =
460 TRANSFER_FUNCTION_LINEAR;
461
462 r = __set_input_tf(dc_plane_state->in_transfer_func,
463 degamma_lut, degamma_size);
464 if (r)
465 return r;
466 } else if (crtc->cm_is_degamma_srgb) {
467
468
469
470
471 dc_plane_state->in_transfer_func->type = TF_TYPE_PREDEFINED;
472 dc_plane_state->in_transfer_func->tf = TRANSFER_FUNCTION_SRGB;
473 } else {
474
475 dc_plane_state->in_transfer_func->type = TF_TYPE_BYPASS;
476 dc_plane_state->in_transfer_func->tf = TRANSFER_FUNCTION_LINEAR;
477 }
478
479 return 0;
480 }