Commit 7a1dd866 authored by Samson Tam's avatar Samson Tam Committed by Alex Deucher

drm/amd/display: enable EASF support for DCN40

[Why]
Enable adaptive scaler support for DCN401

[How]
- Enable build flag for SPL
- Set prefer_easf flag to true
- Apply light linear scaling policy based on transfer function and pixel
  format.  Choose between linear or non-linear scaling
- Set matrix_mode based on pixel format
- Disable ring estimator
- Add missing EASF register defines, masks, and writes
- Disable EASF if scale ratio or number of taps is unsupported and when
  bypassing the scaler
- Add debug flags and registry keys for debugging SPL and EASF
- Add support for Visual Confirm with EASF
Reviewed-by: default avatarRodrigo Siqueira <Rodrigo.Siqueira@amd.com>
Signed-off-by: default avatarSamson Tam <Samson.Tam@amd.com>
Tested-by: default avatarDaniel Wheeler <daniel.wheeler@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 70bb97d9
......@@ -1500,8 +1500,8 @@ bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx)
pipe_ctx->plane_res.scl_data.format = convert_pixel_format_to_dalsurface(
pipe_ctx->plane_state->format);
if (pipe_ctx->stream->ctx->dc->config.use_spl) {
#if defined(CONFIG_DRM_AMD_DC_FP)
if ((pipe_ctx->stream->ctx->dc->config.use_spl) && (!pipe_ctx->stream->ctx->dc->debug.disable_spl)) {
struct spl_in *spl_in = &pipe_ctx->plane_res.spl_in;
struct spl_out *spl_out = &pipe_ctx->plane_res.spl_out;
......@@ -1516,15 +1516,18 @@ bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx)
// Convert pipe_ctx to respective input params for SPL
translate_SPL_in_params_from_pipe_ctx(pipe_ctx, spl_in);
/* Pass visual confirm debug information */
calculate_adjust_recout_for_visual_confirm(pipe_ctx,
&spl_in->debug.visual_confirm_base_offset,
&spl_in->debug.visual_confirm_dpp_offset);
// Set SPL output parameters to dscl_prog_data to be used for hw registers
spl_out->dscl_prog_data = resource_get_dscl_prog_data(pipe_ctx);
// Calculate scaler parameters from SPL
res = spl_calculate_scaler_params(spl_in, spl_out);
// Convert respective out params from SPL to scaler data
translate_SPL_out_params_to_pipe_ctx(pipe_ctx, spl_out);
#endif
} else {
#endif
/* depends on h_active */
calculate_recout(pipe_ctx);
/* depends on pixel format */
......@@ -1604,7 +1607,9 @@ bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx)
pipe_ctx->plane_res.scl_data.viewport.height = MIN_VIEWPORT_SIZE;
if (pipe_ctx->plane_res.scl_data.viewport.width < MIN_VIEWPORT_SIZE)
pipe_ctx->plane_res.scl_data.viewport.width = MIN_VIEWPORT_SIZE;
#ifdef CONFIG_DRM_AMD_DC_FP
}
#endif
DC_LOG_SCALER("%s pipe %d:\nViewport: height:%d width:%d x:%d y:%d Recout: height:%d width:%d x:%d y:%d HACTIVE:%d VACTIVE:%d\n"
"src_rect: height:%d width:%d x:%d y:%d dst_rect: height:%d width:%d x:%d y:%d clip_rect: height:%d width:%d x:%d y:%d\n",
__func__,
......
......@@ -1038,6 +1038,9 @@ struct dc_debug_options {
union dmub_fams2_global_feature_config fams2_config;
bool enable_legacy_clock_update;
unsigned int force_cositing;
unsigned int disable_spl;
unsigned int force_easf;
unsigned int force_lls;
};
......
......@@ -129,6 +129,11 @@ void translate_SPL_in_params_from_pipe_ctx(struct pipe_ctx *pipe_ctx, struct spl
populate_spltaps_from_taps(&spl_in->scaling_quality, &plane_state->scaling_quality);
// Translate edge adaptive scaler preference
spl_in->prefer_easf = pipe_ctx->stream->ctx->dc->config.prefer_easf;
spl_in->disable_easf = false;
if (pipe_ctx->stream->ctx->dc->debug.force_easf == 1)
spl_in->prefer_easf = false;
else if (pipe_ctx->stream->ctx->dc->debug.force_easf == 2)
spl_in->disable_easf = true;
// Translate adaptive sharpening preference
spl_in->adaptive_sharpness.enable = plane_state->adaptive_sharpness_en;
if (plane_state->sharpnessX1000 == 0) {
......@@ -141,13 +146,19 @@ void translate_SPL_in_params_from_pipe_ctx(struct pipe_ctx *pipe_ctx, struct spl
spl_in->adaptive_sharpness.sharpness = SHARPNESS_HIGH;
}
// Translate linear light scaling preference
spl_in->lls_pref = plane_state->linear_light_scaling;
if (pipe_ctx->stream->ctx->dc->debug.force_lls > 0)
spl_in->lls_pref = pipe_ctx->stream->ctx->dc->debug.force_lls;
else
spl_in->lls_pref = plane_state->linear_light_scaling;
/* Translate chroma subsampling offset ( cositing ) */
if (pipe_ctx->stream->ctx->dc->debug.force_cositing)
spl_in->basic_in.cositing = pipe_ctx->stream->ctx->dc->debug.force_cositing - 1;
else
spl_in->basic_in.cositing = plane_state->cositing;
/* Translate transfer function */
spl_in->basic_in.tf_type = (enum spl_transfer_func_type) plane_state->in_transfer_func.type;
spl_in->basic_in.tf_predefined_type = (enum spl_transfer_func_predefined) plane_state->in_transfer_func.tf;
}
/// @brief Translate SPL output parameters to pipe context
......
......@@ -373,7 +373,11 @@
TF_SF(DSCL0_ISHARP_NLDELTA_SOFT_CLIP, ISHARP_NLDELTA_SCLIP_SLOPE_P, mask_sh), \
TF_SF(DSCL0_ISHARP_NLDELTA_SOFT_CLIP, ISHARP_NLDELTA_SCLIP_EN_N, mask_sh), \
TF_SF(DSCL0_ISHARP_NLDELTA_SOFT_CLIP, ISHARP_NLDELTA_SCLIP_PIVOT_N, mask_sh), \
TF_SF(DSCL0_ISHARP_NLDELTA_SOFT_CLIP, ISHARP_NLDELTA_SCLIP_SLOPE_N, mask_sh)
TF_SF(DSCL0_ISHARP_NLDELTA_SOFT_CLIP, ISHARP_NLDELTA_SCLIP_SLOPE_N, mask_sh), \
TF_SF(DSCL0_SCL_VERT_FILTER_INIT_BOT, SCL_V_INIT_FRAC_BOT, mask_sh),\
TF_SF(DSCL0_SCL_VERT_FILTER_INIT_BOT, SCL_V_INIT_INT_BOT, mask_sh),\
TF_SF(DSCL0_SCL_VERT_FILTER_INIT_BOT_C, SCL_V_INIT_FRAC_BOT_C, mask_sh),\
TF_SF(DSCL0_SCL_VERT_FILTER_INIT_BOT_C, SCL_V_INIT_INT_BOT_C, mask_sh)
#define DPP_REG_FIELD_LIST_DCN401(type) \
DPP_REG_FIELD_LIST_DCN3(type); \
......
......@@ -1845,6 +1845,7 @@ static bool dcn401_resource_construct(
dc->caps.color.mpc.ogam_rom_caps.hlg = 0;
dc->caps.color.mpc.ocsc = 1;
dc->config.use_spl = true;
dc->config.prefer_easf = true;
dc->config.dc_mode_clk_limit_support = true;
dc->config.enable_windowed_mpo_odm = true;
/* read VBIOS LTTPR caps */
......
......@@ -342,7 +342,53 @@ bool dcn401_validate_bandwidth(struct dc *dc,
SRI_ARR(OBUF_MEM_PWR_CTRL, DSCL, id), \
SRI_ARR(DSCL_MEM_PWR_STATUS, DSCL, id), \
SRI_ARR(DSCL_MEM_PWR_CTRL, DSCL, id), \
SRI_ARR(DSCL_CONTROL, DSCL, id)
SRI_ARR(DSCL_CONTROL, DSCL, id), \
SRI_ARR(DSCL_SC_MODE, DSCL, id), \
SRI_ARR(DSCL_EASF_H_MODE, DSCL, id), \
SRI_ARR(DSCL_EASF_H_BF_CNTL, DSCL, id), \
SRI_ARR(DSCL_EASF_H_RINGEST_EVENTAP_REDUCE, DSCL, id), \
SRI_ARR(DSCL_EASF_H_RINGEST_EVENTAP_GAIN, DSCL, id), \
SRI_ARR(DSCL_EASF_H_BF_FINAL_MAX_MIN, DSCL, id), \
SRI_ARR(DSCL_EASF_H_BF1_PWL_SEG0, DSCL, id), \
SRI_ARR(DSCL_EASF_H_BF1_PWL_SEG1, DSCL, id), \
SRI_ARR(DSCL_EASF_H_BF1_PWL_SEG2, DSCL, id), \
SRI_ARR(DSCL_EASF_H_BF1_PWL_SEG3, DSCL, id), \
SRI_ARR(DSCL_EASF_H_BF1_PWL_SEG4, DSCL, id), \
SRI_ARR(DSCL_EASF_H_BF1_PWL_SEG5, DSCL, id), \
SRI_ARR(DSCL_EASF_H_BF1_PWL_SEG6, DSCL, id), \
SRI_ARR(DSCL_EASF_H_BF1_PWL_SEG7, DSCL, id), \
SRI_ARR(DSCL_EASF_H_BF3_PWL_SEG0, DSCL, id), \
SRI_ARR(DSCL_EASF_H_BF3_PWL_SEG1, DSCL, id), \
SRI_ARR(DSCL_EASF_H_BF3_PWL_SEG2, DSCL, id), \
SRI_ARR(DSCL_EASF_H_BF3_PWL_SEG3, DSCL, id), \
SRI_ARR(DSCL_EASF_H_BF3_PWL_SEG4, DSCL, id), \
SRI_ARR(DSCL_EASF_H_BF3_PWL_SEG5, DSCL, id), \
SRI_ARR(DSCL_EASF_V_MODE, DSCL, id), \
SRI_ARR(DSCL_EASF_V_BF_CNTL, DSCL, id), \
SRI_ARR(DSCL_EASF_V_RINGEST_3TAP_CNTL1, DSCL, id), \
SRI_ARR(DSCL_EASF_V_RINGEST_3TAP_CNTL2, DSCL, id), \
SRI_ARR(DSCL_EASF_V_RINGEST_3TAP_CNTL3, DSCL, id), \
SRI_ARR(DSCL_EASF_V_RINGEST_EVENTAP_REDUCE, DSCL, id), \
SRI_ARR(DSCL_EASF_V_RINGEST_EVENTAP_GAIN, DSCL, id), \
SRI_ARR(DSCL_EASF_V_BF_FINAL_MAX_MIN, DSCL, id), \
SRI_ARR(DSCL_EASF_V_BF1_PWL_SEG0, DSCL, id), \
SRI_ARR(DSCL_EASF_V_BF1_PWL_SEG1, DSCL, id), \
SRI_ARR(DSCL_EASF_V_BF1_PWL_SEG2, DSCL, id), \
SRI_ARR(DSCL_EASF_V_BF1_PWL_SEG3, DSCL, id), \
SRI_ARR(DSCL_EASF_V_BF1_PWL_SEG4, DSCL, id), \
SRI_ARR(DSCL_EASF_V_BF1_PWL_SEG5, DSCL, id), \
SRI_ARR(DSCL_EASF_V_BF1_PWL_SEG6, DSCL, id), \
SRI_ARR(DSCL_EASF_V_BF1_PWL_SEG7, DSCL, id), \
SRI_ARR(DSCL_EASF_V_BF3_PWL_SEG0, DSCL, id), \
SRI_ARR(DSCL_EASF_V_BF3_PWL_SEG1, DSCL, id), \
SRI_ARR(DSCL_EASF_V_BF3_PWL_SEG2, DSCL, id), \
SRI_ARR(DSCL_EASF_V_BF3_PWL_SEG3, DSCL, id), \
SRI_ARR(DSCL_EASF_V_BF3_PWL_SEG4, DSCL, id), \
SRI_ARR(DSCL_EASF_V_BF3_PWL_SEG5, DSCL, id), \
SRI_ARR(DSCL_SC_MATRIX_C0C1, DSCL, id), \
SRI_ARR(DSCL_SC_MATRIX_C2C3, DSCL, id), \
SRI_ARR(SCL_VERT_FILTER_INIT_BOT, DSCL, id), \
SRI_ARR(SCL_VERT_FILTER_INIT_BOT_C, DSCL, id)
/* OPP */
#define OPP_REG_LIST_DCN401_RI(id) \
......
......@@ -324,14 +324,18 @@ static void spl_calculate_recout(struct spl_in *spl_in, struct spl_out *spl_out)
overlapping_area = intersect_rec(&mpc_slice_of_plane_clip, &odm_slice);
if (overlapping_area.height > 0 &&
overlapping_area.width > 0)
overlapping_area.width > 0) {
/* shift the overlapping area so it is with respect to current
* ODM slice's position
*/
spl_out->scl_data.recout = shift_rec(
&overlapping_area,
-odm_slice.x, -odm_slice.y);
else
spl_out->scl_data.recout.height -=
spl_in->debug.visual_confirm_base_offset;
spl_out->scl_data.recout.height -=
spl_in->debug.visual_confirm_dpp_offset;
} else
/* if there is no overlap, zero recout */
memset(&spl_out->scl_data.recout, 0,
sizeof(struct spl_rect));
......@@ -493,13 +497,11 @@ static void spl_calculate_init_and_vp(bool flip_scan_dir,
static bool spl_is_yuv420(enum spl_pixel_format format)
{
switch (format) {
case SPL_PIXEL_FORMAT_420BPP8:
case SPL_PIXEL_FORMAT_420BPP10:
if ((format >= SPL_PIXEL_FORMAT_VIDEO_BEGIN) &&
(format <= SPL_PIXEL_FORMAT_VIDEO_END))
return true;
default:
return false;
}
return false;
}
/*Calculate inits and viewport */
......@@ -969,12 +971,17 @@ static bool enable_easf(int scale_ratio, int taps,
}
/* Set EASF data */
static void spl_set_easf_data(struct dscl_prog_data *dscl_prog_data,
bool enable_easf_v, bool enable_easf_h, enum linear_light_scaling lls_pref)
bool enable_easf_v, bool enable_easf_h, enum linear_light_scaling lls_pref,
enum spl_pixel_format format)
{
dscl_prog_data->easf_matrix_mode = 0;
if (spl_is_yuv420(format)) /* TODO: 0 = RGB, 1 = YUV */
dscl_prog_data->easf_matrix_mode = 1;
else
dscl_prog_data->easf_matrix_mode = 0;
if (enable_easf_v) {
dscl_prog_data->easf_v_en = true;
dscl_prog_data->easf_v_ring = 1;
dscl_prog_data->easf_v_ring = 0;
dscl_prog_data->easf_v_sharp_factor = 1;
dscl_prog_data->easf_v_bf1_en = 1; // 1-bit, BF1 calculation enable, 0=disable, 1=enable
dscl_prog_data->easf_v_bf2_mode = 0xF; // 4-bit, BF2 calculation mode
......@@ -1081,10 +1088,12 @@ static void spl_set_easf_data(struct dscl_prog_data *dscl_prog_data,
0x0780; // FP0.6.6, BF3 Input value PWL Segment 5 (0.5)
dscl_prog_data->easf_v_bf3_pwl_base_set5 = -63; // S0.6, BF3 Base PWL Segment 5
}
}
} else
dscl_prog_data->easf_v_en = false;
if (enable_easf_h) {
dscl_prog_data->easf_h_en = true;
dscl_prog_data->easf_h_ring = 1;
dscl_prog_data->easf_h_ring = 0;
dscl_prog_data->easf_h_sharp_factor = 1;
dscl_prog_data->easf_h_bf1_en =
1; // 1-bit, BF1 calculation enable, 0=disable, 1=enable
......@@ -1177,7 +1186,9 @@ static void spl_set_easf_data(struct dscl_prog_data *dscl_prog_data,
0x0780; // FP0.6.6, BF3 Input value PWL Segment 5 (0.5)
dscl_prog_data->easf_h_bf3_pwl_base_set5 = -63; // S0.6, BF3 Base PWL Segment 5
} // if (lls_pref == LLS_PREF_YES)
}
} else
dscl_prog_data->easf_h_en = false;
if (lls_pref == LLS_PREF_YES) {
dscl_prog_data->easf_ltonl_en = 1; // Linear input
dscl_prog_data->easf_matrix_c0 =
......@@ -1304,12 +1315,40 @@ static bool spl_get_isharp_en(struct adaptive_sharpness adp_sharpness,
}
return enable_isharp;
}
static bool spl_choose_lls_policy(enum spl_pixel_format format,
enum spl_transfer_func_type tf_type,
enum spl_transfer_func_predefined tf_predefined_type,
enum linear_light_scaling *lls_pref)
{
if (spl_is_yuv420(format)) {
*lls_pref = LLS_PREF_NO;
if ((tf_type == SPL_TF_TYPE_PREDEFINED) || (tf_type == SPL_TF_TYPE_DISTRIBUTED_POINTS))
return true;
} else { /* RGB or YUV444 */
if (tf_type == SPL_TF_TYPE_PREDEFINED) {
if ((tf_predefined_type == SPL_TRANSFER_FUNCTION_HLG) ||
(tf_predefined_type == SPL_TRANSFER_FUNCTION_HLG12))
*lls_pref = LLS_PREF_NO;
else
*lls_pref = LLS_PREF_YES;
return true;
} else if (tf_type == SPL_TF_TYPE_BYPASS) {
*lls_pref = LLS_PREF_YES;
return true;
}
}
*lls_pref = LLS_PREF_NO;
return false;
}
/* Caclulate scaler parameters */
bool spl_calculate_scaler_params(struct spl_in *spl_in, struct spl_out *spl_out)
{
bool res = false;
bool enable_easf_v = false;
bool enable_easf_h = false;
bool lls_enable_easf = true;
// All SPL calls
/* recout calculation */
/* depends on h_active */
......@@ -1335,17 +1374,33 @@ bool spl_calculate_scaler_params(struct spl_in *spl_in, struct spl_out *spl_out)
if (!res)
return res;
/*
* If lls_pref is LLS_PREF_DONT_CARE, then use pixel format and transfer
* function to determine whether to use LINEAR or NONLINEAR scaling
*/
if (spl_in->lls_pref == LLS_PREF_DONT_CARE)
lls_enable_easf = spl_choose_lls_policy(spl_in->basic_in.format,
spl_in->basic_in.tf_type, spl_in->basic_in.tf_predefined_type,
&spl_in->lls_pref);
// Save all calculated parameters in dscl_prog_data structure to program hw registers
spl_set_dscl_prog_data(spl_in, spl_out);
// Enable EASF on vertical?
int vratio = dc_fixpt_ceil(spl_out->scl_data.ratios.vert);
int hratio = dc_fixpt_ceil(spl_out->scl_data.ratios.horz);
enable_easf_v = enable_easf(vratio, spl_out->scl_data.taps.v_taps, spl_in->lls_pref, spl_in->prefer_easf);
// Enable EASF on horizontal?
enable_easf_h = enable_easf(hratio, spl_out->scl_data.taps.h_taps, spl_in->lls_pref, spl_in->prefer_easf);
if (!lls_enable_easf || spl_in->disable_easf) {
enable_easf_v = false;
enable_easf_h = false;
} else {
/* Enable EASF on vertical? */
enable_easf_v = enable_easf(vratio, spl_out->scl_data.taps.v_taps, spl_in->lls_pref, spl_in->prefer_easf);
/* Enable EASF on horizontal? */
enable_easf_h = enable_easf(hratio, spl_out->scl_data.taps.h_taps, spl_in->lls_pref, spl_in->prefer_easf);
}
// Set EASF
spl_set_easf_data(spl_out->dscl_prog_data, enable_easf_v, enable_easf_h, spl_in->lls_pref);
// Set iSHARP
spl_set_easf_data(spl_out->dscl_prog_data, enable_easf_v, enable_easf_h, spl_in->lls_pref,
spl_in->basic_in.format); // Set iSHARP
bool enable_isharp = spl_get_isharp_en(spl_in->adaptive_sharpness, vratio, hratio,
spl_out->scl_data.taps);
if (enable_isharp)
......
......@@ -132,6 +132,26 @@ struct spl_scaler_data {
struct spl_inits inits;
};
enum spl_transfer_func_type {
SPL_TF_TYPE_PREDEFINED,
SPL_TF_TYPE_DISTRIBUTED_POINTS,
SPL_TF_TYPE_BYPASS,
SPL_TF_TYPE_HWPWL
};
enum spl_transfer_func_predefined {
SPL_TRANSFER_FUNCTION_SRGB,
SPL_TRANSFER_FUNCTION_BT709,
SPL_TRANSFER_FUNCTION_PQ,
SPL_TRANSFER_FUNCTION_LINEAR,
SPL_TRANSFER_FUNCTION_UNITY,
SPL_TRANSFER_FUNCTION_HLG,
SPL_TRANSFER_FUNCTION_HLG12,
SPL_TRANSFER_FUNCTION_GAMMA22,
SPL_TRANSFER_FUNCTION_GAMMA24,
SPL_TRANSFER_FUNCTION_GAMMA26
};
/*==============================================================*/
/* Below structs are defined to hold hw register data */
......@@ -400,7 +420,8 @@ struct basic_in {
int mpc_combine_h; // MPC Horizontal Combine Factor (split_count)
int mpc_combine_v; // MPC Vertical Combine Factor (split_idx)
// Inputs for adaptive scaler - TODO
// struct dc_transfer_func transfer_func; // Transfer function
enum spl_transfer_func_type tf_type; /* Transfer function type */
enum spl_transfer_func_predefined tf_predefined_type; /* Transfer function predefined type */
// enum dc_transfer_func_predefined tf;
enum spl_color_space color_space; // Color Space
unsigned int max_luminance; // Max Luminance TODO: Is determined in dc_hw_sequencer.c is_sdr
......@@ -441,6 +462,11 @@ struct spl_funcs {
int *num_part_c);
};
struct spl_debug {
int visual_confirm_base_offset;
int visual_confirm_dpp_offset;
};
struct spl_in {
struct basic_out basic_out;
struct basic_in basic_in;
......@@ -452,6 +478,8 @@ struct spl_in {
struct adaptive_sharpness adaptive_sharpness; // Adaptive Sharpness
enum linear_light_scaling lls_pref; // Linear Light Scaling
bool prefer_easf;
bool disable_easf;
struct spl_debug debug;
};
// end of SPL inputs
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment