diff options
Diffstat (limited to 'meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.19.8/3714-drm-amd-display-update-navi-to-use-new-surface-progr.patch')
-rw-r--r-- | meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.19.8/3714-drm-amd-display-update-navi-to-use-new-surface-progr.patch | 975 |
1 files changed, 975 insertions, 0 deletions
diff --git a/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.19.8/3714-drm-amd-display-update-navi-to-use-new-surface-progr.patch b/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.19.8/3714-drm-amd-display-update-navi-to-use-new-surface-progr.patch new file mode 100644 index 00000000..d1519fb1 --- /dev/null +++ b/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.19.8/3714-drm-amd-display-update-navi-to-use-new-surface-progr.patch @@ -0,0 +1,975 @@ +From 5dc3dc29e75bab941513cdd6e80c5f0213aa9ed7 Mon Sep 17 00:00:00 2001 +From: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com> +Date: Mon, 8 Jul 2019 16:46:41 -0400 +Subject: [PATCH 3714/4256] drm/amd/display: update navi to use new surface + programming behaviour + +New behaviour will track global updates and update any hw that isn't +related to current stream being updated. + +This should fix any issues caused by pipe split pipes being taken +by other streams. + +Signed-off-by: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com> +Reviewed-by: Charlene Liu <Charlene.Liu@amd.com> +Acked-by: Bhawanpreet Lakha <Bhawanpreet.Lakha@amd.com> +--- + .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 5 +- + drivers/gpu/drm/amd/display/dc/core/dc.c | 105 ++-- + drivers/gpu/drm/amd/display/dc/dc_stream.h | 18 + + .../drm/amd/display/dc/dcn20/dcn20_hwseq.c | 576 +++++++++++++----- + .../gpu/drm/amd/display/dc/inc/hw_sequencer.h | 3 + + 5 files changed, 510 insertions(+), 197 deletions(-) + +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +index 7d2498455d76..ad585734095b 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +@@ -5830,6 +5830,7 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state, + /* Update the planes if changed or disable if we don't have any. */ + if ((planes_count || acrtc_state->active_planes == 0) && + acrtc_state->stream) { ++ bundle->stream_update.stream = acrtc_state->stream; + if (new_pcrtc_state->mode_changed) { + bundle->stream_update.src = acrtc_state->stream->src; + bundle->stream_update.dst = acrtc_state->stream->dst; +@@ -6239,9 +6240,10 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state) + (dm_new_crtc_state->abm_level == dm_old_crtc_state->abm_level)) + continue; + ++ stream_update.stream = dm_new_crtc_state->stream; + if (is_scaling_state_different(dm_new_con_state, dm_old_con_state)) { + update_stream_scaling_settings(&dm_new_con_state->base.crtc->mode, +- dm_new_con_state, (struct dc_stream_state *)dm_new_crtc_state->stream); ++ dm_new_con_state, dm_new_crtc_state->stream); + + stream_update.src = dm_new_crtc_state->stream->src; + stream_update.dst = dm_new_crtc_state->stream->dst; +@@ -7094,6 +7096,7 @@ dm_determine_update_type_for_commit(struct amdgpu_display_manager *dm, + status = dc_stream_get_status_from_state(old_dm_state->context, + new_dm_crtc_state->stream); + ++ stream_update.stream = new_dm_crtc_state->stream; + /* + * TODO: DC modifies the surface during this call so we need + * to lock here - find a way to do this without locking. +diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c +index d5e4d6337113..17990586e704 100644 +--- a/drivers/gpu/drm/amd/display/dc/core/dc.c ++++ b/drivers/gpu/drm/amd/display/dc/core/dc.c +@@ -765,8 +765,13 @@ static void disable_dangling_plane(struct dc *dc, struct dc_state *context) + #if defined(CONFIG_DRM_AMD_DC_DCN2_0) + disable_all_writeback_pipes_for_stream(dc, old_stream, dangling_context); + #endif +- dc->hwss.apply_ctx_for_surface(dc, old_stream, 0, dangling_context); ++ if (dc->hwss.apply_ctx_for_surface) ++ dc->hwss.apply_ctx_for_surface(dc, old_stream, 0, dangling_context); + } ++#if defined(CONFIG_DRM_AMD_DC_DCN2_0) ++ if (dc->hwss.program_front_end_for_ctx) ++ dc->hwss.program_front_end_for_ctx(dc, dangling_context); ++#endif + } + + current_ctx = dc->current_state; +@@ -1082,15 +1087,20 @@ static enum dc_status dc_commit_state_no_check(struct dc *dc, struct dc_state *c + /* re-program planes for existing stream, in case we need to + * free up plane resource for later use + */ +- for (i = 0; i < context->stream_count; i++) { +- if (context->streams[i]->mode_changed) +- continue; ++ if (dc->hwss.apply_ctx_for_surface) ++ for (i = 0; i < context->stream_count; i++) { ++ if (context->streams[i]->mode_changed) ++ continue; + +- dc->hwss.apply_ctx_for_surface( +- dc, context->streams[i], +- context->stream_status[i].plane_count, +- context); /* use new pipe config in new context */ +- } ++ dc->hwss.apply_ctx_for_surface( ++ dc, context->streams[i], ++ context->stream_status[i].plane_count, ++ context); /* use new pipe config in new context */ ++ } ++#if defined(CONFIG_DRM_AMD_DC_DCN2_0) ++ if (dc->hwss.program_front_end_for_ctx) ++ dc->hwss.program_front_end_for_ctx(dc, context); ++#endif + + /* Program hardware */ + for (i = 0; i < dc->res_pool->pipe_count; i++) { +@@ -1109,16 +1119,21 @@ static enum dc_status dc_commit_state_no_check(struct dc *dc, struct dc_state *c + } + + /* Program all planes within new context*/ ++#if defined(CONFIG_DRM_AMD_DC_DCN2_0) ++ if (dc->hwss.program_front_end_for_ctx) ++ dc->hwss.program_front_end_for_ctx(dc, context); ++#endif + for (i = 0; i < context->stream_count; i++) { + const struct dc_link *link = context->streams[i]->link; + + if (!context->streams[i]->mode_changed) + continue; + +- dc->hwss.apply_ctx_for_surface( +- dc, context->streams[i], +- context->stream_status[i].plane_count, +- context); ++ if (dc->hwss.apply_ctx_for_surface) ++ dc->hwss.apply_ctx_for_surface( ++ dc, context->streams[i], ++ context->stream_status[i].plane_count, ++ context); + + /* + * enable stereo +@@ -1501,20 +1516,15 @@ static enum surface_update_type det_surface_update(const struct dc *dc, + enum surface_update_type overall_type = UPDATE_TYPE_FAST; + union surface_update_flags *update_flags = &u->surface->update_flags; + +- update_flags->raw = 0; // Reset all flags +- + if (u->flip_addr) + update_flags->bits.addr_update = 1; + +- if (!is_surface_in_context(context, u->surface)) { +- update_flags->bits.new_plane = 1; ++ if (!is_surface_in_context(context, u->surface) || u->surface->force_full_update) { ++ update_flags->raw = 0xFFFFFFFF; + return UPDATE_TYPE_FULL; + } + +- if (u->surface->force_full_update) { +- update_flags->bits.full_update = 1; +- return UPDATE_TYPE_FULL; +- } ++ update_flags->raw = 0; // Reset all flags + + type = get_plane_info_update_type(u); + elevate_update_type(&overall_type, type); +@@ -1572,40 +1582,43 @@ static enum surface_update_type check_update_surfaces_for_stream( + enum surface_update_type overall_type = UPDATE_TYPE_FAST; + + if (stream_status == NULL || stream_status->plane_count != surface_count) +- return UPDATE_TYPE_FULL; ++ overall_type = UPDATE_TYPE_FULL; + + /* some stream updates require passive update */ + if (stream_update) { +- if ((stream_update->src.height != 0) && +- (stream_update->src.width != 0)) +- return UPDATE_TYPE_FULL; ++ union stream_update_flags *su_flags = &stream_update->stream->update_flags; + +- if ((stream_update->dst.height != 0) && +- (stream_update->dst.width != 0)) +- return UPDATE_TYPE_FULL; ++ if ((stream_update->src.height != 0 && stream_update->src.width != 0) || ++ (stream_update->dst.height != 0 && stream_update->dst.width != 0)) ++ su_flags->bits.scaling = 1; + + if (stream_update->out_transfer_func) +- return UPDATE_TYPE_FULL; ++ su_flags->bits.out_tf = 1; + + if (stream_update->abm_level) +- return UPDATE_TYPE_FULL; ++ su_flags->bits.abm_level = 1; + + if (stream_update->dpms_off) +- return UPDATE_TYPE_FULL; ++ su_flags->bits.dpms_off = 1; ++ ++ if (stream_update->gamut_remap) ++ su_flags->bits.gamut_remap = 1; + + #if defined(CONFIG_DRM_AMD_DC_DCN2_0) + if (stream_update->wb_update) +- return UPDATE_TYPE_FULL; ++ su_flags->bits.wb_update = 1; + #endif ++ if (su_flags->raw != 0) ++ overall_type = UPDATE_TYPE_FULL; ++ ++ if (stream_update->output_csc_transform || stream_update->output_color_space) ++ su_flags->bits.out_csc = 1; + } + + for (i = 0 ; i < surface_count; i++) { + enum surface_update_type type = + det_surface_update(dc, &updates[i]); + +- if (type == UPDATE_TYPE_FULL) +- return type; +- + elevate_update_type(&overall_type, type); + } + +@@ -1627,13 +1640,18 @@ enum surface_update_type dc_check_update_surfaces_for_stream( + int i; + enum surface_update_type type; + ++ if (stream_update) ++ stream_update->stream->update_flags.raw = 0; + for (i = 0; i < surface_count; i++) + updates[i].surface->update_flags.raw = 0; + + type = check_update_surfaces_for_stream(dc, updates, surface_count, stream_update, stream_status); +- if (type == UPDATE_TYPE_FULL) ++ if (type == UPDATE_TYPE_FULL) { ++ if (stream_update) ++ stream_update->stream->update_flags.raw = 0xFFFFFFFF; + for (i = 0; i < surface_count; i++) + updates[i].surface->update_flags.raw = 0xFFFFFFFF; ++ } + + if (type == UPDATE_TYPE_FAST && memcmp(&dc->current_state->bw_ctx.bw.dcn.clk, &dc->clk_mgr->clks, offsetof(struct dc_clocks, prev_p_state_change_support)) != 0) + dc->optimized_required = true; +@@ -2009,7 +2027,13 @@ static void commit_planes_for_stream(struct dc *dc, + * In case of turning off screen, no need to program front end a second time. + * just return after program blank. + */ +- dc->hwss.apply_ctx_for_surface(dc, stream, 0, context); ++ if (dc->hwss.apply_ctx_for_surface) ++ dc->hwss.apply_ctx_for_surface(dc, stream, 0, context); ++#if defined(CONFIG_DRM_AMD_DC_DCN2_0) ++ if (dc->hwss.program_front_end_for_ctx) ++ dc->hwss.program_front_end_for_ctx(dc, context); ++#endif ++ + return; + } + +@@ -2069,10 +2093,15 @@ static void commit_planes_for_stream(struct dc *dc, + stream_status = + stream_get_status(context, pipe_ctx->stream); + +- dc->hwss.apply_ctx_for_surface( ++ if (dc->hwss.apply_ctx_for_surface) ++ dc->hwss.apply_ctx_for_surface( + dc, pipe_ctx->stream, stream_status->plane_count, context); + } + } ++#if defined(CONFIG_DRM_AMD_DC_DCN2_0) ++ if (dc->hwss.program_front_end_for_ctx && update_type != UPDATE_TYPE_FAST) ++ dc->hwss.program_front_end_for_ctx(dc, context); ++#endif + + // Update Type FAST, Surface updates + if (update_type == UPDATE_TYPE_FAST) { +diff --git a/drivers/gpu/drm/amd/display/dc/dc_stream.h b/drivers/gpu/drm/amd/display/dc/dc_stream.h +index 0fa1c26bc20d..e2d9e11be4b0 100644 +--- a/drivers/gpu/drm/amd/display/dc/dc_stream.h ++++ b/drivers/gpu/drm/amd/display/dc/dc_stream.h +@@ -113,6 +113,21 @@ struct periodic_interrupt_config { + int lines_offset; + }; + ++union stream_update_flags { ++ struct { ++ uint32_t scaling:1; ++ uint32_t out_tf:1; ++ uint32_t out_csc:1; ++ uint32_t abm_level:1; ++ uint32_t dpms_off:1; ++ uint32_t gamut_remap:1; ++#if defined(CONFIG_DRM_AMD_DC_DCN2_0) ++ uint32_t wb_update:1; ++#endif ++ } bits; ++ ++ uint32_t raw; ++}; + + struct dc_stream_state { + // sink is deprecated, new code should not reference +@@ -214,9 +229,12 @@ struct dc_stream_state { + #ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT + bool is_dsc_enabled; + #endif ++ union stream_update_flags update_flags; + }; + + struct dc_stream_update { ++ struct dc_stream_state *stream; ++ + struct rect src; + struct rect dst; + struct dc_transfer_func *out_transfer_func; +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 1212da12c414..b5b5d9145f6a 100644 +--- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c ++++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c +@@ -508,7 +508,7 @@ static void dcn20_plane_atomic_disable(struct dc *dc, struct pipe_ctx *pipe_ctx) + } + + +-void dcn20_disable_plane(struct dc *dc, struct pipe_ctx *pipe_ctx) ++static void dcn20_disable_plane(struct dc *dc, struct pipe_ctx *pipe_ctx) + { + DC_LOGGER_INIT(dc->ctx->logger); + +@@ -923,7 +923,7 @@ static void dcn20_power_on_plane( + } + } + +-void dcn20_enable_plane( ++static void dcn20_enable_plane( + struct dc *dc, + struct pipe_ctx *pipe_ctx, + struct dc_state *context) +@@ -999,72 +999,6 @@ void dcn20_enable_plane( + } + + +-static void dcn20_program_pipe( +- struct dc *dc, +- struct pipe_ctx *pipe_ctx, +- struct dc_state *context) +-{ +- pipe_ctx->plane_state->update_flags.bits.full_update = +- context->commit_hints.full_update_needed ? 1 : pipe_ctx->plane_state->update_flags.bits.full_update; +- +- if (pipe_ctx->plane_state->update_flags.bits.full_update) +- dcn20_enable_plane(dc, pipe_ctx, context); +- +- update_dchubp_dpp(dc, pipe_ctx, context); +- +- set_hdr_multiplier(pipe_ctx); +- +- if (pipe_ctx->plane_state->update_flags.bits.full_update || +- pipe_ctx->plane_state->update_flags.bits.in_transfer_func_change || +- pipe_ctx->plane_state->update_flags.bits.gamma_change) +- dc->hwss.set_input_transfer_func(pipe_ctx, pipe_ctx->plane_state); +- +- /* dcn10_translate_regamma_to_hw_format takes 750us to finish +- * only do gamma programming for full update. +- * TODO: This can be further optimized/cleaned up +- * Always call this for now since it does memcmp inside before +- * doing heavy calculation and programming +- */ +- if (pipe_ctx->plane_state->update_flags.bits.full_update) +- dc->hwss.set_output_transfer_func(pipe_ctx, pipe_ctx->stream); +-} +- +-static void dcn20_program_all_pipe_in_tree( +- struct dc *dc, +- struct pipe_ctx *pipe_ctx, +- struct dc_state *context) +-{ +- if (pipe_ctx->top_pipe == NULL && !pipe_ctx->prev_odm_pipe) { +- bool blank = !is_pipe_tree_visible(pipe_ctx); +- +- pipe_ctx->stream_res.tg->funcs->program_global_sync( +- pipe_ctx->stream_res.tg, +- pipe_ctx->pipe_dlg_param.vready_offset, +- pipe_ctx->pipe_dlg_param.vstartup_start, +- pipe_ctx->pipe_dlg_param.vupdate_offset, +- pipe_ctx->pipe_dlg_param.vupdate_width); +- +- pipe_ctx->stream_res.tg->funcs->set_vtg_params( +- pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing); +- +- dc->hwss.blank_pixel_data(dc, pipe_ctx, blank); +- +- if (dc->hwss.update_odm) +- dc->hwss.update_odm(dc, context, pipe_ctx); +- } +- +- if (pipe_ctx->plane_state != NULL) +- dcn20_program_pipe(dc, pipe_ctx, context); +- +- if (pipe_ctx->bottom_pipe != NULL) { +- ASSERT(pipe_ctx->bottom_pipe != pipe_ctx); +- dcn20_program_all_pipe_in_tree(dc, pipe_ctx->bottom_pipe, context); +- } else if (pipe_ctx->next_odm_pipe != NULL) { +- ASSERT(pipe_ctx->next_odm_pipe != pipe_ctx); +- dcn20_program_all_pipe_in_tree(dc, pipe_ctx->next_odm_pipe, context); +- } +-} +- + void dcn20_pipe_control_lock_global( + struct dc *dc, + struct pipe_ctx *pipe, +@@ -1087,7 +1021,7 @@ void dcn20_pipe_control_lock_global( + } + } + +-void dcn20_pipe_control_lock( ++static void dcn20_pipe_control_lock( + struct dc *dc, + struct pipe_ctx *pipe, + bool lock) +@@ -1124,114 +1058,436 @@ void dcn20_pipe_control_lock( + } + } + +-static void dcn20_apply_ctx_for_surface( +- struct dc *dc, +- const struct dc_stream_state *stream, +- int num_planes, +- struct dc_state *context) ++static void dcn20_detect_pipe_changes(struct pipe_ctx *old_pipe, struct pipe_ctx *new_pipe) + { +- const unsigned int TIMEOUT_FOR_PIPE_ENABLE_MS = 100; +- int i; +- struct timing_generator *tg; +- bool removed_pipe[6] = { false }; +- bool interdependent_update = false; +- struct pipe_ctx *top_pipe_to_program = +- find_top_pipe_for_stream(dc, context, stream); +- struct pipe_ctx *prev_top_pipe_to_program = +- find_top_pipe_for_stream(dc, dc->current_state, stream); +- DC_LOGGER_INIT(dc->ctx->logger); ++ new_pipe->update_flags.raw = 0; + +- if (!top_pipe_to_program) ++ /* Exit on unchanged, unused pipe */ ++ if (!old_pipe->plane_state && !new_pipe->plane_state) + return; ++ /* Detect pipe enable/disable */ ++ if (!old_pipe->plane_state && new_pipe->plane_state) { ++ new_pipe->update_flags.bits.enable = 1; ++ new_pipe->update_flags.bits.mpcc = 1; ++ new_pipe->update_flags.bits.dppclk = 1; ++ new_pipe->update_flags.bits.hubp_interdependent = 1; ++ new_pipe->update_flags.bits.hubp_rq_dlg_ttu = 1; ++ new_pipe->update_flags.bits.gamut_remap = 1; ++ new_pipe->update_flags.bits.scaler = 1; ++ new_pipe->update_flags.bits.viewport = 1; ++ if (!new_pipe->top_pipe && !new_pipe->prev_odm_pipe) { ++ new_pipe->update_flags.bits.odm = 1; ++ new_pipe->update_flags.bits.global_sync = 1; ++ } ++ return; ++ } ++ if (old_pipe->plane_state && !new_pipe->plane_state) { ++ new_pipe->update_flags.bits.disable = 1; ++ return; ++ } + +- /* Carry over GSL groups in case the context is changing. */ +- for (i = 0; i < dc->res_pool->pipe_count; i++) { +- struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; +- struct pipe_ctx *old_pipe_ctx = +- &dc->current_state->res_ctx.pipe_ctx[i]; ++ /* Detect top pipe only changes */ ++ if (!new_pipe->top_pipe && !new_pipe->prev_odm_pipe) { ++ /* Detect odm changes */ ++ if ((old_pipe->next_odm_pipe && new_pipe->next_odm_pipe ++ && old_pipe->next_odm_pipe->pipe_idx != new_pipe->next_odm_pipe->pipe_idx) ++ || (!old_pipe->next_odm_pipe && new_pipe->next_odm_pipe) ++ || (old_pipe->next_odm_pipe && !new_pipe->next_odm_pipe) ++ || old_pipe->stream_res.opp != new_pipe->stream_res.opp) ++ new_pipe->update_flags.bits.odm = 1; ++ ++ /* Detect global sync changes */ ++ if (old_pipe->pipe_dlg_param.vready_offset != new_pipe->pipe_dlg_param.vready_offset ++ || old_pipe->pipe_dlg_param.vstartup_start != new_pipe->pipe_dlg_param.vstartup_start ++ || old_pipe->pipe_dlg_param.vupdate_offset != new_pipe->pipe_dlg_param.vupdate_offset ++ || old_pipe->pipe_dlg_param.vupdate_width != new_pipe->pipe_dlg_param.vupdate_width) ++ new_pipe->update_flags.bits.global_sync = 1; ++ } + +- if (pipe_ctx->stream == stream && +- pipe_ctx->stream == old_pipe_ctx->stream) +- pipe_ctx->stream_res.gsl_group = +- old_pipe_ctx->stream_res.gsl_group; ++ /* ++ * Detect opp / tg change, only set on change, not on enable ++ * Assume mpcc inst = pipe index, if not this code needs to be updated ++ * since mpcc is what is affected by these. In fact all of our sequence ++ * makes this assumption at the moment with how hubp reset is matched to ++ * same index mpcc reset. ++ */ ++ if (old_pipe->stream_res.opp != new_pipe->stream_res.opp) ++ new_pipe->update_flags.bits.opp_changed = 1; ++ 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 */ ++ 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)) ++ new_pipe->update_flags.bits.mpcc = 1; ++ ++ /* Detect dppclk change */ ++ if (old_pipe->plane_res.bw.dppclk_khz != new_pipe->plane_res.bw.dppclk_khz) ++ new_pipe->update_flags.bits.dppclk = 1; ++ ++ /* Check for scl update */ ++ if (memcmp(&old_pipe->plane_res.scl_data, &new_pipe->plane_res.scl_data, sizeof(struct scaler_data))) ++ new_pipe->update_flags.bits.scaler = 1; ++ /* Check for vp update */ ++ if (memcmp(&old_pipe->plane_res.scl_data.viewport, &new_pipe->plane_res.scl_data.viewport, sizeof(struct rect)) ++ || memcmp(&old_pipe->plane_res.scl_data.viewport_c, ++ &new_pipe->plane_res.scl_data.viewport_c, sizeof(struct rect))) ++ new_pipe->update_flags.bits.viewport = 1; ++ ++ /* Detect dlg/ttu/rq updates */ ++ { ++ struct _vcs_dpi_display_dlg_regs_st old_dlg_attr = old_pipe->dlg_regs; ++ struct _vcs_dpi_display_ttu_regs_st old_ttu_attr = old_pipe->ttu_regs; ++ struct _vcs_dpi_display_dlg_regs_st *new_dlg_attr = &new_pipe->dlg_regs; ++ struct _vcs_dpi_display_ttu_regs_st *new_ttu_attr = &new_pipe->ttu_regs; ++ ++ /* Detect pipe interdependent updates */ ++ if (old_dlg_attr.dst_y_prefetch != new_dlg_attr->dst_y_prefetch || ++ old_dlg_attr.vratio_prefetch != new_dlg_attr->vratio_prefetch || ++ old_dlg_attr.vratio_prefetch_c != new_dlg_attr->vratio_prefetch_c || ++ old_dlg_attr.dst_y_per_vm_vblank != new_dlg_attr->dst_y_per_vm_vblank || ++ old_dlg_attr.dst_y_per_row_vblank != new_dlg_attr->dst_y_per_row_vblank || ++ old_dlg_attr.dst_y_per_vm_flip != new_dlg_attr->dst_y_per_vm_flip || ++ old_dlg_attr.dst_y_per_row_flip != new_dlg_attr->dst_y_per_row_flip || ++ old_dlg_attr.refcyc_per_meta_chunk_vblank_l != new_dlg_attr->refcyc_per_meta_chunk_vblank_l || ++ old_dlg_attr.refcyc_per_meta_chunk_vblank_c != new_dlg_attr->refcyc_per_meta_chunk_vblank_c || ++ old_dlg_attr.refcyc_per_meta_chunk_flip_l != new_dlg_attr->refcyc_per_meta_chunk_flip_l || ++ old_dlg_attr.refcyc_per_line_delivery_pre_l != new_dlg_attr->refcyc_per_line_delivery_pre_l || ++ old_dlg_attr.refcyc_per_line_delivery_pre_c != new_dlg_attr->refcyc_per_line_delivery_pre_c || ++ old_ttu_attr.refcyc_per_req_delivery_pre_l != new_ttu_attr->refcyc_per_req_delivery_pre_l || ++ old_ttu_attr.refcyc_per_req_delivery_pre_c != new_ttu_attr->refcyc_per_req_delivery_pre_c || ++ old_ttu_attr.refcyc_per_req_delivery_pre_cur0 != new_ttu_attr->refcyc_per_req_delivery_pre_cur0 || ++ old_ttu_attr.refcyc_per_req_delivery_pre_cur1 != new_ttu_attr->refcyc_per_req_delivery_pre_cur1 || ++ old_ttu_attr.min_ttu_vblank != new_ttu_attr->min_ttu_vblank || ++ old_ttu_attr.qos_level_flip != new_ttu_attr->qos_level_flip) { ++ old_dlg_attr.dst_y_prefetch = new_dlg_attr->dst_y_prefetch; ++ old_dlg_attr.vratio_prefetch = new_dlg_attr->vratio_prefetch; ++ old_dlg_attr.vratio_prefetch_c = new_dlg_attr->vratio_prefetch_c; ++ old_dlg_attr.dst_y_per_vm_vblank = new_dlg_attr->dst_y_per_vm_vblank; ++ old_dlg_attr.dst_y_per_row_vblank = new_dlg_attr->dst_y_per_row_vblank; ++ old_dlg_attr.dst_y_per_vm_flip = new_dlg_attr->dst_y_per_vm_flip; ++ old_dlg_attr.dst_y_per_row_flip = new_dlg_attr->dst_y_per_row_flip; ++ old_dlg_attr.refcyc_per_meta_chunk_vblank_l = new_dlg_attr->refcyc_per_meta_chunk_vblank_l; ++ old_dlg_attr.refcyc_per_meta_chunk_vblank_c = new_dlg_attr->refcyc_per_meta_chunk_vblank_c; ++ old_dlg_attr.refcyc_per_meta_chunk_flip_l = new_dlg_attr->refcyc_per_meta_chunk_flip_l; ++ old_dlg_attr.refcyc_per_line_delivery_pre_l = new_dlg_attr->refcyc_per_line_delivery_pre_l; ++ old_dlg_attr.refcyc_per_line_delivery_pre_c = new_dlg_attr->refcyc_per_line_delivery_pre_c; ++ old_ttu_attr.refcyc_per_req_delivery_pre_l = new_ttu_attr->refcyc_per_req_delivery_pre_l; ++ old_ttu_attr.refcyc_per_req_delivery_pre_c = new_ttu_attr->refcyc_per_req_delivery_pre_c; ++ old_ttu_attr.refcyc_per_req_delivery_pre_cur0 = new_ttu_attr->refcyc_per_req_delivery_pre_cur0; ++ old_ttu_attr.refcyc_per_req_delivery_pre_cur1 = new_ttu_attr->refcyc_per_req_delivery_pre_cur1; ++ old_ttu_attr.min_ttu_vblank = new_ttu_attr->min_ttu_vblank; ++ old_ttu_attr.qos_level_flip = new_ttu_attr->qos_level_flip; ++ new_pipe->update_flags.bits.hubp_interdependent = 1; ++ } ++ /* Detect any other updates to ttu/rq/dlg */ ++ if (memcmp(&old_dlg_attr, &new_pipe->dlg_regs, sizeof(old_dlg_attr)) || ++ memcmp(&old_ttu_attr, &new_pipe->ttu_regs, sizeof(old_ttu_attr)) || ++ memcmp(&old_pipe->rq_regs, &new_pipe->rq_regs, sizeof(old_pipe->rq_regs))) ++ new_pipe->update_flags.bits.hubp_rq_dlg_ttu = 1; + } ++} + +- tg = top_pipe_to_program->stream_res.tg; ++static void dcn20_update_dchubp_dpp( ++ struct dc *dc, ++ struct pipe_ctx *pipe_ctx, ++ struct dc_state *context) ++{ ++ struct hubp *hubp = pipe_ctx->plane_res.hubp; ++ struct dpp *dpp = pipe_ctx->plane_res.dpp; ++ struct dc_plane_state *plane_state = pipe_ctx->plane_state; + +- interdependent_update = top_pipe_to_program->plane_state && +- top_pipe_to_program->plane_state->update_flags.bits.full_update; ++ if (pipe_ctx->update_flags.bits.dppclk) { ++ dpp->funcs->dpp_dppclk_control(dpp, false, true); + +- if (interdependent_update) +- lock_all_pipes(dc, context, true); +- else +- dcn20_pipe_control_lock(dc, top_pipe_to_program, true); ++ dc->res_pool->dccg->funcs->update_dpp_dto( ++ dc->res_pool->dccg, ++ dpp->inst, ++ pipe_ctx->plane_res.bw.dppclk_khz, ++ false); ++ } + +- if (num_planes == 0) { +- /* OTG blank before remove all front end */ +- dc->hwss.blank_pixel_data(dc, top_pipe_to_program, true); ++ /* TODO: Need input parameter to tell current DCHUB pipe tie to which OTG ++ * VTG is within DCHUBBUB which is commond block share by each pipe HUBP. ++ * VTG is 1:1 mapping with OTG. Each pipe HUBP will select which VTG ++ */ ++ if (pipe_ctx->update_flags.bits.hubp_rq_dlg_ttu) { ++ hubp->funcs->hubp_vtg_sel(hubp, pipe_ctx->stream_res.tg->inst); ++ ++ hubp->funcs->hubp_setup( ++ hubp, ++ &pipe_ctx->dlg_regs, ++ &pipe_ctx->ttu_regs, ++ &pipe_ctx->rq_regs, ++ &pipe_ctx->pipe_dlg_param); ++ } ++ if (pipe_ctx->update_flags.bits.hubp_interdependent) ++ hubp->funcs->hubp_setup_interdependent( ++ hubp, ++ &pipe_ctx->dlg_regs, ++ &pipe_ctx->ttu_regs); ++ ++ if (pipe_ctx->update_flags.bits.enable || ++ plane_state->update_flags.bits.bpp_change || ++ plane_state->update_flags.bits.input_csc_change || ++ plane_state->update_flags.bits.color_space_change || ++ plane_state->update_flags.bits.coeff_reduction_change) { ++ struct dc_bias_and_scale bns_params = {0}; ++ ++ // program the input csc ++ dpp->funcs->dpp_setup(dpp, ++ plane_state->format, ++ EXPANSION_MODE_ZERO, ++ plane_state->input_csc_color_matrix, ++ plane_state->color_space, ++ NULL); ++ ++ if (dpp->funcs->dpp_program_bias_and_scale) { ++ //TODO :for CNVC set scale and bias registers if necessary ++ dcn10_build_prescale_params(&bns_params, plane_state); ++ dpp->funcs->dpp_program_bias_and_scale(dpp, &bns_params); ++ } + } + +- /* Disconnect unused mpcc */ +- for (i = 0; i < dc->res_pool->pipe_count; i++) { +- struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; +- struct pipe_ctx *old_pipe_ctx = +- &dc->current_state->res_ctx.pipe_ctx[i]; +- /* +- * Powergate reused pipes that are not powergated +- * fairly hacky right now, using opp_id as indicator +- * TODO: After move dc_post to dc_update, this will +- * be removed. +- */ +- if (pipe_ctx->plane_state && !old_pipe_ctx->plane_state) { +- 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) +- dc->hwss.disable_plane(dc, old_pipe_ctx); ++ if (pipe_ctx->update_flags.bits.mpcc ++ || plane_state->update_flags.bits.global_alpha_change ++ || plane_state->update_flags.bits.per_pixel_alpha_change) { ++ /* Need mpcc to be idle if changing opp */ ++ if (pipe_ctx->update_flags.bits.opp_changed) { ++ struct pipe_ctx *old_pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[pipe_ctx->pipe_idx]; ++ int mpcc_inst; ++ ++ for (mpcc_inst = 0; mpcc_inst < MAX_PIPES; mpcc_inst++) { ++ if (!old_pipe_ctx->stream_res.opp->mpcc_disconnect_pending[mpcc_inst]) ++ continue; ++ dc->res_pool->mpc->funcs->wait_for_idle(dc->res_pool->mpc, mpcc_inst); ++ old_pipe_ctx->stream_res.opp->mpcc_disconnect_pending[mpcc_inst] = false; ++ } + } ++ dc->hwss.update_mpcc(dc, pipe_ctx); ++ } + +- if ((!pipe_ctx->plane_state || +- pipe_ctx->stream_res.tg != old_pipe_ctx->stream_res.tg) && +- old_pipe_ctx->plane_state && +- old_pipe_ctx->stream_res.tg == tg) { ++ if (pipe_ctx->update_flags.bits.scaler || ++ plane_state->update_flags.bits.scaling_change || ++ plane_state->update_flags.bits.position_change || ++ plane_state->update_flags.bits.per_pixel_alpha_change || ++ pipe_ctx->stream->update_flags.bits.scaling) { ++ pipe_ctx->plane_res.scl_data.lb_params.alpha_en = pipe_ctx->plane_state->per_pixel_alpha; ++ ASSERT(pipe_ctx->plane_res.scl_data.lb_params.depth == LB_PIXEL_DEPTH_30BPP); ++ /* scaler configuration */ ++ pipe_ctx->plane_res.dpp->funcs->dpp_set_scaler( ++ pipe_ctx->plane_res.dpp, &pipe_ctx->plane_res.scl_data); ++ } + +- dc->hwss.plane_atomic_disconnect(dc, old_pipe_ctx); +- removed_pipe[i] = true; ++ if (pipe_ctx->update_flags.bits.viewport || ++ (context == dc->current_state && plane_state->update_flags.bits.scaling_change) || ++ (context == dc->current_state && pipe_ctx->stream->update_flags.bits.scaling)) ++ hubp->funcs->mem_program_viewport( ++ hubp, ++ &pipe_ctx->plane_res.scl_data.viewport, ++ &pipe_ctx->plane_res.scl_data.viewport_c); ++ ++ /* 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->stream->cursor_attributes.address.quad_part != 0) { ++ dc->hwss.set_cursor_position(pipe_ctx); ++ dc->hwss.set_cursor_attribute(pipe_ctx); ++ ++ if (dc->hwss.set_cursor_sdr_white_level) ++ dc->hwss.set_cursor_sdr_white_level(pipe_ctx); ++ } + +- DC_LOG_DC("Reset mpcc for pipe %d\n", +- old_pipe_ctx->pipe_idx); +- } ++ /* Any updates are handled in dc interface, just need ++ * to apply existing for plane enable / opp change */ ++ 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) { ++ /* dpp/cm gamut remap*/ ++ dc->hwss.program_gamut_remap(pipe_ctx); ++ ++ /*call the dcn2 method which uses mpc csc*/ ++ dc->hwss.program_output_csc(dc, ++ pipe_ctx, ++ pipe_ctx->stream->output_color_space, ++ pipe_ctx->stream->csc_color_matrix.matrix, ++ hubp->opp_id); + } + +- if (num_planes > 0) +- dcn20_program_all_pipe_in_tree(dc, top_pipe_to_program, context); ++ if (pipe_ctx->update_flags.bits.enable || ++ pipe_ctx->update_flags.bits.opp_changed || ++ plane_state->update_flags.bits.pixel_format_change || ++ plane_state->update_flags.bits.horizontal_mirror_change || ++ plane_state->update_flags.bits.rotation_change || ++ plane_state->update_flags.bits.swizzle_change || ++ plane_state->update_flags.bits.dcc_change || ++ plane_state->update_flags.bits.bpp_change || ++ plane_state->update_flags.bits.scaling_change || ++ plane_state->update_flags.bits.plane_size_change) { ++ struct plane_size size = plane_state->plane_size; ++ ++ size.surface_size = pipe_ctx->plane_res.scl_data.viewport; ++ hubp->funcs->hubp_program_surface_config( ++ hubp, ++ plane_state->format, ++ &plane_state->tiling_info, ++ &size, ++ plane_state->rotation, ++ &plane_state->dcc, ++ plane_state->horizontal_mirror, ++ 0); ++ hubp->power_gated = false; ++ } ++ ++ if (pipe_ctx->update_flags.bits.enable || plane_state->update_flags.bits.addr_update) ++ dc->hwss.update_plane_addr(dc, pipe_ctx); ++ ++ if (pipe_ctx->update_flags.bits.enable) ++ hubp->funcs->set_blank(hubp, false); ++} ++ ++ ++static void dcn20_program_pipe( ++ struct dc *dc, ++ struct pipe_ctx *pipe_ctx, ++ struct dc_state *context) ++{ ++ /* Only need to unblank on top pipe */ ++ if ((pipe_ctx->update_flags.bits.enable || pipe_ctx->stream->update_flags.bits.abm_level) ++ && !pipe_ctx->top_pipe && !pipe_ctx->prev_odm_pipe) ++ dc->hwss.blank_pixel_data(dc, pipe_ctx, !pipe_ctx->plane_state->visible); ++ ++ if (pipe_ctx->update_flags.bits.global_sync) ++ pipe_ctx->stream_res.tg->funcs->program_global_sync( ++ pipe_ctx->stream_res.tg, ++ pipe_ctx->pipe_dlg_param.vready_offset, ++ pipe_ctx->pipe_dlg_param.vstartup_start, ++ pipe_ctx->pipe_dlg_param.vupdate_offset, ++ pipe_ctx->pipe_dlg_param.vupdate_width); ++ ++ if (pipe_ctx->update_flags.bits.odm) ++ dc->hwss.update_odm(dc, context, pipe_ctx); ++ ++ if (pipe_ctx->update_flags.bits.enable) ++ dcn20_enable_plane(dc, pipe_ctx, context); ++ ++ if (pipe_ctx->update_flags.raw || pipe_ctx->plane_state->update_flags.raw) ++ dcn20_update_dchubp_dpp(dc, pipe_ctx, context); ++ ++ if (pipe_ctx->update_flags.bits.enable ++ || pipe_ctx->plane_state->update_flags.bits.sdr_white_level) ++ set_hdr_multiplier(pipe_ctx); ++ ++ if (pipe_ctx->update_flags.bits.enable || ++ pipe_ctx->plane_state->update_flags.bits.in_transfer_func_change || ++ pipe_ctx->plane_state->update_flags.bits.gamma_change) ++ dc->hwss.set_input_transfer_func(pipe_ctx, pipe_ctx->plane_state); ++ ++ /* dcn10_translate_regamma_to_hw_format takes 750us to finish ++ * only do gamma programming for powering on, internal memcmp to avoid ++ * updating on slave planes ++ */ ++ if (pipe_ctx->update_flags.bits.enable || pipe_ctx->stream->update_flags.bits.out_tf) ++ dc->hwss.set_output_transfer_func(pipe_ctx, pipe_ctx->stream); ++} ++ ++static bool does_pipe_need_lock(struct pipe_ctx *pipe) ++{ ++ if ((pipe->plane_state && pipe->plane_state->update_flags.raw) ++ || pipe->update_flags.raw) ++ return true; ++ if (pipe->bottom_pipe) ++ return does_pipe_need_lock(pipe->bottom_pipe); + +- /* Program secondary blending tree and writeback pipes */ +- if ((stream->num_wb_info > 0) && (dc->hwss.program_all_writeback_pipes_in_tree)) +- dc->hwss.program_all_writeback_pipes_in_tree(dc, stream, context); ++ return false; ++} + +- if (interdependent_update) +- for (i = 0; i < dc->res_pool->pipe_count; i++) { ++static void dcn20_program_front_end_for_ctx( ++ struct dc *dc, ++ struct dc_state *context) ++{ ++ const unsigned int TIMEOUT_FOR_PIPE_ENABLE_MS = 100; ++ int i; ++ bool pipe_locked[MAX_PIPES] = {false}; ++ DC_LOGGER_INIT(dc->ctx->logger); ++ ++ /* Carry over GSL groups in case the context is changing. */ ++ for (i = 0; i < dc->res_pool->pipe_count; i++) ++ if (context->res_ctx.pipe_ctx[i].stream == dc->current_state->res_ctx.pipe_ctx[i].stream) ++ context->res_ctx.pipe_ctx[i].stream_res.gsl_group = ++ dc->current_state->res_ctx.pipe_ctx[i].stream_res.gsl_group; ++ ++ /* Set pipe update flags and lock pipes */ ++ for (i = 0; i < dc->res_pool->pipe_count; i++) ++ dcn20_detect_pipe_changes(&dc->current_state->res_ctx.pipe_ctx[i], ++ &context->res_ctx.pipe_ctx[i]); ++ for (i = 0; i < dc->res_pool->pipe_count; i++) ++ if (!context->res_ctx.pipe_ctx[i].top_pipe && ++ does_pipe_need_lock(&context->res_ctx.pipe_ctx[i])) { + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; + +- /* Skip inactive pipes and ones already updated */ +- if (!pipe_ctx->stream || pipe_ctx->stream == stream || +- !pipe_ctx->plane_state || !tg->funcs->is_tg_enabled(tg)) +- continue; ++ if (pipe_ctx->update_flags.bits.tg_changed || pipe_ctx->update_flags.bits.enable) ++ dc->hwss.pipe_control_lock(dc, pipe_ctx, true); ++ if (!pipe_ctx->update_flags.bits.enable) ++ dc->hwss.pipe_control_lock(dc, &dc->current_state->res_ctx.pipe_ctx[i], true); ++ pipe_locked[i] = true; ++ } + +- pipe_ctx->plane_res.hubp->funcs->hubp_setup_interdependent( +- pipe_ctx->plane_res.hubp, +- &pipe_ctx->dlg_regs, +- &pipe_ctx->ttu_regs); ++ /* OTG blank before disabling all front ends */ ++ for (i = 0; i < dc->res_pool->pipe_count; i++) ++ if (context->res_ctx.pipe_ctx[i].update_flags.bits.disable ++ && !context->res_ctx.pipe_ctx[i].top_pipe ++ && !context->res_ctx.pipe_ctx[i].prev_odm_pipe ++ && context->res_ctx.pipe_ctx[i].stream) ++ dc->hwss.blank_pixel_data(dc, &context->res_ctx.pipe_ctx[i], true); ++ ++ /* Disconnect mpcc */ ++ for (i = 0; i < dc->res_pool->pipe_count; i++) ++ if (context->res_ctx.pipe_ctx[i].update_flags.bits.disable ++ || context->res_ctx.pipe_ctx[i].update_flags.bits.opp_changed) { ++ dc->hwss.plane_atomic_disconnect(dc, &dc->current_state->res_ctx.pipe_ctx[i]); ++ DC_LOG_DC("Reset mpcc for pipe %d\n", dc->current_state->res_ctx.pipe_ctx[i].pipe_idx); + } + +- if (interdependent_update) +- lock_all_pipes(dc, context, false); +- else +- dcn20_pipe_control_lock(dc, top_pipe_to_program, false); ++ /* ++ * Program all updated pipes, order matters for mpcc setup. Start with ++ * top pipe and program all pipes that follow in order ++ */ ++ for (i = 0; i < dc->res_pool->pipe_count; i++) { ++ struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; + ++ if (pipe->plane_state && !pipe->top_pipe) { ++ while (pipe) { ++ dcn20_program_pipe(dc, pipe, context); ++ pipe = pipe->bottom_pipe; ++ } ++ /* Program secondary blending tree and writeback pipes */ ++ pipe = &context->res_ctx.pipe_ctx[i]; ++ if (!pipe->prev_odm_pipe && pipe->stream->num_wb_info > 0 ++ && (pipe->update_flags.raw || pipe->plane_state->update_flags.raw || pipe->stream->update_flags.raw) ++ && dc->hwss.program_all_writeback_pipes_in_tree) ++ dc->hwss.program_all_writeback_pipes_in_tree(dc, pipe->stream, context); ++ } ++ } ++ ++ /* Unlock all locked pipes */ + for (i = 0; i < dc->res_pool->pipe_count; i++) +- if (removed_pipe[i]) +- dcn20_disable_plane(dc, &dc->current_state->res_ctx.pipe_ctx[i]); ++ if (pipe_locked[i]) { ++ struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; ++ ++ if (pipe_ctx->update_flags.bits.tg_changed || pipe_ctx->update_flags.bits.enable) ++ dc->hwss.pipe_control_lock(dc, pipe_ctx, false); ++ if (!pipe_ctx->update_flags.bits.enable) ++ dc->hwss.pipe_control_lock(dc, &dc->current_state->res_ctx.pipe_ctx[i], false); ++ } ++ ++ for (i = 0; i < dc->res_pool->pipe_count; i++) ++ if (context->res_ctx.pipe_ctx[i].update_flags.bits.disable) ++ dc->hwss.disable_plane(dc, &dc->current_state->res_ctx.pipe_ctx[i]); + + /* + * If we are enabling a pipe, we need to wait for pending clear as this is a critical +@@ -1239,13 +1495,16 @@ static void dcn20_apply_ctx_for_surface( + * will cause HW to perform an "immediate enable" (as opposed to "vsync enable") which + * is unsupported on DCN. + */ +- i = 0; +- if (num_planes > 0 && top_pipe_to_program && +- (prev_top_pipe_to_program == NULL || prev_top_pipe_to_program->plane_state == NULL)) { +- while (i < TIMEOUT_FOR_PIPE_ENABLE_MS && +- top_pipe_to_program->plane_res.hubp->funcs->hubp_is_flip_pending(top_pipe_to_program->plane_res.hubp)) { +- i += 1; +- msleep(1); ++ for (i = 0; i < dc->res_pool->pipe_count; i++) { ++ struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; ++ ++ if (pipe->plane_state && !pipe->top_pipe && pipe->update_flags.bits.enable) { ++ struct hubp *hubp = pipe->plane_res.hubp; ++ int j = 0; ++ ++ for (j = 0; j < TIMEOUT_FOR_PIPE_ENABLE_MS ++ && hubp->funcs->hubp_is_flip_pending(hubp); j++) ++ msleep(1); + } + } + } +@@ -2095,7 +2354,8 @@ void dcn20_hw_sequencer_construct(struct dc *dc) + dc->hwss.program_triplebuffer = dcn20_program_tripleBuffer; + dc->hwss.set_input_transfer_func = dcn20_set_input_transfer_func; + dc->hwss.set_output_transfer_func = dcn20_set_output_transfer_func; +- dc->hwss.apply_ctx_for_surface = dcn20_apply_ctx_for_surface; ++ dc->hwss.apply_ctx_for_surface = NULL; ++ dc->hwss.program_front_end_for_ctx = dcn20_program_front_end_for_ctx; + dc->hwss.pipe_control_lock = dcn20_pipe_control_lock; + dc->hwss.pipe_control_lock_global = dcn20_pipe_control_lock_global; + dc->hwss.optimize_bandwidth = dcn20_optimize_bandwidth; +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 3a938cd414ea..cbac3b61da94 100644 +--- a/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h ++++ b/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h +@@ -114,6 +114,9 @@ struct hw_sequencer_funcs { + int opp_id); + + #if defined(CONFIG_DRM_AMD_DC_DCN2_0) ++ void (*program_front_end_for_ctx)( ++ struct dc *dc, ++ struct dc_state *context); + void (*program_triplebuffer)( + const struct dc *dc, + struct pipe_ctx *pipe_ctx, +-- +2.17.1 + |