diff options
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.patch | 469 |
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, ®amma->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 + |