aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/amd/display/modules
diff options
context:
space:
mode:
authorHarry Wentland <harry.wentland@amd.com>2017-09-12 15:58:20 -0400
committerAlex Deucher <alexander.deucher@amd.com>2017-09-26 17:01:32 -0400
commit4562236b3bc0a28aeb6ee93b2d8a849a4c4e1c7c (patch)
tree84301c04dcaaa05c3318a8fe62cf62ab52ecc162 /drivers/gpu/drm/amd/display/modules
parent9c5b2b0d409304c2e3c1f4d1c9bb4958e1d46f8f (diff)
drm/amd/dc: Add dc display driver (v2)
Supported DCE versions: 8.0, 10.0, 11.0, 11.2 v2: rebase against 4.11 Signed-off-by: Harry Wentland <harry.wentland@amd.com> Acked-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Diffstat (limited to 'drivers/gpu/drm/amd/display/modules')
-rw-r--r--drivers/gpu/drm/amd/display/modules/color/color.c2094
-rw-r--r--drivers/gpu/drm/amd/display/modules/freesync/Makefile10
-rw-r--r--drivers/gpu/drm/amd/display/modules/freesync/freesync.c1158
-rw-r--r--drivers/gpu/drm/amd/display/modules/inc/mod_color.h179
-rw-r--r--drivers/gpu/drm/amd/display/modules/inc/mod_freesync.h149
-rw-r--r--drivers/gpu/drm/amd/display/modules/inc/mod_power.h112
-rw-r--r--drivers/gpu/drm/amd/display/modules/power/power.c784
7 files changed, 4486 insertions, 0 deletions
diff --git a/drivers/gpu/drm/amd/display/modules/color/color.c b/drivers/gpu/drm/amd/display/modules/color/color.c
new file mode 100644
index 000000000000..cf030b18f6a9
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/modules/color/color.c
@@ -0,0 +1,2094 @@
1/*
2 * Copyright 2016 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 "dc.h"
28#include "mod_color.h"
29#include "core_types.h"
30#include "fixed31_32.h"
31#include "core_dc.h"
32
33#define MOD_COLOR_MAX_CONCURRENT_SINKS 32
34#define DIVIDER 10000
35/* S2D13 value in [-3.00...0.9999] */
36#define S2D13_MIN (-3 * DIVIDER)
37#define S2D13_MAX (3 * DIVIDER)
38#define S0D13_MIN (-1 * DIVIDER)
39#define S0D13_MAX (1 * DIVIDER)
40
41struct sink_caps {
42 const struct dc_sink *sink;
43};
44
45struct gamut_calculation_matrix {
46 struct fixed31_32 MTransposed[9];
47 struct fixed31_32 XYZtoRGB_Custom[9];
48 struct fixed31_32 XYZtoRGB_Ref[9];
49 struct fixed31_32 RGBtoXYZ_Final[9];
50
51 struct fixed31_32 MResult[9];
52 struct fixed31_32 fXYZofWhiteRef[9];
53 struct fixed31_32 fXYZofRGBRef[9];
54};
55
56struct gamut_src_dst_matrix {
57 struct fixed31_32 rgbCoeffDst[9];
58 struct fixed31_32 whiteCoeffDst[3];
59 struct fixed31_32 rgbCoeffSrc[9];
60 struct fixed31_32 whiteCoeffSrc[3];
61};
62
63struct color_state {
64 bool user_enable_color_temperature;
65 int custom_color_temperature;
66 struct color_space_coordinates source_gamut;
67 struct color_space_coordinates destination_gamut;
68 struct color_range contrast;
69 struct color_range saturation;
70 struct color_range brightness;
71 struct color_range hue;
72 enum dc_quantization_range preferred_quantization_range;
73};
74
75struct core_color {
76 struct mod_color public;
77 struct dc *dc;
78 int num_sinks;
79 struct sink_caps *caps;
80 struct color_state *state;
81};
82
83#define MOD_COLOR_TO_CORE(mod_color)\
84 container_of(mod_color, struct core_color, public)
85
86#define COLOR_REGISTRY_NAME "color_v1"
87
88/*Matrix Calculation Functions*/
89/**
90 *****************************************************************************
91 * Function: transposeMatrix
92 *
93 * @brief
94 * rotate the matrix 90 degrees clockwise
95 * rows become a columns and columns to rows
96 * @param [ in ] M - source matrix
97 * @param [ in ] Rows - num of Rows of the original matrix
98 * @param [ in ] Cols - num of Cols of the original matrix
99 * @param [ out] MTransposed - result matrix
100 * @return void
101 *
102 *****************************************************************************
103 */
104static void transpose_matrix(const struct fixed31_32 *M, unsigned int Rows,
105 unsigned int Cols, struct fixed31_32 *MTransposed)
106{
107 unsigned int i, j;
108
109 for (i = 0; i < Rows; i++) {
110 for (j = 0; j < Cols; j++)
111 MTransposed[(j*Rows)+i] = M[(i*Cols)+j];
112 }
113}
114
115/**
116 *****************************************************************************
117 * Function: multiplyMatrices
118 *
119 * @brief
120 * multiplies produce of two matrices: M = M1[ulRows1 x ulCols1] *
121 * M2[ulCols1 x ulCols2].
122 *
123 * @param [ in ] M1 - first Matrix.
124 * @param [ in ] M2 - second Matrix.
125 * @param [ in ] Rows1 - num of Rows of the first Matrix
126 * @param [ in ] Cols1 - num of Cols of the first Matrix/Num of Rows
127 * of the second Matrix
128 * @param [ in ] Cols2 - num of Cols of the second Matrix
129 * @param [out ] mResult - resulting matrix.
130 * @return void
131 *
132 *****************************************************************************
133 */
134static void multiply_matrices(struct fixed31_32 *mResult,
135 const struct fixed31_32 *M1,
136 const struct fixed31_32 *M2, unsigned int Rows1,
137 unsigned int Cols1, unsigned int Cols2)
138{
139 unsigned int i, j, k;
140
141 for (i = 0; i < Rows1; i++) {
142 for (j = 0; j < Cols2; j++) {
143 mResult[(i * Cols2) + j] = dal_fixed31_32_zero;
144 for (k = 0; k < Cols1; k++)
145 mResult[(i * Cols2) + j] =
146 dal_fixed31_32_add
147 (mResult[(i * Cols2) + j],
148 dal_fixed31_32_mul(M1[(i * Cols1) + k],
149 M2[(k * Cols2) + j]));
150 }
151 }
152}
153
154/**
155 *****************************************************************************
156 * Function: cFind3X3Det
157 *
158 * @brief
159 * finds determinant of given 3x3 matrix
160 *
161 * @param [ in ] m - matrix
162 * @return determinate whioch could not be zero
163 *
164 *****************************************************************************
165 */
166static struct fixed31_32 find_3X3_det(const struct fixed31_32 *m)
167{
168 struct fixed31_32 det, A1, A2, A3;
169
170 A1 = dal_fixed31_32_mul(m[0],
171 dal_fixed31_32_sub(dal_fixed31_32_mul(m[4], m[8]),
172 dal_fixed31_32_mul(m[5], m[7])));
173 A2 = dal_fixed31_32_mul(m[1],
174 dal_fixed31_32_sub(dal_fixed31_32_mul(m[3], m[8]),
175 dal_fixed31_32_mul(m[5], m[6])));
176 A3 = dal_fixed31_32_mul(m[2],
177 dal_fixed31_32_sub(dal_fixed31_32_mul(m[3], m[7]),
178 dal_fixed31_32_mul(m[4], m[6])));
179 det = dal_fixed31_32_add(dal_fixed31_32_sub(A1, A2), A3);
180 return det;
181}
182
183
184/**
185 *****************************************************************************
186 * Function: computeInverseMatrix_3x3
187 *
188 * @brief
189 * builds inverse matrix
190 *
191 * @param [ in ] m - matrix
192 * @param [ out ] im - result matrix
193 * @return true if success
194 *
195 *****************************************************************************
196 */
197static bool compute_inverse_matrix_3x3(const struct fixed31_32 *m,
198 struct fixed31_32 *im)
199{
200 struct fixed31_32 determinant = find_3X3_det(m);
201
202 if (dal_fixed31_32_eq(determinant, dal_fixed31_32_zero) == false) {
203 im[0] = dal_fixed31_32_div(dal_fixed31_32_sub
204 (dal_fixed31_32_mul(m[4], m[8]),
205 dal_fixed31_32_mul(m[5], m[7])), determinant);
206 im[1] = dal_fixed31_32_neg(dal_fixed31_32_div(dal_fixed31_32_sub
207 (dal_fixed31_32_mul(m[1], m[8]),
208 dal_fixed31_32_mul(m[2], m[7])), determinant));
209 im[2] = dal_fixed31_32_div(dal_fixed31_32_sub
210 (dal_fixed31_32_mul(m[1], m[5]),
211 dal_fixed31_32_mul(m[2], m[4])), determinant);
212 im[3] = dal_fixed31_32_neg(dal_fixed31_32_div(dal_fixed31_32_sub
213 (dal_fixed31_32_mul(m[3], m[8]),
214 dal_fixed31_32_mul(m[5], m[6])), determinant));
215 im[4] = dal_fixed31_32_div(dal_fixed31_32_sub
216 (dal_fixed31_32_mul(m[0], m[8]),
217 dal_fixed31_32_mul(m[2], m[6])), determinant);
218 im[5] = dal_fixed31_32_neg(dal_fixed31_32_div(dal_fixed31_32_sub
219 (dal_fixed31_32_mul(m[0], m[5]),
220 dal_fixed31_32_mul(m[2], m[3])), determinant));
221 im[6] = dal_fixed31_32_div(dal_fixed31_32_sub
222 (dal_fixed31_32_mul(m[3], m[7]),
223 dal_fixed31_32_mul(m[4], m[6])), determinant);
224 im[7] = dal_fixed31_32_neg(dal_fixed31_32_div(dal_fixed31_32_sub
225 (dal_fixed31_32_mul(m[0], m[7]),
226 dal_fixed31_32_mul(m[1], m[6])), determinant));
227 im[8] = dal_fixed31_32_div(dal_fixed31_32_sub
228 (dal_fixed31_32_mul(m[0], m[4]),
229 dal_fixed31_32_mul(m[1], m[3])), determinant);
230 return true;
231 }
232 return false;
233}
234
235/**
236 *****************************************************************************
237 * Function: calculateXYZtoRGB_M3x3
238 *
239 * @brief
240 * Calculates transformation matrix from XYZ coordinates to RBG
241 *
242 * @param [ in ] XYZofRGB - primaries XYZ
243 * @param [ in ] XYZofWhite - white point.
244 * @param [ out ] XYZtoRGB - RGB primires
245 * @return true if success
246 *
247 *****************************************************************************
248 */
249static bool calculate_XYZ_to_RGB_3x3(const struct fixed31_32 *XYZofRGB,
250 const struct fixed31_32 *XYZofWhite,
251 struct fixed31_32 *XYZtoRGB)
252{
253
254 struct fixed31_32 MInversed[9];
255 struct fixed31_32 SVector[3];
256
257 /*1. Find Inverse matrix 3x3 of MTransposed*/
258 if (!compute_inverse_matrix_3x3(XYZofRGB, MInversed))
259 return false;
260
261 /*2. Calculate vector: |Sr Sg Sb| = [MInversed] * |Wx Wy Wz|*/
262 multiply_matrices(SVector, MInversed, XYZofWhite, 3, 3, 1);
263
264 /*3. Calculate matrix XYZtoRGB 3x3*/
265 XYZtoRGB[0] = dal_fixed31_32_mul(XYZofRGB[0], SVector[0]);
266 XYZtoRGB[1] = dal_fixed31_32_mul(XYZofRGB[1], SVector[1]);
267 XYZtoRGB[2] = dal_fixed31_32_mul(XYZofRGB[2], SVector[2]);
268
269 XYZtoRGB[3] = dal_fixed31_32_mul(XYZofRGB[3], SVector[0]);
270 XYZtoRGB[4] = dal_fixed31_32_mul(XYZofRGB[4], SVector[1]);
271 XYZtoRGB[5] = dal_fixed31_32_mul(XYZofRGB[5], SVector[2]);
272
273 XYZtoRGB[6] = dal_fixed31_32_mul(XYZofRGB[6], SVector[0]);
274 XYZtoRGB[7] = dal_fixed31_32_mul(XYZofRGB[7], SVector[1]);
275 XYZtoRGB[8] = dal_fixed31_32_mul(XYZofRGB[8], SVector[2]);
276
277 return true;
278}
279
280static bool gamut_to_color_matrix(
281 const struct fixed31_32 *pXYZofRGB,/*destination gamut*/
282 const struct fixed31_32 *pXYZofWhite,/*destination of white point*/
283 const struct fixed31_32 *pRefXYZofRGB,/*source gamut*/
284 const struct fixed31_32 *pRefXYZofWhite,/*source of white point*/
285 bool invert,
286 struct fixed31_32 *tempMatrix3X3)
287{
288 int i = 0;
289 struct gamut_calculation_matrix *matrix =
290 dm_alloc(sizeof(struct gamut_calculation_matrix));
291
292 struct fixed31_32 *pXYZtoRGB_Temp;
293 struct fixed31_32 *pXYZtoRGB_Final;
294
295 matrix->fXYZofWhiteRef[0] = pRefXYZofWhite[0];
296 matrix->fXYZofWhiteRef[1] = pRefXYZofWhite[1];
297 matrix->fXYZofWhiteRef[2] = pRefXYZofWhite[2];
298
299
300 matrix->fXYZofRGBRef[0] = pRefXYZofRGB[0];
301 matrix->fXYZofRGBRef[1] = pRefXYZofRGB[1];
302 matrix->fXYZofRGBRef[2] = pRefXYZofRGB[2];
303
304 matrix->fXYZofRGBRef[3] = pRefXYZofRGB[3];
305 matrix->fXYZofRGBRef[4] = pRefXYZofRGB[4];
306 matrix->fXYZofRGBRef[5] = pRefXYZofRGB[5];
307
308 matrix->fXYZofRGBRef[6] = pRefXYZofRGB[6];
309 matrix->fXYZofRGBRef[7] = pRefXYZofRGB[7];
310 matrix->fXYZofRGBRef[8] = pRefXYZofRGB[8];
311
312 /*default values - unity matrix*/
313 while (i < 9) {
314 if (i == 0 || i == 4 || i == 8)
315 tempMatrix3X3[i] = dal_fixed31_32_one;
316 else
317 tempMatrix3X3[i] = dal_fixed31_32_zero;
318 i++;
319 }
320
321 /*1. Decide about the order of calculation.
322 * bInvert == FALSE --> RGBtoXYZ_Ref * XYZtoRGB_Custom
323 * bInvert == TRUE --> RGBtoXYZ_Custom * XYZtoRGB_Ref */
324 if (invert) {
325 pXYZtoRGB_Temp = matrix->XYZtoRGB_Custom;
326 pXYZtoRGB_Final = matrix->XYZtoRGB_Ref;
327 } else {
328 pXYZtoRGB_Temp = matrix->XYZtoRGB_Ref;
329 pXYZtoRGB_Final = matrix->XYZtoRGB_Custom;
330 }
331
332 /*2. Calculate XYZtoRGB_Ref*/
333 transpose_matrix(matrix->fXYZofRGBRef, 3, 3, matrix->MTransposed);
334
335 if (!calculate_XYZ_to_RGB_3x3(
336 matrix->MTransposed,
337 matrix->fXYZofWhiteRef,
338 matrix->XYZtoRGB_Ref))
339 goto function_fail;
340
341 /*3. Calculate XYZtoRGB_Custom*/
342 transpose_matrix(pXYZofRGB, 3, 3, matrix->MTransposed);
343
344 if (!calculate_XYZ_to_RGB_3x3(
345 matrix->MTransposed,
346 pXYZofWhite,
347 matrix->XYZtoRGB_Custom))
348 goto function_fail;
349
350 /*4. Calculate RGBtoXYZ -
351 * inverse matrix 3x3 of XYZtoRGB_Ref or XYZtoRGB_Custom*/
352 if (!compute_inverse_matrix_3x3(pXYZtoRGB_Temp, matrix->RGBtoXYZ_Final))
353 goto function_fail;
354
355 /*5. Calculate M(3x3) = RGBtoXYZ * XYZtoRGB*/
356 multiply_matrices(matrix->MResult, matrix->RGBtoXYZ_Final,
357 pXYZtoRGB_Final, 3, 3, 3);
358
359 for (i = 0; i < 9; i++)
360 tempMatrix3X3[i] = matrix->MResult[i];
361
362 dm_free(matrix);
363
364 return true;
365
366function_fail:
367 dm_free(matrix);
368 return false;
369}
370
371static bool build_gamut_remap_matrix
372 (struct color_space_coordinates gamut_description,
373 struct fixed31_32 *rgb_matrix,
374 struct fixed31_32 *white_point_matrix)
375{
376 struct fixed31_32 fixed_blueX = dal_fixed31_32_from_fraction
377 (gamut_description.blueX, DIVIDER);
378 struct fixed31_32 fixed_blueY = dal_fixed31_32_from_fraction
379 (gamut_description.blueY, DIVIDER);
380 struct fixed31_32 fixed_greenX = dal_fixed31_32_from_fraction
381 (gamut_description.greenX, DIVIDER);
382 struct fixed31_32 fixed_greenY = dal_fixed31_32_from_fraction
383 (gamut_description.greenY, DIVIDER);
384 struct fixed31_32 fixed_redX = dal_fixed31_32_from_fraction
385 (gamut_description.redX, DIVIDER);
386 struct fixed31_32 fixed_redY = dal_fixed31_32_from_fraction
387 (gamut_description.redY, DIVIDER);
388 struct fixed31_32 fixed_whiteX = dal_fixed31_32_from_fraction
389 (gamut_description.whiteX, DIVIDER);
390 struct fixed31_32 fixed_whiteY = dal_fixed31_32_from_fraction
391 (gamut_description.whiteY, DIVIDER);
392
393 rgb_matrix[0] = dal_fixed31_32_div(fixed_redX, fixed_redY);
394 rgb_matrix[1] = dal_fixed31_32_one;
395 rgb_matrix[2] = dal_fixed31_32_div(dal_fixed31_32_sub
396 (dal_fixed31_32_sub(dal_fixed31_32_one, fixed_redX),
397 fixed_redY), fixed_redY);
398
399 rgb_matrix[3] = dal_fixed31_32_div(fixed_greenX, fixed_greenY);
400 rgb_matrix[4] = dal_fixed31_32_one;
401 rgb_matrix[5] = dal_fixed31_32_div(dal_fixed31_32_sub
402 (dal_fixed31_32_sub(dal_fixed31_32_one, fixed_greenX),
403 fixed_greenY), fixed_greenY);
404
405 rgb_matrix[6] = dal_fixed31_32_div(fixed_blueX, fixed_blueY);
406 rgb_matrix[7] = dal_fixed31_32_one;
407 rgb_matrix[8] = dal_fixed31_32_div(dal_fixed31_32_sub
408 (dal_fixed31_32_sub(dal_fixed31_32_one, fixed_blueX),
409 fixed_blueY), fixed_blueY);
410
411 white_point_matrix[0] = dal_fixed31_32_div(fixed_whiteX, fixed_whiteY);
412 white_point_matrix[1] = dal_fixed31_32_one;
413 white_point_matrix[2] = dal_fixed31_32_div(dal_fixed31_32_sub
414 (dal_fixed31_32_sub(dal_fixed31_32_one, fixed_whiteX),
415 fixed_whiteY), fixed_whiteY);
416
417 return true;
418}
419
420static bool check_dc_support(const struct dc *dc)
421{
422 if (dc->stream_funcs.set_gamut_remap == NULL)
423 return false;
424
425 return true;
426}
427
428static uint16_t fixed_point_to_int_frac(
429 struct fixed31_32 arg,
430 uint8_t integer_bits,
431 uint8_t fractional_bits)
432{
433 int32_t numerator;
434 int32_t divisor = 1 << fractional_bits;
435
436 uint16_t result;
437
438 uint16_t d = (uint16_t)dal_fixed31_32_floor(
439 dal_fixed31_32_abs(
440 arg));
441
442 if (d <= (uint16_t)(1 << integer_bits) - (1 / (uint16_t)divisor))
443 numerator = (uint16_t)dal_fixed31_32_floor(
444 dal_fixed31_32_mul_int(
445 arg,
446 divisor));
447 else {
448 numerator = dal_fixed31_32_floor(
449 dal_fixed31_32_sub(
450 dal_fixed31_32_from_int(
451 1LL << integer_bits),
452 dal_fixed31_32_recip(
453 dal_fixed31_32_from_int(
454 divisor))));
455 }
456
457 if (numerator >= 0)
458 result = (uint16_t)numerator;
459 else
460 result = (uint16_t)(
461 (1 << (integer_bits + fractional_bits + 1)) + numerator);
462
463 if ((result != 0) && dal_fixed31_32_lt(
464 arg, dal_fixed31_32_zero))
465 result |= 1 << (integer_bits + fractional_bits);
466
467 return result;
468}
469
470/**
471* convert_float_matrix
472* This converts a double into HW register spec defined format S2D13.
473* @param :
474* @return None
475*/
476
477static void convert_float_matrix_legacy(
478 uint16_t *matrix,
479 struct fixed31_32 *flt,
480 uint32_t buffer_size)
481{
482 const struct fixed31_32 min_2_13 =
483 dal_fixed31_32_from_fraction(S2D13_MIN, DIVIDER);
484 const struct fixed31_32 max_2_13 =
485 dal_fixed31_32_from_fraction(S2D13_MAX, DIVIDER);
486 uint32_t i;
487
488 for (i = 0; i < buffer_size; ++i) {
489 uint32_t reg_value =
490 fixed_point_to_int_frac(
491 dal_fixed31_32_clamp(
492 flt[i],
493 min_2_13,
494 max_2_13),
495 2,
496 13);
497
498 matrix[i] = (uint16_t)reg_value;
499 }
500}
501
502static void convert_float_matrix(
503 uint16_t *matrix,
504 struct fixed31_32 *flt,
505 uint32_t buffer_size)
506{
507 const struct fixed31_32 min_0_13 =
508 dal_fixed31_32_from_fraction(S0D13_MIN, DIVIDER);
509 const struct fixed31_32 max_0_13 =
510 dal_fixed31_32_from_fraction(S0D13_MAX, DIVIDER);
511 const struct fixed31_32 min_2_13 =
512 dal_fixed31_32_from_fraction(S2D13_MIN, DIVIDER);
513 const struct fixed31_32 max_2_13 =
514 dal_fixed31_32_from_fraction(S2D13_MAX, DIVIDER);
515 uint32_t i;
516 uint16_t temp_matrix[12];
517
518 for (i = 0; i < buffer_size; ++i) {
519 if (i == 3 || i == 7 || i == 11) {
520 uint32_t reg_value =
521 fixed_point_to_int_frac(
522 dal_fixed31_32_clamp(
523 flt[i],
524 min_0_13,
525 max_0_13),
526 2,
527 13);
528
529 temp_matrix[i] = (uint16_t)reg_value;
530 } else {
531 uint32_t reg_value =
532 fixed_point_to_int_frac(
533 dal_fixed31_32_clamp(
534 flt[i],
535 min_2_13,
536 max_2_13),
537 2,
538 13);
539
540 temp_matrix[i] = (uint16_t)reg_value;
541 }
542 }
543
544 matrix[4] = temp_matrix[0];
545 matrix[5] = temp_matrix[1];
546 matrix[6] = temp_matrix[2];
547 matrix[7] = temp_matrix[3];
548
549 matrix[8] = temp_matrix[4];
550 matrix[9] = temp_matrix[5];
551 matrix[10] = temp_matrix[6];
552 matrix[11] = temp_matrix[7];
553
554 matrix[0] = temp_matrix[8];
555 matrix[1] = temp_matrix[9];
556 matrix[2] = temp_matrix[10];
557 matrix[3] = temp_matrix[11];
558}
559
560static int get_hw_value_from_sw_value(int swVal, int swMin,
561 int swMax, int hwMin, int hwMax)
562{
563 int dSW = swMax - swMin; /*software adjustment range size*/
564 int dHW = hwMax - hwMin; /*hardware adjustment range size*/
565 int hwVal; /*HW adjustment value*/
566
567 /* error case, I preserve the behavior from the predecessor
568 *getHwStepFromSwHwMinMaxValue (removed in Feb 2013)
569 *which was the FP version that only computed SCLF (i.e. dHW/dSW).
570 *it would return 0 in this case so
571 *hwVal = hwMin from the formula given in @brief
572 */
573 if (dSW == 0)
574 return hwMin;
575
576 /*it's quite often that ranges match,
577 *e.g. for overlay colors currently (Feb 2013)
578 *only brightness has a different
579 *HW range, and in this case no multiplication or division is needed,
580 *and if minimums match, no calculation at all
581 */
582 if (dSW != dHW) {
583 hwVal = (swVal - swMin)*dHW/dSW + hwMin;
584 } else {
585 hwVal = swVal;
586 if (swMin != hwMin)
587 hwVal += (hwMin - swMin);
588 }
589
590 return hwVal;
591}
592
593static void initialize_fix_point_color_values(
594 struct core_color *core_color,
595 unsigned int sink_index,
596 struct fixed31_32 *grph_cont,
597 struct fixed31_32 *grph_sat,
598 struct fixed31_32 *grph_bright,
599 struct fixed31_32 *sin_grph_hue,
600 struct fixed31_32 *cos_grph_hue)
601{
602 /* Hue adjustment could be negative. -45 ~ +45 */
603 struct fixed31_32 hue =
604 dal_fixed31_32_mul(
605 dal_fixed31_32_from_fraction
606 (get_hw_value_from_sw_value
607 (core_color->state[sink_index].hue.current,
608 core_color->state[sink_index].hue.min,
609 core_color->state[sink_index].hue.max,
610 -30, 30), 180),
611 dal_fixed31_32_pi);
612
613 *sin_grph_hue = dal_fixed31_32_sin(hue);
614 *cos_grph_hue = dal_fixed31_32_cos(hue);
615
616 *grph_cont =
617 dal_fixed31_32_from_fraction(get_hw_value_from_sw_value
618 (core_color->state[sink_index].contrast.current,
619 core_color->state[sink_index].contrast.min,
620 core_color->state[sink_index].contrast.max,
621 50, 150), 100);
622 *grph_sat =
623 dal_fixed31_32_from_fraction(get_hw_value_from_sw_value
624 (core_color->state[sink_index].saturation.current,
625 core_color->state[sink_index].saturation.min,
626 core_color->state[sink_index].saturation.max,
627 0, 200), 100);
628 *grph_bright =
629 dal_fixed31_32_from_fraction(get_hw_value_from_sw_value
630 (core_color->state[sink_index].brightness.current,
631 core_color->state[sink_index].brightness.min,
632 core_color->state[sink_index].brightness.max,
633 -25, 25), 100);
634}
635
636
637/* Given a specific dc_sink* this function finds its equivalent
638 * on the dc_sink array and returns the corresponding index
639 */
640static unsigned int sink_index_from_sink(struct core_color *core_color,
641 const struct dc_sink *sink)
642{
643 unsigned int index = 0;
644
645 for (index = 0; index < core_color->num_sinks; index++)
646 if (core_color->caps[index].sink == sink)
647 return index;
648
649 /* Could not find sink requested */
650 ASSERT(false);
651 return index;
652}
653
654static void calculate_rgb_matrix_legacy(struct core_color *core_color,
655 unsigned int sink_index,
656 struct fixed31_32 *rgb_matrix)
657{
658 const struct fixed31_32 k1 =
659 dal_fixed31_32_from_fraction(701000, 1000000);
660 const struct fixed31_32 k2 =
661 dal_fixed31_32_from_fraction(236568, 1000000);
662 const struct fixed31_32 k3 =
663 dal_fixed31_32_from_fraction(-587000, 1000000);
664 const struct fixed31_32 k4 =
665 dal_fixed31_32_from_fraction(464432, 1000000);
666 const struct fixed31_32 k5 =
667 dal_fixed31_32_from_fraction(-114000, 1000000);
668 const struct fixed31_32 k6 =
669 dal_fixed31_32_from_fraction(-701000, 1000000);
670 const struct fixed31_32 k7 =
671 dal_fixed31_32_from_fraction(-299000, 1000000);
672 const struct fixed31_32 k8 =
673 dal_fixed31_32_from_fraction(-292569, 1000000);
674 const struct fixed31_32 k9 =
675 dal_fixed31_32_from_fraction(413000, 1000000);
676 const struct fixed31_32 k10 =
677 dal_fixed31_32_from_fraction(-92482, 1000000);
678 const struct fixed31_32 k11 =
679 dal_fixed31_32_from_fraction(-114000, 1000000);
680 const struct fixed31_32 k12 =
681 dal_fixed31_32_from_fraction(385051, 1000000);
682 const struct fixed31_32 k13 =
683 dal_fixed31_32_from_fraction(-299000, 1000000);
684 const struct fixed31_32 k14 =
685 dal_fixed31_32_from_fraction(886000, 1000000);
686 const struct fixed31_32 k15 =
687 dal_fixed31_32_from_fraction(-587000, 1000000);
688 const struct fixed31_32 k16 =
689 dal_fixed31_32_from_fraction(-741914, 1000000);
690 const struct fixed31_32 k17 =
691 dal_fixed31_32_from_fraction(886000, 1000000);
692 const struct fixed31_32 k18 =
693 dal_fixed31_32_from_fraction(-144086, 1000000);
694
695 const struct fixed31_32 luma_r =
696 dal_fixed31_32_from_fraction(299, 1000);
697 const struct fixed31_32 luma_g =
698 dal_fixed31_32_from_fraction(587, 1000);
699 const struct fixed31_32 luma_b =
700 dal_fixed31_32_from_fraction(114, 1000);
701
702 struct fixed31_32 grph_cont;
703 struct fixed31_32 grph_sat;
704 struct fixed31_32 grph_bright;
705 struct fixed31_32 sin_grph_hue;
706 struct fixed31_32 cos_grph_hue;
707
708 initialize_fix_point_color_values(
709 core_color, sink_index, &grph_cont, &grph_sat,
710 &grph_bright, &sin_grph_hue, &cos_grph_hue);
711
712 /* COEF_1_1 = GrphCont * (LumaR + GrphSat * (Cos(GrphHue) * K1 +*/
713 /* Sin(GrphHue) * K2))*/
714 /* (Cos(GrphHue) * K1 + Sin(GrphHue) * K2)*/
715 rgb_matrix[0] =
716 dal_fixed31_32_add(
717 dal_fixed31_32_mul(cos_grph_hue, k1),
718 dal_fixed31_32_mul(sin_grph_hue, k2));
719 /* GrphSat * (Cos(GrphHue) * K1 + Sin(GrphHue) * K2 */
720 rgb_matrix[0] = dal_fixed31_32_mul(grph_sat, rgb_matrix[0]);
721 /* (LumaR + GrphSat * (Cos(GrphHue) * K1 + Sin(GrphHue) * K2))*/
722 rgb_matrix[0] = dal_fixed31_32_add(luma_r, rgb_matrix[0]);
723 /* GrphCont * (LumaR + GrphSat * (Cos(GrphHue) * K1 + Sin(GrphHue)**/
724 /* K2))*/
725 rgb_matrix[0] = dal_fixed31_32_mul(grph_cont, rgb_matrix[0]);
726
727 /* COEF_1_2 = GrphCont * (LumaG + GrphSat * (Cos(GrphHue) * K3 +*/
728 /* Sin(GrphHue) * K4))*/
729 /* (Cos(GrphHue) * K3 + Sin(GrphHue) * K4)*/
730 rgb_matrix[1] =
731 dal_fixed31_32_add(
732 dal_fixed31_32_mul(cos_grph_hue, k3),
733 dal_fixed31_32_mul(sin_grph_hue, k4));
734 /* GrphSat * (Cos(GrphHue) * K3 + Sin(GrphHue) * K4)*/
735 rgb_matrix[1] = dal_fixed31_32_mul(grph_sat, rgb_matrix[1]);
736 /* (LumaG + GrphSat * (Cos(GrphHue) * K3 + Sin(GrphHue) * K4))*/
737 rgb_matrix[1] = dal_fixed31_32_add(luma_g, rgb_matrix[1]);
738 /* GrphCont * (LumaG + GrphSat * (Cos(GrphHue) * K3 + Sin(GrphHue)**/
739 /* K4))*/
740 rgb_matrix[1] = dal_fixed31_32_mul(grph_cont, rgb_matrix[1]);
741
742 /* COEF_1_3 = GrphCont * (LumaB + GrphSat * (Cos(GrphHue) * K5 +*/
743 /* Sin(GrphHue) * K6))*/
744 /* (Cos(GrphHue) * K5 + Sin(GrphHue) * K6)*/
745 rgb_matrix[2] =
746 dal_fixed31_32_add(
747 dal_fixed31_32_mul(cos_grph_hue, k5),
748 dal_fixed31_32_mul(sin_grph_hue, k6));
749 /* GrphSat * (Cos(GrphHue) * K5 + Sin(GrphHue) * K6)*/
750 rgb_matrix[2] = dal_fixed31_32_mul(grph_sat, rgb_matrix[2]);
751 /* LumaB + GrphSat * (Cos(GrphHue) * K5 + Sin(GrphHue) * K6)*/
752 rgb_matrix[2] = dal_fixed31_32_add(luma_b, rgb_matrix[2]);
753 /* GrphCont * (LumaB + GrphSat * (Cos(GrphHue) * K5 + Sin(GrphHue)**/
754 /* K6))*/
755 rgb_matrix[2] = dal_fixed31_32_mul(grph_cont, rgb_matrix[2]);
756
757 /* COEF_1_4 = GrphBright*/
758 rgb_matrix[3] = grph_bright;
759
760 /* COEF_2_1 = GrphCont * (LumaR + GrphSat * (Cos(GrphHue) * K7 +*/
761 /* Sin(GrphHue) * K8))*/
762 /* (Cos(GrphHue) * K7 + Sin(GrphHue) * K8)*/
763 rgb_matrix[4] =
764 dal_fixed31_32_add(
765 dal_fixed31_32_mul(cos_grph_hue, k7),
766 dal_fixed31_32_mul(sin_grph_hue, k8));
767 /* GrphSat * (Cos(GrphHue) * K7 + Sin(GrphHue) * K8)*/
768 rgb_matrix[4] = dal_fixed31_32_mul(grph_sat, rgb_matrix[4]);
769 /* (LumaR + GrphSat * (Cos(GrphHue) * K7 + Sin(GrphHue) * K8))*/
770 rgb_matrix[4] = dal_fixed31_32_add(luma_r, rgb_matrix[4]);
771 /* GrphCont * (LumaR + GrphSat * (Cos(GrphHue) * K7 + Sin(GrphHue)**/
772 /* K8))*/
773 rgb_matrix[4] = dal_fixed31_32_mul(grph_cont, rgb_matrix[4]);
774
775 /* COEF_2_2 = GrphCont * (LumaG + GrphSat * (Cos(GrphHue) * K9 +*/
776 /* Sin(GrphHue) * K10))*/
777 /* (Cos(GrphHue) * K9 + Sin(GrphHue) * K10))*/
778 rgb_matrix[5] =
779 dal_fixed31_32_add(
780 dal_fixed31_32_mul(cos_grph_hue, k9),
781 dal_fixed31_32_mul(sin_grph_hue, k10));
782 /* GrphSat * (Cos(GrphHue) * K9 + Sin(GrphHue) * K10))*/
783 rgb_matrix[5] = dal_fixed31_32_mul(grph_sat, rgb_matrix[5]);
784 /* (LumaG + GrphSat * (Cos(GrphHue) * K9 + Sin(GrphHue) * K10))*/
785 rgb_matrix[5] = dal_fixed31_32_add(luma_g, rgb_matrix[5]);
786 /* GrphCont * (LumaG + GrphSat * (Cos(GrphHue) * K9 + Sin(GrphHue)**/
787 /* K10))*/
788 rgb_matrix[5] = dal_fixed31_32_mul(grph_cont, rgb_matrix[5]);
789
790 /* COEF_2_3 = GrphCont * (LumaB + GrphSat * (Cos(GrphHue) * K11 +*/
791 /* Sin(GrphHue) * K12))*/
792 /* (Cos(GrphHue) * K11 + Sin(GrphHue) * K12))*/
793 rgb_matrix[6] =
794 dal_fixed31_32_add(
795 dal_fixed31_32_mul(cos_grph_hue, k11),
796 dal_fixed31_32_mul(sin_grph_hue, k12));
797 /* GrphSat * (Cos(GrphHue) * K11 + Sin(GrphHue) * K12))*/
798 rgb_matrix[6] = dal_fixed31_32_mul(grph_sat, rgb_matrix[6]);
799 /* (LumaB + GrphSat * (Cos(GrphHue) * K11 + Sin(GrphHue) * K12))*/
800 rgb_matrix[6] = dal_fixed31_32_add(luma_b, rgb_matrix[6]);
801 /* GrphCont * (LumaB + GrphSat * (Cos(GrphHue) * K11 + Sin(GrphHue)**/
802 /* K12))*/
803 rgb_matrix[6] = dal_fixed31_32_mul(grph_cont, rgb_matrix[6]);
804
805 /* COEF_2_4 = GrphBright*/
806 rgb_matrix[7] = grph_bright;
807
808 /* COEF_3_1 = GrphCont * (LumaR + GrphSat * (Cos(GrphHue) * K13 +*/
809 /* Sin(GrphHue) * K14))*/
810 /* (Cos(GrphHue) * K13 + Sin(GrphHue) * K14)) */
811 rgb_matrix[8] =
812 dal_fixed31_32_add(
813 dal_fixed31_32_mul(cos_grph_hue, k13),
814 dal_fixed31_32_mul(sin_grph_hue, k14));
815 /* GrphSat * (Cos(GrphHue) * K13 + Sin(GrphHue) * K14)) */
816 rgb_matrix[8] = dal_fixed31_32_mul(grph_sat, rgb_matrix[8]);
817 /* (LumaR + GrphSat * (Cos(GrphHue) * K13 + Sin(GrphHue) * K14)) */
818 rgb_matrix[8] = dal_fixed31_32_add(luma_r, rgb_matrix[8]);
819 /* GrphCont * (LumaR + GrphSat * (Cos(GrphHue) * K13 + Sin(GrphHue)**/
820 /* K14)) */
821 rgb_matrix[8] = dal_fixed31_32_mul(grph_cont, rgb_matrix[8]);
822
823 /* COEF_3_2 = GrphCont * (LumaG + GrphSat * (Cos(GrphHue) * K15 +*/
824 /* Sin(GrphHue) * K16)) */
825 /* GrphSat * (Cos(GrphHue) * K15 + Sin(GrphHue) * K16) */
826 rgb_matrix[9] =
827 dal_fixed31_32_add(
828 dal_fixed31_32_mul(cos_grph_hue, k15),
829 dal_fixed31_32_mul(sin_grph_hue, k16));
830 /* (LumaG + GrphSat * (Cos(GrphHue) * K15 + Sin(GrphHue) * K16)) */
831 rgb_matrix[9] = dal_fixed31_32_mul(grph_sat, rgb_matrix[9]);
832 /* (LumaG + GrphSat * (Cos(GrphHue) * K15 + Sin(GrphHue) * K16)) */
833 rgb_matrix[9] = dal_fixed31_32_add(luma_g, rgb_matrix[9]);
834 /* GrphCont * (LumaG + GrphSat * (Cos(GrphHue) * K15 + Sin(GrphHue)**/
835 /* K16)) */
836 rgb_matrix[9] = dal_fixed31_32_mul(grph_cont, rgb_matrix[9]);
837
838 /* COEF_3_3 = GrphCont * (LumaB + GrphSat * (Cos(GrphHue) * K17 +*/
839 /* Sin(GrphHue) * K18)) */
840 /* (Cos(GrphHue) * K17 + Sin(GrphHue) * K18)) */
841 rgb_matrix[10] =
842 dal_fixed31_32_add(
843 dal_fixed31_32_mul(cos_grph_hue, k17),
844 dal_fixed31_32_mul(sin_grph_hue, k18));
845 /* GrphSat * (Cos(GrphHue) * K17 + Sin(GrphHue) * K18)) */
846 rgb_matrix[10] = dal_fixed31_32_mul(grph_sat, rgb_matrix[10]);
847 /* (LumaB + GrphSat * (Cos(GrphHue) * K17 + Sin(GrphHue) * K18)) */
848 rgb_matrix[10] = dal_fixed31_32_add(luma_b, rgb_matrix[10]);
849 /* GrphCont * (LumaB + GrphSat * (Cos(GrphHue) * K17 + Sin(GrphHue)**/
850 /* K18)) */
851 rgb_matrix[10] = dal_fixed31_32_mul(grph_cont, rgb_matrix[10]);
852
853 /* COEF_3_4 = GrphBright */
854 rgb_matrix[11] = grph_bright;
855}
856
857static void calculate_rgb_limited_range_matrix(struct core_color *core_color,
858 unsigned int sink_index, struct fixed31_32 *rgb_matrix)
859{
860 struct fixed31_32 ideal[12];
861
862 static const int32_t matrix_[] = {
863 85546875, 0, 0, 6250000,
864 0, 85546875, 0, 6250000,
865 0, 0, 85546875, 6250000
866 };
867
868 uint32_t i = 0;
869
870 do {
871 ideal[i] = dal_fixed31_32_from_fraction(
872 matrix_[i],
873 100000000);
874 ++i;
875 } while (i != ARRAY_SIZE(matrix_));
876
877
878 struct fixed31_32 grph_cont;
879 struct fixed31_32 grph_sat;
880 struct fixed31_32 grph_bright;
881 struct fixed31_32 sin_grph_hue;
882 struct fixed31_32 cos_grph_hue;
883
884 initialize_fix_point_color_values(
885 core_color, sink_index, &grph_cont, &grph_sat,
886 &grph_bright, &sin_grph_hue, &cos_grph_hue);
887
888 const struct fixed31_32 multiplier =
889 dal_fixed31_32_mul(grph_cont, grph_sat);
890
891 rgb_matrix[8] = dal_fixed31_32_mul(ideal[0], grph_cont);
892
893 rgb_matrix[9] = dal_fixed31_32_mul(ideal[1], grph_cont);
894
895 rgb_matrix[10] = dal_fixed31_32_mul(ideal[2], grph_cont);
896
897 rgb_matrix[11] = dal_fixed31_32_add(
898 ideal[3],
899 dal_fixed31_32_mul(
900 grph_bright,
901 dal_fixed31_32_from_fraction(86, 100)));
902
903 rgb_matrix[0] = dal_fixed31_32_mul(
904 multiplier,
905 dal_fixed31_32_add(
906 dal_fixed31_32_mul(
907 ideal[8],
908 sin_grph_hue),
909 dal_fixed31_32_mul(
910 ideal[4],
911 cos_grph_hue)));
912
913 rgb_matrix[1] = dal_fixed31_32_mul(
914 multiplier,
915 dal_fixed31_32_add(
916 dal_fixed31_32_mul(
917 ideal[9],
918 sin_grph_hue),
919 dal_fixed31_32_mul(
920 ideal[5],
921 cos_grph_hue)));
922
923 rgb_matrix[2] = dal_fixed31_32_mul(
924 multiplier,
925 dal_fixed31_32_add(
926 dal_fixed31_32_mul(
927 ideal[10],
928 sin_grph_hue),
929 dal_fixed31_32_mul(
930 ideal[6],
931 cos_grph_hue)));
932
933 rgb_matrix[3] = ideal[7];
934
935 rgb_matrix[4] = dal_fixed31_32_mul(
936 multiplier,
937 dal_fixed31_32_sub(
938 dal_fixed31_32_mul(
939 ideal[8],
940 cos_grph_hue),
941 dal_fixed31_32_mul(
942 ideal[4],
943 sin_grph_hue)));
944
945 rgb_matrix[5] = dal_fixed31_32_mul(
946 multiplier,
947 dal_fixed31_32_sub(
948 dal_fixed31_32_mul(
949 ideal[9],
950 cos_grph_hue),
951 dal_fixed31_32_mul(
952 ideal[5],
953 sin_grph_hue)));
954
955 rgb_matrix[6] = dal_fixed31_32_mul(
956 multiplier,
957 dal_fixed31_32_sub(
958 dal_fixed31_32_mul(
959 ideal[10],
960 cos_grph_hue),
961 dal_fixed31_32_mul(
962 ideal[6],
963 sin_grph_hue)));
964
965 rgb_matrix[7] = ideal[11];
966}
967
968static void calculate_yuv_matrix(struct core_color *core_color,
969 unsigned int sink_index,
970 enum dc_color_space color_space,
971 struct fixed31_32 *yuv_matrix)
972{
973 struct fixed31_32 ideal[12];
974 uint32_t i = 0;
975
976 if ((color_space == COLOR_SPACE_YPBPR601) ||
977 (color_space == COLOR_SPACE_YCBCR601) ||
978 (color_space == COLOR_SPACE_YCBCR601_LIMITED)) {
979 static const int32_t matrix_[] = {
980 25578516, 50216016, 9752344, 6250000,
981 -14764391, -28985609, 43750000, 50000000,
982 43750000, -36635164, -7114836, 50000000
983 };
984 do {
985 ideal[i] = dal_fixed31_32_from_fraction(
986 matrix_[i],
987 100000000);
988 ++i;
989 } while (i != ARRAY_SIZE(matrix_));
990 } else {
991 static const int32_t matrix_[] = {
992 18187266, 61183125, 6176484, 6250000,
993 -10025059, -33724941, 43750000, 50000000,
994 43750000, -39738379, -4011621, 50000000
995 };
996 do {
997 ideal[i] = dal_fixed31_32_from_fraction(
998 matrix_[i],
999 100000000);
1000 ++i;
1001 } while (i != ARRAY_SIZE(matrix_));
1002 }
1003
1004 struct fixed31_32 grph_cont;
1005 struct fixed31_32 grph_sat;
1006 struct fixed31_32 grph_bright;
1007 struct fixed31_32 sin_grph_hue;
1008 struct fixed31_32 cos_grph_hue;
1009
1010 initialize_fix_point_color_values(
1011 core_color, sink_index, &grph_cont, &grph_sat,
1012 &grph_bright, &sin_grph_hue, &cos_grph_hue);
1013
1014 const struct fixed31_32 multiplier =
1015 dal_fixed31_32_mul(grph_cont, grph_sat);
1016
1017 yuv_matrix[0] = dal_fixed31_32_mul(ideal[0], grph_cont);
1018
1019 yuv_matrix[1] = dal_fixed31_32_mul(ideal[1], grph_cont);
1020
1021 yuv_matrix[2] = dal_fixed31_32_mul(ideal[2], grph_cont);
1022
1023 yuv_matrix[4] = dal_fixed31_32_mul(
1024 multiplier,
1025 dal_fixed31_32_add(
1026 dal_fixed31_32_mul(
1027 ideal[4],
1028 cos_grph_hue),
1029 dal_fixed31_32_mul(
1030 ideal[8],
1031 sin_grph_hue)));
1032
1033 yuv_matrix[5] = dal_fixed31_32_mul(
1034 multiplier,
1035 dal_fixed31_32_add(
1036 dal_fixed31_32_mul(
1037 ideal[5],
1038 cos_grph_hue),
1039 dal_fixed31_32_mul(
1040 ideal[9],
1041 sin_grph_hue)));
1042
1043 yuv_matrix[6] = dal_fixed31_32_mul(
1044 multiplier,
1045 dal_fixed31_32_add(
1046 dal_fixed31_32_mul(
1047 ideal[6],
1048 cos_grph_hue),
1049 dal_fixed31_32_mul(
1050 ideal[10],
1051 sin_grph_hue)));
1052
1053 yuv_matrix[7] = ideal[7];
1054
1055 yuv_matrix[8] = dal_fixed31_32_mul(
1056 multiplier,
1057 dal_fixed31_32_sub(
1058 dal_fixed31_32_mul(
1059 ideal[8],
1060 cos_grph_hue),
1061 dal_fixed31_32_mul(
1062 ideal[4],
1063 sin_grph_hue)));
1064
1065 yuv_matrix[9] = dal_fixed31_32_mul(
1066 multiplier,
1067 dal_fixed31_32_sub(
1068 dal_fixed31_32_mul(
1069 ideal[9],
1070 cos_grph_hue),
1071 dal_fixed31_32_mul(
1072 ideal[5],
1073 sin_grph_hue)));
1074
1075 yuv_matrix[10] = dal_fixed31_32_mul(
1076 multiplier,
1077 dal_fixed31_32_sub(
1078 dal_fixed31_32_mul(
1079 ideal[10],
1080 cos_grph_hue),
1081 dal_fixed31_32_mul(
1082 ideal[6],
1083 sin_grph_hue)));
1084
1085 yuv_matrix[11] = ideal[11];
1086
1087 if ((color_space == COLOR_SPACE_YCBCR601_LIMITED) ||
1088 (color_space == COLOR_SPACE_YCBCR709_LIMITED)) {
1089 yuv_matrix[3] = dal_fixed31_32_add(ideal[3], grph_bright);
1090 } else {
1091 yuv_matrix[3] = dal_fixed31_32_add(
1092 ideal[3],
1093 dal_fixed31_32_mul(
1094 grph_bright,
1095 dal_fixed31_32_from_fraction(86, 100)));
1096 }
1097}
1098
1099static void calculate_csc_matrix(struct core_color *core_color,
1100 unsigned int sink_index,
1101 enum dc_color_space color_space,
1102 uint16_t *csc_matrix)
1103{
1104 struct fixed31_32 fixed_csc_matrix[12];
1105 switch (color_space) {
1106 case COLOR_SPACE_SRGB:
1107 calculate_rgb_matrix_legacy
1108 (core_color, sink_index, fixed_csc_matrix);
1109 convert_float_matrix_legacy
1110 (csc_matrix, fixed_csc_matrix, 12);
1111 break;
1112 case COLOR_SPACE_SRGB_LIMITED:
1113 calculate_rgb_limited_range_matrix(core_color, sink_index,
1114 fixed_csc_matrix);
1115 convert_float_matrix(csc_matrix, fixed_csc_matrix, 12);
1116 break;
1117 case COLOR_SPACE_YCBCR601:
1118 case COLOR_SPACE_YCBCR709:
1119 case COLOR_SPACE_YCBCR601_LIMITED:
1120 case COLOR_SPACE_YCBCR709_LIMITED:
1121 case COLOR_SPACE_YPBPR601:
1122 case COLOR_SPACE_YPBPR709:
1123 calculate_yuv_matrix(core_color, sink_index, color_space,
1124 fixed_csc_matrix);
1125 convert_float_matrix(csc_matrix, fixed_csc_matrix, 12);
1126 break;
1127 default:
1128 calculate_rgb_matrix_legacy
1129 (core_color, sink_index, fixed_csc_matrix);
1130 convert_float_matrix_legacy
1131 (csc_matrix, fixed_csc_matrix, 12);
1132 break;
1133 }
1134}
1135
1136struct mod_color *mod_color_create(struct dc *dc)
1137{
1138 int i = 0;
1139 struct core_color *core_color =
1140 dm_alloc(sizeof(struct core_color));
1141 struct core_dc *core_dc = DC_TO_CORE(dc);
1142 struct persistent_data_flag flag;
1143
1144 if (core_color == NULL)
1145 goto fail_alloc_context;
1146
1147 core_color->caps = dm_alloc(sizeof(struct sink_caps) *
1148 MOD_COLOR_MAX_CONCURRENT_SINKS);
1149
1150 if (core_color->caps == NULL)
1151 goto fail_alloc_caps;
1152
1153 for (i = 0; i < MOD_COLOR_MAX_CONCURRENT_SINKS; i++)
1154 core_color->caps[i].sink = NULL;
1155
1156 core_color->state = dm_alloc(sizeof(struct color_state) *
1157 MOD_COLOR_MAX_CONCURRENT_SINKS);
1158
1159 /*hardcoded to sRGB with 6500 color temperature*/
1160 for (i = 0; i < MOD_COLOR_MAX_CONCURRENT_SINKS; i++) {
1161 core_color->state[i].source_gamut.blueX = 1500;
1162 core_color->state[i].source_gamut.blueY = 600;
1163 core_color->state[i].source_gamut.greenX = 3000;
1164 core_color->state[i].source_gamut.greenY = 6000;
1165 core_color->state[i].source_gamut.redX = 6400;
1166 core_color->state[i].source_gamut.redY = 3300;
1167 core_color->state[i].source_gamut.whiteX = 3127;
1168 core_color->state[i].source_gamut.whiteY = 3290;
1169
1170 core_color->state[i].destination_gamut.blueX = 1500;
1171 core_color->state[i].destination_gamut.blueY = 600;
1172 core_color->state[i].destination_gamut.greenX = 3000;
1173 core_color->state[i].destination_gamut.greenY = 6000;
1174 core_color->state[i].destination_gamut.redX = 6400;
1175 core_color->state[i].destination_gamut.redY = 3300;
1176 core_color->state[i].destination_gamut.whiteX = 3127;
1177 core_color->state[i].destination_gamut.whiteY = 3290;
1178
1179 core_color->state[i].custom_color_temperature = 6500;
1180
1181 core_color->state[i].contrast.current = 100;
1182 core_color->state[i].contrast.min = 0;
1183 core_color->state[i].contrast.max = 200;
1184
1185 core_color->state[i].saturation.current = 100;
1186 core_color->state[i].saturation.min = 0;
1187 core_color->state[i].saturation.max = 200;
1188
1189 core_color->state[i].brightness.current = 0;
1190 core_color->state[i].brightness.min = -100;
1191 core_color->state[i].brightness.max = 100;
1192
1193 core_color->state[i].hue.current = 0;
1194 core_color->state[i].hue.min = -30;
1195 core_color->state[i].hue.max = 30;
1196 }
1197
1198 if (core_color->state == NULL)
1199 goto fail_alloc_state;
1200
1201 core_color->num_sinks = 0;
1202
1203 if (dc == NULL)
1204 goto fail_construct;
1205
1206 core_color->dc = dc;
1207
1208 if (!check_dc_support(dc))
1209 goto fail_construct;
1210
1211 /* Create initial module folder in registry for color adjustment */
1212 flag.save_per_edid = true;
1213 flag.save_per_link = false;
1214
1215 dm_write_persistent_data(core_dc->ctx, NULL, COLOR_REGISTRY_NAME, NULL,
1216 NULL, 0, &flag);
1217
1218 return &core_color->public;
1219
1220fail_construct:
1221 dm_free(core_color->state);
1222
1223fail_alloc_state:
1224 dm_free(core_color->caps);
1225
1226fail_alloc_caps:
1227 dm_free(core_color);
1228
1229fail_alloc_context:
1230 return NULL;
1231}
1232
1233void mod_color_destroy(struct mod_color *mod_color)
1234{
1235 if (mod_color != NULL) {
1236 int i;
1237 struct core_color *core_color =
1238 MOD_COLOR_TO_CORE(mod_color);
1239
1240 dm_free(core_color->state);
1241
1242 for (i = 0; i < core_color->num_sinks; i++)
1243 dc_sink_release(core_color->caps[i].sink);
1244
1245 dm_free(core_color->caps);
1246
1247 dm_free(core_color);
1248 }
1249}
1250
1251bool mod_color_add_sink(struct mod_color *mod_color, const struct dc_sink *sink)
1252{
1253 struct core_color *core_color = MOD_COLOR_TO_CORE(mod_color);
1254 struct core_dc *core_dc = DC_TO_CORE(core_color->dc);
1255 bool persistent_color_temp_enable;
1256 int persistent_custom_color_temp = 0;
1257 struct color_space_coordinates persistent_source_gamut;
1258 struct color_space_coordinates persistent_destination_gamut;
1259 int persistent_brightness;
1260 int persistent_contrast;
1261 int persistent_hue;
1262 int persistent_saturation;
1263 enum dc_quantization_range persistent_quantization_range;
1264 struct persistent_data_flag flag;
1265
1266 if (core_color->num_sinks < MOD_COLOR_MAX_CONCURRENT_SINKS) {
1267 dc_sink_retain(sink);
1268 core_color->caps[core_color->num_sinks].sink = sink;
1269 core_color->state[core_color->num_sinks].
1270 user_enable_color_temperature = true;
1271
1272 /* get persistent data from registry */
1273 flag.save_per_edid = true;
1274 flag.save_per_link = false;
1275
1276
1277 if (dm_read_persistent_data(core_dc->ctx, sink,
1278 COLOR_REGISTRY_NAME,
1279 "enablecolortempadj",
1280 &persistent_color_temp_enable,
1281 sizeof(bool), &flag))
1282 core_color->state[core_color->num_sinks].
1283 user_enable_color_temperature =
1284 persistent_color_temp_enable;
1285 else
1286 core_color->state[core_color->num_sinks].
1287 user_enable_color_temperature = true;
1288
1289 if (dm_read_persistent_data(core_dc->ctx, sink,
1290 COLOR_REGISTRY_NAME,
1291 "customcolortemp",
1292 &persistent_custom_color_temp,
1293 sizeof(int), &flag))
1294 core_color->state[core_color->num_sinks].
1295 custom_color_temperature
1296 = persistent_custom_color_temp;
1297 else
1298 core_color->state[core_color->num_sinks].
1299 custom_color_temperature = 6500;
1300
1301 if (dm_read_persistent_data(core_dc->ctx, sink,
1302 COLOR_REGISTRY_NAME,
1303 "sourcegamut",
1304 &persistent_source_gamut,
1305 sizeof(struct color_space_coordinates),
1306 &flag)) {
1307 memcpy(&core_color->state[core_color->num_sinks].
1308 source_gamut, &persistent_source_gamut,
1309 sizeof(struct color_space_coordinates));
1310 } else {
1311 core_color->state[core_color->num_sinks].
1312 source_gamut.blueX = 1500;
1313 core_color->state[core_color->num_sinks].
1314 source_gamut.blueY = 600;
1315 core_color->state[core_color->num_sinks].
1316 source_gamut.greenX = 3000;
1317 core_color->state[core_color->num_sinks].
1318 source_gamut.greenY = 6000;
1319 core_color->state[core_color->num_sinks].
1320 source_gamut.redX = 6400;
1321 core_color->state[core_color->num_sinks].
1322 source_gamut.redY = 3300;
1323 core_color->state[core_color->num_sinks].
1324 source_gamut.whiteX = 3127;
1325 core_color->state[core_color->num_sinks].
1326 source_gamut.whiteY = 3290;
1327 }
1328
1329 if (dm_read_persistent_data(core_dc->ctx, sink, COLOR_REGISTRY_NAME,
1330 "destgamut",
1331 &persistent_destination_gamut,
1332 sizeof(struct color_space_coordinates),
1333 &flag)) {
1334 memcpy(&core_color->state[core_color->num_sinks].
1335 destination_gamut,
1336 &persistent_destination_gamut,
1337 sizeof(struct color_space_coordinates));
1338 } else {
1339 core_color->state[core_color->num_sinks].
1340 destination_gamut.blueX = 1500;
1341 core_color->state[core_color->num_sinks].
1342 destination_gamut.blueY = 600;
1343 core_color->state[core_color->num_sinks].
1344 destination_gamut.greenX = 3000;
1345 core_color->state[core_color->num_sinks].
1346 destination_gamut.greenY = 6000;
1347 core_color->state[core_color->num_sinks].
1348 destination_gamut.redX = 6400;
1349 core_color->state[core_color->num_sinks].
1350 destination_gamut.redY = 3300;
1351 core_color->state[core_color->num_sinks].
1352 destination_gamut.whiteX = 3127;
1353 core_color->state[core_color->num_sinks].
1354 destination_gamut.whiteY = 3290;
1355 }
1356
1357 if (dm_read_persistent_data(core_dc->ctx, sink, COLOR_REGISTRY_NAME,
1358 "brightness",
1359 &persistent_brightness,
1360 sizeof(int), &flag))
1361 core_color->state[core_color->num_sinks].
1362 brightness.current = persistent_brightness;
1363 else
1364 core_color->state[core_color->num_sinks].
1365 brightness.current = 0;
1366
1367 if (dm_read_persistent_data(core_dc->ctx, sink, COLOR_REGISTRY_NAME,
1368 "contrast",
1369 &persistent_contrast,
1370 sizeof(int), &flag))
1371 core_color->state[core_color->num_sinks].
1372 contrast.current = persistent_contrast;
1373 else
1374 core_color->state[core_color->num_sinks].
1375 contrast.current = 100;
1376
1377 if (dm_read_persistent_data(core_dc->ctx, sink, COLOR_REGISTRY_NAME,
1378 "hue",
1379 &persistent_hue,
1380 sizeof(int), &flag))
1381 core_color->state[core_color->num_sinks].
1382 hue.current = persistent_hue;
1383 else
1384 core_color->state[core_color->num_sinks].
1385 hue.current = 0;
1386
1387 if (dm_read_persistent_data(core_dc->ctx, sink, COLOR_REGISTRY_NAME,
1388 "saturation",
1389 &persistent_saturation,
1390 sizeof(int), &flag))
1391 core_color->state[core_color->num_sinks].
1392 saturation.current = persistent_saturation;
1393 else
1394 core_color->state[core_color->num_sinks].
1395 saturation.current = 100;
1396
1397 if (dm_read_persistent_data(core_dc->ctx, sink,
1398 COLOR_REGISTRY_NAME,
1399 "preferred_quantization_range",
1400 &persistent_quantization_range,
1401 sizeof(int), &flag))
1402 core_color->state[core_color->num_sinks].
1403 preferred_quantization_range =
1404 persistent_quantization_range;
1405 else
1406 core_color->state[core_color->num_sinks].
1407 preferred_quantization_range = QUANTIZATION_RANGE_FULL;
1408
1409 core_color->num_sinks++;
1410 return true;
1411 }
1412 return false;
1413}
1414
1415bool mod_color_remove_sink(struct mod_color *mod_color,
1416 const struct dc_sink *sink)
1417{
1418 int i = 0, j = 0;
1419 struct core_color *core_color = MOD_COLOR_TO_CORE(mod_color);
1420
1421 for (i = 0; i < core_color->num_sinks; i++) {
1422 if (core_color->caps[i].sink == sink) {
1423 /* To remove this sink, shift everything after down */
1424 for (j = i; j < core_color->num_sinks - 1; j++) {
1425 core_color->caps[j].sink =
1426 core_color->caps[j + 1].sink;
1427
1428 memcpy(&core_color->state[j],
1429 &core_color->state[j + 1],
1430 sizeof(struct color_state));
1431 }
1432
1433 core_color->num_sinks--;
1434
1435 dc_sink_release(sink);
1436
1437 return true;
1438 }
1439 }
1440
1441 return false;
1442}
1443
1444bool mod_color_update_gamut_to_stream(struct mod_color *mod_color,
1445 const struct dc_stream **streams, int num_streams)
1446{
1447 struct core_color *core_color = MOD_COLOR_TO_CORE(mod_color);
1448 struct core_dc *core_dc = DC_TO_CORE(core_color->dc);
1449 struct persistent_data_flag flag;
1450 struct gamut_src_dst_matrix *matrix =
1451 dm_alloc(sizeof(struct gamut_src_dst_matrix));
1452
1453 unsigned int stream_index, sink_index, j;
1454
1455 for (stream_index = 0; stream_index < num_streams; stream_index++) {
1456 sink_index = sink_index_from_sink(core_color,
1457 streams[stream_index]->sink);
1458
1459 /* Write persistent data in registry*/
1460 flag.save_per_edid = true;
1461 flag.save_per_link = false;
1462
1463 dm_write_persistent_data(core_dc->ctx,
1464 streams[stream_index]->sink,
1465 COLOR_REGISTRY_NAME,
1466 "sourcegamut",
1467 &core_color->state[sink_index].
1468 source_gamut,
1469 sizeof(struct color_space_coordinates),
1470 &flag);
1471
1472 dm_write_persistent_data(core_dc->ctx,
1473 streams[stream_index]->sink,
1474 COLOR_REGISTRY_NAME,
1475 "destgamut",
1476 &core_color->state[sink_index].
1477 destination_gamut,
1478 sizeof(struct color_space_coordinates),
1479 &flag);
1480
1481 if (!build_gamut_remap_matrix
1482 (core_color->state[sink_index].source_gamut,
1483 matrix->rgbCoeffSrc,
1484 matrix->whiteCoeffSrc))
1485 goto function_fail;
1486
1487 if (!build_gamut_remap_matrix
1488 (core_color->state[sink_index].
1489 destination_gamut,
1490 matrix->rgbCoeffDst, matrix->whiteCoeffDst))
1491 goto function_fail;
1492
1493 struct fixed31_32 gamut_result[12];
1494 struct fixed31_32 temp_matrix[9];
1495
1496 if (!gamut_to_color_matrix(
1497 matrix->rgbCoeffDst,
1498 matrix->whiteCoeffDst,
1499 matrix->rgbCoeffSrc,
1500 matrix->whiteCoeffSrc,
1501 true,
1502 temp_matrix))
1503 goto function_fail;
1504
1505 gamut_result[0] = temp_matrix[0];
1506 gamut_result[1] = temp_matrix[1];
1507 gamut_result[2] = temp_matrix[2];
1508 gamut_result[3] = matrix->whiteCoeffSrc[0];
1509 gamut_result[4] = temp_matrix[3];
1510 gamut_result[5] = temp_matrix[4];
1511 gamut_result[6] = temp_matrix[5];
1512 gamut_result[7] = matrix->whiteCoeffSrc[1];
1513 gamut_result[8] = temp_matrix[6];
1514 gamut_result[9] = temp_matrix[7];
1515 gamut_result[10] = temp_matrix[8];
1516 gamut_result[11] = matrix->whiteCoeffSrc[2];
1517
1518 struct core_stream *core_stream =
1519 DC_STREAM_TO_CORE
1520 (streams[stream_index]);
1521
1522 core_stream->public.gamut_remap_matrix.enable_remap = true;
1523
1524 for (j = 0; j < 12; j++)
1525 core_stream->public.
1526 gamut_remap_matrix.matrix[j] =
1527 gamut_result[j];
1528 }
1529
1530 dm_free(matrix);
1531 core_color->dc->stream_funcs.set_gamut_remap
1532 (core_color->dc, streams, num_streams);
1533
1534 return true;
1535
1536function_fail:
1537 dm_free(matrix);
1538 return false;
1539}
1540
1541bool mod_color_adjust_source_gamut(struct mod_color *mod_color,
1542 const struct dc_stream **streams, int num_streams,
1543 struct gamut_space_coordinates *input_gamut_coordinates,
1544 struct white_point_coodinates *input_white_point_coordinates)
1545{
1546 struct core_color *core_color = MOD_COLOR_TO_CORE(mod_color);
1547
1548 unsigned int stream_index, sink_index;
1549
1550 for (stream_index = 0; stream_index < num_streams; stream_index++) {
1551 sink_index = sink_index_from_sink(core_color,
1552 streams[stream_index]->sink);
1553
1554 core_color->state[sink_index].source_gamut.blueX =
1555 input_gamut_coordinates->blueX;
1556 core_color->state[sink_index].source_gamut.blueY =
1557 input_gamut_coordinates->blueY;
1558 core_color->state[sink_index].source_gamut.greenX =
1559 input_gamut_coordinates->greenX;
1560 core_color->state[sink_index].source_gamut.greenY =
1561 input_gamut_coordinates->greenY;
1562 core_color->state[sink_index].source_gamut.redX =
1563 input_gamut_coordinates->redX;
1564 core_color->state[sink_index].source_gamut.redY =
1565 input_gamut_coordinates->redY;
1566 core_color->state[sink_index].source_gamut.whiteX =
1567 input_white_point_coordinates->whiteX;
1568 core_color->state[sink_index].source_gamut.whiteY =
1569 input_white_point_coordinates->whiteY;
1570 }
1571
1572 if (!mod_color_update_gamut_to_stream(mod_color, streams, num_streams))
1573 return false;
1574
1575 return true;
1576}
1577
1578bool mod_color_adjust_destination_gamut(struct mod_color *mod_color,
1579 const struct dc_stream **streams, int num_streams,
1580 struct gamut_space_coordinates *input_gamut_coordinates,
1581 struct white_point_coodinates *input_white_point_coordinates)
1582{
1583 struct core_color *core_color = MOD_COLOR_TO_CORE(mod_color);
1584
1585 unsigned int stream_index, sink_index;
1586
1587 for (stream_index = 0; stream_index < num_streams; stream_index++) {
1588 sink_index = sink_index_from_sink(core_color,
1589 streams[stream_index]->sink);
1590
1591 core_color->state[sink_index].destination_gamut.blueX =
1592 input_gamut_coordinates->blueX;
1593 core_color->state[sink_index].destination_gamut.blueY =
1594 input_gamut_coordinates->blueY;
1595 core_color->state[sink_index].destination_gamut.greenX =
1596 input_gamut_coordinates->greenX;
1597 core_color->state[sink_index].destination_gamut.greenY =
1598 input_gamut_coordinates->greenY;
1599 core_color->state[sink_index].destination_gamut.redX =
1600 input_gamut_coordinates->redX;
1601 core_color->state[sink_index].destination_gamut.redY =
1602 input_gamut_coordinates->redY;
1603 core_color->state[sink_index].destination_gamut.whiteX =
1604 input_white_point_coordinates->whiteX;
1605 core_color->state[sink_index].destination_gamut.whiteY =
1606 input_white_point_coordinates->whiteY;
1607 }
1608
1609 if (!mod_color_update_gamut_to_stream(mod_color, streams, num_streams))
1610 return false;
1611
1612 return true;
1613}
1614
1615bool mod_color_set_white_point(struct mod_color *mod_color,
1616 const struct dc_stream **streams, int num_streams,
1617 struct white_point_coodinates *white_point)
1618{
1619 struct core_color *core_color = MOD_COLOR_TO_CORE(mod_color);
1620
1621 unsigned int stream_index, sink_index;
1622
1623 for (stream_index = 0; stream_index < num_streams;
1624 stream_index++) {
1625 sink_index = sink_index_from_sink(core_color,
1626 streams[stream_index]->sink);
1627 core_color->state[sink_index].source_gamut.whiteX =
1628 white_point->whiteX;
1629 core_color->state[sink_index].source_gamut.whiteY =
1630 white_point->whiteY;
1631 }
1632
1633 if (!mod_color_update_gamut_to_stream(mod_color, streams, num_streams))
1634 return false;
1635
1636 return true;
1637}
1638
1639bool mod_color_set_user_enable(struct mod_color *mod_color,
1640 const struct dc_stream **streams, int num_streams,
1641 bool user_enable)
1642{
1643 struct core_color *core_color =
1644 MOD_COLOR_TO_CORE(mod_color);
1645 struct core_dc *core_dc = DC_TO_CORE(core_color->dc);
1646 struct persistent_data_flag flag;
1647 unsigned int stream_index, sink_index;
1648
1649 for (stream_index = 0; stream_index < num_streams; stream_index++) {
1650 sink_index = sink_index_from_sink(core_color,
1651 streams[stream_index]->sink);
1652 core_color->state[sink_index].user_enable_color_temperature
1653 = user_enable;
1654
1655 /* Write persistent data in registry*/
1656 flag.save_per_edid = true;
1657 flag.save_per_link = false;
1658
1659 dm_write_persistent_data(core_dc->ctx,
1660 streams[stream_index]->sink,
1661 COLOR_REGISTRY_NAME,
1662 "enablecolortempadj",
1663 &user_enable,
1664 sizeof(bool),
1665 &flag);
1666 }
1667 return true;
1668}
1669
1670bool mod_color_get_user_enable(struct mod_color *mod_color,
1671 const struct dc_sink *sink,
1672 bool *user_enable)
1673{
1674 struct core_color *core_color =
1675 MOD_COLOR_TO_CORE(mod_color);
1676
1677 unsigned int sink_index = sink_index_from_sink(core_color, sink);
1678
1679 *user_enable = core_color->state[sink_index].
1680 user_enable_color_temperature;
1681
1682 return true;
1683}
1684
1685bool mod_color_get_custom_color_temperature(struct mod_color *mod_color,
1686 const struct dc_sink *sink,
1687 int *color_temperature)
1688{
1689 struct core_color *core_color =
1690 MOD_COLOR_TO_CORE(mod_color);
1691
1692 unsigned int sink_index = sink_index_from_sink(core_color, sink);
1693
1694 *color_temperature = core_color->state[sink_index].
1695 custom_color_temperature;
1696
1697 return true;
1698}
1699
1700bool mod_color_set_custom_color_temperature(struct mod_color *mod_color,
1701 const struct dc_stream **streams, int num_streams,
1702 int color_temperature)
1703{
1704 struct core_color *core_color =
1705 MOD_COLOR_TO_CORE(mod_color);
1706 struct core_dc *core_dc = DC_TO_CORE(core_color->dc);
1707 struct persistent_data_flag flag;
1708 unsigned int stream_index, sink_index;
1709
1710 for (stream_index = 0; stream_index < num_streams; stream_index++) {
1711 sink_index = sink_index_from_sink(core_color,
1712 streams[stream_index]->sink);
1713 core_color->state[sink_index].custom_color_temperature
1714 = color_temperature;
1715
1716 /* Write persistent data in registry*/
1717 flag.save_per_edid = true;
1718 flag.save_per_link = false;
1719
1720 dm_write_persistent_data(core_dc->ctx,
1721 streams[stream_index]->sink,
1722 COLOR_REGISTRY_NAME,
1723 "customcolortemp",
1724 &color_temperature,
1725 sizeof(int),
1726 &flag);
1727 }
1728 return true;
1729}
1730
1731bool mod_color_get_color_saturation(struct mod_color *mod_color,
1732 const struct dc_sink *sink,
1733 struct color_range *color_saturation)
1734{
1735 struct core_color *core_color =
1736 MOD_COLOR_TO_CORE(mod_color);
1737
1738 unsigned int sink_index = sink_index_from_sink(core_color, sink);
1739
1740 *color_saturation = core_color->state[sink_index].saturation;
1741
1742 return true;
1743}
1744
1745bool mod_color_get_color_contrast(struct mod_color *mod_color,
1746 const struct dc_sink *sink,
1747 struct color_range *color_contrast)
1748{
1749 struct core_color *core_color =
1750 MOD_COLOR_TO_CORE(mod_color);
1751
1752 unsigned int sink_index = sink_index_from_sink(core_color, sink);
1753
1754 *color_contrast = core_color->state[sink_index].contrast;
1755
1756 return true;
1757}
1758
1759bool mod_color_get_color_brightness(struct mod_color *mod_color,
1760 const struct dc_sink *sink,
1761 struct color_range *color_brightness)
1762{
1763 struct core_color *core_color =
1764 MOD_COLOR_TO_CORE(mod_color);
1765
1766 unsigned int sink_index = sink_index_from_sink(core_color, sink);
1767
1768 *color_brightness = core_color->state[sink_index].brightness;
1769
1770 return true;
1771}
1772
1773bool mod_color_get_color_hue(struct mod_color *mod_color,
1774 const struct dc_sink *sink,
1775 struct color_range *color_hue)
1776{
1777 struct core_color *core_color =
1778 MOD_COLOR_TO_CORE(mod_color);
1779
1780 unsigned int sink_index = sink_index_from_sink(core_color, sink);
1781
1782 *color_hue = core_color->state[sink_index].hue;
1783
1784 return true;
1785}
1786
1787bool mod_color_get_source_gamut(struct mod_color *mod_color,
1788 const struct dc_sink *sink,
1789 struct color_space_coordinates *source_gamut)
1790{
1791 struct core_color *core_color =
1792 MOD_COLOR_TO_CORE(mod_color);
1793
1794 unsigned int sink_index = sink_index_from_sink(core_color, sink);
1795
1796 *source_gamut = core_color->state[sink_index].source_gamut;
1797
1798 return true;
1799}
1800
1801bool mod_color_notify_mode_change(struct mod_color *mod_color,
1802 const struct dc_stream **streams, int num_streams)
1803{
1804 struct core_color *core_color = MOD_COLOR_TO_CORE(mod_color);
1805
1806 struct gamut_src_dst_matrix *matrix =
1807 dm_alloc(sizeof(struct gamut_src_dst_matrix));
1808
1809 unsigned int stream_index, sink_index, j;
1810
1811 for (stream_index = 0; stream_index < num_streams; stream_index++) {
1812 sink_index = sink_index_from_sink(core_color,
1813 streams[stream_index]->sink);
1814
1815 if (!build_gamut_remap_matrix
1816 (core_color->state[sink_index].source_gamut,
1817 matrix->rgbCoeffSrc,
1818 matrix->whiteCoeffSrc))
1819 goto function_fail;
1820
1821 if (!build_gamut_remap_matrix
1822 (core_color->state[sink_index].
1823 destination_gamut,
1824 matrix->rgbCoeffDst, matrix->whiteCoeffDst))
1825 goto function_fail;
1826
1827 struct fixed31_32 gamut_result[12];
1828 struct fixed31_32 temp_matrix[9];
1829
1830 if (!gamut_to_color_matrix(
1831 matrix->rgbCoeffDst,
1832 matrix->whiteCoeffDst,
1833 matrix->rgbCoeffSrc,
1834 matrix->whiteCoeffSrc,
1835 true,
1836 temp_matrix))
1837 goto function_fail;
1838
1839 gamut_result[0] = temp_matrix[0];
1840 gamut_result[1] = temp_matrix[1];
1841 gamut_result[2] = temp_matrix[2];
1842 gamut_result[3] = matrix->whiteCoeffSrc[0];
1843 gamut_result[4] = temp_matrix[3];
1844 gamut_result[5] = temp_matrix[4];
1845 gamut_result[6] = temp_matrix[5];
1846 gamut_result[7] = matrix->whiteCoeffSrc[1];
1847 gamut_result[8] = temp_matrix[6];
1848 gamut_result[9] = temp_matrix[7];
1849 gamut_result[10] = temp_matrix[8];
1850 gamut_result[11] = matrix->whiteCoeffSrc[2];
1851
1852
1853 struct core_stream *core_stream =
1854 DC_STREAM_TO_CORE
1855 (streams[stream_index]);
1856
1857 core_stream->public.gamut_remap_matrix.enable_remap = true;
1858
1859 for (j = 0; j < 12; j++)
1860 core_stream->public.
1861 gamut_remap_matrix.matrix[j] =
1862 gamut_result[j];
1863
1864 calculate_csc_matrix(core_color, sink_index,
1865 core_stream->public.output_color_space,
1866 core_stream->public.csc_color_matrix.matrix);
1867
1868 core_stream->public.csc_color_matrix.enable_adjustment = true;
1869 }
1870
1871 dm_free(matrix);
1872
1873 return true;
1874
1875function_fail:
1876 dm_free(matrix);
1877 return false;
1878}
1879
1880bool mod_color_set_brightness(struct mod_color *mod_color,
1881 const struct dc_stream **streams, int num_streams,
1882 int brightness_value)
1883{
1884 struct core_color *core_color = MOD_COLOR_TO_CORE(mod_color);
1885 struct core_dc *core_dc = DC_TO_CORE(core_color->dc);
1886 struct persistent_data_flag flag;
1887 unsigned int stream_index, sink_index;
1888
1889 for (stream_index = 0; stream_index < num_streams; stream_index++) {
1890 sink_index = sink_index_from_sink(core_color,
1891 streams[stream_index]->sink);
1892
1893 struct core_stream *core_stream =
1894 DC_STREAM_TO_CORE
1895 (streams[stream_index]);
1896
1897 core_color->state[sink_index].brightness.current =
1898 brightness_value;
1899
1900 calculate_csc_matrix(core_color, sink_index,
1901 core_stream->public.output_color_space,
1902 core_stream->public.csc_color_matrix.matrix);
1903
1904 core_stream->public.csc_color_matrix.enable_adjustment = true;
1905
1906 /* Write persistent data in registry*/
1907 flag.save_per_edid = true;
1908 flag.save_per_link = false;
1909 dm_write_persistent_data(core_dc->ctx,
1910 streams[stream_index]->sink,
1911 COLOR_REGISTRY_NAME,
1912 "brightness",
1913 &brightness_value,
1914 sizeof(int),
1915 &flag);
1916 }
1917
1918 core_color->dc->stream_funcs.set_gamut_remap
1919 (core_color->dc, streams, num_streams);
1920
1921 return true;
1922}
1923
1924bool mod_color_set_contrast(struct mod_color *mod_color,
1925 const struct dc_stream **streams, int num_streams,
1926 int contrast_value)
1927{
1928 struct core_color *core_color = MOD_COLOR_TO_CORE(mod_color);
1929 struct core_dc *core_dc = DC_TO_CORE(core_color->dc);
1930 struct persistent_data_flag flag;
1931 unsigned int stream_index, sink_index;
1932
1933 for (stream_index = 0; stream_index < num_streams; stream_index++) {
1934 sink_index = sink_index_from_sink(core_color,
1935 streams[stream_index]->sink);
1936
1937 struct core_stream *core_stream =
1938 DC_STREAM_TO_CORE
1939 (streams[stream_index]);
1940
1941 core_color->state[sink_index].contrast.current =
1942 contrast_value;
1943
1944 calculate_csc_matrix(core_color, sink_index,
1945 core_stream->public.output_color_space,
1946 core_stream->public.csc_color_matrix.matrix);
1947
1948 core_stream->public.csc_color_matrix.enable_adjustment = true;
1949
1950 /* Write persistent data in registry*/
1951 flag.save_per_edid = true;
1952 flag.save_per_link = false;
1953 dm_write_persistent_data(core_dc->ctx,
1954 streams[stream_index]->sink,
1955 COLOR_REGISTRY_NAME,
1956 "contrast",
1957 &contrast_value,
1958 sizeof(int),
1959 &flag);
1960 }
1961
1962 core_color->dc->stream_funcs.set_gamut_remap
1963 (core_color->dc, streams, num_streams);
1964
1965 return true;
1966}
1967
1968bool mod_color_set_hue(struct mod_color *mod_color,
1969 const struct dc_stream **streams, int num_streams,
1970 int hue_value)
1971{
1972 struct core_color *core_color = MOD_COLOR_TO_CORE(mod_color);
1973 struct core_dc *core_dc = DC_TO_CORE(core_color->dc);
1974 struct persistent_data_flag flag;
1975 unsigned int stream_index, sink_index;
1976
1977 for (stream_index = 0; stream_index < num_streams; stream_index++) {
1978 sink_index = sink_index_from_sink(core_color,
1979 streams[stream_index]->sink);
1980
1981 struct core_stream *core_stream =
1982 DC_STREAM_TO_CORE
1983 (streams[stream_index]);
1984
1985 core_color->state[sink_index].hue.current = hue_value;
1986
1987 calculate_csc_matrix(core_color, sink_index,
1988 core_stream->public.output_color_space,
1989 core_stream->public.csc_color_matrix.matrix);
1990
1991 core_stream->public.csc_color_matrix.enable_adjustment = true;
1992
1993 /* Write persistent data in registry*/
1994 flag.save_per_edid = true;
1995 flag.save_per_link = false;
1996 dm_write_persistent_data(core_dc->ctx,
1997 streams[stream_index]->sink,
1998 COLOR_REGISTRY_NAME,
1999 "hue",
2000 &hue_value,
2001 sizeof(int),
2002 &flag);
2003 }
2004
2005 core_color->dc->stream_funcs.set_gamut_remap
2006 (core_color->dc, streams, num_streams);
2007
2008 return true;
2009}
2010
2011bool mod_color_set_saturation(struct mod_color *mod_color,
2012 const struct dc_stream **streams, int num_streams,
2013 int saturation_value)
2014{
2015 struct core_color *core_color = MOD_COLOR_TO_CORE(mod_color);
2016 struct core_dc *core_dc = DC_TO_CORE(core_color->dc);
2017 struct persistent_data_flag flag;
2018 unsigned int stream_index, sink_index;
2019
2020 for (stream_index = 0; stream_index < num_streams; stream_index++) {
2021 sink_index = sink_index_from_sink(core_color,
2022 streams[stream_index]->sink);
2023
2024 struct core_stream *core_stream =
2025 DC_STREAM_TO_CORE
2026 (streams[stream_index]);
2027
2028 core_color->state[sink_index].saturation.current =
2029 saturation_value;
2030
2031 calculate_csc_matrix(core_color, sink_index,
2032 core_stream->public.output_color_space,
2033 core_stream->public.csc_color_matrix.matrix);
2034
2035 core_stream->public.csc_color_matrix.enable_adjustment = true;
2036
2037 /* Write persistent data in registry*/
2038 flag.save_per_edid = true;
2039 flag.save_per_link = false;
2040 dm_write_persistent_data(core_dc->ctx,
2041 streams[stream_index]->sink,
2042 COLOR_REGISTRY_NAME,
2043 "saturation",
2044 &saturation_value,
2045 sizeof(int),
2046 &flag);
2047 }
2048
2049 core_color->dc->stream_funcs.set_gamut_remap
2050 (core_color->dc, streams, num_streams);
2051
2052 return true;
2053}
2054
2055bool mod_color_set_preferred_quantization_range(struct mod_color *mod_color,
2056 const struct dc_sink *sink,
2057 enum dc_quantization_range quantization_range)
2058{
2059 struct core_color *core_color = MOD_COLOR_TO_CORE(mod_color);
2060 struct core_dc *core_dc = DC_TO_CORE(core_color->dc);
2061 struct persistent_data_flag flag;
2062 unsigned int sink_index;
2063
2064 sink_index = sink_index_from_sink(core_color, sink);
2065 if (core_color->state[sink_index].
2066 preferred_quantization_range != quantization_range) {
2067 core_color->state[sink_index].preferred_quantization_range =
2068 quantization_range;
2069 flag.save_per_edid = true;
2070 flag.save_per_link = false;
2071 dm_write_persistent_data(core_dc->ctx,
2072 sink,
2073 COLOR_REGISTRY_NAME,
2074 "quantization_range",
2075 &quantization_range,
2076 sizeof(int),
2077 &flag);
2078 }
2079
2080 return true;
2081}
2082
2083bool mod_color_get_preferred_quantization_range(struct mod_color *mod_color,
2084 const struct dc_sink *sink,
2085 enum dc_quantization_range *quantization_range)
2086{
2087 struct core_color *core_color = MOD_COLOR_TO_CORE(mod_color);
2088 unsigned int sink_index;
2089
2090 sink_index = sink_index_from_sink(core_color, sink);
2091 *quantization_range = core_color->state[sink_index].
2092 preferred_quantization_range;
2093 return true;
2094}
diff --git a/drivers/gpu/drm/amd/display/modules/freesync/Makefile b/drivers/gpu/drm/amd/display/modules/freesync/Makefile
new file mode 100644
index 000000000000..db8e0ff6d7a9
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/modules/freesync/Makefile
@@ -0,0 +1,10 @@
1#
2# Makefile for the 'freesync' sub-module of DAL.
3#
4
5FREESYNC = freesync.o
6
7AMD_DAL_FREESYNC = $(addprefix $(AMDDALPATH)/modules/freesync/,$(FREESYNC))
8#$(info ************ DAL-FREE SYNC_MAKEFILE ************)
9
10AMD_DISPLAY_FILES += $(AMD_DAL_FREESYNC)
diff --git a/drivers/gpu/drm/amd/display/modules/freesync/freesync.c b/drivers/gpu/drm/amd/display/modules/freesync/freesync.c
new file mode 100644
index 000000000000..eb912baa0169
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/modules/freesync/freesync.c
@@ -0,0 +1,1158 @@
1/*
2 * Copyright 2016 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 "dc.h"
28#include "mod_freesync.h"
29#include "core_types.h"
30#include "core_dc.h"
31
32#define MOD_FREESYNC_MAX_CONCURRENT_STREAMS 32
33
34/* Refresh rate ramp at a fixed rate of 65 Hz/second */
35#define STATIC_SCREEN_RAMP_DELTA_REFRESH_RATE_PER_FRAME ((1000 / 60) * 65)
36/* Number of elements in the render times cache array */
37#define RENDER_TIMES_MAX_COUNT 20
38/* Threshold to exit BTR (to avoid frequent enter-exits at the lower limit) */
39#define BTR_EXIT_MARGIN 2000
40
41#define FREESYNC_REGISTRY_NAME "freesync_v1"
42
43struct gradual_static_ramp {
44 bool ramp_is_active;
45 bool ramp_direction_is_up;
46 unsigned int ramp_current_frame_duration_in_ns;
47};
48
49struct time_cache {
50 /* video (48Hz feature) related */
51 unsigned int update_duration_in_ns;
52
53 /* BTR/fixed refresh related */
54 unsigned int prev_time_stamp_in_us;
55
56 unsigned int min_render_time_in_us;
57 unsigned int max_render_time_in_us;
58
59 unsigned int render_times_index;
60 unsigned int render_times[RENDER_TIMES_MAX_COUNT];
61};
62
63struct below_the_range {
64 bool btr_active;
65 bool program_btr;
66
67 unsigned int mid_point_in_us;
68
69 unsigned int inserted_frame_duration_in_us;
70 unsigned int frames_to_insert;
71 unsigned int frame_counter;
72};
73
74struct fixed_refresh {
75 bool fixed_refresh_active;
76 bool program_fixed_refresh;
77};
78
79struct freesync_state {
80 bool fullscreen;
81 bool static_screen;
82 bool video;
83
84 unsigned int nominal_refresh_rate_in_micro_hz;
85 bool windowed_fullscreen;
86
87 struct time_cache time;
88
89 struct gradual_static_ramp static_ramp;
90 struct below_the_range btr;
91 struct fixed_refresh fixed_refresh;
92};
93
94struct freesync_entity {
95 const struct dc_stream *stream;
96 struct mod_freesync_caps *caps;
97 struct freesync_state state;
98 struct mod_freesync_user_enable user_enable;
99};
100
101struct core_freesync {
102 struct mod_freesync public;
103 struct dc *dc;
104 struct freesync_entity *map;
105 int num_entities;
106};
107
108#define MOD_FREESYNC_TO_CORE(mod_freesync)\
109 container_of(mod_freesync, struct core_freesync, public)
110
111static bool check_dc_support(const struct dc *dc)
112{
113 if (dc->stream_funcs.adjust_vmin_vmax == NULL)
114 return false;
115
116 return true;
117}
118
119struct mod_freesync *mod_freesync_create(struct dc *dc)
120{
121 struct core_freesync *core_freesync =
122 dm_alloc(sizeof(struct core_freesync));
123
124 struct core_dc *core_dc = DC_TO_CORE(dc);
125
126 struct persistent_data_flag flag;
127
128 int i = 0;
129
130 if (core_freesync == NULL)
131 goto fail_alloc_context;
132
133 core_freesync->map = dm_alloc(sizeof(struct freesync_entity) *
134 MOD_FREESYNC_MAX_CONCURRENT_STREAMS);
135
136 if (core_freesync->map == NULL)
137 goto fail_alloc_map;
138
139 for (i = 0; i < MOD_FREESYNC_MAX_CONCURRENT_STREAMS; i++)
140 core_freesync->map[i].stream = NULL;
141
142 core_freesync->num_entities = 0;
143
144 if (dc == NULL)
145 goto fail_construct;
146
147 core_freesync->dc = dc;
148
149 if (!check_dc_support(dc))
150 goto fail_construct;
151
152 /* Create initial module folder in registry for freesync enable data */
153 flag.save_per_edid = true;
154 flag.save_per_link = false;
155 dm_write_persistent_data(core_dc->ctx, NULL, FREESYNC_REGISTRY_NAME, NULL, NULL,
156 0, &flag);
157
158 return &core_freesync->public;
159
160fail_construct:
161 dm_free(core_freesync->map);
162
163fail_alloc_map:
164 dm_free(core_freesync);
165
166fail_alloc_context:
167 return NULL;
168}
169
170void mod_freesync_destroy(struct mod_freesync *mod_freesync)
171{
172 if (mod_freesync != NULL) {
173 int i;
174 struct core_freesync *core_freesync =
175 MOD_FREESYNC_TO_CORE(mod_freesync);
176
177 for (i = 0; i < core_freesync->num_entities; i++)
178 if (core_freesync->map[i].stream)
179 dc_stream_release(core_freesync->map[i].stream);
180
181 dm_free(core_freesync->map);
182
183 dm_free(core_freesync);
184 }
185}
186
187/* Given a specific dc_stream* this function finds its equivalent
188 * on the core_freesync->map and returns the corresponding index
189 */
190static unsigned int map_index_from_stream(struct core_freesync *core_freesync,
191 const struct dc_stream *stream)
192{
193 unsigned int index = 0;
194
195 for (index = 0; index < core_freesync->num_entities; index++) {
196 if (core_freesync->map[index].stream == stream) {
197 return index;
198 }
199 }
200 /* Could not find stream requested */
201 ASSERT(false);
202 return index;
203}
204
205bool mod_freesync_add_stream(struct mod_freesync *mod_freesync,
206 const struct dc_stream *stream, struct mod_freesync_caps *caps)
207{
208 struct core_freesync *core_freesync =
209 MOD_FREESYNC_TO_CORE(mod_freesync);
210 struct core_stream *core_stream =
211 DC_STREAM_TO_CORE(stream);
212 struct core_dc *core_dc = DC_TO_CORE(core_freesync->dc);
213
214 int persistent_freesync_enable = 0;
215 struct persistent_data_flag flag;
216
217 flag.save_per_edid = true;
218 flag.save_per_link = false;
219
220 if (core_freesync->num_entities < MOD_FREESYNC_MAX_CONCURRENT_STREAMS) {
221
222 dc_stream_retain(stream);
223
224 core_freesync->map[core_freesync->num_entities].stream = stream;
225 core_freesync->map[core_freesync->num_entities].caps = caps;
226
227 core_freesync->map[core_freesync->num_entities].state.
228 fullscreen = false;
229 core_freesync->map[core_freesync->num_entities].state.
230 static_screen = false;
231 core_freesync->map[core_freesync->num_entities].state.
232 video = false;
233 core_freesync->map[core_freesync->num_entities].state.time.
234 update_duration_in_ns = 0;
235 core_freesync->map[core_freesync->num_entities].state.
236 static_ramp.ramp_is_active = false;
237
238 /* get persistent data from registry */
239 if (dm_read_persistent_data(core_dc->ctx, stream->sink,
240 FREESYNC_REGISTRY_NAME,
241 "userenable", &persistent_freesync_enable,
242 sizeof(int), &flag)) {
243 core_freesync->map[core_freesync->num_entities].user_enable.
244 enable_for_gaming =
245 (persistent_freesync_enable & 1) ? true : false;
246 core_freesync->map[core_freesync->num_entities].user_enable.
247 enable_for_static =
248 (persistent_freesync_enable & 2) ? true : false;
249 core_freesync->map[core_freesync->num_entities].user_enable.
250 enable_for_video =
251 (persistent_freesync_enable & 4) ? true : false;
252 } else {
253 core_freesync->map[core_freesync->num_entities].user_enable.
254 enable_for_gaming = false;
255 core_freesync->map[core_freesync->num_entities].user_enable.
256 enable_for_static = false;
257 core_freesync->map[core_freesync->num_entities].user_enable.
258 enable_for_video = false;
259 }
260
261 if (caps->supported)
262 core_stream->public.ignore_msa_timing_param = 1;
263
264 core_freesync->num_entities++;
265 return true;
266 }
267 return false;
268}
269
270bool mod_freesync_remove_stream(struct mod_freesync *mod_freesync,
271 const struct dc_stream *stream)
272{
273 struct core_freesync *core_freesync =
274 MOD_FREESYNC_TO_CORE(mod_freesync);
275
276 int i = 0;
277 unsigned int index = map_index_from_stream(core_freesync, stream);
278 dc_stream_release(core_freesync->map[index].stream);
279 core_freesync->map[index].stream = NULL;
280 /* To remove this entity, shift everything after down */
281 for (i = index; i < core_freesync->num_entities - 1; i++)
282 core_freesync->map[i] = core_freesync->map[i + 1];
283 core_freesync->num_entities--;
284 return true;
285}
286
287static void update_stream_freesync_context(struct core_freesync *core_freesync,
288 const struct dc_stream *stream)
289{
290 unsigned int index;
291 struct freesync_context *ctx;
292 struct core_stream *core_stream;
293
294 core_stream = DC_STREAM_TO_CORE(stream);
295 ctx = &core_stream->public.freesync_ctx;
296
297 index = map_index_from_stream(core_freesync, stream);
298
299 ctx->supported = core_freesync->map[index].caps->supported;
300 ctx->enabled = (core_freesync->map[index].user_enable.enable_for_gaming ||
301 core_freesync->map[index].user_enable.enable_for_video ||
302 core_freesync->map[index].user_enable.enable_for_static);
303 ctx->active = (core_freesync->map[index].state.fullscreen ||
304 core_freesync->map[index].state.video ||
305 core_freesync->map[index].state.static_ramp.ramp_is_active);
306 ctx->min_refresh_in_micro_hz =
307 core_freesync->map[index].caps->min_refresh_in_micro_hz;
308 ctx->nominal_refresh_in_micro_hz = core_freesync->
309 map[index].state.nominal_refresh_rate_in_micro_hz;
310
311}
312
313static void update_stream(struct core_freesync *core_freesync,
314 const struct dc_stream *stream)
315{
316 struct core_stream *core_stream = DC_STREAM_TO_CORE(stream);
317
318 unsigned int index = map_index_from_stream(core_freesync, stream);
319 if (core_freesync->map[index].caps->supported) {
320 core_stream->public.ignore_msa_timing_param = 1;
321 update_stream_freesync_context(core_freesync, stream);
322 }
323}
324
325static void calc_vmin_vmax(struct core_freesync *core_freesync,
326 const struct dc_stream *stream, int *vmin, int *vmax)
327{
328 unsigned int min_frame_duration_in_ns = 0, max_frame_duration_in_ns = 0;
329 unsigned int index = map_index_from_stream(core_freesync, stream);
330
331 min_frame_duration_in_ns = ((unsigned int) (div64_u64(
332 (1000000000ULL * 1000000),
333 core_freesync->map[index].state.
334 nominal_refresh_rate_in_micro_hz)));
335 max_frame_duration_in_ns = ((unsigned int) (div64_u64(
336 (1000000000ULL * 1000000),
337 core_freesync->map[index].caps->min_refresh_in_micro_hz)));
338
339 *vmax = div64_u64(div64_u64(((unsigned long long)(
340 max_frame_duration_in_ns) * stream->timing.pix_clk_khz),
341 stream->timing.h_total), 1000000);
342 *vmin = div64_u64(div64_u64(((unsigned long long)(
343 min_frame_duration_in_ns) * stream->timing.pix_clk_khz),
344 stream->timing.h_total), 1000000);
345}
346
347static void calc_v_total_from_duration(const struct dc_stream *stream,
348 unsigned int duration_in_ns, int *v_total_nominal)
349{
350 *v_total_nominal = div64_u64(div64_u64(((unsigned long long)(
351 duration_in_ns) * stream->timing.pix_clk_khz),
352 stream->timing.h_total), 1000000);
353}
354
355static void calc_v_total_for_static_ramp(struct core_freesync *core_freesync,
356 const struct dc_stream *stream,
357 unsigned int index, int *v_total)
358{
359 unsigned int frame_duration = 0;
360
361 struct gradual_static_ramp *static_ramp_variables =
362 &core_freesync->map[index].state.static_ramp;
363
364 /* Calc ratio between new and current frame duration with 3 digit */
365 unsigned int frame_duration_ratio = div64_u64(1000000,
366 (1000 + div64_u64(((unsigned long long)(
367 STATIC_SCREEN_RAMP_DELTA_REFRESH_RATE_PER_FRAME) *
368 static_ramp_variables->ramp_current_frame_duration_in_ns),
369 1000000000)));
370
371 /* Calculate delta between new and current frame duration in ns */
372 unsigned int frame_duration_delta = div64_u64(((unsigned long long)(
373 static_ramp_variables->ramp_current_frame_duration_in_ns) *
374 (1000 - frame_duration_ratio)), 1000);
375
376 /* Adjust frame duration delta based on ratio between current and
377 * standard frame duration (frame duration at 60 Hz refresh rate).
378 */
379 unsigned int ramp_rate_interpolated = div64_u64(((unsigned long long)(
380 frame_duration_delta) * static_ramp_variables->
381 ramp_current_frame_duration_in_ns), 16666666);
382
383 /* Going to a higher refresh rate (lower frame duration) */
384 if (static_ramp_variables->ramp_direction_is_up) {
385 /* reduce frame duration */
386 static_ramp_variables->ramp_current_frame_duration_in_ns -=
387 ramp_rate_interpolated;
388
389 /* min frame duration */
390 frame_duration = ((unsigned int) (div64_u64(
391 (1000000000ULL * 1000000),
392 core_freesync->map[index].state.
393 nominal_refresh_rate_in_micro_hz)));
394
395 /* adjust for frame duration below min */
396 if (static_ramp_variables->ramp_current_frame_duration_in_ns <=
397 frame_duration) {
398
399 static_ramp_variables->ramp_is_active = false;
400 static_ramp_variables->
401 ramp_current_frame_duration_in_ns =
402 frame_duration;
403 }
404 /* Going to a lower refresh rate (larger frame duration) */
405 } else {
406 /* increase frame duration */
407 static_ramp_variables->ramp_current_frame_duration_in_ns +=
408 ramp_rate_interpolated;
409
410 /* max frame duration */
411 frame_duration = ((unsigned int) (div64_u64(
412 (1000000000ULL * 1000000),
413 core_freesync->map[index].caps->min_refresh_in_micro_hz)));
414
415 /* adjust for frame duration above max */
416 if (static_ramp_variables->ramp_current_frame_duration_in_ns >=
417 frame_duration) {
418
419 static_ramp_variables->ramp_is_active = false;
420 static_ramp_variables->
421 ramp_current_frame_duration_in_ns =
422 frame_duration;
423 }
424 }
425
426 calc_v_total_from_duration(stream, static_ramp_variables->
427 ramp_current_frame_duration_in_ns, v_total);
428}
429
430static void reset_freesync_state_variables(struct freesync_state* state)
431{
432 state->static_ramp.ramp_is_active = false;
433 if (state->nominal_refresh_rate_in_micro_hz)
434 state->static_ramp.ramp_current_frame_duration_in_ns =
435 ((unsigned int) (div64_u64(
436 (1000000000ULL * 1000000),
437 state->nominal_refresh_rate_in_micro_hz)));
438
439 state->btr.btr_active = false;
440 state->btr.frame_counter = 0;
441 state->btr.frames_to_insert = 0;
442 state->btr.inserted_frame_duration_in_us = 0;
443 state->btr.program_btr = false;
444
445 state->fixed_refresh.fixed_refresh_active = false;
446 state->fixed_refresh.program_fixed_refresh = false;
447}
448/*
449 * Sets freesync mode on a stream depending on current freesync state.
450 */
451static bool set_freesync_on_streams(struct core_freesync *core_freesync,
452 const struct dc_stream **streams, int num_streams)
453{
454 int v_total_nominal = 0, v_total_min = 0, v_total_max = 0;
455 unsigned int stream_idx, map_index = 0;
456 struct freesync_state *state;
457
458 if (num_streams == 0 || streams == NULL || num_streams > 1)
459 return false;
460
461 for (stream_idx = 0; stream_idx < num_streams; stream_idx++) {
462
463 map_index = map_index_from_stream(core_freesync,
464 streams[stream_idx]);
465
466 state = &core_freesync->map[map_index].state;
467
468 if (core_freesync->map[map_index].caps->supported) {
469
470 /* Fullscreen has the topmost priority. If the
471 * fullscreen bit is set, we are in a fullscreen
472 * application where it should not matter if it is
473 * static screen. We should not check the static_screen
474 * or video bit.
475 *
476 * Special cases of fullscreen include btr and fixed
477 * refresh. We program btr on every flip and involves
478 * programming full range right before the last inserted frame.
479 * However, we do not want to program the full freesync range
480 * when fixed refresh is active, because we only program
481 * that logic once and this will override it.
482 */
483 if (core_freesync->map[map_index].user_enable.
484 enable_for_gaming == true &&
485 state->fullscreen == true &&
486 state->fixed_refresh.fixed_refresh_active == false) {
487 /* Enable freesync */
488
489 calc_vmin_vmax(core_freesync,
490 streams[stream_idx],
491 &v_total_min, &v_total_max);
492
493 /* Update the freesync context for the stream */
494 update_stream_freesync_context(core_freesync,
495 streams[stream_idx]);
496
497 core_freesync->dc->stream_funcs.
498 adjust_vmin_vmax(core_freesync->dc, streams,
499 num_streams, v_total_min,
500 v_total_max);
501
502 return true;
503
504 } else if (core_freesync->map[map_index].user_enable.
505 enable_for_video && state->video == true) {
506 /* Enable 48Hz feature */
507
508 calc_v_total_from_duration(streams[stream_idx],
509 state->time.update_duration_in_ns,
510 &v_total_nominal);
511
512 /* Program only if v_total_nominal is in range*/
513 if (v_total_nominal >=
514 streams[stream_idx]->timing.v_total) {
515
516 /* Update the freesync context for
517 * the stream
518 */
519 update_stream_freesync_context(
520 core_freesync,
521 streams[stream_idx]);
522
523 core_freesync->dc->stream_funcs.
524 adjust_vmin_vmax(
525 core_freesync->dc, streams,
526 num_streams, v_total_nominal,
527 v_total_nominal);
528 }
529 return true;
530
531 } else {
532 /* Disable freesync */
533 v_total_nominal = streams[stream_idx]->
534 timing.v_total;
535
536 /* Update the freesync context for
537 * the stream
538 */
539 update_stream_freesync_context(
540 core_freesync,
541 streams[stream_idx]);
542
543 core_freesync->dc->stream_funcs.
544 adjust_vmin_vmax(
545 core_freesync->dc, streams,
546 num_streams, v_total_nominal,
547 v_total_nominal);
548
549 /* Reset the cached variables */
550 reset_freesync_state_variables(state);
551
552 return true;
553 }
554 } else {
555 /* Disable freesync */
556 v_total_nominal = streams[stream_idx]->
557 timing.v_total;
558 /*
559 * we have to reset drr always even sink does
560 * not support freesync because a former stream has
561 * be programmed
562 */
563 core_freesync->dc->stream_funcs.
564 adjust_vmin_vmax(
565 core_freesync->dc, streams,
566 num_streams, v_total_nominal,
567 v_total_nominal);
568 /* Reset the cached variables */
569 reset_freesync_state_variables(state);
570 }
571
572 }
573
574 return false;
575}
576
577static void set_static_ramp_variables(struct core_freesync *core_freesync,
578 unsigned int index, bool enable_static_screen)
579{
580 unsigned int frame_duration = 0;
581
582 struct gradual_static_ramp *static_ramp_variables =
583 &core_freesync->map[index].state.static_ramp;
584
585 /* If ramp is not active, set initial frame duration depending on
586 * whether we are enabling/disabling static screen mode. If the ramp is
587 * already active, ramp should continue in the opposite direction
588 * starting with the current frame duration
589 */
590 if (!static_ramp_variables->ramp_is_active) {
591
592 static_ramp_variables->ramp_is_active = true;
593
594 if (enable_static_screen == true) {
595 /* Going to lower refresh rate, so start from max
596 * refresh rate (min frame duration)
597 */
598 frame_duration = ((unsigned int) (div64_u64(
599 (1000000000ULL * 1000000),
600 core_freesync->map[index].state.
601 nominal_refresh_rate_in_micro_hz)));
602 } else {
603 /* Going to higher refresh rate, so start from min
604 * refresh rate (max frame duration)
605 */
606 frame_duration = ((unsigned int) (div64_u64(
607 (1000000000ULL * 1000000),
608 core_freesync->map[index].caps->min_refresh_in_micro_hz)));
609 }
610
611 static_ramp_variables->
612 ramp_current_frame_duration_in_ns = frame_duration;
613 }
614
615 /* If we are ENABLING static screen, refresh rate should go DOWN.
616 * If we are DISABLING static screen, refresh rate should go UP.
617 */
618 static_ramp_variables->ramp_direction_is_up = !enable_static_screen;
619}
620
621void mod_freesync_handle_v_update(struct mod_freesync *mod_freesync,
622 const struct dc_stream **streams, int num_streams)
623{
624 struct core_freesync *core_freesync =
625 MOD_FREESYNC_TO_CORE(mod_freesync);
626
627 unsigned int index, v_total = 0;
628 struct freesync_state *state;
629
630 if (core_freesync->num_entities == 0)
631 return;
632
633 index = map_index_from_stream(core_freesync,
634 streams[0]);
635
636 if (core_freesync->map[index].caps->supported == false)
637 return;
638
639 state = &core_freesync->map[index].state;
640
641 /* Below the Range Logic */
642
643 /* Only execute if in fullscreen mode */
644 if (state->fullscreen == true &&
645 core_freesync->map[index].user_enable.enable_for_gaming) {
646
647 if (state->btr.btr_active)
648 if (state->btr.frame_counter > 0)
649
650 state->btr.frame_counter--;
651
652 if (state->btr.frame_counter == 1) {
653
654 /* Restore FreeSync */
655 set_freesync_on_streams(core_freesync, streams,
656 num_streams);
657 }
658 }
659
660 /* If in fullscreen freesync mode or in video, do not program
661 * static screen ramp values
662 */
663 if (state->fullscreen == true || state->video == true) {
664
665 state->static_ramp.ramp_is_active = false;
666
667 return;
668 }
669
670 /* Gradual Static Screen Ramping Logic */
671
672 /* Execute if ramp is active and user enabled freesync static screen*/
673 if (state->static_ramp.ramp_is_active &&
674 core_freesync->map[index].user_enable.enable_for_static) {
675
676 calc_v_total_for_static_ramp(core_freesync, streams[0],
677 index, &v_total);
678
679 /* Update the freesync context for the stream */
680 update_stream_freesync_context(core_freesync, streams[0]);
681
682 /* Program static screen ramp values */
683 core_freesync->dc->stream_funcs.adjust_vmin_vmax(
684 core_freesync->dc, streams,
685 num_streams, v_total,
686 v_total);
687 }
688}
689
690void mod_freesync_update_state(struct mod_freesync *mod_freesync,
691 const struct dc_stream **streams, int num_streams,
692 struct mod_freesync_params *freesync_params)
693{
694 struct core_freesync *core_freesync =
695 MOD_FREESYNC_TO_CORE(mod_freesync);
696 bool freesync_program_required = false;
697 unsigned int stream_index;
698 struct freesync_state *state;
699
700 if (core_freesync->num_entities == 0)
701 return;
702
703 for(stream_index = 0; stream_index < num_streams; stream_index++) {
704
705 unsigned int map_index = map_index_from_stream(core_freesync,
706 streams[stream_index]);
707
708 state = &core_freesync->map[map_index].state;
709
710 switch (freesync_params->state){
711 case FREESYNC_STATE_FULLSCREEN:
712 state->fullscreen = freesync_params->enable;
713 freesync_program_required = true;
714 state->windowed_fullscreen =
715 freesync_params->windowed_fullscreen;
716 break;
717 case FREESYNC_STATE_STATIC_SCREEN:
718 /* Static screen ramp is only enabled for embedded
719 * panels. Also change core variables only if there
720 * is a change.
721 */
722 if (dc_is_embedded_signal(
723 streams[stream_index]->sink->sink_signal) &&
724 state->static_screen !=
725 freesync_params->enable) {
726
727 /* Change the state flag */
728 state->static_screen = freesync_params->enable;
729
730 /* Change static screen ramp variables */
731 set_static_ramp_variables(core_freesync,
732 map_index,
733 freesync_params->enable);
734 }
735 /* We program the ramp starting next VUpdate */
736 break;
737 case FREESYNC_STATE_VIDEO:
738 /* Change core variables only if there is a change*/
739 if(freesync_params->update_duration_in_ns !=
740 state->time.update_duration_in_ns) {
741
742 state->video = freesync_params->enable;
743 state->time.update_duration_in_ns =
744 freesync_params->update_duration_in_ns;
745
746 freesync_program_required = true;
747 }
748 break;
749 }
750 }
751
752 if (freesync_program_required)
753 /* Program freesync according to current state*/
754 set_freesync_on_streams(core_freesync, streams, num_streams);
755}
756
757
758bool mod_freesync_get_state(struct mod_freesync *mod_freesync,
759 const struct dc_stream *stream,
760 struct mod_freesync_params *freesync_params)
761{
762 struct core_freesync *core_freesync =
763 MOD_FREESYNC_TO_CORE(mod_freesync);
764
765 unsigned int index = map_index_from_stream(core_freesync, stream);
766
767 if (core_freesync->map[index].state.fullscreen) {
768 freesync_params->state = FREESYNC_STATE_FULLSCREEN;
769 freesync_params->enable = true;
770 } else if (core_freesync->map[index].state.static_screen) {
771 freesync_params->state = FREESYNC_STATE_STATIC_SCREEN;
772 freesync_params->enable = true;
773 } else if (core_freesync->map[index].state.video) {
774 freesync_params->state = FREESYNC_STATE_VIDEO;
775 freesync_params->enable = true;
776 } else {
777 freesync_params->state = FREESYNC_STATE_NONE;
778 freesync_params->enable = false;
779 }
780
781 freesync_params->update_duration_in_ns =
782 core_freesync->map[index].state.time.update_duration_in_ns;
783
784 return true;
785}
786
787bool mod_freesync_set_user_enable(struct mod_freesync *mod_freesync,
788 const struct dc_stream **streams, int num_streams,
789 struct mod_freesync_user_enable *user_enable)
790{
791 struct core_freesync *core_freesync =
792 MOD_FREESYNC_TO_CORE(mod_freesync);
793 struct core_dc *core_dc = DC_TO_CORE(core_freesync->dc);
794
795 unsigned int stream_index, map_index;
796 int persistent_data = 0;
797 struct persistent_data_flag flag;
798
799 flag.save_per_edid = true;
800 flag.save_per_link = false;
801
802 for(stream_index = 0; stream_index < num_streams;
803 stream_index++){
804
805 map_index = map_index_from_stream(core_freesync,
806 streams[stream_index]);
807
808 core_freesync->map[map_index].user_enable = *user_enable;
809
810 /* Write persistent data in registry*/
811 if (core_freesync->map[map_index].user_enable.
812 enable_for_gaming)
813 persistent_data = persistent_data | 1;
814 if (core_freesync->map[map_index].user_enable.
815 enable_for_static)
816 persistent_data = persistent_data | 2;
817 if (core_freesync->map[map_index].user_enable.
818 enable_for_video)
819 persistent_data = persistent_data | 4;
820
821 dm_write_persistent_data(core_dc->ctx,
822 streams[stream_index]->sink,
823 FREESYNC_REGISTRY_NAME,
824 "userenable",
825 &persistent_data,
826 sizeof(int),
827 &flag);
828 }
829
830 set_freesync_on_streams(core_freesync, streams, num_streams);
831
832 return true;
833}
834
835bool mod_freesync_get_user_enable(struct mod_freesync *mod_freesync,
836 const struct dc_stream *stream,
837 struct mod_freesync_user_enable *user_enable)
838{
839 struct core_freesync *core_freesync =
840 MOD_FREESYNC_TO_CORE(mod_freesync);
841
842 unsigned int index = map_index_from_stream(core_freesync, stream);
843
844 *user_enable = core_freesync->map[index].user_enable;
845
846 return true;
847}
848
849void mod_freesync_notify_mode_change(struct mod_freesync *mod_freesync,
850 const struct dc_stream **streams, int num_streams)
851{
852 struct core_freesync *core_freesync =
853 MOD_FREESYNC_TO_CORE(mod_freesync);
854
855 unsigned int stream_index, map_index;
856 unsigned min_frame_duration_in_ns, max_frame_duration_in_ns;
857 struct freesync_state *state;
858
859 for (stream_index = 0; stream_index < num_streams; stream_index++) {
860
861 map_index = map_index_from_stream(core_freesync,
862 streams[stream_index]);
863
864 state = &core_freesync->map[map_index].state;
865
866 if (core_freesync->map[map_index].caps->supported) {
867 /* Update the field rate for new timing */
868 state->nominal_refresh_rate_in_micro_hz = 1000000 *
869 div64_u64(div64_u64((streams[stream_index]->
870 timing.pix_clk_khz * 1000),
871 streams[stream_index]->timing.v_total),
872 streams[stream_index]->timing.h_total);
873
874 /* Update the stream */
875 update_stream(core_freesync, streams[stream_index]);
876
877 /* Determine whether BTR can be supported */
878 min_frame_duration_in_ns = ((unsigned int) (div64_u64(
879 (1000000000ULL * 1000000),
880 state->nominal_refresh_rate_in_micro_hz)));
881
882 max_frame_duration_in_ns = ((unsigned int) (div64_u64(
883 (1000000000ULL * 1000000),
884 core_freesync->map[map_index].caps->min_refresh_in_micro_hz)));
885
886 if (max_frame_duration_in_ns >=
887 2 * min_frame_duration_in_ns)
888 core_freesync->map[map_index].caps->btr_supported = true;
889 else
890 core_freesync->map[map_index].caps->btr_supported = false;
891
892 /* Cache the time variables */
893 state->time.max_render_time_in_us =
894 max_frame_duration_in_ns / 1000;
895 state->time.min_render_time_in_us =
896 min_frame_duration_in_ns / 1000;
897 state->btr.mid_point_in_us =
898 (max_frame_duration_in_ns +
899 min_frame_duration_in_ns) / 2000;
900
901 }
902 }
903
904 /* Program freesync according to current state*/
905 set_freesync_on_streams(core_freesync, streams, num_streams);
906}
907
908/* Add the timestamps to the cache and determine whether BTR programming
909 * is required, depending on the times calculated
910 */
911static void update_timestamps(struct core_freesync *core_freesync,
912 const struct dc_stream *stream, unsigned int map_index,
913 unsigned int last_render_time_in_us)
914{
915 struct freesync_state *state = &core_freesync->map[map_index].state;
916
917 state->time.render_times[state->time.render_times_index] =
918 last_render_time_in_us;
919 state->time.render_times_index++;
920
921 if (state->time.render_times_index >= RENDER_TIMES_MAX_COUNT)
922 state->time.render_times_index = 0;
923
924 if (last_render_time_in_us + BTR_EXIT_MARGIN <
925 state->time.max_render_time_in_us) {
926
927 /* Exit Below the Range */
928 if (state->btr.btr_active) {
929
930 state->btr.program_btr = true;
931 state->btr.btr_active = false;
932 state->btr.frame_counter = 0;
933
934 /* Exit Fixed Refresh mode */
935 } else if (state->fixed_refresh.fixed_refresh_active) {
936
937 state->fixed_refresh.program_fixed_refresh = true;
938 state->fixed_refresh.fixed_refresh_active = false;
939
940 }
941
942 } else if (last_render_time_in_us > state->time.max_render_time_in_us) {
943
944 /* Enter Below the Range */
945 if (!state->btr.btr_active &&
946 core_freesync->map[map_index].caps->btr_supported) {
947
948 state->btr.program_btr = true;
949 state->btr.btr_active = true;
950
951 /* Enter Fixed Refresh mode */
952 } else if (!state->fixed_refresh.fixed_refresh_active &&
953 !core_freesync->map[map_index].caps->btr_supported) {
954
955 state->fixed_refresh.program_fixed_refresh = true;
956 state->fixed_refresh.fixed_refresh_active = true;
957
958 }
959 }
960
961 /* When Below the Range is active, must react on every frame */
962 if (state->btr.btr_active)
963 state->btr.program_btr = true;
964}
965
966static void apply_below_the_range(struct core_freesync *core_freesync,
967 const struct dc_stream *stream, unsigned int map_index,
968 unsigned int last_render_time_in_us)
969{
970 unsigned int inserted_frame_duration_in_us = 0;
971 unsigned int mid_point_frames_ceil = 0;
972 unsigned int mid_point_frames_floor = 0;
973 unsigned int frame_time_in_us = 0;
974 unsigned int delta_from_mid_point_in_us_1 = 0xFFFFFFFF;
975 unsigned int delta_from_mid_point_in_us_2 = 0xFFFFFFFF;
976 unsigned int frames_to_insert = 0;
977 unsigned int inserted_frame_v_total = 0;
978 unsigned int vmin = 0, vmax = 0;
979 unsigned int min_frame_duration_in_ns = 0;
980 struct freesync_state *state = &core_freesync->map[map_index].state;
981
982 if (!state->btr.program_btr)
983 return;
984
985 state->btr.program_btr = false;
986
987 min_frame_duration_in_ns = ((unsigned int) (div64_u64(
988 (1000000000ULL * 1000000),
989 state->nominal_refresh_rate_in_micro_hz)));
990
991 /* Program BTR */
992
993 /* BTR set to "not active" so disengage */
994 if (!state->btr.btr_active)
995
996 /* Restore FreeSync */
997 set_freesync_on_streams(core_freesync, &stream, 1);
998
999 /* BTR set to "active" so engage */
1000 else {
1001
1002 /* Calculate number of midPoint frames that could fit within
1003 * the render time interval- take ceil of this value
1004 */
1005 mid_point_frames_ceil = (last_render_time_in_us +
1006 state->btr.mid_point_in_us- 1) /
1007 state->btr.mid_point_in_us;
1008
1009 if (mid_point_frames_ceil > 0) {
1010
1011 frame_time_in_us = last_render_time_in_us /
1012 mid_point_frames_ceil;
1013 delta_from_mid_point_in_us_1 = (state->btr.mid_point_in_us >
1014 frame_time_in_us) ?
1015 (state->btr.mid_point_in_us - frame_time_in_us):
1016 (frame_time_in_us - state->btr.mid_point_in_us);
1017 }
1018
1019 /* Calculate number of midPoint frames that could fit within
1020 * the render time interval- take floor of this value
1021 */
1022 mid_point_frames_floor = last_render_time_in_us /
1023 state->btr.mid_point_in_us;
1024
1025 if (mid_point_frames_floor > 0) {
1026
1027 frame_time_in_us = last_render_time_in_us /
1028 mid_point_frames_floor;
1029 delta_from_mid_point_in_us_2 = (state->btr.mid_point_in_us >
1030 frame_time_in_us) ?
1031 (state->btr.mid_point_in_us - frame_time_in_us):
1032 (frame_time_in_us - state->btr.mid_point_in_us);
1033 }
1034
1035 /* Choose number of frames to insert based on how close it
1036 * can get to the mid point of the variable range.
1037 */
1038 if (delta_from_mid_point_in_us_1 < delta_from_mid_point_in_us_2)
1039 frames_to_insert = mid_point_frames_ceil;
1040 else
1041 frames_to_insert = mid_point_frames_floor;
1042
1043 /* Either we've calculated the number of frames to insert,
1044 * or we need to insert min duration frames
1045 */
1046 if (frames_to_insert > 0)
1047 inserted_frame_duration_in_us = last_render_time_in_us /
1048 frames_to_insert;
1049
1050 if (inserted_frame_duration_in_us <
1051 state->time.min_render_time_in_us)
1052
1053 inserted_frame_duration_in_us =
1054 state->time.min_render_time_in_us;
1055
1056 /* We need the v_total_min from capability */
1057 calc_vmin_vmax(core_freesync, stream, &vmin, &vmax);
1058
1059 inserted_frame_v_total = vmin;
1060 if (min_frame_duration_in_ns / 1000)
1061 inserted_frame_v_total = inserted_frame_duration_in_us *
1062 vmin / (min_frame_duration_in_ns / 1000);
1063
1064 /* Set length of inserted frames as v_total_max*/
1065 vmax = inserted_frame_v_total;
1066
1067 /* Program V_TOTAL */
1068 core_freesync->dc->stream_funcs.adjust_vmin_vmax(
1069 core_freesync->dc, &stream,
1070 1, vmin,
1071 vmax);
1072
1073 /* Cache the calculated variables */
1074 state->btr.inserted_frame_duration_in_us =
1075 inserted_frame_duration_in_us;
1076 state->btr.frames_to_insert = frames_to_insert;
1077 state->btr.frame_counter = frames_to_insert;
1078
1079 }
1080}
1081
1082static void apply_fixed_refresh(struct core_freesync *core_freesync,
1083 const struct dc_stream *stream, unsigned int map_index)
1084{
1085 unsigned int vmin = 0, vmax = 0;
1086 struct freesync_state *state = &core_freesync->map[map_index].state;
1087
1088 if (!state->fixed_refresh.program_fixed_refresh)
1089 return;
1090
1091 state->fixed_refresh.program_fixed_refresh = false;
1092
1093 /* Program Fixed Refresh */
1094
1095 /* Fixed Refresh set to "not active" so disengage */
1096 if (!state->fixed_refresh.fixed_refresh_active) {
1097 set_freesync_on_streams(core_freesync, &stream, 1);
1098
1099 /* Fixed Refresh set to "active" so engage (fix to max) */
1100 } else {
1101
1102 calc_vmin_vmax(core_freesync, stream, &vmin, &vmax);
1103
1104 vmax = vmin;
1105
1106 core_freesync->dc->stream_funcs.adjust_vmin_vmax(
1107 core_freesync->dc, &stream,
1108 1, vmin,
1109 vmax);
1110 }
1111}
1112
1113void mod_freesync_pre_update_plane_addresses(struct mod_freesync *mod_freesync,
1114 const struct dc_stream **streams, int num_streams,
1115 unsigned int curr_time_stamp_in_us)
1116{
1117 unsigned int stream_index, map_index, last_render_time_in_us = 0;
1118 struct core_freesync *core_freesync =
1119 MOD_FREESYNC_TO_CORE(mod_freesync);
1120
1121 for (stream_index = 0; stream_index < num_streams; stream_index++) {
1122
1123 map_index = map_index_from_stream(core_freesync,
1124 streams[stream_index]);
1125
1126 if (core_freesync->map[map_index].caps->supported) {
1127
1128 last_render_time_in_us = curr_time_stamp_in_us -
1129 core_freesync->map[map_index].state.time.
1130 prev_time_stamp_in_us;
1131
1132 /* Add the timestamps to the cache and determine
1133 * whether BTR program is required
1134 */
1135 update_timestamps(core_freesync, streams[stream_index],
1136 map_index, last_render_time_in_us);
1137
1138 if (core_freesync->map[map_index].state.fullscreen &&
1139 core_freesync->map[map_index].user_enable.
1140 enable_for_gaming) {
1141
1142 if (core_freesync->map[map_index].caps->btr_supported) {
1143
1144 apply_below_the_range(core_freesync,
1145 streams[stream_index], map_index,
1146 last_render_time_in_us);
1147 } else {
1148 apply_fixed_refresh(core_freesync,
1149 streams[stream_index], map_index);
1150 }
1151 }
1152
1153 core_freesync->map[map_index].state.time.
1154 prev_time_stamp_in_us = curr_time_stamp_in_us;
1155 }
1156
1157 }
1158}
diff --git a/drivers/gpu/drm/amd/display/modules/inc/mod_color.h b/drivers/gpu/drm/amd/display/modules/inc/mod_color.h
new file mode 100644
index 000000000000..e54fe2cb8611
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/modules/inc/mod_color.h
@@ -0,0 +1,179 @@
1/*
2 * Copyright 2016 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
27#ifndef MOD_COLOR_H_
28#define MOD_COLOR_H_
29
30#include "dm_services.h"
31
32struct mod_color {
33 int dummy;
34};
35
36struct color_space_coordinates {
37 unsigned int redX;
38 unsigned int redY;
39 unsigned int greenX;
40 unsigned int greenY;
41 unsigned int blueX;
42 unsigned int blueY;
43 unsigned int whiteX;
44 unsigned int whiteY;
45};
46
47struct gamut_space_coordinates {
48 unsigned int redX;
49 unsigned int redY;
50 unsigned int greenX;
51 unsigned int greenY;
52 unsigned int blueX;
53 unsigned int blueY;
54};
55
56struct gamut_space_entry {
57 unsigned int index;
58 unsigned int redX;
59 unsigned int redY;
60 unsigned int greenX;
61 unsigned int greenY;
62 unsigned int blueX;
63 unsigned int blueY;
64
65 int a0;
66 int a1;
67 int a2;
68 int a3;
69 int gamma;
70};
71
72struct white_point_coodinates {
73 unsigned int whiteX;
74 unsigned int whiteY;
75};
76
77struct white_point_coodinates_entry {
78 unsigned int index;
79 unsigned int whiteX;
80 unsigned int whiteY;
81};
82
83struct color_range {
84 int current;
85 int min;
86 int max;
87};
88
89struct mod_color *mod_color_create(struct dc *dc);
90
91void mod_color_destroy(struct mod_color *mod_color);
92
93bool mod_color_add_sink(struct mod_color *mod_color,
94 const struct dc_sink *sink);
95
96bool mod_color_remove_sink(struct mod_color *mod_color,
97 const struct dc_sink *sink);
98
99bool mod_color_update_gamut_to_stream(struct mod_color *mod_color,
100 const struct dc_stream **streams, int num_streams);
101
102bool mod_color_set_white_point(struct mod_color *mod_color,
103 const struct dc_stream **streams, int num_streams,
104 struct white_point_coodinates *white_point);
105
106bool mod_color_adjust_source_gamut(struct mod_color *mod_color,
107 const struct dc_stream **streams, int num_streams,
108 struct gamut_space_coordinates *input_gamut_coordinates,
109 struct white_point_coodinates *input_white_point_coordinates);
110
111bool mod_color_adjust_destination_gamut(struct mod_color *mod_color,
112 const struct dc_stream **streams, int num_streams,
113 struct gamut_space_coordinates *input_gamut_coordinates,
114 struct white_point_coodinates *input_white_point_coordinates);
115
116bool mod_color_get_user_enable(struct mod_color *mod_color,
117 const struct dc_sink *sink,
118 bool *user_enable);
119
120bool mod_color_set_user_enable(struct mod_color *mod_color,
121 const struct dc_stream **streams, int num_streams,
122 bool user_enable);
123
124bool mod_color_get_custom_color_temperature(struct mod_color *mod_color,
125 const struct dc_sink *sink,
126 int *color_temperature);
127
128bool mod_color_set_custom_color_temperature(struct mod_color *mod_color,
129 const struct dc_stream **streams, int num_streams,
130 int color_temperature);
131
132bool mod_color_get_color_saturation(struct mod_color *mod_color,
133 const struct dc_sink *sink,
134 struct color_range *color_saturation);
135
136bool mod_color_get_color_contrast(struct mod_color *mod_color,
137 const struct dc_sink *sink,
138 struct color_range *color_contrast);
139
140bool mod_color_get_color_brightness(struct mod_color *mod_color,
141 const struct dc_sink *sink,
142 struct color_range *color_brightness);
143
144bool mod_color_get_color_hue(struct mod_color *mod_color,
145 const struct dc_sink *sink,
146 struct color_range *color_hue);
147
148bool mod_color_get_source_gamut(struct mod_color *mod_color,
149 const struct dc_sink *sink,
150 struct color_space_coordinates *source_gamut);
151
152bool mod_color_notify_mode_change(struct mod_color *mod_color,
153 const struct dc_stream **streams, int num_streams);
154
155bool mod_color_set_brightness(struct mod_color *mod_color,
156 const struct dc_stream **streams, int num_streams,
157 int brightness_value);
158
159bool mod_color_set_contrast(struct mod_color *mod_color,
160 const struct dc_stream **streams, int num_streams,
161 int contrast_value);
162
163bool mod_color_set_hue(struct mod_color *mod_color,
164 const struct dc_stream **streams, int num_streams,
165 int hue_value);
166
167bool mod_color_set_saturation(struct mod_color *mod_color,
168 const struct dc_stream **streams, int num_streams,
169 int saturation_value);
170
171bool mod_color_set_preferred_quantization_range(struct mod_color *mod_color,
172 const struct dc_sink *sink,
173 enum dc_quantization_range quantization_range);
174
175bool mod_color_get_preferred_quantization_range(struct mod_color *mod_color,
176 const struct dc_sink *sink,
177 enum dc_quantization_range *quantization_range);
178
179#endif /* MOD_COLOR_H_ */
diff --git a/drivers/gpu/drm/amd/display/modules/inc/mod_freesync.h b/drivers/gpu/drm/amd/display/modules/inc/mod_freesync.h
new file mode 100644
index 000000000000..7abfe34dc2d9
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/modules/inc/mod_freesync.h
@@ -0,0 +1,149 @@
1/*
2 * Copyright 2016 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
27
28
29/*
30 * Copyright 2016 Advanced Micro Devices, Inc.
31 *
32 * Permission is hereby granted, free of charge, to any person obtaining a
33 * copy of this software and associated documentation files (the "Software"),
34 * to deal in the Software without restriction, including without limitation
35 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
36 * and/or sell copies of the Software, and to permit persons to whom the
37 * Software is furnished to do so, subject to the following conditions:
38 *
39 * The above copyright notice and this permission notice shall be included in
40 * all copies or substantial portions of the Software.
41 *
42 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
43 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
44 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
45 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
46 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
47 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
48 * OTHER DEALINGS IN THE SOFTWARE.
49 *
50 * Authors: AMD
51 *
52 */
53
54#ifndef MOD_FREESYNC_H_
55#define MOD_FREESYNC_H_
56
57#include "dm_services.h"
58
59struct mod_freesync *mod_freesync_create(struct dc *dc);
60void mod_freesync_destroy(struct mod_freesync *mod_freesync);
61
62struct mod_freesync {
63 int dummy;
64};
65
66enum mod_freesync_state {
67 FREESYNC_STATE_NONE,
68 FREESYNC_STATE_FULLSCREEN,
69 FREESYNC_STATE_STATIC_SCREEN,
70 FREESYNC_STATE_VIDEO
71};
72
73enum mod_freesync_user_enable_mask {
74 FREESYNC_USER_ENABLE_STATIC = 0x1,
75 FREESYNC_USER_ENABLE_VIDEO = 0x2,
76 FREESYNC_USER_ENABLE_GAMING = 0x4
77};
78
79struct mod_freesync_user_enable {
80 bool enable_for_static;
81 bool enable_for_video;
82 bool enable_for_gaming;
83};
84
85struct mod_freesync_caps {
86 bool supported;
87 unsigned int min_refresh_in_micro_hz;
88 unsigned int max_refresh_in_micro_hz;
89
90 bool btr_supported;
91};
92
93struct mod_freesync_params {
94 enum mod_freesync_state state;
95 bool enable;
96 unsigned int update_duration_in_ns;
97 bool windowed_fullscreen;
98};
99
100/*
101 * Add stream to be tracked by module
102 */
103bool mod_freesync_add_stream(struct mod_freesync *mod_freesync,
104 const struct dc_stream *stream, struct mod_freesync_caps *caps);
105
106/*
107 * Remove stream to be tracked by module
108 */
109bool mod_freesync_remove_stream(struct mod_freesync *mod_freesync,
110 const struct dc_stream *stream);
111
112/*
113 * Build additional parameters for dc_stream when creating stream for
114 * sink to support freesync
115 */
116void mod_freesync_update_stream(struct mod_freesync *mod_freesync,
117 struct dc_stream *stream);
118
119/*
120 * Update the freesync state flags for each display and program
121 * freesync accordingly
122 */
123void mod_freesync_update_state(struct mod_freesync *mod_freesync,
124 const struct dc_stream **streams, int num_streams,
125 struct mod_freesync_params *freesync_params);
126
127bool mod_freesync_get_state(struct mod_freesync *mod_freesync,
128 const struct dc_stream *stream,
129 struct mod_freesync_params *freesync_params);
130
131bool mod_freesync_set_user_enable(struct mod_freesync *mod_freesync,
132 const struct dc_stream **streams, int num_streams,
133 struct mod_freesync_user_enable *user_enable);
134
135bool mod_freesync_get_user_enable(struct mod_freesync *mod_freesync,
136 const struct dc_stream *stream,
137 struct mod_freesync_user_enable *user_enable);
138
139void mod_freesync_handle_v_update(struct mod_freesync *mod_freesync,
140 const struct dc_stream **streams, int num_streams);
141
142void mod_freesync_notify_mode_change(struct mod_freesync *mod_freesync,
143 const struct dc_stream **streams, int num_streams);
144
145void mod_freesync_pre_update_plane_addresses(struct mod_freesync *mod_freesync,
146 const struct dc_stream **streams, int num_streams,
147 unsigned int curr_time_stamp);
148
149#endif
diff --git a/drivers/gpu/drm/amd/display/modules/inc/mod_power.h b/drivers/gpu/drm/amd/display/modules/inc/mod_power.h
new file mode 100644
index 000000000000..a204e8d6cd23
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/modules/inc/mod_power.h
@@ -0,0 +1,112 @@
1/*
2 * Copyright 2016 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#ifndef MODULES_INC_MOD_POWER_H_
27#define MODULES_INC_MOD_POWER_H_
28
29#include "dm_services.h"
30
31struct mod_power {
32 int dummy;
33};
34
35/* VariBright related commands */
36enum varibright_command {
37 VariBright_Cmd__SetVBLevel = 0,
38 VariBright_Cmd__UserEnable,
39 VariBright_Cmd__PreDisplayConfigChange,
40 VariBright_Cmd__PostDisplayConfigChange,
41 VariBright_Cmd__SuspendABM,
42 VariBright_Cmd__ResumeABM,
43
44 VariBright_Cmd__Unknown,
45};
46
47/* VariBright settings structure */
48struct varibright_info {
49 enum varibright_command cmd;
50
51 unsigned int level;
52 bool enable;
53 bool activate;
54};
55
56enum dmcu_block_psr_reason {
57 /* This is a bitfield mask */
58 dmcu_block_psr_reason_invalid = 0x0,
59 dmcu_block_psr_reason_vsync_int = 0x1,
60 dmcu_block_psr_reason_shared_primary = 0x2,
61 dmcu_block_psr_reason_unsupported_link_rate = 0x4
62};
63
64struct mod_power *mod_power_create(struct dc *dc);
65
66void mod_power_destroy(struct mod_power *mod_power);
67
68bool mod_power_add_sink(struct mod_power *mod_power,
69 const struct dc_sink *sink);
70
71bool mod_power_remove_sink(struct mod_power *mod_power,
72 const struct dc_sink *sink);
73
74bool mod_power_set_backlight(struct mod_power *mod_power,
75 const struct dc_stream **streams, int num_streams,
76 unsigned int backlight_8bit);
77
78bool mod_power_get_backlight(struct mod_power *mod_power,
79 const struct dc_sink *sink,
80 unsigned int *backlight_8bit);
81
82void mod_power_initialize_backlight_caps
83 (struct mod_power *mod_power);
84
85unsigned int mod_power_backlight_level_percentage_to_signal
86 (struct mod_power *mod_power, unsigned int percentage);
87
88unsigned int mod_power_backlight_level_signal_to_percentage
89 (struct mod_power *mod_power, unsigned int signalLevel8bit);
90
91bool mod_power_get_panel_backlight_boundaries
92 (struct mod_power *mod_power,
93 unsigned int *min_backlight,
94 unsigned int *max_backlight,
95 unsigned int *output_ac_level_percentage,
96 unsigned int *output_dc_level_percentage);
97
98bool mod_power_set_smooth_brightness(struct mod_power *mod_power,
99 const struct dc_sink *sink, bool enable_brightness);
100
101bool mod_power_notify_mode_change(struct mod_power *mod_power,
102 const struct dc_stream *stream);
103
104bool mod_power_varibright_control(struct mod_power *mod_power,
105 struct varibright_info *input_varibright_info);
106
107bool mod_power_block_psr(bool block_enable, enum dmcu_block_psr_reason reason);
108
109bool mod_power_set_psr_enable(struct mod_power *mod_power,
110 bool psr_enable);
111
112#endif /* MODULES_INC_MOD_POWER_H_ */
diff --git a/drivers/gpu/drm/amd/display/modules/power/power.c b/drivers/gpu/drm/amd/display/modules/power/power.c
new file mode 100644
index 000000000000..ea07e847da0a
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/modules/power/power.c
@@ -0,0 +1,784 @@
1/*
2 * Copyright 2016 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 "mod_power.h"
27#include "dm_services.h"
28#include "dc.h"
29#include "core_types.h"
30#include "core_dc.h"
31
32#define MOD_POWER_MAX_CONCURRENT_SINKS 32
33#define SMOOTH_BRIGHTNESS_ADJUSTMENT_TIME_IN_MS 500
34
35struct sink_caps {
36 const struct dc_sink *sink;
37};
38
39struct backlight_state {
40 unsigned int backlight;
41 unsigned int frame_ramp;
42 bool smooth_brightness_enabled;
43};
44
45struct core_power {
46 struct mod_power public;
47 struct dc *dc;
48 int num_sinks;
49 struct sink_caps *caps;
50 struct backlight_state *state;
51};
52
53union dmcu_abm_set_bl_params {
54 struct {
55 unsigned int gradual_change : 1; /* [0:0] */
56 unsigned int reserved : 15; /* [15:1] */
57 unsigned int frame_ramp : 16; /* [31:16] */
58 } bits;
59 unsigned int u32All;
60};
61
62/* Backlight cached properties */
63static unsigned int backlight_8bit_lut_array[101];
64static unsigned int ac_level_percentage;
65static unsigned int dc_level_percentage;
66static bool backlight_caps_valid;
67/* we use lazy initialization of backlight capabilities cache */
68static bool backlight_caps_initialized;
69/* AC/DC levels initialized later in separate context */
70static bool backlight_def_levels_valid;
71
72/* ABM cached properties */
73static unsigned int abm_level;
74static bool abm_user_enable;
75static bool abm_active;
76
77/*PSR cached properties*/
78static unsigned int block_psr;
79
80/* Defines default backlight curve F(x) = A(x*x) + Bx + C.
81 *
82 * Backlight curve should always satisfy F(0) = min, F(100) = max,
83 * so polynom coefficients are:
84 * A is 0.0255 - B/100 - min/10000 - (255-max)/10000 = (max - min)/10000 - B/100
85 * B is adjustable factor to modify the curve.
86 * Bigger B results in less concave curve. B range is [0..(max-min)/100]
87 * C is backlight minimum
88 */
89static const unsigned int backlight_curve_coeff_a_factor = 10000;
90static const unsigned int backlight_curve_coeff_b = 100;
91static const unsigned int backlight_curve_coeff_b_factor = 100;
92
93/* Minimum and maximum backlight input signal levels */
94static const unsigned int default_min_backlight = 12;
95static const unsigned int default_max_backlight = 255;
96
97/* Other backlight constants */
98static const unsigned int absolute_backlight_max = 255;
99
100#define MOD_POWER_TO_CORE(mod_power)\
101 container_of(mod_power, struct core_power, public)
102
103static bool check_dc_support(const struct dc *dc)
104{
105 if (dc->stream_funcs.set_backlight == NULL)
106 return false;
107
108 return true;
109}
110
111/* Given a specific dc_sink* this function finds its equivalent
112 * on the dc_sink array and returns the corresponding index
113 */
114static unsigned int sink_index_from_sink(struct core_power *core_power,
115 const struct dc_sink *sink)
116{
117 unsigned int index = 0;
118
119 for (index = 0; index < core_power->num_sinks; index++)
120 if (core_power->caps[index].sink == sink)
121 return index;
122
123 /* Could not find sink requested */
124 ASSERT(false);
125 return index;
126}
127
128static unsigned int convertBL8to17(unsigned int backlight_8bit)
129{
130 unsigned int temp_ulong = backlight_8bit * 0x10101;
131 unsigned char temp_uchar =
132 (unsigned char)(((temp_ulong & 0x80) >> 7) & 1);
133
134 temp_ulong = (temp_ulong >> 8) + temp_uchar;
135
136 return temp_ulong;
137}
138
139static uint16_t convertBL8to16(unsigned int backlight_8bit)
140{
141 return (uint16_t)((backlight_8bit * 0x10101) >> 8);
142}
143
144/*This is used when OS wants to retrieve the current BL.
145 * We return the 8bit value to OS.
146 */
147static unsigned int convertBL17to8(unsigned int backlight_17bit)
148{
149 if (backlight_17bit & 0x10000)
150 return default_max_backlight;
151 else
152 return (backlight_17bit >> 8);
153}
154
155struct mod_power *mod_power_create(struct dc *dc)
156{
157 struct core_power *core_power =
158 dm_alloc(sizeof(struct core_power));
159
160 struct core_dc *core_dc = DC_TO_CORE(dc);
161
162 int i = 0;
163
164 if (core_power == NULL)
165 goto fail_alloc_context;
166
167 core_power->caps = dm_alloc(sizeof(struct sink_caps) *
168 MOD_POWER_MAX_CONCURRENT_SINKS);
169
170 if (core_power->caps == NULL)
171 goto fail_alloc_caps;
172
173 for (i = 0; i < MOD_POWER_MAX_CONCURRENT_SINKS; i++)
174 core_power->caps[i].sink = NULL;
175
176 core_power->state = dm_alloc(sizeof(struct backlight_state) *
177 MOD_POWER_MAX_CONCURRENT_SINKS);
178
179 if (core_power->state == NULL)
180 goto fail_alloc_state;
181
182 core_power->num_sinks = 0;
183 backlight_caps_valid = false;
184
185 if (dc == NULL)
186 goto fail_construct;
187
188 core_power->dc = dc;
189
190 if (!check_dc_support(dc))
191 goto fail_construct;
192
193 abm_user_enable = false;
194 abm_active = false;
195
196 return &core_power->public;
197
198fail_construct:
199 dm_free(core_power->state);
200
201fail_alloc_state:
202 dm_free(core_power->caps);
203
204fail_alloc_caps:
205 dm_free(core_power);
206
207fail_alloc_context:
208 return NULL;
209}
210
211
212void mod_power_destroy(struct mod_power *mod_power)
213{
214 if (mod_power != NULL) {
215 int i;
216 struct core_power *core_power =
217 MOD_POWER_TO_CORE(mod_power);
218
219 dm_free(core_power->state);
220
221 for (i = 0; i < core_power->num_sinks; i++)
222 dc_sink_release(core_power->caps[i].sink);
223
224 dm_free(core_power->caps);
225
226 dm_free(core_power);
227 }
228}
229
230bool mod_power_add_sink(struct mod_power *mod_power,
231 const struct dc_sink *sink)
232{
233 if (sink->sink_signal == SIGNAL_TYPE_VIRTUAL)
234 return false;
235
236 struct core_power *core_power =
237 MOD_POWER_TO_CORE(mod_power);
238 struct core_dc *core_dc = DC_TO_CORE(core_power->dc);
239
240 if (core_power->num_sinks < MOD_POWER_MAX_CONCURRENT_SINKS) {
241 dc_sink_retain(sink);
242 core_power->caps[core_power->num_sinks].sink = sink;
243 core_power->state[core_power->num_sinks].
244 smooth_brightness_enabled = false;
245 core_power->state[core_power->num_sinks].
246 backlight = 100;
247 core_power->num_sinks++;
248 return true;
249 }
250
251 return false;
252}
253
254bool mod_power_remove_sink(struct mod_power *mod_power,
255 const struct dc_sink *sink)
256{
257 int i = 0, j = 0;
258 struct core_power *core_power =
259 MOD_POWER_TO_CORE(mod_power);
260
261 for (i = 0; i < core_power->num_sinks; i++) {
262 if (core_power->caps[i].sink == sink) {
263 /* To remove this sink, shift everything after down */
264 for (j = i; j < core_power->num_sinks - 1; j++) {
265 core_power->caps[j].sink =
266 core_power->caps[j + 1].sink;
267
268 memcpy(&core_power->state[j],
269 &core_power->state[j + 1],
270 sizeof(struct backlight_state));
271 }
272 core_power->num_sinks--;
273 dc_sink_release(sink);
274 return true;
275 }
276 }
277 return false;
278}
279
280bool mod_power_set_backlight(struct mod_power *mod_power,
281 const struct dc_stream **streams, int num_streams,
282 unsigned int backlight_8bit)
283{
284 struct core_power *core_power =
285 MOD_POWER_TO_CORE(mod_power);
286
287 unsigned int frame_ramp = 0;
288
289 unsigned int stream_index, sink_index, vsync_rate_hz;
290
291 union dmcu_abm_set_bl_params params;
292
293 for (stream_index = 0; stream_index < num_streams; stream_index++) {
294 if (streams[stream_index]->sink->sink_signal == SIGNAL_TYPE_VIRTUAL) {
295 core_power->state[sink_index].backlight = 0;
296 core_power->state[sink_index].frame_ramp = 0;
297 core_power->state[sink_index].smooth_brightness_enabled = false;
298 continue;
299 }
300
301 sink_index = sink_index_from_sink(core_power,
302 streams[stream_index]->sink);
303
304 vsync_rate_hz = div64_u64(div64_u64((streams[stream_index]->
305 timing.pix_clk_khz * 1000),
306 streams[stream_index]->timing.v_total),
307 streams[stream_index]->timing.h_total);
308
309 core_power->state[sink_index].backlight = backlight_8bit;
310
311 if (core_power->state[sink_index].smooth_brightness_enabled)
312 frame_ramp = ((vsync_rate_hz *
313 SMOOTH_BRIGHTNESS_ADJUSTMENT_TIME_IN_MS) + 500)
314 / 1000;
315 else
316 frame_ramp = 0;
317
318 core_power->state[sink_index].frame_ramp = frame_ramp;
319 }
320
321 params.u32All = 0;
322 params.bits.gradual_change = (frame_ramp > 0);
323 params.bits.frame_ramp = frame_ramp;
324
325 core_power->dc->stream_funcs.set_backlight
326 (core_power->dc, backlight_8bit, params.u32All, streams[0]);
327
328 return true;
329}
330
331bool mod_power_get_backlight(struct mod_power *mod_power,
332 const struct dc_sink *sink,
333 unsigned int *backlight_8bit)
334{
335 if (sink->sink_signal == SIGNAL_TYPE_VIRTUAL)
336 return false;
337
338 struct core_power *core_power =
339 MOD_POWER_TO_CORE(mod_power);
340
341 unsigned int sink_index = sink_index_from_sink(core_power, sink);
342
343 *backlight_8bit = core_power->state[sink_index].backlight;
344
345 return true;
346}
347
348/* hard coded to default backlight curve. */
349void mod_power_initialize_backlight_caps(struct mod_power
350 *mod_power)
351{
352 struct core_power *core_power =
353 MOD_POWER_TO_CORE(mod_power);
354 struct core_dc *core_dc = DC_TO_CORE(core_power->dc);
355 unsigned int i;
356
357 backlight_caps_initialized = true;
358
359 struct dm_acpi_atif_backlight_caps *pExtCaps = NULL;
360 bool customCurvePresent = false;
361 bool customMinMaxPresent = false;
362 bool customDefLevelsPresent = false;
363
364 /* Allocate memory for ATIF output
365 * (do not want to use 256 bytes on the stack)
366 */
367 pExtCaps = (struct dm_acpi_atif_backlight_caps *)
368 (dm_alloc(sizeof(struct dm_acpi_atif_backlight_caps)));
369 if (pExtCaps == NULL)
370 return;
371
372 /* Retrieve ACPI extended brightness caps */
373 if (dm_query_extended_brightness_caps
374 (core_dc->ctx, AcpiDisplayType_LCD1, pExtCaps)) {
375 ac_level_percentage = pExtCaps->acLevelPercentage;
376 dc_level_percentage = pExtCaps->dcLevelPercentage;
377 customMinMaxPresent = true;
378 customDefLevelsPresent = true;
379 customCurvePresent = (pExtCaps->numOfDataPoints > 0);
380
381 ASSERT(pExtCaps->numOfDataPoints <= 99);
382 } else {
383 dm_free(pExtCaps);
384 return;
385 }
386
387 if (customMinMaxPresent)
388 backlight_8bit_lut_array[0] = pExtCaps->minInputSignal;
389 else
390 backlight_8bit_lut_array[0] = default_min_backlight;
391
392 if (customMinMaxPresent)
393 backlight_8bit_lut_array[100] = pExtCaps->maxInputSignal;
394 else
395 backlight_8bit_lut_array[100] = default_max_backlight;
396
397 ASSERT(backlight_8bit_lut_array[100] <= absolute_backlight_max);
398 ASSERT(backlight_8bit_lut_array[0] <=
399 backlight_8bit_lut_array[100]);
400
401 /* Just to make sure we use valid values */
402 if (backlight_8bit_lut_array[100] > absolute_backlight_max)
403 backlight_8bit_lut_array[100] = absolute_backlight_max;
404 if (backlight_8bit_lut_array[0] > backlight_8bit_lut_array[100]) {
405 unsigned int swap;
406
407 swap = backlight_8bit_lut_array[0];
408 backlight_8bit_lut_array[0] = backlight_8bit_lut_array[100];
409 backlight_8bit_lut_array[100] = swap;
410 }
411
412 /* Build backlight translation table for custom curve */
413 if (customCurvePresent) {
414 unsigned int index = 1;
415 unsigned int numOfDataPoints =
416 (pExtCaps->numOfDataPoints <= 99 ?
417 pExtCaps->numOfDataPoints : 99);
418
419 /* Filling translation table from data points -
420 * between every two provided data points we
421 * lineary interpolate missing values
422 */
423 for (i = 0; i < numOfDataPoints; i++) {
424 /* Clamp signal level between min and max
425 * (since min and max might come other
426 * soruce like registry)
427 */
428 unsigned int luminance =
429 pExtCaps->dataPoints[i].luminance;
430 unsigned int signalLevel =
431 pExtCaps->dataPoints[i].signalLevel;
432
433 if (signalLevel < backlight_8bit_lut_array[0])
434 signalLevel = backlight_8bit_lut_array[0];
435 if (signalLevel > backlight_8bit_lut_array[100])
436 signalLevel = backlight_8bit_lut_array[100];
437
438 /* Lineary interpolate missing values */
439 if (index < luminance) {
440 unsigned int baseValue =
441 backlight_8bit_lut_array[index-1];
442 unsigned int deltaSignal =
443 signalLevel - baseValue;
444 unsigned int deltaLuma =
445 luminance - index + 1;
446 unsigned int step = deltaSignal;
447
448 for (; index < luminance; index++) {
449 backlight_8bit_lut_array[index] =
450 baseValue + (step / deltaLuma);
451 step += deltaSignal;
452 }
453 }
454
455 /* Now [index == luminance],
456 * so we can add data point to the translation table
457 */
458 backlight_8bit_lut_array[index++] = signalLevel;
459 }
460
461 /* Complete the final segment of interpolation -
462 * between last datapoint and maximum value
463 */
464 if (index < 100) {
465 unsigned int baseValue =
466 backlight_8bit_lut_array[index-1];
467 unsigned int deltaSignal =
468 backlight_8bit_lut_array[100] -
469 baseValue;
470 unsigned int deltaLuma = 100 - index + 1;
471 unsigned int step = deltaSignal;
472
473 for (; index < 100; index++) {
474 backlight_8bit_lut_array[index] =
475 baseValue + (step / deltaLuma);
476 step += deltaSignal;
477 }
478 }
479 /* Build backlight translation table based on default curve */
480 } else {
481 unsigned int delta =
482 backlight_8bit_lut_array[100] -
483 backlight_8bit_lut_array[0];
484 unsigned int coeffC = backlight_8bit_lut_array[0];
485 unsigned int coeffB =
486 (backlight_curve_coeff_b < delta ?
487 backlight_curve_coeff_b : delta);
488 unsigned int coeffA = delta - coeffB; /* coeffB is B*100 */
489
490 for (i = 1; i < 100; i++) {
491 backlight_8bit_lut_array[i] =
492 (coeffA * i * i) /
493 backlight_curve_coeff_a_factor +
494 (coeffB * i) /
495 backlight_curve_coeff_b_factor +
496 coeffC;
497 }
498 }
499
500 if (pExtCaps != NULL)
501 dm_free(pExtCaps);
502
503 /* Successfully initialized */
504 backlight_caps_valid = true;
505 backlight_def_levels_valid = customDefLevelsPresent;
506}
507
508unsigned int mod_power_backlight_level_percentage_to_signal(
509 struct mod_power *mod_power, unsigned int percentage)
510{
511 /* Do lazy initialization of backlight capabilities*/
512 if (!backlight_caps_initialized)
513 mod_power_initialize_backlight_caps(mod_power);
514
515 /* Since the translation table is indexed by percentage,
516 * we simply return backlight value at given percent
517 */
518 if (backlight_caps_valid && percentage <= 100)
519 return backlight_8bit_lut_array[percentage];
520
521 return -1;
522}
523
524unsigned int mod_power_backlight_level_signal_to_percentage(
525 struct mod_power *mod_power,
526 unsigned int signalLevel8bit)
527{
528 unsigned int invalid_backlight = (unsigned int)(-1);
529 /* Do lazy initialization of backlight capabilities */
530 if (!backlight_caps_initialized)
531 mod_power_initialize_backlight_caps(mod_power);
532
533 /* If customer curve cannot convert to differentiated value near min
534 * it is important to report 0 for min signal to pass setting "Dimmed"
535 * setting in HCK brightness2 tests.
536 */
537 if (signalLevel8bit <= backlight_8bit_lut_array[0])
538 return 0;
539
540 /* Since the translation table is indexed by percentage
541 * we need to do a binary search over the array
542 * Another option would be to guess entry based on linear distribution
543 * and then do linear search in correct direction
544 */
545 if (backlight_caps_valid && signalLevel8bit <=
546 absolute_backlight_max) {
547 unsigned int min = 0;
548 unsigned int max = 100;
549 unsigned int mid = invalid_backlight;
550
551 while (max >= min) {
552 mid = (min + max) / 2; /* floor of half range */
553
554 if (backlight_8bit_lut_array[mid] < signalLevel8bit)
555 min = mid + 1;
556 else if (backlight_8bit_lut_array[mid] >
557 signalLevel8bit)
558 max = mid - 1;
559 else
560 break;
561
562 if (max == 0 || max == 1)
563 return invalid_backlight;
564 }
565 return mid;
566 }
567
568 return invalid_backlight;
569}
570
571
572bool mod_power_get_panel_backlight_boundaries(
573 struct mod_power *mod_power,
574 unsigned int *min_backlight,
575 unsigned int *max_backlight,
576 unsigned int *output_ac_level_percentage,
577 unsigned int *output_dc_level_percentage)
578{
579 /* Do lazy initialization of backlight capabilities */
580 if (!backlight_caps_initialized)
581 mod_power_initialize_backlight_caps(mod_power);
582
583 /* If cache was successfully updated,
584 * copy the values to output structure and return success
585 */
586 if (backlight_caps_valid) {
587 *min_backlight = backlight_8bit_lut_array[0];
588 *max_backlight = backlight_8bit_lut_array[100];
589
590 *output_ac_level_percentage = ac_level_percentage;
591 *output_dc_level_percentage = dc_level_percentage;
592
593 return true;
594 }
595
596 return false;
597}
598
599bool mod_power_set_smooth_brightness(struct mod_power *mod_power,
600 const struct dc_sink *sink, bool enable_brightness)
601{
602 if (sink->sink_signal == SIGNAL_TYPE_VIRTUAL)
603 return false;
604
605 struct core_power *core_power =
606 MOD_POWER_TO_CORE(mod_power);
607 unsigned int sink_index = sink_index_from_sink(core_power, sink);
608
609 core_power->state[sink_index].smooth_brightness_enabled
610 = enable_brightness;
611 return true;
612}
613
614bool mod_power_notify_mode_change(struct mod_power *mod_power,
615 const struct dc_stream *stream)
616{
617 if (stream->sink->sink_signal == SIGNAL_TYPE_VIRTUAL)
618 return false;
619
620 struct core_power *core_power =
621 MOD_POWER_TO_CORE(mod_power);
622
623 unsigned int sink_index = sink_index_from_sink(core_power,
624 stream->sink);
625 unsigned int frame_ramp = core_power->state[sink_index].frame_ramp;
626 union dmcu_abm_set_bl_params params;
627
628 params.u32All = 0;
629 params.bits.gradual_change = (frame_ramp > 0);
630 params.bits.frame_ramp = frame_ramp;
631
632 core_power->dc->stream_funcs.set_backlight
633 (core_power->dc,
634 core_power->state[sink_index].backlight,
635 params.u32All, stream);
636
637 core_power->dc->stream_funcs.setup_psr
638 (core_power->dc, stream);
639
640 return true;
641}
642
643
644static bool mod_power_abm_feature_enable(struct mod_power
645 *mod_power, bool enable)
646{
647 struct core_power *core_power =
648 MOD_POWER_TO_CORE(mod_power);
649 if (abm_user_enable == enable)
650 return true;
651
652 abm_user_enable = enable;
653
654 if (enable) {
655 if (abm_level != 0 && abm_active)
656 core_power->dc->stream_funcs.set_abm_level
657 (core_power->dc, abm_level);
658 } else {
659 if (abm_level != 0 && abm_active) {
660 abm_level = 0;
661 core_power->dc->stream_funcs.set_abm_level
662 (core_power->dc, abm_level);
663 }
664 }
665
666 return true;
667}
668
669static bool mod_power_abm_activate(struct mod_power
670 *mod_power, bool activate)
671{
672 struct core_power *core_power =
673 MOD_POWER_TO_CORE(mod_power);
674 if (abm_active == activate)
675 return true;
676
677 abm_active = activate;
678
679 if (activate) {
680 if (abm_level != 0 && abm_user_enable)
681 core_power->dc->stream_funcs.set_abm_level
682 (core_power->dc, abm_level);
683 } else {
684 if (abm_level != 0 && abm_user_enable) {
685 abm_level = 0;
686 core_power->dc->stream_funcs.set_abm_level
687 (core_power->dc, abm_level);
688 }
689 }
690
691 return true;
692}
693
694static bool mod_power_abm_set_level(struct mod_power *mod_power,
695 unsigned int level)
696{
697 struct core_power *core_power =
698 MOD_POWER_TO_CORE(mod_power);
699 if (abm_level == level)
700 return true;
701
702 if (abm_active && abm_user_enable && level == 0)
703 core_power->dc->stream_funcs.set_abm_level
704 (core_power->dc, 0);
705 else if (abm_active && abm_user_enable && level != 0)
706 core_power->dc->stream_funcs.set_abm_level
707 (core_power->dc, level);
708
709 abm_level = level;
710
711 return true;
712}
713
714bool mod_power_varibright_control(struct mod_power *mod_power,
715 struct varibright_info *input_varibright_info)
716{
717 switch (input_varibright_info->cmd) {
718 case VariBright_Cmd__SetVBLevel:
719 {
720 /* Set VariBright user level. */
721 mod_power_abm_set_level(mod_power,
722 input_varibright_info->level);
723 }
724 break;
725
726 case VariBright_Cmd__UserEnable:
727 {
728 /* Set VariBright user enable state. */
729 mod_power_abm_feature_enable(mod_power,
730 input_varibright_info->enable);
731 }
732 break;
733
734 case VariBright_Cmd__PostDisplayConfigChange:
735 {
736 /* Set VariBright user level. */
737 mod_power_abm_set_level(mod_power,
738 input_varibright_info->level);
739
740 /* Set VariBright user enable state. */
741 mod_power_abm_feature_enable(mod_power,
742 input_varibright_info->enable);
743
744 /* Set VariBright activate based on power state. */
745 mod_power_abm_activate(mod_power,
746 input_varibright_info->activate);
747 }
748 break;
749
750 default:
751 {
752 return false;
753 }
754 break;
755 }
756
757 return true;
758}
759
760bool mod_power_block_psr(bool block_enable, enum dmcu_block_psr_reason reason)
761{
762 if (block_enable)
763 block_psr |= reason;
764 else
765 block_psr &= ~reason;
766
767 return true;
768}
769
770
771bool mod_power_set_psr_enable(struct mod_power *mod_power,
772 bool psr_enable)
773{
774 struct core_power *core_power =
775 MOD_POWER_TO_CORE(mod_power);
776
777 if (block_psr == 0)
778 return core_power->dc->stream_funcs.set_psr_enable
779 (core_power->dc, psr_enable);
780
781 return false;
782}
783
784