diff options
Diffstat (limited to 'drivers/gpu/drm/amd/display/dc/dce80/dce80_opp_regamma.c')
-rw-r--r-- | drivers/gpu/drm/amd/display/dc/dce80/dce80_opp_regamma.c | 543 |
1 files changed, 543 insertions, 0 deletions
diff --git a/drivers/gpu/drm/amd/display/dc/dce80/dce80_opp_regamma.c b/drivers/gpu/drm/amd/display/dc/dce80/dce80_opp_regamma.c new file mode 100644 index 000000000000..648e3ef35d91 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dce80/dce80_opp_regamma.c @@ -0,0 +1,543 @@ +/* + * 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 DCE8 register header files */ +#include "dce/dce_8_0_d.h" +#include "dce/dce_8_0_sh_mask.h" + +#include "dce80_opp.h" +#include "gamma_types.h" + +#define DCP_REG(reg)\ + (reg + opp80->offsets.dcp_offset) + +#define DCFE_REG(reg)\ + (reg + opp80->offsets.crtc_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; +}; + +/* + ***************************************************************************** + * 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 dce80_opp *opp80, 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(opp80->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(opp80->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(opp80->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(opp80->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( + opp80->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(opp80->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(opp80->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(opp80->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(opp80->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(opp80->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(opp80->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(opp80->base.ctx, + DCP_REG(mmREGAMMA_CNTLA_REGION_14_15), + value); + } +} + +static void program_pwl( + struct dce80_opp *opp80, + 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(opp80->base.ctx, + DCFE_REG(mmDCFE_MEM_LIGHT_SLEEP_CNTL)); + + set_reg_field_value( + value, + 1, + DCFE_MEM_LIGHT_SLEEP_CNTL, + REGAMMA_LUT_LIGHT_SLEEP_DIS); + + dm_write_reg(opp80->base.ctx, + DCFE_REG(mmDCFE_MEM_LIGHT_SLEEP_CNTL), value); + + while (counter < max_tries) { + value = + dm_read_reg( + opp80->base.ctx, + DCFE_REG(mmDCFE_MEM_LIGHT_SLEEP_CNTL)); + + if (get_reg_field_value( + value, + DCFE_MEM_LIGHT_SLEEP_CNTL, + REGAMMA_LUT_MEM_PWR_STATE) == 0) + break; + + ++counter; + } + + if (counter == max_tries) { + dm_logger_write(opp80->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(opp80->base.ctx, + DCP_REG(mmREGAMMA_LUT_WRITE_EN_MASK), value); + dm_write_reg(opp80->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(opp80->base.ctx, addr, rgb->red_reg); + dm_write_reg(opp80->base.ctx, addr, rgb->green_reg); + dm_write_reg(opp80->base.ctx, addr, rgb->blue_reg); + + dm_write_reg(opp80->base.ctx, addr, + rgb->delta_red_reg); + dm_write_reg(opp80->base.ctx, addr, + rgb->delta_green_reg); + dm_write_reg(opp80->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(opp80->base.ctx, + DCFE_REG(mmDCFE_MEM_LIGHT_SLEEP_CNTL)); + + set_reg_field_value( + value, + 0, + DCFE_MEM_LIGHT_SLEEP_CNTL, + REGAMMA_LUT_LIGHT_SLEEP_DIS); + + dm_write_reg(opp80->base.ctx, DCFE_REG(mmDCFE_MEM_LIGHT_SLEEP_CNTL), + value); +} + +void dce80_opp_power_on_regamma_lut( + struct output_pixel_processor *opp, + bool power_on) +{ + struct dce80_opp *opp80 = TO_DCE80_OPP(opp); + + uint32_t value = + dm_read_reg(opp->ctx, DCFE_REG(mmDCFE_MEM_LIGHT_SLEEP_CNTL)); + + set_reg_field_value( + value, + power_on, + DCFE_MEM_LIGHT_SLEEP_CNTL, + REGAMMA_LUT_LIGHT_SLEEP_DIS); + + set_reg_field_value( + value, + power_on, + DCFE_MEM_LIGHT_SLEEP_CNTL, + DCP_LUT_LIGHT_SLEEP_DIS); + + dm_write_reg(opp->ctx, DCFE_REG(mmDCFE_MEM_LIGHT_SLEEP_CNTL), value); +} + +bool dce80_opp_program_regamma_pwl( + struct output_pixel_processor *opp, + const struct pwl_params *params) +{ + + struct dce80_opp *opp80 = TO_DCE80_OPP(opp); + + regamma_config_regions_and_segments(opp80, params); + + program_pwl(opp80, params); + + return true; +} + +void dce80_opp_set_regamma_mode(struct output_pixel_processor *opp, + enum opp_regamma mode) +{ + struct dce80_opp *opp80 = TO_DCE80_OPP(opp); + uint32_t value = dm_read_reg(opp80->base.ctx, + DCP_REG(mmREGAMMA_CONTROL)); + + set_reg_field_value( + value, + mode, + REGAMMA_CONTROL, + GRPH_REGAMMA_MODE); + + dm_write_reg(opp80->base.ctx, DCP_REG(mmREGAMMA_CONTROL), value); +} |