Adds programming of cursor and input gamma.

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_ipp.c     |  65 ++
 drivers/gpu/drm/amd/dal/dc/dce110/dce110_ipp.h     | 100 +++
 .../gpu/drm/amd/dal/dc/dce110/dce110_ipp_cursor.c  | 256 ++++++
 .../gpu/drm/amd/dal/dc/dce110/dce110_ipp_gamma.c   | 872 +++++++++++++++++++++
 4 files changed, 1293 insertions(+)
 create mode 100644 drivers/gpu/drm/amd/dal/dc/dce110/dce110_ipp.c
 create mode 100644 drivers/gpu/drm/amd/dal/dc/dce110/dce110_ipp.h
 create mode 100644 drivers/gpu/drm/amd/dal/dc/dce110/dce110_ipp_cursor.c
 create mode 100644 drivers/gpu/drm/amd/dal/dc/dce110/dce110_ipp_gamma.c

diff --git a/drivers/gpu/drm/amd/dal/dc/dce110/dce110_ipp.c 
b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_ipp.c
new file mode 100644
index 000000000000..6ab35272f979
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_ipp.c
@@ -0,0 +1,65 @@
+/*
+ * 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 "include/logger_interface.h"
+
+#include "dce/dce_11_0_d.h"
+#include "dce/dce_11_0_sh_mask.h"
+
+#include "dce110_ipp.h"
+
+static struct ipp_funcs funcs = {
+               .ipp_cursor_set_attributes = dce110_ipp_cursor_set_attributes,
+               .ipp_cursor_set_position = dce110_ipp_cursor_set_position,
+               .ipp_program_prescale = dce110_ipp_program_prescale,
+               .ipp_set_degamma = dce110_ipp_set_degamma,
+               .ipp_set_legacy_input_gamma_mode = 
dce110_ipp_set_legacy_input_gamma_mode,
+               .ipp_set_legacy_input_gamma_ramp = 
dce110_ipp_set_legacy_input_gamma_ramp,
+               .ipp_set_palette = dce110_ipp_set_palette,
+};
+
+bool dce110_ipp_construct(
+       struct dce110_ipp* ipp,
+       struct dc_context *ctx,
+       uint32_t inst,
+       const struct dce110_ipp_reg_offsets *offset)
+{
+       ipp->base.ctx = ctx;
+
+       ipp->base.inst = inst;
+
+       ipp->offsets = *offset;
+
+       ipp->base.funcs = &funcs;
+
+       return true;
+}
+
+void dce110_ipp_destroy(struct input_pixel_processor **ipp)
+{
+       dm_free((*ipp)->ctx, TO_DCE110_IPP(*ipp));
+       *ipp = NULL;
+}
diff --git a/drivers/gpu/drm/amd/dal/dc/dce110/dce110_ipp.h 
b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_ipp.h
new file mode 100644
index 000000000000..709906face3f
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_ipp.h
@@ -0,0 +1,100 @@
+/*
+ * 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_IPP_DCE110_H__
+#define __DC_IPP_DCE110_H__
+
+#include "inc/ipp.h"
+
+
+struct gamma_parameters;
+struct dev_c_lut;
+
+#define TO_DCE110_IPP(input_pixel_processor)\
+       container_of(input_pixel_processor, struct dce110_ipp, base)
+
+struct dce110_ipp_reg_offsets {
+       uint32_t dcp_offset;
+};
+
+struct dce110_ipp {
+       struct input_pixel_processor base;
+       struct dce110_ipp_reg_offsets offsets;
+       struct dev_c_lut saved_palette[RGB_256X3X16];
+};
+
+bool dce110_ipp_construct(
+       struct dce110_ipp* ipp,
+       struct dc_context *ctx,
+       enum controller_id id,
+       const struct dce110_ipp_reg_offsets *offset);
+
+void dce110_ipp_destroy(struct input_pixel_processor **ipp);
+
+/* CURSOR RELATED */
+bool dce110_ipp_cursor_set_position(
+       struct input_pixel_processor *ipp,
+       const struct dc_cursor_position *position);
+
+bool dce110_ipp_cursor_set_attributes(
+       struct input_pixel_processor *ipp,
+       const struct dc_cursor_attributes *attributes);
+
+/* DEGAMMA RELATED */
+bool dce110_ipp_set_degamma(
+       struct input_pixel_processor *ipp,
+       const struct gamma_parameters *params,
+       bool force_bypass);
+
+void dce110_ipp_program_prescale(
+       struct input_pixel_processor *ipp,
+       enum pixel_format pixel_format);
+
+void dce110_ipp_set_legacy_input_gamma_mode(
+               struct input_pixel_processor *ipp,
+               bool is_legacy);
+
+bool dce110_ipp_set_legacy_input_gamma_ramp(
+       struct input_pixel_processor *ipp,
+       const struct gamma_ramp *gamma_ramp,
+       const struct gamma_parameters *params);
+
+bool dce110_ipp_set_palette(
+       struct input_pixel_processor *ipp,
+       const struct dev_c_lut *palette,
+       uint32_t start,
+       uint32_t length,
+       enum pixel_format surface_pixel_format);
+
+/*
+ * Helper functions to be resused in other ASICs
+ */
+void dce110_helper_select_lut(struct dce110_ipp *ipp110);
+
+void dce110_helper_program_black_white_offset(
+       struct dce110_ipp *ipp110,
+       enum pixel_format surface_pixel_format);
+
+#endif /*__DC_IPP_DCE110_H__*/
diff --git a/drivers/gpu/drm/amd/dal/dc/dce110/dce110_ipp_cursor.c 
b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_ipp_cursor.c
new file mode 100644
index 000000000000..ef91f2db24e3
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_ipp_cursor.c
@@ -0,0 +1,256 @@
+/*
+ * 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 "include/logger_interface.h"
+
+#include "dce/dce_11_0_d.h"
+#include "dce/dce_11_0_sh_mask.h"
+
+#include "dce110_ipp.h"
+
+#define CURSOR_COLOR_BLACK 0x00000000
+#define CURSOR_COLOR_WHITE 0xFFFFFFFF
+
+#define DCP_REG(reg)\
+       (reg + ipp110->offsets.dcp_offset)
+
+static void enable(
+       struct dce110_ipp *ipp110,
+       bool enable);
+
+static void lock(
+       struct dce110_ipp *ipp110,
+       bool enable);
+
+static void program_position(
+       struct dce110_ipp *ipp110,
+       uint32_t x,
+       uint32_t y);
+
+static bool program_control(
+       struct dce110_ipp *ipp110,
+       enum dc_cursor_color_format color_format,
+       bool enable_magnification,
+       bool inverse_transparent_clamping);
+
+static void program_hotspot(
+       struct dce110_ipp *ipp110,
+       uint32_t x,
+       uint32_t y);
+
+static void program_size(
+       struct dce110_ipp *ipp110,
+       uint32_t width,
+       uint32_t height);
+
+static void program_address(
+       struct dce110_ipp *ipp110,
+       PHYSICAL_ADDRESS_LOC address);
+
+
+bool dce110_ipp_cursor_set_position(
+       struct input_pixel_processor *ipp,
+       const struct dc_cursor_position *position)
+{
+       struct dce110_ipp *ipp110 = TO_DCE110_IPP(ipp);
+
+       /* lock cursor registers */
+       lock(ipp110, true);
+
+       /* Flag passed in structure differentiates cursor enable/disable. */
+       /* Update if it differs from cached state. */
+       enable(ipp110, position->enable);
+
+       program_position(ipp110, position->x, position->y);
+
+       if (position->hot_spot_enable)
+               program_hotspot(
+                               ipp110,
+                               position->x_origin,
+                               position->y_origin);
+
+       /* unlock cursor registers */
+       lock(ipp110, false);
+
+       return true;
+}
+
+bool dce110_ipp_cursor_set_attributes(
+       struct input_pixel_processor *ipp,
+       const struct dc_cursor_attributes *attributes)
+{
+       struct dce110_ipp *ipp110 = TO_DCE110_IPP(ipp);
+       /* Lock cursor registers */
+       lock(ipp110, true);
+
+       /* Program cursor control */
+       program_control(
+               ipp110,
+               attributes->color_format,
+               attributes->attribute_flags.bits.ENABLE_MAGNIFICATION,
+               attributes->attribute_flags.bits.INVERSE_TRANSPARENT_CLAMPING);
+
+       /* Program hot spot coordinates */
+       program_hotspot(ipp110, attributes->x_hot, attributes->y_hot);
+
+       /*
+        * Program cursor size -- NOTE: HW spec specifies that HW register
+        * stores size as (height - 1, width - 1)
+        */
+       program_size(ipp110, attributes->width, attributes->height);
+
+       /* Program cursor surface address */
+       program_address(ipp110, attributes->address);
+
+       /* Unlock Cursor registers. */
+       lock(ipp110, false);
+
+       return true;
+}
+
+static void enable(
+       struct dce110_ipp *ipp110, bool enable)
+{
+       uint32_t value = 0;
+       uint32_t addr = DCP_REG(mmCUR_CONTROL);
+
+       value = dm_read_reg(ipp110->base.ctx, addr);
+       set_reg_field_value(value, enable, CUR_CONTROL, CURSOR_EN);
+       dm_write_reg(ipp110->base.ctx, addr, value);
+}
+
+static void lock(
+       struct dce110_ipp *ipp110, bool lock)
+{
+       uint32_t value = 0;
+       uint32_t addr = DCP_REG(mmCUR_UPDATE);
+
+       value = dm_read_reg(ipp110->base.ctx, addr);
+       set_reg_field_value(value, lock, CUR_UPDATE, CURSOR_UPDATE_LOCK);
+       dm_write_reg(ipp110->base.ctx, addr, value);
+}
+
+static void program_position(
+       struct dce110_ipp *ipp110,
+       uint32_t x,
+       uint32_t y)
+{
+       uint32_t value = 0;
+       uint32_t addr = DCP_REG(mmCUR_POSITION);
+
+       value = dm_read_reg(ipp110->base.ctx, addr);
+       set_reg_field_value(value, x, CUR_POSITION, CURSOR_X_POSITION);
+       set_reg_field_value(value, y, CUR_POSITION, CURSOR_Y_POSITION);
+       dm_write_reg(ipp110->base.ctx, addr, value);
+}
+
+static bool program_control(
+       struct dce110_ipp *ipp110,
+       enum dc_cursor_color_format color_format,
+       bool enable_magnification,
+       bool inverse_transparent_clamping)
+{
+       uint32_t value = 0;
+       uint32_t addr = DCP_REG(mmCUR_CONTROL);
+       uint32_t mode = 0;
+
+       switch (color_format) {
+       case CURSOR_MODE_MONO:
+               mode = 0;
+               break;
+       case CURSOR_MODE_COLOR_1BIT_AND:
+               mode = 1;
+               break;
+       case CURSOR_MODE_COLOR_PRE_MULTIPLIED_ALPHA:
+               mode = 2;
+               break;
+       case CURSOR_MODE_COLOR_UN_PRE_MULTIPLIED_ALPHA:
+               mode = 3;
+               break;
+       default:
+               return false;
+       }
+
+       set_reg_field_value(value, mode, CUR_CONTROL, CURSOR_MODE);
+       set_reg_field_value(value, enable_magnification,
+                       CUR_CONTROL, CURSOR_2X_MAGNIFY);
+       set_reg_field_value(value, inverse_transparent_clamping,
+                       CUR_CONTROL, CUR_INV_TRANS_CLAMP);
+       dm_write_reg(ipp110->base.ctx, addr, value);
+
+       if (color_format == CURSOR_MODE_MONO) {
+               addr = DCP_REG(mmCUR_COLOR1);
+               dm_write_reg(ipp110->base.ctx, addr, CURSOR_COLOR_BLACK);
+               addr = DCP_REG(mmCUR_COLOR2);
+               dm_write_reg(ipp110->base.ctx, addr, CURSOR_COLOR_WHITE);
+       }
+       return true;
+}
+
+static void program_hotspot(
+       struct dce110_ipp *ipp110,
+       uint32_t x,
+       uint32_t y)
+{
+       uint32_t value = 0;
+       uint32_t addr = DCP_REG(mmCUR_HOT_SPOT);
+
+       value = dm_read_reg(ipp110->base.ctx, addr);
+       set_reg_field_value(value, x, CUR_HOT_SPOT, CURSOR_HOT_SPOT_X);
+       set_reg_field_value(value, y, CUR_HOT_SPOT, CURSOR_HOT_SPOT_Y);
+       dm_write_reg(ipp110->base.ctx, addr, value);
+}
+
+static void program_size(
+       struct dce110_ipp *ipp110,
+       uint32_t width,
+       uint32_t height)
+{
+       uint32_t value = 0;
+       uint32_t addr = DCP_REG(mmCUR_SIZE);
+
+       value = dm_read_reg(ipp110->base.ctx, addr);
+       set_reg_field_value(value, width, CUR_SIZE, CURSOR_WIDTH);
+       set_reg_field_value(value, height, CUR_SIZE, CURSOR_HEIGHT);
+       dm_write_reg(ipp110->base.ctx, addr, value);
+}
+
+static void program_address(
+       struct dce110_ipp *ipp110,
+       PHYSICAL_ADDRESS_LOC address)
+{
+       uint32_t addr = DCP_REG(mmCUR_SURFACE_ADDRESS_HIGH);
+       /* SURFACE_ADDRESS_HIGH: Higher order bits (39:32) of hardware cursor
+        * surface base address in byte. It is 4K byte aligned.
+        * The correct way to program cursor surface address is to first write
+        * to CUR_SURFACE_ADDRESS_HIGH, and then write to CUR_SURFACE_ADDRESS */
+
+       dm_write_reg(ipp110->base.ctx, addr, address.high_part);
+
+       addr = DCP_REG(mmCUR_SURFACE_ADDRESS);
+       dm_write_reg(ipp110->base.ctx, addr, address.low_part);
+}
+
diff --git a/drivers/gpu/drm/amd/dal/dc/dce110/dce110_ipp_gamma.c 
b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_ipp_gamma.c
new file mode 100644
index 000000000000..fcf65f119af4
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_ipp_gamma.c
@@ -0,0 +1,872 @@
+/*
+ * 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 "include/logger_interface.h"
+#include "include/fixed31_32.h"
+#include "basics/conversion.h"
+
+#include "dce/dce_11_0_d.h"
+#include "dce/dce_11_0_sh_mask.h"
+
+#include "dce110_ipp.h"
+#include "gamma_types.h"
+
+#define DCP_REG(reg)\
+       (reg + ipp110->offsets.dcp_offset)
+
+enum {
+       MAX_INPUT_LUT_ENTRY = 256
+};
+
+/* CALCULATION OPERATIONS*/
+static void convert_256_lut_entries_to_gxo_format(
+       const struct gamma_ramp_rgb256x3x16 *lut,
+       struct dev_c_lut16 *gamma)
+{
+       uint32_t i = 0;
+
+       ASSERT(lut);
+       ASSERT(gamma);
+
+       do {
+               gamma->red = lut->red[i];
+               gamma->green = lut->green[i];
+               gamma->blue = lut->blue[i];
+
+               ++gamma;
+               ++i;
+       } while (i != MAX_INPUT_LUT_ENTRY);
+}
+
+static void convert_udx_gamma_entries_to_gxo_format(
+       const struct gamma_ramp_dxgi_1 *lut,
+       struct dev_c_lut16 *gamma)
+{
+       /* TODO here we deal with DXGI gamma table,
+        * originally, values was expressed as 'float',
+        * now values expressed as 'dal_fixed20_12'. */
+}
+
+/*PROTOTYPE DECLARATIONS*/
+static void set_lut_inc(
+       struct dce110_ipp *ipp110,
+       uint8_t inc,
+       bool is_float,
+       bool is_signed);
+
+static void program_black_offsets(
+       struct dce110_ipp *ipp110,
+       struct dev_c_lut16 *offset);
+
+static void program_white_offsets(
+       struct dce110_ipp *ipp110,
+       struct dev_c_lut16 *offset);
+
+static void program_lut_gamma(
+       struct dce110_ipp *ipp110,
+       const struct dev_c_lut16 *gamma,
+       const struct gamma_parameters *params);
+
+static void program_prescale(
+       struct dce110_ipp *ipp110,
+       enum pixel_format pixel_format);
+
+static void set_legacy_input_gamma_mode(
+       struct dce110_ipp *ipp110,
+       bool is_legacy);
+
+static bool set_legacy_input_gamma_ramp_rgb256x3x16(
+       struct dce110_ipp *ipp110,
+       const struct gamma_ramp *gamma_ramp,
+       const struct gamma_parameters *params);
+
+static bool set_legacy_input_gamma_ramp_dxgi1(
+       struct dce110_ipp *ipp110,
+       const struct gamma_ramp *gamma_ramp,
+       const struct gamma_parameters *params);
+
+static bool set_default_gamma(
+       struct dce110_ipp *ipp110,
+       enum pixel_format surface_pixel_format);
+
+static void set_degamma(
+       struct dce110_ipp *ipp110,
+       const struct gamma_parameters *params,
+       bool force_bypass);
+
+bool dce110_ipp_set_legacy_input_gamma_ramp(
+       struct input_pixel_processor *ipp,
+       const struct gamma_ramp *gamma_ramp,
+       const struct gamma_parameters *params)
+{
+       struct dce110_ipp *ipp110 = TO_DCE110_IPP(ipp);
+
+       switch (gamma_ramp->type) {
+       case GAMMA_RAMP_RBG256X3X16:
+               return set_legacy_input_gamma_ramp_rgb256x3x16(
+                               ipp110, gamma_ramp, params);
+       case GAMMA_RAMP_DXGI_1:
+               return set_legacy_input_gamma_ramp_dxgi1(
+                               ipp110, gamma_ramp, params);
+       default:
+               ASSERT_CRITICAL(false);
+               return false;
+       }
+}
+
+bool dce110_ipp_set_palette(
+       struct input_pixel_processor *ipp,
+       const struct dev_c_lut *palette,
+       uint32_t start,
+       uint32_t length,
+       enum pixel_format surface_pixel_format)
+{
+       struct dce110_ipp *ipp110 = TO_DCE110_IPP(ipp);
+       uint32_t i;
+
+       if (((start + length) > MAX_INPUT_LUT_ENTRY) || (NULL == palette)) {
+               BREAK_TO_DEBUGGER();
+               /* wrong input */
+               return false;
+       }
+
+       for (i = start; i < start + length; i++) {
+               ipp110->saved_palette[i] = palette[i];
+               ipp110->saved_palette[i] = palette[i];
+               ipp110->saved_palette[i] = palette[i];
+       }
+
+       return set_default_gamma(ipp110, surface_pixel_format);
+}
+
+bool dce110_ipp_set_degamma(
+       struct input_pixel_processor *ipp,
+       const struct gamma_parameters *params,
+       bool force_bypass)
+{
+       struct dce110_ipp *ipp110 = TO_DCE110_IPP(ipp);
+
+       set_degamma(ipp110, params, force_bypass);
+
+       return true;
+}
+
+void dce110_ipp_program_prescale(
+       struct input_pixel_processor *ipp,
+       enum pixel_format pixel_format)
+{
+       struct dce110_ipp *ipp110 = TO_DCE110_IPP(ipp);
+
+       program_prescale(ipp110, pixel_format);
+}
+
+void dce110_ipp_set_legacy_input_gamma_mode(
+               struct input_pixel_processor *ipp,
+               bool is_legacy)
+{
+       struct dce110_ipp *ipp110 = TO_DCE110_IPP(ipp);
+
+       set_legacy_input_gamma_mode(ipp110, is_legacy);
+}
+
+static void set_lut_inc(
+       struct dce110_ipp *ipp110,
+       uint8_t inc,
+       bool is_float,
+       bool is_signed)
+{
+       const uint32_t addr = DCP_REG(mmDC_LUT_CONTROL);
+
+       uint32_t value = dm_read_reg(ipp110->base.ctx, addr);
+
+       set_reg_field_value(
+               value,
+               inc,
+               DC_LUT_CONTROL,
+               DC_LUT_INC_R);
+
+       set_reg_field_value(
+               value,
+               inc,
+               DC_LUT_CONTROL,
+               DC_LUT_INC_G);
+
+       set_reg_field_value(
+               value,
+               inc,
+               DC_LUT_CONTROL,
+               DC_LUT_INC_B);
+
+       set_reg_field_value(
+               value,
+               is_float,
+               DC_LUT_CONTROL,
+               DC_LUT_DATA_R_FLOAT_POINT_EN);
+
+       set_reg_field_value(
+               value,
+               is_float,
+               DC_LUT_CONTROL,
+               DC_LUT_DATA_G_FLOAT_POINT_EN);
+
+       set_reg_field_value(
+               value,
+               is_float,
+               DC_LUT_CONTROL,
+               DC_LUT_DATA_B_FLOAT_POINT_EN);
+
+       set_reg_field_value(
+               value,
+               is_signed,
+               DC_LUT_CONTROL,
+               DC_LUT_DATA_R_SIGNED_EN);
+
+       set_reg_field_value(
+               value,
+               is_signed,
+               DC_LUT_CONTROL,
+               DC_LUT_DATA_G_SIGNED_EN);
+
+       set_reg_field_value(
+               value,
+               is_signed,
+               DC_LUT_CONTROL,
+               DC_LUT_DATA_B_SIGNED_EN);
+
+       dm_write_reg(ipp110->base.ctx, addr, value);
+}
+
+void dce110_helper_select_lut(struct dce110_ipp *ipp110)
+{
+       uint32_t value = 0;
+
+       set_lut_inc(ipp110, 0, false, false);
+
+       {
+               const uint32_t addr = DCP_REG(mmDC_LUT_WRITE_EN_MASK);
+
+               value = dm_read_reg(ipp110->base.ctx, addr);
+
+               /* enable all */
+               set_reg_field_value(
+                       value,
+                       0x7,
+                       DC_LUT_WRITE_EN_MASK,
+                       DC_LUT_WRITE_EN_MASK);
+
+               dm_write_reg(ipp110->base.ctx, addr, value);
+       }
+
+       {
+               const uint32_t addr = DCP_REG(mmDC_LUT_RW_MODE);
+
+               value = dm_read_reg(ipp110->base.ctx, addr);
+
+               set_reg_field_value(
+                       value,
+                       0,
+                       DC_LUT_RW_MODE,
+                       DC_LUT_RW_MODE);
+
+               dm_write_reg(ipp110->base.ctx, addr, value);
+       }
+
+       {
+               const uint32_t addr = DCP_REG(mmDC_LUT_CONTROL);
+
+               value = dm_read_reg(ipp110->base.ctx, addr);
+
+               /* 00 - new u0.12 */
+               set_reg_field_value(
+                       value,
+                       3,
+                       DC_LUT_CONTROL,
+                       DC_LUT_DATA_R_FORMAT);
+
+               set_reg_field_value(
+                       value,
+                       3,
+                       DC_LUT_CONTROL,
+                       DC_LUT_DATA_G_FORMAT);
+
+               set_reg_field_value(
+                       value,
+                       3,
+                       DC_LUT_CONTROL,
+                       DC_LUT_DATA_B_FORMAT);
+
+               dm_write_reg(ipp110->base.ctx, addr, value);
+       }
+
+       {
+               const uint32_t addr = DCP_REG(mmDC_LUT_RW_INDEX);
+
+               value = dm_read_reg(ipp110->base.ctx, addr);
+
+               set_reg_field_value(
+                       value,
+                       0,
+                       DC_LUT_RW_INDEX,
+                       DC_LUT_RW_INDEX);
+
+               dm_write_reg(ipp110->base.ctx, addr, value);
+       }
+}
+
+static void program_black_offsets(
+       struct dce110_ipp *ipp110,
+       struct dev_c_lut16 *offset)
+{
+       dm_write_reg(ipp110->base.ctx,
+               DCP_REG(mmDC_LUT_BLACK_OFFSET_RED),
+               offset->red);
+       dm_write_reg(ipp110->base.ctx,
+               DCP_REG(mmDC_LUT_BLACK_OFFSET_GREEN),
+               offset->green);
+       dm_write_reg(ipp110->base.ctx,
+               DCP_REG(mmDC_LUT_BLACK_OFFSET_BLUE),
+               offset->blue);
+}
+
+static void program_white_offsets(
+       struct dce110_ipp *ipp110,
+       struct dev_c_lut16 *offset)
+{
+       dm_write_reg(ipp110->base.ctx,
+               DCP_REG(mmDC_LUT_WHITE_OFFSET_RED),
+               offset->red);
+       dm_write_reg(ipp110->base.ctx,
+               DCP_REG(mmDC_LUT_WHITE_OFFSET_GREEN),
+               offset->green);
+       dm_write_reg(ipp110->base.ctx,
+               DCP_REG(mmDC_LUT_WHITE_OFFSET_BLUE),
+               offset->blue);
+}
+
+void dce110_helper_program_black_white_offset(
+       struct dce110_ipp *ipp110,
+       enum pixel_format surface_pixel_format)
+{
+       struct dev_c_lut16 black_offset;
+       struct dev_c_lut16 white_offset;
+
+       /* get black offset */
+
+       switch (surface_pixel_format) {
+       case PIXEL_FORMAT_FP16:
+               /* sRGB gamut, [0.0...1.0] */
+               black_offset.red = 0;
+               black_offset.green = 0;
+               black_offset.blue = 0;
+       break;
+
+       case PIXEL_FORMAT_ARGB2101010_XRBIAS:
+               /* [-1.0...3.0] */
+               black_offset.red = 0x100;
+               black_offset.green = 0x100;
+               black_offset.blue = 0x100;
+       break;
+
+       default:
+               black_offset.red = 0;
+               black_offset.green = 0;
+               black_offset.blue = 0;
+       }
+
+       /* get white offset */
+
+       switch (surface_pixel_format) {
+       case PIXEL_FORMAT_FP16:
+               white_offset.red = 0x3BFF;
+               white_offset.green = 0x3BFF;
+               white_offset.blue = 0x3BFF;
+       break;
+
+       case PIXEL_FORMAT_ARGB2101010_XRBIAS:
+               white_offset.red = 0x37E;
+               white_offset.green = 0x37E;
+               white_offset.blue = 0x37E;
+               break;
+
+       case PIXEL_FORMAT_ARGB8888:
+               white_offset.red = 0xFF;
+               white_offset.green = 0xFF;
+               white_offset.blue = 0xFF;
+               break;
+
+       default:
+               white_offset.red = 0x3FF;
+               white_offset.green = 0x3FF;
+               white_offset.blue = 0x3FF;
+       }
+
+       program_black_offsets(ipp110, &black_offset);
+       program_white_offsets(ipp110, &white_offset);
+}
+
+static void program_lut_gamma(
+       struct dce110_ipp *ipp110,
+       const struct dev_c_lut16 *gamma,
+       const struct gamma_parameters *params)
+{
+       uint32_t i = 0;
+       uint32_t value = 0;
+       uint32_t addr;
+
+       {
+               uint8_t max_tries = 10;
+               uint8_t counter = 0;
+
+               /* Power on LUT memory */
+               value = dm_read_reg(
+                               ipp110->base.ctx, DCP_REG(mmDCFE_MEM_PWR_CTRL));
+
+               set_reg_field_value(
+                       value,
+                       1,
+                       DCFE_MEM_PWR_CTRL,
+                       DCP_REGAMMA_MEM_PWR_DIS);
+
+               dm_write_reg(
+                       ipp110->base.ctx, DCP_REG(mmDCFE_MEM_PWR_CTRL), value);
+
+               while (counter < max_tries) {
+                       value =
+                               dm_read_reg(
+                                       ipp110->base.ctx,
+                                       DCP_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(ipp110->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__);
+               }
+       }
+
+       dce110_helper_program_black_white_offset(ipp110, 
params->surface_pixel_format);
+
+       dce110_helper_select_lut(ipp110);
+
+       if (params->surface_pixel_format == PIXEL_FORMAT_INDEX8) {
+               addr = DCP_REG(mmDC_LUT_SEQ_COLOR);
+
+               do {
+                       struct dev_c_lut *index =
+                               ipp110->saved_palette + i;
+
+                       set_reg_field_value(
+                               value,
+                               gamma[index->red].red,
+                               DC_LUT_SEQ_COLOR,
+                               DC_LUT_SEQ_COLOR);
+                       dm_write_reg(ipp110->base.ctx, addr, value);
+
+
+                       set_reg_field_value(
+                               value,
+                               gamma[index->green].green,
+                               DC_LUT_SEQ_COLOR,
+                               DC_LUT_SEQ_COLOR);
+                       dm_write_reg(ipp110->base.ctx, addr, value);
+
+
+                       set_reg_field_value(
+                               value,
+                               gamma[index->blue].blue,
+                               DC_LUT_SEQ_COLOR,
+                               DC_LUT_SEQ_COLOR);
+                       dm_write_reg(ipp110->base.ctx, addr, value);
+
+                       ++i;
+               } while (i != RGB_256X3X16);
+       } else {
+               addr = DCP_REG(mmDC_LUT_SEQ_COLOR);
+
+               do {
+                       set_reg_field_value(
+                               value,
+                               gamma[i].red,
+                               DC_LUT_SEQ_COLOR,
+                               DC_LUT_SEQ_COLOR);
+                       dm_write_reg(ipp110->base.ctx, addr, value);
+
+
+                       set_reg_field_value(
+                               value,
+                               gamma[i].green,
+                               DC_LUT_SEQ_COLOR,
+                               DC_LUT_SEQ_COLOR);
+                       dm_write_reg(ipp110->base.ctx, addr, value);
+
+
+                       set_reg_field_value(
+                               value,
+                               gamma[i].blue,
+                               DC_LUT_SEQ_COLOR,
+                               DC_LUT_SEQ_COLOR);
+                       dm_write_reg(ipp110->base.ctx, addr, value);
+
+                       ++i;
+               } while (i != RGB_256X3X16);
+       }
+
+       /*  we are done with DCP LUT memory; re-enable low power mode */
+       value = dm_read_reg(ipp110->base.ctx, DCP_REG(mmDCFE_MEM_PWR_CTRL));
+
+       set_reg_field_value(
+               value,
+               0,
+               DCFE_MEM_PWR_CTRL,
+               DCP_REGAMMA_MEM_PWR_DIS);
+
+       dm_write_reg(ipp110->base.ctx, DCP_REG(mmDCFE_MEM_PWR_CTRL), value);
+}
+
+static void program_prescale(
+       struct dce110_ipp *ipp110,
+       enum pixel_format pixel_format)
+{
+       uint32_t prescale_control;
+       uint32_t prescale_values_grph_r = 0;
+       uint32_t prescale_values_grph_g = 0;
+       uint32_t prescale_values_grph_b = 0;
+
+       uint32_t prescale_num;
+       uint32_t prescale_denom = 1;
+       uint16_t prescale_hw;
+       uint32_t bias_num = 0;
+       uint32_t bias_denom = 1;
+       uint16_t bias_hw;
+
+       const uint32_t addr_control = DCP_REG(mmPRESCALE_GRPH_CONTROL);
+
+       prescale_control = dm_read_reg(ipp110->base.ctx, addr_control);
+
+       set_reg_field_value(
+               prescale_control,
+               0,
+               PRESCALE_GRPH_CONTROL,
+               GRPH_PRESCALE_BYPASS);
+
+       switch (pixel_format) {
+       case PIXEL_FORMAT_RGB565:
+               prescale_num = 64;
+               prescale_denom = 63;
+       break;
+
+       case PIXEL_FORMAT_ARGB8888:
+               /* This function should only be called when using regamma
+                * and bypassing legacy INPUT GAMMA LUT (function name is
+                * misleading)
+                */
+               prescale_num = 256;
+               prescale_denom = 255;
+       break;
+
+       case PIXEL_FORMAT_ARGB2101010:
+               prescale_num = 1024;
+               prescale_denom = 1023;
+       break;
+
+       case PIXEL_FORMAT_ARGB2101010_XRBIAS:
+               prescale_num = 1024;
+               prescale_denom = 510;
+               bias_num = 384;
+               bias_denom = 1024;
+       break;
+
+       case PIXEL_FORMAT_FP16:
+               prescale_num = 1;
+       break;
+
+       default:
+               prescale_num = 1;
+
+               set_reg_field_value(
+                       prescale_control,
+                       1,
+                       PRESCALE_GRPH_CONTROL,
+                       GRPH_PRESCALE_BYPASS);
+       }
+
+       prescale_hw = fixed_point_to_int_frac(
+               dal_fixed31_32_from_fraction(prescale_num, prescale_denom),
+               2, 13);
+
+       bias_hw = fixed_point_to_int_frac(
+               dal_fixed31_32_from_fraction(bias_num, bias_denom),
+               2, 13);
+
+
+       set_reg_field_value(
+               prescale_values_grph_r,
+               prescale_hw,
+               PRESCALE_VALUES_GRPH_R,
+               GRPH_PRESCALE_SCALE_R);
+
+       set_reg_field_value(
+               prescale_values_grph_r,
+               bias_hw,
+               PRESCALE_VALUES_GRPH_R,
+               GRPH_PRESCALE_BIAS_R);
+
+
+       set_reg_field_value(
+               prescale_values_grph_g,
+               prescale_hw,
+               PRESCALE_VALUES_GRPH_G,
+               GRPH_PRESCALE_SCALE_G);
+
+       set_reg_field_value(
+               prescale_values_grph_g,
+               bias_hw,
+               PRESCALE_VALUES_GRPH_G,
+               GRPH_PRESCALE_BIAS_G);
+
+
+       set_reg_field_value(
+               prescale_values_grph_b,
+               prescale_hw,
+               PRESCALE_VALUES_GRPH_B,
+               GRPH_PRESCALE_SCALE_B);
+
+       set_reg_field_value(
+               prescale_values_grph_b,
+               bias_hw,
+               PRESCALE_VALUES_GRPH_B,
+               GRPH_PRESCALE_BIAS_B);
+
+       dm_write_reg(ipp110->base.ctx,
+               addr_control, prescale_control);
+
+       {
+               dm_write_reg(ipp110->base.ctx,
+                               DCP_REG(mmPRESCALE_VALUES_GRPH_R),
+                               prescale_values_grph_r);
+       }
+
+       {
+               dm_write_reg(ipp110->base.ctx,
+                               DCP_REG(mmPRESCALE_VALUES_GRPH_G),
+                               prescale_values_grph_g);
+       }
+
+       {
+               dm_write_reg(ipp110->base.ctx,
+                               DCP_REG(mmPRESCALE_VALUES_GRPH_B),
+                               prescale_values_grph_b);
+       }
+}
+
+static void set_legacy_input_gamma_mode(
+       struct dce110_ipp *ipp110,
+       bool is_legacy)
+{
+       const uint32_t addr = DCP_REG(mmINPUT_GAMMA_CONTROL);
+       uint32_t value = dm_read_reg(ipp110->base.ctx, addr);
+
+       set_reg_field_value(
+               value,
+               !is_legacy,
+               INPUT_GAMMA_CONTROL,
+               GRPH_INPUT_GAMMA_MODE);
+
+       dm_write_reg(ipp110->base.ctx, addr, value);
+}
+
+static bool set_legacy_input_gamma_ramp_rgb256x3x16(
+       struct dce110_ipp *ipp110,
+       const struct gamma_ramp *gamma_ramp,
+       const struct gamma_parameters *params)
+{
+       struct dev_c_lut16 *gamma16 =
+               dm_alloc(
+                       ipp110->base.ctx,
+                       sizeof(struct dev_c_lut16) * MAX_INPUT_LUT_ENTRY);
+
+       if (!gamma16)
+               return false;
+
+       convert_256_lut_entries_to_gxo_format(
+               &gamma_ramp->gamma_ramp_rgb256x3x16, gamma16);
+
+       if ((params->surface_pixel_format != PIXEL_FORMAT_ARGB2101010) &&
+               (params->surface_pixel_format !=
+                       PIXEL_FORMAT_ARGB2101010_XRBIAS) &&
+               (params->surface_pixel_format != PIXEL_FORMAT_FP16)) {
+               program_lut_gamma(ipp110, gamma16, params);
+               dm_free(ipp110->base.ctx, gamma16);
+               return true;
+       }
+
+       /* TODO process DirectX-specific formats*/
+       dm_free(ipp110->base.ctx, gamma16);
+       return false;
+}
+
+static bool set_legacy_input_gamma_ramp_dxgi1(
+       struct dce110_ipp *ipp110,
+       const struct gamma_ramp *gamma_ramp,
+       const struct gamma_parameters *params)
+{
+       struct dev_c_lut16 *gamma16 =
+               dm_alloc(
+                       ipp110->base.ctx,
+                       sizeof(struct dev_c_lut16) * MAX_INPUT_LUT_ENTRY);
+
+       if (!gamma16)
+               return false;
+
+       convert_udx_gamma_entries_to_gxo_format(
+               &gamma_ramp->gamma_ramp_dxgi1, gamma16);
+
+       if ((params->surface_pixel_format != PIXEL_FORMAT_ARGB2101010) &&
+               (params->surface_pixel_format !=
+                       PIXEL_FORMAT_ARGB2101010_XRBIAS) &&
+               (params->surface_pixel_format != PIXEL_FORMAT_FP16)) {
+               program_lut_gamma(ipp110, gamma16, params);
+               dm_free(ipp110->base.ctx, gamma16);
+               return true;
+       }
+
+       /* TODO process DirectX-specific formats*/
+       dm_free(ipp110->base.ctx, gamma16);
+       return false;
+}
+
+static bool set_default_gamma(
+       struct dce110_ipp *ipp110,
+       enum pixel_format surface_pixel_format)
+{
+       uint32_t i;
+
+       struct dev_c_lut16 *gamma16 = NULL;
+       struct gamma_parameters *params = NULL;
+
+       gamma16 = dm_alloc(
+                       ipp110->base.ctx,
+                       sizeof(struct dev_c_lut16) * MAX_INPUT_LUT_ENTRY);
+
+       if (!gamma16)
+               return false;
+
+       params = dm_alloc(ipp110->base.ctx, sizeof(*params));
+
+       if (!params) {
+               dm_free(ipp110->base.ctx, gamma16);
+               return false;
+       }
+
+       for (i = 0; i < MAX_INPUT_LUT_ENTRY; i++) {
+               gamma16[i].red = gamma16[i].green =
+                       gamma16[i].blue = (uint16_t) (i << 8);
+       }
+
+       params->surface_pixel_format = surface_pixel_format;
+       params->regamma_adjust_type = GRAPHICS_REGAMMA_ADJUST_HW;
+       params->degamma_adjust_type = GRAPHICS_DEGAMMA_ADJUST_HW;
+       params->selected_gamma_lut = GRAPHICS_GAMMA_LUT_REGAMMA;
+       params->disable_adjustments = false;
+
+       params->regamma.features.value = 0;
+
+       params->regamma.features.bits.GAMMA_RAMP_ARRAY = 0;
+       params->regamma.features.bits.GRAPHICS_DEGAMMA_SRGB = 1;
+       params->regamma.features.bits.OVERLAY_DEGAMMA_SRGB = 1;
+
+       for (i = 0; i < 3; i++) {
+               params->regamma.gamma_coeff.a0[i] = 31308;
+               params->regamma.gamma_coeff.a1[i] = 12920;
+               params->regamma.gamma_coeff.a2[i] = 55;
+               params->regamma.gamma_coeff.a3[i] = 55;
+               params->regamma.gamma_coeff.gamma[i] = 2400;
+
+       }
+
+       program_lut_gamma(ipp110, gamma16, params);
+
+       dm_free(ipp110->base.ctx, gamma16);
+       dm_free(ipp110->base.ctx, params);
+
+       return true;
+}
+
+static void set_degamma(
+       struct dce110_ipp *ipp110,
+       const struct gamma_parameters *params,
+       bool force_bypass)
+{
+       uint32_t value;
+       const uint32_t addr = DCP_REG(mmDEGAMMA_CONTROL);
+       uint32_t degamma_type =
+               params->regamma.features.bits.GRAPHICS_DEGAMMA_SRGB == 1 ?
+                       1 : 2;
+
+       value = dm_read_reg(ipp110->base.ctx, addr);
+
+       /* if by pass - no degamma
+        * when legacy and regamma LUT's we do degamma */
+       if (params->degamma_adjust_type == GRAPHICS_DEGAMMA_ADJUST_BYPASS ||
+               (params->surface_pixel_format == PIXEL_FORMAT_FP16 &&
+                       params->selected_gamma_lut ==
+                               GRAPHICS_GAMMA_LUT_REGAMMA))
+               degamma_type = 0;
+
+       if (force_bypass)
+               degamma_type = 0;
+
+       set_reg_field_value(
+               value,
+               degamma_type,
+               DEGAMMA_CONTROL,
+               GRPH_DEGAMMA_MODE);
+
+       set_reg_field_value(
+               value,
+               degamma_type,
+               DEGAMMA_CONTROL,
+               CURSOR_DEGAMMA_MODE);
+
+       set_reg_field_value(
+               value,
+               degamma_type,
+               DEGAMMA_CONTROL,
+               CURSOR2_DEGAMMA_MODE);
+
+       dm_write_reg(ipp110->base.ctx, addr, value);
+}
+
-- 
2.1.4

Reply via email to