Resguardo inicial

This commit is contained in:
lastdragon
2026-09-06 12:53:21 -06:00
parent 662efe3c2a
commit ad2088d178
94853 changed files with 43200404 additions and 0 deletions
@@ -0,0 +1,612 @@
/*
* Copyright 2016 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 "core_types.h"
#include "reg_helper.h"
#include "dcn10/dcn10_dpp.h"
#include "basics/conversion.h"
#define NUM_PHASES 64
#define HORZ_MAX_TAPS 8
#define VERT_MAX_TAPS 8
#define BLACK_OFFSET_RGB_Y 0x0
#define BLACK_OFFSET_CBCR 0x8000
#define REG(reg)\
dpp->tf_regs->reg
#define CTX \
dpp->base.ctx
#undef FN
#define FN(reg_name, field_name) \
dpp->tf_shift->field_name, dpp->tf_mask->field_name
enum pixel_format_description {
PIXEL_FORMAT_FIXED = 0,
PIXEL_FORMAT_FIXED16,
PIXEL_FORMAT_FLOAT
};
enum dcn10_coef_filter_type_sel {
SCL_COEF_LUMA_VERT_FILTER = 0,
SCL_COEF_LUMA_HORZ_FILTER = 1,
SCL_COEF_CHROMA_VERT_FILTER = 2,
SCL_COEF_CHROMA_HORZ_FILTER = 3,
SCL_COEF_ALPHA_VERT_FILTER = 4,
SCL_COEF_ALPHA_HORZ_FILTER = 5
};
enum dscl_autocal_mode {
AUTOCAL_MODE_OFF = 0,
/* Autocal calculate the scaling ratio and initial phase and the
* DSCL_MODE_SEL must be set to 1
*/
AUTOCAL_MODE_AUTOSCALE = 1,
/* Autocal perform auto centering without replication and the
* DSCL_MODE_SEL must be set to 0
*/
AUTOCAL_MODE_AUTOCENTER = 2,
/* Autocal perform auto centering and auto replication and the
* DSCL_MODE_SEL must be set to 0
*/
AUTOCAL_MODE_AUTOREPLICATE = 3
};
enum dscl_mode_sel {
DSCL_MODE_SCALING_444_BYPASS = 0,
DSCL_MODE_SCALING_444_RGB_ENABLE = 1,
DSCL_MODE_SCALING_444_YCBCR_ENABLE = 2,
DSCL_MODE_SCALING_420_YCBCR_ENABLE = 3,
DSCL_MODE_SCALING_420_LUMA_BYPASS = 4,
DSCL_MODE_SCALING_420_CHROMA_BYPASS = 5,
DSCL_MODE_DSCL_BYPASS = 6
};
void dpp_read_state(struct dpp *dpp_base,
struct dcn_dpp_state *s)
{
struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base);
REG_GET(DPP_CONTROL,
DPP_CLOCK_ENABLE, &s->is_enabled);
REG_GET(CM_IGAM_CONTROL,
CM_IGAM_LUT_MODE, &s->igam_lut_mode);
REG_GET(CM_IGAM_CONTROL,
CM_IGAM_INPUT_FORMAT, &s->igam_input_format);
REG_GET(CM_DGAM_CONTROL,
CM_DGAM_LUT_MODE, &s->dgam_lut_mode);
REG_GET(CM_RGAM_CONTROL,
CM_RGAM_LUT_MODE, &s->rgam_lut_mode);
REG_GET(CM_GAMUT_REMAP_CONTROL,
CM_GAMUT_REMAP_MODE, &s->gamut_remap_mode);
if (s->gamut_remap_mode) {
s->gamut_remap_c11_c12 = REG_READ(CM_GAMUT_REMAP_C11_C12);
s->gamut_remap_c13_c14 = REG_READ(CM_GAMUT_REMAP_C13_C14);
s->gamut_remap_c21_c22 = REG_READ(CM_GAMUT_REMAP_C21_C22);
s->gamut_remap_c23_c24 = REG_READ(CM_GAMUT_REMAP_C23_C24);
s->gamut_remap_c31_c32 = REG_READ(CM_GAMUT_REMAP_C31_C32);
s->gamut_remap_c33_c34 = REG_READ(CM_GAMUT_REMAP_C33_C34);
}
}
#define IDENTITY_RATIO(ratio) (dc_fixpt_u2d19(ratio) == (1 << 19))
bool dpp1_get_optimal_number_of_taps(
struct dpp *dpp,
struct scaler_data *scl_data,
const struct scaling_taps *in_taps)
{
/* Some ASICs does not support FP16 scaling, so we reject modes require this*/
if (scl_data->format == PIXEL_FORMAT_FP16 &&
dpp->caps->dscl_data_proc_format == DSCL_DATA_PRCESSING_FIXED_FORMAT &&
scl_data->ratios.horz.value != dc_fixpt_one.value &&
scl_data->ratios.vert.value != dc_fixpt_one.value)
return false;
if (scl_data->viewport.width > scl_data->h_active &&
dpp->ctx->dc->debug.max_downscale_src_width != 0 &&
scl_data->viewport.width > dpp->ctx->dc->debug.max_downscale_src_width)
return false;
/* TODO: add lb check */
/* No support for programming ratio of 4, drop to 3.99999.. */
if (scl_data->ratios.horz.value == (4ll << 32))
scl_data->ratios.horz.value--;
if (scl_data->ratios.vert.value == (4ll << 32))
scl_data->ratios.vert.value--;
if (scl_data->ratios.horz_c.value == (4ll << 32))
scl_data->ratios.horz_c.value--;
if (scl_data->ratios.vert_c.value == (4ll << 32))
scl_data->ratios.vert_c.value--;
/* Set default taps if none are provided */
if (in_taps->h_taps == 0)
scl_data->taps.h_taps = 4;
else
scl_data->taps.h_taps = in_taps->h_taps;
if (in_taps->v_taps == 0)
scl_data->taps.v_taps = 4;
else
scl_data->taps.v_taps = in_taps->v_taps;
if (in_taps->v_taps_c == 0)
scl_data->taps.v_taps_c = 2;
else
scl_data->taps.v_taps_c = in_taps->v_taps_c;
if (in_taps->h_taps_c == 0)
scl_data->taps.h_taps_c = 2;
/* Only 1 and even h_taps_c are supported by hw */
else if ((in_taps->h_taps_c % 2) != 0 && in_taps->h_taps_c != 1)
scl_data->taps.h_taps_c = in_taps->h_taps_c - 1;
else
scl_data->taps.h_taps_c = in_taps->h_taps_c;
if (!dpp->ctx->dc->debug.always_scale) {
if (IDENTITY_RATIO(scl_data->ratios.horz)) {
scl_data->taps.h_taps = 1;
scl_data->taps.h_taps_c = 1;
}
if (IDENTITY_RATIO(scl_data->ratios.vert)) {
scl_data->taps.v_taps = 1;
scl_data->taps.v_taps_c = 1;
}
if (IDENTITY_RATIO(scl_data->ratios.horz_c))
scl_data->taps.h_taps_c = 1;
if (IDENTITY_RATIO(scl_data->ratios.vert_c))
scl_data->taps.v_taps_c = 1;
}
return true;
}
void dpp_reset(struct dpp *dpp_base)
{
struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base);
dpp->filter_h_c = NULL;
dpp->filter_v_c = NULL;
dpp->filter_h = NULL;
dpp->filter_v = NULL;
memset(&dpp_base->pos, 0, sizeof(dpp_base->pos));
memset(&dpp_base->att, 0, sizeof(dpp_base->att));
memset(&dpp->scl_data, 0, sizeof(dpp->scl_data));
memset(&dpp->pwl_data, 0, sizeof(dpp->pwl_data));
dpp_base->cursor_offload = false;
}
static void dpp1_cm_set_regamma_pwl(
struct dpp *dpp_base, const struct pwl_params *params, enum opp_regamma mode)
{
struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base);
uint32_t re_mode = 0;
switch (mode) {
case OPP_REGAMMA_BYPASS:
re_mode = 0;
break;
case OPP_REGAMMA_SRGB:
re_mode = 1;
break;
case OPP_REGAMMA_XVYCC:
re_mode = 2;
break;
case OPP_REGAMMA_USER:
re_mode = dpp->is_write_to_ram_a_safe ? 4 : 3;
if (memcmp(&dpp->pwl_data, params, sizeof(*params)) == 0)
break;
dpp1_cm_power_on_regamma_lut(dpp_base, true);
dpp1_cm_configure_regamma_lut(dpp_base, dpp->is_write_to_ram_a_safe);
if (dpp->is_write_to_ram_a_safe)
dpp1_cm_program_regamma_luta_settings(dpp_base, params);
else
dpp1_cm_program_regamma_lutb_settings(dpp_base, params);
dpp1_cm_program_regamma_lut(dpp_base, params->rgb_resulted,
params->hw_points_num);
dpp->pwl_data = *params;
re_mode = dpp->is_write_to_ram_a_safe ? 3 : 4;
dpp->is_write_to_ram_a_safe = !dpp->is_write_to_ram_a_safe;
break;
default:
break;
}
REG_SET(CM_RGAM_CONTROL, 0, CM_RGAM_LUT_MODE, re_mode);
}
static void dpp1_setup_format_flags(enum surface_pixel_format input_format,\
enum pixel_format_description *fmt)
{
if (input_format == SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616F ||
input_format == SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F)
*fmt = PIXEL_FORMAT_FLOAT;
else if (input_format == SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616 ||
input_format == SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616)
*fmt = PIXEL_FORMAT_FIXED16;
else
*fmt = PIXEL_FORMAT_FIXED;
}
static void dpp1_set_degamma_format_float(
struct dpp *dpp_base,
bool is_float)
{
struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base);
if (is_float) {
REG_UPDATE(CM_IGAM_CONTROL, CM_IGAM_INPUT_FORMAT, 3);
REG_UPDATE(CM_IGAM_CONTROL, CM_IGAM_LUT_MODE, 1);
} else {
REG_UPDATE(CM_IGAM_CONTROL, CM_IGAM_INPUT_FORMAT, 2);
REG_UPDATE(CM_IGAM_CONTROL, CM_IGAM_LUT_MODE, 0);
}
}
void dpp1_cnv_setup (
struct dpp *dpp_base,
enum surface_pixel_format format,
enum expansion_mode mode,
struct dc_csc_transform input_csc_color_matrix,
enum dc_color_space input_color_space,
struct cnv_alpha_2bit_lut *alpha_2bit_lut)
{
(void)alpha_2bit_lut;
uint32_t pixel_format;
uint32_t alpha_en;
enum pixel_format_description fmt ;
enum dc_color_space color_space;
enum dcn10_input_csc_select select;
bool is_float;
struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base);
bool force_disable_cursor = false;
struct out_csc_color_matrix tbl_entry;
int i = 0;
dpp1_setup_format_flags(format, &fmt);
alpha_en = 1;
pixel_format = 0;
color_space = COLOR_SPACE_SRGB;
select = INPUT_CSC_SELECT_BYPASS;
is_float = false;
switch (fmt) {
case PIXEL_FORMAT_FIXED:
case PIXEL_FORMAT_FIXED16:
/*when output is float then FORMAT_CONTROL__OUTPUT_FP=1*/
REG_SET_3(FORMAT_CONTROL, 0,
CNVC_BYPASS, 0,
FORMAT_EXPANSION_MODE, mode,
OUTPUT_FP, 0);
break;
case PIXEL_FORMAT_FLOAT:
REG_SET_3(FORMAT_CONTROL, 0,
CNVC_BYPASS, 0,
FORMAT_EXPANSION_MODE, mode,
OUTPUT_FP, 1);
is_float = true;
break;
default:
break;
}
dpp1_set_degamma_format_float(dpp_base, is_float);
switch (format) {
case SURFACE_PIXEL_FORMAT_GRPH_ARGB1555:
pixel_format = 1;
break;
case SURFACE_PIXEL_FORMAT_GRPH_RGB565:
pixel_format = 3;
alpha_en = 0;
break;
case SURFACE_PIXEL_FORMAT_GRPH_ARGB8888:
case SURFACE_PIXEL_FORMAT_GRPH_ABGR8888:
pixel_format = 8;
break;
case SURFACE_PIXEL_FORMAT_GRPH_ARGB2101010:
case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010:
pixel_format = 10;
break;
case SURFACE_PIXEL_FORMAT_VIDEO_420_YCbCr:
force_disable_cursor = false;
pixel_format = 65;
color_space = COLOR_SPACE_YCBCR709;
select = INPUT_CSC_SELECT_ICSC;
break;
case SURFACE_PIXEL_FORMAT_VIDEO_420_YCrCb:
force_disable_cursor = true;
pixel_format = 64;
color_space = COLOR_SPACE_YCBCR709;
select = INPUT_CSC_SELECT_ICSC;
break;
case SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCbCr:
force_disable_cursor = true;
pixel_format = 67;
color_space = COLOR_SPACE_YCBCR709;
select = INPUT_CSC_SELECT_ICSC;
break;
case SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCrCb:
force_disable_cursor = true;
pixel_format = 66;
color_space = COLOR_SPACE_YCBCR709;
select = INPUT_CSC_SELECT_ICSC;
break;
case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616:
case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616:
pixel_format = 26; /* ARGB16161616_UNORM */
break;
case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616F:
pixel_format = 24;
break;
case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F:
pixel_format = 25;
break;
default:
break;
}
/* Set default color space based on format if none is given. */
color_space = input_color_space ? input_color_space : color_space;
REG_SET(CNVC_SURFACE_PIXEL_FORMAT, 0,
CNVC_SURFACE_PIXEL_FORMAT, pixel_format);
REG_UPDATE(FORMAT_CONTROL, FORMAT_CONTROL__ALPHA_EN, alpha_en);
// if input adjustments exist, program icsc with those values
if (input_csc_color_matrix.enable_adjustment
== true) {
for (i = 0; i < 12; i++)
tbl_entry.regval[i] = input_csc_color_matrix.matrix[i];
tbl_entry.color_space = color_space;
if (color_space >= COLOR_SPACE_YCBCR601)
select = INPUT_CSC_SELECT_ICSC;
else
select = INPUT_CSC_SELECT_BYPASS;
dpp1_program_input_csc(dpp_base, color_space, select, &tbl_entry);
} else
dpp1_program_input_csc(dpp_base, color_space, select, NULL);
if (force_disable_cursor) {
REG_UPDATE(CURSOR_CONTROL,
CURSOR_ENABLE, 0);
REG_UPDATE(CURSOR0_CONTROL,
CUR0_ENABLE, 0);
}
}
void dpp1_set_cursor_attributes(
struct dpp *dpp_base,
struct dc_cursor_attributes *cursor_attributes)
{
enum dc_cursor_color_format color_format = cursor_attributes->color_format;
struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base);
REG_UPDATE_2(CURSOR0_CONTROL,
CUR0_MODE, color_format,
CUR0_EXPANSION_MODE, 0);
if (color_format == CURSOR_MODE_MONO) {
/* todo: clarify what to program these to */
REG_UPDATE(CURSOR0_COLOR0,
CUR0_COLOR0, 0x00000000);
REG_UPDATE(CURSOR0_COLOR1,
CUR0_COLOR1, 0xFFFFFFFF);
}
}
void dpp1_set_cursor_position(
struct dpp *dpp_base,
const struct dc_cursor_position *pos,
const struct dc_cursor_mi_param *param,
uint32_t width,
uint32_t height)
{
struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base);
int x_pos = pos->x - param->viewport.x;
int y_pos = pos->y - param->viewport.y;
int x_hotspot = pos->x_hotspot;
int y_hotspot = pos->y_hotspot;
int src_x_offset = x_pos - pos->x_hotspot;
int src_y_offset = y_pos - pos->y_hotspot;
int cursor_height = (int)height;
int cursor_width = (int)width;
uint32_t cur_en = pos->enable ? 1 : 0;
// Transform cursor width / height and hotspots for offset calculations
if (param->rotation == ROTATION_ANGLE_90 || param->rotation == ROTATION_ANGLE_270) {
swap(cursor_height, cursor_width);
swap(x_hotspot, y_hotspot);
if (param->rotation == ROTATION_ANGLE_90) {
// hotspot = (-y, x)
src_x_offset = x_pos - (cursor_width - x_hotspot);
src_y_offset = y_pos - y_hotspot;
} else if (param->rotation == ROTATION_ANGLE_270) {
// hotspot = (y, -x)
src_x_offset = x_pos - x_hotspot;
src_y_offset = y_pos - (cursor_height - y_hotspot);
}
} else if (param->rotation == ROTATION_ANGLE_180) {
// hotspot = (-x, -y)
if (!param->mirror)
src_x_offset = x_pos - (cursor_width - x_hotspot);
src_y_offset = y_pos - (cursor_height - y_hotspot);
}
if (src_x_offset >= (int)param->viewport.width)
cur_en = 0; /* not visible beyond right edge*/
if (src_x_offset + cursor_width <= 0)
cur_en = 0; /* not visible beyond left edge*/
if (src_y_offset >= (int)param->viewport.height)
cur_en = 0; /* not visible beyond bottom edge*/
if (src_y_offset + cursor_height <= 0)
cur_en = 0; /* not visible beyond top edge*/
if (dpp_base->pos.cur0_ctl.bits.cur0_enable != cur_en) {
if (!dpp_base->cursor_offload)
REG_UPDATE(CURSOR0_CONTROL, CUR0_ENABLE, cur_en);
}
dpp_base->pos.cur0_ctl.bits.cur0_enable = cur_en;
dpp_base->att.cur0_ctl.bits.cur0_enable = cur_en;
}
void dpp1_cnv_set_optional_cursor_attributes(
struct dpp *dpp_base,
struct dpp_cursor_attributes *attr)
{
struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base);
if (attr) {
if (!dpp_base->cursor_offload) {
REG_UPDATE(CURSOR0_FP_SCALE_BIAS, CUR0_FP_BIAS, attr->bias);
REG_UPDATE(CURSOR0_FP_SCALE_BIAS, CUR0_FP_SCALE, attr->scale);
}
dpp_base->att.fp_scale_bias.bits.fp_bias = attr->bias;
dpp_base->att.fp_scale_bias.bits.fp_scale = attr->scale;
}
}
void dpp1_dppclk_control(
struct dpp *dpp_base,
bool dppclk_div,
bool enable)
{
struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base);
if (enable) {
if (dpp->tf_mask->DPPCLK_RATE_CONTROL)
REG_UPDATE_2(DPP_CONTROL,
DPPCLK_RATE_CONTROL, dppclk_div,
DPP_CLOCK_ENABLE, 1);
else
REG_UPDATE(DPP_CONTROL, DPP_CLOCK_ENABLE, 1);
} else
REG_UPDATE(DPP_CONTROL, DPP_CLOCK_ENABLE, 0);
}
void dpp_force_disable_cursor(struct dpp *dpp_base)
{
struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base);
/* Force disable cursor */
REG_UPDATE(CURSOR0_CONTROL, CUR0_ENABLE, 0);
dpp_base->pos.cur0_ctl.bits.cur0_enable = 0;
}
static const struct dpp_funcs dcn10_dpp_funcs = {
.dpp_read_state = dpp_read_state,
.dpp_reset = dpp_reset,
.dpp_set_scaler = dpp1_dscl_set_scaler_manual_scale,
.dpp_get_optimal_number_of_taps = dpp1_get_optimal_number_of_taps,
.dpp_set_gamut_remap = dpp1_cm_set_gamut_remap,
.dpp_set_csc_adjustment = dpp1_cm_set_output_csc_adjustment,
.dpp_set_csc_default = dpp1_cm_set_output_csc_default,
.dpp_power_on_regamma_lut = dpp1_cm_power_on_regamma_lut,
.dpp_program_regamma_lut = dpp1_cm_program_regamma_lut,
.dpp_configure_regamma_lut = dpp1_cm_configure_regamma_lut,
.dpp_program_regamma_lutb_settings = dpp1_cm_program_regamma_lutb_settings,
.dpp_program_regamma_luta_settings = dpp1_cm_program_regamma_luta_settings,
.dpp_program_regamma_pwl = dpp1_cm_set_regamma_pwl,
.dpp_program_bias_and_scale = dpp1_program_bias_and_scale,
.dpp_set_degamma = dpp1_set_degamma,
.dpp_program_input_lut = dpp1_program_input_lut,
.dpp_program_degamma_pwl = dpp1_set_degamma_pwl,
.dpp_setup = dpp1_cnv_setup,
.dpp_full_bypass = dpp1_full_bypass,
.set_cursor_attributes = dpp1_set_cursor_attributes,
.set_cursor_position = dpp1_set_cursor_position,
.set_optional_cursor_attributes = dpp1_cnv_set_optional_cursor_attributes,
.dpp_dppclk_control = dpp1_dppclk_control,
.dpp_set_hdr_multiplier = dpp1_set_hdr_multiplier,
.dpp_program_blnd_lut = NULL,
.dpp_program_shaper_lut = NULL,
.dpp_program_3dlut = NULL,
.dpp_get_gamut_remap = dpp1_cm_get_gamut_remap,
};
static struct dpp_caps dcn10_dpp_cap = {
.dscl_data_proc_format = DSCL_DATA_PRCESSING_FIXED_FORMAT,
.dscl_calc_lb_num_partitions = dpp1_dscl_calc_lb_num_partitions,
};
/*****************************************/
/* Constructor, Destructor */
/*****************************************/
void dpp1_construct(
struct dcn10_dpp *dpp,
struct dc_context *ctx,
uint32_t inst,
const struct dcn_dpp_registers *tf_regs,
const struct dcn_dpp_shift *tf_shift,
const struct dcn_dpp_mask *tf_mask)
{
dpp->base.ctx = ctx;
dpp->base.inst = inst;
dpp->base.funcs = &dcn10_dpp_funcs;
dpp->base.caps = &dcn10_dpp_cap;
dpp->tf_regs = tf_regs;
dpp->tf_shift = tf_shift;
dpp->tf_mask = tf_mask;
dpp->lb_pixel_depth_supported =
LB_PIXEL_DEPTH_18BPP |
LB_PIXEL_DEPTH_24BPP |
LB_PIXEL_DEPTH_30BPP |
LB_PIXEL_DEPTH_36BPP;
dpp->lb_bits_per_entry = LB_BITS_PER_ENTRY;
dpp->lb_memory_size = LB_TOTAL_NUMBER_OF_ENTRIES; /*0x1404*/
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,879 @@
/*
* Copyright 2016 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 "core_types.h"
#include "reg_helper.h"
#include "dcn10/dcn10_dpp.h"
#include "basics/conversion.h"
#include "dcn10/dcn10_cm_common.h"
#define NUM_PHASES 64
#define HORZ_MAX_TAPS 8
#define VERT_MAX_TAPS 8
#define BLACK_OFFSET_RGB_Y 0x0
#define BLACK_OFFSET_CBCR 0x8000
#define REG(reg)\
dpp->tf_regs->reg
#define CTX \
dpp->base.ctx
#undef FN
#define FN(reg_name, field_name) \
dpp->tf_shift->field_name, dpp->tf_mask->field_name
enum dcn10_coef_filter_type_sel {
SCL_COEF_LUMA_VERT_FILTER = 0,
SCL_COEF_LUMA_HORZ_FILTER = 1,
SCL_COEF_CHROMA_VERT_FILTER = 2,
SCL_COEF_CHROMA_HORZ_FILTER = 3,
SCL_COEF_ALPHA_VERT_FILTER = 4,
SCL_COEF_ALPHA_HORZ_FILTER = 5
};
enum dscl_autocal_mode {
AUTOCAL_MODE_OFF = 0,
/* Autocal calculate the scaling ratio and initial phase and the
* DSCL_MODE_SEL must be set to 1
*/
AUTOCAL_MODE_AUTOSCALE = 1,
/* Autocal perform auto centering without replication and the
* DSCL_MODE_SEL must be set to 0
*/
AUTOCAL_MODE_AUTOCENTER = 2,
/* Autocal perform auto centering and auto replication and the
* DSCL_MODE_SEL must be set to 0
*/
AUTOCAL_MODE_AUTOREPLICATE = 3
};
enum dscl_mode_sel {
DSCL_MODE_SCALING_444_BYPASS = 0,
DSCL_MODE_SCALING_444_RGB_ENABLE = 1,
DSCL_MODE_SCALING_444_YCBCR_ENABLE = 2,
DSCL_MODE_SCALING_420_YCBCR_ENABLE = 3,
DSCL_MODE_SCALING_420_LUMA_BYPASS = 4,
DSCL_MODE_SCALING_420_CHROMA_BYPASS = 5,
DSCL_MODE_DSCL_BYPASS = 6
};
static void program_gamut_remap(
struct dcn10_dpp *dpp,
const uint16_t *regval,
enum gamut_remap_select select)
{
uint16_t selection = 0;
struct color_matrices_reg gam_regs;
if (regval == NULL || select == GAMUT_REMAP_BYPASS) {
REG_SET(CM_GAMUT_REMAP_CONTROL, 0,
CM_GAMUT_REMAP_MODE, 0);
return;
}
switch (select) {
case GAMUT_REMAP_COEFF:
selection = 1;
break;
case GAMUT_REMAP_COMA_COEFF:
selection = 2;
break;
case GAMUT_REMAP_COMB_COEFF:
selection = 3;
break;
default:
break;
}
gam_regs.shifts.csc_c11 = dpp->tf_shift->CM_GAMUT_REMAP_C11;
gam_regs.masks.csc_c11 = dpp->tf_mask->CM_GAMUT_REMAP_C11;
gam_regs.shifts.csc_c12 = dpp->tf_shift->CM_GAMUT_REMAP_C12;
gam_regs.masks.csc_c12 = dpp->tf_mask->CM_GAMUT_REMAP_C12;
if (select == GAMUT_REMAP_COEFF) {
gam_regs.csc_c11_c12 = REG(CM_GAMUT_REMAP_C11_C12);
gam_regs.csc_c33_c34 = REG(CM_GAMUT_REMAP_C33_C34);
cm_helper_program_color_matrices(
dpp->base.ctx,
regval,
&gam_regs);
} else if (select == GAMUT_REMAP_COMA_COEFF) {
gam_regs.csc_c11_c12 = REG(CM_COMA_C11_C12);
gam_regs.csc_c33_c34 = REG(CM_COMA_C33_C34);
cm_helper_program_color_matrices(
dpp->base.ctx,
regval,
&gam_regs);
} else {
gam_regs.csc_c11_c12 = REG(CM_COMB_C11_C12);
gam_regs.csc_c33_c34 = REG(CM_COMB_C33_C34);
cm_helper_program_color_matrices(
dpp->base.ctx,
regval,
&gam_regs);
}
REG_SET(
CM_GAMUT_REMAP_CONTROL, 0,
CM_GAMUT_REMAP_MODE, selection);
}
void dpp1_cm_set_gamut_remap(
struct dpp *dpp_base,
const struct dpp_grph_csc_adjustment *adjust)
{
struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base);
int i = 0;
if (adjust->gamut_adjust_type != GRAPHICS_GAMUT_ADJUST_TYPE_SW)
/* Bypass if type is bypass or hw */
program_gamut_remap(dpp, NULL, GAMUT_REMAP_BYPASS);
else {
struct fixed31_32 arr_matrix[12];
uint16_t arr_reg_val[12];
for (i = 0; i < 12; i++)
arr_matrix[i] = adjust->temperature_matrix[i];
convert_float_matrix(
arr_reg_val, arr_matrix, 12);
program_gamut_remap(dpp, arr_reg_val, GAMUT_REMAP_COEFF);
}
}
static void read_gamut_remap(struct dcn10_dpp *dpp,
uint16_t *regval,
enum gamut_remap_select *select)
{
struct color_matrices_reg gam_regs;
uint32_t selection;
REG_GET(CM_GAMUT_REMAP_CONTROL,
CM_GAMUT_REMAP_MODE, &selection);
*select = selection;
gam_regs.shifts.csc_c11 = dpp->tf_shift->CM_GAMUT_REMAP_C11;
gam_regs.masks.csc_c11 = dpp->tf_mask->CM_GAMUT_REMAP_C11;
gam_regs.shifts.csc_c12 = dpp->tf_shift->CM_GAMUT_REMAP_C12;
gam_regs.masks.csc_c12 = dpp->tf_mask->CM_GAMUT_REMAP_C12;
if (*select == GAMUT_REMAP_COEFF) {
gam_regs.csc_c11_c12 = REG(CM_GAMUT_REMAP_C11_C12);
gam_regs.csc_c33_c34 = REG(CM_GAMUT_REMAP_C33_C34);
cm_helper_read_color_matrices(
dpp->base.ctx,
regval,
&gam_regs);
} else if (*select == GAMUT_REMAP_COMA_COEFF) {
gam_regs.csc_c11_c12 = REG(CM_COMA_C11_C12);
gam_regs.csc_c33_c34 = REG(CM_COMA_C33_C34);
cm_helper_read_color_matrices(
dpp->base.ctx,
regval,
&gam_regs);
} else if (*select == GAMUT_REMAP_COMB_COEFF) {
gam_regs.csc_c11_c12 = REG(CM_COMB_C11_C12);
gam_regs.csc_c33_c34 = REG(CM_COMB_C33_C34);
cm_helper_read_color_matrices(
dpp->base.ctx,
regval,
&gam_regs);
}
}
void dpp1_cm_get_gamut_remap(struct dpp *dpp_base,
struct dpp_grph_csc_adjustment *adjust)
{
struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base);
uint16_t arr_reg_val[12] = {0};
enum gamut_remap_select select;
read_gamut_remap(dpp, arr_reg_val, &select);
if (select == GAMUT_REMAP_BYPASS) {
adjust->gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_BYPASS;
return;
}
adjust->gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_SW;
convert_hw_matrix(adjust->temperature_matrix,
arr_reg_val, ARRAY_SIZE(arr_reg_val));
}
static void dpp1_cm_program_color_matrix(
struct dcn10_dpp *dpp,
const uint16_t *regval)
{
uint32_t ocsc_mode;
uint32_t cur_mode;
struct color_matrices_reg gam_regs;
if (regval == NULL) {
BREAK_TO_DEBUGGER();
return;
}
/* determine which CSC matrix (ocsc or comb) we are using
* currently. select the alternate set to double buffer
* the CSC update so CSC is updated on frame boundary
*/
REG_SET(CM_TEST_DEBUG_INDEX, 0,
CM_TEST_DEBUG_INDEX, 9);
REG_GET(CM_TEST_DEBUG_DATA,
CM_TEST_DEBUG_DATA_ID9_OCSC_MODE, &cur_mode);
if (cur_mode != 4)
ocsc_mode = 4;
else
ocsc_mode = 5;
gam_regs.shifts.csc_c11 = dpp->tf_shift->CM_OCSC_C11;
gam_regs.masks.csc_c11 = dpp->tf_mask->CM_OCSC_C11;
gam_regs.shifts.csc_c12 = dpp->tf_shift->CM_OCSC_C12;
gam_regs.masks.csc_c12 = dpp->tf_mask->CM_OCSC_C12;
if (ocsc_mode == 4) {
gam_regs.csc_c11_c12 = REG(CM_OCSC_C11_C12);
gam_regs.csc_c33_c34 = REG(CM_OCSC_C33_C34);
} else {
gam_regs.csc_c11_c12 = REG(CM_COMB_C11_C12);
gam_regs.csc_c33_c34 = REG(CM_COMB_C33_C34);
}
cm_helper_program_color_matrices(
dpp->base.ctx,
regval,
&gam_regs);
REG_SET(CM_OCSC_CONTROL, 0, CM_OCSC_MODE, ocsc_mode);
}
void dpp1_cm_set_output_csc_default(
struct dpp *dpp_base,
enum dc_color_space colorspace)
{
struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base);
const uint16_t *regval = NULL;
uint32_t arr_size;
regval = find_color_matrix(colorspace, &arr_size);
if (regval == NULL) {
BREAK_TO_DEBUGGER();
return;
}
dpp1_cm_program_color_matrix(dpp, regval);
}
static void dpp1_cm_get_reg_field(
struct dcn10_dpp *dpp,
struct xfer_func_reg *reg)
{
reg->shifts.exp_region0_lut_offset = dpp->tf_shift->CM_RGAM_RAMA_EXP_REGION0_LUT_OFFSET;
reg->masks.exp_region0_lut_offset = dpp->tf_mask->CM_RGAM_RAMA_EXP_REGION0_LUT_OFFSET;
reg->shifts.exp_region0_num_segments = dpp->tf_shift->CM_RGAM_RAMA_EXP_REGION0_NUM_SEGMENTS;
reg->masks.exp_region0_num_segments = dpp->tf_mask->CM_RGAM_RAMA_EXP_REGION0_NUM_SEGMENTS;
reg->shifts.exp_region1_lut_offset = dpp->tf_shift->CM_RGAM_RAMA_EXP_REGION1_LUT_OFFSET;
reg->masks.exp_region1_lut_offset = dpp->tf_mask->CM_RGAM_RAMA_EXP_REGION1_LUT_OFFSET;
reg->shifts.exp_region1_num_segments = dpp->tf_shift->CM_RGAM_RAMA_EXP_REGION1_NUM_SEGMENTS;
reg->masks.exp_region1_num_segments = dpp->tf_mask->CM_RGAM_RAMA_EXP_REGION1_NUM_SEGMENTS;
reg->shifts.field_region_end = dpp->tf_shift->CM_RGAM_RAMB_EXP_REGION_END_B;
reg->masks.field_region_end = dpp->tf_mask->CM_RGAM_RAMB_EXP_REGION_END_B;
reg->shifts.field_region_end_slope = dpp->tf_shift->CM_RGAM_RAMB_EXP_REGION_END_SLOPE_B;
reg->masks.field_region_end_slope = dpp->tf_mask->CM_RGAM_RAMB_EXP_REGION_END_SLOPE_B;
reg->shifts.field_region_end_base = dpp->tf_shift->CM_RGAM_RAMB_EXP_REGION_END_BASE_B;
reg->masks.field_region_end_base = dpp->tf_mask->CM_RGAM_RAMB_EXP_REGION_END_BASE_B;
reg->shifts.field_region_linear_slope = dpp->tf_shift->CM_RGAM_RAMB_EXP_REGION_LINEAR_SLOPE_B;
reg->masks.field_region_linear_slope = dpp->tf_mask->CM_RGAM_RAMB_EXP_REGION_LINEAR_SLOPE_B;
reg->shifts.exp_region_start = dpp->tf_shift->CM_RGAM_RAMB_EXP_REGION_START_B;
reg->masks.exp_region_start = dpp->tf_mask->CM_RGAM_RAMB_EXP_REGION_START_B;
reg->shifts.exp_resion_start_segment = dpp->tf_shift->CM_RGAM_RAMB_EXP_REGION_START_SEGMENT_B;
reg->masks.exp_resion_start_segment = dpp->tf_mask->CM_RGAM_RAMB_EXP_REGION_START_SEGMENT_B;
}
static void dpp1_cm_get_degamma_reg_field(
struct dcn10_dpp *dpp,
struct xfer_func_reg *reg)
{
reg->shifts.exp_region0_lut_offset = dpp->tf_shift->CM_DGAM_RAMA_EXP_REGION0_LUT_OFFSET;
reg->masks.exp_region0_lut_offset = dpp->tf_mask->CM_DGAM_RAMA_EXP_REGION0_LUT_OFFSET;
reg->shifts.exp_region0_num_segments = dpp->tf_shift->CM_DGAM_RAMA_EXP_REGION0_NUM_SEGMENTS;
reg->masks.exp_region0_num_segments = dpp->tf_mask->CM_DGAM_RAMA_EXP_REGION0_NUM_SEGMENTS;
reg->shifts.exp_region1_lut_offset = dpp->tf_shift->CM_DGAM_RAMA_EXP_REGION1_LUT_OFFSET;
reg->masks.exp_region1_lut_offset = dpp->tf_mask->CM_DGAM_RAMA_EXP_REGION1_LUT_OFFSET;
reg->shifts.exp_region1_num_segments = dpp->tf_shift->CM_DGAM_RAMA_EXP_REGION1_NUM_SEGMENTS;
reg->masks.exp_region1_num_segments = dpp->tf_mask->CM_DGAM_RAMA_EXP_REGION1_NUM_SEGMENTS;
reg->shifts.field_region_end = dpp->tf_shift->CM_DGAM_RAMB_EXP_REGION_END_B;
reg->masks.field_region_end = dpp->tf_mask->CM_DGAM_RAMB_EXP_REGION_END_B;
reg->shifts.field_region_end_slope = dpp->tf_shift->CM_DGAM_RAMB_EXP_REGION_END_SLOPE_B;
reg->masks.field_region_end_slope = dpp->tf_mask->CM_DGAM_RAMB_EXP_REGION_END_SLOPE_B;
reg->shifts.field_region_end_base = dpp->tf_shift->CM_DGAM_RAMB_EXP_REGION_END_BASE_B;
reg->masks.field_region_end_base = dpp->tf_mask->CM_DGAM_RAMB_EXP_REGION_END_BASE_B;
reg->shifts.field_region_linear_slope = dpp->tf_shift->CM_DGAM_RAMB_EXP_REGION_LINEAR_SLOPE_B;
reg->masks.field_region_linear_slope = dpp->tf_mask->CM_DGAM_RAMB_EXP_REGION_LINEAR_SLOPE_B;
reg->shifts.exp_region_start = dpp->tf_shift->CM_DGAM_RAMB_EXP_REGION_START_B;
reg->masks.exp_region_start = dpp->tf_mask->CM_DGAM_RAMB_EXP_REGION_START_B;
reg->shifts.exp_resion_start_segment = dpp->tf_shift->CM_DGAM_RAMB_EXP_REGION_START_SEGMENT_B;
reg->masks.exp_resion_start_segment = dpp->tf_mask->CM_DGAM_RAMB_EXP_REGION_START_SEGMENT_B;
}
void dpp1_cm_set_output_csc_adjustment(
struct dpp *dpp_base,
const uint16_t *regval)
{
struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base);
dpp1_cm_program_color_matrix(dpp, regval);
}
void dpp1_cm_power_on_regamma_lut(struct dpp *dpp_base,
bool power_on)
{
struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base);
REG_SET(CM_MEM_PWR_CTRL, 0,
RGAM_MEM_PWR_FORCE, power_on == true ? 0:1);
}
void dpp1_cm_program_regamma_lut(struct dpp *dpp_base,
const struct pwl_result_data *rgb,
uint32_t num)
{
uint32_t i;
struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base);
REG_SEQ_START();
for (i = 0 ; i < num; i++) {
REG_SET(CM_RGAM_LUT_DATA, 0, CM_RGAM_LUT_DATA, rgb[i].red_reg);
REG_SET(CM_RGAM_LUT_DATA, 0, CM_RGAM_LUT_DATA, rgb[i].green_reg);
REG_SET(CM_RGAM_LUT_DATA, 0, CM_RGAM_LUT_DATA, rgb[i].blue_reg);
REG_SET(CM_RGAM_LUT_DATA, 0, CM_RGAM_LUT_DATA, rgb[i].delta_red_reg);
REG_SET(CM_RGAM_LUT_DATA, 0, CM_RGAM_LUT_DATA, rgb[i].delta_green_reg);
REG_SET(CM_RGAM_LUT_DATA, 0, CM_RGAM_LUT_DATA, rgb[i].delta_blue_reg);
}
REG_SEQ_SUBMIT();
REG_SEQ_WAIT_DONE();
}
void dpp1_cm_configure_regamma_lut(
struct dpp *dpp_base,
bool is_ram_a)
{
struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base);
REG_UPDATE(CM_RGAM_LUT_WRITE_EN_MASK,
CM_RGAM_LUT_WRITE_EN_MASK, 7);
REG_UPDATE(CM_RGAM_LUT_WRITE_EN_MASK,
CM_RGAM_LUT_WRITE_SEL, is_ram_a == true ? 0:1);
REG_SET(CM_RGAM_LUT_INDEX, 0, CM_RGAM_LUT_INDEX, 0);
}
/*program re gamma RAM A*/
void dpp1_cm_program_regamma_luta_settings(
struct dpp *dpp_base,
const struct pwl_params *params)
{
struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base);
struct xfer_func_reg gam_regs;
dpp1_cm_get_reg_field(dpp, &gam_regs);
gam_regs.start_cntl_b = REG(CM_RGAM_RAMA_START_CNTL_B);
gam_regs.start_cntl_g = REG(CM_RGAM_RAMA_START_CNTL_G);
gam_regs.start_cntl_r = REG(CM_RGAM_RAMA_START_CNTL_R);
gam_regs.start_slope_cntl_b = REG(CM_RGAM_RAMA_SLOPE_CNTL_B);
gam_regs.start_slope_cntl_g = REG(CM_RGAM_RAMA_SLOPE_CNTL_G);
gam_regs.start_slope_cntl_r = REG(CM_RGAM_RAMA_SLOPE_CNTL_R);
gam_regs.start_end_cntl1_b = REG(CM_RGAM_RAMA_END_CNTL1_B);
gam_regs.start_end_cntl2_b = REG(CM_RGAM_RAMA_END_CNTL2_B);
gam_regs.start_end_cntl1_g = REG(CM_RGAM_RAMA_END_CNTL1_G);
gam_regs.start_end_cntl2_g = REG(CM_RGAM_RAMA_END_CNTL2_G);
gam_regs.start_end_cntl1_r = REG(CM_RGAM_RAMA_END_CNTL1_R);
gam_regs.start_end_cntl2_r = REG(CM_RGAM_RAMA_END_CNTL2_R);
gam_regs.region_start = REG(CM_RGAM_RAMA_REGION_0_1);
gam_regs.region_end = REG(CM_RGAM_RAMA_REGION_32_33);
cm_helper_program_xfer_func(dpp->base.ctx, params, &gam_regs);
}
/*program re gamma RAM B*/
void dpp1_cm_program_regamma_lutb_settings(
struct dpp *dpp_base,
const struct pwl_params *params)
{
struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base);
struct xfer_func_reg gam_regs;
dpp1_cm_get_reg_field(dpp, &gam_regs);
gam_regs.start_cntl_b = REG(CM_RGAM_RAMB_START_CNTL_B);
gam_regs.start_cntl_g = REG(CM_RGAM_RAMB_START_CNTL_G);
gam_regs.start_cntl_r = REG(CM_RGAM_RAMB_START_CNTL_R);
gam_regs.start_slope_cntl_b = REG(CM_RGAM_RAMB_SLOPE_CNTL_B);
gam_regs.start_slope_cntl_g = REG(CM_RGAM_RAMB_SLOPE_CNTL_G);
gam_regs.start_slope_cntl_r = REG(CM_RGAM_RAMB_SLOPE_CNTL_R);
gam_regs.start_end_cntl1_b = REG(CM_RGAM_RAMB_END_CNTL1_B);
gam_regs.start_end_cntl2_b = REG(CM_RGAM_RAMB_END_CNTL2_B);
gam_regs.start_end_cntl1_g = REG(CM_RGAM_RAMB_END_CNTL1_G);
gam_regs.start_end_cntl2_g = REG(CM_RGAM_RAMB_END_CNTL2_G);
gam_regs.start_end_cntl1_r = REG(CM_RGAM_RAMB_END_CNTL1_R);
gam_regs.start_end_cntl2_r = REG(CM_RGAM_RAMB_END_CNTL2_R);
gam_regs.region_start = REG(CM_RGAM_RAMB_REGION_0_1);
gam_regs.region_end = REG(CM_RGAM_RAMB_REGION_32_33);
cm_helper_program_xfer_func(dpp->base.ctx, params, &gam_regs);
}
void dpp1_program_input_csc(
struct dpp *dpp_base,
enum dc_color_space color_space,
enum dcn10_input_csc_select input_select,
const struct out_csc_color_matrix *tbl_entry)
{
struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base);
int i;
int arr_size = sizeof(dpp_input_csc_matrix)/sizeof(struct dpp_input_csc_matrix);
const uint16_t *regval = NULL;
uint32_t cur_select = 0;
enum dcn10_input_csc_select select;
struct color_matrices_reg gam_regs;
if (input_select == INPUT_CSC_SELECT_BYPASS) {
REG_SET(CM_ICSC_CONTROL, 0, CM_ICSC_MODE, 0);
return;
}
if (tbl_entry == NULL) {
for (i = 0; i < arr_size; i++)
if (dpp_input_csc_matrix[i].color_space == color_space) {
regval = dpp_input_csc_matrix[i].regval;
break;
}
if (regval == NULL) {
BREAK_TO_DEBUGGER();
return;
}
} else {
regval = tbl_entry->regval;
}
/* determine which CSC matrix (icsc or coma) we are using
* currently. select the alternate set to double buffer
* the CSC update so CSC is updated on frame boundary
*/
REG_SET(CM_TEST_DEBUG_INDEX, 0,
CM_TEST_DEBUG_INDEX, 9);
REG_GET(CM_TEST_DEBUG_DATA,
CM_TEST_DEBUG_DATA_ID9_ICSC_MODE, &cur_select);
if (cur_select != INPUT_CSC_SELECT_ICSC)
select = INPUT_CSC_SELECT_ICSC;
else
select = INPUT_CSC_SELECT_COMA;
gam_regs.shifts.csc_c11 = dpp->tf_shift->CM_ICSC_C11;
gam_regs.masks.csc_c11 = dpp->tf_mask->CM_ICSC_C11;
gam_regs.shifts.csc_c12 = dpp->tf_shift->CM_ICSC_C12;
gam_regs.masks.csc_c12 = dpp->tf_mask->CM_ICSC_C12;
if (select == INPUT_CSC_SELECT_ICSC) {
gam_regs.csc_c11_c12 = REG(CM_ICSC_C11_C12);
gam_regs.csc_c33_c34 = REG(CM_ICSC_C33_C34);
} else {
gam_regs.csc_c11_c12 = REG(CM_COMA_C11_C12);
gam_regs.csc_c33_c34 = REG(CM_COMA_C33_C34);
}
cm_helper_program_color_matrices(
dpp->base.ctx,
regval,
&gam_regs);
REG_SET(CM_ICSC_CONTROL, 0,
CM_ICSC_MODE, select);
}
//keep here for now, decide multi dce support later
void dpp1_program_bias_and_scale(
struct dpp *dpp_base,
struct dc_bias_and_scale *params)
{
struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base);
REG_SET_2(CM_BNS_VALUES_R, 0,
CM_BNS_SCALE_R, params->scale_red,
CM_BNS_BIAS_R, params->bias_red);
REG_SET_2(CM_BNS_VALUES_G, 0,
CM_BNS_SCALE_G, params->scale_green,
CM_BNS_BIAS_G, params->bias_green);
REG_SET_2(CM_BNS_VALUES_B, 0,
CM_BNS_SCALE_B, params->scale_blue,
CM_BNS_BIAS_B, params->bias_blue);
}
/*program de gamma RAM B*/
void dpp1_program_degamma_lutb_settings(
struct dpp *dpp_base,
const struct pwl_params *params)
{
struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base);
struct xfer_func_reg gam_regs;
dpp1_cm_get_degamma_reg_field(dpp, &gam_regs);
gam_regs.start_cntl_b = REG(CM_DGAM_RAMB_START_CNTL_B);
gam_regs.start_cntl_g = REG(CM_DGAM_RAMB_START_CNTL_G);
gam_regs.start_cntl_r = REG(CM_DGAM_RAMB_START_CNTL_R);
gam_regs.start_slope_cntl_b = REG(CM_DGAM_RAMB_SLOPE_CNTL_B);
gam_regs.start_slope_cntl_g = REG(CM_DGAM_RAMB_SLOPE_CNTL_G);
gam_regs.start_slope_cntl_r = REG(CM_DGAM_RAMB_SLOPE_CNTL_R);
gam_regs.start_end_cntl1_b = REG(CM_DGAM_RAMB_END_CNTL1_B);
gam_regs.start_end_cntl2_b = REG(CM_DGAM_RAMB_END_CNTL2_B);
gam_regs.start_end_cntl1_g = REG(CM_DGAM_RAMB_END_CNTL1_G);
gam_regs.start_end_cntl2_g = REG(CM_DGAM_RAMB_END_CNTL2_G);
gam_regs.start_end_cntl1_r = REG(CM_DGAM_RAMB_END_CNTL1_R);
gam_regs.start_end_cntl2_r = REG(CM_DGAM_RAMB_END_CNTL2_R);
gam_regs.region_start = REG(CM_DGAM_RAMB_REGION_0_1);
gam_regs.region_end = REG(CM_DGAM_RAMB_REGION_14_15);
cm_helper_program_xfer_func(dpp->base.ctx, params, &gam_regs);
}
/*program de gamma RAM A*/
void dpp1_program_degamma_luta_settings(
struct dpp *dpp_base,
const struct pwl_params *params)
{
struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base);
struct xfer_func_reg gam_regs;
dpp1_cm_get_degamma_reg_field(dpp, &gam_regs);
gam_regs.start_cntl_b = REG(CM_DGAM_RAMA_START_CNTL_B);
gam_regs.start_cntl_g = REG(CM_DGAM_RAMA_START_CNTL_G);
gam_regs.start_cntl_r = REG(CM_DGAM_RAMA_START_CNTL_R);
gam_regs.start_slope_cntl_b = REG(CM_DGAM_RAMA_SLOPE_CNTL_B);
gam_regs.start_slope_cntl_g = REG(CM_DGAM_RAMA_SLOPE_CNTL_G);
gam_regs.start_slope_cntl_r = REG(CM_DGAM_RAMA_SLOPE_CNTL_R);
gam_regs.start_end_cntl1_b = REG(CM_DGAM_RAMA_END_CNTL1_B);
gam_regs.start_end_cntl2_b = REG(CM_DGAM_RAMA_END_CNTL2_B);
gam_regs.start_end_cntl1_g = REG(CM_DGAM_RAMA_END_CNTL1_G);
gam_regs.start_end_cntl2_g = REG(CM_DGAM_RAMA_END_CNTL2_G);
gam_regs.start_end_cntl1_r = REG(CM_DGAM_RAMA_END_CNTL1_R);
gam_regs.start_end_cntl2_r = REG(CM_DGAM_RAMA_END_CNTL2_R);
gam_regs.region_start = REG(CM_DGAM_RAMA_REGION_0_1);
gam_regs.region_end = REG(CM_DGAM_RAMA_REGION_14_15);
cm_helper_program_xfer_func(dpp->base.ctx, params, &gam_regs);
}
void dpp1_power_on_degamma_lut(
struct dpp *dpp_base,
bool power_on)
{
struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base);
REG_SET(CM_MEM_PWR_CTRL, 0,
SHARED_MEM_PWR_DIS, power_on ? 0:1);
}
static void dpp1_enable_cm_block(
struct dpp *dpp_base)
{
struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base);
REG_UPDATE(CM_CMOUT_CONTROL, CM_CMOUT_ROUND_TRUNC_MODE, 8);
REG_UPDATE(CM_CONTROL, CM_BYPASS_EN, 0);
}
void dpp1_set_degamma(
struct dpp *dpp_base,
enum ipp_degamma_mode mode)
{
struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base);
dpp1_enable_cm_block(dpp_base);
switch (mode) {
case IPP_DEGAMMA_MODE_BYPASS:
/* Setting de gamma bypass for now */
REG_UPDATE(CM_DGAM_CONTROL, CM_DGAM_LUT_MODE, 0);
break;
case IPP_DEGAMMA_MODE_HW_sRGB:
REG_UPDATE(CM_DGAM_CONTROL, CM_DGAM_LUT_MODE, 1);
break;
case IPP_DEGAMMA_MODE_HW_xvYCC:
REG_UPDATE(CM_DGAM_CONTROL, CM_DGAM_LUT_MODE, 2);
break;
case IPP_DEGAMMA_MODE_USER_PWL:
REG_UPDATE(CM_DGAM_CONTROL, CM_DGAM_LUT_MODE, 3);
break;
default:
BREAK_TO_DEBUGGER();
break;
}
}
void dpp1_degamma_ram_select(
struct dpp *dpp_base,
bool use_ram_a)
{
struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base);
if (use_ram_a)
REG_UPDATE(CM_DGAM_CONTROL, CM_DGAM_LUT_MODE, 3);
else
REG_UPDATE(CM_DGAM_CONTROL, CM_DGAM_LUT_MODE, 4);
}
static bool dpp1_degamma_ram_inuse(
struct dpp *dpp_base,
bool *ram_a_inuse)
{
bool ret = false;
uint32_t status_reg = 0;
struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base);
REG_GET(CM_IGAM_LUT_RW_CONTROL, CM_IGAM_DGAM_CONFIG_STATUS,
&status_reg);
if (status_reg == 9) {
*ram_a_inuse = true;
ret = true;
} else if (status_reg == 10) {
*ram_a_inuse = false;
ret = true;
}
return ret;
}
void dpp1_program_degamma_lut(
struct dpp *dpp_base,
const struct pwl_result_data *rgb,
uint32_t num,
bool is_ram_a)
{
uint32_t i;
struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base);
REG_UPDATE(CM_IGAM_LUT_RW_CONTROL, CM_IGAM_LUT_HOST_EN, 0);
REG_UPDATE(CM_DGAM_LUT_WRITE_EN_MASK,
CM_DGAM_LUT_WRITE_EN_MASK, 7);
REG_UPDATE(CM_DGAM_LUT_WRITE_EN_MASK, CM_DGAM_LUT_WRITE_SEL,
is_ram_a == true ? 0:1);
REG_SET(CM_DGAM_LUT_INDEX, 0, CM_DGAM_LUT_INDEX, 0);
for (i = 0 ; i < num; i++) {
REG_SET(CM_DGAM_LUT_DATA, 0, CM_DGAM_LUT_DATA, rgb[i].red_reg);
REG_SET(CM_DGAM_LUT_DATA, 0, CM_DGAM_LUT_DATA, rgb[i].green_reg);
REG_SET(CM_DGAM_LUT_DATA, 0, CM_DGAM_LUT_DATA, rgb[i].blue_reg);
REG_SET(CM_DGAM_LUT_DATA, 0,
CM_DGAM_LUT_DATA, rgb[i].delta_red_reg);
REG_SET(CM_DGAM_LUT_DATA, 0,
CM_DGAM_LUT_DATA, rgb[i].delta_green_reg);
REG_SET(CM_DGAM_LUT_DATA, 0,
CM_DGAM_LUT_DATA, rgb[i].delta_blue_reg);
}
}
void dpp1_set_degamma_pwl(struct dpp *dpp_base,
const struct pwl_params *params)
{
bool is_ram_a = true;
dpp1_power_on_degamma_lut(dpp_base, true);
dpp1_enable_cm_block(dpp_base);
dpp1_degamma_ram_inuse(dpp_base, &is_ram_a);
if (is_ram_a == true)
dpp1_program_degamma_lutb_settings(dpp_base, params);
else
dpp1_program_degamma_luta_settings(dpp_base, params);
dpp1_program_degamma_lut(dpp_base, params->rgb_resulted,
params->hw_points_num, !is_ram_a);
dpp1_degamma_ram_select(dpp_base, !is_ram_a);
}
void dpp1_full_bypass(struct dpp *dpp_base)
{
struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base);
/* Input pixel format: ARGB8888 */
REG_SET(CNVC_SURFACE_PIXEL_FORMAT, 0,
CNVC_SURFACE_PIXEL_FORMAT, 0x8);
/* Zero expansion */
REG_SET_3(FORMAT_CONTROL, 0,
CNVC_BYPASS, 0,
FORMAT_CONTROL__ALPHA_EN, 0,
FORMAT_EXPANSION_MODE, 0);
/* COLOR_KEYER_CONTROL.COLOR_KEYER_EN = 0 this should be default */
if (dpp->tf_mask->CM_BYPASS_EN)
REG_SET(CM_CONTROL, 0, CM_BYPASS_EN, 1);
else
REG_SET(CM_CONTROL, 0, CM_BYPASS, 1);
/* Setting degamma bypass for now */
REG_SET(CM_DGAM_CONTROL, 0, CM_DGAM_LUT_MODE, 0);
}
static bool dpp1_ingamma_ram_inuse(struct dpp *dpp_base,
bool *ram_a_inuse)
{
bool in_use = false;
uint32_t status_reg = 0;
struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base);
REG_GET(CM_IGAM_LUT_RW_CONTROL, CM_IGAM_DGAM_CONFIG_STATUS,
&status_reg);
// 1 => IGAM_RAMA, 3 => IGAM_RAMA & DGAM_ROMA, 4 => IGAM_RAMA & DGAM_ROMB
if (status_reg == 1 || status_reg == 3 || status_reg == 4) {
*ram_a_inuse = true;
in_use = true;
// 2 => IGAM_RAMB, 5 => IGAM_RAMB & DGAM_ROMA, 6 => IGAM_RAMB & DGAM_ROMB
} else if (status_reg == 2 || status_reg == 5 || status_reg == 6) {
*ram_a_inuse = false;
in_use = true;
}
return in_use;
}
/*
* Input gamma LUT currently supports 256 values only. This means input color
* can have a maximum of 8 bits per channel (= 256 possible values) in order to
* have a one-to-one mapping with the LUT. Truncation will occur with color
* values greater than 8 bits.
*
* In the future, this function should support additional input gamma methods,
* such as piecewise linear mapping, and input gamma bypass.
*/
void dpp1_program_input_lut(
struct dpp *dpp_base,
const struct dc_gamma *gamma)
{
unsigned int i;
struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base);
bool rama_occupied = false;
uint32_t ram_num;
// Power on LUT memory.
REG_SET(CM_MEM_PWR_CTRL, 0, SHARED_MEM_PWR_DIS, 1);
dpp1_enable_cm_block(dpp_base);
// Determine whether to use RAM A or RAM B
dpp1_ingamma_ram_inuse(dpp_base, &rama_occupied);
if (!rama_occupied)
REG_UPDATE(CM_IGAM_LUT_RW_CONTROL, CM_IGAM_LUT_SEL, 0);
else
REG_UPDATE(CM_IGAM_LUT_RW_CONTROL, CM_IGAM_LUT_SEL, 1);
// RW mode is 256-entry LUT
REG_UPDATE(CM_IGAM_LUT_RW_CONTROL, CM_IGAM_LUT_RW_MODE, 0);
// IGAM Input format should be 8 bits per channel.
REG_UPDATE(CM_IGAM_CONTROL, CM_IGAM_INPUT_FORMAT, 0);
// Do not mask any R,G,B values
REG_UPDATE(CM_IGAM_LUT_RW_CONTROL, CM_IGAM_LUT_WRITE_EN_MASK, 7);
// LUT-256, unsigned, integer, new u0.12 format
REG_UPDATE_3(
CM_IGAM_CONTROL,
CM_IGAM_LUT_FORMAT_R, 3,
CM_IGAM_LUT_FORMAT_G, 3,
CM_IGAM_LUT_FORMAT_B, 3);
// Start at index 0 of IGAM LUT
REG_UPDATE(CM_IGAM_LUT_RW_INDEX, CM_IGAM_LUT_RW_INDEX, 0);
for (i = 0; i < gamma->num_entries; i++) {
REG_SET(CM_IGAM_LUT_SEQ_COLOR, 0, CM_IGAM_LUT_SEQ_COLOR,
dc_fixpt_round(
gamma->entries.red[i]));
REG_SET(CM_IGAM_LUT_SEQ_COLOR, 0, CM_IGAM_LUT_SEQ_COLOR,
dc_fixpt_round(
gamma->entries.green[i]));
REG_SET(CM_IGAM_LUT_SEQ_COLOR, 0, CM_IGAM_LUT_SEQ_COLOR,
dc_fixpt_round(
gamma->entries.blue[i]));
}
// Power off LUT memory
REG_SET(CM_MEM_PWR_CTRL, 0, SHARED_MEM_PWR_DIS, 0);
// Enable IGAM LUT on ram we just wrote to. 2 => RAMA, 3 => RAMB
REG_UPDATE(CM_IGAM_CONTROL, CM_IGAM_LUT_MODE, rama_occupied ? 3 : 2);
REG_GET(CM_IGAM_CONTROL, CM_IGAM_LUT_MODE, &ram_num);
}
void dpp1_set_hdr_multiplier(
struct dpp *dpp_base,
uint32_t multiplier)
{
struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base);
REG_UPDATE(CM_HDR_MULT_COEF, CM_HDR_MULT_COEF, multiplier);
}
@@ -0,0 +1,696 @@
/*
* Copyright 2016 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 "core_types.h"
#include "reg_helper.h"
#include "dcn10/dcn10_dpp.h"
#include "basics/conversion.h"
#define NUM_PHASES 64
#define HORZ_MAX_TAPS 8
#define VERT_MAX_TAPS 8
#define BLACK_OFFSET_RGB_Y 0x0
#define BLACK_OFFSET_CBCR 0x8000
#define REG(reg)\
dpp->tf_regs->reg
#define CTX \
dpp->base.ctx
#undef FN
#define FN(reg_name, field_name) \
dpp->tf_shift->field_name, dpp->tf_mask->field_name
enum dcn10_coef_filter_type_sel {
SCL_COEF_LUMA_VERT_FILTER = 0,
SCL_COEF_LUMA_HORZ_FILTER = 1,
SCL_COEF_CHROMA_VERT_FILTER = 2,
SCL_COEF_CHROMA_HORZ_FILTER = 3,
SCL_COEF_ALPHA_VERT_FILTER = 4,
SCL_COEF_ALPHA_HORZ_FILTER = 5
};
enum dscl_autocal_mode {
AUTOCAL_MODE_OFF = 0,
/* Autocal calculate the scaling ratio and initial phase and the
* DSCL_MODE_SEL must be set to 1
*/
AUTOCAL_MODE_AUTOSCALE = 1,
/* Autocal perform auto centering without replication and the
* DSCL_MODE_SEL must be set to 0
*/
AUTOCAL_MODE_AUTOCENTER = 2,
/* Autocal perform auto centering and auto replication and the
* DSCL_MODE_SEL must be set to 0
*/
AUTOCAL_MODE_AUTOREPLICATE = 3
};
enum dscl_mode_sel {
DSCL_MODE_SCALING_444_BYPASS = 0,
DSCL_MODE_SCALING_444_RGB_ENABLE = 1,
DSCL_MODE_SCALING_444_YCBCR_ENABLE = 2,
DSCL_MODE_SCALING_420_YCBCR_ENABLE = 3,
DSCL_MODE_SCALING_420_LUMA_BYPASS = 4,
DSCL_MODE_SCALING_420_CHROMA_BYPASS = 5,
DSCL_MODE_DSCL_BYPASS = 6
};
static int dpp1_dscl_get_pixel_depth_val(enum lb_pixel_depth depth)
{
if (depth == LB_PIXEL_DEPTH_30BPP)
return 0; /* 10 bpc */
else if (depth == LB_PIXEL_DEPTH_24BPP)
return 1; /* 8 bpc */
else if (depth == LB_PIXEL_DEPTH_18BPP)
return 2; /* 6 bpc */
else if (depth == LB_PIXEL_DEPTH_36BPP)
return 3; /* 12 bpc */
else {
ASSERT(0);
return -1; /* Unsupported */
}
}
static bool dpp1_dscl_is_video_format(enum dc_pixel_format format)
{
if (format >= PIXEL_FORMAT_VIDEO_BEGIN
&& format <= PIXEL_FORMAT_VIDEO_END)
return true;
else
return false;
}
static bool dpp1_dscl_is_420_format(enum dc_pixel_format format)
{
if (format == PIXEL_FORMAT_420BPP8 ||
format == PIXEL_FORMAT_420BPP10)
return true;
else
return false;
}
static enum dscl_mode_sel dpp1_dscl_get_dscl_mode(
struct dpp *dpp_base,
const struct scaler_data *data,
bool dbg_always_scale)
{
const long long one = dc_fixpt_one.value;
if (dpp_base->caps->dscl_data_proc_format == DSCL_DATA_PRCESSING_FIXED_FORMAT) {
/* DSCL is processing data in fixed format */
if (data->format == PIXEL_FORMAT_FP16)
return DSCL_MODE_DSCL_BYPASS;
}
if (data->ratios.horz.value == one
&& data->ratios.vert.value == one
&& data->ratios.horz_c.value == one
&& data->ratios.vert_c.value == one
&& !dbg_always_scale)
return DSCL_MODE_SCALING_444_BYPASS;
if (!dpp1_dscl_is_420_format(data->format)) {
if (dpp1_dscl_is_video_format(data->format))
return DSCL_MODE_SCALING_444_YCBCR_ENABLE;
else
return DSCL_MODE_SCALING_444_RGB_ENABLE;
}
if (data->ratios.horz.value == one && data->ratios.vert.value == one)
return DSCL_MODE_SCALING_420_LUMA_BYPASS;
if (data->ratios.horz_c.value == one && data->ratios.vert_c.value == one)
return DSCL_MODE_SCALING_420_CHROMA_BYPASS;
return DSCL_MODE_SCALING_420_YCBCR_ENABLE;
}
static void dpp1_power_on_dscl(
struct dpp *dpp_base,
bool power_on)
{
struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base);
if (dpp->tf_regs->DSCL_MEM_PWR_CTRL) {
if (power_on) {
REG_UPDATE(DSCL_MEM_PWR_CTRL, LUT_MEM_PWR_FORCE, 0);
REG_WAIT(DSCL_MEM_PWR_STATUS, LUT_MEM_PWR_STATE, 0, 1, 5);
} else {
if (dpp->base.ctx->dc->debug.enable_mem_low_power.bits.dscl) {
dpp->base.ctx->dc->optimized_required = true;
dpp->base.deferred_reg_writes.bits.disable_dscl = true;
} else {
REG_UPDATE(DSCL_MEM_PWR_CTRL, LUT_MEM_PWR_FORCE, 3);
}
}
}
}
static void dpp1_dscl_set_lb(
struct dcn10_dpp *dpp,
const struct line_buffer_params *lb_params,
enum lb_memory_config mem_size_config)
{
uint32_t max_partitions = 63; /* Currently hardcoded on all ASICs before DCN 3.2 */
/* LB */
if (dpp->base.caps->dscl_data_proc_format == DSCL_DATA_PRCESSING_FIXED_FORMAT) {
/* DSCL caps: pixel data processed in fixed format */
uint32_t pixel_depth = dpp1_dscl_get_pixel_depth_val(lb_params->depth);
uint32_t dyn_pix_depth = lb_params->dynamic_pixel_depth;
REG_SET_7(LB_DATA_FORMAT, 0,
PIXEL_DEPTH, pixel_depth, /* Pixel depth stored in LB */
PIXEL_EXPAN_MODE, lb_params->pixel_expan_mode, /* Pixel expansion mode */
PIXEL_REDUCE_MODE, 1, /* Pixel reduction mode: Rounding */
DYNAMIC_PIXEL_DEPTH, dyn_pix_depth, /* Dynamic expansion pixel depth */
DITHER_EN, 0, /* Dithering enable: Disabled */
INTERLEAVE_EN, lb_params->interleave_en, /* Interleave source enable */
LB_DATA_FORMAT__ALPHA_EN, lb_params->alpha_en); /* Alpha enable */
} else {
/* DSCL caps: pixel data processed in float format */
REG_SET_2(LB_DATA_FORMAT, 0,
INTERLEAVE_EN, lb_params->interleave_en, /* Interleave source enable */
LB_DATA_FORMAT__ALPHA_EN, lb_params->alpha_en); /* Alpha enable */
}
if (dpp->base.caps->max_lb_partitions == 31)
max_partitions = 31;
REG_SET_2(LB_MEMORY_CTRL, 0,
MEMORY_CONFIG, mem_size_config,
LB_MAX_PARTITIONS, max_partitions);
}
static const uint16_t *dpp1_dscl_get_filter_coeffs_64p(int taps, struct fixed31_32 ratio)
{
if (taps == 8)
return get_filter_8tap_64p(ratio);
else if (taps == 7)
return get_filter_7tap_64p(ratio);
else if (taps == 6)
return get_filter_6tap_64p(ratio);
else if (taps == 5)
return get_filter_5tap_64p(ratio);
else if (taps == 4)
return get_filter_4tap_64p(ratio);
else if (taps == 3)
return get_filter_3tap_64p(ratio);
else if (taps == 2)
return get_filter_2tap_64p();
else if (taps == 1)
return NULL;
else {
/* should never happen, bug */
BREAK_TO_DEBUGGER();
return NULL;
}
}
static void dpp1_dscl_set_scaler_filter(
struct dcn10_dpp *dpp,
uint32_t taps,
enum dcn10_coef_filter_type_sel filter_type,
const uint16_t *filter)
{
const int tap_pairs = (taps + 1) / 2;
int phase;
int pair;
uint16_t odd_coef, even_coef;
REG_SET_3(SCL_COEF_RAM_TAP_SELECT, 0,
SCL_COEF_RAM_TAP_PAIR_IDX, 0,
SCL_COEF_RAM_PHASE, 0,
SCL_COEF_RAM_FILTER_TYPE, filter_type);
for (phase = 0; phase < (NUM_PHASES / 2 + 1); phase++) {
for (pair = 0; pair < tap_pairs; pair++) {
even_coef = filter[phase * taps + 2 * pair];
if ((uint32_t)(pair * 2 + 1) < taps)
odd_coef = filter[phase * taps + 2 * pair + 1];
else
odd_coef = 0;
REG_SET_4(SCL_COEF_RAM_TAP_DATA, 0,
/* Even tap coefficient (bits 1:0 fixed to 0) */
SCL_COEF_RAM_EVEN_TAP_COEF, even_coef,
/* Write/read control for even coefficient */
SCL_COEF_RAM_EVEN_TAP_COEF_EN, 1,
/* Odd tap coefficient (bits 1:0 fixed to 0) */
SCL_COEF_RAM_ODD_TAP_COEF, odd_coef,
/* Write/read control for odd coefficient */
SCL_COEF_RAM_ODD_TAP_COEF_EN, 1);
}
}
}
static void dpp1_dscl_set_scl_filter(
struct dcn10_dpp *dpp,
const struct scaler_data *scl_data,
bool chroma_coef_mode)
{
bool h_2tap_hardcode_coef_en = false;
bool v_2tap_hardcode_coef_en = false;
bool h_2tap_sharp_en = false;
bool v_2tap_sharp_en = false;
uint32_t h_2tap_sharp_factor = scl_data->sharpness.horz;
uint32_t v_2tap_sharp_factor = scl_data->sharpness.vert;
bool coef_ram_current;
const uint16_t *filter_h = NULL;
const uint16_t *filter_v = NULL;
const uint16_t *filter_h_c = NULL;
const uint16_t *filter_v_c = NULL;
h_2tap_hardcode_coef_en = scl_data->taps.h_taps < 3
&& scl_data->taps.h_taps_c < 3
&& (scl_data->taps.h_taps > 1 && scl_data->taps.h_taps_c > 1);
v_2tap_hardcode_coef_en = scl_data->taps.v_taps < 3
&& scl_data->taps.v_taps_c < 3
&& (scl_data->taps.v_taps > 1 && scl_data->taps.v_taps_c > 1);
h_2tap_sharp_en = h_2tap_hardcode_coef_en && h_2tap_sharp_factor != 0;
v_2tap_sharp_en = v_2tap_hardcode_coef_en && v_2tap_sharp_factor != 0;
REG_UPDATE_6(DSCL_2TAP_CONTROL,
SCL_H_2TAP_HARDCODE_COEF_EN, h_2tap_hardcode_coef_en,
SCL_H_2TAP_SHARP_EN, h_2tap_sharp_en,
SCL_H_2TAP_SHARP_FACTOR, h_2tap_sharp_factor,
SCL_V_2TAP_HARDCODE_COEF_EN, v_2tap_hardcode_coef_en,
SCL_V_2TAP_SHARP_EN, v_2tap_sharp_en,
SCL_V_2TAP_SHARP_FACTOR, v_2tap_sharp_factor);
if (!v_2tap_hardcode_coef_en || !h_2tap_hardcode_coef_en) {
bool filter_updated = false;
filter_h = dpp1_dscl_get_filter_coeffs_64p(
scl_data->taps.h_taps, scl_data->ratios.horz);
filter_v = dpp1_dscl_get_filter_coeffs_64p(
scl_data->taps.v_taps, scl_data->ratios.vert);
filter_updated = (filter_h && (filter_h != dpp->filter_h))
|| (filter_v && (filter_v != dpp->filter_v));
if (chroma_coef_mode) {
filter_h_c = dpp1_dscl_get_filter_coeffs_64p(
scl_data->taps.h_taps_c, scl_data->ratios.horz_c);
filter_v_c = dpp1_dscl_get_filter_coeffs_64p(
scl_data->taps.v_taps_c, scl_data->ratios.vert_c);
filter_updated = filter_updated || (filter_h_c && (filter_h_c != dpp->filter_h_c))
|| (filter_v_c && (filter_v_c != dpp->filter_v_c));
}
if (filter_updated) {
uint32_t scl_mode = REG_READ(SCL_MODE);
if (!h_2tap_hardcode_coef_en && filter_h) {
dpp1_dscl_set_scaler_filter(
dpp, scl_data->taps.h_taps,
SCL_COEF_LUMA_HORZ_FILTER, filter_h);
}
dpp->filter_h = filter_h;
if (!v_2tap_hardcode_coef_en && filter_v) {
dpp1_dscl_set_scaler_filter(
dpp, scl_data->taps.v_taps,
SCL_COEF_LUMA_VERT_FILTER, filter_v);
}
dpp->filter_v = filter_v;
if (chroma_coef_mode) {
if (!h_2tap_hardcode_coef_en && filter_h_c) {
dpp1_dscl_set_scaler_filter(
dpp, scl_data->taps.h_taps_c,
SCL_COEF_CHROMA_HORZ_FILTER, filter_h_c);
}
if (!v_2tap_hardcode_coef_en && filter_v_c) {
dpp1_dscl_set_scaler_filter(
dpp, scl_data->taps.v_taps_c,
SCL_COEF_CHROMA_VERT_FILTER, filter_v_c);
}
}
dpp->filter_h_c = filter_h_c;
dpp->filter_v_c = filter_v_c;
coef_ram_current = get_reg_field_value_ex(
scl_mode, dpp->tf_mask->SCL_COEF_RAM_SELECT_CURRENT,
dpp->tf_shift->SCL_COEF_RAM_SELECT_CURRENT);
/* Swap coefficient RAM and set chroma coefficient mode */
REG_SET_2(SCL_MODE, scl_mode,
SCL_COEF_RAM_SELECT, !coef_ram_current,
SCL_CHROMA_COEF_MODE, chroma_coef_mode);
}
}
}
static int dpp1_dscl_get_lb_depth_bpc(enum lb_pixel_depth depth)
{
if (depth == LB_PIXEL_DEPTH_30BPP)
return 10;
else if (depth == LB_PIXEL_DEPTH_24BPP)
return 8;
else if (depth == LB_PIXEL_DEPTH_18BPP)
return 6;
else if (depth == LB_PIXEL_DEPTH_36BPP)
return 12;
else {
BREAK_TO_DEBUGGER();
return -1; /* Unsupported */
}
}
void dpp1_dscl_calc_lb_num_partitions(
const struct scaler_data *scl_data,
enum lb_memory_config lb_config,
int *num_part_y,
int *num_part_c)
{
int lb_memory_size, lb_memory_size_c, lb_memory_size_a, num_partitions_a,
lb_bpc, memory_line_size_y, memory_line_size_c, memory_line_size_a;
int line_size = scl_data->viewport.width < scl_data->recout.width ?
scl_data->viewport.width : scl_data->recout.width;
int line_size_c = scl_data->viewport_c.width < scl_data->recout.width ?
scl_data->viewport_c.width : scl_data->recout.width;
if (line_size == 0)
line_size = 1;
if (line_size_c == 0)
line_size_c = 1;
lb_bpc = dpp1_dscl_get_lb_depth_bpc(scl_data->lb_params.depth);
memory_line_size_y = (line_size * lb_bpc + 71) / 72; /* +71 to ceil */
memory_line_size_c = (line_size_c * lb_bpc + 71) / 72; /* +71 to ceil */
memory_line_size_a = (line_size + 5) / 6; /* +5 to ceil */
if (lb_config == LB_MEMORY_CONFIG_1) {
lb_memory_size = 816;
lb_memory_size_c = 816;
lb_memory_size_a = 984;
} else if (lb_config == LB_MEMORY_CONFIG_2) {
lb_memory_size = 1088;
lb_memory_size_c = 1088;
lb_memory_size_a = 1312;
} else if (lb_config == LB_MEMORY_CONFIG_3) {
/* 420 mode: using 3rd mem from Y, Cr and Cb */
lb_memory_size = 816 + 1088 + 848 + 848 + 848;
lb_memory_size_c = 816 + 1088;
lb_memory_size_a = 984 + 1312 + 456;
} else {
lb_memory_size = 816 + 1088 + 848;
lb_memory_size_c = 816 + 1088 + 848;
lb_memory_size_a = 984 + 1312 + 456;
}
*num_part_y = lb_memory_size / memory_line_size_y;
*num_part_c = lb_memory_size_c / memory_line_size_c;
num_partitions_a = lb_memory_size_a / memory_line_size_a;
if (scl_data->lb_params.alpha_en
&& (num_partitions_a < *num_part_y))
*num_part_y = num_partitions_a;
if (*num_part_y > 64)
*num_part_y = 64;
if (*num_part_c > 64)
*num_part_c = 64;
}
bool dpp1_dscl_is_lb_conf_valid(int ceil_vratio, int num_partitions, int vtaps)
{
if (ceil_vratio > 2)
return vtaps <= (num_partitions - ceil_vratio + 2);
else
return vtaps <= num_partitions;
}
/*find first match configuration which meets the min required lb size*/
static enum lb_memory_config dpp1_dscl_find_lb_memory_config(struct dcn10_dpp *dpp,
const struct scaler_data *scl_data)
{
int num_part_y, num_part_c;
int vtaps = scl_data->taps.v_taps;
int vtaps_c = scl_data->taps.v_taps_c;
int ceil_vratio = dc_fixpt_ceil(scl_data->ratios.vert);
int ceil_vratio_c = dc_fixpt_ceil(scl_data->ratios.vert_c);
if (dpp->base.ctx->dc->debug.use_max_lb) {
if (scl_data->format == PIXEL_FORMAT_420BPP8
|| scl_data->format == PIXEL_FORMAT_420BPP10)
return LB_MEMORY_CONFIG_3;
return LB_MEMORY_CONFIG_0;
}
dpp->base.caps->dscl_calc_lb_num_partitions(
scl_data, LB_MEMORY_CONFIG_1, &num_part_y, &num_part_c);
if (dpp1_dscl_is_lb_conf_valid(ceil_vratio, num_part_y, vtaps)
&& dpp1_dscl_is_lb_conf_valid(ceil_vratio_c, num_part_c, vtaps_c))
return LB_MEMORY_CONFIG_1;
dpp->base.caps->dscl_calc_lb_num_partitions(
scl_data, LB_MEMORY_CONFIG_2, &num_part_y, &num_part_c);
if (dpp1_dscl_is_lb_conf_valid(ceil_vratio, num_part_y, vtaps)
&& dpp1_dscl_is_lb_conf_valid(ceil_vratio_c, num_part_c, vtaps_c))
return LB_MEMORY_CONFIG_2;
if (scl_data->format == PIXEL_FORMAT_420BPP8
|| scl_data->format == PIXEL_FORMAT_420BPP10) {
dpp->base.caps->dscl_calc_lb_num_partitions(
scl_data, LB_MEMORY_CONFIG_3, &num_part_y, &num_part_c);
if (dpp1_dscl_is_lb_conf_valid(ceil_vratio, num_part_y, vtaps)
&& dpp1_dscl_is_lb_conf_valid(ceil_vratio_c, num_part_c, vtaps_c))
return LB_MEMORY_CONFIG_3;
}
dpp->base.caps->dscl_calc_lb_num_partitions(
scl_data, LB_MEMORY_CONFIG_0, &num_part_y, &num_part_c);
/*Ensure we can support the requested number of vtaps*/
ASSERT(dpp1_dscl_is_lb_conf_valid(ceil_vratio, num_part_y, vtaps)
&& dpp1_dscl_is_lb_conf_valid(ceil_vratio_c, num_part_c, vtaps_c));
return LB_MEMORY_CONFIG_0;
}
static void dpp1_dscl_set_manual_ratio_init(
struct dcn10_dpp *dpp, const struct scaler_data *data)
{
uint32_t init_frac = 0;
uint32_t init_int = 0;
REG_SET(SCL_HORZ_FILTER_SCALE_RATIO, 0,
SCL_H_SCALE_RATIO, dc_fixpt_u3d19(data->ratios.horz) << 5);
REG_SET(SCL_VERT_FILTER_SCALE_RATIO, 0,
SCL_V_SCALE_RATIO, dc_fixpt_u3d19(data->ratios.vert) << 5);
REG_SET(SCL_HORZ_FILTER_SCALE_RATIO_C, 0,
SCL_H_SCALE_RATIO_C, dc_fixpt_u3d19(data->ratios.horz_c) << 5);
REG_SET(SCL_VERT_FILTER_SCALE_RATIO_C, 0,
SCL_V_SCALE_RATIO_C, dc_fixpt_u3d19(data->ratios.vert_c) << 5);
/*
* 0.24 format for fraction, first five bits zeroed
*/
init_frac = dc_fixpt_u0d19(data->inits.h) << 5;
init_int = dc_fixpt_floor(data->inits.h);
REG_SET_2(SCL_HORZ_FILTER_INIT, 0,
SCL_H_INIT_FRAC, init_frac,
SCL_H_INIT_INT, init_int);
init_frac = dc_fixpt_u0d19(data->inits.h_c) << 5;
init_int = dc_fixpt_floor(data->inits.h_c);
REG_SET_2(SCL_HORZ_FILTER_INIT_C, 0,
SCL_H_INIT_FRAC_C, init_frac,
SCL_H_INIT_INT_C, init_int);
init_frac = dc_fixpt_u0d19(data->inits.v) << 5;
init_int = dc_fixpt_floor(data->inits.v);
REG_SET_2(SCL_VERT_FILTER_INIT, 0,
SCL_V_INIT_FRAC, init_frac,
SCL_V_INIT_INT, init_int);
if (REG(SCL_VERT_FILTER_INIT_BOT)) {
struct fixed31_32 bot = dc_fixpt_add(data->inits.v, data->ratios.vert);
init_frac = dc_fixpt_u0d19(bot) << 5;
init_int = dc_fixpt_floor(bot);
REG_SET_2(SCL_VERT_FILTER_INIT_BOT, 0,
SCL_V_INIT_FRAC_BOT, init_frac,
SCL_V_INIT_INT_BOT, init_int);
}
init_frac = dc_fixpt_u0d19(data->inits.v_c) << 5;
init_int = dc_fixpt_floor(data->inits.v_c);
REG_SET_2(SCL_VERT_FILTER_INIT_C, 0,
SCL_V_INIT_FRAC_C, init_frac,
SCL_V_INIT_INT_C, init_int);
if (REG(SCL_VERT_FILTER_INIT_BOT_C)) {
struct fixed31_32 bot = dc_fixpt_add(data->inits.v_c, data->ratios.vert_c);
init_frac = dc_fixpt_u0d19(bot) << 5;
init_int = dc_fixpt_floor(bot);
REG_SET_2(SCL_VERT_FILTER_INIT_BOT_C, 0,
SCL_V_INIT_FRAC_BOT_C, init_frac,
SCL_V_INIT_INT_BOT_C, init_int);
}
}
/**
* dpp1_dscl_set_recout - Set the first pixel of RECOUT in the OTG active area
*
* @dpp: DPP data struct
* @recout: Rectangle information
*
* This function sets the MPC RECOUT_START and RECOUT_SIZE registers based on
* the values specified in the recount parameter.
*
* Note: This function only have effect if AutoCal is disabled.
*/
static void dpp1_dscl_set_recout(struct dcn10_dpp *dpp,
const struct rect *recout)
{
REG_SET_2(RECOUT_START, 0,
/* First pixel of RECOUT in the active OTG area */
RECOUT_START_X, recout->x,
/* First line of RECOUT in the active OTG area */
RECOUT_START_Y, recout->y);
REG_SET_2(RECOUT_SIZE, 0,
/* Number of RECOUT horizontal pixels */
RECOUT_WIDTH, recout->width,
/* Number of RECOUT vertical lines */
RECOUT_HEIGHT, recout->height);
}
/**
* dpp1_dscl_set_scaler_manual_scale - Manually program scaler and line buffer
*
* @dpp_base: High level DPP struct
* @scl_data: scalaer_data info
*
* This is the primary function to program scaler and line buffer in manual
* scaling mode. To execute the required operations for manual scale, we need
* to disable AutoCal first.
*/
void dpp1_dscl_set_scaler_manual_scale(struct dpp *dpp_base,
const struct scaler_data *scl_data)
{
enum lb_memory_config lb_config;
struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base);
enum dscl_mode_sel dscl_mode = dpp1_dscl_get_dscl_mode(
dpp_base, scl_data, dpp_base->ctx->dc->debug.always_scale);
bool ycbcr = scl_data->format >= PIXEL_FORMAT_VIDEO_BEGIN
&& scl_data->format <= PIXEL_FORMAT_VIDEO_END;
if (memcmp(&dpp->scl_data, scl_data, sizeof(*scl_data)) == 0)
return;
PERF_TRACE();
dpp->scl_data = *scl_data;
if (dpp_base->ctx->dc->debug.enable_mem_low_power.bits.dscl) {
if (dscl_mode != DSCL_MODE_DSCL_BYPASS)
dpp1_power_on_dscl(dpp_base, true);
}
/* Autocal off */
REG_SET_3(DSCL_AUTOCAL, 0,
AUTOCAL_MODE, AUTOCAL_MODE_OFF,
AUTOCAL_NUM_PIPE, 0,
AUTOCAL_PIPE_ID, 0);
/*clean scaler boundary mode when Autocal off*/
REG_SET(DSCL_CONTROL, 0,
SCL_BOUNDARY_MODE, 0);
/* Recout */
dpp1_dscl_set_recout(dpp, &scl_data->recout);
/* MPC Size */
REG_SET_2(MPC_SIZE, 0,
/* Number of horizontal pixels of MPC */
MPC_WIDTH, scl_data->h_active,
/* Number of vertical lines of MPC */
MPC_HEIGHT, scl_data->v_active);
/* SCL mode */
REG_UPDATE(SCL_MODE, DSCL_MODE, dscl_mode);
if (dscl_mode == DSCL_MODE_DSCL_BYPASS) {
if (dpp_base->ctx->dc->debug.enable_mem_low_power.bits.dscl)
dpp1_power_on_dscl(dpp_base, false);
return;
}
/* LB */
lb_config = dpp1_dscl_find_lb_memory_config(dpp, scl_data);
dpp1_dscl_set_lb(dpp, &scl_data->lb_params, lb_config);
if (dscl_mode == DSCL_MODE_SCALING_444_BYPASS)
return;
/* Black offsets */
if (REG(SCL_BLACK_OFFSET)) {
if (ycbcr)
REG_SET_2(SCL_BLACK_OFFSET, 0,
SCL_BLACK_OFFSET_RGB_Y, BLACK_OFFSET_RGB_Y,
SCL_BLACK_OFFSET_CBCR, BLACK_OFFSET_CBCR);
else
REG_SET_2(SCL_BLACK_OFFSET, 0,
SCL_BLACK_OFFSET_RGB_Y, BLACK_OFFSET_RGB_Y,
SCL_BLACK_OFFSET_CBCR, BLACK_OFFSET_RGB_Y);
}
/* Manually calculate scale ratio and init values */
dpp1_dscl_set_manual_ratio_init(dpp, scl_data);
/* HTaps/VTaps */
REG_SET_4(SCL_TAP_CONTROL, 0,
SCL_V_NUM_TAPS, scl_data->taps.v_taps - 1,
SCL_H_NUM_TAPS, scl_data->taps.h_taps - 1,
SCL_V_NUM_TAPS_C, scl_data->taps.v_taps_c - 1,
SCL_H_NUM_TAPS_C, scl_data->taps.h_taps_c - 1);
dpp1_dscl_set_scl_filter(dpp, scl_data, ycbcr);
PERF_TRACE();
}