| /* |
| * 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[1].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 |
| } |