aboutsummaryrefslogtreecommitdiffstats
path: root/common/recipes-kernel/linux/linux-yocto-4.14.71/4348-drm-amd-display-Add-user_regamma-to-color-module.patch
diff options
context:
space:
mode:
Diffstat (limited to 'common/recipes-kernel/linux/linux-yocto-4.14.71/4348-drm-amd-display-Add-user_regamma-to-color-module.patch')
-rw-r--r--common/recipes-kernel/linux/linux-yocto-4.14.71/4348-drm-amd-display-Add-user_regamma-to-color-module.patch469
1 files changed, 469 insertions, 0 deletions
diff --git a/common/recipes-kernel/linux/linux-yocto-4.14.71/4348-drm-amd-display-Add-user_regamma-to-color-module.patch b/common/recipes-kernel/linux/linux-yocto-4.14.71/4348-drm-amd-display-Add-user_regamma-to-color-module.patch
new file mode 100644
index 00000000..5fc046e1
--- /dev/null
+++ b/common/recipes-kernel/linux/linux-yocto-4.14.71/4348-drm-amd-display-Add-user_regamma-to-color-module.patch
@@ -0,0 +1,469 @@
+From fb4c5dd9dfd9874d908943b4647ee1f5955de1e7 Mon Sep 17 00:00:00 2001
+From: Krunoslav Kovac <Krunoslav.Kovac@amd.com>
+Date: Fri, 13 Apr 2018 16:06:24 -0400
+Subject: [PATCH 4348/5725] drm/amd/display: Add user_regamma to color module
+
+Signed-off-by: Krunoslav Kovac <Krunoslav.Kovac@amd.com>
+Reviewed-by: Anthony Koo <Anthony.Koo@amd.com>
+Acked-by: Harry Wentland <harry.wentland@amd.com>
+---
+ .../drm/amd/display/modules/color/color_gamma.c | 314 ++++++++++++++++++++-
+ .../drm/amd/display/modules/color/color_gamma.h | 48 +++-
+ 2 files changed, 348 insertions(+), 14 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 e7e374f..ad0ff50 100644
+--- a/drivers/gpu/drm/amd/display/modules/color/color_gamma.c
++++ b/drivers/gpu/drm/amd/display/modules/color/color_gamma.c
+@@ -185,14 +185,14 @@ struct dividers {
+
+ static void build_coefficients(struct gamma_coefficients *coefficients, bool is_2_4)
+ {
+- static const int32_t numerator01[] = { 31308, 180000};
+- static const int32_t numerator02[] = { 12920, 4500};
+- static const int32_t numerator03[] = { 55, 99};
+- static const int32_t numerator04[] = { 55, 99};
+- static const int32_t numerator05[] = { 2400, 2200};
++ static const int32_t numerator01[] = { 31308, 180000};
++ static const int32_t numerator02[] = { 12920, 4500};
++ static const int32_t numerator03[] = { 55, 99};
++ static const int32_t numerator04[] = { 55, 99};
++ static const int32_t numerator05[] = { 2400, 2200};
+
+- uint32_t i = 0;
+- uint32_t index = is_2_4 == true ? 0:1;
++ uint32_t i = 0;
++ uint32_t index = is_2_4 == true ? 0:1;
+
+ do {
+ coefficients->a0[i] = dal_fixed31_32_from_fraction(
+@@ -691,7 +691,7 @@ static void build_degamma(struct pwl_float_data_ex *curve,
+ }
+ }
+
+-static bool scale_gamma(struct pwl_float_data *pwl_rgb,
++static void scale_gamma(struct pwl_float_data *pwl_rgb,
+ const struct dc_gamma *ramp,
+ struct dividers dividers)
+ {
+@@ -752,11 +752,9 @@ static bool scale_gamma(struct pwl_float_data *pwl_rgb,
+ dividers.divider3);
+ rgb->b = dal_fixed31_32_mul(rgb_last->b,
+ dividers.divider3);
+-
+- return true;
+ }
+
+-static bool scale_gamma_dx(struct pwl_float_data *pwl_rgb,
++static void scale_gamma_dx(struct pwl_float_data *pwl_rgb,
+ const struct dc_gamma *ramp,
+ struct dividers dividers)
+ {
+@@ -818,8 +816,71 @@ static bool scale_gamma_dx(struct pwl_float_data *pwl_rgb,
+ pwl_rgb[i-1].g, 2), pwl_rgb[i-2].g);
+ pwl_rgb[i].b = dal_fixed31_32_sub(dal_fixed31_32_mul_int(
+ pwl_rgb[i-1].b, 2), pwl_rgb[i-2].b);
++}
+
+- return true;
++/* todo: all these scale_gamma functions are inherently the same but
++ * take different structures as params or different format for ramp
++ * values. We could probably implement it in a more generic fashion
++ */
++static void scale_user_regamma_ramp(struct pwl_float_data *pwl_rgb,
++ const struct regamma_ramp *ramp,
++ struct dividers dividers)
++{
++ unsigned short max_driver = 0xFFFF;
++ unsigned short max_os = 0xFF00;
++ unsigned short scaler = max_os;
++ uint32_t i;
++ struct pwl_float_data *rgb = pwl_rgb;
++ struct pwl_float_data *rgb_last = rgb + GAMMA_RGB_256_ENTRIES - 1;
++
++ i = 0;
++ do {
++ if (ramp->gamma[i] > max_os ||
++ ramp->gamma[i + 256] > max_os ||
++ ramp->gamma[i + 512] > max_os) {
++ scaler = max_driver;
++ break;
++ }
++ i++;
++ } while (i != GAMMA_RGB_256_ENTRIES);
++
++ i = 0;
++ do {
++ rgb->r = dal_fixed31_32_from_fraction(
++ ramp->gamma[i], scaler);
++ rgb->g = dal_fixed31_32_from_fraction(
++ ramp->gamma[i + 256], scaler);
++ rgb->b = dal_fixed31_32_from_fraction(
++ ramp->gamma[i + 512], scaler);
++
++ ++rgb;
++ ++i;
++ } while (i != GAMMA_RGB_256_ENTRIES);
++
++ rgb->r = dal_fixed31_32_mul(rgb_last->r,
++ dividers.divider1);
++ rgb->g = dal_fixed31_32_mul(rgb_last->g,
++ dividers.divider1);
++ rgb->b = dal_fixed31_32_mul(rgb_last->b,
++ dividers.divider1);
++
++ ++rgb;
++
++ rgb->r = dal_fixed31_32_mul(rgb_last->r,
++ dividers.divider2);
++ rgb->g = dal_fixed31_32_mul(rgb_last->g,
++ dividers.divider2);
++ rgb->b = dal_fixed31_32_mul(rgb_last->b,
++ dividers.divider2);
++
++ ++rgb;
++
++ rgb->r = dal_fixed31_32_mul(rgb_last->r,
++ dividers.divider3);
++ rgb->g = dal_fixed31_32_mul(rgb_last->g,
++ dividers.divider3);
++ rgb->b = dal_fixed31_32_mul(rgb_last->b,
++ dividers.divider3);
+ }
+
+ /*
+@@ -949,7 +1010,7 @@ static inline void copy_rgb_regamma_to_coordinates_x(
+ uint32_t i = 0;
+ const struct pwl_float_data_ex *rgb_regamma = rgb_ex;
+
+- while (i <= hw_points_num) {
++ while (i <= hw_points_num + 1) {
+ coords->regamma_y_red = rgb_regamma->r;
+ coords->regamma_y_green = rgb_regamma->g;
+ coords->regamma_y_blue = rgb_regamma->b;
+@@ -1002,6 +1063,102 @@ static bool calculate_interpolated_hardware_curve(
+ return true;
+ }
+
++/* The "old" interpolation uses a complicated scheme to build an array of
++ * coefficients while also using an array of 0-255 normalized to 0-1
++ * Then there's another loop using both of the above + new scaled user ramp
++ * and we concatenate them. It also searches for points of interpolation and
++ * uses enums for positions.
++ *
++ * This function uses a different approach:
++ * user ramp is always applied on X with 0/255, 1/255, 2/255, ..., 255/255
++ * To find index for hwX , we notice the following:
++ * i/255 <= hwX < (i+1)/255 <=> i <= 255*hwX < i+1
++ * See apply_lut_1d which is the same principle, but on 4K entry 1D LUT
++ *
++ * Once the index is known, combined Y is simply:
++ * user_ramp(index) + (hwX-index/255)*(user_ramp(index+1) - user_ramp(index)
++ *
++ * We should switch to this method in all cases, it's simpler and faster
++ * ToDo one day - for now this only applies to ADL regamma to avoid regression
++ * for regular use cases (sRGB and PQ)
++ */
++static void interpolate_user_regamma(uint32_t hw_points_num,
++ struct pwl_float_data *rgb_user,
++ bool apply_degamma,
++ struct dc_transfer_func_distributed_points *tf_pts)
++{
++ uint32_t i;
++ uint32_t color = 0;
++ int32_t index;
++ int32_t index_next;
++ struct fixed31_32 *tf_point;
++ struct fixed31_32 hw_x;
++ struct fixed31_32 norm_factor =
++ dal_fixed31_32_from_int_nonconst(255);
++ struct fixed31_32 norm_x;
++ struct fixed31_32 index_f;
++ struct fixed31_32 lut1;
++ struct fixed31_32 lut2;
++ struct fixed31_32 delta_lut;
++ struct fixed31_32 delta_index;
++
++ i = 0;
++ /* fixed_pt library has problems handling too small values */
++ while (i != 32) {
++ tf_pts->red[i] = dal_fixed31_32_zero;
++ tf_pts->green[i] = dal_fixed31_32_zero;
++ tf_pts->blue[i] = dal_fixed31_32_zero;
++ ++i;
++ }
++ while (i <= hw_points_num + 1) {
++ for (color = 0; color < 3; color++) {
++ if (color == 0)
++ tf_point = &tf_pts->red[i];
++ else if (color == 1)
++ tf_point = &tf_pts->green[i];
++ else
++ tf_point = &tf_pts->blue[i];
++
++ if (apply_degamma) {
++ if (color == 0)
++ hw_x = coordinates_x[i].regamma_y_red;
++ else if (color == 1)
++ hw_x = coordinates_x[i].regamma_y_green;
++ else
++ hw_x = coordinates_x[i].regamma_y_blue;
++ } else
++ hw_x = coordinates_x[i].x;
++
++ norm_x = dal_fixed31_32_mul(norm_factor, hw_x);
++ index = dal_fixed31_32_floor(norm_x);
++ if (index < 0 || index > 255)
++ continue;
++
++ index_f = dal_fixed31_32_from_int_nonconst(index);
++ index_next = (index == 255) ? index : index + 1;
++
++ if (color == 0) {
++ lut1 = rgb_user[index].r;
++ lut2 = rgb_user[index_next].r;
++ } else if (color == 1) {
++ lut1 = rgb_user[index].g;
++ lut2 = rgb_user[index_next].g;
++ } else {
++ lut1 = rgb_user[index].b;
++ lut2 = rgb_user[index_next].b;
++ }
++
++ // we have everything now, so interpolate
++ delta_lut = dal_fixed31_32_sub(lut2, lut1);
++ delta_index = dal_fixed31_32_sub(norm_x, index_f);
++
++ *tf_point = dal_fixed31_32_add(lut1,
++ dal_fixed31_32_mul(delta_index, delta_lut));
++ }
++ ++i;
++ }
++}
++
+ static void build_new_custom_resulted_curve(
+ uint32_t hw_points_num,
+ struct dc_transfer_func_distributed_points *tf_pts)
+@@ -1025,6 +1182,29 @@ static void build_new_custom_resulted_curve(
+ }
+ }
+
++static void apply_degamma_for_user_regamma(struct pwl_float_data_ex *rgb_regamma,
++ uint32_t hw_points_num)
++{
++ uint32_t i;
++
++ struct gamma_coefficients coeff;
++ struct pwl_float_data_ex *rgb = rgb_regamma;
++ const struct hw_x_point *coord_x = coordinates_x;
++
++ build_coefficients(&coeff, true);
++
++ i = 0;
++ while (i != hw_points_num + 1) {
++ rgb->r = translate_from_linear_space_ex(
++ coord_x->x, &coeff, 0);
++ rgb->g = rgb->r;
++ rgb->b = rgb->r;
++ ++coord_x;
++ ++rgb;
++ ++i;
++ }
++}
++
+ static bool map_regamma_hw_to_x_user(
+ const struct dc_gamma *ramp,
+ struct pixel_gamma_point *coeff128,
+@@ -1062,6 +1242,7 @@ static bool map_regamma_hw_to_x_user(
+ }
+ }
+
++ /* this should be named differently, all it does is clamp to 0-1 */
+ build_new_custom_resulted_curve(hw_points_num, tf_pts);
+
+ return true;
+@@ -1168,6 +1349,113 @@ bool mod_color_calculate_regamma_params(struct dc_transfer_func *output_tf,
+ return ret;
+ }
+
++bool calculate_user_regamma_coeff(struct dc_transfer_func *output_tf,
++ const struct regamma_lut *regamma)
++{
++ struct gamma_coefficients coeff;
++ const struct hw_x_point *coord_x = coordinates_x;
++ uint32_t i = 0;
++
++ do {
++ coeff.a0[i] = dal_fixed31_32_from_fraction(
++ regamma->coeff.A0[i], 10000000);
++ coeff.a1[i] = dal_fixed31_32_from_fraction(
++ regamma->coeff.A1[i], 1000);
++ coeff.a2[i] = dal_fixed31_32_from_fraction(
++ regamma->coeff.A2[i], 1000);
++ coeff.a3[i] = dal_fixed31_32_from_fraction(
++ regamma->coeff.A3[i], 1000);
++ coeff.user_gamma[i] = dal_fixed31_32_from_fraction(
++ regamma->coeff.gamma[i], 1000);
++
++ ++i;
++ } while (i != 3);
++
++ i = 0;
++ /* fixed_pt library has problems handling too small values */
++ while (i != 32) {
++ output_tf->tf_pts.red[i] = dal_fixed31_32_zero;
++ output_tf->tf_pts.green[i] = dal_fixed31_32_zero;
++ output_tf->tf_pts.blue[i] = dal_fixed31_32_zero;
++ ++coord_x;
++ ++i;
++ }
++ while (i != MAX_HW_POINTS + 1) {
++ output_tf->tf_pts.red[i] = translate_from_linear_space_ex(
++ coord_x->x, &coeff, 0);
++ output_tf->tf_pts.green[i] = translate_from_linear_space_ex(
++ coord_x->x, &coeff, 1);
++ output_tf->tf_pts.blue[i] = translate_from_linear_space_ex(
++ coord_x->x, &coeff, 2);
++ ++coord_x;
++ ++i;
++ }
++
++ // this function just clamps output to 0-1
++ build_new_custom_resulted_curve(MAX_HW_POINTS, &output_tf->tf_pts);
++ output_tf->type = TF_TYPE_DISTRIBUTED_POINTS;
++
++ return true;
++}
++
++bool calculate_user_regamma_ramp(struct dc_transfer_func *output_tf,
++ const struct regamma_lut *regamma)
++{
++ struct dc_transfer_func_distributed_points *tf_pts = &output_tf->tf_pts;
++ struct dividers dividers;
++
++ struct pwl_float_data *rgb_user = NULL;
++ struct pwl_float_data_ex *rgb_regamma = NULL;
++ bool ret = false;
++
++ if (regamma == NULL)
++ return false;
++
++ output_tf->type = TF_TYPE_DISTRIBUTED_POINTS;
++
++ rgb_user = kzalloc(sizeof(*rgb_user) * (GAMMA_RGB_256_ENTRIES + _EXTRA_POINTS),
++ GFP_KERNEL);
++ if (!rgb_user)
++ goto rgb_user_alloc_fail;
++
++ rgb_regamma = kzalloc(sizeof(*rgb_regamma) * (MAX_HW_POINTS + _EXTRA_POINTS),
++ GFP_KERNEL);
++ if (!rgb_regamma)
++ goto rgb_regamma_alloc_fail;
++
++ dividers.divider1 = dal_fixed31_32_from_fraction(3, 2);
++ dividers.divider2 = dal_fixed31_32_from_int(2);
++ dividers.divider3 = dal_fixed31_32_from_fraction(5, 2);
++
++ scale_user_regamma_ramp(rgb_user, &regamma->ramp, dividers);
++
++ if (regamma->flags.bits.applyDegamma == 1) {
++ apply_degamma_for_user_regamma(rgb_regamma, MAX_HW_POINTS);
++ copy_rgb_regamma_to_coordinates_x(coordinates_x,
++ MAX_HW_POINTS, rgb_regamma);
++ }
++
++ interpolate_user_regamma(MAX_HW_POINTS, rgb_user,
++ regamma->flags.bits.applyDegamma, tf_pts);
++
++ // no custom HDR curves!
++ tf_pts->end_exponent = 0;
++ tf_pts->x_point_at_y1_red = 1;
++ tf_pts->x_point_at_y1_green = 1;
++ tf_pts->x_point_at_y1_blue = 1;
++
++ // this function just clamps output to 0-1
++ build_new_custom_resulted_curve(MAX_HW_POINTS, tf_pts);
++
++ ret = true;
++
++ kfree(rgb_regamma);
++rgb_regamma_alloc_fail:
++ kfree(rgb_user);
++rgb_user_alloc_fail:
++ return ret;
++}
++
+ bool mod_color_calculate_degamma_params(struct dc_transfer_func *input_tf,
+ const struct dc_gamma *ramp, bool mapUserRamp)
+ {
+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 b7f9bc2..b6404899 100644
+--- a/drivers/gpu/drm/amd/display/modules/color/color_gamma.h
++++ b/drivers/gpu/drm/amd/display/modules/color/color_gamma.h
+@@ -32,6 +32,47 @@ struct dc_transfer_func_distributed_points;
+ struct dc_rgb_fixed;
+ enum dc_transfer_func_predefined;
+
++/* For SetRegamma ADL interface support
++ * Must match escape type
++ */
++union regamma_flags {
++ unsigned int raw;
++ struct {
++ unsigned int gammaRampArray :1; // RegammaRamp is in use
++ unsigned int gammaFromEdid :1; //gamma from edid is in use
++ unsigned int gammaFromEdidEx :1; //gamma from edid is in use , but only for Display Id 1.2
++ unsigned int gammaFromUser :1; //user custom gamma is used
++ unsigned int coeffFromUser :1; //coeff. A0-A3 from user is in use
++ unsigned int coeffFromEdid :1; //coeff. A0-A3 from edid is in use
++ unsigned int applyDegamma :1; //flag for additional degamma correction in driver
++ unsigned int gammaPredefinedSRGB :1; //flag for SRGB gamma
++ unsigned int gammaPredefinedPQ :1; //flag for PQ gamma
++ unsigned int gammaPredefinedPQ2084Interim :1; //flag for PQ gamma, lower max nits
++ unsigned int gammaPredefined36 :1; //flag for 3.6 gamma
++ unsigned int gammaPredefinedReset :1; //flag to return to previous gamma
++ } bits;
++};
++
++struct regamma_ramp {
++ unsigned short gamma[256*3]; // gamma ramp packed in same way as OS windows ,r , g & b
++};
++
++struct regamma_coeff {
++ int gamma[3];
++ int A0[3];
++ int A1[3];
++ int A2[3];
++ int A3[3];
++};
++
++struct regamma_lut {
++ union regamma_flags flags;
++ union {
++ struct regamma_ramp ramp;
++ struct regamma_coeff coeff;
++ };
++};
++
+ void setup_x_points_distribution(void);
+ void precompute_pq(void);
+ void precompute_de_pq(void);
+@@ -45,9 +86,14 @@ bool mod_color_calculate_degamma_params(struct dc_transfer_func *output_tf,
+ bool mod_color_calculate_curve(enum dc_transfer_func_predefined trans,
+ struct dc_transfer_func_distributed_points *points);
+
+-bool mod_color_calculate_degamma_curve(enum dc_transfer_func_predefined trans,
++bool mod_color_calculate_degamma_curve(enum dc_transfer_func_predefined trans,
+ struct dc_transfer_func_distributed_points *points);
+
++bool calculate_user_regamma_coeff(struct dc_transfer_func *output_tf,
++ const struct regamma_lut *regamma);
++
++bool calculate_user_regamma_ramp(struct dc_transfer_func *output_tf,
++ const struct regamma_lut *regamma);
+
+
+ #endif /* COLOR_MOD_COLOR_GAMMA_H_ */
+--
+2.7.4
+