diff options
Diffstat (limited to 'meta-v1000/recipes-kernel/linux/linux-yocto-4.14.71/0142-drm-amd-display-Output-Transfer-Function-Regamma-Ref.patch')
-rw-r--r-- | meta-v1000/recipes-kernel/linux/linux-yocto-4.14.71/0142-drm-amd-display-Output-Transfer-Function-Regamma-Ref.patch | 2131 |
1 files changed, 2131 insertions, 0 deletions
diff --git a/meta-v1000/recipes-kernel/linux/linux-yocto-4.14.71/0142-drm-amd-display-Output-Transfer-Function-Regamma-Ref.patch b/meta-v1000/recipes-kernel/linux/linux-yocto-4.14.71/0142-drm-amd-display-Output-Transfer-Function-Regamma-Ref.patch new file mode 100644 index 00000000..8b4922e1 --- /dev/null +++ b/meta-v1000/recipes-kernel/linux/linux-yocto-4.14.71/0142-drm-amd-display-Output-Transfer-Function-Regamma-Ref.patch @@ -0,0 +1,2131 @@ +From 7bca50c9ad6a913eaabf9b7b23e7347d9673f62c Mon Sep 17 00:00:00 2001 +From: Amy Zhang <Amy.Zhang@amd.com> +Date: Thu, 5 Jan 2017 17:12:20 -0500 +Subject: [PATCH 0142/4131] drm/amd/display: Output Transfer Function Regamma + Refactor + +- Create translation function to translate logical format to hw format +- Refactor to use transfer function in dc instead of input gamma + +Signed-off-by: Amy Zhang <Amy.Zhang@amd.com> +Acked-by: Harry Wentland <Harry.Wentland@amd.com> +Reviewed-by: Anthony Koo <Anthony.Koo@amd.com> +Signed-off-by: Alex Deucher <alexander.deucher@amd.com> +--- + drivers/gpu/drm/amd/display/dc/basics/fixpt31_32.c | 9 + + drivers/gpu/drm/amd/display/dc/calcs/Makefile | 2 +- + drivers/gpu/drm/amd/display/dc/calcs/gamma_calcs.c | 1481 -------------------- + drivers/gpu/drm/amd/display/dc/core/dc.c | 10 +- + drivers/gpu/drm/amd/display/dc/dc.h | 11 +- + .../amd/display/dc/dce110/dce110_hw_sequencer.c | 440 +++++- + drivers/gpu/drm/amd/display/dc/inc/gamma_calcs.h | 20 - + drivers/gpu/drm/amd/display/dc/inc/hw/opp.h | 2 - + drivers/gpu/drm/amd/display/include/fixed31_32.h | 8 + + 9 files changed, 466 insertions(+), 1517 deletions(-) + delete mode 100644 drivers/gpu/drm/amd/display/dc/calcs/gamma_calcs.c + delete mode 100644 drivers/gpu/drm/amd/display/dc/inc/gamma_calcs.h + +diff --git a/drivers/gpu/drm/amd/display/dc/basics/fixpt31_32.c b/drivers/gpu/drm/amd/display/dc/basics/fixpt31_32.c +index 5a6e4684..546ed67 100644 +--- a/drivers/gpu/drm/amd/display/dc/basics/fixpt31_32.c ++++ b/drivers/gpu/drm/amd/display/dc/basics/fixpt31_32.c +@@ -246,6 +246,15 @@ struct fixed31_32 dal_fixed31_32_add( + return res; + } + ++struct fixed31_32 dal_fixed31_32_add_int( ++ struct fixed31_32 arg1, ++ int32_t arg2) ++{ ++ return dal_fixed31_32_add( ++ arg1, ++ dal_fixed31_32_from_int(arg2)); ++} ++ + struct fixed31_32 dal_fixed31_32_sub_int( + struct fixed31_32 arg1, + int32_t arg2) +diff --git a/drivers/gpu/drm/amd/display/dc/calcs/Makefile b/drivers/gpu/drm/amd/display/dc/calcs/Makefile +index 4001933..4bb08ae 100644 +--- a/drivers/gpu/drm/amd/display/dc/calcs/Makefile ++++ b/drivers/gpu/drm/amd/display/dc/calcs/Makefile +@@ -3,7 +3,7 @@ + # It calculates Bandwidth and Watermarks values for HW programming + # + +-BW_CALCS = bandwidth_calcs.o bw_fixed.o gamma_calcs.o ++BW_CALCS = bandwidth_calcs.o bw_fixed.o + + AMD_DAL_BW_CALCS = $(addprefix $(AMDDALPATH)/dc/calcs/,$(BW_CALCS)) + +diff --git a/drivers/gpu/drm/amd/display/dc/calcs/gamma_calcs.c b/drivers/gpu/drm/amd/display/dc/calcs/gamma_calcs.c +deleted file mode 100644 +index fd300db..0000000 +--- a/drivers/gpu/drm/amd/display/dc/calcs/gamma_calcs.c ++++ /dev/null +@@ -1,1481 +0,0 @@ +-/* +- * Copyright 2015 Advanced Micro Devices, Inc. +- * +- * Permission is hereby granted, free of charge, to any person obtaining a +- * copy of this software and associated documentation files (the "Software"), +- * to deal in the Software without restriction, including without limitation +- * the rights to use, copy, modify, merge, publish, distribute, sublicense, +- * and/or sell copies of the Software, and to permit persons to whom the +- * Software is furnished to do so, subject to the following conditions: +- * +- * The above copyright notice and this permission notice shall be included in +- * all copies or substantial portions of the Software. +- * +- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR +- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +- * OTHER DEALINGS IN THE SOFTWARE. +- * +- * Authors: AMD +- * +- */ +- +-#include "dm_services.h" +-#include "gamma_calcs.h" +- +-struct curve_config { +- uint32_t offset; +- int8_t segments[16]; +- int8_t begin; +-}; +- +-static bool build_custom_float( +- struct fixed31_32 value, +- const struct custom_float_format *format, +- bool *negative, +- uint32_t *mantissa, +- uint32_t *exponenta) +-{ +- uint32_t exp_offset = (1 << (format->exponenta_bits - 1)) - 1; +- +- const struct fixed31_32 mantissa_constant_plus_max_fraction = +- dal_fixed31_32_from_fraction( +- (1LL << (format->mantissa_bits + 1)) - 1, +- 1LL << format->mantissa_bits); +- +- struct fixed31_32 mantiss; +- +- if (dal_fixed31_32_eq( +- value, +- dal_fixed31_32_zero)) { +- *negative = false; +- *mantissa = 0; +- *exponenta = 0; +- return true; +- } +- +- if (dal_fixed31_32_lt( +- value, +- dal_fixed31_32_zero)) { +- *negative = format->sign; +- value = dal_fixed31_32_neg(value); +- } else { +- *negative = false; +- } +- +- if (dal_fixed31_32_lt( +- value, +- dal_fixed31_32_one)) { +- uint32_t i = 1; +- +- do { +- value = dal_fixed31_32_shl(value, 1); +- ++i; +- } while (dal_fixed31_32_lt( +- value, +- dal_fixed31_32_one)); +- +- --i; +- +- if (exp_offset <= i) { +- *mantissa = 0; +- *exponenta = 0; +- return true; +- } +- +- *exponenta = exp_offset - i; +- } else if (dal_fixed31_32_le( +- mantissa_constant_plus_max_fraction, +- value)) { +- uint32_t i = 1; +- +- do { +- value = dal_fixed31_32_shr(value, 1); +- ++i; +- } while (dal_fixed31_32_lt( +- mantissa_constant_plus_max_fraction, +- value)); +- +- *exponenta = exp_offset + i - 1; +- } else { +- *exponenta = exp_offset; +- } +- +- mantiss = dal_fixed31_32_sub( +- value, +- dal_fixed31_32_one); +- +- if (dal_fixed31_32_lt( +- mantiss, +- dal_fixed31_32_zero) || +- dal_fixed31_32_lt( +- dal_fixed31_32_one, +- mantiss)) +- mantiss = dal_fixed31_32_zero; +- else +- mantiss = dal_fixed31_32_shl( +- mantiss, +- format->mantissa_bits); +- +- *mantissa = dal_fixed31_32_floor(mantiss); +- +- return true; +-} +- +-static bool setup_custom_float( +- const struct custom_float_format *format, +- bool negative, +- uint32_t mantissa, +- uint32_t exponenta, +- uint32_t *result) +-{ +- uint32_t i = 0; +- uint32_t j = 0; +- +- uint32_t value = 0; +- +- /* verification code: +- * once calculation is ok we can remove it +- */ +- +- const uint32_t mantissa_mask = +- (1 << (format->mantissa_bits + 1)) - 1; +- +- const uint32_t exponenta_mask = +- (1 << (format->exponenta_bits + 1)) - 1; +- +- if (mantissa & ~mantissa_mask) { +- BREAK_TO_DEBUGGER(); +- mantissa = mantissa_mask; +- } +- +- if (exponenta & ~exponenta_mask) { +- BREAK_TO_DEBUGGER(); +- exponenta = exponenta_mask; +- } +- +- /* end of verification code */ +- +- while (i < format->mantissa_bits) { +- uint32_t mask = 1 << i; +- +- if (mantissa & mask) +- value |= mask; +- +- ++i; +- } +- +- while (j < format->exponenta_bits) { +- uint32_t mask = 1 << j; +- +- if (exponenta & mask) +- value |= mask << i; +- +- ++j; +- } +- +- if (negative && format->sign) +- value |= 1 << (i + j); +- +- *result = value; +- +- return true; +-} +- +-static bool build_hw_curve_configuration( +- const struct curve_config *curve_config, +- struct gamma_curve *gamma_curve, +- struct curve_points *curve_points, +- struct hw_x_point *points, +- uint32_t *number_of_points) +-{ +- const int8_t max_regions_number = ARRAY_SIZE(curve_config->segments); +- +- int8_t i; +- +- uint8_t segments_calculation[8] = { 0 }; +- +- struct fixed31_32 region1 = dal_fixed31_32_zero; +- struct fixed31_32 region2; +- struct fixed31_32 increment; +- +- uint32_t index = 0; +- uint32_t segments = 0; +- uint32_t max_number; +- +- int8_t num_regions = 0; +- +- bool result = false; +- +- if (!number_of_points) { +- BREAK_TO_DEBUGGER(); +- return false; +- } +- +- max_number = *number_of_points; +- +- i = 0; +- +- while (i != max_regions_number) { +- gamma_curve[i].offset = 0; +- gamma_curve[i].segments_num = 0; +- +- ++i; +- } +- +- i = 0; +- +- while (i != max_regions_number) { +- /* number should go in uninterruptible sequence */ +- if (curve_config->segments[i] == -1) +- break; +- +- ASSERT(curve_config->segments[i] >= 0); +- +- segments += (1 << curve_config->segments[i]); +- ++num_regions; +- +- ++i; +- } +- +- if (segments > max_number) { +- BREAK_TO_DEBUGGER(); +- } else { +- int32_t divisor; +- uint32_t offset = 0; +- int8_t begin = curve_config->begin; +- int32_t region_number = 0; +- +- i = begin; +- +- while ((index < max_number) && +- (region_number < max_regions_number) && +- (i < (begin + num_regions))) { +- int32_t j = 0; +- +- segments = curve_config->segments[region_number]; +- divisor = 1 << segments; +- +- if (segments == -1) { +- if (i > 0) { +- region1 = dal_fixed31_32_shl( +- dal_fixed31_32_one, +- i - 1); +- region2 = dal_fixed31_32_shl( +- dal_fixed31_32_one, +- i); +- } else { +- region1 = dal_fixed31_32_shr( +- dal_fixed31_32_one, +- -(i - 1)); +- region2 = dal_fixed31_32_shr( +- dal_fixed31_32_one, +- -i); +- } +- +- break; +- } +- +- if (i > -1) { +- region1 = dal_fixed31_32_shl( +- dal_fixed31_32_one, +- i); +- region2 = dal_fixed31_32_shl( +- dal_fixed31_32_one, +- i + 1); +- } else { +- region1 = dal_fixed31_32_shr( +- dal_fixed31_32_one, +- -i); +- region2 = dal_fixed31_32_shr( +- dal_fixed31_32_one, +- -(i + 1)); +- } +- +- gamma_curve[region_number].offset = offset; +- gamma_curve[region_number].segments_num = segments; +- +- offset += divisor; +- +- ++segments_calculation[segments]; +- +- increment = dal_fixed31_32_div_int( +- dal_fixed31_32_sub( +- region2, +- region1), +- divisor); +- +- points[index].x = region1; +- points[index].adjusted_x = region1; +- +- ++index; +- ++region_number; +- +- while ((index < max_number) && (j < divisor - 1)) { +- region1 = dal_fixed31_32_add( +- region1, +- increment); +- +- points[index].x = region1; +- points[index].adjusted_x = region1; +- +- ++index; +- ++j; +- } +- +- ++i; +- } +- +- points[index].x = region1; +- points[index].adjusted_x = region1; +- +- *number_of_points = index; +- +- result = true; +- } +- +- curve_points[0].x = points[0].adjusted_x; +- curve_points[0].offset = dal_fixed31_32_zero; +- +- curve_points[1].x = points[index - 1].adjusted_x; +- curve_points[1].offset = dal_fixed31_32_zero; +- +- curve_points[2].x = points[index].adjusted_x; +- curve_points[2].offset = dal_fixed31_32_zero; +- +- return result; +-} +- +-static bool setup_distribution_points_pq( +- struct gamma_curve *arr_curve_points, +- struct curve_points *arr_points, +- uint32_t *hw_points_num, +- struct hw_x_point *coordinates_x, +- enum surface_pixel_format format) +-{ +- struct curve_config cfg; +- +- cfg.offset = 0; +- cfg.segments[0] = 2; +- cfg.segments[1] = 2; +- cfg.segments[2] = 2; +- cfg.segments[3] = 2; +- cfg.segments[4] = 2; +- cfg.segments[5] = 2; +- cfg.segments[6] = 3; +- cfg.segments[7] = 4; +- cfg.segments[8] = 4; +- cfg.segments[9] = 4; +- cfg.segments[10] = 4; +- cfg.segments[11] = 5; +- cfg.segments[12] = 5; +- cfg.segments[13] = 5; +- cfg.segments[14] = 5; +- cfg.segments[15] = 5; +- +- if (format == SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616F || +- format == SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F) +- cfg.begin = -11; +- else +- cfg.begin = -16; +- +- if (!build_hw_curve_configuration( +- &cfg, arr_curve_points, +- arr_points, +- coordinates_x, hw_points_num)) { +- ASSERT_CRITICAL(false); +- return false; +- } +- return true; +-} +- +-static bool setup_distribution_points( +- struct gamma_curve *arr_curve_points, +- struct curve_points *arr_points, +- uint32_t *hw_points_num, +- struct hw_x_point *coordinates_x) +-{ +- struct curve_config cfg; +- +- cfg.offset = 0; +- cfg.segments[0] = 3; +- cfg.segments[1] = 4; +- cfg.segments[2] = 4; +- cfg.segments[3] = 4; +- cfg.segments[4] = 4; +- cfg.segments[5] = 4; +- cfg.segments[6] = 4; +- cfg.segments[7] = 4; +- cfg.segments[8] = 5; +- cfg.segments[9] = 5; +- cfg.segments[10] = 0; +- cfg.segments[11] = -1; +- cfg.segments[12] = -1; +- cfg.segments[13] = -1; +- cfg.segments[14] = -1; +- cfg.segments[15] = -1; +- +- cfg.begin = -10; +- +- if (!build_hw_curve_configuration( +- &cfg, arr_curve_points, +- arr_points, +- coordinates_x, hw_points_num)) { +- ASSERT_CRITICAL(false); +- return false; +- } +- return true; +-} +- +-struct dividers { +- struct fixed31_32 divider1; +- struct fixed31_32 divider2; +- struct fixed31_32 divider3; +-}; +- +-static void build_regamma_coefficients(struct gamma_coefficients *coefficients) +-{ +- /* sRGB should apply 2.4 */ +- static const int32_t numerator01[3] = { 31308, 31308, 31308 }; +- static const int32_t numerator02[3] = { 12920, 12920, 12920 }; +- static const int32_t numerator03[3] = { 55, 55, 55 }; +- static const int32_t numerator04[3] = { 55, 55, 55 }; +- static const int32_t numerator05[3] = { 2400, 2400, 2400 }; +- +- const int32_t *numerator1; +- const int32_t *numerator2; +- const int32_t *numerator3; +- const int32_t *numerator4; +- const int32_t *numerator5; +- +- uint32_t i = 0; +- +- numerator1 = numerator01; +- numerator2 = numerator02; +- numerator3 = numerator03; +- numerator4 = numerator04; +- numerator5 = numerator05; +- +- do { +- coefficients->a0[i] = dal_fixed31_32_from_fraction( +- numerator1[i], 10000000); +- coefficients->a1[i] = dal_fixed31_32_from_fraction( +- numerator2[i], 1000); +- coefficients->a2[i] = dal_fixed31_32_from_fraction( +- numerator3[i], 1000); +- coefficients->a3[i] = dal_fixed31_32_from_fraction( +- numerator4[i], 1000); +- coefficients->user_gamma[i] = dal_fixed31_32_from_fraction( +- numerator5[i], 1000); +- +- ++i; +- } while (i != ARRAY_SIZE(coefficients->a0)); +-} +- +-static struct fixed31_32 translate_from_linear_space( +- struct fixed31_32 arg, +- struct fixed31_32 a0, +- struct fixed31_32 a1, +- struct fixed31_32 a2, +- struct fixed31_32 a3, +- struct fixed31_32 gamma) +-{ +- const struct fixed31_32 one = dal_fixed31_32_from_int(1); +- +- if (dal_fixed31_32_le(arg, dal_fixed31_32_neg(a0))) +- return dal_fixed31_32_sub( +- a2, +- dal_fixed31_32_mul( +- dal_fixed31_32_add( +- one, +- a3), +- dal_fixed31_32_pow( +- dal_fixed31_32_neg(arg), +- dal_fixed31_32_recip(gamma)))); +- else if (dal_fixed31_32_le(a0, arg)) +- return dal_fixed31_32_sub( +- dal_fixed31_32_mul( +- dal_fixed31_32_add( +- one, +- a3), +- dal_fixed31_32_pow( +- arg, +- dal_fixed31_32_recip(gamma))), +- a2); +- else +- return dal_fixed31_32_mul( +- arg, +- a1); +-} +- +-static inline struct fixed31_32 translate_from_linear_space_ex( +- struct fixed31_32 arg, +- struct gamma_coefficients *coeff, +- uint32_t color_index) +-{ +- return translate_from_linear_space( +- arg, +- coeff->a0[color_index], +- coeff->a1[color_index], +- coeff->a2[color_index], +- coeff->a3[color_index], +- coeff->user_gamma[color_index]); +-} +- +-static bool find_software_points( +- const struct gamma_pixel *axis_x_256, +- struct fixed31_32 hw_point, +- enum channel_name channel, +- uint32_t *index_to_start, +- uint32_t *index_left, +- uint32_t *index_right, +- enum hw_point_position *pos) +-{ +- const uint32_t max_number = INPUT_LUT_ENTRIES + 3; +- +- struct fixed31_32 left, right; +- +- uint32_t i = *index_to_start; +- +- while (i < max_number) { +- if (channel == CHANNEL_NAME_RED) { +- left = axis_x_256[i].r; +- +- if (i < max_number - 1) +- right = axis_x_256[i + 1].r; +- else +- right = axis_x_256[max_number - 1].r; +- } else if (channel == CHANNEL_NAME_GREEN) { +- left = axis_x_256[i].g; +- +- if (i < max_number - 1) +- right = axis_x_256[i + 1].g; +- else +- right = axis_x_256[max_number - 1].g; +- } else { +- left = axis_x_256[i].b; +- +- if (i < max_number - 1) +- right = axis_x_256[i + 1].b; +- else +- right = axis_x_256[max_number - 1].b; +- } +- +- if (dal_fixed31_32_le(left, hw_point) && +- dal_fixed31_32_le(hw_point, right)) { +- *index_to_start = i; +- *index_left = i; +- +- if (i < max_number - 1) +- *index_right = i + 1; +- else +- *index_right = max_number - 1; +- +- *pos = HW_POINT_POSITION_MIDDLE; +- +- return true; +- } else if ((i == *index_to_start) && +- dal_fixed31_32_le(hw_point, left)) { +- *index_to_start = i; +- *index_left = i; +- *index_right = i; +- +- *pos = HW_POINT_POSITION_LEFT; +- +- return true; +- } else if ((i == max_number - 1) && +- dal_fixed31_32_le(right, hw_point)) { +- *index_to_start = i; +- *index_left = i; +- *index_right = i; +- +- *pos = HW_POINT_POSITION_RIGHT; +- +- return true; +- } +- +- ++i; +- } +- +- return false; +-} +- +-static bool build_custom_gamma_mapping_coefficients_worker( +- struct pixel_gamma_point *coeff, +- const struct hw_x_point *coordinates_x, +- const struct gamma_pixel *axis_x_256, +- enum channel_name channel, +- uint32_t number_of_points, +- enum surface_pixel_format pixel_format) +-{ +- uint32_t i = 0; +- +- while (i <= number_of_points) { +- struct fixed31_32 coord_x; +- +- uint32_t index_to_start = 0; +- uint32_t index_left = 0; +- uint32_t index_right = 0; +- +- enum hw_point_position hw_pos; +- +- struct gamma_point *point; +- +- struct fixed31_32 left_pos; +- struct fixed31_32 right_pos; +- +- /* +- * TODO: confirm enum in surface_pixel_format +- * if (pixel_format == PIXEL_FORMAT_FP16) +- *coord_x = coordinates_x[i].adjusted_x; +- *else +- */ +- if (channel == CHANNEL_NAME_RED) +- coord_x = coordinates_x[i].regamma_y_red; +- else if (channel == CHANNEL_NAME_GREEN) +- coord_x = coordinates_x[i].regamma_y_green; +- else +- coord_x = coordinates_x[i].regamma_y_blue; +- +- if (!find_software_points( +- axis_x_256, coord_x, channel, +- &index_to_start, &index_left, &index_right, &hw_pos)) { +- BREAK_TO_DEBUGGER(); +- return false; +- } +- +- if (index_left >= INPUT_LUT_ENTRIES + 3) { +- BREAK_TO_DEBUGGER(); +- return false; +- } +- +- if (index_right >= INPUT_LUT_ENTRIES + 3) { +- BREAK_TO_DEBUGGER(); +- return false; +- } +- +- if (channel == CHANNEL_NAME_RED) { +- point = &coeff[i].r; +- +- left_pos = axis_x_256[index_left].r; +- right_pos = axis_x_256[index_right].r; +- } else if (channel == CHANNEL_NAME_GREEN) { +- point = &coeff[i].g; +- +- left_pos = axis_x_256[index_left].g; +- right_pos = axis_x_256[index_right].g; +- } else { +- point = &coeff[i].b; +- +- left_pos = axis_x_256[index_left].b; +- right_pos = axis_x_256[index_right].b; +- } +- +- if (hw_pos == HW_POINT_POSITION_MIDDLE) +- point->coeff = dal_fixed31_32_div( +- dal_fixed31_32_sub( +- coord_x, +- left_pos), +- dal_fixed31_32_sub( +- right_pos, +- left_pos)); +- else if (hw_pos == HW_POINT_POSITION_LEFT) +- point->coeff = dal_fixed31_32_zero; +- else if (hw_pos == HW_POINT_POSITION_RIGHT) +- point->coeff = dal_fixed31_32_from_int(2); +- else { +- BREAK_TO_DEBUGGER(); +- return false; +- } +- +- point->left_index = index_left; +- point->right_index = index_right; +- point->pos = hw_pos; +- +- ++i; +- } +- +- return true; +-} +- +-static inline bool build_oem_custom_gamma_mapping_coefficients( +- struct pixel_gamma_point *coeff128_oem, +- const struct hw_x_point *coordinates_x, +- const struct gamma_pixel *axis_x_256, +- uint32_t number_of_points, +- enum surface_pixel_format pixel_format) +-{ +- int i; +- +- for (i = 0; i < 3; i++) { +- if (!build_custom_gamma_mapping_coefficients_worker( +- coeff128_oem, coordinates_x, axis_x_256, i, +- number_of_points, pixel_format)) +- return false; +- } +- return true; +-} +- +-static struct fixed31_32 calculate_mapped_value( +- struct pwl_float_data *rgb, +- const struct pixel_gamma_point *coeff, +- enum channel_name channel, +- uint32_t max_index) +-{ +- const struct gamma_point *point; +- +- struct fixed31_32 result; +- +- if (channel == CHANNEL_NAME_RED) +- point = &coeff->r; +- else if (channel == CHANNEL_NAME_GREEN) +- point = &coeff->g; +- else +- point = &coeff->b; +- +- if ((point->left_index < 0) || (point->left_index > max_index)) { +- BREAK_TO_DEBUGGER(); +- return dal_fixed31_32_zero; +- } +- +- if ((point->right_index < 0) || (point->right_index > max_index)) { +- BREAK_TO_DEBUGGER(); +- return dal_fixed31_32_zero; +- } +- +- if (point->pos == HW_POINT_POSITION_MIDDLE) +- if (channel == CHANNEL_NAME_RED) +- result = dal_fixed31_32_add( +- dal_fixed31_32_mul( +- point->coeff, +- dal_fixed31_32_sub( +- rgb[point->right_index].r, +- rgb[point->left_index].r)), +- rgb[point->left_index].r); +- else if (channel == CHANNEL_NAME_GREEN) +- result = dal_fixed31_32_add( +- dal_fixed31_32_mul( +- point->coeff, +- dal_fixed31_32_sub( +- rgb[point->right_index].g, +- rgb[point->left_index].g)), +- rgb[point->left_index].g); +- else +- result = dal_fixed31_32_add( +- dal_fixed31_32_mul( +- point->coeff, +- dal_fixed31_32_sub( +- rgb[point->right_index].b, +- rgb[point->left_index].b)), +- rgb[point->left_index].b); +- else if (point->pos == HW_POINT_POSITION_LEFT) { +- BREAK_TO_DEBUGGER(); +- result = dal_fixed31_32_zero; +- } else { +- BREAK_TO_DEBUGGER(); +- result = dal_fixed31_32_one; +- } +- +- return result; +-} +- +-static inline struct fixed31_32 calculate_oem_mapped_value( +- struct pwl_float_data *rgb_oem, +- const struct pixel_gamma_point *coeff, +- uint32_t index, +- enum channel_name channel, +- uint32_t max_index) +-{ +- return calculate_mapped_value( +- rgb_oem, +- coeff + index, +- channel, +- max_index); +-} +- +-static void compute_pq(struct fixed31_32 in_x, struct fixed31_32 *out_y) +-{ +- /* consts for PQ gamma formula. */ +- const struct fixed31_32 m1 = +- dal_fixed31_32_from_fraction(159301758, 1000000000); +- const struct fixed31_32 m2 = +- dal_fixed31_32_from_fraction(7884375, 100000); +- const struct fixed31_32 c1 = +- dal_fixed31_32_from_fraction(8359375, 10000000); +- const struct fixed31_32 c2 = +- dal_fixed31_32_from_fraction(188515625, 10000000); +- const struct fixed31_32 c3 = +- dal_fixed31_32_from_fraction(186875, 10000); +- +- struct fixed31_32 l_pow_m1; +- struct fixed31_32 base; +- +- if (dal_fixed31_32_lt(in_x, dal_fixed31_32_zero)) +- in_x = dal_fixed31_32_zero; +- +- l_pow_m1 = dal_fixed31_32_pow(in_x, m1); +- base = dal_fixed31_32_div( +- dal_fixed31_32_add(c1, +- (dal_fixed31_32_mul(c2, l_pow_m1))), +- dal_fixed31_32_add(dal_fixed31_32_one, +- (dal_fixed31_32_mul(c3, l_pow_m1)))); +- *out_y = dal_fixed31_32_pow(base, m2); +-} +- +-static void build_regamma_curve_pq(struct pwl_float_data_ex *rgb_regamma, +- struct pwl_float_data *rgb_oem, +- struct pixel_gamma_point *coeff128_oem, +- const struct core_gamma *ramp, +- const struct core_surface *surface, +- uint32_t hw_points_num, +- const struct hw_x_point *coordinate_x, +- const struct gamma_pixel *axis_x, +- struct dividers dividers) +-{ +- uint32_t i; +- +- struct pwl_float_data_ex *rgb = rgb_regamma; +- const struct hw_x_point *coord_x = coordinate_x; +- struct fixed31_32 x; +- struct fixed31_32 output; +- struct fixed31_32 scaling_factor = +- dal_fixed31_32_from_fraction(8, 1000); +- +- /* use coord_x to retrieve coordinates chosen base on given user curve +- * the x values are exponentially distributed and currently it is hard +- * coded, the user curve shape is ignored. Need to recalculate coord_x +- * based on input curve, translation from 256/1025 to 128 PWL points. +- */ +- for (i = 0; i <= hw_points_num; i++) { +- /* Multiply 0.008 as regamma is 0-1 and FP16 input is 0-125. +- * FP 1.0 = 80nits +- */ +- x = dal_fixed31_32_mul(coord_x->adjusted_x, scaling_factor); +- +- compute_pq(x, &output); +- +- /* should really not happen? */ +- if (dal_fixed31_32_lt(output, dal_fixed31_32_zero)) +- output = dal_fixed31_32_zero; +- else if (dal_fixed31_32_lt(dal_fixed31_32_one, output)) +- output = dal_fixed31_32_one; +- +- rgb->r = output; +- rgb->g = output; +- rgb->b = output; +- +- ++coord_x; +- ++rgb; +- } +-} +- +-static void build_regamma_curve(struct pwl_float_data_ex *rgb_regamma, +- struct pwl_float_data *rgb_oem, +- struct pixel_gamma_point *coeff128_oem, +- const struct core_gamma *ramp, +- const struct core_surface *surface, +- uint32_t hw_points_num, +- const struct hw_x_point *coordinate_x, +- const struct gamma_pixel *axis_x, +- struct dividers dividers) +-{ +- uint32_t i; +- +- struct gamma_coefficients coeff; +- struct pwl_float_data_ex *rgb = rgb_regamma; +- const struct hw_x_point *coord_x = coordinate_x; +- +- build_regamma_coefficients(&coeff); +- +- /* Use opp110->regamma.coordinates_x to retrieve +- * coordinates chosen base on given user curve (future task). +- * The x values are exponentially distributed and currently +- * it is hard-coded, the user curve shape is ignored. +- * The future task is to recalculate opp110- +- * regamma.coordinates_x based on input/user curve, +- * translation from 256/1025 to 128 pwl points. +- */ +- +- i = 0; +- +- while (i != hw_points_num + 1) { +- rgb->r = translate_from_linear_space_ex( +- coord_x->adjusted_x, &coeff, 0); +- rgb->g = translate_from_linear_space_ex( +- coord_x->adjusted_x, &coeff, 1); +- rgb->b = translate_from_linear_space_ex( +- coord_x->adjusted_x, &coeff, 2); +- +- ++coord_x; +- ++rgb; +- ++i; +- } +-} +- +-static bool scale_gamma(struct pwl_float_data *pwl_rgb, +- const struct core_gamma *ramp, +- struct dividers dividers) +-{ +- const struct dc_gamma *gamma = &ramp->public; +- const uint16_t max_driver = 0xFFFF; +- const uint16_t max_os = 0xFF00; +- uint16_t scaler = max_os; +- uint32_t i = 0; +- struct pwl_float_data *rgb = pwl_rgb; +- struct pwl_float_data *rgb_last = rgb + INPUT_LUT_ENTRIES - 1; +- +- do { +- if ((gamma->red[i] > max_os) || +- (gamma->green[i] > max_os) || +- (gamma->blue[i] > max_os)) { +- scaler = max_driver; +- break; +- } +- ++i; +- } while (i != INPUT_LUT_ENTRIES); +- +- i = 0; +- +- do { +- rgb->r = dal_fixed31_32_from_fraction( +- gamma->red[i], scaler); +- rgb->g = dal_fixed31_32_from_fraction( +- gamma->green[i], scaler); +- rgb->b = dal_fixed31_32_from_fraction( +- gamma->blue[i], scaler); +- +- ++rgb; +- ++i; +- } while (i != INPUT_LUT_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); +- +- return true; +-} +- +-static void build_evenly_distributed_points( +- struct gamma_pixel *points, +- uint32_t numberof_points, +- struct fixed31_32 max_value, +- struct dividers dividers) +-{ +- struct gamma_pixel *p = points; +- struct gamma_pixel *p_last = p + numberof_points - 1; +- +- uint32_t i = 0; +- +- do { +- struct fixed31_32 value = dal_fixed31_32_div_int( +- dal_fixed31_32_mul_int(max_value, i), +- numberof_points - 1); +- +- p->r = value; +- p->g = value; +- p->b = value; +- +- ++p; +- ++i; +- } while (i != numberof_points); +- +- p->r = dal_fixed31_32_div(p_last->r, dividers.divider1); +- p->g = dal_fixed31_32_div(p_last->g, dividers.divider1); +- p->b = dal_fixed31_32_div(p_last->b, dividers.divider1); +- +- ++p; +- +- p->r = dal_fixed31_32_div(p_last->r, dividers.divider2); +- p->g = dal_fixed31_32_div(p_last->g, dividers.divider2); +- p->b = dal_fixed31_32_div(p_last->b, dividers.divider2); +- +- ++p; +- +- p->r = dal_fixed31_32_div(p_last->r, dividers.divider3); +- p->g = dal_fixed31_32_div(p_last->g, dividers.divider3); +- p->b = dal_fixed31_32_div(p_last->b, dividers.divider3); +-} +- +-static inline void copy_rgb_regamma_to_coordinates_x( +- struct hw_x_point *coordinates_x, +- uint32_t hw_points_num, +- const struct pwl_float_data_ex *rgb_ex) +-{ +- struct hw_x_point *coords = coordinates_x; +- uint32_t i = 0; +- const struct pwl_float_data_ex *rgb_regamma = rgb_ex; +- +- while (i <= hw_points_num) { +- coords->regamma_y_red = rgb_regamma->r; +- coords->regamma_y_green = rgb_regamma->g; +- coords->regamma_y_blue = rgb_regamma->b; +- +- ++coords; +- ++rgb_regamma; +- ++i; +- } +-} +- +-static bool calculate_interpolated_hardware_curve( +- struct pwl_result_data *rgb, +- struct pixel_gamma_point *coeff128, +- struct pwl_float_data *rgb_user, +- const struct hw_x_point *coordinates_x, +- const struct gamma_pixel *axis_x_256, +- uint32_t number_of_points, +- enum surface_pixel_format pixel_format) +-{ +- +- const struct pixel_gamma_point *coeff; +- struct pixel_gamma_point *coeff_128 = coeff128; +- uint32_t max_entries = 3 - 1; +- struct pwl_result_data *rgb_resulted = rgb; +- +- uint32_t i = 0; +- +- if (!build_oem_custom_gamma_mapping_coefficients( +- coeff_128, coordinates_x, axis_x_256, +- number_of_points, +- pixel_format)) +- return false; +- +- coeff = coeff128; +- max_entries += INPUT_LUT_ENTRIES; +- +- /* TODO: float point case */ +- +- while (i <= number_of_points) { +- rgb_resulted->red = calculate_mapped_value( +- rgb_user, coeff, CHANNEL_NAME_RED, max_entries); +- rgb_resulted->green = calculate_mapped_value( +- rgb_user, coeff, CHANNEL_NAME_GREEN, max_entries); +- rgb_resulted->blue = calculate_mapped_value( +- rgb_user, coeff, CHANNEL_NAME_BLUE, max_entries); +- +- ++coeff; +- ++rgb_resulted; +- ++i; +- } +- +- return true; +-} +- +-static bool map_regamma_hw_to_x_user( +- struct pixel_gamma_point *coeff128, +- struct pwl_float_data *rgb_oem, +- struct pwl_result_data *rgb_resulted, +- struct pwl_float_data *rgb_user, +- struct hw_x_point *coords_x, +- const struct gamma_pixel *axis_x, +- const struct dc_gamma *gamma, +- const struct pwl_float_data_ex *rgb_regamma, +- struct dividers dividers, +- uint32_t hw_points_num, +- const struct core_surface *surface) +-{ +- /* setup to spare calculated ideal regamma values */ +- +- struct pixel_gamma_point *coeff = coeff128; +- +- struct hw_x_point *coords = coords_x; +- +- copy_rgb_regamma_to_coordinates_x(coords, hw_points_num, rgb_regamma); +- +- return calculate_interpolated_hardware_curve( +- rgb_resulted, coeff, rgb_user, coords, axis_x, +- hw_points_num, surface->public.format); +-} +- +-static void build_new_custom_resulted_curve( +- struct pwl_result_data *rgb_resulted, +- uint32_t hw_points_num) +-{ +- struct pwl_result_data *rgb = rgb_resulted; +- struct pwl_result_data *rgb_plus_1 = rgb + 1; +- +- uint32_t i; +- +- i = 0; +- +- while (i != hw_points_num + 1) { +- rgb->red = dal_fixed31_32_clamp( +- rgb->red, dal_fixed31_32_zero, +- dal_fixed31_32_one); +- rgb->green = dal_fixed31_32_clamp( +- rgb->green, dal_fixed31_32_zero, +- dal_fixed31_32_one); +- rgb->blue = dal_fixed31_32_clamp( +- rgb->blue, dal_fixed31_32_zero, +- dal_fixed31_32_one); +- +- ++rgb; +- ++i; +- } +- +- rgb = rgb_resulted; +- +- i = 1; +- +- while (i != hw_points_num + 1) { +- if (dal_fixed31_32_lt(rgb_plus_1->red, rgb->red)) +- rgb_plus_1->red = rgb->red; +- if (dal_fixed31_32_lt(rgb_plus_1->green, rgb->green)) +- rgb_plus_1->green = rgb->green; +- if (dal_fixed31_32_lt(rgb_plus_1->blue, rgb->blue)) +- rgb_plus_1->blue = rgb->blue; +- +- rgb->delta_red = dal_fixed31_32_sub( +- rgb_plus_1->red, +- rgb->red); +- rgb->delta_green = dal_fixed31_32_sub( +- rgb_plus_1->green, +- rgb->green); +- rgb->delta_blue = dal_fixed31_32_sub( +- rgb_plus_1->blue, +- rgb->blue); +- +- ++rgb_plus_1; +- ++rgb; +- ++i; +- } +-} +- +-static void rebuild_curve_configuration_magic( +- struct curve_points *arr_points, +- struct pwl_result_data *rgb_resulted, +- const struct hw_x_point *coordinates_x, +- uint32_t hw_points_num, +- enum dc_transfer_func_predefined tf) +-{ +- struct fixed31_32 y_r; +- struct fixed31_32 y_g; +- struct fixed31_32 y_b; +- +- struct fixed31_32 y1_min; +- struct fixed31_32 y3_max; +- +- y_r = rgb_resulted[0].red; +- y_g = rgb_resulted[0].green; +- y_b = rgb_resulted[0].blue; +- +- y1_min = dal_fixed31_32_min(y_r, dal_fixed31_32_min(y_g, y_b)); +- +- arr_points[0].x = coordinates_x[0].adjusted_x; +- arr_points[0].y = y1_min; +- arr_points[0].slope = dal_fixed31_32_div( +- arr_points[0].y, +- arr_points[0].x); +- +- /* this should be cleaned up as it's confusing my understanding (KK) is +- * that REGAMMA_CNTLA_EXP_REGION_END is the X value for the region end +- * REGAMMA_CNTLA_EXP_REGION_END_BASE is Y value for the above X +- * REGAMMA_CNTLA_EXP_REGION_END_SLOPE is the slope beyond (X,Y) above +- * currently when programming REGION_END = m_arrPoints[1].x, +- * REGION_END_BASE = m_arrPoints[1].y, REGION_END_SLOPE=1 +- * we don't use m_arrPoints[2] at all after this function, +- * and its purpose isn't clear to me +- */ +- arr_points[1].x = coordinates_x[hw_points_num].adjusted_x; +- arr_points[2].x = coordinates_x[hw_points_num].adjusted_x; +- +- y_r = rgb_resulted[hw_points_num].red; +- y_g = rgb_resulted[hw_points_num].green; +- y_b = rgb_resulted[hw_points_num].blue; +- +- /* see comment above, m_arrPoints[1].y should be the Y value for the +- * region end (m_numOfHwPoints), not last HW point(m_numOfHwPoints - 1) +- */ +- y3_max = dal_fixed31_32_max(y_r, dal_fixed31_32_max(y_g, y_b)); +- +- arr_points[1].y = y3_max; +- arr_points[2].y = y3_max; +- +- arr_points[2].slope = dal_fixed31_32_zero; +- +- /* for PQ, we want to have a straight line from last HW X point, and the +- * slope to be such that we hit 1.0 at 10000 nits. +- */ +- if (tf == TRANSFER_FUNCTION_PQ) { +- const struct fixed31_32 end_value = +- dal_fixed31_32_from_int(125); +- +- arr_points[2].slope = dal_fixed31_32_div( +- dal_fixed31_32_sub(dal_fixed31_32_one, arr_points[1].y), +- dal_fixed31_32_sub(end_value, arr_points[1].x)); +- } +-} +- +-static bool convert_to_custom_float_format( +- struct fixed31_32 value, +- const struct custom_float_format *format, +- uint32_t *result) +-{ +- uint32_t mantissa; +- uint32_t exponenta; +- bool negative; +- +- return build_custom_float( +- value, format, &negative, &mantissa, &exponenta) && +- setup_custom_float( +- format, negative, mantissa, exponenta, result); +-} +- +-static bool convert_to_custom_float( +- struct pwl_result_data *rgb_resulted, +- struct curve_points *arr_points, +- uint32_t hw_points_num) +-{ +- struct custom_float_format fmt; +- +- struct pwl_result_data *rgb = rgb_resulted; +- +- uint32_t i = 0; +- +- fmt.exponenta_bits = 6; +- fmt.mantissa_bits = 12; +- fmt.sign = true; +- +- if (!convert_to_custom_float_format( +- arr_points[0].x, +- &fmt, +- &arr_points[0].custom_float_x)) { +- BREAK_TO_DEBUGGER(); +- return false; +- } +- +- if (!convert_to_custom_float_format( +- arr_points[0].offset, +- &fmt, +- &arr_points[0].custom_float_offset)) { +- BREAK_TO_DEBUGGER(); +- return false; +- } +- +- if (!convert_to_custom_float_format( +- arr_points[0].slope, +- &fmt, +- &arr_points[0].custom_float_slope)) { +- BREAK_TO_DEBUGGER(); +- return false; +- } +- +- fmt.mantissa_bits = 10; +- fmt.sign = false; +- +- if (!convert_to_custom_float_format( +- arr_points[1].x, +- &fmt, +- &arr_points[1].custom_float_x)) { +- BREAK_TO_DEBUGGER(); +- return false; +- } +- +- if (!convert_to_custom_float_format( +- arr_points[1].y, +- &fmt, +- &arr_points[1].custom_float_y)) { +- BREAK_TO_DEBUGGER(); +- return false; +- } +- +- if (!convert_to_custom_float_format( +- arr_points[2].slope, +- &fmt, +- &arr_points[2].custom_float_slope)) { +- BREAK_TO_DEBUGGER(); +- return false; +- } +- +- fmt.mantissa_bits = 12; +- fmt.sign = true; +- +- while (i != hw_points_num) { +- if (!convert_to_custom_float_format( +- rgb->red, +- &fmt, +- &rgb->red_reg)) { +- BREAK_TO_DEBUGGER(); +- return false; +- } +- +- if (!convert_to_custom_float_format( +- rgb->green, +- &fmt, +- &rgb->green_reg)) { +- BREAK_TO_DEBUGGER(); +- return false; +- } +- +- if (!convert_to_custom_float_format( +- rgb->blue, +- &fmt, +- &rgb->blue_reg)) { +- BREAK_TO_DEBUGGER(); +- return false; +- } +- +- if (!convert_to_custom_float_format( +- rgb->delta_red, +- &fmt, +- &rgb->delta_red_reg)) { +- BREAK_TO_DEBUGGER(); +- return false; +- } +- +- if (!convert_to_custom_float_format( +- rgb->delta_green, +- &fmt, +- &rgb->delta_green_reg)) { +- BREAK_TO_DEBUGGER(); +- return false; +- } +- +- if (!convert_to_custom_float_format( +- rgb->delta_blue, +- &fmt, +- &rgb->delta_blue_reg)) { +- BREAK_TO_DEBUGGER(); +- return false; +- } +- +- ++rgb; +- ++i; +- } +- +- return true; +-} +- +-bool calculate_regamma_params(struct pwl_params *params, +- const struct core_gamma *ramp, +- const struct core_surface *surface, +- const struct core_stream *stream) +-{ +- struct gamma_curve *arr_curve_points = params->arr_curve_points; +- struct curve_points *arr_points = params->arr_points; +- struct pwl_result_data *rgb_resulted = params->rgb_resulted; +- struct dividers dividers; +- +- struct hw_x_point *coordinates_x = NULL; +- struct pwl_float_data *rgb_user = NULL ; +- struct pwl_float_data_ex *rgb_regamma = NULL; +- struct pwl_float_data *rgb_oem = NULL; +- struct gamma_pixel *axix_x_256 = NULL; +- struct pixel_gamma_point *coeff128_oem = NULL; +- struct pixel_gamma_point *coeff128 = NULL; +- +- enum dc_transfer_func_predefined tf = TRANSFER_FUNCTION_SRGB; +- +- bool ret = false; +- +- coordinates_x = dm_alloc(sizeof(*coordinates_x)*(256 + 3)); +- if (!coordinates_x) +- goto coordinates_x_alloc_fail; +- rgb_user = dm_alloc(sizeof(*rgb_user) * (TRANSFER_FUNC_POINTS + 3)); +- if (!rgb_user) +- goto rgb_user_alloc_fail; +- rgb_regamma = dm_alloc(sizeof(*rgb_regamma) * (256 + 3)); +- if (!rgb_regamma) +- goto rgb_regamma_alloc_fail; +- rgb_oem = dm_alloc(sizeof(*rgb_oem) * (TRANSFER_FUNC_POINTS + 3)); +- if (!rgb_oem) +- goto rgb_oem_alloc_fail; +- axix_x_256 = dm_alloc(sizeof(*axix_x_256) * (256 + 3)); +- if (!axix_x_256) +- goto axix_x_256_alloc_fail; +- coeff128_oem = dm_alloc(sizeof(*coeff128_oem) * (256 + 3)); +- if (!coeff128_oem) +- goto coeff128_oem_alloc_fail; +- coeff128 = dm_alloc(sizeof(*coeff128) * (256 + 3)); +- if (!coeff128) +- goto coeff128_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); +- +- if (stream->public.out_transfer_func) +- tf = stream->public.out_transfer_func->tf; +- +- build_evenly_distributed_points( +- axix_x_256, +- 256, +- dal_fixed31_32_one, +- dividers); +- +- scale_gamma(rgb_user, ramp, dividers); +- +- if (tf == TRANSFER_FUNCTION_PQ) { +- setup_distribution_points_pq(arr_curve_points, arr_points, +- ¶ms->hw_points_num, coordinates_x, +- surface->public.format); +- build_regamma_curve_pq(rgb_regamma, rgb_oem, coeff128_oem, +- ramp, surface, params->hw_points_num, +- coordinates_x, axix_x_256, dividers); +- } else { +- setup_distribution_points(arr_curve_points, arr_points, +- ¶ms->hw_points_num, coordinates_x); +- build_regamma_curve(rgb_regamma, rgb_oem, coeff128_oem, +- ramp, surface, params->hw_points_num, +- coordinates_x, axix_x_256, dividers); +- } +- +- map_regamma_hw_to_x_user(coeff128, rgb_oem, rgb_resulted, rgb_user, +- coordinates_x, axix_x_256, &ramp->public, rgb_regamma, +- dividers, params->hw_points_num, surface); +- +- build_new_custom_resulted_curve(rgb_resulted, params->hw_points_num); +- +- rebuild_curve_configuration_magic( +- arr_points, +- rgb_resulted, +- coordinates_x, +- params->hw_points_num, +- tf); +- +- convert_to_custom_float(rgb_resulted, arr_points, +- params->hw_points_num); +- +- ret = true; +- +- dm_free(coeff128); +-coeff128_alloc_fail: +- dm_free(coeff128_oem); +-coeff128_oem_alloc_fail: +- dm_free(axix_x_256); +-axix_x_256_alloc_fail: +- dm_free(rgb_oem); +-rgb_oem_alloc_fail: +- dm_free(rgb_regamma); +-rgb_regamma_alloc_fail: +- dm_free(rgb_user); +-rgb_user_alloc_fail: +- dm_free(coordinates_x); +-coordinates_x_alloc_fail: +- return ret; +- +-} +- +diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c +index 7d4299b..948f82a 100644 +--- a/drivers/gpu/drm/amd/display/dc/core/dc.c ++++ b/drivers/gpu/drm/amd/display/dc/core/dc.c +@@ -1519,23 +1519,23 @@ void dc_update_surfaces_for_stream(struct dc *dc, struct dc_surface_update *upda + if (dc->debug.disable_color_module) + continue; /* skip below color updates */ + +- if (updates[i].hdr_static_metadata) { +- resource_build_info_frame(pipe_ctx); +- core_dc->hwss.update_info_frame(pipe_ctx); +- } + if (is_new_pipe_surface[j] || + updates[i].in_transfer_func) + core_dc->hwss.set_input_transfer_func( + pipe_ctx, pipe_ctx->surface); + + if (is_new_pipe_surface[j] || +- updates[i].gamma || + updates[i].out_transfer_func) + core_dc->hwss.set_output_transfer_func( + pipe_ctx, + pipe_ctx->surface, + pipe_ctx->stream); + ++ if (updates[i].hdr_static_metadata) { ++ resource_build_info_frame(pipe_ctx); ++ core_dc->hwss.update_info_frame(pipe_ctx); ++ } ++ + } + if (apply_ctx) { + core_dc->hwss.apply_ctx_for_surface(core_dc, surface, context); +diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h +index b814e7b..f53b413 100644 +--- a/drivers/gpu/drm/amd/display/dc/dc.h ++++ b/drivers/gpu/drm/amd/display/dc/dc.h +@@ -213,11 +213,14 @@ enum dc_transfer_func_type { + }; + + struct dc_transfer_func_distributed_points { +- uint16_t red[TRANSFER_FUNC_POINTS]; +- uint16_t green[TRANSFER_FUNC_POINTS]; +- uint16_t blue[TRANSFER_FUNC_POINTS]; ++ struct fixed31_32 red[TRANSFER_FUNC_POINTS]; ++ struct fixed31_32 green[TRANSFER_FUNC_POINTS]; ++ struct fixed31_32 blue[TRANSFER_FUNC_POINTS]; ++ + uint16_t end_exponent; +- uint16_t x_point_at_y1; ++ uint16_t x_point_at_y1_red; ++ uint16_t x_point_at_y1_green; ++ uint16_t x_point_at_y1_blue; + }; + + enum dc_transfer_func_predefined { +diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c +index 415b12a..6e70cf7 100644 +--- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c ++++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c +@@ -42,7 +42,6 @@ + #include "stream_encoder.h" + #include "link_encoder.h" + #include "clock_source.h" +-#include "gamma_calcs.h" + #include "audio.h" + #include "dce/dce_hwseq.h" + +@@ -286,6 +285,436 @@ static bool dce110_set_input_transfer_func( + return result; + } + ++static bool build_custom_float( ++ struct fixed31_32 value, ++ const struct custom_float_format *format, ++ bool *negative, ++ uint32_t *mantissa, ++ uint32_t *exponenta) ++{ ++ uint32_t exp_offset = (1 << (format->exponenta_bits - 1)) - 1; ++ ++ const struct fixed31_32 mantissa_constant_plus_max_fraction = ++ dal_fixed31_32_from_fraction( ++ (1LL << (format->mantissa_bits + 1)) - 1, ++ 1LL << format->mantissa_bits); ++ ++ struct fixed31_32 mantiss; ++ ++ if (dal_fixed31_32_eq( ++ value, ++ dal_fixed31_32_zero)) { ++ *negative = false; ++ *mantissa = 0; ++ *exponenta = 0; ++ return true; ++ } ++ ++ if (dal_fixed31_32_lt( ++ value, ++ dal_fixed31_32_zero)) { ++ *negative = format->sign; ++ value = dal_fixed31_32_neg(value); ++ } else { ++ *negative = false; ++ } ++ ++ if (dal_fixed31_32_lt( ++ value, ++ dal_fixed31_32_one)) { ++ uint32_t i = 1; ++ ++ do { ++ value = dal_fixed31_32_shl(value, 1); ++ ++i; ++ } while (dal_fixed31_32_lt( ++ value, ++ dal_fixed31_32_one)); ++ ++ --i; ++ ++ if (exp_offset <= i) { ++ *mantissa = 0; ++ *exponenta = 0; ++ return true; ++ } ++ ++ *exponenta = exp_offset - i; ++ } else if (dal_fixed31_32_le( ++ mantissa_constant_plus_max_fraction, ++ value)) { ++ uint32_t i = 1; ++ ++ do { ++ value = dal_fixed31_32_shr(value, 1); ++ ++i; ++ } while (dal_fixed31_32_lt( ++ mantissa_constant_plus_max_fraction, ++ value)); ++ ++ *exponenta = exp_offset + i - 1; ++ } else { ++ *exponenta = exp_offset; ++ } ++ ++ mantiss = dal_fixed31_32_sub( ++ value, ++ dal_fixed31_32_one); ++ ++ if (dal_fixed31_32_lt( ++ mantiss, ++ dal_fixed31_32_zero) || ++ dal_fixed31_32_lt( ++ dal_fixed31_32_one, ++ mantiss)) ++ mantiss = dal_fixed31_32_zero; ++ else ++ mantiss = dal_fixed31_32_shl( ++ mantiss, ++ format->mantissa_bits); ++ ++ *mantissa = dal_fixed31_32_floor(mantiss); ++ ++ return true; ++} ++ ++static bool setup_custom_float( ++ const struct custom_float_format *format, ++ bool negative, ++ uint32_t mantissa, ++ uint32_t exponenta, ++ uint32_t *result) ++{ ++ uint32_t i = 0; ++ uint32_t j = 0; ++ ++ uint32_t value = 0; ++ ++ /* verification code: ++ * once calculation is ok we can remove it ++ */ ++ ++ const uint32_t mantissa_mask = ++ (1 << (format->mantissa_bits + 1)) - 1; ++ ++ const uint32_t exponenta_mask = ++ (1 << (format->exponenta_bits + 1)) - 1; ++ ++ if (mantissa & ~mantissa_mask) { ++ BREAK_TO_DEBUGGER(); ++ mantissa = mantissa_mask; ++ } ++ ++ if (exponenta & ~exponenta_mask) { ++ BREAK_TO_DEBUGGER(); ++ exponenta = exponenta_mask; ++ } ++ ++ /* end of verification code */ ++ ++ while (i < format->mantissa_bits) { ++ uint32_t mask = 1 << i; ++ ++ if (mantissa & mask) ++ value |= mask; ++ ++ ++i; ++ } ++ ++ while (j < format->exponenta_bits) { ++ uint32_t mask = 1 << j; ++ ++ if (exponenta & mask) ++ value |= mask << i; ++ ++ ++j; ++ } ++ ++ if (negative && format->sign) ++ value |= 1 << (i + j); ++ ++ *result = value; ++ ++ return true; ++} ++ ++static bool convert_to_custom_float_format( ++ struct fixed31_32 value, ++ const struct custom_float_format *format, ++ uint32_t *result) ++{ ++ uint32_t mantissa; ++ uint32_t exponenta; ++ bool negative; ++ ++ return build_custom_float( ++ value, format, &negative, &mantissa, &exponenta) && ++ setup_custom_float( ++ format, negative, mantissa, exponenta, result); ++} ++ ++static bool convert_to_custom_float( ++ struct pwl_result_data *rgb_resulted, ++ struct curve_points *arr_points, ++ uint32_t hw_points_num) ++{ ++ struct custom_float_format fmt; ++ ++ struct pwl_result_data *rgb = rgb_resulted; ++ ++ uint32_t i = 0; ++ ++ fmt.exponenta_bits = 6; ++ fmt.mantissa_bits = 12; ++ fmt.sign = true; ++ ++ if (!convert_to_custom_float_format( ++ arr_points[0].x, ++ &fmt, ++ &arr_points[0].custom_float_x)) { ++ BREAK_TO_DEBUGGER(); ++ return false; ++ } ++ ++ if (!convert_to_custom_float_format( ++ arr_points[0].offset, ++ &fmt, ++ &arr_points[0].custom_float_offset)) { ++ BREAK_TO_DEBUGGER(); ++ return false; ++ } ++ ++ if (!convert_to_custom_float_format( ++ arr_points[0].slope, ++ &fmt, ++ &arr_points[0].custom_float_slope)) { ++ BREAK_TO_DEBUGGER(); ++ return false; ++ } ++ ++ fmt.mantissa_bits = 10; ++ fmt.sign = false; ++ ++ if (!convert_to_custom_float_format( ++ arr_points[1].x, ++ &fmt, ++ &arr_points[1].custom_float_x)) { ++ BREAK_TO_DEBUGGER(); ++ return false; ++ } ++ ++ if (!convert_to_custom_float_format( ++ arr_points[1].y, ++ &fmt, ++ &arr_points[1].custom_float_y)) { ++ BREAK_TO_DEBUGGER(); ++ return false; ++ } ++ ++ if (!convert_to_custom_float_format( ++ arr_points[2].slope, ++ &fmt, ++ &arr_points[2].custom_float_slope)) { ++ BREAK_TO_DEBUGGER(); ++ return false; ++ } ++ ++ fmt.mantissa_bits = 12; ++ fmt.sign = true; ++ ++ while (i != hw_points_num) { ++ if (!convert_to_custom_float_format( ++ rgb->red, ++ &fmt, ++ &rgb->red_reg)) { ++ BREAK_TO_DEBUGGER(); ++ return false; ++ } ++ ++ if (!convert_to_custom_float_format( ++ rgb->green, ++ &fmt, ++ &rgb->green_reg)) { ++ BREAK_TO_DEBUGGER(); ++ return false; ++ } ++ ++ if (!convert_to_custom_float_format( ++ rgb->blue, ++ &fmt, ++ &rgb->blue_reg)) { ++ BREAK_TO_DEBUGGER(); ++ return false; ++ } ++ ++ if (!convert_to_custom_float_format( ++ rgb->delta_red, ++ &fmt, ++ &rgb->delta_red_reg)) { ++ BREAK_TO_DEBUGGER(); ++ return false; ++ } ++ ++ if (!convert_to_custom_float_format( ++ rgb->delta_green, ++ &fmt, ++ &rgb->delta_green_reg)) { ++ BREAK_TO_DEBUGGER(); ++ return false; ++ } ++ ++ if (!convert_to_custom_float_format( ++ rgb->delta_blue, ++ &fmt, ++ &rgb->delta_blue_reg)) { ++ BREAK_TO_DEBUGGER(); ++ return false; ++ } ++ ++ ++rgb; ++ ++i; ++ } ++ ++ return true; ++} ++ ++static bool dce110_translate_regamma_to_hw_format(const struct dc_transfer_func ++ *output_tf, struct pwl_params *regamma_params) ++{ ++ if (output_tf == NULL || regamma_params == NULL) ++ return false; ++ ++ struct gamma_curve *arr_curve_points = regamma_params->arr_curve_points; ++ struct curve_points *arr_points = regamma_params->arr_points; ++ struct pwl_result_data *rgb_resulted = regamma_params->rgb_resulted; ++ struct fixed31_32 y_r; ++ struct fixed31_32 y_g; ++ struct fixed31_32 y_b; ++ struct fixed31_32 y1_min; ++ struct fixed31_32 y3_max; ++ ++ int32_t segment_start, segment_end; ++ uint32_t hw_points, start_index; ++ uint32_t i, j; ++ ++ memset(regamma_params, 0, sizeof(struct pwl_params)); ++ ++ if (output_tf->tf == TRANSFER_FUNCTION_PQ) { ++ /* 16 segments x 16 points ++ * segments are from 2^-11 to 2^5 ++ */ ++ segment_start = -11; ++ segment_end = 5; ++ ++ } else { ++ /* 10 segments x 16 points ++ * segment is from 2^-10 to 2^0 ++ */ ++ segment_start = -10; ++ segment_end = 0; ++ } ++ ++ hw_points = (segment_end - segment_start) * 16; ++ j = 0; ++ /* (segment + 25) * 32, every 2nd point */ ++ start_index = (segment_start + 25) * 32; ++ for (i = start_index; i <= 1025; i += 2) { ++ if (j > hw_points) ++ break; ++ rgb_resulted[j].red = output_tf->tf_pts.red[i]; ++ rgb_resulted[j].green = output_tf->tf_pts.green[i]; ++ rgb_resulted[j].blue = output_tf->tf_pts.blue[i]; ++ j++; ++ } ++ ++ arr_points[0].x = dal_fixed31_32_pow(dal_fixed31_32_from_int(2), ++ dal_fixed31_32_from_int(segment_start)); ++ arr_points[1].x = dal_fixed31_32_pow(dal_fixed31_32_from_int(2), ++ dal_fixed31_32_from_int(segment_end)); ++ arr_points[2].x = dal_fixed31_32_pow(dal_fixed31_32_from_int(2), ++ dal_fixed31_32_from_int(segment_end)); ++ ++ y_r = rgb_resulted[0].red; ++ y_g = rgb_resulted[0].green; ++ y_b = rgb_resulted[0].blue; ++ ++ y1_min = dal_fixed31_32_min(y_r, dal_fixed31_32_min(y_g, y_b)); ++ ++ arr_points[0].y = y1_min; ++ arr_points[0].slope = dal_fixed31_32_div( ++ arr_points[0].y, ++ arr_points[0].x); ++ ++ y_r = rgb_resulted[hw_points - 1].red; ++ y_g = rgb_resulted[hw_points - 1].green; ++ y_b = rgb_resulted[hw_points - 1].blue; ++ ++ /* see comment above, m_arrPoints[1].y should be the Y value for the ++ * region end (m_numOfHwPoints), not last HW point(m_numOfHwPoints - 1) ++ */ ++ y3_max = dal_fixed31_32_max(y_r, dal_fixed31_32_max(y_g, y_b)); ++ ++ arr_points[1].y = y3_max; ++ arr_points[2].y = y3_max; ++ ++ arr_points[1].slope = dal_fixed31_32_zero; ++ arr_points[2].slope = dal_fixed31_32_zero; ++ ++ if (output_tf->tf == TRANSFER_FUNCTION_PQ) { ++ /* for PQ, we want to have a straight line from last HW X point, ++ * and the slope to be such that we hit 1.0 at 10000 nits. ++ */ ++ const struct fixed31_32 end_value = ++ dal_fixed31_32_from_int(125); ++ ++ arr_points[1].slope = dal_fixed31_32_div( ++ dal_fixed31_32_sub(dal_fixed31_32_one, arr_points[1].y), ++ dal_fixed31_32_sub(end_value, arr_points[1].x)); ++ arr_points[2].slope = dal_fixed31_32_div( ++ dal_fixed31_32_sub(dal_fixed31_32_one, arr_points[1].y), ++ dal_fixed31_32_sub(end_value, arr_points[1].x)); ++ } ++ ++ regamma_params->hw_points_num = hw_points; ++ ++ for (i = 0; i < segment_end - segment_start; i++) { ++ regamma_params->arr_curve_points[i].offset = i * 16; ++ regamma_params->arr_curve_points[i].segments_num = 4; ++ } ++ ++ struct pwl_result_data *rgb = rgb_resulted; ++ struct pwl_result_data *rgb_plus_1 = rgb_resulted + 1; ++ ++ i = 1; ++ ++ while (i != hw_points + 1) { ++ if (dal_fixed31_32_lt(rgb_plus_1->red, rgb->red)) ++ rgb_plus_1->red = rgb->red; ++ if (dal_fixed31_32_lt(rgb_plus_1->green, rgb->green)) ++ rgb_plus_1->green = rgb->green; ++ if (dal_fixed31_32_lt(rgb_plus_1->blue, rgb->blue)) ++ rgb_plus_1->blue = rgb->blue; ++ ++ rgb->delta_red = dal_fixed31_32_sub( ++ rgb_plus_1->red, ++ rgb->red); ++ rgb->delta_green = dal_fixed31_32_sub( ++ rgb_plus_1->green, ++ rgb->green); ++ rgb->delta_blue = dal_fixed31_32_sub( ++ rgb_plus_1->blue, ++ rgb->blue); ++ ++ ++rgb_plus_1; ++ ++rgb; ++ ++i; ++ } ++ ++ convert_to_custom_float(rgb_resulted, arr_points, hw_points); ++ ++ return true; ++} ++ + static bool dce110_set_output_transfer_func( + struct pipe_ctx *pipe_ctx, + const struct core_surface *surface, /* Surface - To be removed */ +@@ -308,10 +737,13 @@ static bool dce110_set_output_transfer_func( + opp->funcs->opp_power_on_regamma_lut(opp, true); + + if (stream->public.out_transfer_func && +- stream->public.out_transfer_func->type == TF_TYPE_PREDEFINED && +- stream->public.out_transfer_func->tf == TRANSFER_FUNCTION_SRGB) { ++ stream->public.out_transfer_func->type == ++ TF_TYPE_PREDEFINED && ++ stream->public.out_transfer_func->tf == ++ TRANSFER_FUNCTION_SRGB) { + opp->funcs->opp_set_regamma_mode(opp, OPP_REGAMMA_SRGB); +- } else if (ramp && calculate_regamma_params(regamma_params, ramp, surface, stream)) { ++ } else if (dce110_translate_regamma_to_hw_format( ++ stream->public.out_transfer_func, regamma_params)) { + opp->funcs->opp_program_regamma_pwl(opp, regamma_params); + opp->funcs->opp_set_regamma_mode(opp, OPP_REGAMMA_USER); + } else { +diff --git a/drivers/gpu/drm/amd/display/dc/inc/gamma_calcs.h b/drivers/gpu/drm/amd/display/dc/inc/gamma_calcs.h +deleted file mode 100644 +index 0712268..0000000 +--- a/drivers/gpu/drm/amd/display/dc/inc/gamma_calcs.h ++++ /dev/null +@@ -1,20 +0,0 @@ +-/* +- * gamma_calcs.h +- * +- * Created on: Feb 9, 2016 +- * Author: yonsun +- */ +- +-#ifndef DRIVERS_GPU_DRM_AMD_DC_DEV_DC_INC_GAMMA_CALCS_H_ +-#define DRIVERS_GPU_DRM_AMD_DC_DEV_DC_INC_GAMMA_CALCS_H_ +- +-#include "opp.h" +-#include "core_types.h" +-#include "dc.h" +- +-bool calculate_regamma_params(struct pwl_params *params, +- const struct core_gamma *ramp, +- const struct core_surface *surface, +- const struct core_stream *stream); +- +-#endif /* DRIVERS_GPU_DRM_AMD_DC_DEV_DC_INC_GAMMA_CALCS_H_ */ +diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/opp.h b/drivers/gpu/drm/amd/display/dc/inc/hw/opp.h +index a1f31a4..bef5e2c 100644 +--- a/drivers/gpu/drm/amd/display/dc/inc/hw/opp.h ++++ b/drivers/gpu/drm/amd/display/dc/inc/hw/opp.h +@@ -138,9 +138,7 @@ struct custom_float_value { + + struct hw_x_point { + uint32_t custom_float_x; +- uint32_t custom_float_x_adjusted; + struct fixed31_32 x; +- struct fixed31_32 adjusted_x; + struct fixed31_32 regamma_y_red; + struct fixed31_32 regamma_y_green; + struct fixed31_32 regamma_y_blue; +diff --git a/drivers/gpu/drm/amd/display/include/fixed31_32.h b/drivers/gpu/drm/amd/display/include/fixed31_32.h +index c28de16..5a4364d 100644 +--- a/drivers/gpu/drm/amd/display/include/fixed31_32.h ++++ b/drivers/gpu/drm/amd/display/include/fixed31_32.h +@@ -192,6 +192,14 @@ struct fixed31_32 dal_fixed31_32_add( + + /* + * @brief ++ * result = arg1 + arg2 ++ */ ++struct fixed31_32 dal_fixed31_32_add_int( ++ struct fixed31_32 arg1, ++ int32_t arg2); ++ ++/* ++ * @brief + * result = arg1 - arg2 + */ + struct fixed31_32 dal_fixed31_32_sub_int( +-- +2.7.4 + |