diff options
Diffstat (limited to 'meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.14.71/3558-drm-amd-display-Add-color-module-s-gamma-helpers-to-.patch')
-rw-r--r-- | meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.14.71/3558-drm-amd-display-Add-color-module-s-gamma-helpers-to-.patch | 1206 |
1 files changed, 1206 insertions, 0 deletions
diff --git a/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.14.71/3558-drm-amd-display-Add-color-module-s-gamma-helpers-to-.patch b/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.14.71/3558-drm-amd-display-Add-color-module-s-gamma-helpers-to-.patch new file mode 100644 index 00000000..a0317c10 --- /dev/null +++ b/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.14.71/3558-drm-amd-display-Add-color-module-s-gamma-helpers-to-.patch @@ -0,0 +1,1206 @@ +From 5e27c53b5a2275f9b9d728f09920514b288fc271 Mon Sep 17 00:00:00 2001 +From: "Leo (Sunpeng) Li" <sunpeng.li@amd.com> +Date: Mon, 5 Feb 2018 14:29:57 -0500 +Subject: [PATCH 3558/4131] drm/amd/display: Add color module's gamma helpers + to Linux build + +Also guard includes that we don't need. + +Signed-off-by: Leo (Sunpeng) Li <sunpeng.li@amd.com> +Reviewed-by: Harry Wentland <Harry.Wentland@amd.com> +Signed-off-by: Alex Deucher <alexander.deucher@amd.com> +--- + drivers/gpu/drm/amd/display/Makefile | 3 +- + drivers/gpu/drm/amd/display/modules/color/Makefile | 31 + + .../drm/amd/display/modules/color/color_gamma.c | 1070 ++++++++++++++++++++ + .../drm/amd/display/modules/color/color_gamma.h | 45 + + 4 files changed, 1148 insertions(+), 1 deletion(-) + create mode 100644 drivers/gpu/drm/amd/display/modules/color/Makefile + create mode 100644 drivers/gpu/drm/amd/display/modules/color/color_gamma.c + create mode 100644 drivers/gpu/drm/amd/display/modules/color/color_gamma.h + +diff --git a/drivers/gpu/drm/amd/display/Makefile b/drivers/gpu/drm/amd/display/Makefile +index 8ba37dd..c348feb 100644 +--- a/drivers/gpu/drm/amd/display/Makefile ++++ b/drivers/gpu/drm/amd/display/Makefile +@@ -11,11 +11,12 @@ subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/dc/inc/ + subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/dc/inc/hw + subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/modules/inc + subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/modules/freesync ++subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/modules/color + + #TODO: remove when Timing Sync feature is complete + subdir-ccflags-y += -DBUILD_FEATURE_TIMING_SYNC=0 + +-DAL_LIBS = amdgpu_dm dc modules/freesync ++DAL_LIBS = amdgpu_dm dc modules/freesync modules/color + + AMD_DAL = $(addsuffix /Makefile, $(addprefix $(FULL_AMD_DISPLAY_PATH)/,$(DAL_LIBS))) + +diff --git a/drivers/gpu/drm/amd/display/modules/color/Makefile b/drivers/gpu/drm/amd/display/modules/color/Makefile +new file mode 100644 +index 0000000..65c33a7 +--- /dev/null ++++ b/drivers/gpu/drm/amd/display/modules/color/Makefile +@@ -0,0 +1,31 @@ ++# ++# Copyright 2018 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. ++# ++# ++# Makefile for the color sub-module of DAL. ++# ++ ++MOD_COLOR = color_gamma.o ++ ++AMD_DAL_MOD_COLOR = $(addprefix $(AMDDALPATH)/modules/color/,$(MOD_COLOR)) ++#$(info ************ DAL COLOR MODULE MAKEFILE ************) ++ ++AMD_DISPLAY_FILES += $(AMD_DAL_MOD_COLOR) +diff --git a/drivers/gpu/drm/amd/display/modules/color/color_gamma.c b/drivers/gpu/drm/amd/display/modules/color/color_gamma.c +new file mode 100644 +index 0000000..fde3ae8 +--- /dev/null ++++ b/drivers/gpu/drm/amd/display/modules/color/color_gamma.c +@@ -0,0 +1,1070 @@ ++/* ++ * Copyright 2016 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 "dc.h" ++#include "opp.h" ++#include "color_gamma.h" ++ ++/* MAX_HW_POINTS = NUM_REGIONS * NUM_PTS_IN_REGION */ ++#define NUM_PTS_IN_REGION 16 ++#define NUM_REGIONS 32 ++#define MAX_HW_POINTS 512 ++ ++static struct hw_x_point coordinates_x[MAX_HW_POINTS + 2]; ++static struct fixed31_32 pq_table[MAX_HW_POINTS + 2]; ++static bool pq_initialized; /* = false; */ ++ ++/* one-time setup of X points */ ++void setup_x_points_distribution(void) ++{ ++ struct fixed31_32 region_size = dal_fixed31_32_from_int(128); ++ int32_t segment; ++ uint32_t seg_offset; ++ uint32_t index; ++ struct fixed31_32 increment; ++ ++ coordinates_x[NUM_REGIONS * NUM_PTS_IN_REGION].x = region_size; ++ coordinates_x[NUM_REGIONS * NUM_PTS_IN_REGION + 1].x = region_size; ++ ++ for (segment = 6; segment > (6 - NUM_REGIONS); segment--) { ++ region_size = dal_fixed31_32_div_int(region_size, 2); ++ increment = dal_fixed31_32_div_int(region_size, ++ NUM_PTS_IN_REGION); ++ seg_offset = (segment + (NUM_REGIONS - 7)) * NUM_PTS_IN_REGION; ++ coordinates_x[seg_offset].x = region_size; ++ ++ for (index = seg_offset + 1; ++ index < seg_offset + NUM_PTS_IN_REGION; ++ index++) { ++ coordinates_x[index].x = dal_fixed31_32_add ++ (coordinates_x[index-1].x, increment); ++ } ++ } ++} ++ ++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); ++} ++ ++/* one-time pre-compute PQ values - only for sdr_white_level 80 */ ++void precompute_pq(void) ++{ ++ int i; ++ struct fixed31_32 x; ++ const struct hw_x_point *coord_x = coordinates_x + 32; ++ struct fixed31_32 scaling_factor = ++ dal_fixed31_32_from_fraction(80, 10000); ++ ++ /* pow function has problems with arguments too small */ ++ for (i = 0; i < 32; i++) ++ pq_table[i] = dal_fixed31_32_zero; ++ ++ for (i = 32; i <= MAX_HW_POINTS; i++) { ++ x = dal_fixed31_32_mul(coord_x->x, scaling_factor); ++ compute_pq(x, &pq_table[i]); ++ ++coord_x; ++ } ++} ++ ++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_lt(one, arg)) ++ return one; ++ ++ 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 dc_gamma *ramp, ++ const struct gamma_pixel *axis_x, ++ 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 = ramp->num_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[i].r; ++ ++ if (i < max_number - 1) ++ right = axis_x[i + 1].r; ++ else ++ right = axis_x[max_number - 1].r; ++ } else if (channel == CHANNEL_NAME_GREEN) { ++ left = axis_x[i].g; ++ ++ if (i < max_number - 1) ++ right = axis_x[i + 1].g; ++ else ++ right = axis_x[max_number - 1].g; ++ } else { ++ left = axis_x[i].b; ++ ++ if (i < max_number - 1) ++ right = axis_x[i + 1].b; ++ else ++ right = axis_x[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( ++ const struct dc_gamma *ramp, ++ struct pixel_gamma_point *coeff, ++ const struct hw_x_point *coordinates_x, ++ const struct gamma_pixel *axis_x, ++ enum channel_name channel, ++ uint32_t number_of_points) ++{ ++ 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( ++ ramp, axis_x, coord_x, channel, ++ &index_to_start, &index_left, &index_right, &hw_pos)) { ++ BREAK_TO_DEBUGGER(); ++ return false; ++ } ++ ++ if (index_left >= ramp->num_entries + 3) { ++ BREAK_TO_DEBUGGER(); ++ return false; ++ } ++ ++ if (index_right >= ramp->num_entries + 3) { ++ BREAK_TO_DEBUGGER(); ++ return false; ++ } ++ ++ if (channel == CHANNEL_NAME_RED) { ++ point = &coeff[i].r; ++ ++ left_pos = axis_x[index_left].r; ++ right_pos = axis_x[index_right].r; ++ } else if (channel == CHANNEL_NAME_GREEN) { ++ point = &coeff[i].g; ++ ++ left_pos = axis_x[index_left].g; ++ right_pos = axis_x[index_right].g; ++ } else { ++ point = &coeff[i].b; ++ ++ left_pos = axis_x[index_left].b; ++ right_pos = axis_x[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 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 void build_regamma_curve_pq(struct pwl_float_data_ex *rgb_regamma, ++ uint32_t hw_points_num, ++ const struct hw_x_point *coordinate_x, ++ uint32_t sdr_white_level) ++{ ++ uint32_t i, start_index; ++ ++ 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(sdr_white_level, 10000); ++ ++ if (!pq_initialized && sdr_white_level == 80) { ++ precompute_pq(); ++ pq_initialized = true; ++ } ++ ++ /* TODO: start index is from segment 2^-24, skipping first segment ++ * due to x values too small for power calculations ++ */ ++ start_index = 32; ++ rgb += start_index; ++ coord_x += start_index; ++ ++ /* 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 = start_index; i <= hw_points_num; i++) { ++ /* Multiply 0.008 as regamma is 0-1 and FP16 input is 0-125. ++ * FP 1.0 = 80nits ++ */ ++ if (sdr_white_level == 80) { ++ output = pq_table[i]; ++ } else { ++ x = dal_fixed31_32_mul(coord_x->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, ++ uint32_t hw_points_num, ++ const struct hw_x_point *coordinate_x) ++{ ++ 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->x, &coeff, 0); ++ rgb->g = translate_from_linear_space_ex( ++ coord_x->x, &coeff, 1); ++ rgb->b = translate_from_linear_space_ex( ++ coord_x->x, &coeff, 2); ++ ++ ++coord_x; ++ ++rgb; ++ ++i; ++ } ++} ++ ++static bool scale_gamma(struct pwl_float_data *pwl_rgb, ++ const struct dc_gamma *ramp, ++ struct dividers dividers) ++{ ++ const struct fixed31_32 max_driver = dal_fixed31_32_from_int(0xFFFF); ++ const struct fixed31_32 max_os = dal_fixed31_32_from_int(0xFF00); ++ struct fixed31_32 scaler = max_os; ++ uint32_t i; ++ struct pwl_float_data *rgb = pwl_rgb; ++ struct pwl_float_data *rgb_last = rgb + ramp->num_entries - 1; ++ ++ i = 0; ++ ++ do { ++ if (dal_fixed31_32_lt(max_os, ramp->entries.red[i]) || ++ dal_fixed31_32_lt(max_os, ramp->entries.green[i]) || ++ dal_fixed31_32_lt(max_os, ramp->entries.blue[i])) { ++ scaler = max_driver; ++ break; ++ } ++ ++i; ++ } while (i != ramp->num_entries); ++ ++ i = 0; ++ ++ do { ++ rgb->r = dal_fixed31_32_div( ++ ramp->entries.red[i], scaler); ++ rgb->g = dal_fixed31_32_div( ++ ramp->entries.green[i], scaler); ++ rgb->b = dal_fixed31_32_div( ++ ramp->entries.blue[i], scaler); ++ ++ ++rgb; ++ ++i; ++ } while (i != ramp->num_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 bool scale_gamma_dx(struct pwl_float_data *pwl_rgb, ++ const struct dc_gamma *ramp, ++ struct dividers dividers) ++{ ++ uint32_t i; ++ struct fixed31_32 min = dal_fixed31_32_zero; ++ struct fixed31_32 max = dal_fixed31_32_one; ++ ++ struct fixed31_32 delta = dal_fixed31_32_zero; ++ struct fixed31_32 offset = dal_fixed31_32_zero; ++ ++ for (i = 0 ; i < ramp->num_entries; i++) { ++ if (dal_fixed31_32_lt(ramp->entries.red[i], min)) ++ min = ramp->entries.red[i]; ++ ++ if (dal_fixed31_32_lt(ramp->entries.green[i], min)) ++ min = ramp->entries.green[i]; ++ ++ if (dal_fixed31_32_lt(ramp->entries.blue[i], min)) ++ min = ramp->entries.blue[i]; ++ ++ if (dal_fixed31_32_lt(max, ramp->entries.red[i])) ++ max = ramp->entries.red[i]; ++ ++ if (dal_fixed31_32_lt(max, ramp->entries.green[i])) ++ max = ramp->entries.green[i]; ++ ++ if (dal_fixed31_32_lt(max, ramp->entries.blue[i])) ++ max = ramp->entries.blue[i]; ++ } ++ ++ if (dal_fixed31_32_lt(min, dal_fixed31_32_zero)) ++ delta = dal_fixed31_32_neg(min); ++ ++ offset = dal_fixed31_32_add(min, max); ++ ++ for (i = 0 ; i < ramp->num_entries; i++) { ++ pwl_rgb[i].r = dal_fixed31_32_div( ++ dal_fixed31_32_add( ++ ramp->entries.red[i], delta), offset); ++ pwl_rgb[i].g = dal_fixed31_32_div( ++ dal_fixed31_32_add( ++ ramp->entries.green[i], delta), offset); ++ pwl_rgb[i].b = dal_fixed31_32_div( ++ dal_fixed31_32_add( ++ ramp->entries.blue[i], delta), offset); ++ ++ } ++ ++ pwl_rgb[i].r = dal_fixed31_32_sub(dal_fixed31_32_mul_int( ++ pwl_rgb[i-1].r, 2), pwl_rgb[i-2].r); ++ pwl_rgb[i].g = dal_fixed31_32_sub(dal_fixed31_32_mul_int( ++ 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); ++ ++i; ++ pwl_rgb[i].r = dal_fixed31_32_sub(dal_fixed31_32_mul_int( ++ pwl_rgb[i-1].r, 2), pwl_rgb[i-2].r); ++ pwl_rgb[i].g = dal_fixed31_32_sub(dal_fixed31_32_mul_int( ++ 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; ++} ++ ++/* ++ * RS3+ color transform DDI - 1D LUT adjustment is composed with regamma here ++ * Input is evenly distributed in the output color space as specified in ++ * SetTimings ++ * ++ * Interpolation details: ++ * 1D LUT has 4096 values which give curve correction in 0-1 float range ++ * for evenly spaced points in 0-1 range. lut1D[index] gives correction ++ * for index/4095. ++ * First we find index for which: ++ * index/4095 < regamma_y < (index+1)/4095 => ++ * index < 4095*regamma_y < index + 1 ++ * norm_y = 4095*regamma_y, and index is just truncating to nearest integer ++ * lut1 = lut1D[index], lut2 = lut1D[index+1] ++ * ++ *adjustedY is then linearly interpolating regamma Y between lut1 and lut2 ++ */ ++static void apply_lut_1d( ++ const struct dc_gamma *ramp, ++ uint32_t num_hw_points, ++ struct dc_transfer_func_distributed_points *tf_pts) ++{ ++ int i = 0; ++ int color = 0; ++ struct fixed31_32 *regamma_y; ++ struct fixed31_32 norm_y; ++ struct fixed31_32 lut1; ++ struct fixed31_32 lut2; ++ const int max_lut_index = 4095; ++ const struct fixed31_32 max_lut_index_f = ++ dal_fixed31_32_from_int_nonconst(max_lut_index); ++ int32_t index = 0, index_next = 0; ++ struct fixed31_32 index_f; ++ struct fixed31_32 delta_lut; ++ struct fixed31_32 delta_index; ++ ++ if (ramp->type != GAMMA_CS_TFM_1D) ++ return; // this is not expected ++ ++ for (i = 0; i < num_hw_points; i++) { ++ for (color = 0; color < 3; color++) { ++ if (color == 0) ++ regamma_y = &tf_pts->red[i]; ++ else if (color == 1) ++ regamma_y = &tf_pts->green[i]; ++ else ++ regamma_y = &tf_pts->blue[i]; ++ ++ norm_y = dal_fixed31_32_mul(max_lut_index_f, ++ *regamma_y); ++ index = dal_fixed31_32_floor(norm_y); ++ index_f = dal_fixed31_32_from_int_nonconst(index); ++ ++ if (index < 0 || index > max_lut_index) ++ continue; ++ ++ index_next = (index == max_lut_index) ? index : index+1; ++ ++ if (color == 0) { ++ lut1 = ramp->entries.red[index]; ++ lut2 = ramp->entries.red[index_next]; ++ } else if (color == 1) { ++ lut1 = ramp->entries.green[index]; ++ lut2 = ramp->entries.green[index_next]; ++ } else { ++ lut1 = ramp->entries.blue[index]; ++ lut2 = ramp->entries.blue[index_next]; ++ } ++ ++ // we have everything now, so interpolate ++ delta_lut = dal_fixed31_32_sub(lut2, lut1); ++ delta_index = dal_fixed31_32_sub(norm_y, index_f); ++ ++ *regamma_y = dal_fixed31_32_add(lut1, ++ dal_fixed31_32_mul(delta_index, delta_lut)); ++ } ++ } ++} ++ ++static void build_evenly_distributed_points( ++ struct gamma_pixel *points, ++ uint32_t numberof_points, ++ 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_from_fraction(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( ++ const struct dc_gamma *ramp, ++ struct pixel_gamma_point *coeff128, ++ struct pwl_float_data *rgb_user, ++ const struct hw_x_point *coordinates_x, ++ const struct gamma_pixel *axis_x, ++ uint32_t number_of_points, ++ struct dc_transfer_func_distributed_points *tf_pts) ++{ ++ ++ const struct pixel_gamma_point *coeff = coeff128; ++ uint32_t max_entries = 3 - 1; ++ ++ uint32_t i = 0; ++ ++ for (i = 0; i < 3; i++) { ++ if (!build_custom_gamma_mapping_coefficients_worker( ++ ramp, coeff128, coordinates_x, axis_x, i, ++ number_of_points)) ++ return false; ++ } ++ ++ i = 0; ++ max_entries += ramp->num_entries; ++ ++ /* TODO: float point case */ ++ ++ while (i <= number_of_points) { ++ tf_pts->red[i] = calculate_mapped_value( ++ rgb_user, coeff, CHANNEL_NAME_RED, max_entries); ++ tf_pts->green[i] = calculate_mapped_value( ++ rgb_user, coeff, CHANNEL_NAME_GREEN, max_entries); ++ tf_pts->blue[i] = calculate_mapped_value( ++ rgb_user, coeff, CHANNEL_NAME_BLUE, max_entries); ++ ++ ++coeff; ++ ++i; ++ } ++ ++ return true; ++} ++ ++static void build_new_custom_resulted_curve( ++ uint32_t hw_points_num, ++ struct dc_transfer_func_distributed_points *tf_pts) ++{ ++ uint32_t i; ++ ++ i = 0; ++ ++ while (i != hw_points_num + 1) { ++ tf_pts->red[i] = dal_fixed31_32_clamp( ++ tf_pts->red[i], dal_fixed31_32_zero, ++ dal_fixed31_32_one); ++ tf_pts->green[i] = dal_fixed31_32_clamp( ++ tf_pts->green[i], dal_fixed31_32_zero, ++ dal_fixed31_32_one); ++ tf_pts->blue[i] = dal_fixed31_32_clamp( ++ tf_pts->blue[i], dal_fixed31_32_zero, ++ dal_fixed31_32_one); ++ ++ ++i; ++ } ++} ++ ++static bool map_regamma_hw_to_x_user( ++ const struct dc_gamma *ramp, ++ struct pixel_gamma_point *coeff128, ++ struct pwl_float_data *rgb_user, ++ struct hw_x_point *coords_x, ++ const struct gamma_pixel *axis_x, ++ const struct pwl_float_data_ex *rgb_regamma, ++ uint32_t hw_points_num, ++ struct dc_transfer_func_distributed_points *tf_pts, ++ bool mapUserRamp) ++{ ++ /* setup to spare calculated ideal regamma values */ ++ ++ int i = 0; ++ struct hw_x_point *coords = coords_x; ++ const struct pwl_float_data_ex *regamma = rgb_regamma; ++ ++ if (mapUserRamp) { ++ copy_rgb_regamma_to_coordinates_x(coords, ++ hw_points_num, ++ rgb_regamma); ++ ++ calculate_interpolated_hardware_curve( ++ ramp, coeff128, rgb_user, coords, axis_x, ++ hw_points_num, tf_pts); ++ } else { ++ /* just copy current rgb_regamma into tf_pts */ ++ while (i <= hw_points_num) { ++ tf_pts->red[i] = regamma->r; ++ tf_pts->green[i] = regamma->g; ++ tf_pts->blue[i] = regamma->b; ++ ++ ++regamma; ++ ++i; ++ } ++ } ++ ++ build_new_custom_resulted_curve(hw_points_num, tf_pts); ++ ++ return true; ++} ++ ++bool mod_color_calculate_regamma_params(struct dc_transfer_func *output_tf, ++ const struct dc_gamma *ramp, bool mapUserRamp) ++{ ++ 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; ++ struct gamma_pixel *axix_x = NULL; ++ struct pixel_gamma_point *coeff128 = NULL; ++ enum dc_transfer_func_predefined tf = TRANSFER_FUNCTION_SRGB; ++ bool ret = false; ++ ++ if (output_tf->type == TF_TYPE_BYPASS) ++ return false; ++ ++ /* we can use hardcoded curve for plain SRGB TF */ ++ if (output_tf->type == TF_TYPE_PREDEFINED && ++ output_tf->tf == TRANSFER_FUNCTION_SRGB && ++ (!mapUserRamp && ramp->type == GAMMA_RGB_256)) ++ return true; ++ ++ output_tf->type = TF_TYPE_DISTRIBUTED_POINTS; ++ ++ rgb_user = kzalloc(sizeof(*rgb_user) * (ramp->num_entries + 3), ++ GFP_KERNEL); ++ if (!rgb_user) ++ goto rgb_user_alloc_fail; ++ rgb_regamma = kzalloc(sizeof(*rgb_regamma) * (MAX_HW_POINTS + 3), ++ GFP_KERNEL); ++ if (!rgb_regamma) ++ goto rgb_regamma_alloc_fail; ++ axix_x = kzalloc(sizeof(*axix_x) * (ramp->num_entries + 3), ++ GFP_KERNEL); ++ if (!axix_x) ++ goto axix_x_alloc_fail; ++ coeff128 = kzalloc(sizeof(*coeff128) * (MAX_HW_POINTS + 3), GFP_KERNEL); ++ 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); ++ ++ tf = output_tf->tf; ++ ++ build_evenly_distributed_points( ++ axix_x, ++ ramp->num_entries, ++ dividers); ++ ++ if (ramp->type == GAMMA_RGB_256 && mapUserRamp) ++ scale_gamma(rgb_user, ramp, dividers); ++ else if (ramp->type == GAMMA_RGB_FLOAT_1024) ++ scale_gamma_dx(rgb_user, ramp, dividers); ++ ++ if (tf == TRANSFER_FUNCTION_PQ) { ++ tf_pts->end_exponent = 7; ++ tf_pts->x_point_at_y1_red = 125; ++ tf_pts->x_point_at_y1_green = 125; ++ tf_pts->x_point_at_y1_blue = 125; ++ ++ build_regamma_curve_pq(rgb_regamma, ++ MAX_HW_POINTS, ++ coordinates_x, ++ output_tf->sdr_ref_white_level); ++ } else { ++ 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; ++ ++ build_regamma_curve(rgb_regamma, ++ MAX_HW_POINTS, ++ coordinates_x); ++ } ++ ++ map_regamma_hw_to_x_user(ramp, coeff128, rgb_user, ++ coordinates_x, axix_x, rgb_regamma, ++ MAX_HW_POINTS, tf_pts, ++ (mapUserRamp || ramp->type != GAMMA_RGB_256) && ++ ramp->type != GAMMA_CS_TFM_1D); ++ ++ if (ramp->type == GAMMA_CS_TFM_1D) ++ apply_lut_1d(ramp, MAX_HW_POINTS, tf_pts); ++ ++ ret = true; ++ ++ kfree(coeff128); ++coeff128_alloc_fail: ++ kfree(axix_x); ++axix_x_alloc_fail: ++ kfree(rgb_regamma); ++rgb_regamma_alloc_fail: ++ kfree(rgb_user); ++rgb_user_alloc_fail: ++ return ret; ++} ++ ++ ++/*TODO fix me should be 2*/ ++#define _EXTRA_POINTS 3 ++ ++bool mod_color_calculate_curve(enum dc_transfer_func_predefined trans, ++ struct dc_transfer_func_distributed_points *points) ++{ ++ uint32_t i; ++ bool ret = false; ++ struct pwl_float_data_ex *rgb_regamma = NULL; ++ ++ if (trans == TRANSFER_FUNCTION_UNITY) { ++ //setup_x_points_distribution(coordinates_x); ++ for (i = 0; i < MAX_HW_POINTS ; i++) { ++ points->red[i] = coordinates_x[i].x; ++ points->green[i] = coordinates_x[i].x; ++ points->blue[i] = coordinates_x[i].x; ++ } ++ ret = true; ++ } else if (trans == TRANSFER_FUNCTION_PQ) { ++ rgb_regamma = kzalloc(sizeof(*rgb_regamma) * (MAX_HW_POINTS + ++ _EXTRA_POINTS), GFP_KERNEL); ++ if (!rgb_regamma) ++ goto rgb_regamma_alloc_fail; ++ //setup_x_points_distribution(coordinates_x); ++ points->end_exponent = 0; ++ points->x_point_at_y1_red = 1; ++ points->x_point_at_y1_green = 1; ++ points->x_point_at_y1_blue = 1; ++ ++ build_regamma_curve_pq(rgb_regamma, ++ MAX_HW_POINTS, ++ coordinates_x, ++ 80); ++ for (i = 0; i < MAX_HW_POINTS ; i++) { ++ points->red[i] = rgb_regamma[i].r; ++ points->green[i] = rgb_regamma[i].g; ++ points->blue[i] = rgb_regamma[i].b; ++ } ++ ret = true; ++ ++ kfree(rgb_regamma); ++ } ++rgb_regamma_alloc_fail: ++ return ret; ++} ++ ++ +diff --git a/drivers/gpu/drm/amd/display/modules/color/color_gamma.h b/drivers/gpu/drm/amd/display/modules/color/color_gamma.h +new file mode 100644 +index 0000000..774c6da +--- /dev/null ++++ b/drivers/gpu/drm/amd/display/modules/color/color_gamma.h +@@ -0,0 +1,45 @@ ++/* ++ * Copyright 2016 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 ++ * ++ */ ++ ++#ifndef COLOR_MOD_COLOR_GAMMA_H_ ++#define COLOR_MOD_COLOR_GAMMA_H_ ++ ++struct dc_transfer_func; ++struct dc_gamma; ++struct dc_transfer_func_distributed_points; ++struct dc_rgb_fixed; ++enum dc_transfer_func_predefined; ++ ++void setup_x_points_distribution(void); ++void precompute_pq(void); ++ ++bool mod_color_calculate_regamma_params(struct dc_transfer_func *output_tf, ++ const struct dc_gamma *ramp, bool mapUserRamp); ++ ++bool mod_color_calculate_curve(enum dc_transfer_func_predefined trans, ++ struct dc_transfer_func_distributed_points *points); ++ ++ ++#endif /* COLOR_MOD_COLOR_GAMMA_H_ */ +-- +2.7.4 + |