summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/amd/display/dc/dce110/dce110_opp_regamma.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/amd/display/dc/dce110/dce110_opp_regamma.c')
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce110/dce110_opp_regamma.c537
1 files changed, 537 insertions, 0 deletions
diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_opp_regamma.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_opp_regamma.c
new file mode 100644
index 000000000000..62051abcfe2f
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_opp_regamma.c
@@ -0,0 +1,537 @@
+/*
+ * 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
+
+};
+
+/*
+ *****************************************************************************
+ * 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,
+ const struct pwl_params *params)
+{
+ const struct gamma_curve *curve;
+ uint32_t value = 0;
+
+ {
+ set_reg_field_value(
+ value,
+ params->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,
+ params->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,
+ params->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,
+ params->arr_points[2].custom_float_slope,
+ REGAMMA_CNTLA_END_CNTL2,
+ REGAMMA_CNTLA_EXP_REGION_END_BASE);
+
+ set_reg_field_value(
+ value,
+ params->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 = params->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 pwl_params *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) {
+ dm_logger_write(opp110->base.ctx->logger, LOG_WARNING,
+ "%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;
+
+ const struct pwl_result_data *rgb = params->rgb_resulted;
+
+ while (i != params->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);
+}
+
+bool dce110_opp_program_regamma_pwl(
+ struct output_pixel_processor *opp,
+ const struct pwl_params *params)
+{
+ struct dce110_opp *opp110 = TO_DCE110_OPP(opp);
+
+ /* Setup regions */
+ regamma_config_regions_and_segments(opp110, params);
+
+ /* Program PWL */
+ program_pwl(opp110, params);
+
+ return true;
+}
+
+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);
+}
+
+void dce110_opp_set_regamma_mode(struct output_pixel_processor *opp,
+ enum opp_regamma mode)
+{
+ struct dce110_opp *opp110 = TO_DCE110_OPP(opp);
+ uint32_t value = dm_read_reg(opp110->base.ctx,
+ DCP_REG(mmREGAMMA_CONTROL));
+
+ set_reg_field_value(
+ value,
+ mode,
+ REGAMMA_CONTROL,
+ GRPH_REGAMMA_MODE);
+
+ dm_write_reg(opp110->base.ctx, DCP_REG(mmREGAMMA_CONTROL),
+ value);
+}