Adds programming for color space conversion (CSC),
regamma, and formatter.

Signed-off-by: Harry Wentland <harry.wentland at amd.com>
Reviewed-by: Alex Deucher <alexander.deucher at amd.com>
---
 drivers/gpu/drm/amd/dal/dc/dce110/dce110_opp.c     |  272 +++
 drivers/gpu/drm/amd/dal/dc/dce110/dce110_opp.h     |  143 ++
 drivers/gpu/drm/amd/dal/dc/dce110/dce110_opp_csc.c |  904 +++++++
 .../drm/amd/dal/dc/dce110/dce110_opp_formatter.c   |  610 +++++
 .../gpu/drm/amd/dal/dc/dce110/dce110_opp_regamma.c | 2474 ++++++++++++++++++++
 5 files changed, 4403 insertions(+)
 create mode 100644 drivers/gpu/drm/amd/dal/dc/dce110/dce110_opp.c
 create mode 100644 drivers/gpu/drm/amd/dal/dc/dce110/dce110_opp.h
 create mode 100644 drivers/gpu/drm/amd/dal/dc/dce110/dce110_opp_csc.c
 create mode 100644 drivers/gpu/drm/amd/dal/dc/dce110/dce110_opp_formatter.c
 create mode 100644 drivers/gpu/drm/amd/dal/dc/dce110/dce110_opp_regamma.c

diff --git a/drivers/gpu/drm/amd/dal/dc/dce110/dce110_opp.c 
b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_opp.c
new file mode 100644
index 000000000000..acb405e7b2e7
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_opp.c
@@ -0,0 +1,272 @@
+/*
+ * Copyright 2012-15 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 DCE11 register header files */
+#include "dce/dce_11_0_d.h"
+#include "dce/dce_11_0_sh_mask.h"
+
+#include "dce110_opp.h"
+
+#include "gamma_types.h"
+
+enum {
+       MAX_LUT_ENTRY = 256,
+       MAX_NUMBER_OF_ENTRIES = 256
+};
+
+static void build_evenly_distributed_points(
+       struct gamma_pixel *points,
+       uint32_t numberof_points,
+       struct fixed31_32 max_value,
+       struct fixed31_32 divider1,
+       struct fixed31_32 divider2,
+       struct fixed31_32 divider3)
+{
+       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, divider1);
+       p->g = dal_fixed31_32_div(p_last->g, divider1);
+       p->b = dal_fixed31_32_div(p_last->b, divider1);
+
+       ++p;
+
+       p->r = dal_fixed31_32_div(p_last->r, divider2);
+       p->g = dal_fixed31_32_div(p_last->g, divider2);
+       p->b = dal_fixed31_32_div(p_last->b, divider2);
+
+       ++p;
+
+       p->r = dal_fixed31_32_div(p_last->r, divider3);
+       p->g = dal_fixed31_32_div(p_last->g, divider3);
+       p->b = dal_fixed31_32_div(p_last->b, divider3);
+}
+
+/*****************************************/
+/* Constructor, Destructor               */
+/*****************************************/
+
+struct opp_funcs funcs = {
+               .opp_map_legacy_and_regamma_hw_to_x_user = 
dce110_opp_map_legacy_and_regamma_hw_to_x_user,
+               .opp_power_on_regamma_lut = dce110_opp_power_on_regamma_lut,
+               .opp_program_bit_depth_reduction = 
dce110_opp_program_bit_depth_reduction,
+               .opp_program_clamping_and_pixel_encoding = 
dce110_opp_program_clamping_and_pixel_encoding,
+               .opp_set_csc_adjustment = dce110_opp_set_csc_adjustment,
+               .opp_set_csc_default = dce110_opp_set_csc_default,
+               .opp_set_dyn_expansion = dce110_opp_set_dyn_expansion,
+               .opp_set_regamma = dce110_opp_set_regamma
+};
+
+bool dce110_opp_construct(struct dce110_opp *opp110,
+       struct dc_context *ctx,
+       uint32_t inst,
+       const struct dce110_opp_reg_offsets *offsets)
+{
+
+       opp110->base.funcs = &funcs;
+
+       opp110->base.ctx = ctx;
+
+       opp110->base.inst = inst;
+
+       opp110->offsets = *offsets;
+
+       opp110->regamma.hw_points_num = 128;
+       opp110->regamma.coordinates_x = NULL;
+       opp110->regamma.rgb_resulted = NULL;
+       opp110->regamma.rgb_regamma = NULL;
+       opp110->regamma.coeff128 = NULL;
+       opp110->regamma.coeff128_oem = NULL;
+       opp110->regamma.coeff128_dx = NULL;
+       opp110->regamma.axis_x_256 = NULL;
+       opp110->regamma.axis_x_1025 = NULL;
+       opp110->regamma.rgb_oem = NULL;
+       opp110->regamma.rgb_user = NULL;
+       opp110->regamma.extra_points = 3;
+       opp110->regamma.use_half_points = false;
+       opp110->regamma.x_max1 = dal_fixed31_32_one;
+       opp110->regamma.x_max2 = dal_fixed31_32_from_int(2);
+       opp110->regamma.x_min = dal_fixed31_32_zero;
+       opp110->regamma.divider1 = dal_fixed31_32_from_fraction(3, 2);
+       opp110->regamma.divider2 = dal_fixed31_32_from_int(2);
+       opp110->regamma.divider3 = dal_fixed31_32_from_fraction(5, 2);
+
+       opp110->regamma.rgb_user = dm_alloc(
+               ctx,
+               sizeof(struct pwl_float_data) *
+               (DX_GAMMA_RAMP_MAX + opp110->regamma.extra_points));
+       if (!opp110->regamma.rgb_user)
+               goto failure_1;
+
+       opp110->regamma.rgb_oem = dm_alloc(
+               ctx,
+               sizeof(struct pwl_float_data) *
+               (DX_GAMMA_RAMP_MAX + opp110->regamma.extra_points));
+       if (!opp110->regamma.rgb_oem)
+               goto failure_2;
+
+       opp110->regamma.rgb_resulted = dm_alloc(
+               ctx,
+               sizeof(struct pwl_result_data) *
+               (MAX_NUMBER_OF_ENTRIES + opp110->regamma.extra_points));
+       if (!opp110->regamma.rgb_resulted)
+               goto failure_3;
+
+       opp110->regamma.rgb_regamma = dm_alloc(
+               ctx,
+               sizeof(struct pwl_float_data_ex) *
+               (MAX_NUMBER_OF_ENTRIES + opp110->regamma.extra_points));
+       if (!opp110->regamma.rgb_regamma)
+               goto failure_4;
+
+       opp110->regamma.coordinates_x = dm_alloc(
+               ctx,
+               sizeof(struct hw_x_point) *
+               (MAX_NUMBER_OF_ENTRIES + opp110->regamma.extra_points));
+       if (!opp110->regamma.coordinates_x)
+               goto failure_5;
+
+       opp110->regamma.axis_x_256 = dm_alloc(
+               ctx,
+               sizeof(struct gamma_pixel) *
+               (MAX_LUT_ENTRY + opp110->regamma.extra_points));
+       if (!opp110->regamma.axis_x_256)
+               goto failure_6;
+
+       opp110->regamma.axis_x_1025 = dm_alloc(
+               ctx,
+               sizeof(struct gamma_pixel) *
+               (DX_GAMMA_RAMP_MAX + opp110->regamma.extra_points));
+       if (!opp110->regamma.axis_x_1025)
+               goto failure_7;
+
+       opp110->regamma.coeff128 = dm_alloc(
+               ctx,
+               sizeof(struct pixel_gamma_point) *
+               (MAX_NUMBER_OF_ENTRIES + opp110->regamma.extra_points));
+       if (!opp110->regamma.coeff128)
+               goto failure_8;
+
+       opp110->regamma.coeff128_oem = dm_alloc(
+               ctx,
+               sizeof(struct pixel_gamma_point) *
+               (MAX_NUMBER_OF_ENTRIES + opp110->regamma.extra_points));
+       if (!opp110->regamma.coeff128_oem)
+               goto failure_9;
+
+       opp110->regamma.coeff128_dx = dm_alloc(
+               ctx,
+               sizeof(struct pixel_gamma_point) *
+               (MAX_NUMBER_OF_ENTRIES + opp110->regamma.extra_points));
+       if (!opp110->regamma.coeff128_dx)
+               goto failure_10;
+
+       /* init palette */
+       {
+               uint32_t i = 0;
+
+               do {
+                       opp110->regamma.saved_palette[i].red = (uint8_t)i;
+                       opp110->regamma.saved_palette[i].green = (uint8_t)i;
+                       opp110->regamma.saved_palette[i].blue = (uint8_t)i;
+
+                       ++i;
+               } while (i != MAX_LUT_ENTRY);
+       }
+
+       build_evenly_distributed_points(
+               opp110->regamma.axis_x_256,
+               MAX_LUT_ENTRY,
+               opp110->regamma.x_max1,
+               opp110->regamma.divider1,
+               opp110->regamma.divider2,
+               opp110->regamma.divider3);
+
+       build_evenly_distributed_points(
+               opp110->regamma.axis_x_1025,
+               DX_GAMMA_RAMP_MAX,
+               opp110->regamma.x_max1,
+               opp110->regamma.divider1,
+               opp110->regamma.divider2,
+               opp110->regamma.divider3);
+
+       return true;
+
+failure_10:
+       dm_free(ctx, opp110->regamma.coeff128_oem);
+failure_9:
+       dm_free(ctx, opp110->regamma.coeff128);
+failure_8:
+       dm_free(ctx, opp110->regamma.axis_x_1025);
+failure_7:
+       dm_free(ctx, opp110->regamma.axis_x_256);
+failure_6:
+       dm_free(ctx, opp110->regamma.coordinates_x);
+failure_5:
+       dm_free(ctx, opp110->regamma.rgb_regamma);
+failure_4:
+       dm_free(ctx, opp110->regamma.rgb_resulted);
+failure_3:
+       dm_free(ctx, opp110->regamma.rgb_oem);
+failure_2:
+       dm_free(ctx, opp110->regamma.rgb_user);
+failure_1:
+
+       return true;
+}
+
+void dce110_opp_destroy(struct output_pixel_processor **opp)
+{
+       dm_free((*opp)->ctx, FROM_DCE11_OPP(*opp)->regamma.coeff128_dx);
+       dm_free((*opp)->ctx, FROM_DCE11_OPP(*opp)->regamma.coeff128_oem);
+       dm_free((*opp)->ctx, FROM_DCE11_OPP(*opp)->regamma.coeff128);
+       dm_free((*opp)->ctx, FROM_DCE11_OPP(*opp)->regamma.axis_x_1025);
+       dm_free((*opp)->ctx, FROM_DCE11_OPP(*opp)->regamma.axis_x_256);
+       dm_free((*opp)->ctx, FROM_DCE11_OPP(*opp)->regamma.coordinates_x);
+       dm_free((*opp)->ctx, FROM_DCE11_OPP(*opp)->regamma.rgb_regamma);
+       dm_free((*opp)->ctx, FROM_DCE11_OPP(*opp)->regamma.rgb_resulted);
+       dm_free((*opp)->ctx, FROM_DCE11_OPP(*opp)->regamma.rgb_oem);
+       dm_free((*opp)->ctx, FROM_DCE11_OPP(*opp)->regamma.rgb_user);
+       dm_free((*opp)->ctx, FROM_DCE11_OPP(*opp));
+       *opp = NULL;
+}
+
diff --git a/drivers/gpu/drm/amd/dal/dc/dce110/dce110_opp.h 
b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_opp.h
new file mode 100644
index 000000000000..e53eb7413948
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_opp.h
@@ -0,0 +1,143 @@
+/* Copyright 2012-15 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 __DC_OPP_DCE110_H__
+#define __DC_OPP_DCE110_H__
+
+#include "dc_types.h"
+#include "inc/opp.h"
+#include "gamma_types.h"
+
+struct gamma_parameters;
+
+#define FROM_DCE11_OPP(opp)\
+       container_of(opp, struct dce110_opp, base)
+
+enum dce110_opp_reg_type {
+       DCE110_OPP_REG_DCP = 0,
+       DCE110_OPP_REG_DCFE,
+       DCE110_OPP_REG_FMT,
+
+       DCE110_OPP_REG_MAX
+};
+
+struct dce110_regamma {
+       struct gamma_curve arr_curve_points[16];
+       struct curve_points arr_points[3];
+       uint32_t hw_points_num;
+       struct hw_x_point *coordinates_x;
+       struct pwl_result_data *rgb_resulted;
+
+       /* re-gamma curve */
+       struct pwl_float_data_ex *rgb_regamma;
+       /* coeff used to map user evenly distributed points
+        * to our hardware points (predefined) for gamma 256 */
+       struct pixel_gamma_point *coeff128;
+       struct pixel_gamma_point *coeff128_oem;
+       /* coeff used to map user evenly distributed points
+        * to our hardware points (predefined) for gamma 1025 */
+       struct pixel_gamma_point *coeff128_dx;
+       /* evenly distributed points, gamma 256 software points 0-255 */
+       struct gamma_pixel *axis_x_256;
+       /* evenly distributed points, gamma 1025 software points 0-1025 */
+       struct gamma_pixel *axis_x_1025;
+       /* OEM supplied gamma for regamma LUT */
+       struct pwl_float_data *rgb_oem;
+       /* user supplied gamma */
+       struct pwl_float_data *rgb_user;
+       struct dev_c_lut saved_palette[RGB_256X3X16];
+       uint32_t extra_points;
+       bool use_half_points;
+       struct fixed31_32 x_max1;
+       struct fixed31_32 x_max2;
+       struct fixed31_32 x_min;
+       struct fixed31_32 divider1;
+       struct fixed31_32 divider2;
+       struct fixed31_32 divider3;
+};
+
+/* OPP RELATED */
+#define TO_DCE110_OPP(opp)\
+       container_of(opp, struct dce110_opp, base)
+
+struct dce110_opp_reg_offsets {
+       uint32_t fmt_offset;
+       uint32_t dcp_offset;
+       uint32_t dcfe_offset;
+};
+
+struct dce110_opp {
+       struct output_pixel_processor base;
+       struct dce110_opp_reg_offsets offsets;
+       struct dce110_regamma regamma;
+};
+
+bool dce110_opp_construct(struct dce110_opp *opp110,
+       struct dc_context *ctx,
+       uint32_t inst,
+       const struct dce110_opp_reg_offsets *offsets);
+
+void dce110_opp_destroy(struct output_pixel_processor **opp);
+
+/* REGAMMA RELATED */
+void dce110_opp_power_on_regamma_lut(
+       struct output_pixel_processor *opp,
+       bool power_on);
+
+bool dce110_opp_set_regamma(
+       struct output_pixel_processor *opp,
+       const struct gamma_ramp *ramp,
+       const struct gamma_parameters *params,
+       bool force_bypass);
+
+bool dce110_opp_map_legacy_and_regamma_hw_to_x_user(
+       struct output_pixel_processor *opp,
+       const struct gamma_ramp *gamma_ramp,
+       const struct gamma_parameters *params);
+
+void dce110_opp_set_csc_adjustment(
+       struct output_pixel_processor *opp,
+       const struct grph_csc_adjustment *adjust);
+
+void dce110_opp_set_csc_default(
+       struct output_pixel_processor *opp,
+       const struct default_adjustment *default_adjust);
+
+/* FORMATTER RELATED */
+void dce110_opp_program_bit_depth_reduction(
+       struct output_pixel_processor *opp,
+       const struct bit_depth_reduction_params *params);
+
+void dce110_opp_program_clamping_and_pixel_encoding(
+       struct output_pixel_processor *opp,
+       const struct clamping_and_pixel_encoding_params *params);
+
+
+void dce110_opp_set_dyn_expansion(
+       struct output_pixel_processor *opp,
+       enum color_space color_sp,
+       enum dc_color_depth color_dpth,
+       enum signal_type signal);
+
+#endif
diff --git a/drivers/gpu/drm/amd/dal/dc/dce110/dce110_opp_csc.c 
b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_opp_csc.c
new file mode 100644
index 000000000000..8f651e9329bc
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_opp_csc.c
@@ -0,0 +1,904 @@
+/*
+ * Copyright 2012-15 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 "dce110_opp.h"
+#include "basics/conversion.h"
+
+/* include DCE11 register header files */
+#include "dce/dce_11_0_d.h"
+#include "dce/dce_11_0_sh_mask.h"
+
+#define DCP_REG(reg)\
+       (reg + opp110->offsets.dcp_offset)
+
+enum {
+       OUTPUT_CSC_MATRIX_SIZE = 12
+};
+
+struct out_csc_color_matrix {
+       enum color_space color_space;
+       uint16_t regval[OUTPUT_CSC_MATRIX_SIZE];
+};
+
+static const struct out_csc_color_matrix global_color_matrix[] = {
+{ COLOR_SPACE_SRGB_FULL_RANGE,
+       { 0x2000, 0, 0, 0, 0, 0x2000, 0, 0, 0, 0, 0x2000, 0} },
+{ COLOR_SPACE_SRGB_LIMITED_RANGE,
+       { 0x1B60, 0, 0, 0x200, 0, 0x1B60, 0, 0x200, 0, 0, 0x1B60, 0x200} },
+{ COLOR_SPACE_YCBCR601,
+       { 0xE00, 0xF447, 0xFDB9, 0x1000, 0x82F, 0x1012, 0x31F, 0x200, 0xFB47,
+               0xF6B9, 0xE00, 0x1000} },
+{ COLOR_SPACE_YCBCR709, { 0xE00, 0xF349, 0xFEB7, 0x1000, 0x5D2, 0x1394, 0x1FA,
+       0x200, 0xFCCB, 0xF535, 0xE00, 0x1000} },
+/*  YOnly same as YCbCr709 but Y in Full range -To do. */
+{ COLOR_SPACE_YCBCR601_YONLY, { 0xE00, 0xF447, 0xFDB9, 0x1000, 0x991,
+       0x12C9, 0x3A6, 0x200, 0xFB47, 0xF6B9, 0xE00, 0x1000} },
+{ COLOR_SPACE_YCBCR709_YONLY, { 0xE00, 0xF349, 0xFEB7, 0x1000, 0x6CE, 0x16E3,
+       0x24F, 0x200, 0xFCCB, 0xF535, 0xE00, 0x1000} }
+};
+
+enum csc_color_mode {
+       /* 00 - BITS2:0 Bypass */
+       CSC_COLOR_MODE_GRAPHICS_BYPASS,
+       /* 01 - hard coded coefficient TV RGB */
+       CSC_COLOR_MODE_GRAPHICS_PREDEFINED,
+       /* 04 - programmable OUTPUT CSC coefficient */
+       CSC_COLOR_MODE_GRAPHICS_OUTPUT_CSC,
+};
+
+static void program_color_matrix(
+       struct dce110_opp *opp110,
+       const struct out_csc_color_matrix *tbl_entry,
+       enum grph_color_adjust_option options)
+{
+       struct dc_context *ctx = opp110->base.ctx;
+       {
+               uint32_t value = 0;
+               uint32_t addr = DCP_REG(mmOUTPUT_CSC_C11_C12);
+               /* fixed S2.13 format */
+               set_reg_field_value(
+                       value,
+                       tbl_entry->regval[0],
+                       OUTPUT_CSC_C11_C12,
+                       OUTPUT_CSC_C11);
+
+               set_reg_field_value(
+                       value,
+                       tbl_entry->regval[1],
+                       OUTPUT_CSC_C11_C12,
+                       OUTPUT_CSC_C12);
+
+               dm_write_reg(ctx, addr, value);
+       }
+       {
+               uint32_t value = 0;
+               uint32_t addr = DCP_REG(mmOUTPUT_CSC_C13_C14);
+               /* fixed S2.13 format */
+               set_reg_field_value(
+                       value,
+                       tbl_entry->regval[2],
+                       OUTPUT_CSC_C13_C14,
+                       OUTPUT_CSC_C13);
+               /* fixed S0.13 format */
+               set_reg_field_value(
+                       value,
+                       tbl_entry->regval[3],
+                       OUTPUT_CSC_C13_C14,
+                       OUTPUT_CSC_C14);
+
+               dm_write_reg(ctx, addr, value);
+       }
+       {
+               uint32_t value = 0;
+               uint32_t addr = DCP_REG(mmOUTPUT_CSC_C21_C22);
+               /* fixed S2.13 format */
+               set_reg_field_value(
+                       value,
+                       tbl_entry->regval[4],
+                       OUTPUT_CSC_C21_C22,
+                       OUTPUT_CSC_C21);
+               /* fixed S2.13 format */
+               set_reg_field_value(
+                       value,
+                       tbl_entry->regval[5],
+                       OUTPUT_CSC_C21_C22,
+                       OUTPUT_CSC_C22);
+
+               dm_write_reg(ctx, addr, value);
+       }
+       {
+               uint32_t value = 0;
+               uint32_t addr = DCP_REG(mmOUTPUT_CSC_C23_C24);
+               /* fixed S2.13 format */
+               set_reg_field_value(
+                       value,
+                       tbl_entry->regval[6],
+                       OUTPUT_CSC_C23_C24,
+                       OUTPUT_CSC_C23);
+               /* fixed S0.13 format */
+               set_reg_field_value(
+                       value,
+                       tbl_entry->regval[7],
+                       OUTPUT_CSC_C23_C24,
+                       OUTPUT_CSC_C24);
+
+               dm_write_reg(ctx, addr, value);
+       }
+       {
+               uint32_t value = 0;
+               uint32_t addr = DCP_REG(mmOUTPUT_CSC_C31_C32);
+               /* fixed S2.13 format */
+               set_reg_field_value(
+                       value,
+                       tbl_entry->regval[8],
+                       OUTPUT_CSC_C31_C32,
+                       OUTPUT_CSC_C31);
+               /* fixed S0.13 format */
+               set_reg_field_value(
+                       value,
+                       tbl_entry->regval[9],
+                       OUTPUT_CSC_C31_C32,
+                       OUTPUT_CSC_C32);
+
+               dm_write_reg(ctx, addr, value);
+       }
+       {
+               uint32_t value = 0;
+               uint32_t addr = DCP_REG(mmOUTPUT_CSC_C33_C34);
+               /* fixed S2.13 format */
+               set_reg_field_value(
+                       value,
+                       tbl_entry->regval[10],
+                       OUTPUT_CSC_C33_C34,
+                       OUTPUT_CSC_C33);
+               /* fixed S0.13 format */
+               set_reg_field_value(
+                       value,
+                       tbl_entry->regval[11],
+                       OUTPUT_CSC_C33_C34,
+                       OUTPUT_CSC_C34);
+
+               dm_write_reg(ctx, addr, value);
+       }
+}
+
+/*
+ * initialize_color_float_adj_reference_values
+ * This initialize display color adjust input from API to HW range for later
+ * calculation use. This is shared by all the display color adjustment.
+ * @param :
+ * @return None
+ */
+static void initialize_color_float_adj_reference_values(
+       const struct grph_csc_adjustment *adjust,
+       struct fixed31_32 *grph_cont,
+       struct fixed31_32 *grph_sat,
+       struct fixed31_32 *grph_bright,
+       struct fixed31_32 *sin_grph_hue,
+       struct fixed31_32 *cos_grph_hue)
+{
+       /* Hue adjustment could be negative. -45 ~ +45 */
+       struct fixed31_32 hue =
+               dal_fixed31_32_mul(
+                       dal_fixed31_32_from_fraction(adjust->grph_hue, 180),
+                       dal_fixed31_32_pi);
+
+       *sin_grph_hue = dal_fixed31_32_sin(hue);
+       *cos_grph_hue = dal_fixed31_32_cos(hue);
+
+       if (adjust->adjust_divider) {
+               *grph_cont =
+                       dal_fixed31_32_from_fraction(
+                               adjust->grph_cont,
+                               adjust->adjust_divider);
+               *grph_sat =
+                       dal_fixed31_32_from_fraction(
+                               adjust->grph_sat,
+                               adjust->adjust_divider);
+               *grph_bright =
+                       dal_fixed31_32_from_fraction(
+                               adjust->grph_bright,
+                               adjust->adjust_divider);
+       } else {
+               *grph_cont = dal_fixed31_32_from_int(adjust->grph_cont);
+               *grph_sat = dal_fixed31_32_from_int(adjust->grph_sat);
+               *grph_bright = dal_fixed31_32_from_int(adjust->grph_bright);
+       }
+}
+
+static inline struct fixed31_32 fixed31_32_clamp(
+       struct fixed31_32 value,
+       int32_t min_numerator,
+       int32_t max_numerator,
+       int32_t denominator)
+{
+       return dal_fixed31_32_clamp(
+               value,
+               dal_fixed31_32_from_fraction(
+                       min_numerator,
+                       denominator),
+               dal_fixed31_32_from_fraction(
+                       max_numerator,
+                       denominator));
+}
+
+static void setup_reg_format(
+       struct fixed31_32 *coefficients,
+       uint16_t *reg_values)
+{
+       enum {
+               LENGTH = 12,
+               DENOMINATOR = 10000
+       };
+
+       static const int32_t min_numerator[] = {
+               -3 * DENOMINATOR,
+               -DENOMINATOR
+       };
+
+       static const int32_t max_numerator[] = {
+               DENOMINATOR,
+               DENOMINATOR
+       };
+
+       static const uint8_t integer_bits[] = { 2, 0 };
+
+       uint32_t i = 0;
+
+       do {
+               const uint32_t index = (i % 4) == 3;
+
+               reg_values[i] = fixed_point_to_int_frac(
+                       fixed31_32_clamp(coefficients[(i + 8) % LENGTH],
+                               min_numerator[index],
+                               max_numerator[index],
+                               DENOMINATOR),
+                       integer_bits[index], 13);
+
+               ++i;
+       } while (i != LENGTH);
+}
+
+/**
+ *****************************************************************************
+ *  Function: setup_adjustments
+ *  @note prepare to setup the values
+ *
+ *  @see
+ *
+ *****************************************************************************
+ */
+static void setup_adjustments(const struct grph_csc_adjustment *adjust,
+       struct dc_csc_adjustments *adjustments)
+{
+       if (adjust->adjust_divider != 0) {
+               adjustments->brightness =
+                       dal_fixed31_32_from_fraction(adjust->grph_bright,
+                       adjust->adjust_divider);
+               adjustments->contrast =
+                       dal_fixed31_32_from_fraction(adjust->grph_cont,
+                       adjust->adjust_divider);
+               adjustments->saturation =
+                       dal_fixed31_32_from_fraction(adjust->grph_sat,
+                       adjust->adjust_divider);
+       } else {
+               adjustments->brightness =
+                       dal_fixed31_32_from_fraction(adjust->grph_bright, 1);
+               adjustments->contrast =
+                       dal_fixed31_32_from_fraction(adjust->grph_cont, 1);
+               adjustments->saturation =
+                       dal_fixed31_32_from_fraction(adjust->grph_sat, 1);
+       }
+
+       /* convert degrees into radians */
+       adjustments->hue =
+               dal_fixed31_32_mul(
+                       dal_fixed31_32_from_fraction(adjust->grph_hue, 180),
+                       dal_fixed31_32_pi);
+}
+
+static void prepare_tv_rgb_ideal(
+       struct fixed31_32 *matrix)
+{
+       static const int32_t matrix_[] = {
+               85546875, 0, 0, 6250000,
+               0, 85546875, 0, 6250000,
+               0, 0, 85546875, 6250000
+       };
+
+       uint32_t i = 0;
+
+       do {
+               matrix[i] = dal_fixed31_32_from_fraction(
+                       matrix_[i],
+                       100000000);
+               ++i;
+       } while (i != ARRAY_SIZE(matrix_));
+}
+
+/**
+ *****************************************************************************
+ *  Function: dal_transform_wide_gamut_set_rgb_adjustment_legacy
+ *
+ *  @param [in] const struct grph_csc_adjustment *adjust
+ *
+ *  @return
+ *     void
+ *
+ *  @note calculate and program color adjustments for sRGB color space
+ *
+ *  @see
+ *
+ *****************************************************************************
+ */
+static void set_rgb_adjustment_legacy(
+       struct dce110_opp *opp110,
+       const struct grph_csc_adjustment *adjust)
+{
+       const struct fixed31_32 k1 =
+               dal_fixed31_32_from_fraction(701000, 1000000);
+       const struct fixed31_32 k2 =
+               dal_fixed31_32_from_fraction(236568, 1000000);
+       const struct fixed31_32 k3 =
+               dal_fixed31_32_from_fraction(-587000, 1000000);
+       const struct fixed31_32 k4 =
+               dal_fixed31_32_from_fraction(464432, 1000000);
+       const struct fixed31_32 k5 =
+               dal_fixed31_32_from_fraction(-114000, 1000000);
+       const struct fixed31_32 k6 =
+               dal_fixed31_32_from_fraction(-701000, 1000000);
+       const struct fixed31_32 k7 =
+               dal_fixed31_32_from_fraction(-299000, 1000000);
+       const struct fixed31_32 k8 =
+               dal_fixed31_32_from_fraction(-292569, 1000000);
+       const struct fixed31_32 k9 =
+               dal_fixed31_32_from_fraction(413000, 1000000);
+       const struct fixed31_32 k10 =
+               dal_fixed31_32_from_fraction(-92482, 1000000);
+       const struct fixed31_32 k11 =
+               dal_fixed31_32_from_fraction(-114000, 1000000);
+       const struct fixed31_32 k12 =
+               dal_fixed31_32_from_fraction(385051, 1000000);
+       const struct fixed31_32 k13 =
+               dal_fixed31_32_from_fraction(-299000, 1000000);
+       const struct fixed31_32 k14 =
+               dal_fixed31_32_from_fraction(886000, 1000000);
+       const struct fixed31_32 k15 =
+               dal_fixed31_32_from_fraction(-587000, 1000000);
+       const struct fixed31_32 k16 =
+               dal_fixed31_32_from_fraction(-741914, 1000000);
+       const struct fixed31_32 k17 =
+               dal_fixed31_32_from_fraction(886000, 1000000);
+       const struct fixed31_32 k18 =
+               dal_fixed31_32_from_fraction(-144086, 1000000);
+
+       const struct fixed31_32 luma_r =
+               dal_fixed31_32_from_fraction(299, 1000);
+       const struct fixed31_32 luma_g =
+               dal_fixed31_32_from_fraction(587, 1000);
+       const struct fixed31_32 luma_b =
+               dal_fixed31_32_from_fraction(114, 1000);
+
+       struct out_csc_color_matrix tbl_entry;
+       struct fixed31_32 matrix[OUTPUT_CSC_MATRIX_SIZE];
+
+       struct fixed31_32 grph_cont;
+       struct fixed31_32 grph_sat;
+       struct fixed31_32 grph_bright;
+       struct fixed31_32 sin_grph_hue;
+       struct fixed31_32 cos_grph_hue;
+
+       initialize_color_float_adj_reference_values(
+               adjust, &grph_cont, &grph_sat,
+               &grph_bright, &sin_grph_hue, &cos_grph_hue);
+
+       /* COEF_1_1 = GrphCont * (LumaR + GrphSat * (Cos(GrphHue) * K1 +
+        * Sin(GrphHue) * K2)) */
+       /* (Cos(GrphHue) * K1 + Sin(GrphHue) * K2) */
+       matrix[0] =
+               dal_fixed31_32_add(
+                       dal_fixed31_32_mul(cos_grph_hue, k1),
+                       dal_fixed31_32_mul(sin_grph_hue, k2));
+       /* GrphSat * (Cos(GrphHue) * K1 + Sin(GrphHue) * K2 */
+       matrix[0] = dal_fixed31_32_mul(grph_sat, matrix[0]);
+       /* (LumaR + GrphSat * (Cos(GrphHue) * K1 + Sin(GrphHue) * K2)) */
+       matrix[0] = dal_fixed31_32_add(luma_r, matrix[0]);
+       /* GrphCont * (LumaR + GrphSat * (Cos(GrphHue) * K1 + Sin(GrphHue) *
+        * K2)) */
+       matrix[0] = dal_fixed31_32_mul(grph_cont, matrix[0]);
+
+       /* COEF_1_2 = GrphCont * (LumaG + GrphSat * (Cos(GrphHue) * K3 +
+        * Sin(GrphHue) * K4)) */
+       /* (Cos(GrphHue) * K3 + Sin(GrphHue) * K4) */
+       matrix[1] =
+               dal_fixed31_32_add(
+                       dal_fixed31_32_mul(cos_grph_hue, k3),
+                       dal_fixed31_32_mul(sin_grph_hue, k4));
+       /* GrphSat * (Cos(GrphHue) * K3 + Sin(GrphHue) * K4) */
+       matrix[1] = dal_fixed31_32_mul(grph_sat, matrix[1]);
+       /* (LumaG + GrphSat * (Cos(GrphHue) * K3 + Sin(GrphHue) * K4)) */
+       matrix[1] = dal_fixed31_32_add(luma_g, matrix[1]);
+       /* GrphCont * (LumaG + GrphSat * (Cos(GrphHue) * K3 + Sin(GrphHue) *
+        * K4)) */
+       matrix[1] = dal_fixed31_32_mul(grph_cont, matrix[1]);
+
+       /* COEF_1_3 = GrphCont * (LumaB + GrphSat * (Cos(GrphHue) * K5 +
+        * Sin(GrphHue) * K6)) */
+       /* (Cos(GrphHue) * K5 + Sin(GrphHue) * K6) */
+       matrix[2] =
+               dal_fixed31_32_add(
+                       dal_fixed31_32_mul(cos_grph_hue, k5),
+                       dal_fixed31_32_mul(sin_grph_hue, k6));
+       /* GrphSat * (Cos(GrphHue) * K5 + Sin(GrphHue) * K6) */
+       matrix[2] = dal_fixed31_32_mul(grph_sat, matrix[2]);
+       /* LumaB + GrphSat * (Cos(GrphHue) * K5 + Sin(GrphHue) * K6) */
+       matrix[2] = dal_fixed31_32_add(luma_b, matrix[2]);
+       /* GrphCont  * (LumaB + GrphSat * (Cos(GrphHue) * K5 + Sin(GrphHue) *
+        * K6)) */
+       matrix[2] = dal_fixed31_32_mul(grph_cont, matrix[2]);
+
+       /* COEF_1_4 = GrphBright */
+       matrix[3] = grph_bright;
+
+       /* COEF_2_1 = GrphCont * (LumaR + GrphSat * (Cos(GrphHue) * K7 +
+        * Sin(GrphHue) * K8)) */
+       /* (Cos(GrphHue) * K7 + Sin(GrphHue) * K8) */
+       matrix[4] =
+               dal_fixed31_32_add(
+                       dal_fixed31_32_mul(cos_grph_hue, k7),
+                       dal_fixed31_32_mul(sin_grph_hue, k8));
+       /* GrphSat * (Cos(GrphHue) * K7 + Sin(GrphHue) * K8) */
+       matrix[4] = dal_fixed31_32_mul(grph_sat, matrix[4]);
+       /* (LumaR + GrphSat * (Cos(GrphHue) * K7 + Sin(GrphHue) * K8)) */
+       matrix[4] = dal_fixed31_32_add(luma_r, matrix[4]);
+       /* GrphCont * (LumaR + GrphSat * (Cos(GrphHue) * K7 + Sin(GrphHue) *
+        * K8)) */
+       matrix[4] = dal_fixed31_32_mul(grph_cont, matrix[4]);
+
+       /* COEF_2_2 = GrphCont * (LumaG + GrphSat * (Cos(GrphHue) * K9 +
+        * Sin(GrphHue) * K10)) */
+       /* (Cos(GrphHue) * K9 + Sin(GrphHue) * K10)) */
+       matrix[5] =
+               dal_fixed31_32_add(
+                       dal_fixed31_32_mul(cos_grph_hue, k9),
+                       dal_fixed31_32_mul(sin_grph_hue, k10));
+       /* GrphSat * (Cos(GrphHue) * K9 + Sin(GrphHue) * K10)) */
+       matrix[5] = dal_fixed31_32_mul(grph_sat, matrix[5]);
+       /* (LumaG + GrphSat * (Cos(GrphHue) * K9 + Sin(GrphHue) * K10)) */
+       matrix[5] = dal_fixed31_32_add(luma_g, matrix[5]);
+       /* GrphCont * (LumaG + GrphSat * (Cos(GrphHue) * K9 + Sin(GrphHue) *
+        * K10)) */
+       matrix[5] = dal_fixed31_32_mul(grph_cont, matrix[5]);
+
+       /*  COEF_2_3 = GrphCont * (LumaB + GrphSat * (Cos(GrphHue) * K11 +
+        * Sin(GrphHue) * K12)) */
+       /* (Cos(GrphHue) * K11 + Sin(GrphHue) * K12)) */
+       matrix[6] =
+               dal_fixed31_32_add(
+                       dal_fixed31_32_mul(cos_grph_hue, k11),
+                       dal_fixed31_32_mul(sin_grph_hue, k12));
+       /* GrphSat * (Cos(GrphHue) * K11 + Sin(GrphHue) * K12)) */
+       matrix[6] = dal_fixed31_32_mul(grph_sat, matrix[6]);
+       /*  (LumaB + GrphSat * (Cos(GrphHue) * K11 + Sin(GrphHue) * K12)) */
+       matrix[6] = dal_fixed31_32_add(luma_b, matrix[6]);
+       /* GrphCont * (LumaB + GrphSat * (Cos(GrphHue) * K11 + Sin(GrphHue) *
+        * K12)) */
+       matrix[6] = dal_fixed31_32_mul(grph_cont, matrix[6]);
+
+       /* COEF_2_4 = GrphBright */
+       matrix[7] = grph_bright;
+
+       /* COEF_3_1 = GrphCont  * (LumaR + GrphSat * (Cos(GrphHue) * K13 +
+        * Sin(GrphHue) * K14)) */
+       /* (Cos(GrphHue) * K13 + Sin(GrphHue) * K14)) */
+       matrix[8] =
+               dal_fixed31_32_add(
+                       dal_fixed31_32_mul(cos_grph_hue, k13),
+                       dal_fixed31_32_mul(sin_grph_hue, k14));
+       /* GrphSat * (Cos(GrphHue) * K13 + Sin(GrphHue) * K14)) */
+       matrix[8] = dal_fixed31_32_mul(grph_sat, matrix[8]);
+       /* (LumaR + GrphSat * (Cos(GrphHue) * K13 + Sin(GrphHue) * K14)) */
+       matrix[8] = dal_fixed31_32_add(luma_r, matrix[8]);
+       /* GrphCont  * (LumaR + GrphSat * (Cos(GrphHue) * K13 + Sin(GrphHue) *
+        * K14)) */
+       matrix[8] = dal_fixed31_32_mul(grph_cont, matrix[8]);
+
+       /* COEF_3_2    = GrphCont * (LumaG + GrphSat * (Cos(GrphHue) * K15 +
+        * Sin(GrphHue) * K16)) */
+       /* GrphSat * (Cos(GrphHue) * K15 + Sin(GrphHue) * K16) */
+       matrix[9] =
+               dal_fixed31_32_add(
+                       dal_fixed31_32_mul(cos_grph_hue, k15),
+                       dal_fixed31_32_mul(sin_grph_hue, k16));
+       /* (LumaG + GrphSat * (Cos(GrphHue) * K15 + Sin(GrphHue) * K16)) */
+       matrix[9] = dal_fixed31_32_mul(grph_sat, matrix[9]);
+       /* (LumaG + GrphSat * (Cos(GrphHue) * K15 + Sin(GrphHue) * K16)) */
+       matrix[9] = dal_fixed31_32_add(luma_g, matrix[9]);
+        /* GrphCont * (LumaG + GrphSat * (Cos(GrphHue) * K15 + Sin(GrphHue) *
+         * K16)) */
+       matrix[9] = dal_fixed31_32_mul(grph_cont, matrix[9]);
+
+       /*  COEF_3_3 = GrphCont * (LumaB + GrphSat * (Cos(GrphHue) * K17 +
+        * Sin(GrphHue) * K18)) */
+       /* (Cos(GrphHue) * K17 + Sin(GrphHue) * K18)) */
+       matrix[10] =
+               dal_fixed31_32_add(
+                       dal_fixed31_32_mul(cos_grph_hue, k17),
+                       dal_fixed31_32_mul(sin_grph_hue, k18));
+       /*  GrphSat * (Cos(GrphHue) * K17 + Sin(GrphHue) * K18)) */
+       matrix[10] = dal_fixed31_32_mul(grph_sat, matrix[10]);
+       /* (LumaB + GrphSat * (Cos(GrphHue) * K17 + Sin(GrphHue) * K18)) */
+       matrix[10] = dal_fixed31_32_add(luma_b, matrix[10]);
+        /* GrphCont * (LumaB + GrphSat * (Cos(GrphHue) * K17 + Sin(GrphHue) *
+         * K18)) */
+       matrix[10] = dal_fixed31_32_mul(grph_cont, matrix[10]);
+
+       /*  COEF_3_4    = GrphBright */
+       matrix[11] = grph_bright;
+
+       tbl_entry.color_space = adjust->c_space;
+
+       convert_float_matrix(tbl_entry.regval, matrix, OUTPUT_CSC_MATRIX_SIZE);
+
+       program_color_matrix(
+               opp110, &tbl_entry, adjust->color_adjust_option);
+}
+
+/**
+ *****************************************************************************
+ *  Function: dal_transform_wide_gamut_set_rgb_limited_range_adjustment
+ *
+ *  @param [in] const struct grph_csc_adjustment *adjust
+ *
+ *  @return
+ *     void
+ *
+ *  @note calculate and program color adjustments for sRGB limited color space
+ *
+ *  @see
+ *
+ *****************************************************************************
+ */
+static void set_rgb_limited_range_adjustment(
+       struct dce110_opp *opp110,
+       const struct grph_csc_adjustment *adjust)
+{
+       struct out_csc_color_matrix reg_matrix;
+       struct fixed31_32 change_matrix[OUTPUT_CSC_MATRIX_SIZE];
+       struct fixed31_32 matrix[OUTPUT_CSC_MATRIX_SIZE];
+       struct dc_csc_adjustments adjustments;
+       struct fixed31_32 ideals[OUTPUT_CSC_MATRIX_SIZE];
+
+       prepare_tv_rgb_ideal(ideals);
+
+       setup_adjustments(adjust, &adjustments);
+
+       calculate_adjustments(ideals, &adjustments, matrix);
+
+       dm_memmove(change_matrix, matrix, sizeof(matrix));
+
+       /* from 1 -> 3 */
+       matrix[8] = change_matrix[0];
+       matrix[9] = change_matrix[1];
+       matrix[10] = change_matrix[2];
+       matrix[11] = change_matrix[3];
+
+       /* from 2 -> 1 */
+       matrix[0] = change_matrix[4];
+       matrix[1] = change_matrix[5];
+       matrix[2] = change_matrix[6];
+       matrix[3] = change_matrix[7];
+
+       /* from 3 -> 2 */
+       matrix[4] = change_matrix[8];
+       matrix[5] = change_matrix[9];
+       matrix[6] = change_matrix[10];
+       matrix[7] = change_matrix[11];
+
+       dm_memset(&reg_matrix, 0, sizeof(struct out_csc_color_matrix));
+
+       setup_reg_format(matrix, reg_matrix.regval);
+
+       program_color_matrix(opp110, &reg_matrix, GRPH_COLOR_MATRIX_SW);
+}
+
+static void prepare_yuv_ideal(
+       bool b601,
+       struct fixed31_32 *matrix)
+{
+       static const int32_t matrix_1[] = {
+               25578516, 50216016, 9752344, 6250000,
+               -14764391, -28985609, 43750000, 50000000,
+               43750000, -36635164, -7114836, 50000000
+       };
+
+       static const int32_t matrix_2[] = {
+               18187266, 61183125, 6176484, 6250000,
+               -10025059, -33724941, 43750000, 50000000,
+               43750000, -39738379, -4011621, 50000000
+       };
+
+       const int32_t *matrix_x = b601 ? matrix_1 : matrix_2;
+
+       uint32_t i = 0;
+
+       do {
+               matrix[i] = dal_fixed31_32_from_fraction(
+                       matrix_x[i],
+                       100000000);
+               ++i;
+       } while (i != ARRAY_SIZE(matrix_1));
+}
+
+/**
+ *****************************************************************************
+ *  Function: dal_transform_wide_gamut_set_yuv_adjustment
+ *
+ *  @param [in] const struct grph_csc_adjustment *adjust
+ *
+ *  @return
+ *     void
+ *
+ *  @note calculate and program color adjustments for YUV  color spaces
+ *
+ *  @see
+ *
+ *****************************************************************************
+ */
+static void set_yuv_adjustment(
+       struct dce110_opp *opp110,
+       const struct grph_csc_adjustment *adjust)
+{
+       bool b601 = (adjust->c_space == COLOR_SPACE_YPBPR601) ||
+               (adjust->c_space == COLOR_SPACE_YCBCR601) ||
+               (adjust->c_space == COLOR_SPACE_YCBCR601_YONLY);
+       struct out_csc_color_matrix reg_matrix;
+       struct fixed31_32 matrix[OUTPUT_CSC_MATRIX_SIZE];
+       struct dc_csc_adjustments adjustments;
+       struct fixed31_32 ideals[OUTPUT_CSC_MATRIX_SIZE];
+
+       prepare_yuv_ideal(b601, ideals);
+
+       setup_adjustments(adjust, &adjustments);
+
+       if ((adjust->c_space == COLOR_SPACE_YCBCR601_YONLY) ||
+               (adjust->c_space == COLOR_SPACE_YCBCR709_YONLY))
+               calculate_adjustments_y_only(
+                       ideals, &adjustments, matrix);
+       else
+               calculate_adjustments(
+                       ideals, &adjustments, matrix);
+
+       dm_memset(&reg_matrix, 0, sizeof(struct out_csc_color_matrix));
+
+       setup_reg_format(matrix, reg_matrix.regval);
+
+       program_color_matrix(opp110, &reg_matrix, GRPH_COLOR_MATRIX_SW);
+}
+
+static bool configure_graphics_mode(
+       struct dce110_opp *opp110,
+       enum csc_color_mode config,
+       enum graphics_csc_adjust_type csc_adjust_type,
+       enum color_space color_space)
+{
+       struct dc_context *ctx = opp110->base.ctx;
+       uint32_t addr = DCP_REG(mmOUTPUT_CSC_CONTROL);
+       uint32_t value = dm_read_reg(ctx, addr);
+
+       set_reg_field_value(
+               value,
+               0,
+               OUTPUT_CSC_CONTROL,
+               OUTPUT_CSC_GRPH_MODE);
+
+       if (csc_adjust_type == GRAPHICS_CSC_ADJUST_TYPE_SW) {
+               if (config == CSC_COLOR_MODE_GRAPHICS_OUTPUT_CSC) {
+                       set_reg_field_value(
+                               value,
+                               4,
+                               OUTPUT_CSC_CONTROL,
+                               OUTPUT_CSC_GRPH_MODE);
+               } else {
+
+                       switch (color_space) {
+                       case COLOR_SPACE_SRGB_FULL_RANGE:
+                               /* by pass */
+                               set_reg_field_value(
+                                       value,
+                                       0,
+                                       OUTPUT_CSC_CONTROL,
+                                       OUTPUT_CSC_GRPH_MODE);
+                               break;
+                       case COLOR_SPACE_SRGB_LIMITED_RANGE:
+                               /* TV RGB */
+                               set_reg_field_value(
+                                       value,
+                                       1,
+                                       OUTPUT_CSC_CONTROL,
+                                       OUTPUT_CSC_GRPH_MODE);
+                               break;
+                       case COLOR_SPACE_YCBCR601:
+                       case COLOR_SPACE_YPBPR601:
+                       case COLOR_SPACE_YCBCR601_YONLY:
+                               /* YCbCr601 */
+                               set_reg_field_value(
+                                       value,
+                                       2,
+                                       OUTPUT_CSC_CONTROL,
+                                       OUTPUT_CSC_GRPH_MODE);
+                               break;
+                       case COLOR_SPACE_YCBCR709:
+                       case COLOR_SPACE_YPBPR709:
+                       case COLOR_SPACE_YCBCR709_YONLY:
+                               /* YCbCr709 */
+                               set_reg_field_value(
+                                       value,
+                                       3,
+                                       OUTPUT_CSC_CONTROL,
+                                       OUTPUT_CSC_GRPH_MODE);
+                               break;
+                       default:
+                               return false;
+                       }
+               }
+       } else if (csc_adjust_type == GRAPHICS_CSC_ADJUST_TYPE_HW) {
+               switch (color_space) {
+               case COLOR_SPACE_SRGB_FULL_RANGE:
+                       /* by pass */
+                       set_reg_field_value(
+                               value,
+                               0,
+                               OUTPUT_CSC_CONTROL,
+                               OUTPUT_CSC_GRPH_MODE);
+                       break;
+               case COLOR_SPACE_SRGB_LIMITED_RANGE:
+                       /* TV RGB */
+                       set_reg_field_value(
+                               value,
+                               1,
+                               OUTPUT_CSC_CONTROL,
+                               OUTPUT_CSC_GRPH_MODE);
+                       break;
+               case COLOR_SPACE_YCBCR601:
+               case COLOR_SPACE_YPBPR601:
+               case COLOR_SPACE_YCBCR601_YONLY:
+                       /* YCbCr601 */
+                       set_reg_field_value(
+                               value,
+                               2,
+                               OUTPUT_CSC_CONTROL,
+                               OUTPUT_CSC_GRPH_MODE);
+                       break;
+               case COLOR_SPACE_YCBCR709:
+               case COLOR_SPACE_YPBPR709:
+               case COLOR_SPACE_YCBCR709_YONLY:
+                        /* YCbCr709 */
+                       set_reg_field_value(
+                               value,
+                               3,
+                               OUTPUT_CSC_CONTROL,
+                               OUTPUT_CSC_GRPH_MODE);
+                       break;
+               default:
+                       return false;
+               }
+
+       } else
+               /* by pass */
+               set_reg_field_value(
+                       value,
+                       0,
+                       OUTPUT_CSC_CONTROL,
+                       OUTPUT_CSC_GRPH_MODE);
+
+       addr = DCP_REG(mmOUTPUT_CSC_CONTROL);
+       dm_write_reg(ctx, addr, value);
+
+       return true;
+}
+
+void dce110_opp_set_csc_adjustment(
+       struct output_pixel_processor *opp,
+       const struct grph_csc_adjustment *adjust)
+{
+       struct dce110_opp *opp110 = TO_DCE110_OPP(opp);
+       enum csc_color_mode config =
+                       CSC_COLOR_MODE_GRAPHICS_OUTPUT_CSC;
+
+       /* Apply color adjustments: brightness, saturation, hue, contrast and
+        * CSC. No need for different color space routine, color space defines
+        * the ideal values only, but keep original design to allow quick switch
+        * to the old legacy routines */
+       switch (adjust->c_space) {
+       case COLOR_SPACE_SRGB_FULL_RANGE:
+               set_rgb_adjustment_legacy(opp110, adjust);
+               break;
+       case COLOR_SPACE_SRGB_LIMITED_RANGE:
+               set_rgb_limited_range_adjustment(
+                       opp110, adjust);
+               break;
+       case COLOR_SPACE_YCBCR601:
+       case COLOR_SPACE_YCBCR709:
+       case COLOR_SPACE_YCBCR601_YONLY:
+       case COLOR_SPACE_YCBCR709_YONLY:
+       case COLOR_SPACE_YPBPR601:
+       case COLOR_SPACE_YPBPR709:
+               set_yuv_adjustment(opp110, adjust);
+               break;
+       default:
+               set_rgb_adjustment_legacy(opp110, adjust);
+               break;
+       }
+
+       /*  We did everything ,now program DxOUTPUT_CSC_CONTROL */
+       configure_graphics_mode(opp110, config, adjust->csc_adjust_type,
+               adjust->c_space);
+}
+
+void dce110_opp_set_csc_default(
+       struct output_pixel_processor *opp,
+       const struct default_adjustment *default_adjust)
+{
+       struct dce110_opp *opp110 = TO_DCE110_OPP(opp);
+       enum csc_color_mode config =
+                       CSC_COLOR_MODE_GRAPHICS_PREDEFINED;
+
+       if (default_adjust->force_hw_default == false) {
+               const struct out_csc_color_matrix *elm;
+               /* currently parameter not in use */
+               enum grph_color_adjust_option option =
+                       GRPH_COLOR_MATRIX_HW_DEFAULT;
+               uint32_t i;
+               /*
+                * HW default false we program locally defined matrix
+                * HW default true  we use predefined hw matrix and we
+                * do not need to program matrix
+                * OEM wants the HW default via runtime parameter.
+                */
+               option = GRPH_COLOR_MATRIX_SW;
+
+               for (i = 0; i < ARRAY_SIZE(global_color_matrix); ++i) {
+                       elm = &global_color_matrix[i];
+                       if (elm->color_space != default_adjust->color_space)
+                               continue;
+                       /* program the matrix with default values from this
+                        * file */
+                       program_color_matrix(opp110, elm, option);
+                       config = CSC_COLOR_MODE_GRAPHICS_OUTPUT_CSC;
+                       break;
+               }
+       }
+
+       /* configure the what we programmed :
+        * 1. Default values from this file
+        * 2. Use hardware default from ROM_A and we do not need to program
+        * matrix */
+
+       configure_graphics_mode(opp110, config,
+               default_adjust->csc_adjust_type,
+               default_adjust->color_space);
+}
diff --git a/drivers/gpu/drm/amd/dal/dc/dce110/dce110_opp_formatter.c 
b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_opp_formatter.c
new file mode 100644
index 000000000000..235b92e3af61
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_opp_formatter.c
@@ -0,0 +1,610 @@
+/*
+ * Copyright 2012-15 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 "dce/dce_11_0_d.h"
+#include "dce/dce_11_0_sh_mask.h"
+
+#include "dce110_opp.h"
+
+#define FMT_REG(reg)\
+       (reg + opp110->offsets.fmt_offset)
+
+/**
+ *     set_truncation
+ *     1) set truncation depth: 0 for 18 bpp or 1 for 24 bpp
+ *     2) enable truncation
+ *     3) HW remove 12bit FMT support for DCE11 power saving reason.
+ */
+static void set_truncation(
+               struct dce110_opp *opp110,
+               const struct bit_depth_reduction_params *params)
+{
+       uint32_t value = 0;
+       uint32_t addr = FMT_REG(mmFMT_BIT_DEPTH_CONTROL);
+
+       /*Disable truncation*/
+       value = dm_read_reg(opp110->base.ctx, addr);
+       set_reg_field_value(value, 0,
+               FMT_BIT_DEPTH_CONTROL, FMT_TRUNCATE_EN);
+       set_reg_field_value(value, 0,
+               FMT_BIT_DEPTH_CONTROL, FMT_TRUNCATE_DEPTH);
+       set_reg_field_value(value, 0,
+               FMT_BIT_DEPTH_CONTROL, FMT_TRUNCATE_MODE);
+
+       dm_write_reg(opp110->base.ctx, addr, value);
+
+       /* no 10bpc trunc on DCE11*/
+       if (params->flags.TRUNCATE_ENABLED == 0 ||
+               params->flags.TRUNCATE_DEPTH == 2)
+               return;
+
+       /*Set truncation depth and Enable truncation*/
+       set_reg_field_value(value, 1,
+               FMT_BIT_DEPTH_CONTROL, FMT_TRUNCATE_EN);
+       set_reg_field_value(value, params->flags.TRUNCATE_MODE,
+               FMT_BIT_DEPTH_CONTROL, FMT_TRUNCATE_MODE);
+       set_reg_field_value(value, params->flags.TRUNCATE_DEPTH,
+               FMT_BIT_DEPTH_CONTROL, FMT_TRUNCATE_DEPTH);
+
+       dm_write_reg(opp110->base.ctx, addr, value);
+
+}
+
+/**
+ *     set_spatial_dither
+ *     1) set spatial dithering mode: pattern of seed
+ *     2) set spatical dithering depth: 0 for 18bpp or 1 for 24bpp
+ *     3) set random seed
+ *     4) set random mode
+ *             lfsr is reset every frame or not reset
+ *             RGB dithering method
+ *             0: RGB data are all dithered with x^28+x^3+1
+ *             1: R data is dithered with x^28+x^3+1
+ *             G data is dithered with x^28+X^9+1
+ *             B data is dithered with x^28+x^13+1
+ *             enable high pass filter or not
+ *     5) enable spatical dithering
+ */
+static void set_spatial_dither(
+       struct dce110_opp *opp110,
+       const struct bit_depth_reduction_params *params)
+{
+       uint32_t addr = FMT_REG(mmFMT_BIT_DEPTH_CONTROL);
+       uint32_t depth_cntl_value = 0;
+       uint32_t fmt_cntl_value = 0;
+       uint32_t dither_r_value = 0;
+       uint32_t dither_g_value = 0;
+       uint32_t dither_b_value = 0;
+
+       /*Disable spatial (random) dithering*/
+       depth_cntl_value = dm_read_reg(opp110->base.ctx, addr);
+       set_reg_field_value(depth_cntl_value, 0,
+               FMT_BIT_DEPTH_CONTROL, FMT_SPATIAL_DITHER_EN);
+       set_reg_field_value(depth_cntl_value, 0,
+               FMT_BIT_DEPTH_CONTROL, FMT_SPATIAL_DITHER_MODE);
+       set_reg_field_value(depth_cntl_value, 0,
+               FMT_BIT_DEPTH_CONTROL, FMT_SPATIAL_DITHER_DEPTH);
+       set_reg_field_value(depth_cntl_value, 0,
+               FMT_BIT_DEPTH_CONTROL, FMT_TEMPORAL_DITHER_EN);
+       set_reg_field_value(depth_cntl_value, 0,
+               FMT_BIT_DEPTH_CONTROL, FMT_HIGHPASS_RANDOM_ENABLE);
+       set_reg_field_value(depth_cntl_value, 0,
+               FMT_BIT_DEPTH_CONTROL, FMT_FRAME_RANDOM_ENABLE);
+       set_reg_field_value(depth_cntl_value, 0,
+               FMT_BIT_DEPTH_CONTROL, FMT_RGB_RANDOM_ENABLE);
+
+       dm_write_reg(opp110->base.ctx, addr, depth_cntl_value);
+
+       /* no 10bpc on DCE11*/
+       if (params->flags.SPATIAL_DITHER_ENABLED == 0 ||
+               params->flags.SPATIAL_DITHER_DEPTH == 2)
+               return;
+
+       addr = FMT_REG(mmFMT_CONTROL);
+       fmt_cntl_value = dm_read_reg(opp110->base.ctx, addr);
+       /* only use FRAME_COUNTER_MAX if frameRandom == 1*/
+       if (params->flags.FRAME_RANDOM == 1) {
+               if (params->flags.SPATIAL_DITHER_DEPTH == 0 ||
+               params->flags.SPATIAL_DITHER_DEPTH == 1) {
+                       set_reg_field_value(fmt_cntl_value, 15,
+                               FMT_CONTROL,
+                               FMT_SPATIAL_DITHER_FRAME_COUNTER_MAX);
+                       set_reg_field_value(fmt_cntl_value, 2,
+                               FMT_CONTROL,
+                               FMT_SPATIAL_DITHER_FRAME_COUNTER_BIT_SWAP);
+               } else if (params->flags.SPATIAL_DITHER_DEPTH == 2) {
+                       set_reg_field_value(fmt_cntl_value, 3,
+                               FMT_CONTROL,
+                               FMT_SPATIAL_DITHER_FRAME_COUNTER_MAX);
+                       set_reg_field_value(fmt_cntl_value, 1,
+                               FMT_CONTROL,
+                               FMT_SPATIAL_DITHER_FRAME_COUNTER_BIT_SWAP);
+               } else
+                       return;
+       } else {
+               set_reg_field_value(fmt_cntl_value, 0,
+                       FMT_CONTROL,
+                       FMT_SPATIAL_DITHER_FRAME_COUNTER_MAX);
+               set_reg_field_value(fmt_cntl_value, 0,
+                       FMT_CONTROL,
+                       FMT_SPATIAL_DITHER_FRAME_COUNTER_BIT_SWAP);
+       }
+
+       dm_write_reg(opp110->base.ctx, addr, fmt_cntl_value);
+
+       /*Set seed for random values for
+        * spatial dithering for R,G,B channels*/
+       addr = FMT_REG(mmFMT_DITHER_RAND_R_SEED);
+       set_reg_field_value(dither_r_value, params->r_seed_value,
+               FMT_DITHER_RAND_R_SEED,
+               FMT_RAND_R_SEED);
+       dm_write_reg(opp110->base.ctx, addr, dither_r_value);
+
+       addr = FMT_REG(mmFMT_DITHER_RAND_G_SEED);
+       set_reg_field_value(dither_g_value,
+               params->g_seed_value,
+               FMT_DITHER_RAND_G_SEED,
+               FMT_RAND_G_SEED);
+       dm_write_reg(opp110->base.ctx, addr, dither_g_value);
+
+       addr = FMT_REG(mmFMT_DITHER_RAND_B_SEED);
+       set_reg_field_value(dither_b_value, params->b_seed_value,
+               FMT_DITHER_RAND_B_SEED,
+               FMT_RAND_B_SEED);
+       dm_write_reg(opp110->base.ctx, addr, dither_b_value);
+
+       /* FMT_OFFSET_R_Cr  31:16 0x0 Setting the zero
+        * offset for the R/Cr channel, lower 4LSB
+        * is forced to zeros. Typically set to 0
+        * RGB and 0x80000 YCbCr.
+        */
+       /* FMT_OFFSET_G_Y   31:16 0x0 Setting the zero
+        * offset for the G/Y  channel, lower 4LSB is
+        * forced to zeros. Typically set to 0 RGB
+        * and 0x80000 YCbCr.
+        */
+       /* FMT_OFFSET_B_Cb  31:16 0x0 Setting the zero
+        * offset for the B/Cb channel, lower 4LSB is
+        * forced to zeros. Typically set to 0 RGB and
+        * 0x80000 YCbCr.
+        */
+
+       /*Set spatial dithering bit depth*/
+       set_reg_field_value(depth_cntl_value,
+               params->flags.SPATIAL_DITHER_DEPTH,
+               FMT_BIT_DEPTH_CONTROL,
+               FMT_SPATIAL_DITHER_DEPTH);
+
+       /* Set spatial dithering mode
+        * (default is Seed patterrn AAAA...)
+        */
+       set_reg_field_value(depth_cntl_value,
+               params->flags.SPATIAL_DITHER_MODE,
+               FMT_BIT_DEPTH_CONTROL,
+               FMT_SPATIAL_DITHER_MODE);
+
+       /*Reset only at startup*/
+       set_reg_field_value(depth_cntl_value,
+               params->flags.FRAME_RANDOM,
+               FMT_BIT_DEPTH_CONTROL,
+               FMT_RGB_RANDOM_ENABLE);
+
+       /*Set RGB data dithered with x^28+x^3+1*/
+       set_reg_field_value(depth_cntl_value,
+               params->flags.RGB_RANDOM,
+               FMT_BIT_DEPTH_CONTROL,
+               FMT_RGB_RANDOM_ENABLE);
+
+       /*Disable High pass filter*/
+       set_reg_field_value(depth_cntl_value,
+               params->flags.HIGHPASS_RANDOM,
+               FMT_BIT_DEPTH_CONTROL,
+               FMT_HIGHPASS_RANDOM_ENABLE);
+
+       /*Enable spatial dithering*/
+       set_reg_field_value(depth_cntl_value,
+               1,
+               FMT_BIT_DEPTH_CONTROL,
+               FMT_SPATIAL_DITHER_EN);
+
+       addr = FMT_REG(mmFMT_BIT_DEPTH_CONTROL);
+       dm_write_reg(opp110->base.ctx, addr, depth_cntl_value);
+
+}
+
+/**
+ *     SetTemporalDither (Frame Modulation)
+ *     1) set temporal dither depth
+ *     2) select pattern: from hard-coded pattern or programmable pattern
+ *     3) select optimized strips for BGR or RGB LCD sub-pixel
+ *     4) set s matrix
+ *     5) set t matrix
+ *     6) set grey level for 0.25, 0.5, 0.75
+ *     7) enable temporal dithering
+ */
+static void set_temporal_dither(
+       struct dce110_opp *opp110,
+       const struct bit_depth_reduction_params *params)
+{
+       uint32_t addr = FMT_REG(mmFMT_BIT_DEPTH_CONTROL);
+       uint32_t value;
+
+       /*Disable temporal (frame modulation) dithering first*/
+       value = dm_read_reg(opp110->base.ctx, addr);
+
+       set_reg_field_value(value,
+               0,
+               FMT_BIT_DEPTH_CONTROL,
+               FMT_TEMPORAL_DITHER_EN);
+
+       set_reg_field_value(value,
+               0,
+               FMT_BIT_DEPTH_CONTROL,
+               FMT_TEMPORAL_DITHER_RESET);
+       set_reg_field_value(value,
+               0,
+               FMT_BIT_DEPTH_CONTROL,
+               FMT_TEMPORAL_DITHER_OFFSET);
+       set_reg_field_value(value,
+               0,
+               FMT_BIT_DEPTH_CONTROL,
+               FMT_TEMPORAL_DITHER_DEPTH);
+       set_reg_field_value(value,
+               0,
+               FMT_BIT_DEPTH_CONTROL,
+               FMT_TEMPORAL_LEVEL);
+       set_reg_field_value(value,
+               0,
+               FMT_BIT_DEPTH_CONTROL,
+               FMT_25FRC_SEL);
+
+       set_reg_field_value(value,
+               0,
+               FMT_BIT_DEPTH_CONTROL,
+               FMT_50FRC_SEL);
+
+       set_reg_field_value(value,
+               0,
+               FMT_BIT_DEPTH_CONTROL,
+               FMT_75FRC_SEL);
+
+       dm_write_reg(opp110->base.ctx, addr, value);
+
+       /* no 10bpc dither on DCE11*/
+       if (params->flags.FRAME_MODULATION_ENABLED == 0 ||
+               params->flags.FRAME_MODULATION_DEPTH == 2)
+               return;
+
+       /* Set temporal dithering depth*/
+       set_reg_field_value(value,
+               params->flags.FRAME_MODULATION_DEPTH,
+               FMT_BIT_DEPTH_CONTROL,
+               FMT_TEMPORAL_DITHER_DEPTH);
+
+       set_reg_field_value(value,
+               0,
+               FMT_BIT_DEPTH_CONTROL,
+               FMT_TEMPORAL_DITHER_RESET);
+
+       set_reg_field_value(value,
+               0,
+               FMT_BIT_DEPTH_CONTROL,
+               FMT_TEMPORAL_DITHER_OFFSET);
+
+       /*Select legacy pattern based on FRC and Temporal level*/
+       addr = FMT_REG(mmFMT_TEMPORAL_DITHER_PATTERN_CONTROL);
+       dm_write_reg(opp110->base.ctx, addr, 0);
+       /*Set s matrix*/
+       addr = FMT_REG(
+               mmFMT_TEMPORAL_DITHER_PROGRAMMABLE_PATTERN_S_MATRIX);
+       dm_write_reg(opp110->base.ctx, addr, 0);
+       /*Set t matrix*/
+       addr = FMT_REG(
+               mmFMT_TEMPORAL_DITHER_PROGRAMMABLE_PATTERN_T_MATRIX);
+       dm_write_reg(opp110->base.ctx, addr, 0);
+
+       /*Select patterns for 0.25, 0.5 and 0.75 grey level*/
+       set_reg_field_value(value,
+               params->flags.TEMPORAL_LEVEL,
+               FMT_BIT_DEPTH_CONTROL,
+               FMT_TEMPORAL_LEVEL);
+
+       set_reg_field_value(value,
+               params->flags.FRC25,
+               FMT_BIT_DEPTH_CONTROL,
+               FMT_25FRC_SEL);
+
+       set_reg_field_value(value,
+               params->flags.FRC50,
+               FMT_BIT_DEPTH_CONTROL,
+               FMT_50FRC_SEL);
+
+       set_reg_field_value(value,
+               params->flags.FRC75,
+               FMT_BIT_DEPTH_CONTROL,
+               FMT_75FRC_SEL);
+
+       /*Enable bit reduction by temporal (frame modulation) dithering*/
+       set_reg_field_value(value,
+               1,
+               FMT_BIT_DEPTH_CONTROL,
+               FMT_TEMPORAL_DITHER_EN);
+
+       addr = FMT_REG(mmFMT_BIT_DEPTH_CONTROL);
+       dm_write_reg(opp110->base.ctx, addr, value);
+
+}
+
+/**
+ *     Set Clamping
+ *     1) Set clamping format based on bpc - 0 for 6bpc (No clamping)
+ *             1 for 8 bpc
+ *             2 for 10 bpc
+ *             3 for 12 bpc
+ *             7 for programable
+ *     2) Enable clamp if Limited range requested
+ */
+static void set_clamping(
+       struct dce110_opp *opp110,
+       const struct clamping_and_pixel_encoding_params *params)
+{
+       uint32_t clamp_cntl_value = 0;
+       uint32_t red_clamp_value = 0;
+       uint32_t green_clamp_value = 0;
+       uint32_t blue_clamp_value = 0;
+       uint32_t addr = FMT_REG(mmFMT_CLAMP_CNTL);
+
+       clamp_cntl_value = dm_read_reg(opp110->base.ctx, addr);
+
+       set_reg_field_value(clamp_cntl_value,
+               0,
+               FMT_CLAMP_CNTL,
+               FMT_CLAMP_DATA_EN);
+
+       set_reg_field_value(clamp_cntl_value,
+               0,
+               FMT_CLAMP_CNTL,
+               FMT_CLAMP_COLOR_FORMAT);
+
+       switch (params->clamping_level) {
+       case CLAMPING_FULL_RANGE:
+               break;
+
+       case CLAMPING_LIMITED_RANGE_8BPC:
+               set_reg_field_value(clamp_cntl_value,
+                       1,
+                       FMT_CLAMP_CNTL,
+                       FMT_CLAMP_DATA_EN);
+
+               set_reg_field_value(clamp_cntl_value,
+                       1,
+                       FMT_CLAMP_CNTL,
+                       FMT_CLAMP_COLOR_FORMAT);
+
+               break;
+
+       case CLAMPING_LIMITED_RANGE_10BPC:
+               set_reg_field_value(clamp_cntl_value,
+                       1,
+                       FMT_CLAMP_CNTL,
+                       FMT_CLAMP_DATA_EN);
+
+               set_reg_field_value(clamp_cntl_value,
+                       2,
+                       FMT_CLAMP_CNTL,
+                       FMT_CLAMP_COLOR_FORMAT);
+
+               break;
+       case CLAMPING_LIMITED_RANGE_12BPC:
+               set_reg_field_value(clamp_cntl_value,
+                       1,
+                       FMT_CLAMP_CNTL,
+                       FMT_CLAMP_DATA_EN);
+
+               set_reg_field_value(clamp_cntl_value,
+                       3,
+                       FMT_CLAMP_CNTL,
+                       FMT_CLAMP_COLOR_FORMAT);
+
+               break;
+       case CLAMPING_LIMITED_RANGE_PROGRAMMABLE:
+               set_reg_field_value(clamp_cntl_value,
+                       1,
+                       FMT_CLAMP_CNTL,
+                       FMT_CLAMP_DATA_EN);
+
+               set_reg_field_value(clamp_cntl_value,
+                       7,
+                       FMT_CLAMP_CNTL,
+                       FMT_CLAMP_COLOR_FORMAT);
+
+               /*set the defaults*/
+               set_reg_field_value(red_clamp_value,
+                       0x10,
+                       FMT_CLAMP_COMPONENT_R,
+                       FMT_CLAMP_LOWER_R);
+
+               set_reg_field_value(red_clamp_value,
+                       0xFEF,
+                       FMT_CLAMP_COMPONENT_R,
+                       FMT_CLAMP_UPPER_R);
+
+               addr = FMT_REG(mmFMT_CLAMP_COMPONENT_R);
+               dm_write_reg(opp110->base.ctx, addr, red_clamp_value);
+
+               set_reg_field_value(green_clamp_value,
+                       0x10,
+                       FMT_CLAMP_COMPONENT_G,
+                       FMT_CLAMP_LOWER_G);
+
+               set_reg_field_value(green_clamp_value,
+                       0xFEF,
+                       FMT_CLAMP_COMPONENT_G,
+                       FMT_CLAMP_UPPER_G);
+
+               addr = FMT_REG(mmFMT_CLAMP_COMPONENT_G);
+               dm_write_reg(opp110->base.ctx, addr, green_clamp_value);
+
+               set_reg_field_value(blue_clamp_value,
+                       0x10,
+                       FMT_CLAMP_COMPONENT_B,
+                       FMT_CLAMP_LOWER_B);
+
+               set_reg_field_value(blue_clamp_value,
+                       0xFEF,
+                       FMT_CLAMP_COMPONENT_B,
+                       FMT_CLAMP_UPPER_B);
+
+               addr = FMT_REG(mmFMT_CLAMP_COMPONENT_B);
+               dm_write_reg(opp110->base.ctx, addr, blue_clamp_value);
+
+               break;
+
+       default:
+               break;
+       }
+
+       addr = FMT_REG(mmFMT_CLAMP_CNTL);
+       /*Set clamp control*/
+       dm_write_reg(opp110->base.ctx, addr, clamp_cntl_value);
+
+}
+
+/**
+ *     set_pixel_encoding
+ *
+ *     Set Pixel Encoding
+ *             0: RGB 4:4:4 or YCbCr 4:4:4 or YOnly
+ *             1: YCbCr 4:2:2
+ */
+static void set_pixel_encoding(
+       struct dce110_opp *opp110,
+       const struct clamping_and_pixel_encoding_params *params)
+{
+       uint32_t fmt_cntl_value;
+       uint32_t addr = FMT_REG(mmFMT_CONTROL);
+
+       /*RGB 4:4:4 or YCbCr 4:4:4 - 0; YCbCr 4:2:2 -1.*/
+       fmt_cntl_value = dm_read_reg(opp110->base.ctx, addr);
+
+       set_reg_field_value(fmt_cntl_value,
+               0,
+               FMT_CONTROL,
+               FMT_PIXEL_ENCODING);
+
+       if (params->pixel_encoding == PIXEL_ENCODING_YCBCR422) {
+               set_reg_field_value(fmt_cntl_value,
+                       1,
+                       FMT_CONTROL,
+                       FMT_PIXEL_ENCODING);
+
+               /*00 - Pixels drop mode ,01 - Pixels average mode*/
+               set_reg_field_value(fmt_cntl_value,
+                       0,
+                       FMT_CONTROL,
+                       FMT_SUBSAMPLING_MODE);
+
+               /*00 - Cb before Cr ,01 - Cr before Cb*/
+               set_reg_field_value(fmt_cntl_value,
+                       0,
+                       FMT_CONTROL,
+                       FMT_SUBSAMPLING_ORDER);
+       }
+       dm_write_reg(opp110->base.ctx, addr, fmt_cntl_value);
+
+}
+
+void dce110_opp_program_bit_depth_reduction(
+       struct output_pixel_processor *opp,
+       const struct bit_depth_reduction_params *params)
+{
+       struct dce110_opp *opp110 = TO_DCE110_OPP(opp);
+
+       set_truncation(opp110, params);
+       set_spatial_dither(opp110, params);
+       set_temporal_dither(opp110, params);
+}
+
+void dce110_opp_program_clamping_and_pixel_encoding(
+       struct output_pixel_processor *opp,
+       const struct clamping_and_pixel_encoding_params *params)
+{
+       struct dce110_opp *opp110 = TO_DCE110_OPP(opp);
+
+       set_clamping(opp110, params);
+       set_pixel_encoding(opp110, params);
+}
+
+void dce110_opp_set_dyn_expansion(
+       struct output_pixel_processor *opp,
+       enum color_space color_sp,
+       enum dc_color_depth color_dpth,
+       enum signal_type signal)
+{
+       struct dce110_opp *opp110 = TO_DCE110_OPP(opp);
+       uint32_t value;
+       bool enable_dyn_exp = false;
+       uint32_t addr = FMT_REG(mmFMT_DYNAMIC_EXP_CNTL);
+
+       value = dm_read_reg(opp->ctx, addr);
+
+       set_reg_field_value(value, 0,
+               FMT_DYNAMIC_EXP_CNTL, FMT_DYNAMIC_EXP_EN);
+       set_reg_field_value(value, 0,
+               FMT_DYNAMIC_EXP_CNTL, FMT_DYNAMIC_EXP_MODE);
+
+       /* From HW programming guide:
+               FMT_DYNAMIC_EXP_EN = 0 for limited RGB or YCbCr output
+               FMT_DYNAMIC_EXP_EN = 1 for RGB full range only*/
+       if (color_sp == COLOR_SPACE_SRGB_FULL_RANGE)
+               enable_dyn_exp = true;
+
+       /*00 - 10-bit -> 12-bit dynamic expansion*/
+       /*01 - 8-bit  -> 12-bit dynamic expansion*/
+       if (signal == SIGNAL_TYPE_HDMI_TYPE_A) {
+               switch (color_dpth) {
+               case COLOR_DEPTH_888:
+                       set_reg_field_value(value, enable_dyn_exp ? 1:0,
+                               FMT_DYNAMIC_EXP_CNTL, FMT_DYNAMIC_EXP_EN);
+                       set_reg_field_value(value, 1,
+                               FMT_DYNAMIC_EXP_CNTL, FMT_DYNAMIC_EXP_MODE);
+                       break;
+               case COLOR_DEPTH_101010:
+                       set_reg_field_value(value, enable_dyn_exp ? 1:0,
+                               FMT_DYNAMIC_EXP_CNTL, FMT_DYNAMIC_EXP_EN);
+                       set_reg_field_value(value, 0,
+                               FMT_DYNAMIC_EXP_CNTL, FMT_DYNAMIC_EXP_MODE);
+                       break;
+               case COLOR_DEPTH_121212:
+                       break;
+               default:
+                       break;
+               }
+       }
+
+       dm_write_reg(opp->ctx, addr, value);
+}
diff --git a/drivers/gpu/drm/amd/dal/dc/dce110/dce110_opp_regamma.c 
b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_opp_regamma.c
new file mode 100644
index 000000000000..32cf57dd80d2
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_opp_regamma.c
@@ -0,0 +1,2474 @@
+/*
+ * Copyright 2012-15 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 DCE11 register header files */
+#include "dce/dce_11_0_d.h"
+#include "dce/dce_11_0_sh_mask.h"
+
+#include "dce110_opp.h"
+#include "gamma_types.h"
+
+#define DCP_REG(reg)\
+       (reg + opp110->offsets.dcp_offset)
+
+#define DCFE_REG(reg)\
+       (reg + opp110->offsets.dcfe_offset)
+
+enum {
+       MAX_PWL_ENTRY = 128,
+       MAX_REGIONS_NUMBER = 16
+
+};
+
+struct curve_config {
+       uint32_t offset;
+       int8_t segments[MAX_REGIONS_NUMBER];
+       int8_t begin;
+};
+
+/* BASE */
+static bool find_software_points(
+       struct dce110_opp *opp110,
+       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 =
+                       RGB_256X3X16 + opp110->regamma.extra_points;
+
+       struct fixed31_32 left, right;
+
+       uint32_t i = *index_to_start;
+
+       while (i < max_number) {
+               if (channel == CHANNEL_NAME_RED) {
+                       left = opp110->
+                                       regamma.axis_x_256[i].r;
+
+                       if (i < max_number - 1)
+                               right = opp110->
+                                       regamma.axis_x_256[i + 1].r;
+                       else
+                               right = opp110->
+                                       regamma.axis_x_256[max_number - 1].r;
+               } else if (channel == CHANNEL_NAME_GREEN) {
+                       left = opp110->regamma.axis_x_256[i].g;
+
+                       if (i < max_number - 1)
+                               right = opp110->
+                                       regamma.axis_x_256[i + 1].g;
+                       else
+                               right = opp110->
+                                       regamma.axis_x_256[max_number - 1].g;
+               } else {
+                       left = opp110->regamma.axis_x_256[i].b;
+
+                       if (i < max_number - 1)
+                               right = opp110->
+                                       regamma.axis_x_256[i + 1].b;
+                       else
+                               right = opp110->
+                                       regamma.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 find_software_points_dx(
+       struct dce110_opp *opp110,
+       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 = DX_GAMMA_RAMP_MAX +
+                                       opp110->regamma.extra_points;
+
+       struct fixed31_32 left, right;
+
+       uint32_t i = *index_to_start;
+
+       while (i < max_number) {
+               if (channel == CHANNEL_NAME_RED) {
+                       left = opp110->regamma.axis_x_1025[i].r;
+
+                       if (i < DX_GAMMA_RAMP_MAX - 1)
+                               right = opp110->
+                                       regamma.axis_x_1025[i + 1].r;
+                       else
+                               right = opp110->
+                               regamma.axis_x_1025[DX_GAMMA_RAMP_MAX-1].r;
+               } else if (channel == CHANNEL_NAME_GREEN) {
+                       left = opp110->regamma.axis_x_1025[i].g;
+
+                       if (i < DX_GAMMA_RAMP_MAX - 1)
+                               right = opp110->
+                                       regamma.axis_x_1025[i + 1].g;
+                       else
+                               right = opp110->
+                               regamma.axis_x_1025[DX_GAMMA_RAMP_MAX-1].g;
+               } else {
+                       left = opp110->regamma.axis_x_1025[i].b;
+
+                       if (i < DX_GAMMA_RAMP_MAX - 1)
+                               right = opp110->
+                                       regamma.axis_x_1025[i + 1].b;
+                       else
+                               right = opp110->
+                               regamma.axis_x_1025[DX_GAMMA_RAMP_MAX-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 < DX_GAMMA_RAMP_MAX - 1)
+                               *index_right = i + 1;
+                       else
+                               *index_right = DX_GAMMA_RAMP_MAX - 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 dce110_opp *opp110,
+       struct pixel_gamma_point *coeff,
+       enum channel_name channel,
+       uint32_t number_of_points,
+       enum 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;
+
+               if (pixel_format == PIXEL_FORMAT_FP16)
+                       coord_x = opp110->
+                               regamma.coordinates_x[i].adjusted_x;
+               else if (channel == CHANNEL_NAME_RED)
+                       coord_x = opp110->
+                               regamma.coordinates_x[i].regamma_y_red;
+               else if (channel == CHANNEL_NAME_GREEN)
+                       coord_x = opp110->
+                               regamma.coordinates_x[i].regamma_y_green;
+               else
+                       coord_x = opp110->
+                               regamma.coordinates_x[i].regamma_y_blue;
+
+               if (!find_software_points(
+                       opp110, coord_x, channel,
+                       &index_to_start, &index_left, &index_right, &hw_pos)) {
+                       BREAK_TO_DEBUGGER();
+                       return false;
+               }
+
+               if (index_left >= RGB_256X3X16 +
+                               opp110->regamma.extra_points) {
+                       BREAK_TO_DEBUGGER();
+                       return false;
+               }
+
+               if (index_right >= RGB_256X3X16 +
+                               opp110->regamma.extra_points) {
+                       BREAK_TO_DEBUGGER();
+                       return false;
+               }
+
+               if (channel == CHANNEL_NAME_RED) {
+                       point = &coeff[i].r;
+
+                       left_pos = opp110->
+                                       regamma.axis_x_256[index_left].r;
+                       right_pos = opp110->
+                                       regamma.axis_x_256[index_right].r;
+               } else if (channel == CHANNEL_NAME_GREEN) {
+                       point = &coeff[i].g;
+
+                       left_pos = opp110->
+                                       regamma.axis_x_256[index_left].g;
+                       right_pos = opp110->
+                                       regamma.axis_x_256[index_right].g;
+               } else {
+                       point = &coeff[i].b;
+
+                       left_pos = opp110->
+                                       regamma.axis_x_256[index_left].b;
+                       right_pos = opp110->
+                                       regamma.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 = opp110->regamma.x_min;
+               else if (hw_pos == HW_POINT_POSITION_RIGHT)
+                       point->coeff = opp110->regamma.x_max2;
+               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_custom_gamma_mapping_coefficients(
+       struct dce110_opp *opp110,
+       enum channel_name channel,
+       uint32_t number_of_points,
+       enum pixel_format pixel_format)
+{
+       return build_custom_gamma_mapping_coefficients_worker(
+               opp110, opp110->regamma.coeff128, channel,
+               number_of_points, pixel_format);
+}
+
+static inline bool build_oem_custom_gamma_mapping_coefficients(
+       struct dce110_opp *opp110,
+       enum channel_name channel,
+       uint32_t number_of_points,
+       enum pixel_format pixel_format)
+{
+       return build_custom_gamma_mapping_coefficients_worker(
+               opp110, opp110->regamma.coeff128_oem, channel,
+               number_of_points, pixel_format);
+}
+
+static bool build_custom_dx_gamma_mapping_coefficients(
+       struct dce110_opp *opp110,
+       enum channel_name channel,
+       uint32_t number_of_points,
+       enum 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;
+
+               if (pixel_format == PIXEL_FORMAT_FP16)
+                       coord_x = opp110->
+                       regamma.coordinates_x[i].adjusted_x;
+               else if (channel == CHANNEL_NAME_RED)
+                       coord_x = opp110->
+                       regamma.coordinates_x[i].regamma_y_red;
+               else if (channel == CHANNEL_NAME_GREEN)
+                       coord_x = opp110->
+                       regamma.coordinates_x[i].regamma_y_green;
+               else
+                       coord_x = opp110->
+                       regamma.coordinates_x[i].regamma_y_blue;
+
+               if (!find_software_points_dx(
+                       opp110, coord_x, channel,
+                       &index_to_start, &index_left, &index_right, &hw_pos)) {
+                       BREAK_TO_DEBUGGER();
+                       return false;
+               }
+
+               if (index_left >= DX_GAMMA_RAMP_MAX +
+                               opp110->regamma.extra_points) {
+                       BREAK_TO_DEBUGGER();
+                       return false;
+               }
+
+               if (index_right >= DX_GAMMA_RAMP_MAX +
+                               opp110->regamma.extra_points) {
+                       BREAK_TO_DEBUGGER();
+                       return false;
+               }
+
+               if (channel == CHANNEL_NAME_RED) {
+                       point = &opp110->regamma.coeff128_dx[i].r;
+
+                       left_pos = opp110->
+                                       regamma.axis_x_1025[index_left].r;
+                       right_pos = opp110->
+                                       regamma.axis_x_1025[index_right].r;
+               } else if (channel == CHANNEL_NAME_GREEN) {
+                       point = &opp110->regamma.coeff128_dx[i].g;
+
+                       left_pos = opp110->
+                                       regamma.axis_x_1025[index_left].g;
+                       right_pos = opp110->
+                                       regamma.axis_x_1025[index_right].g;
+               } else {
+                       point = &opp110->regamma.coeff128_dx[i].b;
+
+                       left_pos = opp110->
+                                       regamma.axis_x_1025[index_left].b;
+                       right_pos = opp110->
+                                       regamma.axis_x_1025[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 = opp110->regamma.x_min;
+               else if (hw_pos == HW_POINT_POSITION_RIGHT)
+                       point->coeff = opp110->regamma.x_max2;
+               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 dce110_opp *opp110,
+       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 = opp110->regamma.x_min;
+       } else {
+               BREAK_TO_DEBUGGER();
+               result = opp110->regamma.x_max1;
+       }
+
+       return result;
+}
+
+static inline struct fixed31_32 calculate_regamma_user_mapped_value(
+       struct dce110_opp *opp110,
+       const struct pixel_gamma_point *coeff,
+       enum channel_name channel,
+       uint32_t max_index)
+{
+       return calculate_mapped_value(
+               opp110, opp110->regamma.rgb_oem,
+               coeff, channel, max_index);
+}
+
+static inline struct fixed31_32 calculate_user_mapped_value(
+       struct dce110_opp *opp110,
+       const struct pixel_gamma_point *coeff,
+       enum channel_name channel,
+       uint32_t max_index)
+{
+       return calculate_mapped_value(
+               opp110, opp110->regamma.rgb_user,
+               coeff, channel, max_index);
+}
+
+static inline struct fixed31_32 calculate_oem_mapped_value(
+       struct dce110_opp *opp110,
+       uint32_t index,
+       enum channel_name channel,
+       uint32_t max_index)
+{
+       return calculate_regamma_user_mapped_value(
+               opp110, opp110->regamma.coeff128_oem +
+               index, channel, max_index);
+}
+
+static void scale_oem_gamma(
+       struct dce110_opp *opp110,
+       const struct regamma_ramp *regamma_ramp)
+{
+       const uint16_t max_driver = 0xFFFF;
+       const uint16_t max_os = 0xFF00;
+
+       uint16_t scale = max_os;
+
+       uint32_t i;
+
+       struct pwl_float_data *rgb = opp110->regamma.rgb_oem;
+       struct pwl_float_data *rgb_last = rgb + RGB_256X3X16 - 1;
+
+       /* find OEM maximum */
+
+       i = 0;
+
+       do {
+               if ((regamma_ramp->gamma[i] > max_os) ||
+                       (regamma_ramp->gamma[i + RGB_256X3X16] > max_os) ||
+                       (regamma_ramp->gamma[i + 2 * RGB_256X3X16] > max_os)) {
+                       scale = max_driver;
+                       break;
+               }
+
+               ++i;
+       } while (i != RGB_256X3X16);
+
+       /* scale */
+
+       i = 0;
+
+       do {
+               rgb->r = dal_fixed31_32_div_int(
+                       dal_fixed31_32_from_int(
+                               regamma_ramp->gamma[i]),
+                       scale);
+               rgb->g = dal_fixed31_32_div_int(
+                       dal_fixed31_32_from_int(
+                               regamma_ramp->gamma[i + RGB_256X3X16]),
+                       scale);
+               rgb->b = dal_fixed31_32_div_int(
+                       dal_fixed31_32_from_int(
+                               regamma_ramp->gamma[i + 2 * RGB_256X3X16]),
+                       scale);
+
+               ++rgb;
+               ++i;
+       } while (i != RGB_256X3X16);
+
+       /* add 3 extra points, 2 physical plus 1 virtual */
+
+       rgb->r = dal_fixed31_32_mul(rgb_last->r,
+                       opp110->regamma.divider1);
+       rgb->g = dal_fixed31_32_mul(rgb_last->g,
+                       opp110->regamma.divider1);
+       rgb->b = dal_fixed31_32_mul(rgb_last->b,
+                       opp110->regamma.divider1);
+
+       ++rgb;
+
+       rgb->r = dal_fixed31_32_mul(rgb_last->r,
+                       opp110->regamma.divider2);
+       rgb->g = dal_fixed31_32_mul(rgb_last->g,
+                       opp110->regamma.divider2);
+       rgb->b = dal_fixed31_32_mul(rgb_last->b,
+                       opp110->regamma.divider2);
+
+       ++rgb;
+
+       rgb->r = dal_fixed31_32_mul(rgb_last->r,
+                       opp110->regamma.divider3);
+       rgb->g = dal_fixed31_32_mul(rgb_last->g,
+                       opp110->regamma.divider3);
+       rgb->b = dal_fixed31_32_mul(rgb_last->b,
+                       opp110->regamma.divider3);
+}
+
+static inline void copy_rgb_regamma_to_coordinates_x(
+       struct dce110_opp *opp110)
+{
+       struct hw_x_point *coords = opp110->regamma.coordinates_x;
+       const struct pwl_float_data_ex *rgb_regamma =
+                       opp110->regamma.rgb_regamma;
+
+       uint32_t i = 0;
+
+       while (i <= opp110->regamma.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 dce110_opp *opp110,
+       const struct gamma_ramp *gamma_ramp,
+       const struct gamma_parameters *params)
+{
+       struct pwl_result_data *rgb_resulted =
+                       opp110->regamma.rgb_resulted;
+
+       const struct pixel_gamma_point *coeff;
+       uint32_t max_entries = opp110->regamma.extra_points - 1;
+
+       uint32_t i = 0;
+
+       if (gamma_ramp->type == GAMMA_RAMP_RBG256X3X16) {
+               if (!build_custom_gamma_mapping_coefficients(
+                       opp110, CHANNEL_NAME_RED,
+                       opp110->regamma.hw_points_num,
+                       params->surface_pixel_format)) {
+                       BREAK_TO_DEBUGGER();
+                       return false;
+               }
+
+               if (!build_custom_gamma_mapping_coefficients(
+                       opp110, CHANNEL_NAME_GREEN,
+                       opp110->regamma.hw_points_num,
+                       params->surface_pixel_format)) {
+                       BREAK_TO_DEBUGGER();
+                       return false;
+               }
+
+               if (!build_custom_gamma_mapping_coefficients(
+                       opp110, CHANNEL_NAME_BLUE,
+                       opp110->regamma.hw_points_num,
+                       params->surface_pixel_format)) {
+                       BREAK_TO_DEBUGGER();
+                       return false;
+               }
+
+               coeff = opp110->regamma.coeff128;
+               max_entries += RGB_256X3X16;
+       } else if (gamma_ramp->type == GAMMA_RAMP_DXGI_1) {
+               if (!build_custom_dx_gamma_mapping_coefficients(
+                       opp110, CHANNEL_NAME_RED,
+                       opp110->regamma.hw_points_num,
+                       params->surface_pixel_format)) {
+                       BREAK_TO_DEBUGGER();
+                       return false;
+               }
+
+               if (!build_custom_dx_gamma_mapping_coefficients(
+                       opp110, CHANNEL_NAME_GREEN,
+                       opp110->regamma.hw_points_num,
+                       params->surface_pixel_format)) {
+                       BREAK_TO_DEBUGGER();
+                       return false;
+               }
+
+               if (!build_custom_dx_gamma_mapping_coefficients(
+                       opp110, CHANNEL_NAME_BLUE,
+                       opp110->regamma.hw_points_num,
+                       params->surface_pixel_format)) {
+                       BREAK_TO_DEBUGGER();
+                       return false;
+               }
+
+               coeff = opp110->regamma.coeff128_dx;
+               max_entries += DX_GAMMA_RAMP_MAX;
+       } else {
+               BREAK_TO_DEBUGGER();
+               return false;
+       }
+
+       while (i <= opp110->regamma.hw_points_num) {
+               rgb_resulted->red = calculate_user_mapped_value(
+                       opp110, coeff, CHANNEL_NAME_RED, max_entries);
+               rgb_resulted->green = calculate_user_mapped_value(
+                       opp110, coeff, CHANNEL_NAME_GREEN, max_entries);
+               rgb_resulted->blue = calculate_user_mapped_value(
+                       opp110, coeff, CHANNEL_NAME_BLUE, max_entries);
+
+               ++coeff;
+               ++rgb_resulted;
+               ++i;
+       }
+
+       return true;
+}
+
+static void map_standard_regamma_hw_to_x_user(
+       struct dce110_opp *opp110,
+       enum gamma_ramp_type type,
+       const struct gamma_parameters *params)
+{
+       struct pwl_result_data *rgb_resulted =
+                       opp110->regamma.rgb_resulted;
+       const struct pwl_float_data_ex *rgb_regamma =
+                       opp110->regamma.rgb_regamma;
+
+       uint32_t i = 0;
+
+       while (i <= opp110->regamma.hw_points_num) {
+               rgb_resulted->red = rgb_regamma->r;
+               rgb_resulted->green = rgb_regamma->g;
+               rgb_resulted->blue = rgb_regamma->b;
+
+               ++rgb_resulted;
+               ++rgb_regamma;
+               ++i;
+       }
+}
+
+bool dce110_opp_map_legacy_and_regamma_hw_to_x_user(
+       struct output_pixel_processor *opp,
+       const struct gamma_ramp *gamma_ramp,
+       const struct gamma_parameters *params)
+{
+       struct dce110_opp *opp110 = TO_DCE110_OPP(opp);
+
+       if (params->regamma.features.bits.GAMMA_RAMP_ARRAY ||
+               params->regamma.features.bits.APPLY_DEGAMMA) {
+
+               const uint32_t max_entries =
+                       RGB_256X3X16 + opp110->regamma.extra_points - 1;
+
+               const struct pixel_gamma_point *coeff =
+                               opp110->regamma.coeff128;
+               struct pwl_result_data *rgb_resulted =
+                               opp110->regamma.rgb_resulted;
+
+               uint32_t i = 0;
+
+               scale_oem_gamma(opp110, &params->regamma.regamma_ramp);
+
+               copy_rgb_regamma_to_coordinates_x(opp110);
+
+               if (!build_custom_gamma_mapping_coefficients(
+                       opp110, CHANNEL_NAME_RED,
+                       opp110->regamma.hw_points_num,
+                       params->surface_pixel_format)) {
+                       BREAK_TO_DEBUGGER();
+                       return false;
+               }
+
+               if (!build_custom_gamma_mapping_coefficients(
+                       opp110, CHANNEL_NAME_GREEN,
+                       opp110->regamma.hw_points_num,
+                       params->surface_pixel_format)) {
+                       BREAK_TO_DEBUGGER();
+                       return false;
+               }
+
+               if (!build_custom_gamma_mapping_coefficients(
+                       opp110, CHANNEL_NAME_BLUE,
+                       opp110->regamma.hw_points_num,
+                       params->surface_pixel_format)) {
+                       BREAK_TO_DEBUGGER();
+                       return false;
+               }
+
+               while (i <= opp110->regamma.hw_points_num) {
+                       rgb_resulted->red =
+                               calculate_regamma_user_mapped_value(opp110,
+                                       coeff,
+                                       CHANNEL_NAME_RED, max_entries);
+                       rgb_resulted->green =
+                               calculate_regamma_user_mapped_value(opp110,
+                                       coeff,
+                                       CHANNEL_NAME_GREEN, max_entries);
+                       rgb_resulted->blue =
+                               calculate_regamma_user_mapped_value(opp110,
+                                       coeff,
+                                       CHANNEL_NAME_BLUE, max_entries);
+
+                       ++coeff;
+                       ++rgb_resulted;
+                       ++i;
+               }
+       } else
+               map_standard_regamma_hw_to_x_user(opp110,
+                               gamma_ramp->type,
+                               params);
+
+       return true;
+}
+
+static bool map_regamma_hw_to_x_user(
+       struct dce110_opp *opp110,
+       const struct gamma_ramp *gamma_ramp,
+       const struct gamma_parameters *params)
+{
+       /* setup to spare calculated ideal regamma values */
+       if (params->regamma.features.bits.GAMMA_RAMP_ARRAY ||
+               params->regamma.features.bits.APPLY_DEGAMMA) {
+
+               const uint32_t max_entries =
+                       RGB_256X3X16 + opp110->regamma.extra_points - 1;
+
+               const struct pixel_gamma_point *coeff =
+                               opp110->regamma.coeff128;
+               struct hw_x_point *coords =
+                               opp110->regamma.coordinates_x;
+
+               uint32_t i = 0;
+
+               scale_oem_gamma(opp110, &params->regamma.regamma_ramp);
+
+               copy_rgb_regamma_to_coordinates_x(opp110);
+
+               if (!build_custom_gamma_mapping_coefficients(
+                       opp110, CHANNEL_NAME_RED,
+                       opp110->regamma.hw_points_num,
+                       params->surface_pixel_format)) {
+                       BREAK_TO_DEBUGGER();
+                       return false;
+               }
+
+               if (!build_custom_gamma_mapping_coefficients(
+                       opp110, CHANNEL_NAME_GREEN,
+                       opp110->regamma.hw_points_num,
+                       params->surface_pixel_format)) {
+                       BREAK_TO_DEBUGGER();
+                       return false;
+               }
+
+               if (!build_custom_gamma_mapping_coefficients(
+                       opp110, CHANNEL_NAME_BLUE,
+                       opp110->regamma.hw_points_num,
+                       params->surface_pixel_format)) {
+                       BREAK_TO_DEBUGGER();
+                       return false;
+               }
+
+               while (i <= opp110->regamma.hw_points_num) {
+                       coords->regamma_y_red =
+                               calculate_regamma_user_mapped_value(opp110,
+                                       coeff,
+                                       CHANNEL_NAME_RED, max_entries);
+                       coords->regamma_y_green =
+                               calculate_regamma_user_mapped_value(opp110,
+                                       coeff,
+                                       CHANNEL_NAME_GREEN, max_entries);
+                       coords->regamma_y_blue =
+                               calculate_regamma_user_mapped_value(opp110,
+                                       coeff,
+                                       CHANNEL_NAME_BLUE, max_entries);
+
+                       ++coeff;
+                       ++coords;
+                       ++i;
+               }
+       } else {
+               copy_rgb_regamma_to_coordinates_x(opp110);
+       }
+
+       return calculate_interpolated_hardware_curve(opp110, gamma_ramp,
+               params);
+}
+
+static void build_regamma_coefficients(
+       const struct regamma_lut *regamma,
+       bool is_degamma_srgb,
+       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 };
+
+       /* Non-sRGB should apply 2.2 */
+       static const int32_t numerator11[3] = { 180000, 180000, 180000 };
+       static const int32_t numerator12[3] = { 4500, 4500, 4500 };
+       static const int32_t numerator13[3] = { 99, 99, 99 };
+       static const int32_t numerator14[3] = { 99, 99, 99 };
+       static const int32_t numerator15[3] = { 2200, 2200, 2200 };
+
+       const int32_t *numerator1;
+       const int32_t *numerator2;
+       const int32_t *numerator3;
+       const int32_t *numerator4;
+       const int32_t *numerator5;
+
+       uint32_t i = 0;
+
+       if (!regamma->features.bits.GAMMA_RAMP_ARRAY) {
+               numerator1 = regamma->gamma_coeff.a0;
+               numerator2 = regamma->gamma_coeff.a1;
+               numerator3 = regamma->gamma_coeff.a2;
+               numerator4 = regamma->gamma_coeff.a3;
+               numerator5 = regamma->gamma_coeff.gamma;
+       } else if (is_degamma_srgb) {
+               numerator1 = numerator01;
+               numerator2 = numerator02;
+               numerator3 = numerator03;
+               numerator4 = numerator04;
+               numerator5 = numerator05;
+       } else {
+               numerator1 = numerator11;
+               numerator2 = numerator12;
+               numerator3 = numerator13;
+               numerator4 = numerator14;
+               numerator5 = numerator15;
+       }
+
+       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(regamma->gamma_coeff.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 build_regamma_curve(
+       struct dce110_opp *opp110,
+       const struct gamma_parameters *params)
+{
+       struct pwl_float_data_ex *rgb = opp110->regamma.rgb_regamma;
+
+       uint32_t i;
+
+       struct gamma_coefficients coeff;
+
+       struct hw_x_point *coord_x =
+               opp110->regamma.coordinates_x;
+
+       build_regamma_coefficients(
+               &params->regamma,
+               params->regamma.features.bits.GRAPHICS_DEGAMMA_SRGB,
+               &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 != opp110->regamma.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;
+       }
+
+       if (params->regamma.features.bits.GAMMA_RAMP_ARRAY &&
+                       !params->regamma.features.bits.APPLY_DEGAMMA) {
+               const uint32_t max_entries =
+                       RGB_256X3X16 + opp110->regamma.extra_points - 1;
+
+               /* interpolate between 256 input points and output 185 points */
+
+               scale_oem_gamma(opp110, &params->regamma.regamma_ramp);
+
+               if (!build_oem_custom_gamma_mapping_coefficients(
+                       opp110, CHANNEL_NAME_RED,
+                       opp110->regamma.hw_points_num,
+                       params->surface_pixel_format)) {
+                       BREAK_TO_DEBUGGER();
+                       return false;
+               }
+
+               if (!build_oem_custom_gamma_mapping_coefficients(
+                       opp110, CHANNEL_NAME_GREEN,
+                       opp110->regamma.hw_points_num,
+                       params->surface_pixel_format)) {
+                       BREAK_TO_DEBUGGER();
+                       return false;
+               }
+
+               if (!build_oem_custom_gamma_mapping_coefficients(
+                       opp110, CHANNEL_NAME_BLUE,
+                       opp110->regamma.hw_points_num,
+                       params->surface_pixel_format)) {
+                       BREAK_TO_DEBUGGER();
+                       return false;
+               }
+
+               i = 0;
+
+               while (i != opp110->regamma.hw_points_num + 1) {
+                       rgb->r = calculate_oem_mapped_value(
+                               opp110, i, CHANNEL_NAME_RED, max_entries);
+                       rgb->g = calculate_oem_mapped_value(
+                               opp110, i, CHANNEL_NAME_GREEN, max_entries);
+                       rgb->b = calculate_oem_mapped_value(
+                               opp110, i, CHANNEL_NAME_BLUE, max_entries);
+                       ++rgb;
+                       ++i;
+               }
+       }
+
+       return true;
+}
+
+static void build_new_custom_resulted_curve(
+       struct dce110_opp *opp110,
+       const struct gamma_parameters *params)
+{
+       struct pwl_result_data *rgb = opp110->regamma.rgb_resulted;
+       struct pwl_result_data *rgb_plus_1 = rgb + 1;
+
+       uint32_t i;
+
+       i = 0;
+
+       while (i != opp110->regamma.hw_points_num + 1) {
+               rgb->red = dal_fixed31_32_clamp(
+                       rgb->red, opp110->regamma.x_min,
+                       opp110->regamma.x_max1);
+               rgb->green = dal_fixed31_32_clamp(
+                       rgb->green, opp110->regamma.x_min,
+                       opp110->regamma.x_max1);
+               rgb->blue = dal_fixed31_32_clamp(
+                       rgb->blue, opp110->regamma.x_min,
+                       opp110->regamma.x_max1);
+
+               ++rgb;
+               ++i;
+       }
+
+       rgb = opp110->regamma.rgb_resulted;
+
+       i = 1;
+
+       while (i != opp110->regamma.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 bool rebuild_curve_configuration_magic(
+       struct dce110_opp *opp110)
+{
+       const struct fixed31_32 magic_number =
+               dal_fixed31_32_from_fraction(249, 1000);
+
+       struct fixed31_32 y_r;
+       struct fixed31_32 y_g;
+       struct fixed31_32 y_b;
+
+       struct fixed31_32 y1_min;
+       struct fixed31_32 y2_max;
+       struct fixed31_32 y3_max;
+
+       y_r = opp110->regamma.rgb_resulted[0].red;
+       y_g = opp110->regamma.rgb_resulted[0].green;
+       y_b = opp110->regamma.rgb_resulted[0].blue;
+
+       y1_min = dal_fixed31_32_min(y_r, dal_fixed31_32_min(y_g, y_b));
+
+       opp110->regamma.arr_points[0].x =
+                       opp110->regamma.coordinates_x[0].adjusted_x;
+       opp110->regamma.arr_points[0].y = y1_min;
+       opp110->regamma.arr_points[0].slope = dal_fixed31_32_div(
+               opp110->regamma.arr_points[0].y,
+               opp110->regamma.arr_points[0].x);
+
+       opp110->regamma.arr_points[1].x = dal_fixed31_32_add(
+               opp110->regamma.coordinates_x
+               [opp110->regamma.hw_points_num - 1].adjusted_x,
+               magic_number);
+
+       opp110->regamma.arr_points[2].x =
+                       opp110->regamma.arr_points[1].x;
+
+       y_r = opp110->regamma.rgb_resulted
+                       [opp110->regamma.hw_points_num - 1].red;
+       y_g = opp110->regamma.rgb_resulted
+                       [opp110->regamma.hw_points_num - 1].green;
+       y_b = opp110->regamma.rgb_resulted
+                       [opp110->regamma.hw_points_num - 1].blue;
+
+       y2_max = dal_fixed31_32_max(y_r, dal_fixed31_32_max(y_g, y_b));
+
+       opp110->regamma.arr_points[1].y = y2_max;
+
+       y_r = opp110->regamma.rgb_resulted
+                       [opp110->regamma.hw_points_num].red;
+       y_g = opp110->regamma.rgb_resulted
+                       [opp110->regamma.hw_points_num].green;
+       y_b = opp110->regamma.rgb_resulted
+                       [opp110->regamma.hw_points_num].blue;
+
+       y3_max = dal_fixed31_32_max(y_r, dal_fixed31_32_max(y_g, y_b));
+
+       opp110->regamma.arr_points[2].y = y3_max;
+
+       opp110->regamma.arr_points[2].slope = dal_fixed31_32_one;
+
+       return true;
+}
+
+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_format_ex(
+       struct fixed31_32 value,
+       const struct custom_float_format *format,
+       struct custom_float_value *result)
+{
+       return build_custom_float(
+               value, format,
+               &result->negative, &result->mantissa, &result->exponenta) &&
+       setup_custom_float(
+               format, result->negative, result->mantissa, result->exponenta,
+               &result->value);
+}
+
+static bool convert_to_custom_float(
+       struct dce110_opp *opp110)
+{
+       struct custom_float_format fmt;
+
+       struct pwl_result_data *rgb = opp110->regamma.rgb_resulted;
+
+       uint32_t i = 0;
+
+       fmt.exponenta_bits = 6;
+       fmt.mantissa_bits = 12;
+       fmt.sign = true;
+
+       if (!convert_to_custom_float_format(
+               opp110->regamma.arr_points[0].x,
+               &fmt,
+               &opp110->regamma.arr_points[0].custom_float_x)) {
+               BREAK_TO_DEBUGGER();
+               return false;
+       }
+
+       if (!convert_to_custom_float_format(
+               opp110->regamma.arr_points[0].offset,
+               &fmt,
+               &opp110->regamma.arr_points[0].custom_float_offset)) {
+               BREAK_TO_DEBUGGER();
+               return false;
+       }
+
+       if (!convert_to_custom_float_format(
+               opp110->regamma.arr_points[0].slope,
+               &fmt,
+               &opp110->regamma.arr_points[0].custom_float_slope)) {
+               BREAK_TO_DEBUGGER();
+               return false;
+       }
+
+       fmt.mantissa_bits = 10;
+       fmt.sign = false;
+
+       if (!convert_to_custom_float_format(
+               opp110->regamma.arr_points[1].x,
+               &fmt,
+               &opp110->regamma.arr_points[1].custom_float_x)) {
+               BREAK_TO_DEBUGGER();
+               return false;
+       }
+
+       if (!convert_to_custom_float_format(
+               opp110->regamma.arr_points[1].y,
+               &fmt,
+               &opp110->regamma.arr_points[1].custom_float_y)) {
+               BREAK_TO_DEBUGGER();
+               return false;
+       }
+
+       if (!convert_to_custom_float_format(
+               opp110->regamma.arr_points[2].slope,
+               &fmt,
+               &opp110->regamma.arr_points[2].custom_float_slope)) {
+               BREAK_TO_DEBUGGER();
+               return false;
+       }
+
+       fmt.mantissa_bits = 12;
+       fmt.sign = true;
+
+       while (i != opp110->regamma.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 round_custom_float_6_12(
+       struct hw_x_point *x)
+{
+       struct custom_float_format fmt;
+
+       struct custom_float_value value;
+
+       fmt.exponenta_bits = 6;
+       fmt.mantissa_bits = 12;
+       fmt.sign = true;
+
+       if (!convert_to_custom_float_format_ex(
+               x->x, &fmt, &value))
+               return false;
+
+       x->adjusted_x = x->x;
+
+       if (value.mantissa) {
+               BREAK_TO_DEBUGGER();
+
+               return false;
+       }
+
+       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;
+
+       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]);
+
+               ++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 <= 1)) {
+                       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;
+
+                       round_custom_float_6_12(points + index);
+
+                       ++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;
+
+               round_custom_float_6_12(points + index);
+
+               *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(
+       struct dce110_opp *opp110)
+{
+       uint32_t hw_points_num = MAX_PWL_ENTRY * 2;
+
+       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, opp110->regamma.arr_curve_points,
+               opp110->regamma.arr_points,
+               opp110->regamma.coordinates_x, &hw_points_num)) {
+               ASSERT_CRITICAL(false);
+               return false;
+       }
+
+       opp110->regamma.hw_points_num = hw_points_num;
+
+       return true;
+}
+
+
+/*
+ *****************************************************************************
+ *  Function: regamma_config_regions_and_segments
+ *
+ *     build regamma curve by using predefined hw points
+ *     uses interface parameters ,like EDID coeff.
+ *
+ * @param   : parameters   interface parameters
+ *  @return void
+ *
+ *  @note
+ *
+ *  @see
+ *
+ *****************************************************************************
+ */
+static void regamma_config_regions_and_segments(
+       struct dce110_opp *opp110)
+{
+       struct gamma_curve *curve;
+       uint32_t value = 0;
+
+       {
+               set_reg_field_value(
+                       value,
+                       opp110->regamma.arr_points[0].custom_float_x,
+                       REGAMMA_CNTLA_START_CNTL,
+                       REGAMMA_CNTLA_EXP_REGION_START);
+
+               set_reg_field_value(
+                       value,
+                       0,
+                       REGAMMA_CNTLA_START_CNTL,
+                       REGAMMA_CNTLA_EXP_REGION_START_SEGMENT);
+
+               dm_write_reg(opp110->base.ctx,
+                               DCP_REG(mmREGAMMA_CNTLA_START_CNTL),
+                               value);
+       }
+       {
+               value = 0;
+               set_reg_field_value(
+                       value,
+                       opp110->regamma.arr_points[0].custom_float_slope,
+                       REGAMMA_CNTLA_SLOPE_CNTL,
+                       REGAMMA_CNTLA_EXP_REGION_LINEAR_SLOPE);
+
+               dm_write_reg(opp110->base.ctx,
+                       DCP_REG(mmREGAMMA_CNTLA_SLOPE_CNTL), value);
+       }
+       {
+               value = 0;
+               set_reg_field_value(
+                       value,
+                       opp110->regamma.arr_points[1].custom_float_x,
+                       REGAMMA_CNTLA_END_CNTL1,
+                       REGAMMA_CNTLA_EXP_REGION_END);
+
+               dm_write_reg(opp110->base.ctx,
+                       DCP_REG(mmREGAMMA_CNTLA_END_CNTL1), value);
+       }
+       {
+               value = 0;
+               set_reg_field_value(
+                       value,
+                       opp110->regamma.arr_points[2].custom_float_slope,
+                       REGAMMA_CNTLA_END_CNTL2,
+                       REGAMMA_CNTLA_EXP_REGION_END_BASE);
+
+               set_reg_field_value(
+                       value,
+                       opp110->regamma.arr_points[1].custom_float_y,
+                       REGAMMA_CNTLA_END_CNTL2,
+                       REGAMMA_CNTLA_EXP_REGION_END_SLOPE);
+
+               dm_write_reg(opp110->base.ctx,
+                       DCP_REG(mmREGAMMA_CNTLA_END_CNTL2), value);
+       }
+
+       curve = opp110->regamma.arr_curve_points;
+
+       {
+               value = 0;
+               set_reg_field_value(
+                       value,
+                       curve[0].offset,
+                       REGAMMA_CNTLA_REGION_0_1,
+                       REGAMMA_CNTLA_EXP_REGION0_LUT_OFFSET);
+
+               set_reg_field_value(
+                       value,
+                       curve[0].segments_num,
+                       REGAMMA_CNTLA_REGION_0_1,
+                       REGAMMA_CNTLA_EXP_REGION0_NUM_SEGMENTS);
+
+               set_reg_field_value(
+                       value,
+                       curve[1].offset,
+                       REGAMMA_CNTLA_REGION_0_1,
+                       REGAMMA_CNTLA_EXP_REGION1_LUT_OFFSET);
+
+               set_reg_field_value(
+                       value,
+                       curve[1].segments_num,
+                       REGAMMA_CNTLA_REGION_0_1,
+                       REGAMMA_CNTLA_EXP_REGION1_NUM_SEGMENTS);
+
+               dm_write_reg(
+                       opp110->base.ctx,
+                       DCP_REG(mmREGAMMA_CNTLA_REGION_0_1),
+                       value);
+       }
+
+       curve += 2;
+       {
+               value = 0;
+               set_reg_field_value(
+                       value,
+                       curve[0].offset,
+                       REGAMMA_CNTLA_REGION_2_3,
+                       REGAMMA_CNTLA_EXP_REGION2_LUT_OFFSET);
+
+               set_reg_field_value(
+                       value,
+                       curve[0].segments_num,
+                       REGAMMA_CNTLA_REGION_2_3,
+                       REGAMMA_CNTLA_EXP_REGION2_NUM_SEGMENTS);
+
+               set_reg_field_value(
+                       value,
+                       curve[1].offset,
+                       REGAMMA_CNTLA_REGION_2_3,
+                       REGAMMA_CNTLA_EXP_REGION3_LUT_OFFSET);
+
+               set_reg_field_value(
+                       value,
+                       curve[1].segments_num,
+                       REGAMMA_CNTLA_REGION_2_3,
+                       REGAMMA_CNTLA_EXP_REGION3_NUM_SEGMENTS);
+
+               dm_write_reg(opp110->base.ctx,
+                       DCP_REG(mmREGAMMA_CNTLA_REGION_2_3),
+                       value);
+       }
+
+       curve += 2;
+       {
+               value = 0;
+               set_reg_field_value(
+                       value,
+                       curve[0].offset,
+                       REGAMMA_CNTLA_REGION_4_5,
+                       REGAMMA_CNTLA_EXP_REGION4_LUT_OFFSET);
+
+               set_reg_field_value(
+                       value,
+                       curve[0].segments_num,
+                       REGAMMA_CNTLA_REGION_4_5,
+                       REGAMMA_CNTLA_EXP_REGION4_NUM_SEGMENTS);
+
+               set_reg_field_value(
+                       value,
+                       curve[1].offset,
+                       REGAMMA_CNTLA_REGION_4_5,
+                       REGAMMA_CNTLA_EXP_REGION5_LUT_OFFSET);
+
+               set_reg_field_value(
+                       value,
+                       curve[1].segments_num,
+                       REGAMMA_CNTLA_REGION_4_5,
+                       REGAMMA_CNTLA_EXP_REGION5_NUM_SEGMENTS);
+
+               dm_write_reg(opp110->base.ctx,
+                       DCP_REG(mmREGAMMA_CNTLA_REGION_4_5),
+                       value);
+       }
+
+       curve += 2;
+       {
+               value = 0;
+               set_reg_field_value(
+                       value,
+                       curve[0].offset,
+                       REGAMMA_CNTLA_REGION_6_7,
+                       REGAMMA_CNTLA_EXP_REGION6_LUT_OFFSET);
+
+               set_reg_field_value(
+                       value,
+                       curve[0].segments_num,
+                       REGAMMA_CNTLA_REGION_6_7,
+                       REGAMMA_CNTLA_EXP_REGION6_NUM_SEGMENTS);
+
+               set_reg_field_value(
+                       value,
+                       curve[1].offset,
+                       REGAMMA_CNTLA_REGION_6_7,
+                       REGAMMA_CNTLA_EXP_REGION7_LUT_OFFSET);
+
+               set_reg_field_value(
+                       value,
+                       curve[1].segments_num,
+                       REGAMMA_CNTLA_REGION_6_7,
+                       REGAMMA_CNTLA_EXP_REGION7_NUM_SEGMENTS);
+
+               dm_write_reg(opp110->base.ctx,
+                       DCP_REG(mmREGAMMA_CNTLA_REGION_6_7),
+                       value);
+       }
+
+       curve += 2;
+       {
+               value = 0;
+               set_reg_field_value(
+                       value,
+                       curve[0].offset,
+                       REGAMMA_CNTLA_REGION_8_9,
+                       REGAMMA_CNTLA_EXP_REGION8_LUT_OFFSET);
+
+               set_reg_field_value(
+                       value,
+                       curve[0].segments_num,
+                       REGAMMA_CNTLA_REGION_8_9,
+                       REGAMMA_CNTLA_EXP_REGION8_NUM_SEGMENTS);
+
+               set_reg_field_value(
+                       value,
+                       curve[1].offset,
+                       REGAMMA_CNTLA_REGION_8_9,
+                       REGAMMA_CNTLA_EXP_REGION9_LUT_OFFSET);
+
+               set_reg_field_value(
+                       value,
+                       curve[1].segments_num,
+                       REGAMMA_CNTLA_REGION_8_9,
+                       REGAMMA_CNTLA_EXP_REGION9_NUM_SEGMENTS);
+
+               dm_write_reg(opp110->base.ctx,
+                       DCP_REG(mmREGAMMA_CNTLA_REGION_8_9),
+                       value);
+       }
+
+       curve += 2;
+       {
+               value = 0;
+               set_reg_field_value(
+                       value,
+                       curve[0].offset,
+                       REGAMMA_CNTLA_REGION_10_11,
+                       REGAMMA_CNTLA_EXP_REGION10_LUT_OFFSET);
+
+               set_reg_field_value(
+                       value,
+                       curve[0].segments_num,
+                       REGAMMA_CNTLA_REGION_10_11,
+                       REGAMMA_CNTLA_EXP_REGION10_NUM_SEGMENTS);
+
+               set_reg_field_value(
+                       value,
+                       curve[1].offset,
+                       REGAMMA_CNTLA_REGION_10_11,
+                       REGAMMA_CNTLA_EXP_REGION11_LUT_OFFSET);
+
+               set_reg_field_value(
+                       value,
+                       curve[1].segments_num,
+                       REGAMMA_CNTLA_REGION_10_11,
+                       REGAMMA_CNTLA_EXP_REGION11_NUM_SEGMENTS);
+
+               dm_write_reg(opp110->base.ctx,
+                       DCP_REG(mmREGAMMA_CNTLA_REGION_10_11),
+                       value);
+       }
+
+       curve += 2;
+       {
+               value = 0;
+               set_reg_field_value(
+                       value,
+                       curve[0].offset,
+                       REGAMMA_CNTLA_REGION_12_13,
+                       REGAMMA_CNTLA_EXP_REGION12_LUT_OFFSET);
+
+               set_reg_field_value(
+                       value,
+                       curve[0].segments_num,
+                       REGAMMA_CNTLA_REGION_12_13,
+                       REGAMMA_CNTLA_EXP_REGION12_NUM_SEGMENTS);
+
+               set_reg_field_value(
+                       value,
+                       curve[1].offset,
+                       REGAMMA_CNTLA_REGION_12_13,
+                       REGAMMA_CNTLA_EXP_REGION13_LUT_OFFSET);
+
+               set_reg_field_value(
+                       value,
+                       curve[1].segments_num,
+                       REGAMMA_CNTLA_REGION_12_13,
+                       REGAMMA_CNTLA_EXP_REGION13_NUM_SEGMENTS);
+
+               dm_write_reg(opp110->base.ctx,
+                       DCP_REG(mmREGAMMA_CNTLA_REGION_12_13),
+                       value);
+       }
+
+       curve += 2;
+       {
+               value = 0;
+               set_reg_field_value(
+                       value,
+                       curve[0].offset,
+                       REGAMMA_CNTLA_REGION_14_15,
+                       REGAMMA_CNTLA_EXP_REGION14_LUT_OFFSET);
+
+               set_reg_field_value(
+                       value,
+                       curve[0].segments_num,
+                       REGAMMA_CNTLA_REGION_14_15,
+                       REGAMMA_CNTLA_EXP_REGION14_NUM_SEGMENTS);
+
+               set_reg_field_value(
+                       value,
+                       curve[1].offset,
+                       REGAMMA_CNTLA_REGION_14_15,
+                       REGAMMA_CNTLA_EXP_REGION15_LUT_OFFSET);
+
+               set_reg_field_value(
+                       value,
+                       curve[1].segments_num,
+                       REGAMMA_CNTLA_REGION_14_15,
+                       REGAMMA_CNTLA_EXP_REGION15_NUM_SEGMENTS);
+
+               dm_write_reg(opp110->base.ctx,
+                       DCP_REG(mmREGAMMA_CNTLA_REGION_14_15),
+                       value);
+       }
+}
+
+static void program_pwl(
+       struct dce110_opp *opp110,
+       const struct gamma_parameters *params)
+{
+       uint32_t value;
+
+       {
+               uint8_t max_tries = 10;
+               uint8_t counter = 0;
+
+               /* Power on LUT memory */
+               value = dm_read_reg(opp110->base.ctx,
+                               DCFE_REG(mmDCFE_MEM_PWR_CTRL));
+
+               set_reg_field_value(
+                       value,
+                       1,
+                       DCFE_MEM_PWR_CTRL,
+                       DCP_REGAMMA_MEM_PWR_DIS);
+
+               dm_write_reg(opp110->base.ctx,
+                               DCFE_REG(mmDCFE_MEM_PWR_CTRL), value);
+
+               while (counter < max_tries) {
+                       value =
+                               dm_read_reg(
+                                       opp110->base.ctx,
+                                       DCFE_REG(mmDCFE_MEM_PWR_STATUS));
+
+                       if (get_reg_field_value(
+                               value,
+                               DCFE_MEM_PWR_STATUS,
+                               DCP_REGAMMA_MEM_PWR_STATE) == 0)
+                               break;
+
+                       ++counter;
+               }
+
+               if (counter == max_tries) {
+                       dal_logger_write(opp110->base.ctx->logger,
+                               LOG_MAJOR_WARNING,
+                               LOG_MINOR_COMPONENT_CONTROLLER,
+                               "%s: regamma lut was not powered on "
+                               "in a timely manner,"
+                               " programming still proceeds\n",
+                               __func__);
+               }
+       }
+
+       value = 0;
+
+       set_reg_field_value(
+               value,
+               7,
+               REGAMMA_LUT_WRITE_EN_MASK,
+               REGAMMA_LUT_WRITE_EN_MASK);
+
+       dm_write_reg(opp110->base.ctx,
+               DCP_REG(mmREGAMMA_LUT_WRITE_EN_MASK), value);
+       dm_write_reg(opp110->base.ctx,
+               DCP_REG(mmREGAMMA_LUT_INDEX), 0);
+
+       /* Program REGAMMA_LUT_DATA */
+       {
+               const uint32_t addr = DCP_REG(mmREGAMMA_LUT_DATA);
+
+               uint32_t i = 0;
+
+               struct pwl_result_data *rgb =
+                               opp110->regamma.rgb_resulted;
+
+               while (i != opp110->regamma.hw_points_num) {
+                       dm_write_reg(opp110->base.ctx, addr, rgb->red_reg);
+                       dm_write_reg(opp110->base.ctx, addr, rgb->green_reg);
+                       dm_write_reg(opp110->base.ctx, addr, rgb->blue_reg);
+
+                       dm_write_reg(opp110->base.ctx, addr,
+                               rgb->delta_red_reg);
+                       dm_write_reg(opp110->base.ctx, addr,
+                               rgb->delta_green_reg);
+                       dm_write_reg(opp110->base.ctx, addr,
+                               rgb->delta_blue_reg);
+
+                       ++rgb;
+                       ++i;
+               }
+       }
+
+       /*  we are done with DCP LUT memory; re-enable low power mode */
+       value = dm_read_reg(opp110->base.ctx, DCFE_REG(mmDCFE_MEM_PWR_CTRL));
+
+       set_reg_field_value(
+               value,
+               0,
+               DCFE_MEM_PWR_CTRL,
+               DCP_REGAMMA_MEM_PWR_DIS);
+
+       dm_write_reg(opp110->base.ctx, DCFE_REG(mmDCFE_MEM_PWR_CTRL), value);
+}
+
+void dce110_opp_power_on_regamma_lut(
+       struct output_pixel_processor *opp,
+       bool power_on)
+{
+       struct dce110_opp *opp110 = TO_DCE110_OPP(opp);
+
+       uint32_t value =
+               dm_read_reg(opp->ctx, DCFE_REG(mmDCFE_MEM_PWR_CTRL));
+
+       set_reg_field_value(
+               value,
+               power_on,
+               DCFE_MEM_PWR_CTRL,
+               DCP_REGAMMA_MEM_PWR_DIS);
+
+       set_reg_field_value(
+               value,
+               power_on,
+               DCFE_MEM_PWR_CTRL,
+               DCP_LUT_MEM_PWR_DIS);
+
+       dm_write_reg(opp->ctx, DCFE_REG(mmDCFE_MEM_PWR_CTRL), value);
+}
+
+static bool scale_gamma(
+       struct dce110_opp *opp110,
+       const struct gamma_ramp *gamma_ramp,
+       const struct gamma_parameters *params)
+{
+       const struct gamma_ramp_rgb256x3x16 *gamma;
+       bool use_palette = params->surface_pixel_format == PIXEL_FORMAT_INDEX8;
+
+       const uint16_t max_driver = 0xFFFF;
+       const uint16_t max_os = 0xFF00;
+
+       uint16_t scaler = max_os;
+
+       uint32_t i;
+
+       struct dev_c_lut *palette = opp110->regamma.saved_palette;
+
+       struct pwl_float_data *rgb = opp110->regamma.rgb_user;
+       struct pwl_float_data *rgb_last = rgb + RGB_256X3X16 - 1;
+
+       if (gamma_ramp->type == GAMMA_RAMP_RBG256X3X16)
+               gamma = &gamma_ramp->gamma_ramp_rgb256x3x16;
+       else
+               return false; /* invalid option */
+
+       i = 0;
+
+       do {
+               if ((gamma->red[i] > max_os) ||
+                       (gamma->green[i] > max_os) ||
+                       (gamma->blue[i] > max_os)) {
+                       scaler = max_driver;
+                       break;
+               }
+               ++i;
+       } while (i != RGB_256X3X16);
+
+       i = 0;
+
+       if (use_palette)
+               do {
+                       rgb->r = dal_fixed31_32_from_fraction(
+                               gamma->red[palette->red], scaler);
+                       rgb->g = dal_fixed31_32_from_fraction(
+                               gamma->green[palette->green], scaler);
+                       rgb->b = dal_fixed31_32_from_fraction(
+                               gamma->blue[palette->blue], scaler);
+
+                       ++palette;
+                       ++rgb;
+                       ++i;
+               } while (i != RGB_256X3X16);
+       else
+               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 != RGB_256X3X16);
+
+       rgb->r = dal_fixed31_32_mul(rgb_last->r,
+                       opp110->regamma.divider1);
+       rgb->g = dal_fixed31_32_mul(rgb_last->g,
+                       opp110->regamma.divider1);
+       rgb->b = dal_fixed31_32_mul(rgb_last->b,
+                       opp110->regamma.divider1);
+
+       ++rgb;
+
+       rgb->r = dal_fixed31_32_mul(rgb_last->r,
+                       opp110->regamma.divider2);
+       rgb->g = dal_fixed31_32_mul(rgb_last->g,
+                       opp110->regamma.divider2);
+       rgb->b = dal_fixed31_32_mul(rgb_last->b,
+                       opp110->regamma.divider2);
+
+       ++rgb;
+
+       rgb->r = dal_fixed31_32_mul(rgb_last->r,
+                       opp110->regamma.divider3);
+       rgb->g = dal_fixed31_32_mul(rgb_last->g,
+                       opp110->regamma.divider3);
+       rgb->b = dal_fixed31_32_mul(rgb_last->b,
+                       opp110->regamma.divider3);
+
+       return true;
+}
+
+
+static void configure_regamma_mode(
+       struct dce110_opp *opp110,
+       const struct gamma_parameters *params,
+       bool force_bypass)
+{
+       const uint32_t addr = DCP_REG(mmREGAMMA_CONTROL);
+
+       enum wide_gamut_regamma_mode mode =
+               WIDE_GAMUT_REGAMMA_MODE_GRAPHICS_MATRIX_A;
+
+       uint32_t value = dm_read_reg(opp110->base.ctx, addr);
+
+       if (force_bypass) {
+
+               set_reg_field_value(
+                       value,
+                       0,
+                       REGAMMA_CONTROL,
+                       GRPH_REGAMMA_MODE);
+
+               dm_write_reg(opp110->base.ctx, addr, value);
+
+               return;
+       }
+
+       if (params->regamma_adjust_type == GRAPHICS_REGAMMA_ADJUST_BYPASS)
+               mode = WIDE_GAMUT_REGAMMA_MODE_GRAPHICS_BYPASS;
+       else if (params->regamma_adjust_type == GRAPHICS_REGAMMA_ADJUST_HW) {
+               if (params->surface_pixel_format == PIXEL_FORMAT_FP16)
+                       mode = WIDE_GAMUT_REGAMMA_MODE_GRAPHICS_BYPASS;
+               else
+                       mode = WIDE_GAMUT_REGAMMA_MODE_GRAPHICS_SRGB24;
+       }
+
+       switch (mode) {
+       case WIDE_GAMUT_REGAMMA_MODE_GRAPHICS_BYPASS:
+               set_reg_field_value(
+                       value,
+                       0,
+                       REGAMMA_CONTROL,
+                       GRPH_REGAMMA_MODE);
+               break;
+       case WIDE_GAMUT_REGAMMA_MODE_GRAPHICS_SRGB24:
+               set_reg_field_value(
+                       value,
+                       1,
+                       REGAMMA_CONTROL,
+                       GRPH_REGAMMA_MODE);
+               break;
+       case WIDE_GAMUT_REGAMMA_MODE_GRAPHICS_XYYCC22:
+               set_reg_field_value(
+                       value,
+                       2,
+                       REGAMMA_CONTROL,
+                       GRPH_REGAMMA_MODE);
+               break;
+       case WIDE_GAMUT_REGAMMA_MODE_GRAPHICS_MATRIX_A:
+               set_reg_field_value(
+                       value,
+                       3,
+                       REGAMMA_CONTROL,
+                       GRPH_REGAMMA_MODE);
+               break;
+       case WIDE_GAMUT_REGAMMA_MODE_GRAPHICS_MATRIX_B:
+               set_reg_field_value(
+                       value,
+                       4,
+                       REGAMMA_CONTROL,
+                       GRPH_REGAMMA_MODE);
+               break;
+       default:
+               break;
+       }
+
+       dm_write_reg(opp110->base.ctx, addr, value);
+}
+
+bool dce110_opp_set_regamma(
+       struct output_pixel_processor *opp,
+       const struct gamma_ramp *ramp,
+       const struct gamma_parameters *params,
+       bool force_bypass)
+{
+       struct dce110_opp *opp110 = TO_DCE110_OPP(opp);
+
+       if (force_bypass) {
+               configure_regamma_mode(opp110, params, true);
+       } else {
+               /* 1. Scale gamma to 0 - 1 to m_pRgbUser */
+               if (!scale_gamma(opp110, ramp, params)) {
+                       ASSERT_CRITICAL(false);
+                       /* invalid option */
+                       return false;
+               }
+
+               /* 2. Configure regamma curve without analysis (future task) */
+               /*    and program the PWL regions and segments */
+               if (params->regamma_adjust_type == GRAPHICS_REGAMMA_ADJUST_SW ||
+                       params->surface_pixel_format == PIXEL_FORMAT_FP16) {
+
+                       /* 3. Setup x exponentially distributed points */
+                       if (!setup_distribution_points(opp110)) {
+                               ASSERT_CRITICAL(false);
+                               /* invalid option */
+                               return false;
+                       }
+
+                       /* 4. Build ideal regamma curve */
+                       if (!build_regamma_curve(opp110, params)) {
+                               ASSERT_CRITICAL(false);
+                               /* invalid parameters or bug */
+                               return false;
+                       }
+
+                       /* 5. Map user gamma (evenly distributed x points) to
+                        * new curve when x is y from ideal regamma , step 5 */
+                       if (!map_regamma_hw_to_x_user(
+                               opp110, ramp, params)) {
+                               ASSERT_CRITICAL(false);
+                               /* invalid parameters or bug */
+                               return false;
+                       }
+
+                       /* 6.Build and verify resulted curve */
+                       build_new_custom_resulted_curve(opp110, params);
+
+                       /* 7. Build and translate x to hw format */
+                       if (!rebuild_curve_configuration_magic(opp110)) {
+                               ASSERT_CRITICAL(false);
+                               /* invalid parameters or bug */
+                               return false;
+                       }
+
+                       /* 8. convert all params to the custom float format */
+                       if (!convert_to_custom_float(opp110)) {
+                               ASSERT_CRITICAL(false);
+                               /* invalid parameters or bug */
+                               return false;
+                       }
+
+                       /* 9. program regamma curve configuration */
+                       regamma_config_regions_and_segments(opp110);
+
+                       /* 10. Program PWL */
+                       program_pwl(opp110, params);
+               }
+
+               /*
+                * 11. program regamma config
+                */
+               configure_regamma_mode(opp110, params, false);
+       }
+       return true;
+}
-- 
2.1.4

Reply via email to