diff options
Diffstat (limited to 'drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c')
-rw-r--r-- | drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c | 156 |
1 files changed, 101 insertions, 55 deletions
diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c index cb45f05a0319..da0897fe3b54 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c @@ -1255,6 +1255,7 @@ void dcn10_init_hw(struct dc *dc) struct dc_bios *dcb = dc->ctx->dc_bios; struct resource_pool *res_pool = dc->res_pool; uint32_t backlight = MAX_BACKLIGHT_LEVEL; + bool is_optimized_init_done = false; if (dc->clk_mgr && dc->clk_mgr->funcs->init_clocks) dc->clk_mgr->funcs->init_clocks(dc->clk_mgr); @@ -1288,8 +1289,7 @@ void dcn10_init_hw(struct dc *dc) if (!dcb->funcs->is_accelerated_mode(dcb)) hws->funcs.disable_vga(dc->hwseq); - if (!dc_dmub_srv_optimized_init_done(dc->ctx->dmub_srv)) - hws->funcs.bios_golden_init(dc); + hws->funcs.bios_golden_init(dc); if (dc->ctx->dc_bios->fw_info_valid) { res_pool->ref_clocks.xtalin_clock_inKhz = @@ -1323,7 +1323,8 @@ void dcn10_init_hw(struct dc *dc) */ struct dc_link *link = dc->links[i]; - link->link_enc->funcs->hw_init(link->link_enc); + if (!is_optimized_init_done) + link->link_enc->funcs->hw_init(link->link_enc); /* Check for enabled DIG to identify enabled display */ if (link->link_enc->funcs->is_dig_enabled && @@ -1332,9 +1333,11 @@ void dcn10_init_hw(struct dc *dc) } /* Power gate DSCs */ - for (i = 0; i < res_pool->res_cap->num_dsc; i++) - if (hws->funcs.dsc_pg_control != NULL) - hws->funcs.dsc_pg_control(hws, res_pool->dscs[i]->inst, false); + if (!is_optimized_init_done) { + for (i = 0; i < res_pool->res_cap->num_dsc; i++) + if (hws->funcs.dsc_pg_control != NULL) + hws->funcs.dsc_pg_control(hws, res_pool->dscs[i]->inst, false); + } /* we want to turn off all dp displays before doing detection */ if (dc->config.power_down_display_on_boot) { @@ -1379,68 +1382,42 @@ void dcn10_init_hw(struct dc *dc) * everything down. */ if (dcb->funcs->is_accelerated_mode(dcb) || dc->config.power_down_display_on_boot) { - hws->funcs.init_pipes(dc, dc->current_state); - if (dc->res_pool->hubbub->funcs->allow_self_refresh_control) - dc->res_pool->hubbub->funcs->allow_self_refresh_control(dc->res_pool->hubbub, - !dc->res_pool->hubbub->ctx->dc->debug.disable_stutter); + if (!is_optimized_init_done) { + hws->funcs.init_pipes(dc, dc->current_state); + if (dc->res_pool->hubbub->funcs->allow_self_refresh_control) + dc->res_pool->hubbub->funcs->allow_self_refresh_control(dc->res_pool->hubbub, + !dc->res_pool->hubbub->ctx->dc->debug.disable_stutter); + } } - /* In headless boot cases, DIG may be turned - * on which causes HW/SW discrepancies. - * To avoid this, power down hardware on boot - * if DIG is turned on and seamless boot not enabled - */ - if (dc->config.power_down_display_on_boot) { - struct dc_link *edp_link = get_edp_link(dc); + if (!is_optimized_init_done) { - if (edp_link && - edp_link->link_enc->funcs->is_dig_enabled && - edp_link->link_enc->funcs->is_dig_enabled(edp_link->link_enc) && - dc->hwseq->funcs.edp_backlight_control && - dc->hwss.power_down && - dc->hwss.edp_power_control) { - dc->hwseq->funcs.edp_backlight_control(edp_link, false); - dc->hwss.power_down(dc); - dc->hwss.edp_power_control(edp_link, false); - } else { - for (i = 0; i < dc->link_count; i++) { - struct dc_link *link = dc->links[i]; + for (i = 0; i < res_pool->audio_count; i++) { + struct audio *audio = res_pool->audios[i]; - if (link->link_enc->funcs->is_dig_enabled && - link->link_enc->funcs->is_dig_enabled(link->link_enc) && - dc->hwss.power_down) { - dc->hwss.power_down(dc); - break; - } - - } + audio->funcs->hw_init(audio); } - } - for (i = 0; i < res_pool->audio_count; i++) { - struct audio *audio = res_pool->audios[i]; + for (i = 0; i < dc->link_count; i++) { + struct dc_link *link = dc->links[i]; - audio->funcs->hw_init(audio); - } + if (link->panel_cntl) + backlight = link->panel_cntl->funcs->hw_init(link->panel_cntl); + } - for (i = 0; i < dc->link_count; i++) { - struct dc_link *link = dc->links[i]; + if (abm != NULL) + abm->funcs->abm_init(abm, backlight); - if (link->panel_cntl) - backlight = link->panel_cntl->funcs->hw_init(link->panel_cntl); + if (dmcu != NULL && !dmcu->auto_load_dmcu) + dmcu->funcs->dmcu_init(dmcu); } - if (abm != NULL) - abm->funcs->abm_init(abm, backlight); - - if (dmcu != NULL && !dmcu->auto_load_dmcu) - dmcu->funcs->dmcu_init(dmcu); - if (abm != NULL && dmcu != NULL) abm->dmcu_is_running = dmcu->funcs->is_dmcu_initialized(dmcu); /* power AFMT HDMI memory TODO: may move to dis/en output save power*/ - REG_WRITE(DIO_MEM_PWR_CTRL, 0); + if (!is_optimized_init_done) + REG_WRITE(DIO_MEM_PWR_CTRL, 0); if (!dc->debug.disable_clock_gate) { /* enable all DCN clock gating */ @@ -1463,6 +1440,43 @@ void dcn10_init_hw(struct dc *dc) } +/* In headless boot cases, DIG may be turned + * on which causes HW/SW discrepancies. + * To avoid this, power down hardware on boot + * if DIG is turned on and seamless boot not enabled + */ +void dcn10_power_down_on_boot(struct dc *dc) +{ + int i = 0; + + if (dc->config.power_down_display_on_boot) { + struct dc_link *edp_link = get_edp_link(dc); + + if (edp_link && + edp_link->link_enc->funcs->is_dig_enabled && + edp_link->link_enc->funcs->is_dig_enabled(edp_link->link_enc) && + dc->hwseq->funcs.edp_backlight_control && + dc->hwss.power_down && + dc->hwss.edp_power_control) { + dc->hwseq->funcs.edp_backlight_control(edp_link, false); + dc->hwss.power_down(dc); + dc->hwss.edp_power_control(edp_link, false); + } else { + for (i = 0; i < dc->link_count; i++) { + struct dc_link *link = dc->links[i]; + + if (link->link_enc->funcs->is_dig_enabled && + link->link_enc->funcs->is_dig_enabled(link->link_enc) && + dc->hwss.power_down) { + dc->hwss.power_down(dc); + break; + } + + } + } + } +} + void dcn10_reset_hw_ctx_wrap( struct dc *dc, struct dc_state *context) @@ -2445,14 +2459,46 @@ static void dcn10_update_dchubp_dpp( struct dc_plane_state *plane_state = pipe_ctx->plane_state; struct plane_size size = plane_state->plane_size; unsigned int compat_level = 0; + bool should_divided_by_2 = false; /* depends on DML calculation, DPP clock value may change dynamically */ /* If request max dpp clk is lower than current dispclk, no need to * divided by 2 */ if (plane_state->update_flags.bits.full_update) { - bool should_divided_by_2 = context->bw_ctx.bw.dcn.clk.dppclk_khz <= - dc->clk_mgr->clks.dispclk_khz / 2; + + /* new calculated dispclk, dppclk are stored in + * context->bw_ctx.bw.dcn.clk.dispclk_khz / dppclk_khz. current + * dispclk, dppclk are from dc->clk_mgr->clks.dispclk_khz. + * dcn_validate_bandwidth compute new dispclk, dppclk. + * dispclk will put in use after optimize_bandwidth when + * ramp_up_dispclk_with_dpp is called. + * there are two places for dppclk be put in use. One location + * is the same as the location as dispclk. Another is within + * update_dchubp_dpp which happens between pre_bandwidth and + * optimize_bandwidth. + * dppclk updated within update_dchubp_dpp will cause new + * clock values of dispclk and dppclk not be in use at the same + * time. when clocks are decreased, this may cause dppclk is + * lower than previous configuration and let pipe stuck. + * for example, eDP + external dp, change resolution of DP from + * 1920x1080x144hz to 1280x960x60hz. + * before change: dispclk = 337889 dppclk = 337889 + * change mode, dcn_validate_bandwidth calculate + * dispclk = 143122 dppclk = 143122 + * update_dchubp_dpp be executed before dispclk be updated, + * dispclk = 337889, but dppclk use new value dispclk /2 = + * 168944. this will cause pipe pstate warning issue. + * solution: between pre_bandwidth and optimize_bandwidth, while + * dispclk is going to be decreased, keep dppclk = dispclk + **/ + if (context->bw_ctx.bw.dcn.clk.dispclk_khz < + dc->clk_mgr->clks.dispclk_khz) + should_divided_by_2 = false; + else + should_divided_by_2 = + context->bw_ctx.bw.dcn.clk.dppclk_khz <= + dc->clk_mgr->clks.dispclk_khz / 2; dpp->funcs->dpp_dppclk_control( dpp, |