diff options
-rw-r--r-- | drivers/gpu/drm/amd/display/dc/basics/fixpt31_32.c | 9 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/display/dc/calcs/Makefile | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/display/dc/calcs/gamma_calcs.c | 1481 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/display/dc/core/dc.c | 10 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/display/dc/dc.h | 11 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c | 440 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/display/dc/inc/gamma_calcs.h | 20 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/display/dc/inc/hw/opp.h | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/display/include/fixed31_32.h | 8 |
9 files changed, 466 insertions, 1517 deletions
diff --git a/drivers/gpu/drm/amd/display/dc/basics/fixpt31_32.c b/drivers/gpu/drm/amd/display/dc/basics/fixpt31_32.c index 5a6e46843502..546ed67c6f83 100644 --- a/drivers/gpu/drm/amd/display/dc/basics/fixpt31_32.c +++ b/drivers/gpu/drm/amd/display/dc/basics/fixpt31_32.c | |||
@@ -246,6 +246,15 @@ struct fixed31_32 dal_fixed31_32_add( | |||
246 | return res; | 246 | return res; |
247 | } | 247 | } |
248 | 248 | ||
249 | struct fixed31_32 dal_fixed31_32_add_int( | ||
250 | struct fixed31_32 arg1, | ||
251 | int32_t arg2) | ||
252 | { | ||
253 | return dal_fixed31_32_add( | ||
254 | arg1, | ||
255 | dal_fixed31_32_from_int(arg2)); | ||
256 | } | ||
257 | |||
249 | struct fixed31_32 dal_fixed31_32_sub_int( | 258 | struct fixed31_32 dal_fixed31_32_sub_int( |
250 | struct fixed31_32 arg1, | 259 | struct fixed31_32 arg1, |
251 | int32_t arg2) | 260 | int32_t arg2) |
diff --git a/drivers/gpu/drm/amd/display/dc/calcs/Makefile b/drivers/gpu/drm/amd/display/dc/calcs/Makefile index 4001933e7808..4bb08aea6a03 100644 --- a/drivers/gpu/drm/amd/display/dc/calcs/Makefile +++ b/drivers/gpu/drm/amd/display/dc/calcs/Makefile | |||
@@ -3,7 +3,7 @@ | |||
3 | # It calculates Bandwidth and Watermarks values for HW programming | 3 | # It calculates Bandwidth and Watermarks values for HW programming |
4 | # | 4 | # |
5 | 5 | ||
6 | BW_CALCS = bandwidth_calcs.o bw_fixed.o gamma_calcs.o | 6 | BW_CALCS = bandwidth_calcs.o bw_fixed.o |
7 | 7 | ||
8 | AMD_DAL_BW_CALCS = $(addprefix $(AMDDALPATH)/dc/calcs/,$(BW_CALCS)) | 8 | AMD_DAL_BW_CALCS = $(addprefix $(AMDDALPATH)/dc/calcs/,$(BW_CALCS)) |
9 | 9 | ||
diff --git a/drivers/gpu/drm/amd/display/dc/calcs/gamma_calcs.c b/drivers/gpu/drm/amd/display/dc/calcs/gamma_calcs.c deleted file mode 100644 index fd300db833c7..000000000000 --- a/drivers/gpu/drm/amd/display/dc/calcs/gamma_calcs.c +++ /dev/null | |||
@@ -1,1481 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright 2015 Advanced Micro Devices, Inc. | ||
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 shall be included in | ||
12 | * all copies or substantial portions of the Software. | ||
13 | * | ||
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||
19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
20 | * OTHER DEALINGS IN THE SOFTWARE. | ||
21 | * | ||
22 | * Authors: AMD | ||
23 | * | ||
24 | */ | ||
25 | |||
26 | #include "dm_services.h" | ||
27 | #include "gamma_calcs.h" | ||
28 | |||
29 | struct curve_config { | ||
30 | uint32_t offset; | ||
31 | int8_t segments[16]; | ||
32 | int8_t begin; | ||
33 | }; | ||
34 | |||
35 | static bool build_custom_float( | ||
36 | struct fixed31_32 value, | ||
37 | const struct custom_float_format *format, | ||
38 | bool *negative, | ||
39 | uint32_t *mantissa, | ||
40 | uint32_t *exponenta) | ||
41 | { | ||
42 | uint32_t exp_offset = (1 << (format->exponenta_bits - 1)) - 1; | ||
43 | |||
44 | const struct fixed31_32 mantissa_constant_plus_max_fraction = | ||
45 | dal_fixed31_32_from_fraction( | ||
46 | (1LL << (format->mantissa_bits + 1)) - 1, | ||
47 | 1LL << format->mantissa_bits); | ||
48 | |||
49 | struct fixed31_32 mantiss; | ||
50 | |||
51 | if (dal_fixed31_32_eq( | ||
52 | value, | ||
53 | dal_fixed31_32_zero)) { | ||
54 | *negative = false; | ||
55 | *mantissa = 0; | ||
56 | *exponenta = 0; | ||
57 | return true; | ||
58 | } | ||
59 | |||
60 | if (dal_fixed31_32_lt( | ||
61 | value, | ||
62 | dal_fixed31_32_zero)) { | ||
63 | *negative = format->sign; | ||
64 | value = dal_fixed31_32_neg(value); | ||
65 | } else { | ||
66 | *negative = false; | ||
67 | } | ||
68 | |||
69 | if (dal_fixed31_32_lt( | ||
70 | value, | ||
71 | dal_fixed31_32_one)) { | ||
72 | uint32_t i = 1; | ||
73 | |||
74 | do { | ||
75 | value = dal_fixed31_32_shl(value, 1); | ||
76 | ++i; | ||
77 | } while (dal_fixed31_32_lt( | ||
78 | value, | ||
79 | dal_fixed31_32_one)); | ||
80 | |||
81 | --i; | ||
82 | |||
83 | if (exp_offset <= i) { | ||
84 | *mantissa = 0; | ||
85 | *exponenta = 0; | ||
86 | return true; | ||
87 | } | ||
88 | |||
89 | *exponenta = exp_offset - i; | ||
90 | } else if (dal_fixed31_32_le( | ||
91 | mantissa_constant_plus_max_fraction, | ||
92 | value)) { | ||
93 | uint32_t i = 1; | ||
94 | |||
95 | do { | ||
96 | value = dal_fixed31_32_shr(value, 1); | ||
97 | ++i; | ||
98 | } while (dal_fixed31_32_lt( | ||
99 | mantissa_constant_plus_max_fraction, | ||
100 | value)); | ||
101 | |||
102 | *exponenta = exp_offset + i - 1; | ||
103 | } else { | ||
104 | *exponenta = exp_offset; | ||
105 | } | ||
106 | |||
107 | mantiss = dal_fixed31_32_sub( | ||
108 | value, | ||
109 | dal_fixed31_32_one); | ||
110 | |||
111 | if (dal_fixed31_32_lt( | ||
112 | mantiss, | ||
113 | dal_fixed31_32_zero) || | ||
114 | dal_fixed31_32_lt( | ||
115 | dal_fixed31_32_one, | ||
116 | mantiss)) | ||
117 | mantiss = dal_fixed31_32_zero; | ||
118 | else | ||
119 | mantiss = dal_fixed31_32_shl( | ||
120 | mantiss, | ||
121 | format->mantissa_bits); | ||
122 | |||
123 | *mantissa = dal_fixed31_32_floor(mantiss); | ||
124 | |||
125 | return true; | ||
126 | } | ||
127 | |||
128 | static bool setup_custom_float( | ||
129 | const struct custom_float_format *format, | ||
130 | bool negative, | ||
131 | uint32_t mantissa, | ||
132 | uint32_t exponenta, | ||
133 | uint32_t *result) | ||
134 | { | ||
135 | uint32_t i = 0; | ||
136 | uint32_t j = 0; | ||
137 | |||
138 | uint32_t value = 0; | ||
139 | |||
140 | /* verification code: | ||
141 | * once calculation is ok we can remove it | ||
142 | */ | ||
143 | |||
144 | const uint32_t mantissa_mask = | ||
145 | (1 << (format->mantissa_bits + 1)) - 1; | ||
146 | |||
147 | const uint32_t exponenta_mask = | ||
148 | (1 << (format->exponenta_bits + 1)) - 1; | ||
149 | |||
150 | if (mantissa & ~mantissa_mask) { | ||
151 | BREAK_TO_DEBUGGER(); | ||
152 | mantissa = mantissa_mask; | ||
153 | } | ||
154 | |||
155 | if (exponenta & ~exponenta_mask) { | ||
156 | BREAK_TO_DEBUGGER(); | ||
157 | exponenta = exponenta_mask; | ||
158 | } | ||
159 | |||
160 | /* end of verification code */ | ||
161 | |||
162 | while (i < format->mantissa_bits) { | ||
163 | uint32_t mask = 1 << i; | ||
164 | |||
165 | if (mantissa & mask) | ||
166 | value |= mask; | ||
167 | |||
168 | ++i; | ||
169 | } | ||
170 | |||
171 | while (j < format->exponenta_bits) { | ||
172 | uint32_t mask = 1 << j; | ||
173 | |||
174 | if (exponenta & mask) | ||
175 | value |= mask << i; | ||
176 | |||
177 | ++j; | ||
178 | } | ||
179 | |||
180 | if (negative && format->sign) | ||
181 | value |= 1 << (i + j); | ||
182 | |||
183 | *result = value; | ||
184 | |||
185 | return true; | ||
186 | } | ||
187 | |||
188 | static bool build_hw_curve_configuration( | ||
189 | const struct curve_config *curve_config, | ||
190 | struct gamma_curve *gamma_curve, | ||
191 | struct curve_points *curve_points, | ||
192 | struct hw_x_point *points, | ||
193 | uint32_t *number_of_points) | ||
194 | { | ||
195 | const int8_t max_regions_number = ARRAY_SIZE(curve_config->segments); | ||
196 | |||
197 | int8_t i; | ||
198 | |||
199 | uint8_t segments_calculation[8] = { 0 }; | ||
200 | |||
201 | struct fixed31_32 region1 = dal_fixed31_32_zero; | ||
202 | struct fixed31_32 region2; | ||
203 | struct fixed31_32 increment; | ||
204 | |||
205 | uint32_t index = 0; | ||
206 | uint32_t segments = 0; | ||
207 | uint32_t max_number; | ||
208 | |||
209 | int8_t num_regions = 0; | ||
210 | |||
211 | bool result = false; | ||
212 | |||
213 | if (!number_of_points) { | ||
214 | BREAK_TO_DEBUGGER(); | ||
215 | return false; | ||
216 | } | ||
217 | |||
218 | max_number = *number_of_points; | ||
219 | |||
220 | i = 0; | ||
221 | |||
222 | while (i != max_regions_number) { | ||
223 | gamma_curve[i].offset = 0; | ||
224 | gamma_curve[i].segments_num = 0; | ||
225 | |||
226 | ++i; | ||
227 | } | ||
228 | |||
229 | i = 0; | ||
230 | |||
231 | while (i != max_regions_number) { | ||
232 | /* number should go in uninterruptible sequence */ | ||
233 | if (curve_config->segments[i] == -1) | ||
234 | break; | ||
235 | |||
236 | ASSERT(curve_config->segments[i] >= 0); | ||
237 | |||
238 | segments += (1 << curve_config->segments[i]); | ||
239 | ++num_regions; | ||
240 | |||
241 | ++i; | ||
242 | } | ||
243 | |||
244 | if (segments > max_number) { | ||
245 | BREAK_TO_DEBUGGER(); | ||
246 | } else { | ||
247 | int32_t divisor; | ||
248 | uint32_t offset = 0; | ||
249 | int8_t begin = curve_config->begin; | ||
250 | int32_t region_number = 0; | ||
251 | |||
252 | i = begin; | ||
253 | |||
254 | while ((index < max_number) && | ||
255 | (region_number < max_regions_number) && | ||
256 | (i < (begin + num_regions))) { | ||
257 | int32_t j = 0; | ||
258 | |||
259 | segments = curve_config->segments[region_number]; | ||
260 | divisor = 1 << segments; | ||
261 | |||
262 | if (segments == -1) { | ||
263 | if (i > 0) { | ||
264 | region1 = dal_fixed31_32_shl( | ||
265 | dal_fixed31_32_one, | ||
266 | i - 1); | ||
267 | region2 = dal_fixed31_32_shl( | ||
268 | dal_fixed31_32_one, | ||
269 | i); | ||
270 | } else { | ||
271 | region1 = dal_fixed31_32_shr( | ||
272 | dal_fixed31_32_one, | ||
273 | -(i - 1)); | ||
274 | region2 = dal_fixed31_32_shr( | ||
275 | dal_fixed31_32_one, | ||
276 | -i); | ||
277 | } | ||
278 | |||
279 | break; | ||
280 | } | ||
281 | |||
282 | if (i > -1) { | ||
283 | region1 = dal_fixed31_32_shl( | ||
284 | dal_fixed31_32_one, | ||
285 | i); | ||
286 | region2 = dal_fixed31_32_shl( | ||
287 | dal_fixed31_32_one, | ||
288 | i + 1); | ||
289 | } else { | ||
290 | region1 = dal_fixed31_32_shr( | ||
291 | dal_fixed31_32_one, | ||
292 | -i); | ||
293 | region2 = dal_fixed31_32_shr( | ||
294 | dal_fixed31_32_one, | ||
295 | -(i + 1)); | ||
296 | } | ||
297 | |||
298 | gamma_curve[region_number].offset = offset; | ||
299 | gamma_curve[region_number].segments_num = segments; | ||
300 | |||
301 | offset += divisor; | ||
302 | |||
303 | ++segments_calculation[segments]; | ||
304 | |||
305 | increment = dal_fixed31_32_div_int( | ||
306 | dal_fixed31_32_sub( | ||
307 | region2, | ||
308 | region1), | ||
309 | divisor); | ||
310 | |||
311 | points[index].x = region1; | ||
312 | points[index].adjusted_x = region1; | ||
313 | |||
314 | ++index; | ||
315 | ++region_number; | ||
316 | |||
317 | while ((index < max_number) && (j < divisor - 1)) { | ||
318 | region1 = dal_fixed31_32_add( | ||
319 | region1, | ||
320 | increment); | ||
321 | |||
322 | points[index].x = region1; | ||
323 | points[index].adjusted_x = region1; | ||
324 | |||
325 | ++index; | ||
326 | ++j; | ||
327 | } | ||
328 | |||
329 | ++i; | ||
330 | } | ||
331 | |||
332 | points[index].x = region1; | ||
333 | points[index].adjusted_x = region1; | ||
334 | |||
335 | *number_of_points = index; | ||
336 | |||
337 | result = true; | ||
338 | } | ||
339 | |||
340 | curve_points[0].x = points[0].adjusted_x; | ||
341 | curve_points[0].offset = dal_fixed31_32_zero; | ||
342 | |||
343 | curve_points[1].x = points[index - 1].adjusted_x; | ||
344 | curve_points[1].offset = dal_fixed31_32_zero; | ||
345 | |||
346 | curve_points[2].x = points[index].adjusted_x; | ||
347 | curve_points[2].offset = dal_fixed31_32_zero; | ||
348 | |||
349 | return result; | ||
350 | } | ||
351 | |||
352 | static bool setup_distribution_points_pq( | ||
353 | struct gamma_curve *arr_curve_points, | ||
354 | struct curve_points *arr_points, | ||
355 | uint32_t *hw_points_num, | ||
356 | struct hw_x_point *coordinates_x, | ||
357 | enum surface_pixel_format format) | ||
358 | { | ||
359 | struct curve_config cfg; | ||
360 | |||
361 | cfg.offset = 0; | ||
362 | cfg.segments[0] = 2; | ||
363 | cfg.segments[1] = 2; | ||
364 | cfg.segments[2] = 2; | ||
365 | cfg.segments[3] = 2; | ||
366 | cfg.segments[4] = 2; | ||
367 | cfg.segments[5] = 2; | ||
368 | cfg.segments[6] = 3; | ||
369 | cfg.segments[7] = 4; | ||
370 | cfg.segments[8] = 4; | ||
371 | cfg.segments[9] = 4; | ||
372 | cfg.segments[10] = 4; | ||
373 | cfg.segments[11] = 5; | ||
374 | cfg.segments[12] = 5; | ||
375 | cfg.segments[13] = 5; | ||
376 | cfg.segments[14] = 5; | ||
377 | cfg.segments[15] = 5; | ||
378 | |||
379 | if (format == SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616F || | ||
380 | format == SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F) | ||
381 | cfg.begin = -11; | ||
382 | else | ||
383 | cfg.begin = -16; | ||
384 | |||
385 | if (!build_hw_curve_configuration( | ||
386 | &cfg, arr_curve_points, | ||
387 | arr_points, | ||
388 | coordinates_x, hw_points_num)) { | ||
389 | ASSERT_CRITICAL(false); | ||
390 | return false; | ||
391 | } | ||
392 | return true; | ||
393 | } | ||
394 | |||
395 | static bool setup_distribution_points( | ||
396 | struct gamma_curve *arr_curve_points, | ||
397 | struct curve_points *arr_points, | ||
398 | uint32_t *hw_points_num, | ||
399 | struct hw_x_point *coordinates_x) | ||
400 | { | ||
401 | struct curve_config cfg; | ||
402 | |||
403 | cfg.offset = 0; | ||
404 | cfg.segments[0] = 3; | ||
405 | cfg.segments[1] = 4; | ||
406 | cfg.segments[2] = 4; | ||
407 | cfg.segments[3] = 4; | ||
408 | cfg.segments[4] = 4; | ||
409 | cfg.segments[5] = 4; | ||
410 | cfg.segments[6] = 4; | ||
411 | cfg.segments[7] = 4; | ||
412 | cfg.segments[8] = 5; | ||
413 | cfg.segments[9] = 5; | ||
414 | cfg.segments[10] = 0; | ||
415 | cfg.segments[11] = -1; | ||
416 | cfg.segments[12] = -1; | ||
417 | cfg.segments[13] = -1; | ||
418 | cfg.segments[14] = -1; | ||
419 | cfg.segments[15] = -1; | ||
420 | |||
421 | cfg.begin = -10; | ||
422 | |||
423 | if (!build_hw_curve_configuration( | ||
424 | &cfg, arr_curve_points, | ||
425 | arr_points, | ||
426 | coordinates_x, hw_points_num)) { | ||
427 | ASSERT_CRITICAL(false); | ||
428 | return false; | ||
429 | } | ||
430 | return true; | ||
431 | } | ||
432 | |||
433 | struct dividers { | ||
434 | struct fixed31_32 divider1; | ||
435 | struct fixed31_32 divider2; | ||
436 | struct fixed31_32 divider3; | ||
437 | }; | ||
438 | |||
439 | static void build_regamma_coefficients(struct gamma_coefficients *coefficients) | ||
440 | { | ||
441 | /* sRGB should apply 2.4 */ | ||
442 | static const int32_t numerator01[3] = { 31308, 31308, 31308 }; | ||
443 | static const int32_t numerator02[3] = { 12920, 12920, 12920 }; | ||
444 | static const int32_t numerator03[3] = { 55, 55, 55 }; | ||
445 | static const int32_t numerator04[3] = { 55, 55, 55 }; | ||
446 | static const int32_t numerator05[3] = { 2400, 2400, 2400 }; | ||
447 | |||
448 | const int32_t *numerator1; | ||
449 | const int32_t *numerator2; | ||
450 | const int32_t *numerator3; | ||
451 | const int32_t *numerator4; | ||
452 | const int32_t *numerator5; | ||
453 | |||
454 | uint32_t i = 0; | ||
455 | |||
456 | numerator1 = numerator01; | ||
457 | numerator2 = numerator02; | ||
458 | numerator3 = numerator03; | ||
459 | numerator4 = numerator04; | ||
460 | numerator5 = numerator05; | ||
461 | |||
462 | do { | ||
463 | coefficients->a0[i] = dal_fixed31_32_from_fraction( | ||
464 | numerator1[i], 10000000); | ||
465 | coefficients->a1[i] = dal_fixed31_32_from_fraction( | ||
466 | numerator2[i], 1000); | ||
467 | coefficients->a2[i] = dal_fixed31_32_from_fraction( | ||
468 | numerator3[i], 1000); | ||
469 | coefficients->a3[i] = dal_fixed31_32_from_fraction( | ||
470 | numerator4[i], 1000); | ||
471 | coefficients->user_gamma[i] = dal_fixed31_32_from_fraction( | ||
472 | numerator5[i], 1000); | ||
473 | |||
474 | ++i; | ||
475 | } while (i != ARRAY_SIZE(coefficients->a0)); | ||
476 | } | ||
477 | |||
478 | static struct fixed31_32 translate_from_linear_space( | ||
479 | struct fixed31_32 arg, | ||
480 | struct fixed31_32 a0, | ||
481 | struct fixed31_32 a1, | ||
482 | struct fixed31_32 a2, | ||
483 | struct fixed31_32 a3, | ||
484 | struct fixed31_32 gamma) | ||
485 | { | ||
486 | const struct fixed31_32 one = dal_fixed31_32_from_int(1); | ||
487 | |||
488 | if (dal_fixed31_32_le(arg, dal_fixed31_32_neg(a0))) | ||
489 | return dal_fixed31_32_sub( | ||
490 | a2, | ||
491 | dal_fixed31_32_mul( | ||
492 | dal_fixed31_32_add( | ||
493 | one, | ||
494 | a3), | ||
495 | dal_fixed31_32_pow( | ||
496 | dal_fixed31_32_neg(arg), | ||
497 | dal_fixed31_32_recip(gamma)))); | ||
498 | else if (dal_fixed31_32_le(a0, arg)) | ||
499 | return dal_fixed31_32_sub( | ||
500 | dal_fixed31_32_mul( | ||
501 | dal_fixed31_32_add( | ||
502 | one, | ||
503 | a3), | ||
504 | dal_fixed31_32_pow( | ||
505 | arg, | ||
506 | dal_fixed31_32_recip(gamma))), | ||
507 | a2); | ||
508 | else | ||
509 | return dal_fixed31_32_mul( | ||
510 | arg, | ||
511 | a1); | ||
512 | } | ||
513 | |||
514 | static inline struct fixed31_32 translate_from_linear_space_ex( | ||
515 | struct fixed31_32 arg, | ||
516 | struct gamma_coefficients *coeff, | ||
517 | uint32_t color_index) | ||
518 | { | ||
519 | return translate_from_linear_space( | ||
520 | arg, | ||
521 | coeff->a0[color_index], | ||
522 | coeff->a1[color_index], | ||
523 | coeff->a2[color_index], | ||
524 | coeff->a3[color_index], | ||
525 | coeff->user_gamma[color_index]); | ||
526 | } | ||
527 | |||
528 | static bool find_software_points( | ||
529 | const struct gamma_pixel *axis_x_256, | ||
530 | struct fixed31_32 hw_point, | ||
531 | enum channel_name channel, | ||
532 | uint32_t *index_to_start, | ||
533 | uint32_t *index_left, | ||
534 | uint32_t *index_right, | ||
535 | enum hw_point_position *pos) | ||
536 | { | ||
537 | const uint32_t max_number = INPUT_LUT_ENTRIES + 3; | ||
538 | |||
539 | struct fixed31_32 left, right; | ||
540 | |||
541 | uint32_t i = *index_to_start; | ||
542 | |||
543 | while (i < max_number) { | ||
544 | if (channel == CHANNEL_NAME_RED) { | ||
545 | left = axis_x_256[i].r; | ||
546 | |||
547 | if (i < max_number - 1) | ||
548 | right = axis_x_256[i + 1].r; | ||
549 | else | ||
550 | right = axis_x_256[max_number - 1].r; | ||
551 | } else if (channel == CHANNEL_NAME_GREEN) { | ||
552 | left = axis_x_256[i].g; | ||
553 | |||
554 | if (i < max_number - 1) | ||
555 | right = axis_x_256[i + 1].g; | ||
556 | else | ||
557 | right = axis_x_256[max_number - 1].g; | ||
558 | } else { | ||
559 | left = axis_x_256[i].b; | ||
560 | |||
561 | if (i < max_number - 1) | ||
562 | right = axis_x_256[i + 1].b; | ||
563 | else | ||
564 | right = axis_x_256[max_number - 1].b; | ||
565 | } | ||
566 | |||
567 | if (dal_fixed31_32_le(left, hw_point) && | ||
568 | dal_fixed31_32_le(hw_point, right)) { | ||
569 | *index_to_start = i; | ||
570 | *index_left = i; | ||
571 | |||
572 | if (i < max_number - 1) | ||
573 | *index_right = i + 1; | ||
574 | else | ||
575 | *index_right = max_number - 1; | ||
576 | |||
577 | *pos = HW_POINT_POSITION_MIDDLE; | ||
578 | |||
579 | return true; | ||
580 | } else if ((i == *index_to_start) && | ||
581 | dal_fixed31_32_le(hw_point, left)) { | ||
582 | *index_to_start = i; | ||
583 | *index_left = i; | ||
584 | *index_right = i; | ||
585 | |||
586 | *pos = HW_POINT_POSITION_LEFT; | ||
587 | |||
588 | return true; | ||
589 | } else if ((i == max_number - 1) && | ||
590 | dal_fixed31_32_le(right, hw_point)) { | ||
591 | *index_to_start = i; | ||
592 | *index_left = i; | ||
593 | *index_right = i; | ||
594 | |||
595 | *pos = HW_POINT_POSITION_RIGHT; | ||
596 | |||
597 | return true; | ||
598 | } | ||
599 | |||
600 | ++i; | ||
601 | } | ||
602 | |||
603 | return false; | ||
604 | } | ||
605 | |||
606 | static bool build_custom_gamma_mapping_coefficients_worker( | ||
607 | struct pixel_gamma_point *coeff, | ||
608 | const struct hw_x_point *coordinates_x, | ||
609 | const struct gamma_pixel *axis_x_256, | ||
610 | enum channel_name channel, | ||
611 | uint32_t number_of_points, | ||
612 | enum surface_pixel_format pixel_format) | ||
613 | { | ||
614 | uint32_t i = 0; | ||
615 | |||
616 | while (i <= number_of_points) { | ||
617 | struct fixed31_32 coord_x; | ||
618 | |||
619 | uint32_t index_to_start = 0; | ||
620 | uint32_t index_left = 0; | ||
621 | uint32_t index_right = 0; | ||
622 | |||
623 | enum hw_point_position hw_pos; | ||
624 | |||
625 | struct gamma_point *point; | ||
626 | |||
627 | struct fixed31_32 left_pos; | ||
628 | struct fixed31_32 right_pos; | ||
629 | |||
630 | /* | ||
631 | * TODO: confirm enum in surface_pixel_format | ||
632 | * if (pixel_format == PIXEL_FORMAT_FP16) | ||
633 | *coord_x = coordinates_x[i].adjusted_x; | ||
634 | *else | ||
635 | */ | ||
636 | if (channel == CHANNEL_NAME_RED) | ||
637 | coord_x = coordinates_x[i].regamma_y_red; | ||
638 | else if (channel == CHANNEL_NAME_GREEN) | ||
639 | coord_x = coordinates_x[i].regamma_y_green; | ||
640 | else | ||
641 | coord_x = coordinates_x[i].regamma_y_blue; | ||
642 | |||
643 | if (!find_software_points( | ||
644 | axis_x_256, coord_x, channel, | ||
645 | &index_to_start, &index_left, &index_right, &hw_pos)) { | ||
646 | BREAK_TO_DEBUGGER(); | ||
647 | return false; | ||
648 | } | ||
649 | |||
650 | if (index_left >= INPUT_LUT_ENTRIES + 3) { | ||
651 | BREAK_TO_DEBUGGER(); | ||
652 | return false; | ||
653 | } | ||
654 | |||
655 | if (index_right >= INPUT_LUT_ENTRIES + 3) { | ||
656 | BREAK_TO_DEBUGGER(); | ||
657 | return false; | ||
658 | } | ||
659 | |||
660 | if (channel == CHANNEL_NAME_RED) { | ||
661 | point = &coeff[i].r; | ||
662 | |||
663 | left_pos = axis_x_256[index_left].r; | ||
664 | right_pos = axis_x_256[index_right].r; | ||
665 | } else if (channel == CHANNEL_NAME_GREEN) { | ||
666 | point = &coeff[i].g; | ||
667 | |||
668 | left_pos = axis_x_256[index_left].g; | ||
669 | right_pos = axis_x_256[index_right].g; | ||
670 | } else { | ||
671 | point = &coeff[i].b; | ||
672 | |||
673 | left_pos = axis_x_256[index_left].b; | ||
674 | right_pos = axis_x_256[index_right].b; | ||
675 | } | ||
676 | |||
677 | if (hw_pos == HW_POINT_POSITION_MIDDLE) | ||
678 | point->coeff = dal_fixed31_32_div( | ||
679 | dal_fixed31_32_sub( | ||
680 | coord_x, | ||
681 | left_pos), | ||
682 | dal_fixed31_32_sub( | ||
683 | right_pos, | ||
684 | left_pos)); | ||
685 | else if (hw_pos == HW_POINT_POSITION_LEFT) | ||
686 | point->coeff = dal_fixed31_32_zero; | ||
687 | else if (hw_pos == HW_POINT_POSITION_RIGHT) | ||
688 | point->coeff = dal_fixed31_32_from_int(2); | ||
689 | else { | ||
690 | BREAK_TO_DEBUGGER(); | ||
691 | return false; | ||
692 | } | ||
693 | |||
694 | point->left_index = index_left; | ||
695 | point->right_index = index_right; | ||
696 | point->pos = hw_pos; | ||
697 | |||
698 | ++i; | ||
699 | } | ||
700 | |||
701 | return true; | ||
702 | } | ||
703 | |||
704 | static inline bool build_oem_custom_gamma_mapping_coefficients( | ||
705 | struct pixel_gamma_point *coeff128_oem, | ||
706 | const struct hw_x_point *coordinates_x, | ||
707 | const struct gamma_pixel *axis_x_256, | ||
708 | uint32_t number_of_points, | ||
709 | enum surface_pixel_format pixel_format) | ||
710 | { | ||
711 | int i; | ||
712 | |||
713 | for (i = 0; i < 3; i++) { | ||
714 | if (!build_custom_gamma_mapping_coefficients_worker( | ||
715 | coeff128_oem, coordinates_x, axis_x_256, i, | ||
716 | number_of_points, pixel_format)) | ||
717 | return false; | ||
718 | } | ||
719 | return true; | ||
720 | } | ||
721 | |||
722 | static struct fixed31_32 calculate_mapped_value( | ||
723 | struct pwl_float_data *rgb, | ||
724 | const struct pixel_gamma_point *coeff, | ||
725 | enum channel_name channel, | ||
726 | uint32_t max_index) | ||
727 | { | ||
728 | const struct gamma_point *point; | ||
729 | |||
730 | struct fixed31_32 result; | ||
731 | |||
732 | if (channel == CHANNEL_NAME_RED) | ||
733 | point = &coeff->r; | ||
734 | else if (channel == CHANNEL_NAME_GREEN) | ||
735 | point = &coeff->g; | ||
736 | else | ||
737 | point = &coeff->b; | ||
738 | |||
739 | if ((point->left_index < 0) || (point->left_index > max_index)) { | ||
740 | BREAK_TO_DEBUGGER(); | ||
741 | return dal_fixed31_32_zero; | ||
742 | } | ||
743 | |||
744 | if ((point->right_index < 0) || (point->right_index > max_index)) { | ||
745 | BREAK_TO_DEBUGGER(); | ||
746 | return dal_fixed31_32_zero; | ||
747 | } | ||
748 | |||
749 | if (point->pos == HW_POINT_POSITION_MIDDLE) | ||
750 | if (channel == CHANNEL_NAME_RED) | ||
751 | result = dal_fixed31_32_add( | ||
752 | dal_fixed31_32_mul( | ||
753 | point->coeff, | ||
754 | dal_fixed31_32_sub( | ||
755 | rgb[point->right_index].r, | ||
756 | rgb[point->left_index].r)), | ||
757 | rgb[point->left_index].r); | ||
758 | else if (channel == CHANNEL_NAME_GREEN) | ||
759 | result = dal_fixed31_32_add( | ||
760 | dal_fixed31_32_mul( | ||
761 | point->coeff, | ||
762 | dal_fixed31_32_sub( | ||
763 | rgb[point->right_index].g, | ||
764 | rgb[point->left_index].g)), | ||
765 | rgb[point->left_index].g); | ||
766 | else | ||
767 | result = dal_fixed31_32_add( | ||
768 | dal_fixed31_32_mul( | ||
769 | point->coeff, | ||
770 | dal_fixed31_32_sub( | ||
771 | rgb[point->right_index].b, | ||
772 | rgb[point->left_index].b)), | ||
773 | rgb[point->left_index].b); | ||
774 | else if (point->pos == HW_POINT_POSITION_LEFT) { | ||
775 | BREAK_TO_DEBUGGER(); | ||
776 | result = dal_fixed31_32_zero; | ||
777 | } else { | ||
778 | BREAK_TO_DEBUGGER(); | ||
779 | result = dal_fixed31_32_one; | ||
780 | } | ||
781 | |||
782 | return result; | ||
783 | } | ||
784 | |||
785 | static inline struct fixed31_32 calculate_oem_mapped_value( | ||
786 | struct pwl_float_data *rgb_oem, | ||
787 | const struct pixel_gamma_point *coeff, | ||
788 | uint32_t index, | ||
789 | enum channel_name channel, | ||
790 | uint32_t max_index) | ||
791 | { | ||
792 | return calculate_mapped_value( | ||
793 | rgb_oem, | ||
794 | coeff + index, | ||
795 | channel, | ||
796 | max_index); | ||
797 | } | ||
798 | |||
799 | static void compute_pq(struct fixed31_32 in_x, struct fixed31_32 *out_y) | ||
800 | { | ||
801 | /* consts for PQ gamma formula. */ | ||
802 | const struct fixed31_32 m1 = | ||
803 | dal_fixed31_32_from_fraction(159301758, 1000000000); | ||
804 | const struct fixed31_32 m2 = | ||
805 | dal_fixed31_32_from_fraction(7884375, 100000); | ||
806 | const struct fixed31_32 c1 = | ||
807 | dal_fixed31_32_from_fraction(8359375, 10000000); | ||
808 | const struct fixed31_32 c2 = | ||
809 | dal_fixed31_32_from_fraction(188515625, 10000000); | ||
810 | const struct fixed31_32 c3 = | ||
811 | dal_fixed31_32_from_fraction(186875, 10000); | ||
812 | |||
813 | struct fixed31_32 l_pow_m1; | ||
814 | struct fixed31_32 base; | ||
815 | |||
816 | if (dal_fixed31_32_lt(in_x, dal_fixed31_32_zero)) | ||
817 | in_x = dal_fixed31_32_zero; | ||
818 | |||
819 | l_pow_m1 = dal_fixed31_32_pow(in_x, m1); | ||
820 | base = dal_fixed31_32_div( | ||
821 | dal_fixed31_32_add(c1, | ||
822 | (dal_fixed31_32_mul(c2, l_pow_m1))), | ||
823 | dal_fixed31_32_add(dal_fixed31_32_one, | ||
824 | (dal_fixed31_32_mul(c3, l_pow_m1)))); | ||
825 | *out_y = dal_fixed31_32_pow(base, m2); | ||
826 | } | ||
827 | |||
828 | static void build_regamma_curve_pq(struct pwl_float_data_ex *rgb_regamma, | ||
829 | struct pwl_float_data *rgb_oem, | ||
830 | struct pixel_gamma_point *coeff128_oem, | ||
831 | const struct core_gamma *ramp, | ||
832 | const struct core_surface *surface, | ||
833 | uint32_t hw_points_num, | ||
834 | const struct hw_x_point *coordinate_x, | ||
835 | const struct gamma_pixel *axis_x, | ||
836 | struct dividers dividers) | ||
837 | { | ||
838 | uint32_t i; | ||
839 | |||
840 | struct pwl_float_data_ex *rgb = rgb_regamma; | ||
841 | const struct hw_x_point *coord_x = coordinate_x; | ||
842 | struct fixed31_32 x; | ||
843 | struct fixed31_32 output; | ||
844 | struct fixed31_32 scaling_factor = | ||
845 | dal_fixed31_32_from_fraction(8, 1000); | ||
846 | |||
847 | /* use coord_x to retrieve coordinates chosen base on given user curve | ||
848 | * the x values are exponentially distributed and currently it is hard | ||
849 | * coded, the user curve shape is ignored. Need to recalculate coord_x | ||
850 | * based on input curve, translation from 256/1025 to 128 PWL points. | ||
851 | */ | ||
852 | for (i = 0; i <= hw_points_num; i++) { | ||
853 | /* Multiply 0.008 as regamma is 0-1 and FP16 input is 0-125. | ||
854 | * FP 1.0 = 80nits | ||
855 | */ | ||
856 | x = dal_fixed31_32_mul(coord_x->adjusted_x, scaling_factor); | ||
857 | |||
858 | compute_pq(x, &output); | ||
859 | |||
860 | /* should really not happen? */ | ||
861 | if (dal_fixed31_32_lt(output, dal_fixed31_32_zero)) | ||
862 | output = dal_fixed31_32_zero; | ||
863 | else if (dal_fixed31_32_lt(dal_fixed31_32_one, output)) | ||
864 | output = dal_fixed31_32_one; | ||
865 | |||
866 | rgb->r = output; | ||
867 | rgb->g = output; | ||
868 | rgb->b = output; | ||
869 | |||
870 | ++coord_x; | ||
871 | ++rgb; | ||
872 | } | ||
873 | } | ||
874 | |||
875 | static void build_regamma_curve(struct pwl_float_data_ex *rgb_regamma, | ||
876 | struct pwl_float_data *rgb_oem, | ||
877 | struct pixel_gamma_point *coeff128_oem, | ||
878 | const struct core_gamma *ramp, | ||
879 | const struct core_surface *surface, | ||
880 | uint32_t hw_points_num, | ||
881 | const struct hw_x_point *coordinate_x, | ||
882 | const struct gamma_pixel *axis_x, | ||
883 | struct dividers dividers) | ||
884 | { | ||
885 | uint32_t i; | ||
886 | |||
887 | struct gamma_coefficients coeff; | ||
888 | struct pwl_float_data_ex *rgb = rgb_regamma; | ||
889 | const struct hw_x_point *coord_x = coordinate_x; | ||
890 | |||
891 | build_regamma_coefficients(&coeff); | ||
892 | |||
893 | /* Use opp110->regamma.coordinates_x to retrieve | ||
894 | * coordinates chosen base on given user curve (future task). | ||
895 | * The x values are exponentially distributed and currently | ||
896 | * it is hard-coded, the user curve shape is ignored. | ||
897 | * The future task is to recalculate opp110- | ||
898 | * regamma.coordinates_x based on input/user curve, | ||
899 | * translation from 256/1025 to 128 pwl points. | ||
900 | */ | ||
901 | |||
902 | i = 0; | ||
903 | |||
904 | while (i != hw_points_num + 1) { | ||
905 | rgb->r = translate_from_linear_space_ex( | ||
906 | coord_x->adjusted_x, &coeff, 0); | ||
907 | rgb->g = translate_from_linear_space_ex( | ||
908 | coord_x->adjusted_x, &coeff, 1); | ||
909 | rgb->b = translate_from_linear_space_ex( | ||
910 | coord_x->adjusted_x, &coeff, 2); | ||
911 | |||
912 | ++coord_x; | ||
913 | ++rgb; | ||
914 | ++i; | ||
915 | } | ||
916 | } | ||
917 | |||
918 | static bool scale_gamma(struct pwl_float_data *pwl_rgb, | ||
919 | const struct core_gamma *ramp, | ||
920 | struct dividers dividers) | ||
921 | { | ||
922 | const struct dc_gamma *gamma = &ramp->public; | ||
923 | const uint16_t max_driver = 0xFFFF; | ||
924 | const uint16_t max_os = 0xFF00; | ||
925 | uint16_t scaler = max_os; | ||
926 | uint32_t i = 0; | ||
927 | struct pwl_float_data *rgb = pwl_rgb; | ||
928 | struct pwl_float_data *rgb_last = rgb + INPUT_LUT_ENTRIES - 1; | ||
929 | |||
930 | do { | ||
931 | if ((gamma->red[i] > max_os) || | ||
932 | (gamma->green[i] > max_os) || | ||
933 | (gamma->blue[i] > max_os)) { | ||
934 | scaler = max_driver; | ||
935 | break; | ||
936 | } | ||
937 | ++i; | ||
938 | } while (i != INPUT_LUT_ENTRIES); | ||
939 | |||
940 | i = 0; | ||
941 | |||
942 | do { | ||
943 | rgb->r = dal_fixed31_32_from_fraction( | ||
944 | gamma->red[i], scaler); | ||
945 | rgb->g = dal_fixed31_32_from_fraction( | ||
946 | gamma->green[i], scaler); | ||
947 | rgb->b = dal_fixed31_32_from_fraction( | ||
948 | gamma->blue[i], scaler); | ||
949 | |||
950 | ++rgb; | ||
951 | ++i; | ||
952 | } while (i != INPUT_LUT_ENTRIES); | ||
953 | |||
954 | rgb->r = dal_fixed31_32_mul(rgb_last->r, | ||
955 | dividers.divider1); | ||
956 | rgb->g = dal_fixed31_32_mul(rgb_last->g, | ||
957 | dividers.divider1); | ||
958 | rgb->b = dal_fixed31_32_mul(rgb_last->b, | ||
959 | dividers.divider1); | ||
960 | |||
961 | ++rgb; | ||
962 | |||
963 | rgb->r = dal_fixed31_32_mul(rgb_last->r, | ||
964 | dividers.divider2); | ||
965 | rgb->g = dal_fixed31_32_mul(rgb_last->g, | ||
966 | dividers.divider2); | ||
967 | rgb->b = dal_fixed31_32_mul(rgb_last->b, | ||
968 | dividers.divider2); | ||
969 | |||
970 | ++rgb; | ||
971 | |||
972 | rgb->r = dal_fixed31_32_mul(rgb_last->r, | ||
973 | dividers.divider3); | ||
974 | rgb->g = dal_fixed31_32_mul(rgb_last->g, | ||
975 | dividers.divider3); | ||
976 | rgb->b = dal_fixed31_32_mul(rgb_last->b, | ||
977 | dividers.divider3); | ||
978 | |||
979 | return true; | ||
980 | } | ||
981 | |||
982 | static void build_evenly_distributed_points( | ||
983 | struct gamma_pixel *points, | ||
984 | uint32_t numberof_points, | ||
985 | struct fixed31_32 max_value, | ||
986 | struct dividers dividers) | ||
987 | { | ||
988 | struct gamma_pixel *p = points; | ||
989 | struct gamma_pixel *p_last = p + numberof_points - 1; | ||
990 | |||
991 | uint32_t i = 0; | ||
992 | |||
993 | do { | ||
994 | struct fixed31_32 value = dal_fixed31_32_div_int( | ||
995 | dal_fixed31_32_mul_int(max_value, i), | ||
996 | numberof_points - 1); | ||
997 | |||
998 | p->r = value; | ||
999 | p->g = value; | ||
1000 | p->b = value; | ||
1001 | |||
1002 | ++p; | ||
1003 | ++i; | ||
1004 | } while (i != numberof_points); | ||
1005 | |||
1006 | p->r = dal_fixed31_32_div(p_last->r, dividers.divider1); | ||
1007 | p->g = dal_fixed31_32_div(p_last->g, dividers.divider1); | ||
1008 | p->b = dal_fixed31_32_div(p_last->b, dividers.divider1); | ||
1009 | |||
1010 | ++p; | ||
1011 | |||
1012 | p->r = dal_fixed31_32_div(p_last->r, dividers.divider2); | ||
1013 | p->g = dal_fixed31_32_div(p_last->g, dividers.divider2); | ||
1014 | p->b = dal_fixed31_32_div(p_last->b, dividers.divider2); | ||
1015 | |||
1016 | ++p; | ||
1017 | |||
1018 | p->r = dal_fixed31_32_div(p_last->r, dividers.divider3); | ||
1019 | p->g = dal_fixed31_32_div(p_last->g, dividers.divider3); | ||
1020 | p->b = dal_fixed31_32_div(p_last->b, dividers.divider3); | ||
1021 | } | ||
1022 | |||
1023 | static inline void copy_rgb_regamma_to_coordinates_x( | ||
1024 | struct hw_x_point *coordinates_x, | ||
1025 | uint32_t hw_points_num, | ||
1026 | const struct pwl_float_data_ex *rgb_ex) | ||
1027 | { | ||
1028 | struct hw_x_point *coords = coordinates_x; | ||
1029 | uint32_t i = 0; | ||
1030 | const struct pwl_float_data_ex *rgb_regamma = rgb_ex; | ||
1031 | |||
1032 | while (i <= hw_points_num) { | ||
1033 | coords->regamma_y_red = rgb_regamma->r; | ||
1034 | coords->regamma_y_green = rgb_regamma->g; | ||
1035 | coords->regamma_y_blue = rgb_regamma->b; | ||
1036 | |||
1037 | ++coords; | ||
1038 | ++rgb_regamma; | ||
1039 | ++i; | ||
1040 | } | ||
1041 | } | ||
1042 | |||
1043 | static bool calculate_interpolated_hardware_curve( | ||
1044 | struct pwl_result_data *rgb, | ||
1045 | struct pixel_gamma_point *coeff128, | ||
1046 | struct pwl_float_data *rgb_user, | ||
1047 | const struct hw_x_point *coordinates_x, | ||
1048 | const struct gamma_pixel *axis_x_256, | ||
1049 | uint32_t number_of_points, | ||
1050 | enum surface_pixel_format pixel_format) | ||
1051 | { | ||
1052 | |||
1053 | const struct pixel_gamma_point *coeff; | ||
1054 | struct pixel_gamma_point *coeff_128 = coeff128; | ||
1055 | uint32_t max_entries = 3 - 1; | ||
1056 | struct pwl_result_data *rgb_resulted = rgb; | ||
1057 | |||
1058 | uint32_t i = 0; | ||
1059 | |||
1060 | if (!build_oem_custom_gamma_mapping_coefficients( | ||
1061 | coeff_128, coordinates_x, axis_x_256, | ||
1062 | number_of_points, | ||
1063 | pixel_format)) | ||
1064 | return false; | ||
1065 | |||
1066 | coeff = coeff128; | ||
1067 | max_entries += INPUT_LUT_ENTRIES; | ||
1068 | |||
1069 | /* TODO: float point case */ | ||
1070 | |||
1071 | while (i <= number_of_points) { | ||
1072 | rgb_resulted->red = calculate_mapped_value( | ||
1073 | rgb_user, coeff, CHANNEL_NAME_RED, max_entries); | ||
1074 | rgb_resulted->green = calculate_mapped_value( | ||
1075 | rgb_user, coeff, CHANNEL_NAME_GREEN, max_entries); | ||
1076 | rgb_resulted->blue = calculate_mapped_value( | ||
1077 | rgb_user, coeff, CHANNEL_NAME_BLUE, max_entries); | ||
1078 | |||
1079 | ++coeff; | ||
1080 | ++rgb_resulted; | ||
1081 | ++i; | ||
1082 | } | ||
1083 | |||
1084 | return true; | ||
1085 | } | ||
1086 | |||
1087 | static bool map_regamma_hw_to_x_user( | ||
1088 | struct pixel_gamma_point *coeff128, | ||
1089 | struct pwl_float_data *rgb_oem, | ||
1090 | struct pwl_result_data *rgb_resulted, | ||
1091 | struct pwl_float_data *rgb_user, | ||
1092 | struct hw_x_point *coords_x, | ||
1093 | const struct gamma_pixel *axis_x, | ||
1094 | const struct dc_gamma *gamma, | ||
1095 | const struct pwl_float_data_ex *rgb_regamma, | ||
1096 | struct dividers dividers, | ||
1097 | uint32_t hw_points_num, | ||
1098 | const struct core_surface *surface) | ||
1099 | { | ||
1100 | /* setup to spare calculated ideal regamma values */ | ||
1101 | |||
1102 | struct pixel_gamma_point *coeff = coeff128; | ||
1103 | |||
1104 | struct hw_x_point *coords = coords_x; | ||
1105 | |||
1106 | copy_rgb_regamma_to_coordinates_x(coords, hw_points_num, rgb_regamma); | ||
1107 | |||
1108 | return calculate_interpolated_hardware_curve( | ||
1109 | rgb_resulted, coeff, rgb_user, coords, axis_x, | ||
1110 | hw_points_num, surface->public.format); | ||
1111 | } | ||
1112 | |||
1113 | static void build_new_custom_resulted_curve( | ||
1114 | struct pwl_result_data *rgb_resulted, | ||
1115 | uint32_t hw_points_num) | ||
1116 | { | ||
1117 | struct pwl_result_data *rgb = rgb_resulted; | ||
1118 | struct pwl_result_data *rgb_plus_1 = rgb + 1; | ||
1119 | |||
1120 | uint32_t i; | ||
1121 | |||
1122 | i = 0; | ||
1123 | |||
1124 | while (i != hw_points_num + 1) { | ||
1125 | rgb->red = dal_fixed31_32_clamp( | ||
1126 | rgb->red, dal_fixed31_32_zero, | ||
1127 | dal_fixed31_32_one); | ||
1128 | rgb->green = dal_fixed31_32_clamp( | ||
1129 | rgb->green, dal_fixed31_32_zero, | ||
1130 | dal_fixed31_32_one); | ||
1131 | rgb->blue = dal_fixed31_32_clamp( | ||
1132 | rgb->blue, dal_fixed31_32_zero, | ||
1133 | dal_fixed31_32_one); | ||
1134 | |||
1135 | ++rgb; | ||
1136 | ++i; | ||
1137 | } | ||
1138 | |||
1139 | rgb = rgb_resulted; | ||
1140 | |||
1141 | i = 1; | ||
1142 | |||
1143 | while (i != hw_points_num + 1) { | ||
1144 | if (dal_fixed31_32_lt(rgb_plus_1->red, rgb->red)) | ||
1145 | rgb_plus_1->red = rgb->red; | ||
1146 | if (dal_fixed31_32_lt(rgb_plus_1->green, rgb->green)) | ||
1147 | rgb_plus_1->green = rgb->green; | ||
1148 | if (dal_fixed31_32_lt(rgb_plus_1->blue, rgb->blue)) | ||
1149 | rgb_plus_1->blue = rgb->blue; | ||
1150 | |||
1151 | rgb->delta_red = dal_fixed31_32_sub( | ||
1152 | rgb_plus_1->red, | ||
1153 | rgb->red); | ||
1154 | rgb->delta_green = dal_fixed31_32_sub( | ||
1155 | rgb_plus_1->green, | ||
1156 | rgb->green); | ||
1157 | rgb->delta_blue = dal_fixed31_32_sub( | ||
1158 | rgb_plus_1->blue, | ||
1159 | rgb->blue); | ||
1160 | |||
1161 | ++rgb_plus_1; | ||
1162 | ++rgb; | ||
1163 | ++i; | ||
1164 | } | ||
1165 | } | ||
1166 | |||
1167 | static void rebuild_curve_configuration_magic( | ||
1168 | struct curve_points *arr_points, | ||
1169 | struct pwl_result_data *rgb_resulted, | ||
1170 | const struct hw_x_point *coordinates_x, | ||
1171 | uint32_t hw_points_num, | ||
1172 | enum dc_transfer_func_predefined tf) | ||
1173 | { | ||
1174 | struct fixed31_32 y_r; | ||
1175 | struct fixed31_32 y_g; | ||
1176 | struct fixed31_32 y_b; | ||
1177 | |||
1178 | struct fixed31_32 y1_min; | ||
1179 | struct fixed31_32 y3_max; | ||
1180 | |||
1181 | y_r = rgb_resulted[0].red; | ||
1182 | y_g = rgb_resulted[0].green; | ||
1183 | y_b = rgb_resulted[0].blue; | ||
1184 | |||
1185 | y1_min = dal_fixed31_32_min(y_r, dal_fixed31_32_min(y_g, y_b)); | ||
1186 | |||
1187 | arr_points[0].x = coordinates_x[0].adjusted_x; | ||
1188 | arr_points[0].y = y1_min; | ||
1189 | arr_points[0].slope = dal_fixed31_32_div( | ||
1190 | arr_points[0].y, | ||
1191 | arr_points[0].x); | ||
1192 | |||
1193 | /* this should be cleaned up as it's confusing my understanding (KK) is | ||
1194 | * that REGAMMA_CNTLA_EXP_REGION_END is the X value for the region end | ||
1195 | * REGAMMA_CNTLA_EXP_REGION_END_BASE is Y value for the above X | ||
1196 | * REGAMMA_CNTLA_EXP_REGION_END_SLOPE is the slope beyond (X,Y) above | ||
1197 | * currently when programming REGION_END = m_arrPoints[1].x, | ||
1198 | * REGION_END_BASE = m_arrPoints[1].y, REGION_END_SLOPE=1 | ||
1199 | * we don't use m_arrPoints[2] at all after this function, | ||
1200 | * and its purpose isn't clear to me | ||
1201 | */ | ||
1202 | arr_points[1].x = coordinates_x[hw_points_num].adjusted_x; | ||
1203 | arr_points[2].x = coordinates_x[hw_points_num].adjusted_x; | ||
1204 | |||
1205 | y_r = rgb_resulted[hw_points_num].red; | ||
1206 | y_g = rgb_resulted[hw_points_num].green; | ||
1207 | y_b = rgb_resulted[hw_points_num].blue; | ||
1208 | |||
1209 | /* see comment above, m_arrPoints[1].y should be the Y value for the | ||
1210 | * region end (m_numOfHwPoints), not last HW point(m_numOfHwPoints - 1) | ||
1211 | */ | ||
1212 | y3_max = dal_fixed31_32_max(y_r, dal_fixed31_32_max(y_g, y_b)); | ||
1213 | |||
1214 | arr_points[1].y = y3_max; | ||
1215 | arr_points[2].y = y3_max; | ||
1216 | |||
1217 | arr_points[2].slope = dal_fixed31_32_zero; | ||
1218 | |||
1219 | /* for PQ, we want to have a straight line from last HW X point, and the | ||
1220 | * slope to be such that we hit 1.0 at 10000 nits. | ||
1221 | */ | ||
1222 | if (tf == TRANSFER_FUNCTION_PQ) { | ||
1223 | const struct fixed31_32 end_value = | ||
1224 | dal_fixed31_32_from_int(125); | ||
1225 | |||
1226 | arr_points[2].slope = dal_fixed31_32_div( | ||
1227 | dal_fixed31_32_sub(dal_fixed31_32_one, arr_points[1].y), | ||
1228 | dal_fixed31_32_sub(end_value, arr_points[1].x)); | ||
1229 | } | ||
1230 | } | ||
1231 | |||
1232 | static bool convert_to_custom_float_format( | ||
1233 | struct fixed31_32 value, | ||
1234 | const struct custom_float_format *format, | ||
1235 | uint32_t *result) | ||
1236 | { | ||
1237 | uint32_t mantissa; | ||
1238 | uint32_t exponenta; | ||
1239 | bool negative; | ||
1240 | |||
1241 | return build_custom_float( | ||
1242 | value, format, &negative, &mantissa, &exponenta) && | ||
1243 | setup_custom_float( | ||
1244 | format, negative, mantissa, exponenta, result); | ||
1245 | } | ||
1246 | |||
1247 | static bool convert_to_custom_float( | ||
1248 | struct pwl_result_data *rgb_resulted, | ||
1249 | struct curve_points *arr_points, | ||
1250 | uint32_t hw_points_num) | ||
1251 | { | ||
1252 | struct custom_float_format fmt; | ||
1253 | |||
1254 | struct pwl_result_data *rgb = rgb_resulted; | ||
1255 | |||
1256 | uint32_t i = 0; | ||
1257 | |||
1258 | fmt.exponenta_bits = 6; | ||
1259 | fmt.mantissa_bits = 12; | ||
1260 | fmt.sign = true; | ||
1261 | |||
1262 | if (!convert_to_custom_float_format( | ||
1263 | arr_points[0].x, | ||
1264 | &fmt, | ||
1265 | &arr_points[0].custom_float_x)) { | ||
1266 | BREAK_TO_DEBUGGER(); | ||
1267 | return false; | ||
1268 | } | ||
1269 | |||
1270 | if (!convert_to_custom_float_format( | ||
1271 | arr_points[0].offset, | ||
1272 | &fmt, | ||
1273 | &arr_points[0].custom_float_offset)) { | ||
1274 | BREAK_TO_DEBUGGER(); | ||
1275 | return false; | ||
1276 | } | ||
1277 | |||
1278 | if (!convert_to_custom_float_format( | ||
1279 | arr_points[0].slope, | ||
1280 | &fmt, | ||
1281 | &arr_points[0].custom_float_slope)) { | ||
1282 | BREAK_TO_DEBUGGER(); | ||
1283 | return false; | ||
1284 | } | ||
1285 | |||
1286 | fmt.mantissa_bits = 10; | ||
1287 | fmt.sign = false; | ||
1288 | |||
1289 | if (!convert_to_custom_float_format( | ||
1290 | arr_points[1].x, | ||
1291 | &fmt, | ||
1292 | &arr_points[1].custom_float_x)) { | ||
1293 | BREAK_TO_DEBUGGER(); | ||
1294 | return false; | ||
1295 | } | ||
1296 | |||
1297 | if (!convert_to_custom_float_format( | ||
1298 | arr_points[1].y, | ||
1299 | &fmt, | ||
1300 | &arr_points[1].custom_float_y)) { | ||
1301 | BREAK_TO_DEBUGGER(); | ||
1302 | return false; | ||
1303 | } | ||
1304 | |||
1305 | if (!convert_to_custom_float_format( | ||
1306 | arr_points[2].slope, | ||
1307 | &fmt, | ||
1308 | &arr_points[2].custom_float_slope)) { | ||
1309 | BREAK_TO_DEBUGGER(); | ||
1310 | return false; | ||
1311 | } | ||
1312 | |||
1313 | fmt.mantissa_bits = 12; | ||
1314 | fmt.sign = true; | ||
1315 | |||
1316 | while (i != hw_points_num) { | ||
1317 | if (!convert_to_custom_float_format( | ||
1318 | rgb->red, | ||
1319 | &fmt, | ||
1320 | &rgb->red_reg)) { | ||
1321 | BREAK_TO_DEBUGGER(); | ||
1322 | return false; | ||
1323 | } | ||
1324 | |||
1325 | if (!convert_to_custom_float_format( | ||
1326 | rgb->green, | ||
1327 | &fmt, | ||
1328 | &rgb->green_reg)) { | ||
1329 | BREAK_TO_DEBUGGER(); | ||
1330 | return false; | ||
1331 | } | ||
1332 | |||
1333 | if (!convert_to_custom_float_format( | ||
1334 | rgb->blue, | ||
1335 | &fmt, | ||
1336 | &rgb->blue_reg)) { | ||
1337 | BREAK_TO_DEBUGGER(); | ||
1338 | return false; | ||
1339 | } | ||
1340 | |||
1341 | if (!convert_to_custom_float_format( | ||
1342 | rgb->delta_red, | ||
1343 | &fmt, | ||
1344 | &rgb->delta_red_reg)) { | ||
1345 | BREAK_TO_DEBUGGER(); | ||
1346 | return false; | ||
1347 | } | ||
1348 | |||
1349 | if (!convert_to_custom_float_format( | ||
1350 | rgb->delta_green, | ||
1351 | &fmt, | ||
1352 | &rgb->delta_green_reg)) { | ||
1353 | BREAK_TO_DEBUGGER(); | ||
1354 | return false; | ||
1355 | } | ||
1356 | |||
1357 | if (!convert_to_custom_float_format( | ||
1358 | rgb->delta_blue, | ||
1359 | &fmt, | ||
1360 | &rgb->delta_blue_reg)) { | ||
1361 | BREAK_TO_DEBUGGER(); | ||
1362 | return false; | ||
1363 | } | ||
1364 | |||
1365 | ++rgb; | ||
1366 | ++i; | ||
1367 | } | ||
1368 | |||
1369 | return true; | ||
1370 | } | ||
1371 | |||
1372 | bool calculate_regamma_params(struct pwl_params *params, | ||
1373 | const struct core_gamma *ramp, | ||
1374 | const struct core_surface *surface, | ||
1375 | const struct core_stream *stream) | ||
1376 | { | ||
1377 | struct gamma_curve *arr_curve_points = params->arr_curve_points; | ||
1378 | struct curve_points *arr_points = params->arr_points; | ||
1379 | struct pwl_result_data *rgb_resulted = params->rgb_resulted; | ||
1380 | struct dividers dividers; | ||
1381 | |||
1382 | struct hw_x_point *coordinates_x = NULL; | ||
1383 | struct pwl_float_data *rgb_user = NULL ; | ||
1384 | struct pwl_float_data_ex *rgb_regamma = NULL; | ||
1385 | struct pwl_float_data *rgb_oem = NULL; | ||
1386 | struct gamma_pixel *axix_x_256 = NULL; | ||
1387 | struct pixel_gamma_point *coeff128_oem = NULL; | ||
1388 | struct pixel_gamma_point *coeff128 = NULL; | ||
1389 | |||
1390 | enum dc_transfer_func_predefined tf = TRANSFER_FUNCTION_SRGB; | ||
1391 | |||
1392 | bool ret = false; | ||
1393 | |||
1394 | coordinates_x = dm_alloc(sizeof(*coordinates_x)*(256 + 3)); | ||
1395 | if (!coordinates_x) | ||
1396 | goto coordinates_x_alloc_fail; | ||
1397 | rgb_user = dm_alloc(sizeof(*rgb_user) * (TRANSFER_FUNC_POINTS + 3)); | ||
1398 | if (!rgb_user) | ||
1399 | goto rgb_user_alloc_fail; | ||
1400 | rgb_regamma = dm_alloc(sizeof(*rgb_regamma) * (256 + 3)); | ||
1401 | if (!rgb_regamma) | ||
1402 | goto rgb_regamma_alloc_fail; | ||
1403 | rgb_oem = dm_alloc(sizeof(*rgb_oem) * (TRANSFER_FUNC_POINTS + 3)); | ||
1404 | if (!rgb_oem) | ||
1405 | goto rgb_oem_alloc_fail; | ||
1406 | axix_x_256 = dm_alloc(sizeof(*axix_x_256) * (256 + 3)); | ||
1407 | if (!axix_x_256) | ||
1408 | goto axix_x_256_alloc_fail; | ||
1409 | coeff128_oem = dm_alloc(sizeof(*coeff128_oem) * (256 + 3)); | ||
1410 | if (!coeff128_oem) | ||
1411 | goto coeff128_oem_alloc_fail; | ||
1412 | coeff128 = dm_alloc(sizeof(*coeff128) * (256 + 3)); | ||
1413 | if (!coeff128) | ||
1414 | goto coeff128_alloc_fail; | ||
1415 | |||
1416 | dividers.divider1 = dal_fixed31_32_from_fraction(3, 2); | ||
1417 | dividers.divider2 = dal_fixed31_32_from_int(2); | ||
1418 | dividers.divider3 = dal_fixed31_32_from_fraction(5, 2); | ||
1419 | |||
1420 | if (stream->public.out_transfer_func) | ||
1421 | tf = stream->public.out_transfer_func->tf; | ||
1422 | |||
1423 | build_evenly_distributed_points( | ||
1424 | axix_x_256, | ||
1425 | 256, | ||
1426 | dal_fixed31_32_one, | ||
1427 | dividers); | ||
1428 | |||
1429 | scale_gamma(rgb_user, ramp, dividers); | ||
1430 | |||
1431 | if (tf == TRANSFER_FUNCTION_PQ) { | ||
1432 | setup_distribution_points_pq(arr_curve_points, arr_points, | ||
1433 | ¶ms->hw_points_num, coordinates_x, | ||
1434 | surface->public.format); | ||
1435 | build_regamma_curve_pq(rgb_regamma, rgb_oem, coeff128_oem, | ||
1436 | ramp, surface, params->hw_points_num, | ||
1437 | coordinates_x, axix_x_256, dividers); | ||
1438 | } else { | ||
1439 | setup_distribution_points(arr_curve_points, arr_points, | ||
1440 | ¶ms->hw_points_num, coordinates_x); | ||
1441 | build_regamma_curve(rgb_regamma, rgb_oem, coeff128_oem, | ||
1442 | ramp, surface, params->hw_points_num, | ||
1443 | coordinates_x, axix_x_256, dividers); | ||
1444 | } | ||
1445 | |||
1446 | map_regamma_hw_to_x_user(coeff128, rgb_oem, rgb_resulted, rgb_user, | ||
1447 | coordinates_x, axix_x_256, &ramp->public, rgb_regamma, | ||
1448 | dividers, params->hw_points_num, surface); | ||
1449 | |||
1450 | build_new_custom_resulted_curve(rgb_resulted, params->hw_points_num); | ||
1451 | |||
1452 | rebuild_curve_configuration_magic( | ||
1453 | arr_points, | ||
1454 | rgb_resulted, | ||
1455 | coordinates_x, | ||
1456 | params->hw_points_num, | ||
1457 | tf); | ||
1458 | |||
1459 | convert_to_custom_float(rgb_resulted, arr_points, | ||
1460 | params->hw_points_num); | ||
1461 | |||
1462 | ret = true; | ||
1463 | |||
1464 | dm_free(coeff128); | ||
1465 | coeff128_alloc_fail: | ||
1466 | dm_free(coeff128_oem); | ||
1467 | coeff128_oem_alloc_fail: | ||
1468 | dm_free(axix_x_256); | ||
1469 | axix_x_256_alloc_fail: | ||
1470 | dm_free(rgb_oem); | ||
1471 | rgb_oem_alloc_fail: | ||
1472 | dm_free(rgb_regamma); | ||
1473 | rgb_regamma_alloc_fail: | ||
1474 | dm_free(rgb_user); | ||
1475 | rgb_user_alloc_fail: | ||
1476 | dm_free(coordinates_x); | ||
1477 | coordinates_x_alloc_fail: | ||
1478 | return ret; | ||
1479 | |||
1480 | } | ||
1481 | |||
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index 7d4299b9ee1f..948f82a56472 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c | |||
@@ -1519,23 +1519,23 @@ void dc_update_surfaces_for_stream(struct dc *dc, struct dc_surface_update *upda | |||
1519 | if (dc->debug.disable_color_module) | 1519 | if (dc->debug.disable_color_module) |
1520 | continue; /* skip below color updates */ | 1520 | continue; /* skip below color updates */ |
1521 | 1521 | ||
1522 | if (updates[i].hdr_static_metadata) { | ||
1523 | resource_build_info_frame(pipe_ctx); | ||
1524 | core_dc->hwss.update_info_frame(pipe_ctx); | ||
1525 | } | ||
1526 | if (is_new_pipe_surface[j] || | 1522 | if (is_new_pipe_surface[j] || |
1527 | updates[i].in_transfer_func) | 1523 | updates[i].in_transfer_func) |
1528 | core_dc->hwss.set_input_transfer_func( | 1524 | core_dc->hwss.set_input_transfer_func( |
1529 | pipe_ctx, pipe_ctx->surface); | 1525 | pipe_ctx, pipe_ctx->surface); |
1530 | 1526 | ||
1531 | if (is_new_pipe_surface[j] || | 1527 | if (is_new_pipe_surface[j] || |
1532 | updates[i].gamma || | ||
1533 | updates[i].out_transfer_func) | 1528 | updates[i].out_transfer_func) |
1534 | core_dc->hwss.set_output_transfer_func( | 1529 | core_dc->hwss.set_output_transfer_func( |
1535 | pipe_ctx, | 1530 | pipe_ctx, |
1536 | pipe_ctx->surface, | 1531 | pipe_ctx->surface, |
1537 | pipe_ctx->stream); | 1532 | pipe_ctx->stream); |
1538 | 1533 | ||
1534 | if (updates[i].hdr_static_metadata) { | ||
1535 | resource_build_info_frame(pipe_ctx); | ||
1536 | core_dc->hwss.update_info_frame(pipe_ctx); | ||
1537 | } | ||
1538 | |||
1539 | } | 1539 | } |
1540 | if (apply_ctx) { | 1540 | if (apply_ctx) { |
1541 | core_dc->hwss.apply_ctx_for_surface(core_dc, surface, context); | 1541 | core_dc->hwss.apply_ctx_for_surface(core_dc, surface, context); |
diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index b814e7b76bbc..f53b41339951 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h | |||
@@ -213,11 +213,14 @@ enum dc_transfer_func_type { | |||
213 | }; | 213 | }; |
214 | 214 | ||
215 | struct dc_transfer_func_distributed_points { | 215 | struct dc_transfer_func_distributed_points { |
216 | uint16_t red[TRANSFER_FUNC_POINTS]; | 216 | struct fixed31_32 red[TRANSFER_FUNC_POINTS]; |
217 | uint16_t green[TRANSFER_FUNC_POINTS]; | 217 | struct fixed31_32 green[TRANSFER_FUNC_POINTS]; |
218 | uint16_t blue[TRANSFER_FUNC_POINTS]; | 218 | struct fixed31_32 blue[TRANSFER_FUNC_POINTS]; |
219 | |||
219 | uint16_t end_exponent; | 220 | uint16_t end_exponent; |
220 | uint16_t x_point_at_y1; | 221 | uint16_t x_point_at_y1_red; |
222 | uint16_t x_point_at_y1_green; | ||
223 | uint16_t x_point_at_y1_blue; | ||
221 | }; | 224 | }; |
222 | 225 | ||
223 | enum dc_transfer_func_predefined { | 226 | enum dc_transfer_func_predefined { |
diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c index 415b12accd2c..6e70cf7b99ef 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c | |||
@@ -42,7 +42,6 @@ | |||
42 | #include "stream_encoder.h" | 42 | #include "stream_encoder.h" |
43 | #include "link_encoder.h" | 43 | #include "link_encoder.h" |
44 | #include "clock_source.h" | 44 | #include "clock_source.h" |
45 | #include "gamma_calcs.h" | ||
46 | #include "audio.h" | 45 | #include "audio.h" |
47 | #include "dce/dce_hwseq.h" | 46 | #include "dce/dce_hwseq.h" |
48 | 47 | ||
@@ -286,6 +285,436 @@ static bool dce110_set_input_transfer_func( | |||
286 | return result; | 285 | return result; |
287 | } | 286 | } |
288 | 287 | ||
288 | static bool build_custom_float( | ||
289 | struct fixed31_32 value, | ||
290 | const struct custom_float_format *format, | ||
291 | bool *negative, | ||
292 | uint32_t *mantissa, | ||
293 | uint32_t *exponenta) | ||
294 | { | ||
295 | uint32_t exp_offset = (1 << (format->exponenta_bits - 1)) - 1; | ||
296 | |||
297 | const struct fixed31_32 mantissa_constant_plus_max_fraction = | ||
298 | dal_fixed31_32_from_fraction( | ||
299 | (1LL << (format->mantissa_bits + 1)) - 1, | ||
300 | 1LL << format->mantissa_bits); | ||
301 | |||
302 | struct fixed31_32 mantiss; | ||
303 | |||
304 | if (dal_fixed31_32_eq( | ||
305 | value, | ||
306 | dal_fixed31_32_zero)) { | ||
307 | *negative = false; | ||
308 | *mantissa = 0; | ||
309 | *exponenta = 0; | ||
310 | return true; | ||
311 | } | ||
312 | |||
313 | if (dal_fixed31_32_lt( | ||
314 | value, | ||
315 | dal_fixed31_32_zero)) { | ||
316 | *negative = format->sign; | ||
317 | value = dal_fixed31_32_neg(value); | ||
318 | } else { | ||
319 | *negative = false; | ||
320 | } | ||
321 | |||
322 | if (dal_fixed31_32_lt( | ||
323 | value, | ||
324 | dal_fixed31_32_one)) { | ||
325 | uint32_t i = 1; | ||
326 | |||
327 | do { | ||
328 | value = dal_fixed31_32_shl(value, 1); | ||
329 | ++i; | ||
330 | } while (dal_fixed31_32_lt( | ||
331 | value, | ||
332 | dal_fixed31_32_one)); | ||
333 | |||
334 | --i; | ||
335 | |||
336 | if (exp_offset <= i) { | ||
337 | *mantissa = 0; | ||
338 | *exponenta = 0; | ||
339 | return true; | ||
340 | } | ||
341 | |||
342 | *exponenta = exp_offset - i; | ||
343 | } else if (dal_fixed31_32_le( | ||
344 | mantissa_constant_plus_max_fraction, | ||
345 | value)) { | ||
346 | uint32_t i = 1; | ||
347 | |||
348 | do { | ||
349 | value = dal_fixed31_32_shr(value, 1); | ||
350 | ++i; | ||
351 | } while (dal_fixed31_32_lt( | ||
352 | mantissa_constant_plus_max_fraction, | ||
353 | value)); | ||
354 | |||
355 | *exponenta = exp_offset + i - 1; | ||
356 | } else { | ||
357 | *exponenta = exp_offset; | ||
358 | } | ||
359 | |||
360 | mantiss = dal_fixed31_32_sub( | ||
361 | value, | ||
362 | dal_fixed31_32_one); | ||
363 | |||
364 | if (dal_fixed31_32_lt( | ||
365 | mantiss, | ||
366 | dal_fixed31_32_zero) || | ||
367 | dal_fixed31_32_lt( | ||
368 | dal_fixed31_32_one, | ||
369 | mantiss)) | ||
370 | mantiss = dal_fixed31_32_zero; | ||
371 | else | ||
372 | mantiss = dal_fixed31_32_shl( | ||
373 | mantiss, | ||
374 | format->mantissa_bits); | ||
375 | |||
376 | *mantissa = dal_fixed31_32_floor(mantiss); | ||
377 | |||
378 | return true; | ||
379 | } | ||
380 | |||
381 | static bool setup_custom_float( | ||
382 | const struct custom_float_format *format, | ||
383 | bool negative, | ||
384 | uint32_t mantissa, | ||
385 | uint32_t exponenta, | ||
386 | uint32_t *result) | ||
387 | { | ||
388 | uint32_t i = 0; | ||
389 | uint32_t j = 0; | ||
390 | |||
391 | uint32_t value = 0; | ||
392 | |||
393 | /* verification code: | ||
394 | * once calculation is ok we can remove it | ||
395 | */ | ||
396 | |||
397 | const uint32_t mantissa_mask = | ||
398 | (1 << (format->mantissa_bits + 1)) - 1; | ||
399 | |||
400 | const uint32_t exponenta_mask = | ||
401 | (1 << (format->exponenta_bits + 1)) - 1; | ||
402 | |||
403 | if (mantissa & ~mantissa_mask) { | ||
404 | BREAK_TO_DEBUGGER(); | ||
405 | mantissa = mantissa_mask; | ||
406 | } | ||
407 | |||
408 | if (exponenta & ~exponenta_mask) { | ||
409 | BREAK_TO_DEBUGGER(); | ||
410 | exponenta = exponenta_mask; | ||
411 | } | ||
412 | |||
413 | /* end of verification code */ | ||
414 | |||
415 | while (i < format->mantissa_bits) { | ||
416 | uint32_t mask = 1 << i; | ||
417 | |||
418 | if (mantissa & mask) | ||
419 | value |= mask; | ||
420 | |||
421 | ++i; | ||
422 | } | ||
423 | |||
424 | while (j < format->exponenta_bits) { | ||
425 | uint32_t mask = 1 << j; | ||
426 | |||
427 | if (exponenta & mask) | ||
428 | value |= mask << i; | ||
429 | |||
430 | ++j; | ||
431 | } | ||
432 | |||
433 | if (negative && format->sign) | ||
434 | value |= 1 << (i + j); | ||
435 | |||
436 | *result = value; | ||
437 | |||
438 | return true; | ||
439 | } | ||
440 | |||
441 | static bool convert_to_custom_float_format( | ||
442 | struct fixed31_32 value, | ||
443 | const struct custom_float_format *format, | ||
444 | uint32_t *result) | ||
445 | { | ||
446 | uint32_t mantissa; | ||
447 | uint32_t exponenta; | ||
448 | bool negative; | ||
449 | |||
450 | return build_custom_float( | ||
451 | value, format, &negative, &mantissa, &exponenta) && | ||
452 | setup_custom_float( | ||
453 | format, negative, mantissa, exponenta, result); | ||
454 | } | ||
455 | |||
456 | static bool convert_to_custom_float( | ||
457 | struct pwl_result_data *rgb_resulted, | ||
458 | struct curve_points *arr_points, | ||
459 | uint32_t hw_points_num) | ||
460 | { | ||
461 | struct custom_float_format fmt; | ||
462 | |||
463 | struct pwl_result_data *rgb = rgb_resulted; | ||
464 | |||
465 | uint32_t i = 0; | ||
466 | |||
467 | fmt.exponenta_bits = 6; | ||
468 | fmt.mantissa_bits = 12; | ||
469 | fmt.sign = true; | ||
470 | |||
471 | if (!convert_to_custom_float_format( | ||
472 | arr_points[0].x, | ||
473 | &fmt, | ||
474 | &arr_points[0].custom_float_x)) { | ||
475 | BREAK_TO_DEBUGGER(); | ||
476 | return false; | ||
477 | } | ||
478 | |||
479 | if (!convert_to_custom_float_format( | ||
480 | arr_points[0].offset, | ||
481 | &fmt, | ||
482 | &arr_points[0].custom_float_offset)) { | ||
483 | BREAK_TO_DEBUGGER(); | ||
484 | return false; | ||
485 | } | ||
486 | |||
487 | if (!convert_to_custom_float_format( | ||
488 | arr_points[0].slope, | ||
489 | &fmt, | ||
490 | &arr_points[0].custom_float_slope)) { | ||
491 | BREAK_TO_DEBUGGER(); | ||
492 | return false; | ||
493 | } | ||
494 | |||
495 | fmt.mantissa_bits = 10; | ||
496 | fmt.sign = false; | ||
497 | |||
498 | if (!convert_to_custom_float_format( | ||
499 | arr_points[1].x, | ||
500 | &fmt, | ||
501 | &arr_points[1].custom_float_x)) { | ||
502 | BREAK_TO_DEBUGGER(); | ||
503 | return false; | ||
504 | } | ||
505 | |||
506 | if (!convert_to_custom_float_format( | ||
507 | arr_points[1].y, | ||
508 | &fmt, | ||
509 | &arr_points[1].custom_float_y)) { | ||
510 | BREAK_TO_DEBUGGER(); | ||
511 | return false; | ||
512 | } | ||
513 | |||
514 | if (!convert_to_custom_float_format( | ||
515 | arr_points[2].slope, | ||
516 | &fmt, | ||
517 | &arr_points[2].custom_float_slope)) { | ||
518 | BREAK_TO_DEBUGGER(); | ||
519 | return false; | ||
520 | } | ||
521 | |||
522 | fmt.mantissa_bits = 12; | ||
523 | fmt.sign = true; | ||
524 | |||
525 | while (i != hw_points_num) { | ||
526 | if (!convert_to_custom_float_format( | ||
527 | rgb->red, | ||
528 | &fmt, | ||
529 | &rgb->red_reg)) { | ||
530 | BREAK_TO_DEBUGGER(); | ||
531 | return false; | ||
532 | } | ||
533 | |||
534 | if (!convert_to_custom_float_format( | ||
535 | rgb->green, | ||
536 | &fmt, | ||
537 | &rgb->green_reg)) { | ||
538 | BREAK_TO_DEBUGGER(); | ||
539 | return false; | ||
540 | } | ||
541 | |||
542 | if (!convert_to_custom_float_format( | ||
543 | rgb->blue, | ||
544 | &fmt, | ||
545 | &rgb->blue_reg)) { | ||
546 | BREAK_TO_DEBUGGER(); | ||
547 | return false; | ||
548 | } | ||
549 | |||
550 | if (!convert_to_custom_float_format( | ||
551 | rgb->delta_red, | ||
552 | &fmt, | ||
553 | &rgb->delta_red_reg)) { | ||
554 | BREAK_TO_DEBUGGER(); | ||
555 | return false; | ||
556 | } | ||
557 | |||
558 | if (!convert_to_custom_float_format( | ||
559 | rgb->delta_green, | ||
560 | &fmt, | ||
561 | &rgb->delta_green_reg)) { | ||
562 | BREAK_TO_DEBUGGER(); | ||
563 | return false; | ||
564 | } | ||
565 | |||
566 | if (!convert_to_custom_float_format( | ||
567 | rgb->delta_blue, | ||
568 | &fmt, | ||
569 | &rgb->delta_blue_reg)) { | ||
570 | BREAK_TO_DEBUGGER(); | ||
571 | return false; | ||
572 | } | ||
573 | |||
574 | ++rgb; | ||
575 | ++i; | ||
576 | } | ||
577 | |||
578 | return true; | ||
579 | } | ||
580 | |||
581 | static bool dce110_translate_regamma_to_hw_format(const struct dc_transfer_func | ||
582 | *output_tf, struct pwl_params *regamma_params) | ||
583 | { | ||
584 | if (output_tf == NULL || regamma_params == NULL) | ||
585 | return false; | ||
586 | |||
587 | struct gamma_curve *arr_curve_points = regamma_params->arr_curve_points; | ||
588 | struct curve_points *arr_points = regamma_params->arr_points; | ||
589 | struct pwl_result_data *rgb_resulted = regamma_params->rgb_resulted; | ||
590 | struct fixed31_32 y_r; | ||
591 | struct fixed31_32 y_g; | ||
592 | struct fixed31_32 y_b; | ||
593 | struct fixed31_32 y1_min; | ||
594 | struct fixed31_32 y3_max; | ||
595 | |||
596 | int32_t segment_start, segment_end; | ||
597 | uint32_t hw_points, start_index; | ||
598 | uint32_t i, j; | ||
599 | |||
600 | memset(regamma_params, 0, sizeof(struct pwl_params)); | ||
601 | |||
602 | if (output_tf->tf == TRANSFER_FUNCTION_PQ) { | ||
603 | /* 16 segments x 16 points | ||
604 | * segments are from 2^-11 to 2^5 | ||
605 | */ | ||
606 | segment_start = -11; | ||
607 | segment_end = 5; | ||
608 | |||
609 | } else { | ||
610 | /* 10 segments x 16 points | ||
611 | * segment is from 2^-10 to 2^0 | ||
612 | */ | ||
613 | segment_start = -10; | ||
614 | segment_end = 0; | ||
615 | } | ||
616 | |||
617 | hw_points = (segment_end - segment_start) * 16; | ||
618 | j = 0; | ||
619 | /* (segment + 25) * 32, every 2nd point */ | ||
620 | start_index = (segment_start + 25) * 32; | ||
621 | for (i = start_index; i <= 1025; i += 2) { | ||
622 | if (j > hw_points) | ||
623 | break; | ||
624 | rgb_resulted[j].red = output_tf->tf_pts.red[i]; | ||
625 | rgb_resulted[j].green = output_tf->tf_pts.green[i]; | ||
626 | rgb_resulted[j].blue = output_tf->tf_pts.blue[i]; | ||
627 | j++; | ||
628 | } | ||
629 | |||
630 | arr_points[0].x = dal_fixed31_32_pow(dal_fixed31_32_from_int(2), | ||
631 | dal_fixed31_32_from_int(segment_start)); | ||
632 | arr_points[1].x = dal_fixed31_32_pow(dal_fixed31_32_from_int(2), | ||
633 | dal_fixed31_32_from_int(segment_end)); | ||
634 | arr_points[2].x = dal_fixed31_32_pow(dal_fixed31_32_from_int(2), | ||
635 | dal_fixed31_32_from_int(segment_end)); | ||
636 | |||
637 | y_r = rgb_resulted[0].red; | ||
638 | y_g = rgb_resulted[0].green; | ||
639 | y_b = rgb_resulted[0].blue; | ||
640 | |||
641 | y1_min = dal_fixed31_32_min(y_r, dal_fixed31_32_min(y_g, y_b)); | ||
642 | |||
643 | arr_points[0].y = y1_min; | ||
644 | arr_points[0].slope = dal_fixed31_32_div( | ||
645 | arr_points[0].y, | ||
646 | arr_points[0].x); | ||
647 | |||
648 | y_r = rgb_resulted[hw_points - 1].red; | ||
649 | y_g = rgb_resulted[hw_points - 1].green; | ||
650 | y_b = rgb_resulted[hw_points - 1].blue; | ||
651 | |||
652 | /* see comment above, m_arrPoints[1].y should be the Y value for the | ||
653 | * region end (m_numOfHwPoints), not last HW point(m_numOfHwPoints - 1) | ||
654 | */ | ||
655 | y3_max = dal_fixed31_32_max(y_r, dal_fixed31_32_max(y_g, y_b)); | ||
656 | |||
657 | arr_points[1].y = y3_max; | ||
658 | arr_points[2].y = y3_max; | ||
659 | |||
660 | arr_points[1].slope = dal_fixed31_32_zero; | ||
661 | arr_points[2].slope = dal_fixed31_32_zero; | ||
662 | |||
663 | if (output_tf->tf == TRANSFER_FUNCTION_PQ) { | ||
664 | /* for PQ, we want to have a straight line from last HW X point, | ||
665 | * and the slope to be such that we hit 1.0 at 10000 nits. | ||
666 | */ | ||
667 | const struct fixed31_32 end_value = | ||
668 | dal_fixed31_32_from_int(125); | ||
669 | |||
670 | arr_points[1].slope = dal_fixed31_32_div( | ||
671 | dal_fixed31_32_sub(dal_fixed31_32_one, arr_points[1].y), | ||
672 | dal_fixed31_32_sub(end_value, arr_points[1].x)); | ||
673 | arr_points[2].slope = dal_fixed31_32_div( | ||
674 | dal_fixed31_32_sub(dal_fixed31_32_one, arr_points[1].y), | ||
675 | dal_fixed31_32_sub(end_value, arr_points[1].x)); | ||
676 | } | ||
677 | |||
678 | regamma_params->hw_points_num = hw_points; | ||
679 | |||
680 | for (i = 0; i < segment_end - segment_start; i++) { | ||
681 | regamma_params->arr_curve_points[i].offset = i * 16; | ||
682 | regamma_params->arr_curve_points[i].segments_num = 4; | ||
683 | } | ||
684 | |||
685 | struct pwl_result_data *rgb = rgb_resulted; | ||
686 | struct pwl_result_data *rgb_plus_1 = rgb_resulted + 1; | ||
687 | |||
688 | i = 1; | ||
689 | |||
690 | while (i != hw_points + 1) { | ||
691 | if (dal_fixed31_32_lt(rgb_plus_1->red, rgb->red)) | ||
692 | rgb_plus_1->red = rgb->red; | ||
693 | if (dal_fixed31_32_lt(rgb_plus_1->green, rgb->green)) | ||
694 | rgb_plus_1->green = rgb->green; | ||
695 | if (dal_fixed31_32_lt(rgb_plus_1->blue, rgb->blue)) | ||
696 | rgb_plus_1->blue = rgb->blue; | ||
697 | |||
698 | rgb->delta_red = dal_fixed31_32_sub( | ||
699 | rgb_plus_1->red, | ||
700 | rgb->red); | ||
701 | rgb->delta_green = dal_fixed31_32_sub( | ||
702 | rgb_plus_1->green, | ||
703 | rgb->green); | ||
704 | rgb->delta_blue = dal_fixed31_32_sub( | ||
705 | rgb_plus_1->blue, | ||
706 | rgb->blue); | ||
707 | |||
708 | ++rgb_plus_1; | ||
709 | ++rgb; | ||
710 | ++i; | ||
711 | } | ||
712 | |||
713 | convert_to_custom_float(rgb_resulted, arr_points, hw_points); | ||
714 | |||
715 | return true; | ||
716 | } | ||
717 | |||
289 | static bool dce110_set_output_transfer_func( | 718 | static bool dce110_set_output_transfer_func( |
290 | struct pipe_ctx *pipe_ctx, | 719 | struct pipe_ctx *pipe_ctx, |
291 | const struct core_surface *surface, /* Surface - To be removed */ | 720 | const struct core_surface *surface, /* Surface - To be removed */ |
@@ -308,10 +737,13 @@ static bool dce110_set_output_transfer_func( | |||
308 | opp->funcs->opp_power_on_regamma_lut(opp, true); | 737 | opp->funcs->opp_power_on_regamma_lut(opp, true); |
309 | 738 | ||
310 | if (stream->public.out_transfer_func && | 739 | if (stream->public.out_transfer_func && |
311 | stream->public.out_transfer_func->type == TF_TYPE_PREDEFINED && | 740 | stream->public.out_transfer_func->type == |
312 | stream->public.out_transfer_func->tf == TRANSFER_FUNCTION_SRGB) { | 741 | TF_TYPE_PREDEFINED && |
742 | stream->public.out_transfer_func->tf == | ||
743 | TRANSFER_FUNCTION_SRGB) { | ||
313 | opp->funcs->opp_set_regamma_mode(opp, OPP_REGAMMA_SRGB); | 744 | opp->funcs->opp_set_regamma_mode(opp, OPP_REGAMMA_SRGB); |
314 | } else if (ramp && calculate_regamma_params(regamma_params, ramp, surface, stream)) { | 745 | } else if (dce110_translate_regamma_to_hw_format( |
746 | stream->public.out_transfer_func, regamma_params)) { | ||
315 | opp->funcs->opp_program_regamma_pwl(opp, regamma_params); | 747 | opp->funcs->opp_program_regamma_pwl(opp, regamma_params); |
316 | opp->funcs->opp_set_regamma_mode(opp, OPP_REGAMMA_USER); | 748 | opp->funcs->opp_set_regamma_mode(opp, OPP_REGAMMA_USER); |
317 | } else { | 749 | } else { |
diff --git a/drivers/gpu/drm/amd/display/dc/inc/gamma_calcs.h b/drivers/gpu/drm/amd/display/dc/inc/gamma_calcs.h deleted file mode 100644 index 0712268856c2..000000000000 --- a/drivers/gpu/drm/amd/display/dc/inc/gamma_calcs.h +++ /dev/null | |||
@@ -1,20 +0,0 @@ | |||
1 | /* | ||
2 | * gamma_calcs.h | ||
3 | * | ||
4 | * Created on: Feb 9, 2016 | ||
5 | * Author: yonsun | ||
6 | */ | ||
7 | |||
8 | #ifndef DRIVERS_GPU_DRM_AMD_DC_DEV_DC_INC_GAMMA_CALCS_H_ | ||
9 | #define DRIVERS_GPU_DRM_AMD_DC_DEV_DC_INC_GAMMA_CALCS_H_ | ||
10 | |||
11 | #include "opp.h" | ||
12 | #include "core_types.h" | ||
13 | #include "dc.h" | ||
14 | |||
15 | bool calculate_regamma_params(struct pwl_params *params, | ||
16 | const struct core_gamma *ramp, | ||
17 | const struct core_surface *surface, | ||
18 | const struct core_stream *stream); | ||
19 | |||
20 | #endif /* DRIVERS_GPU_DRM_AMD_DC_DEV_DC_INC_GAMMA_CALCS_H_ */ | ||
diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/opp.h b/drivers/gpu/drm/amd/display/dc/inc/hw/opp.h index a1f31a4410a3..bef5e2cacbe3 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/opp.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/opp.h | |||
@@ -138,9 +138,7 @@ struct custom_float_value { | |||
138 | 138 | ||
139 | struct hw_x_point { | 139 | struct hw_x_point { |
140 | uint32_t custom_float_x; | 140 | uint32_t custom_float_x; |
141 | uint32_t custom_float_x_adjusted; | ||
142 | struct fixed31_32 x; | 141 | struct fixed31_32 x; |
143 | struct fixed31_32 adjusted_x; | ||
144 | struct fixed31_32 regamma_y_red; | 142 | struct fixed31_32 regamma_y_red; |
145 | struct fixed31_32 regamma_y_green; | 143 | struct fixed31_32 regamma_y_green; |
146 | struct fixed31_32 regamma_y_blue; | 144 | struct fixed31_32 regamma_y_blue; |
diff --git a/drivers/gpu/drm/amd/display/include/fixed31_32.h b/drivers/gpu/drm/amd/display/include/fixed31_32.h index c28de167250f..5a4364dfd2f7 100644 --- a/drivers/gpu/drm/amd/display/include/fixed31_32.h +++ b/drivers/gpu/drm/amd/display/include/fixed31_32.h | |||
@@ -192,6 +192,14 @@ struct fixed31_32 dal_fixed31_32_add( | |||
192 | 192 | ||
193 | /* | 193 | /* |
194 | * @brief | 194 | * @brief |
195 | * result = arg1 + arg2 | ||
196 | */ | ||
197 | struct fixed31_32 dal_fixed31_32_add_int( | ||
198 | struct fixed31_32 arg1, | ||
199 | int32_t arg2); | ||
200 | |||
201 | /* | ||
202 | * @brief | ||
195 | * result = arg1 - arg2 | 203 | * result = arg1 - arg2 |
196 | */ | 204 | */ |
197 | struct fixed31_32 dal_fixed31_32_sub_int( | 205 | struct fixed31_32 dal_fixed31_32_sub_int( |