Commit 0f782777 authored by Martin Leung's avatar Martin Leung Committed by Alex Deucher

drm/amd/display: enable seamless boot for dcn30

why:
seamless boots requires split of init_hw into hw and pipes to work. This
was implemented in dcn10_init_hw but did not apply yet to dcn30.

how:
Copy over dcn10_init_hw and adapt it to dcn30 using recent changes to
dcn3.  Behavior will be different in init sequence.
Signed-off-by: default avatarMartin Leung <martin.leung@amd.com>
Reviewed-by: default avatarAnthony Koo <Anthony.Koo@amd.com>
Acked-by: default avatarRodrigo Siqueira <Rodrigo.Siqueira@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 3c08d625
...@@ -47,6 +47,8 @@ ...@@ -47,6 +47,8 @@
#include "mpc.h" #include "mpc.h"
#include "mcif_wb.h" #include "mcif_wb.h"
#include "dc_dmub_srv.h" #include "dc_dmub_srv.h"
#include "link_hwss.h"
#include "dpcd_defs.h"
...@@ -427,7 +429,6 @@ void dcn30_init_hw(struct dc *dc) ...@@ -427,7 +429,6 @@ void dcn30_init_hw(struct dc *dc)
struct dce_hwseq *hws = dc->hwseq; struct dce_hwseq *hws = dc->hwseq;
struct dc_bios *dcb = dc->ctx->dc_bios; struct dc_bios *dcb = dc->ctx->dc_bios;
struct resource_pool *res_pool = dc->res_pool; struct resource_pool *res_pool = dc->res_pool;
struct dc_state *context = dc->current_state;
uint32_t backlight = MAX_BACKLIGHT_LEVEL; uint32_t backlight = MAX_BACKLIGHT_LEVEL;
if (dc->clk_mgr && dc->clk_mgr->funcs->init_clocks) if (dc->clk_mgr && dc->clk_mgr->funcs->init_clocks)
...@@ -437,19 +438,28 @@ void dcn30_init_hw(struct dc *dc) ...@@ -437,19 +438,28 @@ void dcn30_init_hw(struct dc *dc)
if (res_pool->dccg->funcs->dccg_init) if (res_pool->dccg->funcs->dccg_init)
res_pool->dccg->funcs->dccg_init(res_pool->dccg); res_pool->dccg->funcs->dccg_init(res_pool->dccg);
//Enable ability to power gate / don't force power on permanently
hws->funcs.enable_power_gating_plane(dc->hwseq, true);
if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) { if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) {
REG_WRITE(RBBMIF_TIMEOUT_DIS, 0xFFFFFFFF);
REG_WRITE(RBBMIF_TIMEOUT_DIS_2, 0xFFFFFFFF);
hws->funcs.dccg_init(hws);
REG_UPDATE(DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_REFDIV, 2);
REG_UPDATE(DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_ENABLE, 1);
REG_WRITE(REFCLK_CNTL, 0); REG_WRITE(REFCLK_CNTL, 0);
} else { REG_UPDATE(DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_ENABLE, 1);
REG_WRITE(DIO_MEM_PWR_CTRL, 0);
if (!dc->debug.disable_clock_gate) {
/* enable all DCN clock gating */
REG_WRITE(DCCG_GATE_DISABLE_CNTL, 0);
REG_WRITE(DCCG_GATE_DISABLE_CNTL2, 0);
REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0);
}
//Enable ability to power gate / don't force power on permanently
if (hws->funcs.enable_power_gating_plane)
hws->funcs.enable_power_gating_plane(hws, true);
return;
}
if (!dcb->funcs->is_accelerated_mode(dcb)) { if (!dcb->funcs->is_accelerated_mode(dcb)) {
hws->funcs.bios_golden_init(dc); hws->funcs.bios_golden_init(dc);
hws->funcs.disable_vga(dc->hwseq); hws->funcs.disable_vga(dc->hwseq);
...@@ -488,102 +498,95 @@ void dcn30_init_hw(struct dc *dc) ...@@ -488,102 +498,95 @@ void dcn30_init_hw(struct dc *dc)
struct dc_link *link = dc->links[i]; struct dc_link *link = dc->links[i];
link->link_enc->funcs->hw_init(link->link_enc); 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 &&
link->link_enc->funcs->is_dig_enabled(link->link_enc))
link->link_status.link_active = true;
} }
/* Power gate DSCs */ /* Power gate DSCs */
for (i = 0; i < res_pool->res_cap->num_dsc; i++) 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); hws->funcs.dsc_pg_control(hws, res_pool->dscs[i]->inst, false);
/* Blank pixel data with OPP DPG */ /* we want to turn off all dp displays before doing detection */
for (i = 0; i < dc->res_pool->timing_generator_count; i++) { if (dc->config.power_down_display_on_boot) {
struct timing_generator *tg = dc->res_pool->timing_generators[i]; uint8_t dpcd_power_state = '\0';
enum dc_status status = DC_ERROR_UNEXPECTED;
if (tg->funcs->is_tg_enabled(tg)) for (i = 0; i < dc->link_count; i++) {
hws->funcs.init_blank(dc, tg); if (dc->links[i]->connector_signal != SIGNAL_TYPE_DISPLAY_PORT)
continue;
/* if any of the displays are lit up turn them off */
status = core_link_read_dpcd(dc->links[i], DP_SET_POWER,
&dpcd_power_state, sizeof(dpcd_power_state));
if (status == DC_OK && dpcd_power_state == DP_POWER_STATE_D0) {
/* blank dp stream before power off receiver*/
if (dc->links[i]->link_enc->funcs->get_dig_frontend) {
unsigned int fe;
fe = dc->links[i]->link_enc->funcs->get_dig_frontend(
dc->links[i]->link_enc);
for (j = 0; j < dc->res_pool->stream_enc_count; j++) {
if (fe == dc->res_pool->stream_enc[j]->id) {
dc->res_pool->stream_enc[j]->funcs->dp_blank(
dc->res_pool->stream_enc[j]);
break;
} }
for (i = 0; i < res_pool->timing_generator_count; i++) {
struct timing_generator *tg = dc->res_pool->timing_generators[i];
if (tg->funcs->is_tg_enabled(tg))
tg->funcs->lock(tg);
} }
for (i = 0; i < dc->res_pool->pipe_count; i++) {
struct dpp *dpp = res_pool->dpps[i];
dpp->funcs->dpp_reset(dpp);
} }
dp_receiver_power_ctrl(dc->links[i], false);
/* Reset all MPCC muxes */
res_pool->mpc->funcs->mpc_init(res_pool->mpc);
/* initialize OPP mpc_tree parameter */
for (i = 0; i < dc->res_pool->res_cap->num_opp; i++) {
res_pool->opps[i]->mpc_tree_params.opp_id = res_pool->opps[i]->inst;
res_pool->opps[i]->mpc_tree_params.opp_list = NULL;
for (j = 0; j < MAX_PIPES; j++)
res_pool->opps[i]->mpcc_disconnect_pending[j] = false;
} }
for (i = 0; i < dc->res_pool->pipe_count; i++) {
struct timing_generator *tg = dc->res_pool->timing_generators[i];
struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
struct hubp *hubp = dc->res_pool->hubps[i];
struct dpp *dpp = dc->res_pool->dpps[i];
pipe_ctx->stream_res.tg = tg;
pipe_ctx->pipe_idx = i;
pipe_ctx->plane_res.hubp = hubp;
pipe_ctx->plane_res.dpp = dpp;
pipe_ctx->plane_res.mpcc_inst = dpp->inst;
hubp->mpcc_id = dpp->inst;
hubp->opp_id = OPP_ID_INVALID;
hubp->power_gated = false;
pipe_ctx->stream_res.opp = NULL;
hubp->funcs->hubp_init(hubp);
//dc->res_pool->opps[i]->mpc_tree_params.opp_id = dc->res_pool->opps[i]->inst;
//dc->res_pool->opps[i]->mpc_tree_params.opp_list = NULL;
dc->res_pool->opps[i]->mpcc_disconnect_pending[pipe_ctx->plane_res.mpcc_inst] = true;
pipe_ctx->stream_res.opp = dc->res_pool->opps[i];
/*to do*/
hws->funcs.plane_atomic_disconnect(dc, pipe_ctx);
} }
/* initialize DWB pointer to MCIF_WB */
for (i = 0; i < res_pool->res_cap->num_dwb; i++)
res_pool->dwbc[i]->mcif = res_pool->mcif_wb[i];
for (i = 0; i < dc->res_pool->timing_generator_count; i++) {
struct timing_generator *tg = dc->res_pool->timing_generators[i];
if (tg->funcs->is_tg_enabled(tg))
tg->funcs->unlock(tg);
} }
for (i = 0; i < dc->res_pool->pipe_count; i++) { /* If taking control over from VBIOS, we may want to optimize our first
struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; * mode set, so we need to skip powering down pipes until we know which
* pipes we want to use.
dc->hwss.disable_plane(dc, pipe_ctx); * Otherwise, if taking control is not possible, we need to power
* everything down.
pipe_ctx->stream_res.tg = NULL; */
pipe_ctx->plane_res.hubp = NULL; 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);
} }
for (i = 0; i < dc->res_pool->timing_generator_count; i++) { /* In headless boot cases, DIG may be turned
struct timing_generator *tg = dc->res_pool->timing_generators[i]; * 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 (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];
tg->funcs->tg_init(tg); 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;
} }
/* end of FPGA. Below if real ASIC */ }
if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) }
return; }
for (i = 0; i < res_pool->audio_count; i++) { for (i = 0; i < res_pool->audio_count; i++) {
struct audio *audio = res_pool->audios[i]; struct audio *audio = res_pool->audios[i];
...@@ -614,6 +617,8 @@ void dcn30_init_hw(struct dc *dc) ...@@ -614,6 +617,8 @@ void dcn30_init_hw(struct dc *dc)
REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0); REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0);
} }
if (hws->funcs.enable_power_gating_plane)
hws->funcs.enable_power_gating_plane(dc->hwseq, true);
if (dc->clk_mgr->funcs->notify_wm_ranges) if (dc->clk_mgr->funcs->notify_wm_ranges)
dc->clk_mgr->funcs->notify_wm_ranges(dc->clk_mgr); dc->clk_mgr->funcs->notify_wm_ranges(dc->clk_mgr);
......
...@@ -30,7 +30,7 @@ ...@@ -30,7 +30,7 @@
static const struct hw_sequencer_funcs dcn30_funcs = { static const struct hw_sequencer_funcs dcn30_funcs = {
.program_gamut_remap = dcn10_program_gamut_remap, .program_gamut_remap = dcn10_program_gamut_remap,
.init_hw = dcn10_init_hw, .init_hw = dcn30_init_hw,
.apply_ctx_to_hw = dce110_apply_ctx_to_hw, .apply_ctx_to_hw = dce110_apply_ctx_to_hw,
.apply_ctx_for_surface = NULL, .apply_ctx_for_surface = NULL,
.program_front_end_for_ctx = dcn20_program_front_end_for_ctx, .program_front_end_for_ctx = dcn20_program_front_end_for_ctx,
...@@ -138,10 +138,4 @@ void dcn30_hw_sequencer_construct(struct dc *dc) ...@@ -138,10 +138,4 @@ void dcn30_hw_sequencer_construct(struct dc *dc)
dc->hwss.init_hw = dcn20_fpga_init_hw; dc->hwss.init_hw = dcn20_fpga_init_hw;
dc->hwseq->funcs.init_pipes = NULL; dc->hwseq->funcs.init_pipes = NULL;
} }
// TODO: Use generic dcn10_init_hw and dcn10_init_pipes sequence
if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) {
dc->hwss.init_hw = dcn30_init_hw;
dc->hwseq->funcs.init_pipes = NULL;
}
} }
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