/* * 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_transform_v.h" static void power_on_lut(struct transform *xfm, bool power_on, bool inputgamma, bool regamma) { uint32_t value = dm_read_reg(xfm->ctx, mmDCFEV_MEM_PWR_CTRL); int i; if (power_on) { if (inputgamma) set_reg_field_value( value, 1, DCFEV_MEM_PWR_CTRL, COL_MAN_INPUT_GAMMA_MEM_PWR_DIS); if (regamma) set_reg_field_value( value, 1, DCFEV_MEM_PWR_CTRL, COL_MAN_GAMMA_CORR_MEM_PWR_DIS); } else { if (inputgamma) set_reg_field_value( value, 0, DCFEV_MEM_PWR_CTRL, COL_MAN_INPUT_GAMMA_MEM_PWR_DIS); if (regamma) set_reg_field_value( value, 0, DCFEV_MEM_PWR_CTRL, COL_MAN_GAMMA_CORR_MEM_PWR_DIS); } dm_write_reg(xfm->ctx, mmDCFEV_MEM_PWR_CTRL, value); for (i = 0; i < 3; i++) { value = dm_read_reg(xfm->ctx, mmDCFEV_MEM_PWR_CTRL); if (get_reg_field_value(value, DCFEV_MEM_PWR_CTRL, COL_MAN_INPUT_GAMMA_MEM_PWR_DIS) && get_reg_field_value(value, DCFEV_MEM_PWR_CTRL, COL_MAN_GAMMA_CORR_MEM_PWR_DIS)) break; udelay(2); } } static void set_bypass_input_gamma(struct dce_transform *xfm_dce) { uint32_t value; value = dm_read_reg(xfm_dce->base.ctx, mmCOL_MAN_INPUT_GAMMA_CONTROL1); set_reg_field_value( value, 0, COL_MAN_INPUT_GAMMA_CONTROL1, INPUT_GAMMA_MODE); dm_write_reg(xfm_dce->base.ctx, mmCOL_MAN_INPUT_GAMMA_CONTROL1, value); } static void configure_regamma_mode(struct dce_transform *xfm_dce, uint32_t mode) { uint32_t value = 0; set_reg_field_value( value, mode, GAMMA_CORR_CONTROL, GAMMA_CORR_MODE); dm_write_reg(xfm_dce->base.ctx, mmGAMMA_CORR_CONTROL, 0); } /* ***************************************************************************** * 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 dce_transform *xfm_dce, 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, GAMMA_CORR_CNTLA_START_CNTL, GAMMA_CORR_CNTLA_EXP_REGION_START); set_reg_field_value( value, 0, GAMMA_CORR_CNTLA_START_CNTL, GAMMA_CORR_CNTLA_EXP_REGION_START_SEGMENT); dm_write_reg(xfm_dce->base.ctx, mmGAMMA_CORR_CNTLA_START_CNTL, value); } { value = 0; set_reg_field_value( value, params->arr_points[0].custom_float_slope, GAMMA_CORR_CNTLA_SLOPE_CNTL, GAMMA_CORR_CNTLA_EXP_REGION_LINEAR_SLOPE); dm_write_reg(xfm_dce->base.ctx, mmGAMMA_CORR_CNTLA_SLOPE_CNTL, value); } { value = 0; set_reg_field_value( value, params->arr_points[1].custom_float_x, GAMMA_CORR_CNTLA_END_CNTL1, GAMMA_CORR_CNTLA_EXP_REGION_END); dm_write_reg(xfm_dce->base.ctx, mmGAMMA_CORR_CNTLA_END_CNTL1, value); } { value = 0; set_reg_field_value( value, params->arr_points[2].custom_float_slope, GAMMA_CORR_CNTLA_END_CNTL2, GAMMA_CORR_CNTLA_EXP_REGION_END_BASE); set_reg_field_value( value, params->arr_points[1].custom_float_y, GAMMA_CORR_CNTLA_END_CNTL2, GAMMA_CORR_CNTLA_EXP_REGION_END_SLOPE); dm_write_reg(xfm_dce->base.ctx, mmGAMMA_CORR_CNTLA_END_CNTL2, value); } curve = params->arr_curve_points; { value = 0; set_reg_field_value( value, curve[0].offset, GAMMA_CORR_CNTLA_REGION_0_1, GAMMA_CORR_CNTLA_EXP_REGION0_LUT_OFFSET); set_reg_field_value( value, curve[0].segments_num, GAMMA_CORR_CNTLA_REGION_0_1, GAMMA_CORR_CNTLA_EXP_REGION0_NUM_SEGMENTS); set_reg_field_value( value, curve[1].offset, GAMMA_CORR_CNTLA_REGION_0_1, GAMMA_CORR_CNTLA_EXP_REGION1_LUT_OFFSET); set_reg_field_value( value, curve[1].segments_num, GAMMA_CORR_CNTLA_REGION_0_1, GAMMA_CORR_CNTLA_EXP_REGION1_NUM_SEGMENTS); dm_write_reg( xfm_dce->base.ctx, mmGAMMA_CORR_CNTLA_REGION_0_1, value); } curve += 2; { value = 0; set_reg_field_value( value, curve[0].offset, GAMMA_CORR_CNTLA_REGION_2_3, GAMMA_CORR_CNTLA_EXP_REGION2_LUT_OFFSET); set_reg_field_value( value, curve[0].segments_num, GAMMA_CORR_CNTLA_REGION_2_3, GAMMA_CORR_CNTLA_EXP_REGION2_NUM_SEGMENTS); set_reg_field_value( value, curve[1].offset, GAMMA_CORR_CNTLA_REGION_2_3, GAMMA_CORR_CNTLA_EXP_REGION3_LUT_OFFSET); set_reg_field_value( value, curve[1].segments_num, GAMMA_CORR_CNTLA_REGION_2_3, GAMMA_CORR_CNTLA_EXP_REGION3_NUM_SEGMENTS); dm_write_reg(xfm_dce->base.ctx, mmGAMMA_CORR_CNTLA_REGION_2_3, value); } curve += 2; { value = 0; set_reg_field_value( value, curve[0].offset, GAMMA_CORR_CNTLA_REGION_4_5, GAMMA_CORR_CNTLA_EXP_REGION4_LUT_OFFSET); set_reg_field_value( value, curve[0].segments_num, GAMMA_CORR_CNTLA_REGION_4_5, GAMMA_CORR_CNTLA_EXP_REGION4_NUM_SEGMENTS); set_reg_field_value( value, curve[1].offset, GAMMA_CORR_CNTLA_REGION_4_5, GAMMA_CORR_CNTLA_EXP_REGION5_LUT_OFFSET); set_reg_field_value( value, curve[1].segments_num, GAMMA_CORR_CNTLA_REGION_4_5, GAMMA_CORR_CNTLA_EXP_REGION5_NUM_SEGMENTS); dm_write_reg(xfm_dce->base.ctx, mmGAMMA_CORR_CNTLA_REGION_4_5, value); } curve += 2; { value = 0; set_reg_field_value( value, curve[0].offset, GAMMA_CORR_CNTLA_REGION_6_7, GAMMA_CORR_CNTLA_EXP_REGION6_LUT_OFFSET); set_reg_field_value( value, curve[0].segments_num, GAMMA_CORR_CNTLA_REGION_6_7, GAMMA_CORR_CNTLA_EXP_REGION6_NUM_SEGMENTS); set_reg_field_value( value, curve[1].offset, GAMMA_CORR_CNTLA_REGION_6_7, GAMMA_CORR_CNTLA_EXP_REGION7_LUT_OFFSET); set_reg_field_value( value, curve[1].segments_num, GAMMA_CORR_CNTLA_REGION_6_7, GAMMA_CORR_CNTLA_EXP_REGION7_NUM_SEGMENTS); dm_write_reg(xfm_dce->base.ctx, mmGAMMA_CORR_CNTLA_REGION_6_7, value); } curve += 2; { value = 0; set_reg_field_value( value, curve[0].offset, GAMMA_CORR_CNTLA_REGION_8_9, GAMMA_CORR_CNTLA_EXP_REGION8_LUT_OFFSET); set_reg_field_value( value, curve[0].segments_num, GAMMA_CORR_CNTLA_REGION_8_9, GAMMA_CORR_CNTLA_EXP_REGION8_NUM_SEGMENTS); set_reg_field_value( value, curve[1].offset, GAMMA_CORR_CNTLA_REGION_8_9, GAMMA_CORR_CNTLA_EXP_REGION9_LUT_OFFSET); set_reg_field_value( value, curve[1].segments_num, GAMMA_CORR_CNTLA_REGION_8_9, GAMMA_CORR_CNTLA_EXP_REGION9_NUM_SEGMENTS); dm_write_reg(xfm_dce->base.ctx, mmGAMMA_CORR_CNTLA_REGION_8_9, value); } curve += 2; { value = 0; set_reg_field_value( value, curve[0].offset, GAMMA_CORR_CNTLA_REGION_10_11, GAMMA_CORR_CNTLA_EXP_REGION10_LUT_OFFSET); set_reg_field_value( value, curve[0].segments_num, GAMMA_CORR_CNTLA_REGION_10_11, GAMMA_CORR_CNTLA_EXP_REGION10_NUM_SEGMENTS); set_reg_field_value( value, curve[1].offset, GAMMA_CORR_CNTLA_REGION_10_11, GAMMA_CORR_CNTLA_EXP_REGION11_LUT_OFFSET); set_reg_field_value( value, curve[1].segments_num, GAMMA_CORR_CNTLA_REGION_10_11, GAMMA_CORR_CNTLA_EXP_REGION11_NUM_SEGMENTS); dm_write_reg(xfm_dce->base.ctx, mmGAMMA_CORR_CNTLA_REGION_10_11, value); } curve += 2; { value = 0; set_reg_field_value( value, curve[0].offset, GAMMA_CORR_CNTLA_REGION_12_13, GAMMA_CORR_CNTLA_EXP_REGION12_LUT_OFFSET); set_reg_field_value( value, curve[0].segments_num, GAMMA_CORR_CNTLA_REGION_12_13, GAMMA_CORR_CNTLA_EXP_REGION12_NUM_SEGMENTS); set_reg_field_value( value, curve[1].offset, GAMMA_CORR_CNTLA_REGION_12_13, GAMMA_CORR_CNTLA_EXP_REGION13_LUT_OFFSET); set_reg_field_value( value, curve[1].segments_num, GAMMA_CORR_CNTLA_REGION_12_13, GAMMA_CORR_CNTLA_EXP_REGION13_NUM_SEGMENTS); dm_write_reg(xfm_dce->base.ctx, mmGAMMA_CORR_CNTLA_REGION_12_13, value); } curve += 2; { value = 0; set_reg_field_value( value, curve[0].offset, GAMMA_CORR_CNTLA_REGION_14_15, GAMMA_CORR_CNTLA_EXP_REGION14_LUT_OFFSET); set_reg_field_value( value, curve[0].segments_num, GAMMA_CORR_CNTLA_REGION_14_15, GAMMA_CORR_CNTLA_EXP_REGION14_NUM_SEGMENTS); set_reg_field_value( value, curve[1].offset, GAMMA_CORR_CNTLA_REGION_14_15, GAMMA_CORR_CNTLA_EXP_REGION15_LUT_OFFSET); set_reg_field_value( value, curve[1].segments_num, GAMMA_CORR_CNTLA_REGION_14_15, GAMMA_CORR_CNTLA_EXP_REGION15_NUM_SEGMENTS); dm_write_reg(xfm_dce->base.ctx, mmGAMMA_CORR_CNTLA_REGION_14_15, value); } } static void program_pwl(struct dce_transform *xfm_dce, const struct pwl_params *params) { uint32_t value = 0; set_reg_field_value( value, 7, GAMMA_CORR_LUT_WRITE_EN_MASK, GAMMA_CORR_LUT_WRITE_EN_MASK); dm_write_reg(xfm_dce->base.ctx, mmGAMMA_CORR_LUT_WRITE_EN_MASK, value); dm_write_reg(xfm_dce->base.ctx, mmGAMMA_CORR_LUT_INDEX, 0); /* Program REGAMMA_LUT_DATA */ { const uint32_t addr = mmGAMMA_CORR_LUT_DATA; uint32_t i = 0; const struct pwl_result_data *rgb = params->rgb_resulted; while (i != params->hw_points_num) { dm_write_reg(xfm_dce->base.ctx, addr, rgb->red_reg); dm_write_reg(xfm_dce->base.ctx, addr, rgb->green_reg); dm_write_reg(xfm_dce->base.ctx, addr, rgb->blue_reg); dm_write_reg(xfm_dce->base.ctx, addr, rgb->delta_red_reg); dm_write_reg(xfm_dce->base.ctx, addr, rgb->delta_green_reg); dm_write_reg(xfm_dce->base.ctx, addr, rgb->delta_blue_reg); ++rgb; ++i; } } } void dce110_opp_program_regamma_pwl_v( struct transform *xfm, const struct pwl_params *params) { struct dce_transform *xfm_dce = TO_DCE_TRANSFORM(xfm); /* Setup regions */ regamma_config_regions_and_segments(xfm_dce, params); set_bypass_input_gamma(xfm_dce); /* Power on gamma LUT memory */ power_on_lut(xfm, true, false, true); /* Program PWL */ program_pwl(xfm_dce, params); /* program regamma config */ configure_regamma_mode(xfm_dce, 1); /* Power return to auto back */ power_on_lut(xfm, false, false, true); } void dce110_opp_power_on_regamma_lut_v( struct transform *xfm, bool power_on) { uint32_t value = dm_read_reg(xfm->ctx, mmDCFEV_MEM_PWR_CTRL); set_reg_field_value( value, 0, DCFEV_MEM_PWR_CTRL, COL_MAN_GAMMA_CORR_MEM_PWR_FORCE); set_reg_field_value( value, power_on, DCFEV_MEM_PWR_CTRL, COL_MAN_GAMMA_CORR_MEM_PWR_DIS); set_reg_field_value( value, 0, DCFEV_MEM_PWR_CTRL, COL_MAN_INPUT_GAMMA_MEM_PWR_FORCE); set_reg_field_value( value, power_on, DCFEV_MEM_PWR_CTRL, COL_MAN_INPUT_GAMMA_MEM_PWR_DIS); dm_write_reg(xfm->ctx, mmDCFEV_MEM_PWR_CTRL, value); } void dce110_opp_set_regamma_mode_v( struct transform *xfm, enum opp_regamma mode) { // TODO: need to implement the function }