From 8a31820b12187c7e31c52e8a00075359d9efac52 Mon Sep 17 00:00:00 2001 From: Martin Leung Date: Tue, 9 Jul 2019 15:15:17 -0400 Subject: [PATCH] drm/amd/display: Make init_hw and init_pipes generic for seamless boot [Why] For seamless boot the init_hw sequence must be split into actual hardware vs pipes, in order to defer pipe initialization to set mode and skip of pipe-destructive sequences [How] made dcn10_init_hw and dcn10_init_pipes generic for future dcns to inherit deleted dcn20 specific versions. This is part 1 of a 2 partimplementation of seamless boot Signed-off-by: Martin Leung Reviewed-by: Jun Lei Acked-by: Leo Li Signed-off-by: Alex Deucher --- .../amd/display/dc/dce110/dce110_hw_sequencer.c | 12 +- .../amd/display/dc/dce110/dce110_hw_sequencer.h | 6 +- .../gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.c | 4 +- .../gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.h | 2 +- .../drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c | 182 +++++++--- .../gpu/drm/amd/display/dc/dcn20/dcn20_hubbub.c | 2 +- drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c | 381 ++++++++------------- drivers/gpu/drm/amd/display/dc/inc/hw/dchubbub.h | 4 + drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h | 32 ++ 9 files changed, 312 insertions(+), 313 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c index 997615582528..94b55143827e 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c @@ -731,7 +731,7 @@ static enum bp_result link_transmitter_control( * @brief * eDP only. */ -void hwss_edp_wait_for_hpd_ready( +void dce110_edp_wait_for_hpd_ready( struct dc_link *link, bool power_up) { @@ -799,7 +799,7 @@ void hwss_edp_wait_for_hpd_ready( } } -void hwss_edp_power_control( +void dce110_edp_power_control( struct dc_link *link, bool power_up) { @@ -881,7 +881,7 @@ void hwss_edp_power_control( * @brief * eDP only. Control the backlight of the eDP panel */ -void hwss_edp_backlight_control( +void dce110_edp_backlight_control( struct dc_link *link, bool enable) { @@ -2758,9 +2758,9 @@ static const struct hw_sequencer_funcs dce110_funcs = { .setup_stereo = NULL, .set_avmute = dce110_set_avmute, .wait_for_mpcc_disconnect = dce110_wait_for_mpcc_disconnect, - .edp_backlight_control = hwss_edp_backlight_control, - .edp_power_control = hwss_edp_power_control, - .edp_wait_for_hpd_ready = hwss_edp_wait_for_hpd_ready, + .edp_backlight_control = dce110_edp_backlight_control, + .edp_power_control = dce110_edp_power_control, + .edp_wait_for_hpd_ready = dce110_edp_wait_for_hpd_ready, .set_cursor_position = dce110_set_cursor_position, .set_cursor_attribute = dce110_set_cursor_attribute }; diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.h index cd3e36d52a52..668feb0d169d 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.h +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.h @@ -73,15 +73,15 @@ void dce110_optimize_bandwidth( void dp_receiver_power_ctrl(struct dc_link *link, bool on); -void hwss_edp_power_control( +void dce110_edp_power_control( struct dc_link *link, bool power_up); -void hwss_edp_backlight_control( +void dce110_edp_backlight_control( struct dc_link *link, bool enable); -void hwss_edp_wait_for_hpd_ready( +void dce110_edp_wait_for_hpd_ready( struct dc_link *link, bool power_up); diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.c index a780057e2dbc..a02c10e23e0d 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.c @@ -104,7 +104,7 @@ void hubbub1_allow_self_refresh_control(struct hubbub *hubbub, bool allow) DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_ENABLE, !allow); } -bool hububu1_is_allow_self_refresh_enabled(struct hubbub *hubbub) +bool hubbub1_is_allow_self_refresh_enabled(struct hubbub *hubbub) { struct dcn10_hubbub *hubbub1 = TO_DCN10_HUBBUB(hubbub); uint32_t enable = 0; @@ -945,6 +945,8 @@ static const struct hubbub_funcs hubbub1_funcs = { .get_dcc_compression_cap = hubbub1_get_dcc_compression_cap, .wm_read_state = hubbub1_wm_read_state, .program_watermarks = hubbub1_program_watermarks, + .is_allow_self_refresh_enabled = hubbub1_is_allow_self_refresh_enabled, + .allow_self_refresh_control = hubbub1_allow_self_refresh_control, }; void hubbub1_construct(struct hubbub *hubbub, diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.h index 7c2559c9ae23..70e5d84fc69a 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.h @@ -247,7 +247,7 @@ void hubbub1_program_watermarks( void hubbub1_allow_self_refresh_control(struct hubbub *hubbub, bool allow); -bool hububu1_is_allow_self_refresh_enabled(struct hubbub *hubub); +bool hubbub1_is_allow_self_refresh_enabled(struct hubbub *hubub); void hubbub1_toggle_watermark_change_req( struct hubbub *hubbub); 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 51857cab1459..9dc11a43d6d5 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 @@ -438,7 +438,7 @@ bool dcn10_did_underflow_occur(struct dc *dc, struct pipe_ctx *pipe_ctx) return false; } -static void enable_power_gating_plane( +static void dcn10_enable_power_gating_plane( struct dce_hwseq *hws, bool enable) { @@ -460,7 +460,7 @@ static void enable_power_gating_plane( REG_UPDATE(DOMAIN7_PG_CONFIG, DOMAIN7_POWER_FORCEON, force_on); } -static void disable_vga( +static void dcn10_disable_vga( struct dce_hwseq *hws) { unsigned int in_vga1_mode = 0; @@ -493,7 +493,7 @@ static void disable_vga( REG_UPDATE(VGA_TEST_CONTROL, VGA_TEST_RENDER_START, 1); } -static void dpp_pg_control( +static void dcn10_dpp_pg_control( struct dce_hwseq *hws, unsigned int dpp_inst, bool power_on) @@ -545,7 +545,7 @@ static void dpp_pg_control( } } -static void hubp_pg_control( +static void dcn10_hubp_pg_control( struct dce_hwseq *hws, unsigned int hubp_inst, bool power_on) @@ -605,8 +605,8 @@ static void power_on_plane( if (REG(DC_IP_REQUEST_CNTL)) { REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1); - dpp_pg_control(hws, plane_id, true); - hubp_pg_control(hws, plane_id, true); + hws->ctx->dc->hwss.dpp_pg_control(hws, plane_id, true); + hws->ctx->dc->hwss.hubp_pg_control(hws, plane_id, true); REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 0); DC_LOG_DEBUG( @@ -627,7 +627,7 @@ static void undo_DEGVIDCN10_253_wa(struct dc *dc) REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1); - hubp_pg_control(hws, 0, false); + dc->hwss.hubp_pg_control(hws, 0, false); REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 0); @@ -656,7 +656,7 @@ static void apply_DEGVIDCN10_253_wa(struct dc *dc) REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1); - hubp_pg_control(hws, 0, true); + dc->hwss.hubp_pg_control(hws, 0, true); REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 0); @@ -664,10 +664,23 @@ static void apply_DEGVIDCN10_253_wa(struct dc *dc) hws->wa_state.DEGVIDCN10_253_applied = true; } -static void bios_golden_init(struct dc *dc) +static void dcn10_bios_golden_init(struct dc *dc) { struct dc_bios *bp = dc->ctx->dc_bios; int i; + bool allow_self_fresh_force_enable = true; + + if (dc->res_pool->hubbub->funcs->is_allow_self_refresh_enabled) + allow_self_fresh_force_enable = + dc->res_pool->hubbub->funcs->is_allow_self_refresh_enabled(dc->res_pool->hubbub); + + + /* WA for making DF sleep when idle after resume from S0i3. + * DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_ENABLE is set to 1 by + * command table, if DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_ENABLE = 0 + * before calling command table and it changed to 1 after, + * it should be set back to 0. + */ /* initialize dcn global */ bp->funcs->enable_disp_power_gating(bp, @@ -678,6 +691,12 @@ static void bios_golden_init(struct dc *dc) bp->funcs->enable_disp_power_gating(bp, CONTROLLER_ID_D0 + i, ASIC_PIPE_DISABLE); } + + if (dc->res_pool->hubbub->funcs->allow_self_refresh_control) + if (allow_self_fresh_force_enable == false && + dc->res_pool->hubbub->funcs->is_allow_self_refresh_enabled(dc->res_pool->hubbub)) + dc->res_pool->hubbub->funcs->allow_self_refresh_control(dc->res_pool->hubbub, true); + } static void false_optc_underflow_wa( @@ -971,7 +990,7 @@ void hwss1_plane_atomic_disconnect(struct dc *dc, struct pipe_ctx *pipe_ctx) dcn10_verify_allow_pstate_change_high(dc); } -static void plane_atomic_power_down(struct dc *dc, +static void dcn10_plane_atomic_power_down(struct dc *dc, struct dpp *dpp, struct hubp *hubp) { @@ -981,8 +1000,8 @@ static void plane_atomic_power_down(struct dc *dc, if (REG(DC_IP_REQUEST_CNTL)) { REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1); - dpp_pg_control(hws, dpp->inst, false); - hubp_pg_control(hws, hubp->inst, false); + dc->hwss.dpp_pg_control(hws, dpp->inst, false); + dc->hwss.hubp_pg_control(hws, hubp->inst, false); dpp->funcs->dpp_reset(dpp); REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 0); @@ -994,7 +1013,7 @@ static void plane_atomic_power_down(struct dc *dc, /* disable HW used by plane. * note: cannot disable until disconnect is complete */ -static void plane_atomic_disable(struct dc *dc, struct pipe_ctx *pipe_ctx) +static void dcn10_plane_atomic_disable(struct dc *dc, struct pipe_ctx *pipe_ctx) { struct hubp *hubp = pipe_ctx->plane_res.hubp; struct dpp *dpp = pipe_ctx->plane_res.dpp; @@ -1014,7 +1033,7 @@ static void plane_atomic_disable(struct dc *dc, struct pipe_ctx *pipe_ctx) hubp->power_gated = true; dc->optimized_required = false; /* We're powering off, no need to optimize */ - plane_atomic_power_down(dc, + dc->hwss.plane_atomic_power_down(dc, pipe_ctx->plane_res.dpp, pipe_ctx->plane_res.hubp); @@ -1033,7 +1052,7 @@ static void dcn10_disable_plane(struct dc *dc, struct pipe_ctx *pipe_ctx) if (!pipe_ctx->plane_res.hubp || pipe_ctx->plane_res.hubp->power_gated) return; - plane_atomic_disable(dc, pipe_ctx); + dc->hwss.plane_atomic_disable(dc, pipe_ctx); apply_DEGVIDCN10_253_wa(dc); @@ -1068,9 +1087,14 @@ static void dcn10_init_pipes(struct dc *dc, struct dc_state *context) * command table. */ if (tg->funcs->is_tg_enabled(tg)) { - tg->funcs->lock(tg); - tg->funcs->set_blank(tg, true); - hwss_wait_for_blank_complete(tg); + if (dc->hwss.init_blank != NULL) { + dc->hwss.init_blank(dc, tg); + tg->funcs->lock(tg); + } else { + tg->funcs->lock(tg); + tg->funcs->set_blank(tg, true); + hwss_wait_for_blank_complete(tg); + } } } @@ -1114,12 +1138,12 @@ static void dcn10_init_pipes(struct dc *dc, struct dc_state *context) 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]; - hwss1_plane_atomic_disconnect(dc, pipe_ctx); + dc->hwss.plane_atomic_disconnect(dc, pipe_ctx); if (tg->funcs->is_tg_enabled(tg)) tg->funcs->unlock(tg); - dcn10_disable_plane(dc, pipe_ctx); + dc->hwss.disable_plane(dc, pipe_ctx); pipe_ctx->stream_res.tg = NULL; pipe_ctx->plane_res.hubp = NULL; @@ -1135,8 +1159,17 @@ static void dcn10_init_hw(struct dc *dc) struct dmcu *dmcu = dc->res_pool->dmcu; struct dce_hwseq *hws = dc->hwseq; struct dc_bios *dcb = dc->ctx->dc_bios; + struct resource_pool *res_pool = dc->res_pool; + + if (dc->clk_mgr && dc->clk_mgr->funcs->init_clocks) + dc->clk_mgr->funcs->init_clocks(dc->clk_mgr); + + // Initialize the dccg + if (dc->res_pool->dccg && dc->res_pool->dccg->funcs->dccg_init) + dc->res_pool->dccg->funcs->dccg_init(res_pool->dccg); if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) { + REG_WRITE(REFCLK_CNTL, 0); REG_UPDATE(DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_ENABLE, 1); REG_WRITE(DIO_MEM_PWR_CTRL, 0); @@ -1150,30 +1183,39 @@ static void dcn10_init_hw(struct dc *dc) REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0); } - enable_power_gating_plane(dc->hwseq, true); + //Enable ability to power gate / don't force power on permanently + dc->hwss.enable_power_gating_plane(hws, true); - /* end of FPGA. Below if real ASIC */ return; } if (!dcb->funcs->is_accelerated_mode(dcb)) { - bool allow_self_fresh_force_enable = - hububu1_is_allow_self_refresh_enabled( - dc->res_pool->hubbub); - - bios_golden_init(dc); - - /* WA for making DF sleep when idle after resume from S0i3. - * DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_ENABLE is set to 1 by - * command table, if DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_ENABLE = 0 - * before calling command table and it changed to 1 after, - * it should be set back to 0. - */ - if (allow_self_fresh_force_enable == false && - hububu1_is_allow_self_refresh_enabled(dc->res_pool->hubbub)) - hubbub1_allow_self_refresh_control(dc->res_pool->hubbub, true); - - disable_vga(dc->hwseq); + dc->hwss.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; + + if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) { + if (res_pool->dccg && res_pool->hubbub) { + + (res_pool->dccg->funcs->get_dccg_ref_freq)(res_pool->dccg, + dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency, + &res_pool->ref_clocks.dccg_ref_clock_inKhz); + + (res_pool->hubbub->funcs->get_dchub_ref_freq)(res_pool->hubbub, + res_pool->ref_clocks.dccg_ref_clock_inKhz, + &res_pool->ref_clocks.dchub_ref_clock_inKhz); + } else { + // Not all ASICs have DCCG sw component + res_pool->ref_clocks.dccg_ref_clock_inKhz = + res_pool->ref_clocks.xtalin_clock_inKhz; + res_pool->ref_clocks.dchub_ref_clock_inKhz = + res_pool->ref_clocks.xtalin_clock_inKhz; + } + } + } else + ASSERT_CRITICAL(false); + dc->hwss.disable_vga(dc->hwseq); } for (i = 0; i < dc->link_count; i++) { @@ -1191,6 +1233,13 @@ static void dcn10_init_hw(struct dc *dc) link->link_status.link_active = true; } + /* Power gate DSCs */ +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT + for (i = 0; i < res_pool->res_cap->num_dsc; i++) + if (dc->hwss.dsc_pg_control != NULL) + dc->hwss.dsc_pg_control(hws, res_pool->dscs[i]->inst, false); +#endif + /* If taking control over from VBIOS, we may want to optimize our first * mode set, so we need to skip powering down pipes until we know which * pipes we want to use. @@ -1199,10 +1248,21 @@ static void dcn10_init_hw(struct dc *dc) */ if (dcb->funcs->is_accelerated_mode(dcb) || dc->config.power_down_display_on_boot) { dc->hwss.init_pipes(dc, dc->current_state); + for (i = 0; i < res_pool->pipe_count; i++) { + struct hubp *hubp = res_pool->hubps[i]; + struct dpp *dpp = res_pool->dpps[i]; + + hubp->funcs->hubp_init(hubp); + res_pool->opps[i]->mpc_tree_params.opp_id = res_pool->opps[i]->inst; + dc->hwss.plane_atomic_power_down(dc, dpp, hubp); + } + + apply_DEGVIDCN10_253_wa(dc); } - for (i = 0; i < dc->res_pool->audio_count; i++) { - struct audio *audio = dc->res_pool->audios[i]; + + for (i = 0; i < res_pool->audio_count; i++) { + struct audio *audio = res_pool->audios[i]; audio->funcs->hw_init(audio); } @@ -1230,7 +1290,7 @@ static void dcn10_init_hw(struct dc *dc) REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0); } - enable_power_gating_plane(dc->hwseq, true); + dc->hwss.enable_power_gating_plane(dc->hwseq, true); memset(&dc->clk_mgr->clks, 0, sizeof(dc->clk_mgr->clks)); } @@ -1789,7 +1849,7 @@ static void dcn10_enable_plane( } } -static void program_gamut_remap(struct pipe_ctx *pipe_ctx) +static void dcn10_program_gamut_remap(struct pipe_ctx *pipe_ctx) { int i = 0; struct dpp_grph_csc_adjustment adjust; @@ -2220,7 +2280,7 @@ void update_dchubp_dpp( if (plane_state->update_flags.bits.full_update) { /*gamut remap*/ - program_gamut_remap(pipe_ctx); + dc->hwss.program_gamut_remap(pipe_ctx); dc->hwss.program_output_csc(dc, pipe_ctx, @@ -2457,7 +2517,7 @@ static void dcn10_apply_ctx_for_surface( if (old_pipe_ctx->stream_res.tg == tg && old_pipe_ctx->plane_res.hubp && old_pipe_ctx->plane_res.hubp->opp_id != OPP_ID_INVALID) - dcn10_disable_plane(dc, old_pipe_ctx); + dc->hwss.disable_plane(dc, old_pipe_ctx); } if ((!pipe_ctx->plane_state || @@ -2505,7 +2565,7 @@ static void dcn10_apply_ctx_for_surface( for (i = 0; i < dc->res_pool->pipe_count; i++) if (removed_pipe[i]) - dcn10_disable_plane(dc, &dc->current_state->res_ctx.pipe_ctx[i]); + dc->hwss.disable_plane(dc, &dc->current_state->res_ctx.pipe_ctx[i]); for (i = 0; i < dc->res_pool->pipe_count; i++) if (removed_pipe[i]) { @@ -2597,7 +2657,7 @@ static void dcn10_optimize_bandwidth( dcn10_verify_allow_pstate_change_high(dc); } -static void set_drr(struct pipe_ctx **pipe_ctx, +static void dcn10_set_drr(struct pipe_ctx **pipe_ctx, int num_pipes, int vmin, int vmax) { int i = 0; @@ -2622,7 +2682,7 @@ static void set_drr(struct pipe_ctx **pipe_ctx, } } -static void get_position(struct pipe_ctx **pipe_ctx, +static void dcn10_get_position(struct pipe_ctx **pipe_ctx, int num_pipes, struct crtc_position *position) { @@ -2634,7 +2694,7 @@ static void get_position(struct pipe_ctx **pipe_ctx, pipe_ctx[i]->stream_res.tg->funcs->get_position(pipe_ctx[i]->stream_res.tg, position); } -static void set_static_screen_control(struct pipe_ctx **pipe_ctx, +static void dcn10_set_static_screen_control(struct pipe_ctx **pipe_ctx, int num_pipes, const struct dc_static_screen_events *events) { unsigned int i; @@ -3125,7 +3185,7 @@ static void dcn10_get_clock(struct dc *dc, } static const struct hw_sequencer_funcs dcn10_funcs = { - .program_gamut_remap = program_gamut_remap, + .program_gamut_remap = dcn10_program_gamut_remap, .init_hw = dcn10_init_hw, .init_pipes = dcn10_init_pipes, .apply_ctx_to_hw = dce110_apply_ctx_to_hw, @@ -3158,18 +3218,18 @@ static const struct hw_sequencer_funcs dcn10_funcs = { .optimize_bandwidth = dcn10_optimize_bandwidth, .reset_hw_ctx_wrap = dcn10_reset_hw_ctx_wrap, .enable_stream_timing = dcn10_enable_stream_timing, - .set_drr = set_drr, - .get_position = get_position, - .set_static_screen_control = set_static_screen_control, + .set_drr = dcn10_set_drr, + .get_position = dcn10_get_position, + .set_static_screen_control = dcn10_set_static_screen_control, .setup_stereo = dcn10_setup_stereo, .set_avmute = dce110_set_avmute, .log_hw_state = dcn10_log_hw_state, .get_hw_state = dcn10_get_hw_state, .clear_status_bits = dcn10_clear_status_bits, .wait_for_mpcc_disconnect = dcn10_wait_for_mpcc_disconnect, - .edp_backlight_control = hwss_edp_backlight_control, - .edp_power_control = hwss_edp_power_control, - .edp_wait_for_hpd_ready = hwss_edp_wait_for_hpd_ready, + .edp_backlight_control = dce110_edp_backlight_control, + .edp_power_control = dce110_edp_power_control, + .edp_wait_for_hpd_ready = dce110_edp_wait_for_hpd_ready, .set_cursor_position = dcn10_set_cursor_position, .set_cursor_attribute = dcn10_set_cursor_attribute, .set_cursor_sdr_white_level = dcn10_set_cursor_sdr_white_level, @@ -3179,6 +3239,16 @@ static const struct hw_sequencer_funcs dcn10_funcs = { .setup_vupdate_interrupt = dcn10_setup_vupdate_interrupt, .set_clock = dcn10_set_clock, .get_clock = dcn10_get_clock, + .did_underflow_occur = dcn10_did_underflow_occur, + .init_blank = NULL, + .disable_vga = dcn10_disable_vga, + .bios_golden_init = dcn10_bios_golden_init, + .plane_atomic_disable = dcn10_plane_atomic_disable, + .plane_atomic_power_down = dcn10_plane_atomic_power_down, + .enable_power_gating_plane = dcn10_enable_power_gating_plane, + .dpp_pg_control = dcn10_dpp_pg_control, + .hubp_pg_control = dcn10_hubp_pg_control, + .dsc_pg_control = NULL, }; diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubbub.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubbub.c index 31d6e79ba2b8..cd101bbd8163 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubbub.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubbub.c @@ -582,7 +582,7 @@ static const struct hubbub_funcs hubbub2_funcs = { .get_dcc_compression_cap = hubbub2_get_dcc_compression_cap, .wm_read_state = hubbub2_wm_read_state, .get_dchub_ref_freq = hubbub2_get_dchub_ref_freq, - .program_watermarks = hubbub2_program_watermarks, + .program_watermarks = hubbub2_program_watermarks }; void hubbub2_construct(struct dcn20_hubbub *hubbub, 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 c11de6f0fe5c..c3635f5cd990 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c @@ -64,23 +64,7 @@ #define FN(reg_name, field_name) \ hws->shifts->field_name, hws->masks->field_name -static void bios_golden_init(struct dc *dc) -{ - struct dc_bios *bp = dc->ctx->dc_bios; - int i; - - /* initialize dcn global */ - bp->funcs->enable_disp_power_gating(bp, - CONTROLLER_ID_D0, ASIC_PIPE_INIT); - - for (i = 0; i < dc->res_pool->pipe_count; i++) { - /* initialize dcn per pipe */ - bp->funcs->enable_disp_power_gating(bp, - CONTROLLER_ID_D0 + i, ASIC_PIPE_DISABLE); - } -} - -static void enable_power_gating_plane( +static void dcn20_enable_power_gating_plane( struct dce_hwseq *hws, bool enable) { @@ -184,7 +168,7 @@ void dcn20_display_init(struct dc *dc) REG_WRITE(AZALIA_CONTROLLER_CLOCK_GATING, 0x1); } -static void disable_vga( +void dcn20_disable_vga( struct dce_hwseq *hws) { REG_WRITE(D1VGA_CONTROL, 0); @@ -487,29 +471,6 @@ static void dcn20_hubp_pg_control( } - -static void dcn20_plane_atomic_power_down(struct dc *dc, struct pipe_ctx *pipe_ctx) -{ - struct dce_hwseq *hws = dc->hwseq; - struct dpp *dpp = pipe_ctx->plane_res.dpp; - - DC_LOGGER_INIT(dc->ctx->logger); - - if (REG(DC_IP_REQUEST_CNTL)) { - REG_SET(DC_IP_REQUEST_CNTL, 0, - IP_REQUEST_EN, 1); - dcn20_dpp_pg_control(hws, dpp->inst, false); - dcn20_hubp_pg_control(hws, pipe_ctx->plane_res.hubp->inst, false); - dpp->funcs->dpp_reset(dpp); - REG_SET(DC_IP_REQUEST_CNTL, 0, - IP_REQUEST_EN, 0); - DC_LOG_DEBUG( - "Power gated front end %d\n", pipe_ctx->pipe_idx); - } -} - - - /* disable HW used by plane. * note: cannot disable until disconnect is complete */ @@ -535,7 +496,9 @@ static void dcn20_plane_atomic_disable(struct dc *dc, struct pipe_ctx *pipe_ctx) hubp->power_gated = true; dc->optimized_required = false; /* We're powering off, no need to optimize */ - dcn20_plane_atomic_power_down(dc, pipe_ctx); + dc->hwss.plane_atomic_power_down(dc, + pipe_ctx->plane_res.dpp, + pipe_ctx->plane_res.hubp); pipe_ctx->stream = NULL; memset(&pipe_ctx->stream_res, 0, sizeof(pipe_ctx->stream_res)); @@ -559,204 +522,6 @@ void dcn20_disable_plane(struct dc *dc, struct pipe_ctx *pipe_ctx) pipe_ctx->pipe_idx); } -static void dcn20_init_hw(struct dc *dc) -{ - int i, j; - struct abm *abm = dc->res_pool->abm; - struct dmcu *dmcu = dc->res_pool->dmcu; - struct dce_hwseq *hws = dc->hwseq; - struct dc_bios *dcb = dc->ctx->dc_bios; - struct resource_pool *res_pool = dc->res_pool; - struct dc_state *context = dc->current_state; - - if (dc->clk_mgr && dc->clk_mgr->funcs->init_clocks) - dc->clk_mgr->funcs->init_clocks(dc->clk_mgr); - - // Initialize the dccg - if (res_pool->dccg->funcs->dccg_init) - res_pool->dccg->funcs->dccg_init(res_pool->dccg); - - //Enable ability to power gate / don't force power on permanently - enable_power_gating_plane(dc->hwseq, true); - - if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) { - REG_WRITE(RBBMIF_TIMEOUT_DIS, 0xFFFFFFFF); - REG_WRITE(RBBMIF_TIMEOUT_DIS_2, 0xFFFFFFFF); - - dcn20_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); - } else { - if (!dcb->funcs->is_accelerated_mode(dcb)) { - 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; - - if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) { - if (res_pool->dccg && res_pool->hubbub) { - - (res_pool->dccg->funcs->get_dccg_ref_freq)(res_pool->dccg, - dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency, - &res_pool->ref_clocks.dccg_ref_clock_inKhz); - - (res_pool->hubbub->funcs->get_dchub_ref_freq)(res_pool->hubbub, - res_pool->ref_clocks.dccg_ref_clock_inKhz, - &res_pool->ref_clocks.dchub_ref_clock_inKhz); - } else { - // Not all ASICs have DCCG sw component - res_pool->ref_clocks.dccg_ref_clock_inKhz = - res_pool->ref_clocks.xtalin_clock_inKhz; - res_pool->ref_clocks.dchub_ref_clock_inKhz = - res_pool->ref_clocks.xtalin_clock_inKhz; - } - } - } else - ASSERT_CRITICAL(false); - disable_vga(dc->hwseq); - } - - for (i = 0; i < dc->link_count; i++) { - /* Power up AND update implementation according to the - * required signal (which may be different from the - * default signal on connector). - */ - struct dc_link *link = dc->links[i]; - - link->link_enc->funcs->hw_init(link->link_enc); - } - } - -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT - /* Power gate DSCs */ - for (i = 0; i < res_pool->res_cap->num_dsc; i++) - dcn20_dsc_pg_control(hws, res_pool->dscs[i]->inst, false); -#endif - - /* Blank pixel data with OPP DPG */ - 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)) { - dcn20_init_blank(dc, tg); - } - } - - 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); - } - - /* 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*/ - hwss1_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++) { - struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; - - dc->hwss.disable_plane(dc, pipe_ctx); - - pipe_ctx->stream_res.tg = NULL; - pipe_ctx->plane_res.hubp = NULL; - } - - for (i = 0; i < dc->res_pool->timing_generator_count; i++) { - struct timing_generator *tg = dc->res_pool->timing_generators[i]; - - tg->funcs->tg_init(tg); - } - - /* 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++) { - struct audio *audio = res_pool->audios[i]; - - audio->funcs->hw_init(audio); - } - - if (abm != NULL) { - abm->funcs->init_backlight(abm); - abm->funcs->abm_init(abm); - } - - if (dmcu != NULL) - 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 (!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); - } - -} - enum dc_status dcn20_enable_stream_timing( struct pipe_ctx *pipe_ctx, struct dc_state *context, @@ -1409,7 +1174,7 @@ static void dcn20_apply_ctx_for_surface( if (old_pipe_ctx->stream_res.tg == tg && old_pipe_ctx->plane_res.hubp && old_pipe_ctx->plane_res.hubp->opp_id != OPP_ID_INVALID) - dcn20_disable_plane(dc, old_pipe_ctx); + dc->hwss.disable_plane(dc, old_pipe_ctx); } if ((!pipe_ctx->plane_state || @@ -2169,14 +1934,126 @@ static void dcn20_program_dmdata_engine(struct pipe_ctx *pipe_ctx) hubp->inst, mode); } +static void dcn20_fpga_init_hw(struct dc *dc) +{ + int i, j; + struct dce_hwseq *hws = dc->hwseq; + struct resource_pool *res_pool = dc->res_pool; + struct dc_state *context = dc->current_state; + + if (dc->clk_mgr && dc->clk_mgr->funcs->init_clocks) + dc->clk_mgr->funcs->init_clocks(dc->clk_mgr); + + // Initialize the dccg + if (res_pool->dccg->funcs->dccg_init) + res_pool->dccg->funcs->dccg_init(res_pool->dccg); + + //Enable ability to power gate / don't force power on permanently + dc->hwss.enable_power_gating_plane(hws, true); + + // Specific to FPGA dccg and registers + REG_WRITE(RBBMIF_TIMEOUT_DIS, 0xFFFFFFFF); + REG_WRITE(RBBMIF_TIMEOUT_DIS_2, 0xFFFFFFFF); + + dcn20_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); + // + + + /* Blank pixel data with OPP DPG */ + 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)) + dcn20_init_blank(dc, tg); + } + + 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); + } + + /* 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*/ + hwss1_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++) { + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; + + dc->hwss.disable_plane(dc, pipe_ctx); + + pipe_ctx->stream_res.tg = NULL; + pipe_ctx->plane_res.hubp = NULL; + } + + for (i = 0; i < dc->res_pool->timing_generator_count; i++) { + struct timing_generator *tg = dc->res_pool->timing_generators[i]; + + tg->funcs->tg_init(tg); + } +} + void dcn20_hw_sequencer_construct(struct dc *dc) { dcn10_hw_sequencer_construct(dc); - dc->hwss.init_hw = dcn20_init_hw; - dc->hwss.init_pipes = NULL; dc->hwss.unblank_stream = dcn20_unblank_stream; dc->hwss.update_plane_addr = dcn20_update_plane_addr; - dc->hwss.disable_plane = dcn20_disable_plane, dc->hwss.enable_stream_timing = dcn20_enable_stream_timing; dc->hwss.program_triplebuffer = dcn20_program_tripleBuffer; dc->hwss.set_input_transfer_func = dcn20_set_input_transfer_func; @@ -2204,5 +2081,19 @@ void dcn20_hw_sequencer_construct(struct dc *dc) dc->hwss.reset_hw_ctx_wrap = dcn20_reset_hw_ctx_wrap; dc->hwss.update_mpcc = dcn20_update_mpcc; dc->hwss.set_flip_control_gsl = dcn20_set_flip_control_gsl; - dc->hwss.did_underflow_occur = dcn10_did_underflow_occur; + dc->hwss.init_blank = dcn20_init_blank; + dc->hwss.disable_plane = dcn20_disable_plane; + dc->hwss.plane_atomic_disable = dcn20_plane_atomic_disable; + dc->hwss.enable_power_gating_plane = dcn20_enable_power_gating_plane; + dc->hwss.dpp_pg_control = dcn20_dpp_pg_control; + dc->hwss.hubp_pg_control = dcn20_hubp_pg_control; + dc->hwss.dsc_pg_control = dcn20_dsc_pg_control; + dc->hwss.disable_vga = dcn20_disable_vga; + + if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) { + dc->hwss.init_hw = dcn20_fpga_init_hw; + dc->hwss.init_pipes = NULL; + } + + } diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/dchubbub.h b/drivers/gpu/drm/amd/display/dc/inc/hw/dchubbub.h index 9502478c4a1b..c1f29b1654d9 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/dchubbub.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/dchubbub.h @@ -141,6 +141,10 @@ struct hubbub_funcs { struct dcn_watermark_set *watermarks, unsigned int refclk_mhz, bool safe_to_lower); + + bool (*is_allow_self_refresh_enabled)(struct hubbub *hubbub); + void (*allow_self_refresh_control)(struct hubbub *hubbub, bool allow); + }; struct hubbub { diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h index 28645e10f854..80de2febd7cb 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h @@ -78,6 +78,8 @@ struct stream_resource; struct dc_phy_addr_space_config; struct dc_virtual_addr_space_config; #endif +struct hubp; +struct dpp; struct hw_sequencer_funcs { @@ -280,6 +282,36 @@ struct hw_sequencer_funcs { void (*setup_vupdate_interrupt)(struct pipe_ctx *pipe_ctx); bool (*did_underflow_occur)(struct dc *dc, struct pipe_ctx *pipe_ctx); + void (*init_blank)(struct dc *dc, struct timing_generator *tg); + void (*disable_vga)(struct dce_hwseq *hws); + void (*bios_golden_init)(struct dc *dc); + void (*plane_atomic_power_down)(struct dc *dc, + struct dpp *dpp, + struct hubp *hubp); + + void (*plane_atomic_disable)( + struct dc *dc, struct pipe_ctx *pipe_ctx); + + void (*enable_power_gating_plane)( + struct dce_hwseq *hws, + bool enable); + + void (*dpp_pg_control)( + struct dce_hwseq *hws, + unsigned int dpp_inst, + bool power_on); + + void (*hubp_pg_control)( + struct dce_hwseq *hws, + unsigned int hubp_inst, + bool power_on); + + void (*dsc_pg_control)( + struct dce_hwseq *hws, + unsigned int dsc_inst, + bool power_on); + + #if defined(CONFIG_DRM_AMD_DC_DCN2_0) void (*update_odm)(struct dc *dc, struct dc_state *context, struct pipe_ctx *pipe_ctx); void (*program_all_writeback_pipes_in_tree)( -- 2.11.0