diff options
Diffstat (limited to 'drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c')
-rw-r--r-- | drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c | 166 |
1 files changed, 149 insertions, 17 deletions
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 da5333d165ac..c8cfd3ba1c15 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c @@ -49,6 +49,8 @@ #include "dc_link_dp.h" #include "vm_helper.h" #include "dccg.h" +#include "dc_dmub_srv.h" +#include "dce/dmub_hw_lock_mgr.h" #define DC_LOGGER_INIT(logger) @@ -291,12 +293,20 @@ void dcn20_init_blank( /* get the OPTC source */ tg->funcs->get_optc_source(tg, &num_opps, &opp_id_src0, &opp_id_src1); - ASSERT(opp_id_src0 < dc->res_pool->res_cap->num_opp); + + if (opp_id_src0 >= dc->res_pool->res_cap->num_opp) { + ASSERT(false); + return; + } opp = dc->res_pool->opps[opp_id_src0]; if (num_opps == 2) { otg_active_width = otg_active_width / 2; - ASSERT(opp_id_src1 < dc->res_pool->res_cap->num_opp); + + if (opp_id_src1 >= dc->res_pool->res_cap->num_opp) { + ASSERT(false); + return; + } bottom_opp = dc->res_pool->opps[opp_id_src1]; } @@ -601,6 +611,31 @@ void dcn20_disable_plane(struct dc *dc, struct pipe_ctx *pipe_ctx) pipe_ctx->pipe_idx); } +#if defined(CONFIG_DRM_AMD_DC_DCN3_0) +static int calc_mpc_flow_ctrl_cnt(const struct dc_stream_state *stream, + int opp_cnt) +{ + bool hblank_halved = optc2_is_two_pixels_per_containter(&stream->timing); + int flow_ctrl_cnt; + + if (opp_cnt >= 2) + hblank_halved = true; + + flow_ctrl_cnt = stream->timing.h_total - stream->timing.h_addressable - + stream->timing.h_border_left - + stream->timing.h_border_right; + + if (hblank_halved) + flow_ctrl_cnt /= 2; + + /* ODM combine 4:1 case */ + if (opp_cnt == 4) + flow_ctrl_cnt /= 2; + + return flow_ctrl_cnt; +} +#endif + enum dc_status dcn20_enable_stream_timing( struct pipe_ctx *pipe_ctx, struct dc_state *context, @@ -614,6 +649,15 @@ enum dc_status dcn20_enable_stream_timing( int opp_cnt = 1; int opp_inst[MAX_PIPES] = { pipe_ctx->stream_res.opp->inst }; +#if defined(CONFIG_DRM_AMD_DC_DCN3_0) + bool interlace = stream->timing.flags.INTERLACE; + int i; + + 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)); + +#endif /* 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. @@ -660,6 +704,21 @@ enum dc_status dcn20_enable_stream_timing( pipe_ctx->stream->signal, true); +#if defined(CONFIG_DRM_AMD_DC_DCN3_0) + rate_control_2x_pclk = rate_control_2x_pclk || opp_cnt > 1; + flow_control.flow_ctrl_mode = 0; + flow_control.flow_ctrl_cnt0 = 0x80; + flow_control.flow_ctrl_cnt1 = calc_mpc_flow_ctrl_cnt(stream, opp_cnt); + if (mpc->funcs->set_out_rate_control) { + for (i = 0; i < opp_cnt; ++i) { + mpc->funcs->set_out_rate_control( + mpc, opp_inst[i], + true, + rate_control_2x_pclk, + &flow_control); + } + } +#endif for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) odm_pipe->stream_res.opp->funcs->opp_pipe_clock_control( odm_pipe->stream_res.opp, @@ -996,8 +1055,7 @@ void dcn20_blank_pixel_data( if (!blank) if (stream_res->abm) { - stream_res->abm->funcs->set_pipe(stream_res->abm, stream_res->tg->inst + 1, - stream->link->panel_cntl->inst); + dc->hwss.set_pipe(pipe_ctx); stream_res->abm->funcs->set_abm_level(stream_res->abm, stream->abm_level); } } @@ -1138,7 +1196,21 @@ void dcn20_pipe_control_lock( (!flip_immediate && pipe->stream_res.gsl_group > 0)) dcn20_setup_gsl_group_as_lock(dc, pipe, flip_immediate); - if (pipe->plane_state != NULL && pipe->plane_state->triplebuffer_flips) { + if (pipe->stream && should_use_dmub_lock(pipe->stream->link)) { + union dmub_hw_lock_flags hw_locks = { 0 }; + struct dmub_hw_lock_inst_flags inst_flags = { 0 }; + + hw_locks.bits.lock_pipe = 1; + inst_flags.otg_inst = pipe->stream_res.tg->inst; + + if (pipe->plane_state != NULL) + hw_locks.bits.triple_buffer_lock = pipe->plane_state->triplebuffer_flips; + + dmub_hw_lock_mgr_cmd(dc->ctx->dmub_srv, + lock, + &hw_locks, + &inst_flags); + } else if (pipe->plane_state != NULL && pipe->plane_state->triplebuffer_flips) { if (lock) pipe->stream_res.tg->funcs->triplebuffer_lock(pipe->stream_res.tg); else @@ -1209,14 +1281,13 @@ static void dcn20_detect_pipe_changes(struct pipe_ctx *old_pipe, struct pipe_ctx if (old_pipe->stream_res.tg != new_pipe->stream_res.tg) new_pipe->update_flags.bits.tg_changed = 1; - /* Detect mpcc blending changes, only dpp inst and bot matter here */ + /* + * Detect mpcc blending changes, only dpp inst and opp matter here, + * mpccs getting removed/inserted update connected ones during their own + * programming + */ if (old_pipe->plane_res.dpp != new_pipe->plane_res.dpp - || old_pipe->stream_res.opp != new_pipe->stream_res.opp - || (!old_pipe->bottom_pipe && new_pipe->bottom_pipe) - || (old_pipe->bottom_pipe && !new_pipe->bottom_pipe) - || (old_pipe->bottom_pipe && new_pipe->bottom_pipe - && old_pipe->bottom_pipe->plane_res.mpcc_inst - != new_pipe->bottom_pipe->plane_res.mpcc_inst)) + || old_pipe->stream_res.opp != new_pipe->stream_res.opp) new_pipe->update_flags.bits.mpcc = 1; /* Detect dppclk change */ @@ -1386,8 +1457,8 @@ static void dcn20_update_dchubp_dpp( /* Any updates are handled in dc interface, just need to apply existing for plane enable */ if ((pipe_ctx->update_flags.bits.enable || pipe_ctx->update_flags.bits.opp_changed || - pipe_ctx->update_flags.bits.scaler || pipe_ctx->update_flags.bits.viewport) - && pipe_ctx->stream->cursor_attributes.address.quad_part != 0) { + pipe_ctx->update_flags.bits.scaler || viewport_changed == true) && + pipe_ctx->stream->cursor_attributes.address.quad_part != 0) { dc->hwss.set_cursor_position(pipe_ctx); dc->hwss.set_cursor_attribute(pipe_ctx); @@ -1400,6 +1471,38 @@ static void dcn20_update_dchubp_dpp( if (pipe_ctx->update_flags.bits.enable || pipe_ctx->update_flags.bits.opp_changed || pipe_ctx->stream->update_flags.bits.gamut_remap || pipe_ctx->stream->update_flags.bits.out_csc) { +#if defined(CONFIG_DRM_AMD_DC_DCN3_0) + struct mpc *mpc = pipe_ctx->stream_res.opp->ctx->dc->res_pool->mpc; + + if (mpc->funcs->set_gamut_remap) { + int i; + int mpcc_id = hubp->inst; + struct mpc_grph_gamut_adjustment adjust; + bool enable_remap_dpp = false; + + memset(&adjust, 0, sizeof(adjust)); + adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_BYPASS; + + /* save the enablement of gamut remap for dpp */ + enable_remap_dpp = pipe_ctx->stream->gamut_remap_matrix.enable_remap; + + /* force bypass gamut remap for dpp/cm */ + pipe_ctx->stream->gamut_remap_matrix.enable_remap = false; + dc->hwss.program_gamut_remap(pipe_ctx); + + /* restore gamut remap flag and use this remap into mpc */ + pipe_ctx->stream->gamut_remap_matrix.enable_remap = enable_remap_dpp; + + /* build remap matrix for top plane if enabled */ + if (enable_remap_dpp && pipe_ctx->top_pipe == NULL) { + adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_SW; + for (i = 0; i < CSC_TEMPERATURE_MATRIX_SIZE; i++) + adjust.temperature_matrix[i] = + pipe_ctx->stream->gamut_remap_matrix.matrix[i]; + } + mpc->funcs->set_gamut_remap(mpc, mpcc_id, &adjust); + } else +#endif /* dpp/cm gamut remap*/ dc->hwss.program_gamut_remap(pipe_ctx); @@ -1436,9 +1539,6 @@ static void dcn20_update_dchubp_dpp( hubp->power_gated = false; } - if (hubp->funcs->apply_PLAT_54186_wa && viewport_changed) - hubp->funcs->apply_PLAT_54186_wa(hubp, &plane_state->address); - if (pipe_ctx->update_flags.bits.enable || plane_state->update_flags.bits.addr_update) hws->funcs.update_plane_addr(dc, pipe_ctx); @@ -2162,6 +2262,11 @@ void dcn20_update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx) blnd_cfg.bottom_inside_gain = 0x1f000; blnd_cfg.bottom_outside_gain = 0x1f000; blnd_cfg.pre_multiplied_alpha = per_pixel_alpha; +#if defined(CONFIG_DRM_AMD_DC_DCN3_0) + if (pipe_ctx->plane_state->format + == SURFACE_PIXEL_FORMAT_GRPH_RGBE_ALPHA) + blnd_cfg.pre_multiplied_alpha = false; +#endif /* * TODO: remove hack @@ -2393,3 +2498,30 @@ void dcn20_fpga_init_hw(struct dc *dc) tg->funcs->tg_init(tg); } } +#ifndef TRIM_FSFT +bool dcn20_optimize_timing_for_fsft(struct dc *dc, + struct dc_crtc_timing *timing, + unsigned int max_input_rate_in_khz) +{ + unsigned int old_v_front_porch; + unsigned int old_v_total; + unsigned int max_input_rate_in_100hz; + unsigned long long new_v_total; + + max_input_rate_in_100hz = max_input_rate_in_khz * 10; + if (max_input_rate_in_100hz < timing->pix_clk_100hz) + return false; + + old_v_total = timing->v_total; + old_v_front_porch = timing->v_front_porch; + + timing->fast_transport_output_rate_100hz = timing->pix_clk_100hz; + timing->pix_clk_100hz = max_input_rate_in_100hz; + + new_v_total = div_u64((unsigned long long)old_v_total * max_input_rate_in_100hz, timing->pix_clk_100hz); + + timing->v_total = new_v_total; + timing->v_front_porch = old_v_front_porch + (timing->v_total - old_v_total); + return true; +} +#endif |