summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c
diff options
context:
space:
mode:
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.c183
1 files changed, 125 insertions, 58 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 77f16921e7f0..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
@@ -51,6 +51,7 @@
#include "link_hwss.h"
#include "dpcd_defs.h"
#include "dsc.h"
+#include "dce/dmub_hw_lock_mgr.h"
#define DC_LOGGER_INIT(logger)
@@ -1254,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,6 +1290,7 @@ void dcn10_init_hw(struct dc *dc)
hws->funcs.disable_vga(dc->hwseq);
hws->funcs.bios_golden_init(dc);
+
if (dc->ctx->dc_bios->fw_info_valid) {
res_pool->ref_clocks.xtalin_clock_inKhz =
dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency;
@@ -1320,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 &&
@@ -1329,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) {
@@ -1376,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->hwss.edp_backlight_control &&
- dc->hwss.power_down &&
- dc->hwss.edp_power_control) {
- dc->hwss.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 */
@@ -1453,6 +1433,48 @@ void dcn10_init_hw(struct dc *dc)
if (dc->clk_mgr->funcs->notify_wm_ranges)
dc->clk_mgr->funcs->notify_wm_ranges(dc->clk_mgr);
+#ifdef CONFIG_DRM_AMD_DC_DCN3_0
+ if (dc->clk_mgr->funcs->set_hard_max_memclk)
+ dc->clk_mgr->funcs->set_hard_max_memclk(dc->clk_mgr);
+#endif
+
+}
+
+/* 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(
@@ -1758,8 +1780,20 @@ void dcn10_cursor_lock(struct dc *dc, struct pipe_ctx *pipe, bool lock)
if (lock)
delay_cursor_until_vupdate(dc, pipe);
- dc->res_pool->mpc->funcs->cursor_lock(dc->res_pool->mpc,
- pipe->stream_res.opp->inst, lock);
+ 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_cursor = 1;
+ inst_flags.opp_inst = pipe->stream_res.opp->inst;
+
+ dmub_hw_lock_mgr_cmd(dc->ctx->dmub_srv,
+ lock,
+ &hw_locks,
+ &inst_flags);
+ } else
+ dc->res_pool->mpc->funcs->cursor_lock(dc->res_pool->mpc,
+ pipe->stream_res.opp->inst, lock);
}
static bool wait_for_reset_trigger_to_occur(
@@ -2425,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,
@@ -2576,14 +2642,15 @@ void dcn10_blank_pixel_data(
if (stream_res->tg->funcs->set_blank)
stream_res->tg->funcs->set_blank(stream_res->tg, 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);
}
} else if (blank) {
dc->hwss.set_abm_immediate_disable(pipe_ctx);
- if (stream_res->tg->funcs->set_blank)
+ if (stream_res->tg->funcs->set_blank) {
+ stream_res->tg->funcs->wait_for_state(stream_res->tg, CRTC_STATE_VBLANK);
stream_res->tg->funcs->set_blank(stream_res->tg, blank);
+ }
}
}