blob: 648e3ef35d91c0f5febe7636aa76ba44cf6088d0 [file] [log] [blame]
/*
* 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);
}