aboutsummaryrefslogtreecommitdiffstats
path: root/common/recipes-kernel/linux/linux-yocto-4.19.8/0541-drm-amd-display-Add-support-for-Freesync-2-HDR-and-C.patch
diff options
context:
space:
mode:
Diffstat (limited to 'common/recipes-kernel/linux/linux-yocto-4.19.8/0541-drm-amd-display-Add-support-for-Freesync-2-HDR-and-C.patch')
-rw-r--r--common/recipes-kernel/linux/linux-yocto-4.19.8/0541-drm-amd-display-Add-support-for-Freesync-2-HDR-and-C.patch290
1 files changed, 290 insertions, 0 deletions
diff --git a/common/recipes-kernel/linux/linux-yocto-4.19.8/0541-drm-amd-display-Add-support-for-Freesync-2-HDR-and-C.patch b/common/recipes-kernel/linux/linux-yocto-4.19.8/0541-drm-amd-display-Add-support-for-Freesync-2-HDR-and-C.patch
new file mode 100644
index 00000000..b09cd169
--- /dev/null
+++ b/common/recipes-kernel/linux/linux-yocto-4.19.8/0541-drm-amd-display-Add-support-for-Freesync-2-HDR-and-C.patch
@@ -0,0 +1,290 @@
+From 62c45a6738804fc2ee76ae77281374b2c9af4b8a Mon Sep 17 00:00:00 2001
+From: SivapiriyanKumarasamy <sivapiriyan.kumarasamy@amd.com>
+Date: Tue, 11 Sep 2018 17:48:07 -0400
+Subject: [PATCH 0541/2940] drm/amd/display: Add support for Freesync 2 HDR and
+ Content to Display Mapping
+
+[Why]
+Freesync 2 HDR and support for HDR content
+outside the range of the HDR display
+require implementation on Dal 3 to better match
+Dal2.
+
+[How]
+Add support for Freesync HDR and mapping
+of source content to display ranges for better
+representation of HDR content.
+
+Signed-off-by: SivapiriyanKumarasamy <sivapiriyan.kumarasamy@amd.com>
+Reviewed-by: Anthony Koo <Anthony.Koo@amd.com>
+Acked-by: Bhawanpreet Lakha <Bhawanpreet.Lakha@amd.com>
+---
+ .../amd/display/amdgpu_dm/amdgpu_dm_color.c | 2 +-
+ .../amd/display/dc/dcn10/dcn10_cm_common.c | 2 +-
+ .../amd/display/modules/color/color_gamma.c | 175 +++++++++++++++++-
+ .../amd/display/modules/color/color_gamma.h | 11 +-
+ 4 files changed, 186 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
+index be19e6861189..216e48cec716 100644
+--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
+@@ -164,7 +164,7 @@ int amdgpu_dm_set_regamma_lut(struct dm_crtc_state *crtc)
+ */
+ stream->out_transfer_func->type = TF_TYPE_DISTRIBUTED_POINTS;
+ ret = mod_color_calculate_regamma_params(stream->out_transfer_func,
+- gamma, true, adev->asic_type <= CHIP_RAVEN);
++ gamma, true, adev->asic_type <= CHIP_RAVEN, NULL);
+ dc_gamma_release(&gamma);
+ if (!ret) {
+ stream->out_transfer_func->type = old_type;
+diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c
+index 5d95a997fd9f..97c059934feb 100644
+--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c
++++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c
+@@ -268,7 +268,7 @@ bool cm_helper_translate_curve_to_hw_format(
+ memset(lut_params, 0, sizeof(struct pwl_params));
+ memset(seg_distr, 0, sizeof(seg_distr));
+
+- if (output_tf->tf == TRANSFER_FUNCTION_PQ) {
++ if (output_tf->tf == TRANSFER_FUNCTION_PQ || output_tf->tf == TRANSFER_FUNCTION_GAMMA22) {
+ /* 32 segments
+ * segments are from 2^-25 to 2^7
+ */
+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..2e215c9e5445 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(
+ a1);
+ }
+
++static struct fixed31_32 calculate_gamma22(struct fixed31_32 arg)
++{
++ struct fixed31_32 gamma = dc_fixpt_from_fraction(22, 10);
++
++ return translate_from_linear_space(arg,
++ dc_fixpt_zero,
++ dc_fixpt_zero,
++ dc_fixpt_zero,
++ dc_fixpt_zero,
++ gamma);
++}
++
+ static struct fixed31_32 translate_to_linear_space(
+ struct fixed31_32 arg,
+ struct fixed31_32 a0,
+@@ -709,6 +721,160 @@ static void build_regamma(struct pwl_float_data_ex *rgb_regamma,
+ }
+ }
+
++static void hermite_spline_eetf(struct fixed31_32 input_x,
++ struct fixed31_32 max_display,
++ struct fixed31_32 min_display,
++ struct fixed31_32 max_content,
++ struct fixed31_32 *out_x)
++{
++ struct fixed31_32 min_lum_pq;
++ struct fixed31_32 max_lum_pq;
++ struct fixed31_32 max_content_pq;
++ struct fixed31_32 ks;
++ struct fixed31_32 E1;
++ struct fixed31_32 E2;
++ struct fixed31_32 E3;
++ struct fixed31_32 t;
++ struct fixed31_32 t2;
++ struct fixed31_32 t3;
++ struct fixed31_32 two;
++ struct fixed31_32 three;
++ struct fixed31_32 temp1;
++ struct fixed31_32 temp2;
++ struct fixed31_32 a = dc_fixpt_from_fraction(15, 10);
++ struct fixed31_32 b = dc_fixpt_from_fraction(5, 10);
++ struct fixed31_32 epsilon = dc_fixpt_from_fraction(1, 1000000); // dc_fixpt_epsilon is a bit too small
++
++ if (dc_fixpt_eq(max_content, dc_fixpt_zero)) {
++ *out_x = dc_fixpt_zero;
++ return;
++ }
++
++ compute_pq(input_x, &E1);
++ compute_pq(dc_fixpt_div(min_display, max_content), &min_lum_pq);
++ compute_pq(dc_fixpt_div(max_display, max_content), &max_lum_pq);
++ compute_pq(dc_fixpt_one, &max_content_pq); // always 1? DAL2 code is weird
++ a = dc_fixpt_div(dc_fixpt_add(dc_fixpt_one, b), max_content_pq); // (1+b)/maxContent
++ ks = dc_fixpt_sub(dc_fixpt_mul(a, max_lum_pq), b); // a * max_lum_pq - b
++
++ if (dc_fixpt_lt(E1, ks))
++ E2 = E1;
++ else if (dc_fixpt_le(ks, E1) && dc_fixpt_le(E1, dc_fixpt_one)) {
++ if (dc_fixpt_lt(epsilon, dc_fixpt_sub(dc_fixpt_one, ks)))
++ // t = (E1 - ks) / (1 - ks)
++ t = dc_fixpt_div(dc_fixpt_sub(E1, ks),
++ dc_fixpt_sub(dc_fixpt_one, ks));
++ else
++ t = dc_fixpt_zero;
++
++ two = dc_fixpt_from_int(2);
++ three = dc_fixpt_from_int(3);
++
++ t2 = dc_fixpt_mul(t, t);
++ t3 = dc_fixpt_mul(t2, t);
++ temp1 = dc_fixpt_mul(two, t3);
++ temp2 = dc_fixpt_mul(three, t2);
++
++ // (2t^3 - 3t^2 + 1) * ks
++ E2 = dc_fixpt_mul(ks, dc_fixpt_add(dc_fixpt_one,
++ dc_fixpt_sub(temp1, temp2)));
++
++ // (-2t^3 + 3t^2) * max_lum_pq
++ E2 = dc_fixpt_add(E2, dc_fixpt_mul(max_lum_pq,
++ dc_fixpt_sub(temp2, temp1)));
++
++ temp1 = dc_fixpt_mul(two, t2);
++ temp2 = dc_fixpt_sub(dc_fixpt_one, ks);
++
++ // (t^3 - 2t^2 + t) * (1-ks)
++ E2 = dc_fixpt_add(E2, dc_fixpt_mul(temp2,
++ dc_fixpt_add(t, dc_fixpt_sub(t3, temp1))));
++ }
++
++ temp1 = dc_fixpt_sub(dc_fixpt_one, E2);
++ temp2 = dc_fixpt_mul(temp1, temp1);
++ temp2 = dc_fixpt_mul(temp2, temp2);
++ // temp2 = (1-E2)^4
++
++ E3 = dc_fixpt_add(E2, dc_fixpt_mul(min_lum_pq, temp2));
++ compute_de_pq(E3, out_x);
++
++ *out_x = dc_fixpt_div(*out_x, dc_fixpt_div(max_display, max_content));
++}
++
++static bool build_freesync_hdr(struct pwl_float_data_ex *rgb_regamma,
++ uint32_t hw_points_num,
++ const struct hw_x_point *coordinate_x,
++ const struct freesync_hdr_tf_params *fs_params)
++{
++ uint32_t i;
++ struct pwl_float_data_ex *rgb = rgb_regamma;
++ const struct hw_x_point *coord_x = coordinate_x;
++ struct fixed31_32 scaledX = dc_fixpt_zero;
++ struct fixed31_32 scaledX1 = dc_fixpt_zero;
++ struct fixed31_32 max_display = dc_fixpt_from_int(fs_params->max_display);
++ struct fixed31_32 min_display = dc_fixpt_from_fraction(fs_params->min_display, 10000);
++ struct fixed31_32 max_content = dc_fixpt_from_int(fs_params->max_content);
++ struct fixed31_32 min_content = dc_fixpt_from_fraction(fs_params->min_content, 10000);
++ struct fixed31_32 clip = dc_fixpt_one;
++ struct fixed31_32 output;
++ bool use_eetf = false;
++ struct fixed31_32 sdr_white_level = dc_fixpt_from_int(fs_params->sdr_white_level);
++
++ if (fs_params == NULL || fs_params->max_content == 0 ||
++ fs_params->max_display == 0)
++ return false;
++
++ if (fs_params->min_display > 1000) // cap at 0.1 at the bottom
++ min_display = dc_fixpt_from_fraction(1, 10);
++ if (fs_params->max_display < 100) // cap at 100 at the top
++ max_display = dc_fixpt_from_int(100);
++
++ if (fs_params->min_content < fs_params->min_display)
++ use_eetf = true;
++ else
++ min_content = min_display;
++
++ if (fs_params->max_content > fs_params->max_display)
++ use_eetf = true;
++ else
++ max_content = max_display;
++
++ rgb += 32; // first 32 points have problems with fixed point, too small
++ coord_x += 32;
++ for (i = 32; i <= hw_points_num; i++) {
++ if (use_eetf) {
++ /*max content is equal 1 */
++ scaledX1 = dc_fixpt_div(coord_x->x,
++ dc_fixpt_div(max_content, sdr_white_level));
++ hermite_spline_eetf(scaledX1, max_display, min_display,
++ max_content, &scaledX);
++ } else
++ scaledX = dc_fixpt_div(coord_x->x,
++ dc_fixpt_div(max_display, sdr_white_level));
++
++ if (dc_fixpt_lt(scaledX, clip)) {
++ if (dc_fixpt_lt(scaledX, dc_fixpt_zero))
++ output = dc_fixpt_zero;
++ else
++ output = calculate_gamma22(scaledX);
++
++ rgb->r = output;
++ rgb->g = output;
++ rgb->b = output;
++ } else {
++ rgb->r = clip;
++ rgb->g = clip;
++ rgb->b = clip;
++ }
++
++ ++coord_x;
++ ++rgb;
++ }
++
++ return true;
++}
++
+ static void build_degamma(struct pwl_float_data_ex *curve,
+ uint32_t hw_points_num,
+ const struct hw_x_point *coordinate_x, bool is_2_4)
+@@ -1356,7 +1522,8 @@ static bool map_regamma_hw_to_x_user(
+ #define _EXTRA_POINTS 3
+
+ bool mod_color_calculate_regamma_params(struct dc_transfer_func *output_tf,
+- const struct dc_gamma *ramp, bool mapUserRamp, bool canRomBeUsed)
++ const struct dc_gamma *ramp, bool mapUserRamp, bool canRomBeUsed,
++ const struct freesync_hdr_tf_params *fs_params)
+ {
+ struct dc_transfer_func_distributed_points *tf_pts = &output_tf->tf_pts;
+ struct dividers dividers;
+@@ -1424,6 +1591,12 @@ bool mod_color_calculate_regamma_params(struct dc_transfer_func *output_tf,
+ MAX_HW_POINTS,
+ coordinates_x,
+ output_tf->sdr_ref_white_level);
++ } else if (tf == TRANSFER_FUNCTION_GAMMA22 &&
++ fs_params != NULL) {
++ build_freesync_hdr(rgb_regamma,
++ MAX_HW_POINTS,
++ coordinates_x,
++ fs_params);
+ } else {
+ tf_pts->end_exponent = 0;
+ 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 {
+ };
+ };
+
++struct freesync_hdr_tf_params {
++ unsigned int sdr_white_level;
++ unsigned int min_content; // luminance in 1/10000 nits
++ unsigned int max_content; // luminance in nits
++ unsigned int min_display; // luminance in 1/10000 nits
++ unsigned int max_display; // luminance in nits
++};
++
+ void setup_x_points_distribution(void);
+ void precompute_pq(void);
+ void precompute_de_pq(void);
+
+ bool mod_color_calculate_regamma_params(struct dc_transfer_func *output_tf,
+- const struct dc_gamma *ramp, bool mapUserRamp, bool canRomBeUsed);
++ const struct dc_gamma *ramp, bool mapUserRamp, bool canRomBeUsed,
++ const struct freesync_hdr_tf_params *fs_params);
+
+ bool mod_color_calculate_degamma_params(struct dc_transfer_func *output_tf,
+ const struct dc_gamma *ramp, bool mapUserRamp);
+--
+2.17.1
+