aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/amd/display/modules
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/amd/display/modules')
-rw-r--r--drivers/gpu/drm/amd/display/modules/color/color_gamma.c186
-rw-r--r--drivers/gpu/drm/amd/display/modules/color/color_gamma.h11
-rw-r--r--drivers/gpu/drm/amd/display/modules/freesync/freesync.c37
3 files changed, 203 insertions, 31 deletions
diff --git a/drivers/gpu/drm/amd/display/modules/color/color_gamma.c b/drivers/gpu/drm/amd/display/modules/color/color_gamma.c
index cdcefd087487..7480f072c375 100644
--- a/drivers/gpu/drm/amd/display/modules/color/color_gamma.c
+++ b/drivers/gpu/drm/amd/display/modules/color/color_gamma.c
@@ -306,6 +306,18 @@ static struct fixed31_32 translate_from_linear_space(
306 a1); 306 a1);
307} 307}
308 308
309static struct fixed31_32 calculate_gamma22(struct fixed31_32 arg)
310{
311 struct fixed31_32 gamma = dc_fixpt_from_fraction(22, 10);
312
313 return translate_from_linear_space(arg,
314 dc_fixpt_zero,
315 dc_fixpt_zero,
316 dc_fixpt_zero,
317 dc_fixpt_zero,
318 gamma);
319}
320
309static struct fixed31_32 translate_to_linear_space( 321static struct fixed31_32 translate_to_linear_space(
310 struct fixed31_32 arg, 322 struct fixed31_32 arg,
311 struct fixed31_32 a0, 323 struct fixed31_32 a0,
@@ -709,6 +721,169 @@ static void build_regamma(struct pwl_float_data_ex *rgb_regamma,
709 } 721 }
710} 722}
711 723
724static void hermite_spline_eetf(struct fixed31_32 input_x,
725 struct fixed31_32 max_display,
726 struct fixed31_32 min_display,
727 struct fixed31_32 max_content,
728 struct fixed31_32 *out_x)
729{
730 struct fixed31_32 min_lum_pq;
731 struct fixed31_32 max_lum_pq;
732 struct fixed31_32 max_content_pq;
733 struct fixed31_32 ks;
734 struct fixed31_32 E1;
735 struct fixed31_32 E2;
736 struct fixed31_32 E3;
737 struct fixed31_32 t;
738 struct fixed31_32 t2;
739 struct fixed31_32 t3;
740 struct fixed31_32 two;
741 struct fixed31_32 three;
742 struct fixed31_32 temp1;
743 struct fixed31_32 temp2;
744 struct fixed31_32 a = dc_fixpt_from_fraction(15, 10);
745 struct fixed31_32 b = dc_fixpt_from_fraction(5, 10);
746 struct fixed31_32 epsilon = dc_fixpt_from_fraction(1, 1000000); // dc_fixpt_epsilon is a bit too small
747
748 if (dc_fixpt_eq(max_content, dc_fixpt_zero)) {
749 *out_x = dc_fixpt_zero;
750 return;
751 }
752
753 compute_pq(input_x, &E1);
754 compute_pq(dc_fixpt_div(min_display, max_content), &min_lum_pq);
755 compute_pq(dc_fixpt_div(max_display, max_content), &max_lum_pq);
756 compute_pq(dc_fixpt_one, &max_content_pq); // always 1? DAL2 code is weird
757 a = dc_fixpt_div(dc_fixpt_add(dc_fixpt_one, b), max_content_pq); // (1+b)/maxContent
758 ks = dc_fixpt_sub(dc_fixpt_mul(a, max_lum_pq), b); // a * max_lum_pq - b
759
760 if (dc_fixpt_lt(E1, ks))
761 E2 = E1;
762 else if (dc_fixpt_le(ks, E1) && dc_fixpt_le(E1, dc_fixpt_one)) {
763 if (dc_fixpt_lt(epsilon, dc_fixpt_sub(dc_fixpt_one, ks)))
764 // t = (E1 - ks) / (1 - ks)
765 t = dc_fixpt_div(dc_fixpt_sub(E1, ks),
766 dc_fixpt_sub(dc_fixpt_one, ks));
767 else
768 t = dc_fixpt_zero;
769
770 two = dc_fixpt_from_int(2);
771 three = dc_fixpt_from_int(3);
772
773 t2 = dc_fixpt_mul(t, t);
774 t3 = dc_fixpt_mul(t2, t);
775 temp1 = dc_fixpt_mul(two, t3);
776 temp2 = dc_fixpt_mul(three, t2);
777
778 // (2t^3 - 3t^2 + 1) * ks
779 E2 = dc_fixpt_mul(ks, dc_fixpt_add(dc_fixpt_one,
780 dc_fixpt_sub(temp1, temp2)));
781
782 // (-2t^3 + 3t^2) * max_lum_pq
783 E2 = dc_fixpt_add(E2, dc_fixpt_mul(max_lum_pq,
784 dc_fixpt_sub(temp2, temp1)));
785
786 temp1 = dc_fixpt_mul(two, t2);
787 temp2 = dc_fixpt_sub(dc_fixpt_one, ks);
788
789 // (t^3 - 2t^2 + t) * (1-ks)
790 E2 = dc_fixpt_add(E2, dc_fixpt_mul(temp2,
791 dc_fixpt_add(t, dc_fixpt_sub(t3, temp1))));
792 } else
793 E2 = dc_fixpt_one;
794
795 temp1 = dc_fixpt_sub(dc_fixpt_one, E2);
796 temp2 = dc_fixpt_mul(temp1, temp1);
797 temp2 = dc_fixpt_mul(temp2, temp2);
798 // temp2 = (1-E2)^4
799
800 E3 = dc_fixpt_add(E2, dc_fixpt_mul(min_lum_pq, temp2));
801 compute_de_pq(E3, out_x);
802
803 *out_x = dc_fixpt_div(*out_x, dc_fixpt_div(max_display, max_content));
804}
805
806static bool build_freesync_hdr(struct pwl_float_data_ex *rgb_regamma,
807 uint32_t hw_points_num,
808 const struct hw_x_point *coordinate_x,
809 const struct freesync_hdr_tf_params *fs_params)
810{
811 uint32_t i;
812 struct pwl_float_data_ex *rgb = rgb_regamma;
813 const struct hw_x_point *coord_x = coordinate_x;
814 struct fixed31_32 scaledX = dc_fixpt_zero;
815 struct fixed31_32 scaledX1 = dc_fixpt_zero;
816 struct fixed31_32 max_display = dc_fixpt_from_int(fs_params->max_display);
817 struct fixed31_32 min_display = dc_fixpt_from_fraction(fs_params->min_display, 10000);
818 struct fixed31_32 max_content = dc_fixpt_from_int(fs_params->max_content);
819 struct fixed31_32 min_content = dc_fixpt_from_fraction(fs_params->min_content, 10000);
820 struct fixed31_32 clip = dc_fixpt_one;
821 struct fixed31_32 output;
822 bool use_eetf = false;
823 bool is_clipped = false;
824 struct fixed31_32 sdr_white_level = dc_fixpt_from_int(fs_params->sdr_white_level);
825
826 if (fs_params == NULL || fs_params->max_content == 0 ||
827 fs_params->max_display == 0)
828 return false;
829
830 if (fs_params->min_display > 1000) // cap at 0.1 at the bottom
831 min_display = dc_fixpt_from_fraction(1, 10);
832 if (fs_params->max_display < 100) // cap at 100 at the top
833 max_display = dc_fixpt_from_int(100);
834
835 if (fs_params->min_content < fs_params->min_display)
836 use_eetf = true;
837 else
838 min_content = min_display;
839
840 if (fs_params->max_content > fs_params->max_display)
841 use_eetf = true;
842 else
843 max_content = max_display;
844
845 rgb += 32; // first 32 points have problems with fixed point, too small
846 coord_x += 32;
847 for (i = 32; i <= hw_points_num; i++) {
848 if (!is_clipped) {
849 if (use_eetf) {
850 /*max content is equal 1 */
851 scaledX1 = dc_fixpt_div(coord_x->x,
852 dc_fixpt_div(max_content, sdr_white_level));
853 hermite_spline_eetf(scaledX1, max_display, min_display,
854 max_content, &scaledX);
855 } else
856 scaledX = dc_fixpt_div(coord_x->x,
857 dc_fixpt_div(max_display, sdr_white_level));
858
859 if (dc_fixpt_lt(scaledX, clip)) {
860 if (dc_fixpt_lt(scaledX, dc_fixpt_zero))
861 output = dc_fixpt_zero;
862 else
863 output = calculate_gamma22(scaledX);
864
865 rgb->r = output;
866 rgb->g = output;
867 rgb->b = output;
868 } else {
869 is_clipped = true;
870 rgb->r = clip;
871 rgb->g = clip;
872 rgb->b = clip;
873 }
874 } else {
875 rgb->r = clip;
876 rgb->g = clip;
877 rgb->b = clip;
878 }
879
880 ++coord_x;
881 ++rgb;
882 }
883
884 return true;
885}
886
712static void build_degamma(struct pwl_float_data_ex *curve, 887static void build_degamma(struct pwl_float_data_ex *curve,
713 uint32_t hw_points_num, 888 uint32_t hw_points_num,
714 const struct hw_x_point *coordinate_x, bool is_2_4) 889 const struct hw_x_point *coordinate_x, bool is_2_4)
@@ -1356,7 +1531,8 @@ static bool map_regamma_hw_to_x_user(
1356#define _EXTRA_POINTS 3 1531#define _EXTRA_POINTS 3
1357 1532
1358bool mod_color_calculate_regamma_params(struct dc_transfer_func *output_tf, 1533bool mod_color_calculate_regamma_params(struct dc_transfer_func *output_tf,
1359 const struct dc_gamma *ramp, bool mapUserRamp, bool canRomBeUsed) 1534 const struct dc_gamma *ramp, bool mapUserRamp, bool canRomBeUsed,
1535 const struct freesync_hdr_tf_params *fs_params)
1360{ 1536{
1361 struct dc_transfer_func_distributed_points *tf_pts = &output_tf->tf_pts; 1537 struct dc_transfer_func_distributed_points *tf_pts = &output_tf->tf_pts;
1362 struct dividers dividers; 1538 struct dividers dividers;
@@ -1374,7 +1550,7 @@ bool mod_color_calculate_regamma_params(struct dc_transfer_func *output_tf,
1374 /* we can use hardcoded curve for plain SRGB TF */ 1550 /* we can use hardcoded curve for plain SRGB TF */
1375 if (output_tf->type == TF_TYPE_PREDEFINED && canRomBeUsed == true && 1551 if (output_tf->type == TF_TYPE_PREDEFINED && canRomBeUsed == true &&
1376 output_tf->tf == TRANSFER_FUNCTION_SRGB && 1552 output_tf->tf == TRANSFER_FUNCTION_SRGB &&
1377 (!mapUserRamp && ramp->type == GAMMA_RGB_256)) 1553 (ramp->is_identity || (!mapUserRamp && ramp->type == GAMMA_RGB_256)))
1378 return true; 1554 return true;
1379 1555
1380 output_tf->type = TF_TYPE_DISTRIBUTED_POINTS; 1556 output_tf->type = TF_TYPE_DISTRIBUTED_POINTS;
@@ -1424,6 +1600,12 @@ bool mod_color_calculate_regamma_params(struct dc_transfer_func *output_tf,
1424 MAX_HW_POINTS, 1600 MAX_HW_POINTS,
1425 coordinates_x, 1601 coordinates_x,
1426 output_tf->sdr_ref_white_level); 1602 output_tf->sdr_ref_white_level);
1603 } else if (tf == TRANSFER_FUNCTION_GAMMA22 &&
1604 fs_params != NULL) {
1605 build_freesync_hdr(rgb_regamma,
1606 MAX_HW_POINTS,
1607 coordinates_x,
1608 fs_params);
1427 } else { 1609 } else {
1428 tf_pts->end_exponent = 0; 1610 tf_pts->end_exponent = 0;
1429 tf_pts->x_point_at_y1_red = 1; 1611 tf_pts->x_point_at_y1_red = 1;
diff --git a/drivers/gpu/drm/amd/display/modules/color/color_gamma.h b/drivers/gpu/drm/amd/display/modules/color/color_gamma.h
index 63ccb9c91224..a6e164df090a 100644
--- a/drivers/gpu/drm/amd/display/modules/color/color_gamma.h
+++ b/drivers/gpu/drm/amd/display/modules/color/color_gamma.h
@@ -73,12 +73,21 @@ struct regamma_lut {
73 }; 73 };
74}; 74};
75 75
76struct freesync_hdr_tf_params {
77 unsigned int sdr_white_level;
78 unsigned int min_content; // luminance in 1/10000 nits
79 unsigned int max_content; // luminance in nits
80 unsigned int min_display; // luminance in 1/10000 nits
81 unsigned int max_display; // luminance in nits
82};
83
76void setup_x_points_distribution(void); 84void setup_x_points_distribution(void);
77void precompute_pq(void); 85void precompute_pq(void);
78void precompute_de_pq(void); 86void precompute_de_pq(void);
79 87
80bool mod_color_calculate_regamma_params(struct dc_transfer_func *output_tf, 88bool mod_color_calculate_regamma_params(struct dc_transfer_func *output_tf,
81 const struct dc_gamma *ramp, bool mapUserRamp, bool canRomBeUsed); 89 const struct dc_gamma *ramp, bool mapUserRamp, bool canRomBeUsed,
90 const struct freesync_hdr_tf_params *fs_params);
82 91
83bool mod_color_calculate_degamma_params(struct dc_transfer_func *output_tf, 92bool mod_color_calculate_degamma_params(struct dc_transfer_func *output_tf,
84 const struct dc_gamma *ramp, bool mapUserRamp); 93 const struct dc_gamma *ramp, bool mapUserRamp);
diff --git a/drivers/gpu/drm/amd/display/modules/freesync/freesync.c b/drivers/gpu/drm/amd/display/modules/freesync/freesync.c
index 4018c7180d00..620a171620ee 100644
--- a/drivers/gpu/drm/amd/display/modules/freesync/freesync.c
+++ b/drivers/gpu/drm/amd/display/modules/freesync/freesync.c
@@ -37,6 +37,8 @@
37#define RENDER_TIMES_MAX_COUNT 10 37#define RENDER_TIMES_MAX_COUNT 10
38/* Threshold to exit BTR (to avoid frequent enter-exits at the lower limit) */ 38/* Threshold to exit BTR (to avoid frequent enter-exits at the lower limit) */
39#define BTR_EXIT_MARGIN 2000 39#define BTR_EXIT_MARGIN 2000
40/*Threshold to exit fixed refresh rate*/
41#define FIXED_REFRESH_EXIT_MARGIN_IN_HZ 4
40/* Number of consecutive frames to check before entering/exiting fixed refresh*/ 42/* Number of consecutive frames to check before entering/exiting fixed refresh*/
41#define FIXED_REFRESH_ENTER_FRAME_COUNT 5 43#define FIXED_REFRESH_ENTER_FRAME_COUNT 5
42#define FIXED_REFRESH_EXIT_FRAME_COUNT 5 44#define FIXED_REFRESH_EXIT_FRAME_COUNT 5
@@ -257,40 +259,14 @@ static void apply_below_the_range(struct core_freesync *core_freesync,
257 if (in_out_vrr->btr.btr_active) { 259 if (in_out_vrr->btr.btr_active) {
258 in_out_vrr->btr.frame_counter = 0; 260 in_out_vrr->btr.frame_counter = 0;
259 in_out_vrr->btr.btr_active = false; 261 in_out_vrr->btr.btr_active = false;
260
261 /* Exit Fixed Refresh mode */
262 } else if (in_out_vrr->fixed.fixed_active) {
263
264 in_out_vrr->fixed.frame_counter++;
265
266 if (in_out_vrr->fixed.frame_counter >
267 FIXED_REFRESH_EXIT_FRAME_COUNT) {
268 in_out_vrr->fixed.frame_counter = 0;
269 in_out_vrr->fixed.fixed_active = false;
270 }
271 } 262 }
272 } else if (last_render_time_in_us > max_render_time_in_us) { 263 } else if (last_render_time_in_us > max_render_time_in_us) {
273 /* Enter Below the Range */ 264 /* Enter Below the Range */
274 if (!in_out_vrr->btr.btr_active && 265 in_out_vrr->btr.btr_active = true;
275 in_out_vrr->btr.btr_enabled) {
276 in_out_vrr->btr.btr_active = true;
277
278 /* Enter Fixed Refresh mode */
279 } else if (!in_out_vrr->fixed.fixed_active &&
280 !in_out_vrr->btr.btr_enabled) {
281 in_out_vrr->fixed.frame_counter++;
282
283 if (in_out_vrr->fixed.frame_counter >
284 FIXED_REFRESH_ENTER_FRAME_COUNT) {
285 in_out_vrr->fixed.frame_counter = 0;
286 in_out_vrr->fixed.fixed_active = true;
287 }
288 }
289 } 266 }
290 267
291 /* BTR set to "not active" so disengage */ 268 /* BTR set to "not active" so disengage */
292 if (!in_out_vrr->btr.btr_active) { 269 if (!in_out_vrr->btr.btr_active) {
293 in_out_vrr->btr.btr_active = false;
294 in_out_vrr->btr.inserted_duration_in_us = 0; 270 in_out_vrr->btr.inserted_duration_in_us = 0;
295 in_out_vrr->btr.frames_to_insert = 0; 271 in_out_vrr->btr.frames_to_insert = 0;
296 in_out_vrr->btr.frame_counter = 0; 272 in_out_vrr->btr.frame_counter = 0;
@@ -375,7 +351,12 @@ static void apply_fixed_refresh(struct core_freesync *core_freesync,
375 bool update = false; 351 bool update = false;
376 unsigned int max_render_time_in_us = in_out_vrr->max_duration_in_us; 352 unsigned int max_render_time_in_us = in_out_vrr->max_duration_in_us;
377 353
378 if (last_render_time_in_us + BTR_EXIT_MARGIN < max_render_time_in_us) { 354 //Compute the exit refresh rate and exit frame duration
355 unsigned int exit_refresh_rate_in_milli_hz = ((1000000000/max_render_time_in_us)
356 + (1000*FIXED_REFRESH_EXIT_MARGIN_IN_HZ));
357 unsigned int exit_frame_duration_in_us = 1000000000/exit_refresh_rate_in_milli_hz;
358
359 if (last_render_time_in_us < exit_frame_duration_in_us) {
379 /* Exit Fixed Refresh mode */ 360 /* Exit Fixed Refresh mode */
380 if (in_out_vrr->fixed.fixed_active) { 361 if (in_out_vrr->fixed.fixed_active) {
381 in_out_vrr->fixed.frame_counter++; 362 in_out_vrr->fixed.frame_counter++;