aboutsummaryrefslogtreecommitdiffstats
path: root/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.14.71/3558-drm-amd-display-Add-color-module-s-gamma-helpers-to-.patch
diff options
context:
space:
mode:
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-.patch1206
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
+