From: Jun Lei <Jun.Lei@xxxxxxx> [why] New dividers in DCCG need to be programmed depending on encoder/stream type since pixels per clock in OTG/DIO is different DIO also needs additional programming depending on pixels per clock Signed-off-by: Jun Lei <Jun.Lei@xxxxxxx> Signed-off-by: Alex Deucher <alexander.deucher@xxxxxxx> Signed-off-by: Rodrigo Siqueira <Rodrigo.Siqueira@xxxxxxx> --- .../display/dc/dcn10/dcn10_stream_encoder.h | 1 + .../drm/amd/display/dc/dcn20/dcn20_hwseq.c | 14 ++++ .../gpu/drm/amd/display/dc/dcn32/dcn32_dccg.c | 1 + .../dc/dcn32/dcn32_dio_stream_encoder.h | 3 +- .../drm/amd/display/dc/dcn32/dcn32_hwseq.c | 72 +++++++++++++++++-- .../drm/amd/display/dc/dcn32/dcn32_hwseq.h | 2 + .../gpu/drm/amd/display/dc/dcn32/dcn32_init.c | 1 + drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h | 3 +- .../amd/display/dc/inc/hw/stream_encoder.h | 3 + .../amd/display/dc/inc/hw_sequencer_private.h | 3 + 10 files changed, 95 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.h index f659aaab792e..034849e37860 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.h @@ -571,6 +571,7 @@ struct dcn10_stream_enc_registers { type DP_SEC_GSP11_LINE_NUM #define SE_REG_FIELD_LIST_DCN3_2(type) \ + type DIG_FIFO_OUTPUT_PIXEL_MODE;\ type DIG_SYMCLK_FE_ON;\ type DIG_FIFO_READ_START_LEVEL;\ type DIG_FIFO_ENABLE;\ diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c index d00a27893ab0..aed8ab06b41d 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c @@ -661,7 +661,17 @@ enum dc_status dcn20_enable_stream_timing( struct mpc_dwb_flow_control flow_control; struct mpc *mpc = dc->res_pool->mpc; bool rate_control_2x_pclk = (interlace || optc2_is_two_pixels_per_containter(&stream->timing)); + unsigned int k1_div = PIXEL_RATE_DIV_NA; + unsigned int k2_div = PIXEL_RATE_DIV_NA; + if (hws->funcs.calculate_dccg_k1_k2_values && dc->res_pool->dccg->funcs->set_pixel_rate_div) { + hws->funcs.calculate_dccg_k1_k2_values(pipe_ctx, &k1_div, &k2_div); + + dc->res_pool->dccg->funcs->set_pixel_rate_div( + dc->res_pool->dccg, + pipe_ctx->stream_res.tg->inst, + k1_div, k2_div); + } /* by upper caller loop, pipe0 is parent pipe and be called first. * back end is set up by for pipe0. Other children pipe share back end * with pipe 0. No program is needed. @@ -2485,6 +2495,10 @@ void dcn20_enable_stream(struct pipe_ctx *pipe_ctx) tg->funcs->set_early_control(tg, early_control); + if (pipe_ctx->stream_res.stream_enc->funcs->set_input_mode) + pipe_ctx->stream_res.stream_enc->funcs->set_input_mode(pipe_ctx->stream_res.stream_enc, + timing->pixel_encoding == PIXEL_ENCODING_YCBCR420 ? 2 : 1); + /* enable audio only within mode set */ if (pipe_ctx->stream_res.audio != NULL) { if (is_dp_128b_132b_signal(pipe_ctx)) diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_dccg.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_dccg.c index a3e0b95fdc84..c7d07203d21a 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_dccg.c +++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_dccg.c @@ -274,6 +274,7 @@ static const struct dccg_funcs dccg32_funcs = { .set_audio_dtbclk_dto = dccg31_set_audio_dtbclk_dto, .otg_add_pixel = dccg32_otg_add_pixel, .otg_drop_pixel = dccg32_otg_drop_pixel, + .set_pixel_rate_div = dccg32_set_pixel_rate_div, }; struct dccg *dccg32_create( diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_dio_stream_encoder.h b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_dio_stream_encoder.h index 77da0a13525b..042bc9aca944 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_dio_stream_encoder.h +++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_dio_stream_encoder.h @@ -240,7 +240,8 @@ SE_SF(DIG0_DIG_FIFO_CTRL0, DIG_FIFO_READ_START_LEVEL, mask_sh),\ SE_SF(DIG0_DIG_FIFO_CTRL0, DIG_FIFO_ENABLE, mask_sh),\ SE_SF(DIG0_DIG_FIFO_CTRL0, DIG_FIFO_RESET, mask_sh),\ - SE_SF(DIG0_DIG_FIFO_CTRL0, DIG_FIFO_RESET_DONE, mask_sh) + SE_SF(DIG0_DIG_FIFO_CTRL0, DIG_FIFO_RESET_DONE, mask_sh),\ + SE_SF(DIG0_DIG_FIFO_CTRL0, DIG_FIFO_OUTPUT_PIXEL_MODE, mask_sh) #if defined(CONFIG_DRM_AMD_DC_HDCP) #define SE_COMMON_MASK_SH_LIST_DCN32(mask_sh)\ diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.c index 8eed05aad54c..5994edc3dd0c 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.c @@ -47,6 +47,7 @@ #include "clk_mgr.h" #include "dsc.h" #include "dcn20/dcn20_optc.h" +#include "dc_link_dp.h" #define DC_LOGGER_INIT(logger) @@ -836,20 +837,44 @@ static void update_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable) } } +/* +* Given any pipe_ctx, return the total ODM combine factor, and optionally return +* the OPPids which are used +* */ +static unsigned int get_odm_config(struct pipe_ctx *pipe_ctx, unsigned int *opp_instances) +{ + unsigned int opp_count = 1; + struct pipe_ctx *odm_pipe; + + /* First get to the top pipe */ + for (odm_pipe = pipe_ctx; odm_pipe->prev_odm_pipe; odm_pipe = odm_pipe->prev_odm_pipe) + ; + + /* First pipe is always used */ + if (opp_instances) + opp_instances[0] = odm_pipe->stream_res.opp->inst; + + /* Find and count odm pipes, if any */ + for (odm_pipe = odm_pipe->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) { + if (opp_instances) + opp_instances[opp_count] = odm_pipe->stream_res.opp->inst; + opp_count++; + } + + return opp_count; +} + void dcn32_update_odm(struct dc *dc, struct dc_state *context, struct pipe_ctx *pipe_ctx) { struct pipe_ctx *odm_pipe; - int opp_cnt = 1; - int opp_inst[MAX_PIPES] = { pipe_ctx->stream_res.opp->inst }; + int opp_cnt = 0; + int opp_inst[MAX_PIPES] = {0}; bool rate_control_2x_pclk = (pipe_ctx->stream->timing.flags.INTERLACE || optc2_is_two_pixels_per_containter(&pipe_ctx->stream->timing)); struct mpc_dwb_flow_control flow_control; struct mpc *mpc = dc->res_pool->mpc; int i; - for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) { - opp_inst[opp_cnt] = odm_pipe->stream_res.opp->inst; - opp_cnt++; - } + opp_cnt = get_odm_config(pipe_ctx, opp_inst); if (opp_cnt > 1) pipe_ctx->stream_res.tg->funcs->set_odm_combine( @@ -892,3 +917,38 @@ void dcn32_update_odm(struct dc *dc, struct dc_state *context, struct pipe_ctx * update_dsc_on_stream(pipe_ctx, pipe_ctx->stream->timing.flags.DSC); } +unsigned int dcn32_calculate_dccg_k1_k2_values(struct pipe_ctx *pipe_ctx, unsigned int *k1_div, unsigned int *k2_div) +{ + struct dc_stream_state *stream = pipe_ctx->stream; + unsigned int odm_combine_factor = 0; + + odm_combine_factor = get_odm_config(pipe_ctx, NULL); + + if (is_dp_128b_132b_signal(pipe_ctx)) { + *k2_div = PIXEL_RATE_DIV_BY_1; + } else if (dc_is_hdmi_tmds_signal(pipe_ctx->stream->signal) || dc_is_dvi_signal(pipe_ctx->stream->signal)) { + *k1_div = PIXEL_RATE_DIV_BY_1; + if (stream->timing.pixel_encoding == PIXEL_ENCODING_YCBCR420) + *k2_div = PIXEL_RATE_DIV_BY_2; + else + *k2_div = PIXEL_RATE_DIV_BY_4; + } else if (dc_is_dp_signal(pipe_ctx->stream->signal)) { + if (stream->timing.pixel_encoding == PIXEL_ENCODING_YCBCR420) { + *k1_div = PIXEL_RATE_DIV_BY_1; + *k2_div = PIXEL_RATE_DIV_BY_2; + } else if (stream->timing.pixel_encoding == PIXEL_ENCODING_YCBCR422) { + *k1_div = PIXEL_RATE_DIV_BY_2; + *k2_div = PIXEL_RATE_DIV_BY_2; + } else { + if (odm_combine_factor == 1) + *k2_div = PIXEL_RATE_DIV_BY_4; + else if (odm_combine_factor == 2) + *k2_div = PIXEL_RATE_DIV_BY_2; + } + } + + if ((*k1_div == PIXEL_RATE_DIV_NA) && (*k2_div == PIXEL_RATE_DIV_NA)) + ASSERT(false); + + return odm_combine_factor; +} diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.h b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.h index 737a7fac5cf9..2a5bdcf58bc6 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.h +++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.h @@ -61,4 +61,6 @@ void dcn32_subvp_update_force_pstate(struct dc *dc, struct dc_state *context); void dcn32_update_odm(struct dc *dc, struct dc_state *context, struct pipe_ctx *pipe_ctx); +unsigned int dcn32_calculate_dccg_k1_k2_values(struct pipe_ctx *pipe_ctx, unsigned int *k1_div, unsigned int *k2_div); + #endif /* __DC_HWSS_DCN32_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_init.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_init.c index d1e3db1bc488..7f492734f881 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_init.c +++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_init.c @@ -141,6 +141,7 @@ static const struct hwseq_private_funcs dcn32_private_funcs = { .program_mall_pipe_config = dcn32_program_mall_pipe_config, .subvp_update_force_pstate = dcn32_subvp_update_force_pstate, .update_mall_sel = dcn32_update_mall_sel, + .calculate_dccg_k1_k2_values = dcn32_calculate_dccg_k1_k2_values, }; void dcn32_hw_sequencer_init_functions(struct dc *dc) diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h b/drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h index 2fbd65d88b61..a06c8daed5ed 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h @@ -59,7 +59,8 @@ enum dentist_dispclk_change_mode { enum pixel_rate_div { PIXEL_RATE_DIV_BY_1 = 0, PIXEL_RATE_DIV_BY_2 = 1, - PIXEL_RATE_DIV_BY_4 = 3 + PIXEL_RATE_DIV_BY_4 = 3, + PIXEL_RATE_DIV_NA = 0xF }; struct dccg { diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/stream_encoder.h b/drivers/gpu/drm/amd/display/dc/inc/hw/stream_encoder.h index 36ec56524afd..e5fe0f6adc86 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/stream_encoder.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/stream_encoder.h @@ -247,6 +247,9 @@ struct stream_encoder_funcs { uint32_t (*get_fifo_cal_average_level)( struct stream_encoder *enc); + + void (*set_input_mode)( + struct stream_encoder *enc, unsigned int pix_per_container); }; struct hpo_dp_stream_encoder_state { diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer_private.h b/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer_private.h index 5a0648784872..60d89e863d1e 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer_private.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer_private.h @@ -147,6 +147,9 @@ struct hwseq_private_funcs { void (*program_mall_pipe_config)(struct dc *dc, struct dc_state *context); void (*subvp_update_force_pstate)(struct dc *dc, struct dc_state *context); void (*update_mall_sel)(struct dc *dc, struct dc_state *context); + unsigned int (*calculate_dccg_k1_k2_values)(struct pipe_ctx *pipe_ctx, + unsigned int *k1_div, + unsigned int *k2_div); #endif }; -- 2.35.3